Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c7301f5

Browse files
Josh-Cenaslorber
authored andcommittedOct 28, 2022
fix(core): normalize slashes for url/baseUrl instead of throwing (#8066)
1 parent 00b2d6c commit c7301f5

File tree

4 files changed

+73
-16
lines changed

4 files changed

+73
-16
lines changed
 

‎packages/docusaurus-utils-validation/src/validationSchemas.ts

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

‎packages/docusaurus/src/server/__tests__/__snapshots__/configValidation.test.ts.snap

-5
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,6 @@ exports[`normalizeConfig should throw error if themes is not array for the input
138138
"
139139
`;
140140

141-
exports[`normalizeConfig throws error for baseUrl without trailing \`/\` 1`] = `
142-
""baseUrl" must be a string with a trailing slash.
143-
"
144-
`;
145-
146141
exports[`normalizeConfig throws error for required fields 1`] = `
147142
""baseUrl" is required
148143
"title" is required

‎packages/docusaurus/src/server/__tests__/configValidation.test.ts

+62-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8+
import {jest} from '@jest/globals';
89
import {
910
ConfigSchema,
1011
DEFAULT_CONFIG,
@@ -86,12 +87,68 @@ describe('normalizeConfig', () => {
8687
}).toThrowErrorMatchingSnapshot();
8788
});
8889

89-
it('throws error for baseUrl without trailing `/`', () => {
90-
expect(() => {
90+
it('throws for non-string URLs', () => {
91+
expect(() =>
92+
normalizeConfig({
93+
// @ts-expect-error: test
94+
url: 1,
95+
}),
96+
).toThrowErrorMatchingInlineSnapshot(`
97+
""url" contains an invalid value
98+
"
99+
`);
100+
});
101+
102+
it('normalizes various URLs', () => {
103+
const consoleMock = jest
104+
.spyOn(console, 'warn')
105+
.mockImplementation(() => {});
106+
107+
expect(
108+
normalizeConfig({
109+
url: 'https://mysite.com/',
110+
}).url,
111+
).toBe('https://mysite.com');
112+
expect(
113+
normalizeConfig({
114+
// This shouldn't happen
115+
url: 'https://mysite.com/foo/',
116+
}).url,
117+
).toBe('https://mysite.com/foo');
118+
119+
expect(consoleMock.mock.calls[0][0]).toMatchInlineSnapshot(
120+
`"[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."`,
121+
);
122+
});
123+
124+
it('throws for non-string base URLs', () => {
125+
expect(() =>
126+
normalizeConfig({
127+
// @ts-expect-error: test
128+
baseUrl: 1,
129+
}),
130+
).toThrowErrorMatchingInlineSnapshot(`
131+
""baseUrl" must be a string
132+
"
133+
`);
134+
});
135+
136+
it('normalizes various base URLs', () => {
137+
expect(
91138
normalizeConfig({
92139
baseUrl: 'noSlash',
93-
});
94-
}).toThrowErrorMatchingSnapshot();
140+
}).baseUrl,
141+
).toBe('/noSlash/');
142+
expect(
143+
normalizeConfig({
144+
baseUrl: '/noSlash',
145+
}).baseUrl,
146+
).toBe('/noSlash/');
147+
expect(
148+
normalizeConfig({
149+
baseUrl: 'noSlash/foo',
150+
}).baseUrl,
151+
).toBe('/noSlash/foo/');
95152
});
96153

97154
it.each([
@@ -342,7 +399,7 @@ describe('config warnings', () => {
342399
expect(warning).toBeDefined();
343400
expect(warning.details).toHaveLength(1);
344401
expect(warning.details[0]!.message).toMatchInlineSnapshot(
345-
`"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"`,
402+
`"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."`,
346403
);
347404
});
348405
});

‎packages/docusaurus/src/server/configValidation.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import {
99
DEFAULT_STATIC_DIR_NAME,
1010
DEFAULT_I18N_DIR_NAME,
11+
addLeadingSlash,
12+
addTrailingSlash,
13+
removeTrailingSlash,
1114
} from '@docusaurus/utils';
1215
import {Joi, URISchema, printWarning} from '@docusaurus/utils-validation';
1316
import type {DocusaurusConfig, I18nConfig} from '@docusaurus/types';
@@ -149,24 +152,23 @@ const I18N_CONFIG_SCHEMA = Joi.object<I18nConfig>({
149152
.optional()
150153
.default(DEFAULT_I18N_CONFIG);
151154

152-
const SiteUrlSchema = URISchema.required().custom((value: unknown, helpers) => {
155+
const SiteUrlSchema = URISchema.required().custom((value: string, helpers) => {
153156
try {
154157
const {pathname} = new URL(String(value));
155158
if (pathname !== '/') {
156159
helpers.warn('docusaurus.configValidationWarning', {
157-
warningMessage: `the url is not supposed to contain a sub-path like '${pathname}', please use the baseUrl field for sub-paths`,
160+
warningMessage: `The url is not supposed to contain a sub-path like '${pathname}'. Please use the baseUrl field for sub-paths.`,
158161
});
159162
}
160163
} catch {}
161-
return value;
162-
}, 'siteUrlCustomValidation');
164+
return removeTrailingSlash(value);
165+
});
163166

164167
// TODO move to @docusaurus/utils-validation
165168
export const ConfigSchema = Joi.object<DocusaurusConfig>({
166169
baseUrl: Joi.string()
167170
.required()
168-
.regex(/\/$/m)
169-
.message('{{#label}} must be a string with a trailing slash.'),
171+
.custom((value: string) => addLeadingSlash(addTrailingSlash(value))),
170172
baseUrlIssueBanner: Joi.boolean().default(DEFAULT_CONFIG.baseUrlIssueBanner),
171173
favicon: Joi.string().optional(),
172174
title: Joi.string().required(),

0 commit comments

Comments
 (0)
Please sign in to comment.