feat(v2): read first heading as title and use it in front-matter (#4485)

* feat(v2): read first heading as title and pass it to front-matter

* fix(v2): always trim content after extracting front-matter

* fix(v2): remove heading from rss and keep duplicate heading

* fix(v2): rollback some unnecessary comment changes

* test(v2): add unit tests to blog

* test(v2): add unit tests to docs

* test(v2): correct issue on windows

* test(v2): add additional test cases
This commit is contained in:
Armano 2021-03-23 18:07:21 +01:00 committed by GitHub
parent fb372c574d
commit ea13c94cc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 448 additions and 35 deletions

View file

@ -252,30 +252,50 @@ export function createExcerpt(fileString: string): string | undefined {
}
type ParsedMarkdown = {
frontMatter: {
// Returned by gray-matter
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
};
// Returned by gray-matter
// eslint-disable-next-line @typescript-eslint/no-explicit-any
frontMatter: Record<string, any>;
content: string;
excerpt: string | undefined;
hasFrontMatter: boolean;
};
export function parseMarkdownString(markdownString: string): ParsedMarkdown {
const options: Record<string, unknown> = {
excerpt: (file: matter.GrayMatterFile<string>): void => {
// Hacky way of stripping out import statements from the excerpt
// TODO: Find a better way to do so, possibly by compiling the Markdown content,
// stripping out HTML tags and obtaining the first line.
file.excerpt = createExcerpt(file.content);
},
};
export function readFrontMatter(
markdownString: string,
source?: string,
options: Record<string, unknown> = {},
removeTitleHeading = true,
): ParsedMarkdown {
try {
const {data: frontMatter, content, excerpt} = matter(
markdownString,
options,
);
return {frontMatter, content, excerpt};
const result = matter(markdownString, options);
result.data = result.data || {};
result.content = result.content.trim();
const hasFrontMatter = Object.keys(result.data).length > 0;
const heading = /^# (.*)[\n\r]?/gi.exec(result.content);
if (heading) {
if (result.data.title) {
console.warn(
`Duplicate title detected in \`${source || 'this'}\` file`,
);
} else {
result.data.title = heading[1].trim();
if (removeTitleHeading) {
result.content = result.content.replace(heading[0], '');
if (result.excerpt) {
result.excerpt = result.excerpt.replace(heading[1], '');
}
}
}
}
return {
frontMatter: result.data,
content: result.content,
excerpt: result.excerpt,
hasFrontMatter,
};
} catch (e) {
throw new Error(`Error while parsing markdown front matter.
This can happen if you use special characters like : in frontmatter values (try using "" around that value)
@ -283,12 +303,26 @@ ${e.message}`);
}
}
export function parseMarkdownString(
markdownString: string,
source?: string,
): ParsedMarkdown {
return readFrontMatter(markdownString, source, {
excerpt: (file: matter.GrayMatterFile<string>): void => {
// Hacky way of stripping out import statements from the excerpt
// TODO: Find a better way to do so, possibly by compiling the Markdown content,
// stripping out HTML tags and obtaining the first line.
file.excerpt = createExcerpt(file.content);
},
});
}
export async function parseMarkdownFile(
source: string,
): Promise<ParsedMarkdown> {
const markdownString = await fs.readFile(source, 'utf-8');
try {
return parseMarkdownString(markdownString);
return parseMarkdownString(markdownString, source);
} catch (e) {
throw new Error(
`Error while parsing markdown file ${source}