Implement priority (#7210)

This commit is contained in:
Matthew Phillips 2023-05-30 08:31:00 -04:00 committed by GitHub
parent ef9a456f25
commit fa03a41a7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 3 deletions

View file

@ -62,6 +62,10 @@ function getParts(part: string, file: string) {
return result;
}
function areSamePart(a: RoutePart, b: RoutePart) {
return a.content === b.content && a.dynamic === b.dynamic && a.spread === b.spread;
}
function getPattern(
segments: RoutePart[][],
base: string,
@ -204,6 +208,49 @@ function injectedRouteToItem(
};
}
// Seeings if the two routes are siblings of each other, with `b` being the route
// in focus. If it is in the same parent folder as `a`, they are siblings.
function areSiblings(a: RouteData, b: RouteData) {
if(a.segments.length < b.segments.length) return false;
for(let i = 0; i < b.segments.length - 1; i++) {
let segment = b.segments[i];
if(segment.length === a.segments[i].length) {
for(let j = 0; j < segment.length; j++) {
if(!areSamePart(segment[j], a.segments[i][j])) {
return false;
}
}
} else {
return false;
}
}
return true;
}
// A fast insertion method based on binary search.
function binaryInsert<T>(sorted: T[], item: T, insertComparator: (a: T, item: T) => boolean) {
if(sorted.length === 0) {
sorted.push(item);
return 0;
}
let low = 0, high = sorted.length - 1, mid = 0;
while (low <= high) {
mid = low + (high - low >> 1);
if(insertComparator(sorted[mid], item)) {
low = mid + 1;
} else {
high = mid -1;
}
}
if(insertComparator(sorted[mid], item)) {
mid++;
}
sorted.splice(mid, 0, item);
return mid;
}
export interface CreateRouteManifestParams {
/** Astro Settings object */
settings: AstroSettings;
@ -444,9 +491,7 @@ export function createRouteManifest(
.map(([{ dynamic, content }]) => (dynamic ? `[${content}]` : content))
.join('/')}`.toLowerCase();
routes.unshift({
const routeData: RouteData = {
type: 'redirect',
route,
pattern,
@ -458,6 +503,17 @@ export function createRouteManifest(
prerender: false,
redirect: to,
redirectRoute: routes.find(r => r.route === to)
};
const isSpreadRoute = isSpread(route);
binaryInsert(routes, routeData, (a, item) => {
// If the routes are siblings and the redirect route is a spread
// Then it should come after the sibling unless it is also a spread.
// This essentially means that redirects are prioritized when *exactly* the same.
if(isSpreadRoute && areSiblings(a, item)) {
return !isSpread(a.route);
}
return true;
});
});
@ -465,3 +521,4 @@ export function createRouteManifest(
routes,
};
}

View file

@ -31,4 +31,32 @@ describe('routing - createRouteManifest', () => {
expect(pattern.test('')).to.equal(true);
expect(pattern.test('/')).to.equal(false);
});
it('redirects are sorted alongside the filesystem routes', async () => {
const fs = createFs(
{
'/src/pages/index.astro': `<h1>test</h1>`,
'/src/pages/blog/contributing.astro': `<h1>test</h1>`,
},
root
);
const settings = await createDefaultDevSettings(
{
base: '/search',
trailingSlash: 'never',
redirects: {
'/blog/[...slug]': '/'
}
},
root
);
const manifest = createRouteManifest({
cwd: fileURLToPath(root),
settings,
fsMod: fs,
});
expect(manifest.routes[1].route).to.equal('/blog/contributing');
expect(manifest.routes[2].route).to.equal('/blog/[...slug]');
})
});