mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-28 08:27:03 +02:00
fix(v2): never remove trailing slash from site root like '/baseUrl/' (#5082)
* never apply trailingSlash to site root ('/baseUrl/') => only subroutes * add deprecation comment for loadContext.baseUrl in favor of loadContext.siteConfig.baseUrl * commit typo * useless code
This commit is contained in:
parent
41b78466da
commit
7592982960
11 changed files with 254 additions and 102 deletions
|
@ -5,116 +5,174 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import applyTrailingSlash from '../applyTrailingSlash';
|
||||
import applyTrailingSlash, {
|
||||
ApplyTrailingSlashParams,
|
||||
} from '../applyTrailingSlash';
|
||||
|
||||
function params(
|
||||
trailingSlash: boolean | undefined,
|
||||
baseUrl: string = '/',
|
||||
): ApplyTrailingSlashParams {
|
||||
return {trailingSlash, baseUrl};
|
||||
}
|
||||
|
||||
describe('applyTrailingSlash', () => {
|
||||
test('should apply to empty', () => {
|
||||
expect(applyTrailingSlash('', true)).toEqual('/');
|
||||
expect(applyTrailingSlash('', false)).toEqual('');
|
||||
expect(applyTrailingSlash('', undefined)).toEqual('');
|
||||
expect(applyTrailingSlash('', params(true))).toEqual('/');
|
||||
expect(applyTrailingSlash('', params(false))).toEqual('');
|
||||
expect(applyTrailingSlash('', params(undefined))).toEqual('');
|
||||
});
|
||||
|
||||
test('should not apply to /', () => {
|
||||
expect(applyTrailingSlash('/', true)).toEqual('/');
|
||||
expect(applyTrailingSlash('/', false)).toEqual('/');
|
||||
expect(applyTrailingSlash('/', undefined)).toEqual('/');
|
||||
expect(applyTrailingSlash('/', params(true))).toEqual('/');
|
||||
expect(applyTrailingSlash('/', params(false))).toEqual('/');
|
||||
expect(applyTrailingSlash('/', params(undefined))).toEqual('/');
|
||||
|
||||
expect(applyTrailingSlash('/?query#anchor', true)).toEqual(
|
||||
expect(applyTrailingSlash('/?query#anchor', params(true))).toEqual(
|
||||
'/?query#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/?query#anchor', false)).toEqual(
|
||||
expect(applyTrailingSlash('/?query#anchor', params(false))).toEqual(
|
||||
'/?query#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/?query#anchor', undefined)).toEqual(
|
||||
expect(applyTrailingSlash('/?query#anchor', params(undefined))).toEqual(
|
||||
'/?query#anchor',
|
||||
);
|
||||
});
|
||||
|
||||
test('should not apply to /baseUrl/', () => {
|
||||
const baseUrl = '/baseUrl/';
|
||||
expect(applyTrailingSlash('/baseUrl/', params(true, baseUrl))).toEqual(
|
||||
'/baseUrl/',
|
||||
);
|
||||
expect(applyTrailingSlash('/baseUrl/', params(false, baseUrl))).toEqual(
|
||||
'/baseUrl/',
|
||||
);
|
||||
expect(applyTrailingSlash('/baseUrl/', params(undefined, baseUrl))).toEqual(
|
||||
'/baseUrl/',
|
||||
);
|
||||
|
||||
expect(
|
||||
applyTrailingSlash('/baseUrl/?query#anchor', params(true, baseUrl)),
|
||||
).toEqual('/baseUrl/?query#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('/baseUrl/?query#anchor', params(false, baseUrl)),
|
||||
).toEqual('/baseUrl/?query#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('/baseUrl/?query#anchor', params(undefined, baseUrl)),
|
||||
).toEqual('/baseUrl/?query#anchor');
|
||||
});
|
||||
|
||||
test('should not apply to #anchor links ', () => {
|
||||
expect(applyTrailingSlash('#', true)).toEqual('#');
|
||||
expect(applyTrailingSlash('#', false)).toEqual('#');
|
||||
expect(applyTrailingSlash('#', undefined)).toEqual('#');
|
||||
expect(applyTrailingSlash('#anchor', true)).toEqual('#anchor');
|
||||
expect(applyTrailingSlash('#anchor', false)).toEqual('#anchor');
|
||||
expect(applyTrailingSlash('#anchor', undefined)).toEqual('#anchor');
|
||||
expect(applyTrailingSlash('#', params(true))).toEqual('#');
|
||||
expect(applyTrailingSlash('#', params(false))).toEqual('#');
|
||||
expect(applyTrailingSlash('#', params(undefined))).toEqual('#');
|
||||
expect(applyTrailingSlash('#anchor', params(true))).toEqual('#anchor');
|
||||
expect(applyTrailingSlash('#anchor', params(false))).toEqual('#anchor');
|
||||
expect(applyTrailingSlash('#anchor', params(undefined))).toEqual('#anchor');
|
||||
});
|
||||
|
||||
test('should apply to simple paths', () => {
|
||||
expect(applyTrailingSlash('abc', true)).toEqual('abc/');
|
||||
expect(applyTrailingSlash('abc', false)).toEqual('abc');
|
||||
expect(applyTrailingSlash('abc', undefined)).toEqual('abc');
|
||||
expect(applyTrailingSlash('abc/', true)).toEqual('abc/');
|
||||
expect(applyTrailingSlash('abc/', false)).toEqual('abc');
|
||||
expect(applyTrailingSlash('abc/', undefined)).toEqual('abc/');
|
||||
expect(applyTrailingSlash('/abc', true)).toEqual('/abc/');
|
||||
expect(applyTrailingSlash('/abc', false)).toEqual('/abc');
|
||||
expect(applyTrailingSlash('/abc', undefined)).toEqual('/abc');
|
||||
expect(applyTrailingSlash('/abc/', true)).toEqual('/abc/');
|
||||
expect(applyTrailingSlash('/abc/', false)).toEqual('/abc');
|
||||
expect(applyTrailingSlash('/abc/', undefined)).toEqual('/abc/');
|
||||
expect(applyTrailingSlash('abc', params(true))).toEqual('abc/');
|
||||
expect(applyTrailingSlash('abc', params(false))).toEqual('abc');
|
||||
expect(applyTrailingSlash('abc', params(undefined))).toEqual('abc');
|
||||
expect(applyTrailingSlash('abc/', params(true))).toEqual('abc/');
|
||||
expect(applyTrailingSlash('abc/', params(false))).toEqual('abc');
|
||||
expect(applyTrailingSlash('abc/', params(undefined))).toEqual('abc/');
|
||||
expect(applyTrailingSlash('/abc', params(true))).toEqual('/abc/');
|
||||
expect(applyTrailingSlash('/abc', params(false))).toEqual('/abc');
|
||||
expect(applyTrailingSlash('/abc', params(undefined))).toEqual('/abc');
|
||||
expect(applyTrailingSlash('/abc/', params(true))).toEqual('/abc/');
|
||||
expect(applyTrailingSlash('/abc/', params(false))).toEqual('/abc');
|
||||
expect(applyTrailingSlash('/abc/', params(undefined))).toEqual('/abc/');
|
||||
});
|
||||
|
||||
test('should apply to path with #anchor', () => {
|
||||
expect(applyTrailingSlash('/abc#anchor', true)).toEqual('/abc/#anchor');
|
||||
expect(applyTrailingSlash('/abc#anchor', false)).toEqual('/abc#anchor');
|
||||
expect(applyTrailingSlash('/abc#anchor', undefined)).toEqual('/abc#anchor');
|
||||
expect(applyTrailingSlash('/abc/#anchor', true)).toEqual('/abc/#anchor');
|
||||
expect(applyTrailingSlash('/abc/#anchor', false)).toEqual('/abc#anchor');
|
||||
expect(applyTrailingSlash('/abc/#anchor', undefined)).toEqual(
|
||||
expect(applyTrailingSlash('/abc#anchor', params(true))).toEqual(
|
||||
'/abc/#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc#anchor', params(false))).toEqual(
|
||||
'/abc#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc#anchor', params(undefined))).toEqual(
|
||||
'/abc#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc/#anchor', params(true))).toEqual(
|
||||
'/abc/#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc/#anchor', params(false))).toEqual(
|
||||
'/abc#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc/#anchor', params(undefined))).toEqual(
|
||||
'/abc/#anchor',
|
||||
);
|
||||
});
|
||||
|
||||
test('should apply to path with ?search', () => {
|
||||
expect(applyTrailingSlash('/abc?search', true)).toEqual('/abc/?search');
|
||||
expect(applyTrailingSlash('/abc?search', false)).toEqual('/abc?search');
|
||||
expect(applyTrailingSlash('/abc?search', undefined)).toEqual('/abc?search');
|
||||
expect(applyTrailingSlash('/abc/?search', true)).toEqual('/abc/?search');
|
||||
expect(applyTrailingSlash('/abc/?search', false)).toEqual('/abc?search');
|
||||
expect(applyTrailingSlash('/abc/?search', undefined)).toEqual(
|
||||
expect(applyTrailingSlash('/abc?search', params(true))).toEqual(
|
||||
'/abc/?search',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc?search', params(false))).toEqual(
|
||||
'/abc?search',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc?search', params(undefined))).toEqual(
|
||||
'/abc?search',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc/?search', params(true))).toEqual(
|
||||
'/abc/?search',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc/?search', params(false))).toEqual(
|
||||
'/abc?search',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc/?search', params(undefined))).toEqual(
|
||||
'/abc/?search',
|
||||
);
|
||||
});
|
||||
|
||||
test('should apply to path with ?search#anchor', () => {
|
||||
expect(applyTrailingSlash('/abc?search#anchor', true)).toEqual(
|
||||
expect(applyTrailingSlash('/abc?search#anchor', params(true))).toEqual(
|
||||
'/abc/?search#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc?search#anchor', false)).toEqual(
|
||||
expect(applyTrailingSlash('/abc?search#anchor', params(false))).toEqual(
|
||||
'/abc?search#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc?search#anchor', undefined)).toEqual(
|
||||
expect(applyTrailingSlash('/abc?search#anchor', params(undefined))).toEqual(
|
||||
'/abc?search#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc/?search#anchor', true)).toEqual(
|
||||
expect(applyTrailingSlash('/abc/?search#anchor', params(true))).toEqual(
|
||||
'/abc/?search#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc/?search#anchor', false)).toEqual(
|
||||
expect(applyTrailingSlash('/abc/?search#anchor', params(false))).toEqual(
|
||||
'/abc?search#anchor',
|
||||
);
|
||||
expect(applyTrailingSlash('/abc/?search#anchor', undefined)).toEqual(
|
||||
'/abc/?search#anchor',
|
||||
);
|
||||
expect(
|
||||
applyTrailingSlash('/abc/?search#anchor', params(undefined)),
|
||||
).toEqual('/abc/?search#anchor');
|
||||
});
|
||||
|
||||
test('should apply to fully qualified urls', () => {
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc?search#anchor', true),
|
||||
applyTrailingSlash('https://xyz.com/abc?search#anchor', params(true)),
|
||||
).toEqual('https://xyz.com/abc/?search#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc?search#anchor', false),
|
||||
applyTrailingSlash('https://xyz.com/abc?search#anchor', params(false)),
|
||||
).toEqual('https://xyz.com/abc?search#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc?search#anchor', undefined),
|
||||
applyTrailingSlash(
|
||||
'https://xyz.com/abc?search#anchor',
|
||||
params(undefined),
|
||||
),
|
||||
).toEqual('https://xyz.com/abc?search#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc/?search#anchor', true),
|
||||
applyTrailingSlash('https://xyz.com/abc/?search#anchor', params(true)),
|
||||
).toEqual('https://xyz.com/abc/?search#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc/?search#anchor', false),
|
||||
applyTrailingSlash('https://xyz.com/abc/?search#anchor', params(false)),
|
||||
).toEqual('https://xyz.com/abc?search#anchor');
|
||||
expect(
|
||||
applyTrailingSlash('https://xyz.com/abc/?search#anchor', undefined),
|
||||
applyTrailingSlash(
|
||||
'https://xyz.com/abc/?search#anchor',
|
||||
params(undefined),
|
||||
),
|
||||
).toEqual('https://xyz.com/abc/?search#anchor');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,10 +5,20 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import type {DocusaurusConfig} from '@docusaurus/types';
|
||||
|
||||
export type ApplyTrailingSlashParams = Pick<
|
||||
DocusaurusConfig,
|
||||
'trailingSlash' | 'baseUrl'
|
||||
>;
|
||||
|
||||
// Trailing slash handling depends in some site configuration options
|
||||
export default function applyTrailingSlash(
|
||||
path: string,
|
||||
trailingSlash: boolean | undefined,
|
||||
options: ApplyTrailingSlashParams,
|
||||
): string {
|
||||
const {trailingSlash, baseUrl} = options;
|
||||
|
||||
if (path.startsWith('#')) {
|
||||
// Never apply trailing slash to an anchor link
|
||||
return path;
|
||||
|
@ -34,7 +44,14 @@ export default function applyTrailingSlash(
|
|||
const [pathname] = path.split(/[#?]/);
|
||||
|
||||
// Never transform '/' to ''
|
||||
const newPathname =
|
||||
pathname === '/' ? '/' : handleTrailingSlash(pathname, trailingSlash);
|
||||
// Never remove the baseUrl trailing slash!
|
||||
// If baseUrl = /myBase/, we want to emit /myBase/index.html and not /myBase.html !
|
||||
// See https://github.com/facebook/docusaurus/issues/5077
|
||||
const shouldNotApply = pathname === '/' || pathname === baseUrl;
|
||||
|
||||
const newPathname = shouldNotApply
|
||||
? pathname
|
||||
: handleTrailingSlash(pathname, trailingSlash);
|
||||
|
||||
return path.replace(pathname, newPathname);
|
||||
}
|
||||
|
|
|
@ -6,4 +6,6 @@
|
|||
*/
|
||||
|
||||
export {default as applyTrailingSlash} from './applyTrailingSlash';
|
||||
export type {ApplyTrailingSlashParams} from './applyTrailingSlash';
|
||||
|
||||
export {default as uniq} from './uniq';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue