Skip to content

Commit

Permalink
fix: nextjs parallel routes with catchall isn't supported
Browse files Browse the repository at this point in the history
  • Loading branch information
feugy committed May 23, 2024
1 parent 74942cd commit 3a04c04
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 10 deletions.
2 changes: 1 addition & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vercel/analytics",
"version": "1.3.0",
"version": "1.3.1",
"description": "Gain real-time traffic insights with Vercel Web Analytics",
"keywords": [
"analytics",
Expand Down
22 changes: 21 additions & 1 deletion packages/web/src/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,21 @@ describe('utils', () => {
const input = '/en/us/next-site';
const params = {
langs: ['en', 'us'],
teamSlug: 'vercel',
};
const expected = '/[...langs]/next-site';
expect(computeRoute(input, params)).toBe(expected);
});

it('handles array segments and individual segments', () => {
const input = '/en/us/next-site';
const params = {
langs: ['en', 'us'],
team: 'next-site',
};
const expected = '/[...langs]/[team]';
expect(computeRoute(input, params)).toBe(expected);
});

it('handles special characters in url', () => {
const input = '/123/test(test';
const params = {
Expand All @@ -172,6 +181,17 @@ describe('utils', () => {
expect(computeRoute(input, params)).toBe(expected);
});

it('parallel routes where params matched both individually and within arrays', () => {
const params = {
catchAll: ['m', 'john', 'p', 'shirt'],
merchantId: 'john',
productSlug: 'shirt',
};
expect(computeRoute('/m/john/p/shirt', params)).toBe(
'/m/[merchantId]/p/[productSlug]'
);
});

describe('edge case handling (same values for multiple params)', () => {
it('replaces based on the priority of the pathParams keys', () => {
const input = '/test/test';
Expand Down
35 changes: 27 additions & 8 deletions packages/web/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,31 @@ export function computeRoute(
}

let result = pathname;

try {
for (const [key, valueOrArray] of Object.entries(pathParams)) {
const isValueArray = Array.isArray(valueOrArray);
const value = isValueArray ? valueOrArray.join('/') : valueOrArray;
const expr = isValueArray ? `...${key}` : key;

const matcher = new RegExp(`/${escapeRegExp(value)}(?=[/?#]|$)`);
const keys = Object.entries(pathParams).reduce<{
simple: string[];
multiple: string[];
}>(
({ simple, multiple }, [key, value]) => ({
simple: Array.isArray(value) ? simple : [...simple, key],
multiple: Array.isArray(value) ? [...multiple, key] : multiple,
}),
{ simple: [], multiple: [] }
);
// simple keys must be handled first
for (const key of keys.simple) {
const matcher = turnValueToRegExp(pathParams[key] as string);
if (matcher.test(result)) {
result = result.replace(matcher, `/[${key}]`);
}
}
// array values next
for (const key of keys.multiple) {
const matcher = turnValueToRegExp(
(pathParams[key] as string[]).join('/')
);
if (matcher.test(result)) {
result = result.replace(matcher, `/[${expr}]`);
result = result.replace(matcher, `/[...${key}]`);
}
}

Expand All @@ -102,6 +117,10 @@ export function computeRoute(
}
}

function turnValueToRegExp(value: string): RegExp {
return new RegExp(`/${escapeRegExp(value)}(?=[/?#]|$)`);
}

function escapeRegExp(string: string): string {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

0 comments on commit 3a04c04

Please sign in to comment.