feat(v2): various markdown string parsing improvements/fixes (#4590)

* extract createExcerpt code in separate file + add bad test

* almost working markdown parsing refactor

* complete parseMarkdownString refactor

* fix tests

* fix blog test issue

* fix docusaurus utils imports
This commit is contained in:
Sébastien Lorber 2021-04-09 17:09:33 +02:00 committed by GitHub
parent b743edf5fb
commit 4efe6824b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 895 additions and 563 deletions

View file

@ -12,9 +12,26 @@ import path from 'path';
import pluginContentBlog from '../index';
import {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types';
import {PluginOptionSchema} from '../pluginOptionSchema';
import {PluginOptions, EditUrlFunction} from '../types';
import {PluginOptions, EditUrlFunction, BlogPost} from '../types';
import {Joi} from '@docusaurus/utils-validation';
function findByTitle(
blogPosts: BlogPost[],
title: string,
): BlogPost | undefined {
return blogPosts.find((v) => v.metadata.title === title);
}
function getByTitle(blogPosts: BlogPost[], title: string): BlogPost {
const post = findByTitle(blogPosts, title);
if (!post) {
throw new Error(`can't find blog post with title ${title}.
Available blog post titles are:\n- ${blogPosts
.map((p) => p.metadata.title)
.join('\n- ')}`);
}
return post;
}
function getI18n(locale: string): I18n {
return {
currentLocale: locale,
@ -77,7 +94,7 @@ describe('loadBlog', () => {
const blogPosts = await getBlogPosts(siteDir);
expect({
...blogPosts.find((v) => v.metadata.title === 'date-matter')!.metadata,
...getByTitle(blogPosts, 'date-matter').metadata,
...{prevItem: undefined},
}).toEqual({
editUrl: `${BaseEditUrl}/blog/date-matter.md`,
@ -98,9 +115,7 @@ describe('loadBlog', () => {
});
expect(
blogPosts.find(
(v) => v.metadata.title === 'Happy 1st Birthday Slash! (translated)',
)!.metadata,
getByTitle(blogPosts, 'Happy 1st Birthday Slash! (translated)').metadata,
).toEqual({
editUrl: `${BaseEditUrl}/blog/2018-12-14-Happy-First-Birthday-Slash.md`,
permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash',
@ -124,7 +139,7 @@ describe('loadBlog', () => {
});
expect({
...blogPosts.find((v) => v.metadata.title === 'Complex Slug')!.metadata,
...getByTitle(blogPosts, 'Complex Slug').metadata,
...{prevItem: undefined},
}).toEqual({
editUrl: `${BaseEditUrl}/blog/complex-slug.md`,
@ -145,7 +160,7 @@ describe('loadBlog', () => {
});
expect({
...blogPosts.find((v) => v.metadata.title === 'Simple Slug')!.metadata,
...getByTitle(blogPosts, 'Simple Slug').metadata,
...{prevItem: undefined},
}).toEqual({
editUrl: `${BaseEditUrl}/blog/simple-slug.md`,
@ -166,7 +181,7 @@ describe('loadBlog', () => {
});
expect({
...blogPosts.find((v) => v.metadata.title === 'some heading')!.metadata,
...getByTitle(blogPosts, 'some heading').metadata,
prevItem: undefined,
}).toEqual({
editUrl: `${BaseEditUrl}/blog/heading-as-title.md`,
@ -301,7 +316,7 @@ describe('loadBlog', () => {
}).format(noDateSourceBirthTime);
expect({
...blogPosts.find((v) => v.metadata.title === 'no date')!.metadata,
...getByTitle(blogPosts, 'no date').metadata,
...{prevItem: undefined},
}).toEqual({
editUrl: `${BaseEditUrl}/blog/no date.md`,

View file

@ -0,0 +1,43 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {Joi} from '@docusaurus/utils-validation';
import {Tag} from './types';
// TODO complete this frontmatter + add unit tests
type BlogPostFrontMatter = {
id?: string;
title?: string;
description?: string;
tags?: (string | Tag)[];
slug?: string;
draft?: boolean;
date?: string;
};
const BlogTagSchema = Joi.alternatives().try(
Joi.string().required(),
Joi.object<Tag>({
label: Joi.string().required(),
permalink: Joi.string().required(),
}),
);
const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({
id: Joi.string(),
title: Joi.string(),
description: Joi.string(),
tags: Joi.array().items(BlogTagSchema),
slug: Joi.string(),
draft: Joi.boolean(),
}).unknown();
export function assertBlogPostFrontMatter(
frontMatter: Record<string, unknown>,
): asserts frontMatter is BlogPostFrontMatter {
Joi.attempt(frontMatter, BlogFrontMatterSchema);
}

View file

@ -26,9 +26,10 @@ import {
getEditUrl,
getFolderContainingFile,
posixPath,
replaceMarkdownLinks,
} from '@docusaurus/utils';
import {LoadContext} from '@docusaurus/types';
import {replaceMarkdownLinks} from '@docusaurus/utils/lib/markdownLinks';
import {assertBlogPostFrontMatter} from './blogFrontMatter';
export function truncate(fileString: string, truncateMarker: RegExp): string {
return fileString.split(truncateMarker, 1).shift()!;
@ -140,12 +141,18 @@ export async function generateBlogPosts(
const source = path.join(blogDirPath, blogSourceFile);
const {
frontMatter,
content,
contentTitle,
excerpt,
} = await parseMarkdownFile(source);
assertBlogPostFrontMatter(frontMatter);
const aliasedSource = aliasedSitePath(source, siteDir);
const blogFileName = path.basename(blogSourceFile);
const {frontMatter, content, excerpt} = await parseMarkdownFile(source);
if (frontMatter.draft && process.env.NODE_ENV === 'production') {
return;
}
@ -182,9 +189,11 @@ export async function generateBlogPosts(
year: 'numeric',
}).format(date);
const title = frontMatter.title ?? contentTitle ?? linkName;
const description = frontMatter.description ?? excerpt ?? '';
const slug =
frontMatter.slug || (match ? toUrl({date, link: linkName}) : linkName);
frontMatter.title = frontMatter.title || linkName;
const permalink = normalizeUrl([baseUrl, routeBasePath, slug]);
@ -220,16 +229,16 @@ export async function generateBlogPosts(
}
blogPosts.push({
id: frontMatter.slug || frontMatter.title,
id: frontMatter.slug ?? title,
metadata: {
permalink,
editUrl: getBlogEditUrl(),
source: aliasedSource,
description: frontMatter.description || excerpt,
title,
description,
date,
formattedDate,
tags: frontMatter.tags,
title: frontMatter.title,
tags: frontMatter.tags ?? [],
readingTime: showReadingTime
? readingTime(content).minutes
: undefined,