fix(core): sortRoutes shouldn't have a default baseUrl value, this led to a bug (#10054)

This commit is contained in:
Sébastien Lorber 2024-04-18 15:08:30 +02:00 committed by GitHub
parent 4772b27a63
commit 128738786b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 58 additions and 20 deletions

View file

@ -58,7 +58,7 @@ Available ids are:\n- ${version.docs.map((d) => d.id).join('\n- ')}`,
} }
const createFakeActions = (contentDir: string) => { const createFakeActions = (contentDir: string) => {
const routeConfigs: RouteConfig[] = []; let routeConfigs: RouteConfig[] = [];
const dataContainer: {[key: string]: unknown} = {}; const dataContainer: {[key: string]: unknown} = {};
const globalDataContainer: {pluginName?: {pluginId: unknown}} = {}; const globalDataContainer: {pluginName?: {pluginId: unknown}} = {};
@ -83,7 +83,7 @@ const createFakeActions = (contentDir: string) => {
expectSnapshot: () => { expectSnapshot: () => {
// Sort the route config like in src/server/plugins/index.ts for // Sort the route config like in src/server/plugins/index.ts for
// consistent snapshot ordering // consistent snapshot ordering
sortRoutes(routeConfigs); routeConfigs = sortRoutes(routeConfigs, '/');
expect(routeConfigs).not.toEqual([]); expect(routeConfigs).not.toEqual([]);
expect(routeConfigs).toMatchSnapshot('route config'); expect(routeConfigs).toMatchSnapshot('route config');
expect(dataContainer).toMatchSnapshot('data'); expect(dataContainer).toMatchSnapshot('data');

View file

@ -202,9 +202,7 @@ describe('sortRoutes', () => {
}, },
]; ];
sortRoutes(routes); expect(sortRoutes(routes, '/')).toMatchSnapshot();
expect(routes).toMatchSnapshot();
}); });
it('sorts route config recursively', () => { it('sorts route config recursively', () => {
@ -248,9 +246,7 @@ describe('sortRoutes', () => {
}, },
]; ];
sortRoutes(routes); expect(sortRoutes(routes, '/')).toMatchSnapshot();
expect(routes).toMatchSnapshot();
}); });
it('sorts route config given a baseURL', () => { it('sorts route config given a baseURL', () => {
@ -290,8 +286,27 @@ describe('sortRoutes', () => {
}, },
]; ];
sortRoutes(routes, baseURL); expect(sortRoutes(routes, baseURL)).toMatchSnapshot();
});
expect(routes).toMatchSnapshot(); it('sorts parent route configs when one included in another', () => {
const r1: RouteConfig = {
path: '/one',
component: '',
routes: [{path: `/one/myDoc`, component: ''}],
};
const r2: RouteConfig = {
path: '/',
component: '',
routes: [{path: `/someDoc`, component: ''}],
};
const r3: RouteConfig = {
path: '/one/another',
component: '',
routes: [{path: `/one/another/myDoc`, component: ''}],
};
expect(sortRoutes([r1, r2, r3], '/')).toEqual([r3, r1, r2]);
expect(sortRoutes([r3, r1, r2], '/')).toEqual([r3, r1, r2]);
}); });
}); });

View file

@ -224,17 +224,18 @@ async function executeAllPluginsAllContentLoaded({
// - contentLoaded() // - contentLoaded()
// - allContentLoaded() // - allContentLoaded()
function mergeResults({ function mergeResults({
baseUrl,
plugins, plugins,
allContentLoadedResult, allContentLoadedResult,
}: { }: {
baseUrl: string;
plugins: LoadedPlugin[]; plugins: LoadedPlugin[];
allContentLoadedResult: AllContentLoadedResult; allContentLoadedResult: AllContentLoadedResult;
}) { }) {
const routes: PluginRouteConfig[] = [ const routes: PluginRouteConfig[] = sortRoutes(
...aggregateRoutes(plugins), [...aggregateRoutes(plugins), ...allContentLoadedResult.routes],
...allContentLoadedResult.routes, baseUrl,
]; );
sortRoutes(routes);
const globalData: GlobalData = mergeGlobalData( const globalData: GlobalData = mergeGlobalData(
aggregateGlobalData(plugins), aggregateGlobalData(plugins),
@ -279,6 +280,7 @@ export async function loadPlugins(
}); });
const {routes, globalData} = mergeResults({ const {routes, globalData} = mergeResults({
baseUrl: context.baseUrl,
plugins, plugins,
allContentLoadedResult, allContentLoadedResult,
}); });
@ -324,6 +326,7 @@ export async function reloadPlugin({
}); });
const {routes, globalData} = mergeResults({ const {routes, globalData} = mergeResults({
baseUrl: context.baseUrl,
plugins, plugins,
allContentLoadedResult, allContentLoadedResult,
}); });

View file

@ -27,10 +27,11 @@ export function applyRouteTrailingSlash<Route extends RouteConfig>(
}; };
} }
export function sortRoutes( export function sortRoutes<Route extends RouteConfig>(
routeConfigs: RouteConfig[], routesToSort: Route[],
baseUrl: string = '/', baseUrl: string,
): void { ): Route[] {
const routeConfigs = [...routesToSort];
// Sort the route config. This ensures that route with nested // Sort the route config. This ensures that route with nested
// routes is always placed last. // routes is always placed last.
routeConfigs.sort((a, b) => { routeConfigs.sort((a, b) => {
@ -48,6 +49,23 @@ export function sortRoutes(
if (!a.routes && b.routes) { if (!a.routes && b.routes) {
return -1; return -1;
} }
// If both are parent routes (for example routeBasePath: "/" and "/docs/"
// We must order them carefully in case of overlapping paths
if (a.routes && b.routes) {
if (a.path === b.path) {
// We don't really support that kind of routing ATM
// React-Router by default will only "enter" a single parent route
} else {
if (a.path.includes(b.path)) {
return -1;
}
if (b.path.includes(a.path)) {
return 1;
}
}
}
// Higher priority get placed first. // Higher priority get placed first.
if (a.priority || b.priority) { if (a.priority || b.priority) {
const priorityA = a.priority ?? 0; const priorityA = a.priority ?? 0;
@ -64,7 +82,9 @@ export function sortRoutes(
routeConfigs.forEach((routeConfig) => { routeConfigs.forEach((routeConfig) => {
if (routeConfig.routes) { if (routeConfig.routes) {
sortRoutes(routeConfig.routes, baseUrl); routeConfig.routes = sortRoutes(routeConfig.routes, baseUrl);
} }
}); });
return routeConfigs;
} }