mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 23:57:22 +02:00
fix(v2): fix too strict markdown frontmatter validation (#4654)
* start work * use orta.vscode-jest * node 14 * add some better infra to validate markdown frontmatter * better docs frontmatter validation * fix Yaml / Joi validation issues * fix Yaml / Joi validation issues Co-authored-by: slorber <lorber.sebastien@gmail.com>
This commit is contained in:
parent
c04e613ffe
commit
e11597aba9
8 changed files with 238 additions and 21 deletions
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* 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 {
|
||||
BlogPostFrontMatter,
|
||||
validateBlogPostFrontMatter,
|
||||
} from '../blogFrontMatter';
|
||||
|
||||
describe('validateBlogPostFrontMatter', () => {
|
||||
test('accept empty object', () => {
|
||||
const frontMatter = {};
|
||||
expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter);
|
||||
});
|
||||
|
||||
test('accept valid values', () => {
|
||||
const frontMatter: BlogPostFrontMatter = {
|
||||
id: 'blog',
|
||||
title: 'title',
|
||||
description: 'description',
|
||||
date: 'date',
|
||||
slug: 'slug',
|
||||
draft: true,
|
||||
tags: ['hello', {label: 'tagLabel', permalink: '/tagPermalink'}],
|
||||
};
|
||||
expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter);
|
||||
});
|
||||
|
||||
// See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
||||
test('accept empty title', () => {
|
||||
const frontMatter: BlogPostFrontMatter = {title: ''};
|
||||
expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter);
|
||||
});
|
||||
|
||||
// See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
||||
test('accept empty description', () => {
|
||||
const frontMatter: BlogPostFrontMatter = {description: ''};
|
||||
expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter);
|
||||
});
|
||||
|
||||
// See https://github.com/facebook/docusaurus/issues/4642
|
||||
test('convert tags as numbers', () => {
|
||||
const frontMatter: BlogPostFrontMatter = {
|
||||
tags: [
|
||||
// @ts-expect-error: number for test
|
||||
42,
|
||||
{
|
||||
// @ts-expect-error: number for test
|
||||
label: 84,
|
||||
permalink: '/tagPermalink',
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(validateBlogPostFrontMatter(frontMatter)).toEqual({
|
||||
tags: [
|
||||
'42',
|
||||
{
|
||||
label: '84',
|
||||
permalink: '/tagPermalink',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,11 +5,14 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {Joi} from '@docusaurus/utils-validation';
|
||||
import {
|
||||
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
||||
validateFrontMatter,
|
||||
} from '@docusaurus/utils-validation';
|
||||
import {Tag} from './types';
|
||||
|
||||
// TODO complete this frontmatter + add unit tests
|
||||
type BlogPostFrontMatter = {
|
||||
export type BlogPostFrontMatter = {
|
||||
id?: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
|
@ -19,6 +22,10 @@ type BlogPostFrontMatter = {
|
|||
date?: string;
|
||||
};
|
||||
|
||||
// NOTE: we don't add any default value on purpose here
|
||||
// We don't want default values to magically appear in doc metadatas and props
|
||||
// While the user did not provide those values explicitly
|
||||
// We use default values in code instead
|
||||
const BlogTagSchema = Joi.alternatives().try(
|
||||
Joi.string().required(),
|
||||
Joi.object<Tag>({
|
||||
|
@ -29,15 +36,16 @@ const BlogTagSchema = Joi.alternatives().try(
|
|||
|
||||
const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({
|
||||
id: Joi.string(),
|
||||
title: Joi.string(),
|
||||
description: Joi.string(),
|
||||
title: Joi.string().allow(''),
|
||||
description: Joi.string().allow(''),
|
||||
tags: Joi.array().items(BlogTagSchema),
|
||||
slug: Joi.string(),
|
||||
draft: Joi.boolean(),
|
||||
date: Joi.string().allow(''), // TODO validate the date better!
|
||||
}).unknown();
|
||||
|
||||
export function assertBlogPostFrontMatter(
|
||||
export function validateBlogPostFrontMatter(
|
||||
frontMatter: Record<string, unknown>,
|
||||
): asserts frontMatter is BlogPostFrontMatter {
|
||||
Joi.attempt(frontMatter, BlogFrontMatterSchema);
|
||||
): BlogPostFrontMatter {
|
||||
return validateFrontMatter(frontMatter, BlogFrontMatterSchema);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import {
|
|||
replaceMarkdownLinks,
|
||||
} from '@docusaurus/utils';
|
||||
import {LoadContext} from '@docusaurus/types';
|
||||
import {assertBlogPostFrontMatter} from './blogFrontMatter';
|
||||
import {validateBlogPostFrontMatter} from './blogFrontMatter';
|
||||
|
||||
export function truncate(fileString: string, truncateMarker: RegExp): string {
|
||||
return fileString.split(truncateMarker, 1).shift()!;
|
||||
|
@ -142,12 +142,12 @@ export async function generateBlogPosts(
|
|||
const source = path.join(blogDirPath, blogSourceFile);
|
||||
|
||||
const {
|
||||
frontMatter,
|
||||
frontMatter: unsafeFrontMatter,
|
||||
content,
|
||||
contentTitle,
|
||||
excerpt,
|
||||
} = await parseMarkdownFile(source);
|
||||
assertBlogPostFrontMatter(frontMatter);
|
||||
const frontMatter = validateBlogPostFrontMatter(unsafeFrontMatter);
|
||||
|
||||
const aliasedSource = aliasedSitePath(source, siteDir);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue