docusaurus/packages/docusaurus-theme-classic/src/themeConfigSchema.js
Teik Jun 2159c4fcfb
fix(v2): make config validation less strict (#3120)
* fix(v2): make navbar title validation less strict

* fix(v2): fix validation for rehype plugin

* fix(v2): allow empty string for routeBasePath

* fix(v2): fix validation for stylesheets and scripts field

* fix(v2): rerun CI

* fix(v2): relax check for stylesheet href
2020-07-27 13:58:24 +02:00

175 lines
5 KiB
JavaScript

/**
* 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.
*/
const Joi = require('@hapi/joi');
const NavbarItemPosition = Joi.string().equal('left', 'right').default('left');
// TODO we should probably create a custom navbar item type "dropdown"
// having this recursive structure is bad because we only support 2 levels
// + parent/child don't have exactly the same props
const DefaultNavbarItemSchema = Joi.object({
items: Joi.array().optional().items(Joi.link('...')),
to: Joi.string(),
href: Joi.string().uri(),
label: Joi.string(),
position: NavbarItemPosition,
activeBasePath: Joi.string(),
activeBaseRegex: Joi.string(),
className: Joi.string(),
'aria-label': Joi.string(),
});
// TODO the dropdown parent item can have no href/to
// should check should not apply to dropdown parent item
// .xor('href', 'to');
const DocsVersionNavbarItemSchema = Joi.object({
type: Joi.string().equal('docsVersion').required(),
position: NavbarItemPosition,
label: Joi.string(),
to: Joi.string(),
docsPluginId: Joi.string(),
nextVersionLabel: Joi.string().default('Next'),
});
const DocsVersionDropdownNavbarItemSchema = Joi.object({
type: Joi.string().equal('docsVersionDropdown').required(),
position: NavbarItemPosition,
docsPluginId: Joi.string(),
nextVersionLabel: Joi.string().default('Next'),
});
// Can this be made easier? :/
const isOfType = (type) => {
let typeSchema = Joi.string().required();
// because equal(undefined) is not supported :/
if (type) {
typeSchema = typeSchema.equal(type);
}
return Joi.object({
type: typeSchema,
})
.unknown()
.required();
};
const NavbarItemSchema = Joi.object().when({
switch: [
{
is: isOfType('docsVersion'),
then: DocsVersionNavbarItemSchema,
},
{
is: isOfType('docsVersionDropdown'),
then: DocsVersionDropdownNavbarItemSchema,
},
{
is: isOfType(undefined),
then: Joi.forbidden().messages({
'any.unknown': 'Bad nav item type {.type}',
}),
},
],
otherwise: DefaultNavbarItemSchema,
});
/*
const NavbarItemSchema = Joi.object({
type: Joi.string().only(['docsVersion'])
})
.when(Joi.object({ type: 'docsVersion' }).unknown(), {
then: Joi.object({ pepperoni: Joi.boolean() })
})
.when(Joi.object().unknown(), {
then: Joi.object({ croutons: Joi.boolean() })
})
*/
/*
const NavbarItemSchema = Joi.object().when('type', {
is: Joi.valid('docsVersion'),
then: DocsVersionNavbarItemSchema,
otherwise: DefaultNavbarItemSchema,
});
*/
const ColorModeSchema = Joi.object({
defaultMode: Joi.string().equal('dark', 'light').default('light'),
disableSwitch: Joi.bool().default(false),
respectPrefersColorScheme: Joi.bool().default(false),
}).default({
defaultMode: 'light',
disableSwitch: false,
respectPrefersColorScheme: false,
});
const ThemeConfigSchema = Joi.object({
// TODO temporary (@alpha-58)
disableDarkMode: Joi.any().forbidden(false).messages({
'any.unknown':
'disableDarkMode theme config is deprecated. Please use the new colorMode attribute. You likely want: config.themeConfig.colorMode.disableSwitch = true',
}),
// TODO temporary (@alpha-58)
defaultDarkMode: Joi.any().forbidden(false).messages({
'any.unknown':
'defaultDarkMode theme config is deprecated. Please use the new colorMode attribute. You likely want: config.themeConfig.colorMode.defaultMode = "dark"',
}),
colorMode: ColorModeSchema,
image: Joi.string(),
announcementBar: Joi.object({
id: Joi.string(),
content: Joi.string(),
backgroundColor: Joi.string().default('#fff'),
textColor: Joi.string().default('#000'),
}).optional(),
navbar: Joi.object({
hideOnScroll: Joi.bool().default(false),
// TODO temporary (@alpha-58)
links: Joi.any().forbidden().messages({
'any.unknown':
'themeConfig.navbar.links has been renamed as themeConfig.navbar.items',
}),
items: Joi.array().items(NavbarItemSchema),
title: Joi.string().allow('', null),
logo: Joi.object({
alt: Joi.string(),
src: Joi.string().required(),
srcDark: Joi.string(),
href: Joi.string(),
target: Joi.string(),
}),
}),
footer: Joi.object({
style: Joi.string().equal('dark', 'light').default('light'),
logo: Joi.object({
alt: Joi.string(),
src: Joi.string(),
href: Joi.string(),
}),
copyright: Joi.string(),
links: Joi.array().items(
Joi.object({
title: Joi.string().required(),
items: Joi.array().items(
Joi.object({
to: Joi.string(),
href: Joi.string().uri(),
html: Joi.string(),
label: Joi.string(),
})
.xor('to', 'href', 'html')
.with('to', 'label')
.with('href', 'label')
.nand('html', 'label'),
),
}),
),
}),
});
module.exports = ThemeConfigSchema;