Skip to content

Commit

Permalink
fix: **BREAKING** refactor frontmatter API
Browse files Browse the repository at this point in the history
  • Loading branch information
3y3 committed Dec 18, 2024
1 parent 4629398 commit 3cdecd9
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 297 deletions.
102 changes: 102 additions & 0 deletions src/transform/frontmatter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {YAMLException, dump, load} from 'js-yaml';
import {dedent} from 'ts-dedent';
import cloneDeepWith from 'lodash/cloneDeepWith';

import {log} from './log';

export type FrontMatter = {
[key: string]: unknown;
metadata?: Record<string, unknown>[];
};

const SEP = '---';

/**
* Temporary workaround to enable parsing YAML metadata from potentially
* Liquid-aware source files
* @param content Input string which could contain Liquid-style substitution syntax (which clashes with YAML
* object syntax)
* @returns String with `{}` escaped, ready to be parsed with `js-yaml`
*/
const escapeLiquid = (content: string): string =>
content.replace(/{{/g, '(({{').replace(/}}/g, '}}))');

/**
* Inverse of a workaround defined above.
* @see `escapeLiquidSubstitutionSyntax`
* @param escapedContent Input string with `{}` escaped with backslashes
* @returns Unescaped string
*/
const unescapeLiquid = (escapedContent: string): string =>
escapedContent.replace(/\(\({{/g, '{{').replace(/}}\)\)/g, '}}');

const matchMetadata = (fileContent: string) => {
if (!fileContent.startsWith(SEP)) {
return null;
}

const closeStart = fileContent.indexOf('\n' + SEP, SEP.length);
const closeEnd = fileContent.indexOf('\n', closeStart + 1);

if (closeStart === -1) {
return null;
}

return [fileContent.slice(SEP.length, closeStart).trim(), fileContent.slice(closeEnd + 1)];
};

const duplicateKeysCompatibleLoad = (yaml: string, filePath: string | undefined) => {
try {
return load(yaml);
} catch (e) {
if (e instanceof YAMLException) {
const duplicateKeysDeprecationWarning = dedent`
In ${filePath ?? '(unknown)'}: Encountered a YAML parsing exception when processing file metadata: ${e.reason}.
It's highly possible the input file contains duplicate mapping keys.
Will retry processing with necessary compatibility flags.
Please note that this behaviour is DEPRECATED and WILL be removed in a future version
without further notice, so the build WILL fail when supplied with YAML-incompatible meta.
`;

log.warn(duplicateKeysDeprecationWarning);

return load(yaml, {json: true});
}

throw e;
}
};

export const extractFrontMatter = (
fileContent: string,
filePath?: string,
): [FrontMatter, string] => {
const matches = matchMetadata(fileContent);

if (matches) {
const [metadata, strippedContent] = matches;

return [
cloneDeepWith(
duplicateKeysCompatibleLoad(escapeLiquid(metadata), filePath) as FrontMatter,
(v) => (typeof v === 'string' ? unescapeLiquid(v) : undefined),
),
strippedContent,
];
}

return [{}, fileContent];
};

export const composeFrontMatter = (frontMatter: FrontMatter, strippedContent: string) => {
const dumped = dump(frontMatter, {lineWidth: -1}).trim();

// This empty object check is a bit naive
// The other option would be to check if all own fields are `undefined`,
// since we exploit passing in `undefined` to remove a field quite a bit
if (dumped === '{}') {
return strippedContent;
}

return `${SEP}\n${dumped}\n${SEP}\n${strippedContent}`;
};
27 changes: 0 additions & 27 deletions src/transform/frontmatter/common.ts

This file was deleted.

24 changes: 0 additions & 24 deletions src/transform/frontmatter/emplace.ts

This file was deleted.

94 changes: 0 additions & 94 deletions src/transform/frontmatter/extract.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/transform/frontmatter/index.ts

This file was deleted.

26 changes: 0 additions & 26 deletions src/transform/frontmatter/transformValues.ts

This file was deleted.

Loading

0 comments on commit 3cdecd9

Please sign in to comment.