fix(core): normalize slashes for url/baseUrl instead of throwing (#8066)

This commit is contained in:
Joshua Chen 2022-09-08 11:18:26 -04:00 committed by GitHub
parent 73d0ede21a
commit bcae7503ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 16 deletions

View file

@ -69,6 +69,9 @@ export const URISchema = Joi.alternatives(
// This custom validation logic is required notably because Joi does not
// accept paths like /a/b/c ...
Joi.custom((val: unknown, helpers) => {
if (typeof val !== 'string') {
return helpers.error('any.invalid');
}
try {
// eslint-disable-next-line no-new
new URL(String(val));

View file

@ -138,11 +138,6 @@ exports[`normalizeConfig should throw error if themes is not array for the input
"
`;
exports[`normalizeConfig throws error for baseUrl without trailing \`/\` 1`] = `
""baseUrl" must be a string with a trailing slash.
"
`;
exports[`normalizeConfig throws error for required fields 1`] = `
""baseUrl" is required
"title" is required

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {jest} from '@jest/globals';
import {
ConfigSchema,
DEFAULT_CONFIG,
@ -86,12 +87,68 @@ describe('normalizeConfig', () => {
}).toThrowErrorMatchingSnapshot();
});
it('throws error for baseUrl without trailing `/`', () => {
expect(() => {
it('throws for non-string URLs', () => {
expect(() =>
normalizeConfig({
// @ts-expect-error: test
url: 1,
}),
).toThrowErrorMatchingInlineSnapshot(`
""url" contains an invalid value
"
`);
});
it('normalizes various URLs', () => {
const consoleMock = jest
.spyOn(console, 'warn')
.mockImplementation(() => {});
expect(
normalizeConfig({
url: 'https://mysite.com/',
}).url,
).toBe('https://mysite.com');
expect(
normalizeConfig({
// This shouldn't happen
url: 'https://mysite.com/foo/',
}).url,
).toBe('https://mysite.com/foo');
expect(consoleMock.mock.calls[0][0]).toMatchInlineSnapshot(
`"[WARNING] Docusaurus config validation warning. Field "url": The url is not supposed to contain a sub-path like '/foo/'. Please use the baseUrl field for sub-paths."`,
);
});
it('throws for non-string base URLs', () => {
expect(() =>
normalizeConfig({
// @ts-expect-error: test
baseUrl: 1,
}),
).toThrowErrorMatchingInlineSnapshot(`
""baseUrl" must be a string
"
`);
});
it('normalizes various base URLs', () => {
expect(
normalizeConfig({
baseUrl: 'noSlash',
});
}).toThrowErrorMatchingSnapshot();
}).baseUrl,
).toBe('/noSlash/');
expect(
normalizeConfig({
baseUrl: '/noSlash',
}).baseUrl,
).toBe('/noSlash/');
expect(
normalizeConfig({
baseUrl: 'noSlash/foo',
}).baseUrl,
).toBe('/noSlash/foo/');
});
it.each([
@ -342,7 +399,7 @@ describe('config warnings', () => {
expect(warning).toBeDefined();
expect(warning.details).toHaveLength(1);
expect(warning.details[0]!.message).toMatchInlineSnapshot(
`"Docusaurus config validation warning. Field "url": the url is not supposed to contain a sub-path like '/someSubpath', please use the baseUrl field for sub-paths"`,
`"Docusaurus config validation warning. Field "url": The url is not supposed to contain a sub-path like '/someSubpath'. Please use the baseUrl field for sub-paths."`,
);
});
});

View file

@ -8,6 +8,9 @@
import {
DEFAULT_STATIC_DIR_NAME,
DEFAULT_I18N_DIR_NAME,
addLeadingSlash,
addTrailingSlash,
removeTrailingSlash,
} from '@docusaurus/utils';
import {Joi, URISchema, printWarning} from '@docusaurus/utils-validation';
import type {DocusaurusConfig, I18nConfig} from '@docusaurus/types';
@ -149,24 +152,23 @@ const I18N_CONFIG_SCHEMA = Joi.object<I18nConfig>({
.optional()
.default(DEFAULT_I18N_CONFIG);
const SiteUrlSchema = URISchema.required().custom((value: unknown, helpers) => {
const SiteUrlSchema = URISchema.required().custom((value: string, helpers) => {
try {
const {pathname} = new URL(String(value));
if (pathname !== '/') {
helpers.warn('docusaurus.configValidationWarning', {
warningMessage: `the url is not supposed to contain a sub-path like '${pathname}', please use the baseUrl field for sub-paths`,
warningMessage: `The url is not supposed to contain a sub-path like '${pathname}'. Please use the baseUrl field for sub-paths.`,
});
}
} catch {}
return value;
}, 'siteUrlCustomValidation');
return removeTrailingSlash(value);
});
// TODO move to @docusaurus/utils-validation
export const ConfigSchema = Joi.object<DocusaurusConfig>({
baseUrl: Joi.string()
.required()
.regex(/\/$/m)
.message('{{#label}} must be a string with a trailing slash.'),
.custom((value: string) => addLeadingSlash(addTrailingSlash(value))),
baseUrlIssueBanner: Joi.boolean().default(DEFAULT_CONFIG.baseUrlIssueBanner),
favicon: Joi.string().optional(),
title: Joi.string().required(),