mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-06 02:08:55 +02:00
improve a bit collectRedirects
This commit is contained in:
parent
d8c163e76b
commit
26beb00476
6 changed files with 180 additions and 22 deletions
|
@ -0,0 +1,154 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2017-present, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {PluginContext, UserPluginOptions} from '../types';
|
||||||
|
import collectRedirects from '../collectRedirects';
|
||||||
|
import normalizePluginOptions from '../normalizePluginOptions';
|
||||||
|
import {removeTrailingSlash} from '../utils';
|
||||||
|
|
||||||
|
function createTestPluginContext(
|
||||||
|
options?: UserPluginOptions,
|
||||||
|
routesPaths: string[] = [],
|
||||||
|
): PluginContext {
|
||||||
|
return {
|
||||||
|
outDir: '/tmp',
|
||||||
|
baseUrl: 'https://docusaurus.io',
|
||||||
|
routesPaths: routesPaths,
|
||||||
|
options: normalizePluginOptions(options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('collectRedirects', () => {
|
||||||
|
test('should collect no redirect for undefined config', () => {
|
||||||
|
expect(
|
||||||
|
collectRedirects(createTestPluginContext(undefined, ['/', '/path'])),
|
||||||
|
).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should collect no redirect for empty config', () => {
|
||||||
|
expect(collectRedirects(createTestPluginContext({}))).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should collect redirects to html/exe extension', () => {
|
||||||
|
expect(
|
||||||
|
collectRedirects(
|
||||||
|
createTestPluginContext(
|
||||||
|
{
|
||||||
|
fromExtensions: ['html', 'exe'],
|
||||||
|
},
|
||||||
|
['/', '/somePath', '/otherPath.html'],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
fromRoutePath: '/somePath.html',
|
||||||
|
toRoutePath: '/somePath',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fromRoutePath: '/somePath.exe',
|
||||||
|
toRoutePath: '/somePath',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should collect redirects to html/exe extension', () => {
|
||||||
|
expect(
|
||||||
|
collectRedirects(
|
||||||
|
createTestPluginContext(
|
||||||
|
{
|
||||||
|
toExtensions: ['html', 'exe'],
|
||||||
|
},
|
||||||
|
['/', '/somePath', '/otherPath.html'],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
fromRoutePath: '/otherPath',
|
||||||
|
toRoutePath: '/otherPath.html',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should collect redirects with custom redirect creator', () => {
|
||||||
|
expect(
|
||||||
|
collectRedirects(
|
||||||
|
createTestPluginContext(
|
||||||
|
{
|
||||||
|
createRedirects: (routePath) => {
|
||||||
|
return [
|
||||||
|
`${removeTrailingSlash(routePath)}/some/path/suffix1`,
|
||||||
|
`${removeTrailingSlash(routePath)}/some/other/path/suffix2`,
|
||||||
|
];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
['/', '/testpath', '/otherPath.html'],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
fromRoutePath: '/some/path/suffix1',
|
||||||
|
toRoutePath: '/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fromRoutePath: '/some/other/path/suffix2',
|
||||||
|
toRoutePath: '/',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
fromRoutePath: '/testpath/some/path/suffix1',
|
||||||
|
toRoutePath: '/testpath',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fromRoutePath: '/testpath/some/other/path/suffix2',
|
||||||
|
toRoutePath: '/testpath',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
fromRoutePath: '/otherPath.html/some/path/suffix1',
|
||||||
|
toRoutePath: '/otherPath.html',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fromRoutePath: '/otherPath.html/some/other/path/suffix2',
|
||||||
|
toRoutePath: '/otherPath.html',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should filter unwanted redirects', () => {
|
||||||
|
expect(
|
||||||
|
collectRedirects(
|
||||||
|
createTestPluginContext(
|
||||||
|
{
|
||||||
|
fromExtensions: ['html', 'exe'],
|
||||||
|
toExtensions: ['html', 'exe'],
|
||||||
|
},
|
||||||
|
[
|
||||||
|
'/',
|
||||||
|
'/somePath',
|
||||||
|
'/somePath.html',
|
||||||
|
'/somePath.exe',
|
||||||
|
'/fromShouldWork.html',
|
||||||
|
'/toShouldWork',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
fromRoutePath: '/toShouldWork.html',
|
||||||
|
toRoutePath: '/toShouldWork',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fromRoutePath: '/toShouldWork.exe',
|
||||||
|
toRoutePath: '/toShouldWork',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fromRoutePath: '/fromShouldWork',
|
||||||
|
toRoutePath: '/fromShouldWork.html',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
|
@ -44,11 +44,11 @@ const createExtensionValidationTests = (
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('fromExtensionsRedirectCreator', () => {
|
describe('toExtensionsRedirectCreator', () => {
|
||||||
createExtensionValidationTests(fromExtensionsRedirectCreator);
|
createExtensionValidationTests(toExtensionsRedirectCreator);
|
||||||
|
|
||||||
test('should create redirects from html/htm extensions', () => {
|
test('should create redirects from html/htm extensions', () => {
|
||||||
const redirectCreator = fromExtensionsRedirectCreator(['html', 'htm']);
|
const redirectCreator = toExtensionsRedirectCreator(['html', 'htm']);
|
||||||
expect(redirectCreator('')).toEqual([]);
|
expect(redirectCreator('')).toEqual([]);
|
||||||
expect(redirectCreator('/')).toEqual([]);
|
expect(redirectCreator('/')).toEqual([]);
|
||||||
expect(redirectCreator('/abc.html')).toEqual(['/abc']);
|
expect(redirectCreator('/abc.html')).toEqual(['/abc']);
|
||||||
|
@ -57,18 +57,18 @@ describe('fromExtensionsRedirectCreator', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not create redirection for an empty extension array', () => {
|
test('should not create redirection for an empty extension array', () => {
|
||||||
const redirectCreator = fromExtensionsRedirectCreator([]);
|
const redirectCreator = toExtensionsRedirectCreator([]);
|
||||||
expect(redirectCreator('')).toEqual([]);
|
expect(redirectCreator('')).toEqual([]);
|
||||||
expect(redirectCreator('/')).toEqual([]);
|
expect(redirectCreator('/')).toEqual([]);
|
||||||
expect(redirectCreator('/abc.html')).toEqual([]);
|
expect(redirectCreator('/abc.html')).toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toExtensionsRedirectCreator', () => {
|
describe('fromExtensionsRedirectCreator', () => {
|
||||||
createExtensionValidationTests(toExtensionsRedirectCreator);
|
createExtensionValidationTests(fromExtensionsRedirectCreator);
|
||||||
|
|
||||||
test('should create redirects to html/htm extensions', () => {
|
test('should create redirects to html/htm extensions', () => {
|
||||||
const redirectCreator = toExtensionsRedirectCreator(['html', 'htm']);
|
const redirectCreator = fromExtensionsRedirectCreator(['html', 'htm']);
|
||||||
expect(redirectCreator('')).toEqual([]);
|
expect(redirectCreator('')).toEqual([]);
|
||||||
expect(redirectCreator('/')).toEqual([]);
|
expect(redirectCreator('/')).toEqual([]);
|
||||||
expect(redirectCreator('/abc')).toEqual(['/abc.html', '/abc.htm']);
|
expect(redirectCreator('/abc')).toEqual(['/abc.html', '/abc.htm']);
|
||||||
|
@ -77,7 +77,7 @@ describe('toExtensionsRedirectCreator', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not create redirection for an empty extension array', () => {
|
test('should not create redirection for an empty extension array', () => {
|
||||||
const redirectCreator = toExtensionsRedirectCreator([]);
|
const redirectCreator = fromExtensionsRedirectCreator([]);
|
||||||
expect(redirectCreator('')).toEqual([]);
|
expect(redirectCreator('')).toEqual([]);
|
||||||
expect(redirectCreator('/')).toEqual([]);
|
expect(redirectCreator('/')).toEqual([]);
|
||||||
expect(redirectCreator('/abc')).toEqual([]);
|
expect(redirectCreator('/abc')).toEqual([]);
|
||||||
|
|
|
@ -31,6 +31,8 @@ function filterUnwantedRedirects(
|
||||||
redirects: RedirectMetadata[],
|
redirects: RedirectMetadata[],
|
||||||
pluginContext: PluginContext,
|
pluginContext: PluginContext,
|
||||||
): RedirectMetadata[] {
|
): RedirectMetadata[] {
|
||||||
|
// TODO how should we warn the user of filtered redirects?
|
||||||
|
|
||||||
// we don't want to create twice the same redirect
|
// we don't want to create twice the same redirect
|
||||||
redirects = uniqBy(redirects, (redirect) => redirect.fromRoutePath);
|
redirects = uniqBy(redirects, (redirect) => redirect.fromRoutePath);
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default function pluginClientRedirectsPages(
|
||||||
async postBuild(props: Props) {
|
async postBuild(props: Props) {
|
||||||
const pluginContext: PluginContext = {
|
const pluginContext: PluginContext = {
|
||||||
routesPaths: props.routesPaths,
|
routesPaths: props.routesPaths,
|
||||||
siteConfig: props.siteConfig,
|
baseUrl: props.baseUrl,
|
||||||
outDir: props.outDir,
|
outDir: props.outDir,
|
||||||
options,
|
options,
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,7 +38,8 @@ const validateExtension = (ext: string) => {
|
||||||
|
|
||||||
const addLeadingDot = (extension: string) => `.${extension}`;
|
const addLeadingDot = (extension: string) => `.${extension}`;
|
||||||
|
|
||||||
export function fromExtensionsRedirectCreator(
|
// Create new /path that redirects to existing an /path.html
|
||||||
|
export function toExtensionsRedirectCreator(
|
||||||
extensions: string[],
|
extensions: string[],
|
||||||
): RedirectsCreator {
|
): RedirectsCreator {
|
||||||
extensions.forEach(validateExtension);
|
extensions.forEach(validateExtension);
|
||||||
|
@ -60,7 +61,8 @@ export function fromExtensionsRedirectCreator(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toExtensionsRedirectCreator(
|
// Create new /path.html that redirects to existing an /path
|
||||||
|
export function fromExtensionsRedirectCreator(
|
||||||
extensions: string[],
|
extensions: string[],
|
||||||
): RedirectsCreator {
|
): RedirectsCreator {
|
||||||
extensions.forEach(validateExtension);
|
extensions.forEach(validateExtension);
|
||||||
|
|
|
@ -15,24 +15,24 @@ export type PluginOptions = {
|
||||||
|
|
||||||
export type UserPluginOptions = Partial<PluginOptions>;
|
export type UserPluginOptions = Partial<PluginOptions>;
|
||||||
|
|
||||||
|
// The minimal infos the plugin needs to work
|
||||||
|
export type PluginContext = Pick<
|
||||||
|
Props,
|
||||||
|
'routesPaths' | 'outDir' | 'baseUrl'
|
||||||
|
> & {
|
||||||
|
options: PluginOptions;
|
||||||
|
};
|
||||||
|
|
||||||
// For a given existing route path,
|
// For a given existing route path,
|
||||||
// return all the paths from which we should redirect from
|
// return all the paths from which we should redirect from
|
||||||
export type RedirectsCreator = (
|
export type RedirectsCreator = (
|
||||||
routePath: string,
|
routePath: string,
|
||||||
) => string[] | null | undefined;
|
) => string[] | null | undefined;
|
||||||
|
|
||||||
// Having an in-memory representation of wanted redirects is easier to test
|
// In-memory representation of redirects we want: easier to test
|
||||||
|
// /!\ easy to be confused: "fromRoutePath" is the new page we should create,
|
||||||
|
// that redirects to "toRoutePath" the existing Docusaurus page
|
||||||
export type RedirectMetadata = {
|
export type RedirectMetadata = {
|
||||||
fromRoutePath: string;
|
fromRoutePath: string;
|
||||||
toRoutePath: string;
|
toRoutePath: string;
|
||||||
toUrl: string;
|
|
||||||
redirectPageContent: string;
|
|
||||||
redirectAbsoluteFilePath: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PluginContext = Pick<
|
|
||||||
Props,
|
|
||||||
'routesPaths' | 'siteConfig' | 'outDir'
|
|
||||||
> & {
|
|
||||||
options: PluginOptions;
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue