mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 07:37:19 +02:00
fix(v2): less strict blog/docs uri frontmatter validation (#5032)
This commit is contained in:
parent
425eccc5df
commit
f20599bb54
7 changed files with 151 additions and 52 deletions
|
@ -24,6 +24,7 @@
|
||||||
"@docusaurus/utils": "2.0.0-beta.1",
|
"@docusaurus/utils": "2.0.0-beta.1",
|
||||||
"@docusaurus/utils-validation": "2.0.0-beta.1",
|
"@docusaurus/utils-validation": "2.0.0-beta.1",
|
||||||
"chalk": "^4.1.1",
|
"chalk": "^4.1.1",
|
||||||
|
"escape-string-regexp": "^4.0.0",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.0.2",
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
BlogPostFrontMatter,
|
BlogPostFrontMatter,
|
||||||
validateBlogPostFrontMatter,
|
validateBlogPostFrontMatter,
|
||||||
} from '../blogFrontMatter';
|
} from '../blogFrontMatter';
|
||||||
|
import escapeStringRegexp from 'escape-string-regexp';
|
||||||
|
|
||||||
function testField(params: {
|
function testField(params: {
|
||||||
fieldName: keyof BlogPostFrontMatter;
|
fieldName: keyof BlogPostFrontMatter;
|
||||||
|
@ -41,7 +42,20 @@ function testField(params: {
|
||||||
|
|
||||||
test('throw error for values', () => {
|
test('throw error for values', () => {
|
||||||
params.invalidFrontMatters?.forEach(([frontMatter, message]) => {
|
params.invalidFrontMatters?.forEach(([frontMatter, message]) => {
|
||||||
expect(() => validateBlogPostFrontMatter(frontMatter)).toThrow(message);
|
try {
|
||||||
|
validateBlogPostFrontMatter(frontMatter);
|
||||||
|
fail(
|
||||||
|
new Error(
|
||||||
|
`Blog frontmatter is expected to be rejected, but was accepted successfully:\n ${JSON.stringify(
|
||||||
|
frontMatter,
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
)}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.message).toMatch(new RegExp(escapeStringRegexp(message)));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -57,7 +71,9 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
const frontMatter = {abc: '1'};
|
const frontMatter = {abc: '1'};
|
||||||
expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter);
|
expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter description', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'description',
|
fieldName: 'description',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -66,7 +82,9 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
{description: 'description'},
|
{description: 'description'},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter title', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'title',
|
fieldName: 'title',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -75,25 +93,25 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
{title: 'title'},
|
{title: 'title'},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter id', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
validFrontMatters: [{id: '123'}, {id: 'id'}],
|
validFrontMatters: [{id: '123'}, {id: 'id'}],
|
||||||
invalidFrontMatters: [[{id: ''}, 'is not allowed to be empty']],
|
invalidFrontMatters: [[{id: ''}, 'is not allowed to be empty']],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter author', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'author',
|
fieldName: 'author',
|
||||||
validFrontMatters: [{author: '123'}, {author: 'author'}],
|
validFrontMatters: [{author: '123'}, {author: 'author'}],
|
||||||
invalidFrontMatters: [[{author: ''}, 'is not allowed to be empty']],
|
invalidFrontMatters: [[{author: ''}, 'is not allowed to be empty']],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
testField({
|
describe('validateBlogPostFrontMatter author_title', () => {
|
||||||
fieldName: 'authorTitle',
|
|
||||||
validFrontMatters: [{authorTitle: '123'}, {authorTitle: 'authorTitle'}],
|
|
||||||
invalidFrontMatters: [[{authorTitle: ''}, 'is not allowed to be empty']],
|
|
||||||
});
|
|
||||||
|
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'author_title',
|
fieldName: 'author_title',
|
||||||
validFrontMatters: [{author_title: '123'}, {author_title: 'author_title'}],
|
validFrontMatters: [{author_title: '123'}, {author_title: 'author_title'}],
|
||||||
|
@ -101,22 +119,55 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'authorURL',
|
fieldName: 'authorTitle',
|
||||||
validFrontMatters: [{authorURL: 'https://docusaurus.io'}],
|
validFrontMatters: [{authorTitle: '123'}, {authorTitle: 'authorTitle'}],
|
||||||
|
invalidFrontMatters: [[{authorTitle: ''}, 'is not allowed to be empty']],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter author_url', () => {
|
||||||
|
testField({
|
||||||
|
fieldName: 'author_url',
|
||||||
|
validFrontMatters: [
|
||||||
|
{author_url: 'https://docusaurus.io'},
|
||||||
|
{author_url: '../../relative'},
|
||||||
|
{author_url: '/absolute'},
|
||||||
|
],
|
||||||
invalidFrontMatters: [
|
invalidFrontMatters: [
|
||||||
[{authorURL: ''}, 'is not allowed to be empty'],
|
[
|
||||||
[{authorURL: '@site/api/author'}, 'must be a valid uri'],
|
{author_url: ''},
|
||||||
[{authorURL: '../../api/author'}, 'must be a valid uri'],
|
'"author_url" does not match any of the allowed types',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'author_url',
|
fieldName: 'authorURL',
|
||||||
validFrontMatters: [{author_url: 'https://docusaurus.io'}],
|
validFrontMatters: [
|
||||||
|
{authorURL: 'https://docusaurus.io'},
|
||||||
|
{authorURL: '../../relative'},
|
||||||
|
{authorURL: '/absolute'},
|
||||||
|
],
|
||||||
|
|
||||||
invalidFrontMatters: [
|
invalidFrontMatters: [
|
||||||
[{author_url: ''}, 'is not allowed to be empty'],
|
[{authorURL: ''}, '"authorURL" does not match any of the allowed types'],
|
||||||
[{author_url: '@site/api/author'}, 'must be a valid uri'],
|
],
|
||||||
[{author_url: '../../api/author'}, 'must be a valid uri'],
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter author_image_url', () => {
|
||||||
|
testField({
|
||||||
|
fieldName: 'author_image_url',
|
||||||
|
validFrontMatters: [
|
||||||
|
{author_image_url: 'https://docusaurus.io/asset/image.png'},
|
||||||
|
{author_image_url: '../../relative'},
|
||||||
|
{author_image_url: '/absolute'},
|
||||||
|
],
|
||||||
|
invalidFrontMatters: [
|
||||||
|
[
|
||||||
|
{author_image_url: ''},
|
||||||
|
'"author_image_url" does not match any of the allowed types',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,26 +175,19 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
fieldName: 'authorImageURL',
|
fieldName: 'authorImageURL',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
{authorImageURL: 'https://docusaurus.io/asset/image.png'},
|
{authorImageURL: 'https://docusaurus.io/asset/image.png'},
|
||||||
|
{authorImageURL: '../../relative'},
|
||||||
|
{authorImageURL: '/absolute'},
|
||||||
],
|
],
|
||||||
invalidFrontMatters: [
|
invalidFrontMatters: [
|
||||||
[{authorImageURL: ''}, 'is not allowed to be empty'],
|
[
|
||||||
[{authorImageURL: '@site/api/asset/image.png'}, 'must be a valid uri'],
|
{authorImageURL: ''},
|
||||||
[{authorImageURL: '../../api/asset/image.png'}, 'must be a valid uri'],
|
'"authorImageURL" does not match any of the allowed types',
|
||||||
],
|
],
|
||||||
});
|
|
||||||
|
|
||||||
testField({
|
|
||||||
fieldName: 'author_image_url',
|
|
||||||
validFrontMatters: [
|
|
||||||
{author_image_url: 'https://docusaurus.io/asset/image.png'},
|
|
||||||
],
|
|
||||||
invalidFrontMatters: [
|
|
||||||
[{author_image_url: ''}, 'is not allowed to be empty'],
|
|
||||||
[{author_image_url: '@site/api/asset/image.png'}, 'must be a valid uri'],
|
|
||||||
[{author_image_url: '../../api/asset/image.png'}, 'must be a valid uri'],
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter slug', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'slug',
|
fieldName: 'slug',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -158,10 +202,13 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
],
|
],
|
||||||
invalidFrontMatters: [[{slug: ''}, 'is not allowed to be empty']],
|
invalidFrontMatters: [[{slug: ''}, 'is not allowed to be empty']],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter image', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'image',
|
fieldName: 'image',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
{image: 'https://docusaurus.io/image.png'},
|
||||||
{image: 'blog/'},
|
{image: 'blog/'},
|
||||||
{image: '/blog'},
|
{image: '/blog'},
|
||||||
{image: '/blog/'},
|
{image: '/blog/'},
|
||||||
|
@ -172,15 +219,12 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
{image: '@site/api/asset/image.png'},
|
{image: '@site/api/asset/image.png'},
|
||||||
],
|
],
|
||||||
invalidFrontMatters: [
|
invalidFrontMatters: [
|
||||||
[{image: ''}, 'is not allowed to be empty'],
|
[{image: ''}, '"image" does not match any of the allowed types'],
|
||||||
[{image: 'https://docusaurus.io'}, 'must be a valid relative uri'],
|
|
||||||
[
|
|
||||||
{image: 'https://docusaurus.io/blog/image.png'},
|
|
||||||
'must be a valid relative uri',
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter tags', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'tags',
|
fieldName: 'tags',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -203,7 +247,9 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter keywords', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'keywords',
|
fieldName: 'keywords',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -218,7 +264,9 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
[{keywords: []}, 'does not contain 1 required value(s)'],
|
[{keywords: []}, 'does not contain 1 required value(s)'],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter draft', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'draft',
|
fieldName: 'draft',
|
||||||
validFrontMatters: [{draft: true}, {draft: false}],
|
validFrontMatters: [{draft: true}, {draft: false}],
|
||||||
|
@ -231,7 +279,9 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
[{draft: 'no'}, 'must be a boolean'],
|
[{draft: 'no'}, 'must be a boolean'],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter hide_table_of_contents', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'hide_table_of_contents',
|
fieldName: 'hide_table_of_contents',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -247,7 +297,9 @@ describe('validateBlogPostFrontMatter', () => {
|
||||||
[{hide_table_of_contents: 'no'}, 'must be a boolean'],
|
[{hide_table_of_contents: 'no'}, 'must be a boolean'],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateBlogPostFrontMatter date', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'date',
|
fieldName: 'date',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
||||||
|
URISchema,
|
||||||
validateFrontMatter,
|
validateFrontMatter,
|
||||||
} from '@docusaurus/utils-validation';
|
} from '@docusaurus/utils-validation';
|
||||||
import {Tag} from './types';
|
import {Tag} from './types';
|
||||||
|
@ -59,19 +60,19 @@ const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({
|
||||||
|
|
||||||
author: Joi.string(),
|
author: Joi.string(),
|
||||||
author_title: Joi.string(),
|
author_title: Joi.string(),
|
||||||
author_url: Joi.string().uri(),
|
author_url: URISchema,
|
||||||
author_image_url: Joi.string().uri(),
|
author_image_url: URISchema,
|
||||||
slug: Joi.string(),
|
slug: Joi.string(),
|
||||||
image: Joi.string().uri({relativeOnly: true}),
|
image: URISchema,
|
||||||
keywords: Joi.array().items(Joi.string().required()),
|
keywords: Joi.array().items(Joi.string().required()),
|
||||||
hide_table_of_contents: Joi.boolean(),
|
hide_table_of_contents: Joi.boolean(),
|
||||||
|
|
||||||
// TODO re-enable warnings later, our v1 blog posts use those older frontmatter fields
|
// TODO re-enable warnings later, our v1 blog posts use those older frontmatter fields
|
||||||
authorURL: Joi.string().uri(),
|
authorURL: URISchema,
|
||||||
// .warning('deprecate.error', { alternative: '"author_url"'}),
|
// .warning('deprecate.error', { alternative: '"author_url"'}),
|
||||||
authorTitle: Joi.string(),
|
authorTitle: Joi.string(),
|
||||||
// .warning('deprecate.error', { alternative: '"author_title"'}),
|
// .warning('deprecate.error', { alternative: '"author_title"'}),
|
||||||
authorImageURL: Joi.string().uri(),
|
authorImageURL: URISchema,
|
||||||
// .warning('deprecate.error', { alternative: '"author_image_url"'}),
|
// .warning('deprecate.error', { alternative: '"author_image_url"'}),
|
||||||
})
|
})
|
||||||
.unknown()
|
.unknown()
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"@docusaurus/utils-validation": "2.0.0-beta.1",
|
"@docusaurus/utils-validation": "2.0.0-beta.1",
|
||||||
"chalk": "^4.1.1",
|
"chalk": "^4.1.1",
|
||||||
"combine-promises": "^1.1.0",
|
"combine-promises": "^1.1.0",
|
||||||
|
"escape-string-regexp": "^4.0.0",
|
||||||
"execa": "^5.0.0",
|
"execa": "^5.0.0",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.0.2",
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {DocFrontMatter, validateDocFrontMatter} from '../docFrontMatter';
|
import {validateDocFrontMatter} from '../docFrontMatter';
|
||||||
|
import {DocFrontMatter} from '../types';
|
||||||
|
import escapeStringRegexp from 'escape-string-regexp';
|
||||||
|
|
||||||
function testField(params: {
|
function testField(params: {
|
||||||
fieldName: keyof DocFrontMatter;
|
fieldName: keyof DocFrontMatter;
|
||||||
|
@ -38,7 +40,20 @@ function testField(params: {
|
||||||
|
|
||||||
test('throw error for values', () => {
|
test('throw error for values', () => {
|
||||||
params.invalidFrontMatters?.forEach(([frontMatter, message]) => {
|
params.invalidFrontMatters?.forEach(([frontMatter, message]) => {
|
||||||
expect(() => validateDocFrontMatter(frontMatter)).toThrow(message);
|
try {
|
||||||
|
validateDocFrontMatter(frontMatter);
|
||||||
|
fail(
|
||||||
|
new Error(
|
||||||
|
`Doc frontmatter is expected to be rejected, but was accepted successfully:\n ${JSON.stringify(
|
||||||
|
frontMatter,
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
)}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.message).toMatch(new RegExp(escapeStringRegexp(message)));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -54,13 +69,17 @@ describe('validateDocFrontMatter', () => {
|
||||||
const frontMatter = {abc: '1'};
|
const frontMatter = {abc: '1'};
|
||||||
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
expect(validateDocFrontMatter(frontMatter)).toEqual(frontMatter);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter id', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
validFrontMatters: [{id: '123'}, {id: 'unique_id'}],
|
validFrontMatters: [{id: '123'}, {id: 'unique_id'}],
|
||||||
invalidFrontMatters: [[{id: ''}, 'is not allowed to be empty']],
|
invalidFrontMatters: [[{id: ''}, 'is not allowed to be empty']],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter title', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'title',
|
fieldName: 'title',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -69,7 +88,9 @@ describe('validateDocFrontMatter', () => {
|
||||||
{title: 'title'},
|
{title: 'title'},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter hide_title', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'hide_title',
|
fieldName: 'hide_title',
|
||||||
validFrontMatters: [{hide_title: true}, {hide_title: false}],
|
validFrontMatters: [{hide_title: true}, {hide_title: false}],
|
||||||
|
@ -83,7 +104,9 @@ describe('validateDocFrontMatter', () => {
|
||||||
[{hide_title: ''}, 'must be a boolean'],
|
[{hide_title: ''}, 'must be a boolean'],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter hide_table_of_contents', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'hide_table_of_contents',
|
fieldName: 'hide_table_of_contents',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -100,7 +123,9 @@ describe('validateDocFrontMatter', () => {
|
||||||
[{hide_table_of_contents: ''}, 'must be a boolean'],
|
[{hide_table_of_contents: ''}, 'must be a boolean'],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter keywords', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'keywords',
|
fieldName: 'keywords',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -115,18 +140,23 @@ describe('validateDocFrontMatter', () => {
|
||||||
[{keywords: []}, 'does not contain 1 required value(s)'],
|
[{keywords: []}, 'does not contain 1 required value(s)'],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter image', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'image',
|
fieldName: 'image',
|
||||||
validFrontMatters: [{image: 'https://docusaurus.io/blog/image.png'}],
|
validFrontMatters: [
|
||||||
|
{image: 'https://docusaurus.io/blog/image.png'},
|
||||||
|
{image: '/absolute/image.png'},
|
||||||
|
{image: '../relative/image.png'},
|
||||||
|
],
|
||||||
invalidFrontMatters: [
|
invalidFrontMatters: [
|
||||||
[{image: ''}, 'is not allowed to be empty'],
|
[{image: ''}, 'does not match any of the allowed types'],
|
||||||
[{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'],
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter description', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'description',
|
fieldName: 'description',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -135,7 +165,9 @@ describe('validateDocFrontMatter', () => {
|
||||||
{description: 'description'},
|
{description: 'description'},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter slug', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'slug',
|
fieldName: 'slug',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -150,13 +182,17 @@ describe('validateDocFrontMatter', () => {
|
||||||
],
|
],
|
||||||
invalidFrontMatters: [[{slug: ''}, 'is not allowed to be empty']],
|
invalidFrontMatters: [[{slug: ''}, 'is not allowed to be empty']],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter sidebar_label', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'sidebar_label',
|
fieldName: 'sidebar_label',
|
||||||
validFrontMatters: [{sidebar_label: 'Awesome docs'}],
|
validFrontMatters: [{sidebar_label: 'Awesome docs'}],
|
||||||
invalidFrontMatters: [[{sidebar_label: ''}, 'is not allowed to be empty']],
|
invalidFrontMatters: [[{sidebar_label: ''}, 'is not allowed to be empty']],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter sidebar_position', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'sidebar_position',
|
fieldName: 'sidebar_position',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -172,7 +208,9 @@ describe('validateDocFrontMatter', () => {
|
||||||
[{sidebar_position: -1}, 'must be greater than or equal to 0'],
|
[{sidebar_position: -1}, 'must be greater than or equal to 0'],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter custom_edit_url', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'custom_edit_url',
|
fieldName: 'custom_edit_url',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
@ -184,7 +222,9 @@ describe('validateDocFrontMatter', () => {
|
||||||
{custom_edit_url: '@site/api/docs/markdown.md'},
|
{custom_edit_url: '@site/api/docs/markdown.md'},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter parse_number_prefixes', () => {
|
||||||
testField({
|
testField({
|
||||||
fieldName: 'parse_number_prefixes',
|
fieldName: 'parse_number_prefixes',
|
||||||
validFrontMatters: [
|
validFrontMatters: [
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
||||||
|
URISchema,
|
||||||
validateFrontMatter,
|
validateFrontMatter,
|
||||||
} from '@docusaurus/utils-validation';
|
} from '@docusaurus/utils-validation';
|
||||||
import {DocFrontMatter} from './types';
|
import {DocFrontMatter} from './types';
|
||||||
|
@ -23,13 +24,13 @@ const DocFrontMatterSchema = Joi.object<DocFrontMatter>({
|
||||||
hide_title: Joi.boolean(),
|
hide_title: Joi.boolean(),
|
||||||
hide_table_of_contents: Joi.boolean(),
|
hide_table_of_contents: Joi.boolean(),
|
||||||
keywords: Joi.array().items(Joi.string().required()),
|
keywords: Joi.array().items(Joi.string().required()),
|
||||||
image: Joi.string().uri({allowRelative: false}),
|
image: URISchema,
|
||||||
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().min(0),
|
sidebar_position: Joi.number().min(0),
|
||||||
pagination_label: Joi.string(),
|
pagination_label: Joi.string(),
|
||||||
custom_edit_url: Joi.string().uri({allowRelative: true}).allow('', null),
|
custom_edit_url: URISchema.allow('', null),
|
||||||
parse_number_prefixes: Joi.boolean(),
|
parse_number_prefixes: Joi.boolean(),
|
||||||
}).unknown();
|
}).unknown();
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,11 @@ export const RehypePluginsSchema = MarkdownPluginsSchema;
|
||||||
|
|
||||||
export const AdmonitionsSchema = Joi.object().default({});
|
export const AdmonitionsSchema = Joi.object().default({});
|
||||||
|
|
||||||
|
// TODO how can we make this emit a custom error message :'(
|
||||||
|
// Joi is such a pain, good luck to annoying trying to improve this
|
||||||
export const URISchema = Joi.alternatives(
|
export const URISchema = Joi.alternatives(
|
||||||
Joi.string().uri({allowRelative: true}),
|
Joi.string().uri({allowRelative: true}),
|
||||||
|
// This custom validation logic is required notably because Joi does not accept paths like /a/b/c ...
|
||||||
Joi.custom((val, helpers) => {
|
Joi.custom((val, helpers) => {
|
||||||
try {
|
try {
|
||||||
const url = new URL(val);
|
const url = new URL(val);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue