fix(v2): modify validation schema and tests for rehype/remark + remove duplicate dependency (#3247)

* chore(v2): remove duplicate dependency

* fix(v2): make changes to validation for rehype and remark plugins

* style(v2): run prettier
This commit is contained in:
Teik Jun 2020-08-11 21:17:23 +08:00 committed by GitHub
parent 9399ad61c9
commit fda1590b0d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 42 deletions

View file

@ -7,12 +7,14 @@
import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema'; import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema';
// the type of remark/rehype plugins is function // the type of remark/rehype plugins can be either function, object or array
const remarkRehypePluginStub = () => {}; const markdownPluginsFunctionStub = () => {};
const markdownPluginsObjectStub = {};
test('should normalize options', () => { test('should normalize options', () => {
const {value} = PluginOptionSchema.validate({}); const {value, error} = PluginOptionSchema.validate({});
expect(value).toEqual(DEFAULT_OPTIONS); expect(value).toEqual(DEFAULT_OPTIONS);
expect(error).toBe(undefined);
}); });
test('should accept correctly defined user options', () => { test('should accept correctly defined user options', () => {
@ -24,27 +26,29 @@ test('should accept correctly defined user options', () => {
postsPerPage: 5, postsPerPage: 5,
include: ['api/*', 'docs/*'], include: ['api/*', 'docs/*'],
}; };
const {value} = PluginOptionSchema.validate(userOptions); const {value, error} = PluginOptionSchema.validate(userOptions);
expect(value).toEqual({ expect(value).toEqual({
...userOptions, ...userOptions,
feedOptions: {type: ['rss'], title: 'myTitle'}, feedOptions: {type: ['rss'], title: 'myTitle'},
}); });
expect(error).toBe(undefined);
}); });
test('should accept valid user options', async () => { test('should accept valid user options', async () => {
const userOptions = { const userOptions = {
...DEFAULT_OPTIONS, ...DEFAULT_OPTIONS,
routebasePath: '', routeBasePath: '',
beforeDefaultRemarkPlugins: [], beforeDefaultRemarkPlugins: [],
beforeDefaultRehypePlugins: [remarkRehypePluginStub], beforeDefaultRehypePlugins: [markdownPluginsFunctionStub],
remarkPlugins: [remarkRehypePluginStub, {option1: '42'}], remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]],
rehypePlugins: [ rehypePlugins: [
remarkRehypePluginStub, markdownPluginsObjectStub,
[remarkRehypePluginStub, {option1: '42'}], [markdownPluginsFunctionStub, {option1: '42'}],
], ],
}; };
const {value} = await PluginOptionSchema.validate(userOptions); const {value, error} = await PluginOptionSchema.validate(userOptions);
expect(value).toEqual(userOptions); expect(value).toEqual(userOptions);
expect(error).toBe(undefined);
}); });
test('should throw Error in case of invalid options', () => { test('should throw Error in case of invalid options', () => {

View file

@ -58,22 +58,12 @@ export const PluginOptionSchema = Joi.object({
admonitions: AdmonitionsSchema.default(DEFAULT_OPTIONS.admonitions), admonitions: AdmonitionsSchema.default(DEFAULT_OPTIONS.admonitions),
editUrl: URISchema, editUrl: URISchema,
truncateMarker: Joi.object().default(DEFAULT_OPTIONS.truncateMarker), truncateMarker: Joi.object().default(DEFAULT_OPTIONS.truncateMarker),
beforeDefaultRemarkPlugins: Joi.array() beforeDefaultRemarkPlugins: RemarkPluginsSchema.default(
.items( DEFAULT_OPTIONS.beforeDefaultRemarkPlugins,
Joi.array() ),
.items(Joi.function().required(), Joi.object().required()) beforeDefaultRehypePlugins: RehypePluginsSchema.default(
.length(2), DEFAULT_OPTIONS.beforeDefaultRehypePlugins,
Joi.function(), ),
)
.default(DEFAULT_OPTIONS.beforeDefaultRemarkPlugins),
beforeDefaultRehypePlugins: Joi.array()
.items(
Joi.array()
.items(Joi.function().required(), Joi.object().required())
.length(2),
Joi.function(),
)
.default(DEFAULT_OPTIONS.beforeDefaultRehypePlugins),
feedOptions: Joi.object({ feedOptions: Joi.object({
type: Joi.alternatives().conditional( type: Joi.alternatives().conditional(
Joi.string().equal('all', 'rss', 'atom'), Joi.string().equal('all', 'rss', 'atom'),

View file

@ -9,12 +9,14 @@ import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema';
import {normalizePluginOptions} from '@docusaurus/utils-validation'; import {normalizePluginOptions} from '@docusaurus/utils-validation';
// the type of remark/rehype plugins is function // the type of remark/rehype plugins is function
const remarkRehypePluginStub = () => {}; const markdownPluginsFunctionStub = () => {};
const markdownPluginsObjectStub = {};
describe('normalizeDocsPluginOptions', () => { describe('normalizeDocsPluginOptions', () => {
test('should return default options for undefined user options', async () => { test('should return default options for undefined user options', async () => {
const {value} = await PluginOptionSchema.validate({}); const {value, error} = await PluginOptionSchema.validate({});
expect(value).toEqual(DEFAULT_OPTIONS); expect(value).toEqual(DEFAULT_OPTIONS);
expect(error).toBe(undefined);
}); });
test('should accept correctly defined user options', async () => { test('should accept correctly defined user options', async () => {
@ -26,29 +28,57 @@ describe('normalizeDocsPluginOptions', () => {
sidebarPath: 'my-sidebar', // Path to sidebar configuration for showing a list of markdown pages. sidebarPath: 'my-sidebar', // Path to sidebar configuration for showing a list of markdown pages.
docLayoutComponent: '@theme/DocPage', docLayoutComponent: '@theme/DocPage',
docItemComponent: '@theme/DocItem', docItemComponent: '@theme/DocItem',
remarkPlugins: [], remarkPlugins: [markdownPluginsObjectStub],
rehypePlugins: [remarkRehypePluginStub], rehypePlugins: [markdownPluginsFunctionStub],
showLastUpdateTime: true, showLastUpdateTime: true,
showLastUpdateAuthor: true, showLastUpdateAuthor: true,
admonitions: {}, admonitions: {},
excludeNextVersionDocs: true, excludeNextVersionDocs: true,
disableVersioning: true, disableVersioning: true,
}; };
const {value} = await PluginOptionSchema.validate(userOptions); const {value, error} = await PluginOptionSchema.validate(userOptions);
expect(value).toEqual(userOptions); expect(value).toEqual(userOptions);
expect(error).toBe(undefined);
}); });
test('should accept correctly defined remark and rehype plugin options', async () => { test('should accept correctly defined remark and rehype plugin options', async () => {
const userOptions = { const userOptions = {
...DEFAULT_OPTIONS, ...DEFAULT_OPTIONS,
remarkPlugins: [remarkRehypePluginStub, {option1: '42'}], remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]],
rehypePlugins: [ rehypePlugins: [
remarkRehypePluginStub, markdownPluginsObjectStub,
[remarkRehypePluginStub, {option1: '42'}], [markdownPluginsFunctionStub, {option1: '42'}],
], ],
}; };
const {value} = await PluginOptionSchema.validate(userOptions); const {value, error} = await PluginOptionSchema.validate(userOptions);
expect(value).toEqual(userOptions); expect(value).toEqual(userOptions);
expect(error).toBe(undefined);
});
test('should reject invalid remark plugin options', () => {
expect(() => {
normalizePluginOptions(PluginOptionSchema, {
remarkPlugins: [[{option1: '42'}, markdownPluginsFunctionStub]],
});
}).toThrowErrorMatchingInlineSnapshot(
`"\\"remarkPlugins[0]\\" does not match any of the allowed types"`,
);
});
test('should reject invalid rehype plugin options', () => {
expect(() => {
normalizePluginOptions(PluginOptionSchema, {
rehypePlugins: [
[
markdownPluginsFunctionStub,
{option1: '42'},
markdownPluginsFunctionStub,
],
],
});
}).toThrowErrorMatchingInlineSnapshot(
`"\\"rehypePlugins[0]\\" does not match any of the allowed types"`,
);
}); });
test('should reject bad path inputs', () => { test('should reject bad path inputs', () => {

View file

@ -36,7 +36,7 @@ export const PluginOptionSchema = Joi.object({
routeBasePath: Joi.string().allow('').default(DEFAULT_OPTIONS.routeBasePath), routeBasePath: Joi.string().allow('').default(DEFAULT_OPTIONS.routeBasePath),
homePageId: Joi.string().optional(), homePageId: Joi.string().optional(),
include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include), include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include),
sidebarPath: Joi.string().default(DEFAULT_OPTIONS.sidebarPath), sidebarPath: Joi.string().allow('').default(DEFAULT_OPTIONS.sidebarPath),
docLayoutComponent: Joi.string().default(DEFAULT_OPTIONS.docLayoutComponent), docLayoutComponent: Joi.string().default(DEFAULT_OPTIONS.docLayoutComponent),
docItemComponent: Joi.string().default(DEFAULT_OPTIONS.docItemComponent), docItemComponent: Joi.string().default(DEFAULT_OPTIONS.docItemComponent),
remarkPlugins: RemarkPluginsSchema.default(DEFAULT_OPTIONS.remarkPlugins), remarkPlugins: RemarkPluginsSchema.default(DEFAULT_OPTIONS.remarkPlugins),

View file

@ -13,11 +13,9 @@ export const PluginIdSchema = Joi.string()
const MarkdownPluginsSchema = Joi.array() const MarkdownPluginsSchema = Joi.array()
.items( .items(
Joi.array() Joi.array().ordered(Joi.function().required(), Joi.object().required()),
// TODO, this allows [config,fn] too?
.items(Joi.function().required(), Joi.object().required())
.length(2),
Joi.function(), Joi.function(),
Joi.object(),
) )
.default([]); .default([]);

View file

@ -107,8 +107,7 @@
"webpack-bundle-analyzer": "^3.6.1", "webpack-bundle-analyzer": "^3.6.1",
"webpack-dev-server": "^3.11.0", "webpack-dev-server": "^3.11.0",
"webpack-merge": "^4.2.2", "webpack-merge": "^4.2.2",
"webpackbar": "^4.0.0", "webpackbar": "^4.0.0"
"@docusaurus/utils-validation": "^2.0.0-alpha.61"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^16.8.4", "react": "^16.8.4",