diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts index 3f85ded47c..9697a1417e 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/pluginOptionSchema.test.ts @@ -7,12 +7,14 @@ import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema'; -// the type of remark/rehype plugins is function -const remarkRehypePluginStub = () => {}; +// the type of remark/rehype plugins can be either function, object or array +const markdownPluginsFunctionStub = () => {}; +const markdownPluginsObjectStub = {}; test('should normalize options', () => { - const {value} = PluginOptionSchema.validate({}); + const {value, error} = PluginOptionSchema.validate({}); expect(value).toEqual(DEFAULT_OPTIONS); + expect(error).toBe(undefined); }); test('should accept correctly defined user options', () => { @@ -24,27 +26,29 @@ test('should accept correctly defined user options', () => { postsPerPage: 5, include: ['api/*', 'docs/*'], }; - const {value} = PluginOptionSchema.validate(userOptions); + const {value, error} = PluginOptionSchema.validate(userOptions); expect(value).toEqual({ ...userOptions, feedOptions: {type: ['rss'], title: 'myTitle'}, }); + expect(error).toBe(undefined); }); test('should accept valid user options', async () => { const userOptions = { ...DEFAULT_OPTIONS, - routebasePath: '', + routeBasePath: '', beforeDefaultRemarkPlugins: [], - beforeDefaultRehypePlugins: [remarkRehypePluginStub], - remarkPlugins: [remarkRehypePluginStub, {option1: '42'}], + beforeDefaultRehypePlugins: [markdownPluginsFunctionStub], + remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]], rehypePlugins: [ - remarkRehypePluginStub, - [remarkRehypePluginStub, {option1: '42'}], + markdownPluginsObjectStub, + [markdownPluginsFunctionStub, {option1: '42'}], ], }; - const {value} = await PluginOptionSchema.validate(userOptions); + const {value, error} = await PluginOptionSchema.validate(userOptions); expect(value).toEqual(userOptions); + expect(error).toBe(undefined); }); test('should throw Error in case of invalid options', () => { diff --git a/packages/docusaurus-plugin-content-blog/src/pluginOptionSchema.ts b/packages/docusaurus-plugin-content-blog/src/pluginOptionSchema.ts index d3605c1d97..466271253d 100644 --- a/packages/docusaurus-plugin-content-blog/src/pluginOptionSchema.ts +++ b/packages/docusaurus-plugin-content-blog/src/pluginOptionSchema.ts @@ -58,22 +58,12 @@ export const PluginOptionSchema = Joi.object({ admonitions: AdmonitionsSchema.default(DEFAULT_OPTIONS.admonitions), editUrl: URISchema, truncateMarker: Joi.object().default(DEFAULT_OPTIONS.truncateMarker), - beforeDefaultRemarkPlugins: Joi.array() - .items( - Joi.array() - .items(Joi.function().required(), Joi.object().required()) - .length(2), - 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), + beforeDefaultRemarkPlugins: RemarkPluginsSchema.default( + DEFAULT_OPTIONS.beforeDefaultRemarkPlugins, + ), + beforeDefaultRehypePlugins: RehypePluginsSchema.default( + DEFAULT_OPTIONS.beforeDefaultRehypePlugins, + ), feedOptions: Joi.object({ type: Joi.alternatives().conditional( Joi.string().equal('all', 'rss', 'atom'), diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/pluginOptionSchema.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/pluginOptionSchema.test.ts index 08ddaf7f1f..4fb4304ff0 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/pluginOptionSchema.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/pluginOptionSchema.test.ts @@ -9,12 +9,14 @@ import {PluginOptionSchema, DEFAULT_OPTIONS} from '../pluginOptionSchema'; import {normalizePluginOptions} from '@docusaurus/utils-validation'; // the type of remark/rehype plugins is function -const remarkRehypePluginStub = () => {}; +const markdownPluginsFunctionStub = () => {}; +const markdownPluginsObjectStub = {}; describe('normalizeDocsPluginOptions', () => { 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(error).toBe(undefined); }); 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. docLayoutComponent: '@theme/DocPage', docItemComponent: '@theme/DocItem', - remarkPlugins: [], - rehypePlugins: [remarkRehypePluginStub], + remarkPlugins: [markdownPluginsObjectStub], + rehypePlugins: [markdownPluginsFunctionStub], showLastUpdateTime: true, showLastUpdateAuthor: true, admonitions: {}, excludeNextVersionDocs: true, disableVersioning: true, }; - const {value} = await PluginOptionSchema.validate(userOptions); + const {value, error} = await PluginOptionSchema.validate(userOptions); expect(value).toEqual(userOptions); + expect(error).toBe(undefined); }); test('should accept correctly defined remark and rehype plugin options', async () => { const userOptions = { ...DEFAULT_OPTIONS, - remarkPlugins: [remarkRehypePluginStub, {option1: '42'}], + remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]], rehypePlugins: [ - remarkRehypePluginStub, - [remarkRehypePluginStub, {option1: '42'}], + markdownPluginsObjectStub, + [markdownPluginsFunctionStub, {option1: '42'}], ], }; - const {value} = await PluginOptionSchema.validate(userOptions); + const {value, error} = await PluginOptionSchema.validate(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', () => { diff --git a/packages/docusaurus-plugin-content-docs/src/pluginOptionSchema.ts b/packages/docusaurus-plugin-content-docs/src/pluginOptionSchema.ts index 7e67024a99..7e3a983bd2 100644 --- a/packages/docusaurus-plugin-content-docs/src/pluginOptionSchema.ts +++ b/packages/docusaurus-plugin-content-docs/src/pluginOptionSchema.ts @@ -36,7 +36,7 @@ export const PluginOptionSchema = Joi.object({ routeBasePath: Joi.string().allow('').default(DEFAULT_OPTIONS.routeBasePath), homePageId: Joi.string().optional(), 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), docItemComponent: Joi.string().default(DEFAULT_OPTIONS.docItemComponent), remarkPlugins: RemarkPluginsSchema.default(DEFAULT_OPTIONS.remarkPlugins), diff --git a/packages/docusaurus-utils-validation/src/validationSchemas.ts b/packages/docusaurus-utils-validation/src/validationSchemas.ts index d6ffd6d692..332a460d08 100644 --- a/packages/docusaurus-utils-validation/src/validationSchemas.ts +++ b/packages/docusaurus-utils-validation/src/validationSchemas.ts @@ -13,11 +13,9 @@ export const PluginIdSchema = Joi.string() const MarkdownPluginsSchema = Joi.array() .items( - Joi.array() - // TODO, this allows [config,fn] too? - .items(Joi.function().required(), Joi.object().required()) - .length(2), + Joi.array().ordered(Joi.function().required(), Joi.object().required()), Joi.function(), + Joi.object(), ) .default([]); diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index 67f803841c..12a3e0561d 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -107,8 +107,7 @@ "webpack-bundle-analyzer": "^3.6.1", "webpack-dev-server": "^3.11.0", "webpack-merge": "^4.2.2", - "webpackbar": "^4.0.0", - "@docusaurus/utils-validation": "^2.0.0-alpha.61" + "webpackbar": "^4.0.0" }, "peerDependencies": { "react": "^16.8.4",