mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-16 18:46:57 +02:00
feat(v2): improve DocFrontMatter schema validation (#4796)
Co-authored-by: Nam Hoang Le <nam.hoang.le@mgm-tp.com>
This commit is contained in:
parent
0360364570
commit
fa7aa08100
3 changed files with 193 additions and 27 deletions
|
@ -251,9 +251,10 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'date',
|
fieldName: 'date',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
// @ts-expect-error: number for test
|
|
||||||
{date: new Date('2020-01-01')},
|
{date: new Date('2020-01-01')},
|
||||||
|
// @ts-expect-error: string for test
|
||||||
{date: '2020-01-01'},
|
{date: '2020-01-01'},
|
||||||
|
// @ts-expect-error: string for test
|
||||||
{date: '2020'},
|
{date: '2020'},
|
||||||
],
|
],
|
||||||
invalidFrontMatters: [
|
invalidFrontMatters: [
|
||||||
|
|
|
@ -7,42 +7,198 @@
|
||||||
|
|
||||||
import {DocFrontMatter, validateDocFrontMatter} from '../docFrontMatter';
|
import {DocFrontMatter, validateDocFrontMatter} from '../docFrontMatter';
|
||||||
|
|
||||||
|
function testField(params: {
|
||||||
|
fieldName: keyof DocFrontMatter;
|
||||||
|
validFrontMatters: DocFrontMatter[];
|
||||||
|
convertibleFrontMatter?: [
|
||||||
|
ConvertableFrontMatter: Record<string, unknown>,
|
||||||
|
ConvertedFrontMatter: DocFrontMatter,
|
||||||
|
][];
|
||||||
|
invalidFrontMatters?: [
|
||||||
|
InvalidFrontMatter: Record<string, unknown>,
|
||||||
|
ErrorMessage: string,
|
||||||
|
][];
|
||||||
|
}) {
|
||||||
|
describe(`"${params.fieldName}" field`, () => {
|
||||||
|
test('accept valid values', () => {
|
||||||
|
params.validFrontMatters.forEach((frontMatter) => {
|
||||||
|
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convert valid values', () => {
|
||||||
|
params.convertibleFrontMatter?.forEach(
|
||||||
|
([convertibleFrontMatter, convertedFrontMatter]) => {
|
||||||
|
expect(validateDocFrontMatter(convertibleFrontMatter)).toEqual(
|
||||||
|
convertedFrontMatter,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('throw error for values', () => {
|
||||||
|
params.invalidFrontMatters?.forEach(([frontMatter, message]) => {
|
||||||
|
expect(() => validateDocFrontMatter(frontMatter)).toThrow(message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
describe('validateDocFrontMatter', () => {
|
describe('validateDocFrontMatter', () => {
|
||||||
test('accept empty object', () => {
|
test('accept empty object', () => {
|
||||||
const frontMatter: DocFrontMatter = {};
|
const frontMatter: DocFrontMatter = {};
|
||||||
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('accept valid values', () => {
|
test('accept unknown field', () => {
|
||||||
const frontMatter: DocFrontMatter = {
|
const frontMatter = {abc: '1'};
|
||||||
id: 'blog',
|
|
||||||
title: 'title',
|
|
||||||
description: 'description',
|
|
||||||
slug: 'slug',
|
|
||||||
};
|
|
||||||
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'id',
|
||||||
|
validFrontMatters: [{id: '123'}, {id: 'unique_id'}],
|
||||||
|
invalidFrontMatters: [[{id: ''}, 'is not allowed to be empty']],
|
||||||
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'title',
|
||||||
|
validFrontMatters: [
|
||||||
// See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
// See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
||||||
test('accept empty title', () => {
|
{title: ''},
|
||||||
const frontMatter: DocFrontMatter = {title: ''};
|
{title: 'title'},
|
||||||
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'hide_title',
|
||||||
|
validFrontMatters: [{hide_title: true}, {hide_title: false}],
|
||||||
|
convertibleFrontMatter: [
|
||||||
|
[{hide_title: 'true'}, {hide_title: true}],
|
||||||
|
[{hide_title: 'false'}, {hide_title: false}],
|
||||||
|
],
|
||||||
|
invalidFrontMatters: [
|
||||||
|
[{hide_title: 'yes'}, 'must be a boolean'],
|
||||||
|
[{hide_title: 'no'}, 'must be a boolean'],
|
||||||
|
[{hide_title: ''}, 'must be a boolean'],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'hide_table_of_contents',
|
||||||
|
validFrontMatters: [
|
||||||
|
{hide_table_of_contents: true},
|
||||||
|
{hide_table_of_contents: false},
|
||||||
|
],
|
||||||
|
convertibleFrontMatter: [
|
||||||
|
[{hide_table_of_contents: 'true'}, {hide_table_of_contents: true}],
|
||||||
|
[{hide_table_of_contents: 'false'}, {hide_table_of_contents: false}],
|
||||||
|
],
|
||||||
|
invalidFrontMatters: [
|
||||||
|
[{hide_table_of_contents: 'yes'}, 'must be a boolean'],
|
||||||
|
[{hide_table_of_contents: 'no'}, 'must be a boolean'],
|
||||||
|
[{hide_table_of_contents: ''}, 'must be a boolean'],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'keywords',
|
||||||
|
validFrontMatters: [
|
||||||
|
{keywords: ['hello']},
|
||||||
|
{keywords: ['hello', 'world']},
|
||||||
|
{keywords: ['hello', 'world']},
|
||||||
|
{keywords: ['hello']},
|
||||||
|
],
|
||||||
|
invalidFrontMatters: [
|
||||||
|
[{keywords: ''}, 'must be an array'],
|
||||||
|
[{keywords: ['']}, 'is not allowed to be empty'],
|
||||||
|
[{keywords: []}, 'does not contain 1 required value(s)'],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'image',
|
||||||
|
validFrontMatters: [{image: 'https://docusaurus.io/blog/image.png'}],
|
||||||
|
invalidFrontMatters: [
|
||||||
|
[{image: ''}, 'is not allowed to be empty'],
|
||||||
|
[{image: './api/@docusaurus/plugin-debug'}, 'must be a valid uri'],
|
||||||
|
[{image: '/api/@docusaurus/plugin-debug'}, 'must be a valid uri'],
|
||||||
|
[{image: '@site/api/asset/image.png'}, 'must be a valid uri'],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'description',
|
||||||
|
validFrontMatters: [
|
||||||
// See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
// See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
||||||
test('accept empty description', () => {
|
{description: ''},
|
||||||
const frontMatter: DocFrontMatter = {description: ''};
|
{description: 'description'},
|
||||||
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
test('accept null custom_edit_url', () => {
|
testField({
|
||||||
const frontMatter: DocFrontMatter = {custom_edit_url: null};
|
fieldName: 'slug',
|
||||||
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
validFrontMatters: [
|
||||||
|
{slug: '/'},
|
||||||
|
{slug: 'slug'},
|
||||||
|
{slug: '/slug/'},
|
||||||
|
{slug: './slug'},
|
||||||
|
{slug: '../../slug'},
|
||||||
|
{slug: '/api/plugins/@docusaurus'},
|
||||||
|
{slug: '@site/api/asset'},
|
||||||
|
{slug: 'slug1 slug2'},
|
||||||
|
],
|
||||||
|
invalidFrontMatters: [[{slug: ''}, 'is not allowed to be empty']],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'sidebar_label',
|
||||||
|
validFrontMatters: [{sidebar_label: 'Awesome docs'}],
|
||||||
|
invalidFrontMatters: [[{sidebar_label: ''}, 'is not allowed to be empty']],
|
||||||
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'sidebar_position',
|
||||||
|
validFrontMatters: [
|
||||||
|
{sidebar_position: 0},
|
||||||
|
{sidebar_position: 5},
|
||||||
|
{sidebar_position: 3.5},
|
||||||
|
],
|
||||||
|
convertibleFrontMatter: [
|
||||||
|
[{sidebar_position: '1'}, {sidebar_position: 1}],
|
||||||
|
[{sidebar_position: '1.5'}, {sidebar_position: 1.5}],
|
||||||
|
],
|
||||||
|
invalidFrontMatters: [
|
||||||
|
[{sidebar_position: -1}, 'must be greater than or equal to 0'],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'custom_edit_url',
|
||||||
|
validFrontMatters: [
|
||||||
// See https://github.com/demisto/content-docs/pull/616#issuecomment-827087566
|
// See https://github.com/demisto/content-docs/pull/616#issuecomment-827087566
|
||||||
test('accept empty custom_edit_url', () => {
|
{custom_edit_url: ''},
|
||||||
const frontMatter: DocFrontMatter = {custom_edit_url: ''};
|
{custom_edit_url: null},
|
||||||
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
{custom_edit_url: 'https://github.com/facebook/docusaurus/markdown.md'},
|
||||||
|
{custom_edit_url: '../../api/docs/markdown.md'},
|
||||||
|
{custom_edit_url: '@site/api/docs/markdown.md'},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
testField({
|
||||||
|
fieldName: 'parse_number_prefixes',
|
||||||
|
validFrontMatters: [
|
||||||
|
{parse_number_prefixes: true},
|
||||||
|
{parse_number_prefixes: false},
|
||||||
|
],
|
||||||
|
convertibleFrontMatter: [
|
||||||
|
[{parse_number_prefixes: 'true'}, {parse_number_prefixes: true}],
|
||||||
|
[{parse_number_prefixes: 'false'}, {parse_number_prefixes: false}],
|
||||||
|
],
|
||||||
|
invalidFrontMatters: [
|
||||||
|
[{parse_number_prefixes: 'yes'}, 'must be a boolean'],
|
||||||
|
[{parse_number_prefixes: 'no'}, 'must be a boolean'],
|
||||||
|
[{parse_number_prefixes: ''}, 'must be a boolean'],
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,15 +5,20 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
|
||||||
import {
|
import {
|
||||||
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
||||||
validateFrontMatter,
|
validateFrontMatter,
|
||||||
} from '@docusaurus/utils-validation';
|
} from '@docusaurus/utils-validation';
|
||||||
|
|
||||||
// TODO complete this frontmatter + add unit tests
|
|
||||||
export type DocFrontMatter = {
|
export type DocFrontMatter = {
|
||||||
id?: string;
|
id?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
hide_title?: boolean;
|
||||||
|
hide_table_of_contents?: boolean;
|
||||||
|
keywords?: string[];
|
||||||
|
image?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
slug?: string;
|
slug?: string;
|
||||||
sidebar_label?: string;
|
sidebar_label?: string;
|
||||||
|
@ -29,13 +34,17 @@ export type DocFrontMatter = {
|
||||||
const DocFrontMatterSchema = Joi.object<DocFrontMatter>({
|
const DocFrontMatterSchema = Joi.object<DocFrontMatter>({
|
||||||
id: Joi.string(),
|
id: Joi.string(),
|
||||||
title: Joi.string().allow(''), // see https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
title: Joi.string().allow(''), // see https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
||||||
|
hide_title: Joi.boolean(),
|
||||||
|
hide_table_of_contents: Joi.boolean(),
|
||||||
|
keywords: Joi.array().items(Joi.string().required()),
|
||||||
|
image: Joi.string().uri({allowRelative: false}),
|
||||||
description: Joi.string().allow(''), // see https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
description: Joi.string().allow(''), // see https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
|
||||||
slug: Joi.string(),
|
slug: Joi.string(),
|
||||||
sidebar_label: Joi.string(),
|
sidebar_label: Joi.string(),
|
||||||
sidebar_position: Joi.number(),
|
sidebar_position: Joi.number().min(0),
|
||||||
custom_edit_url: Joi.string().allow('', null),
|
custom_edit_url: Joi.string().uri({allowRelative: true}).allow('', null),
|
||||||
parse_number_prefixes: Joi.boolean(),
|
parse_number_prefixes: Joi.boolean(),
|
||||||
});
|
}).unknown();
|
||||||
|
|
||||||
export function validateDocFrontMatter(
|
export function validateDocFrontMatter(
|
||||||
frontMatter: Record<string, unknown>,
|
frontMatter: Record<string, unknown>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue