Skip to content

Commit 685bf04

Browse files
authored
Merge branch 'cg-next-client-manifest' into cg-next-manifest-webpack
2 parents 4ad310f + e105620 commit 685bf04

File tree

7 files changed

+81
-86
lines changed

7 files changed

+81
-86
lines changed

packages/nextjs/src/config/manifest/buildManifest.ts renamed to packages/nextjs/src/config/manifest/createRouteManifest.ts

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,6 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
3-
4-
export type RouteInfo = {
5-
path: string;
6-
dynamic: boolean;
7-
pattern?: string;
8-
paramNames?: string[];
9-
};
10-
11-
export type RouteManifest = {
12-
dynamic: RouteInfo[];
13-
static: RouteInfo[];
14-
};
3+
import type { RouteInfo, RouteManifest } from './types';
154

165
export type CreateRouteManifestOptions = {
176
// For starters we only support app router
@@ -38,13 +27,12 @@ function getDynamicRouteSegment(name: string): string {
3827
// Required catchall: [...param]
3928
const paramName = name.slice(4, -1); // Remove [... and ]
4029
return `:${paramName}*`;
41-
} else {
42-
// Regular dynamic: [param]
43-
return `:${name.slice(1, -1)}`;
4430
}
31+
// Regular dynamic: [param]
32+
return `:${name.slice(1, -1)}`;
4533
}
4634

47-
function buildRegexForDynamicRoute(routePath: string): { pattern: string; paramNames: string[] } {
35+
function buildRegexForDynamicRoute(routePath: string): { regex: string; paramNames: string[] } {
4836
const segments = routePath.split('/').filter(Boolean);
4937
const regexSegments: string[] = [];
5038
const paramNames: string[] = [];
@@ -86,7 +74,7 @@ function buildRegexForDynamicRoute(routePath: string): { pattern: string; paramN
8674
pattern = `^/${regexSegments.join('/')}$`;
8775
}
8876

89-
return { pattern, paramNames };
77+
return { regex: pattern, paramNames };
9078
}
9179

9280
function scanAppDirectory(dir: string, basePath: string = ''): RouteInfo[] {
@@ -101,17 +89,15 @@ function scanAppDirectory(dir: string, basePath: string = ''): RouteInfo[] {
10189
const isDynamic = routePath.includes(':');
10290

10391
if (isDynamic) {
104-
const { pattern, paramNames } = buildRegexForDynamicRoute(routePath);
92+
const { regex, paramNames } = buildRegexForDynamicRoute(routePath);
10593
routes.push({
10694
path: routePath,
107-
dynamic: true,
108-
pattern,
95+
regex,
10996
paramNames,
11097
});
11198
} else {
11299
routes.push({
113100
path: routePath,
114-
dynamic: false,
115101
});
116102
}
117103
}
@@ -171,8 +157,7 @@ export function createRouteManifest(options?: CreateRouteManifestOptions): Route
171157

172158
if (!targetDir) {
173159
return {
174-
dynamic: [],
175-
static: [],
160+
routes: [],
176161
};
177162
}
178163

@@ -184,8 +169,7 @@ export function createRouteManifest(options?: CreateRouteManifestOptions): Route
184169
const routes = scanAppDirectory(targetDir);
185170

186171
const manifest: RouteManifest = {
187-
dynamic: routes.filter(route => route.dynamic),
188-
static: routes.filter(route => !route.dynamic),
172+
routes,
189173
};
190174

191175
// set cache
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Information about a single route in the manifest
3+
*/
4+
export type RouteInfo = {
5+
/**
6+
* The parameterised route path, e.g. "/users/[id]"
7+
*/
8+
path: string;
9+
/**
10+
* (Optional) The regex pattern for dynamic routes
11+
*/
12+
regex?: string;
13+
/**
14+
* (Optional) The names of dynamic parameters in the route
15+
*/
16+
paramNames?: string[];
17+
};
18+
19+
/**
20+
* The manifest containing all routes discovered in the app
21+
*/
22+
export type RouteManifest = {
23+
/**
24+
* List of all routes (static and dynamic)
25+
*/
26+
routes: RouteInfo[];
27+
};

packages/nextjs/test/config/manifest/suites/catchall/catchall.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
import path from 'path';
22
import { describe, expect, test } from 'vitest';
3-
import { createRouteManifest } from '../../../../../src/config/manifest/buildManifest';
3+
import { createRouteManifest } from '../../../../../src/config/manifest/createRouteManifest';
44

55
describe('catchall', () => {
66
const manifest = createRouteManifest({ appDirPath: path.join(__dirname, 'app') });
77

88
test('should generate a manifest with catchall route', () => {
99
expect(manifest).toEqual({
10-
dynamic: [
10+
routes: [
11+
{ path: '/' },
1112
{
1213
path: '/catchall/:path*?',
13-
dynamic: true,
14-
pattern: '^/catchall(?:/(.*))?$',
14+
regex: '^/catchall(?:/(.*))?$',
1515
paramNames: ['path'],
1616
},
1717
],
18-
static: [{ path: '/', dynamic: false }],
1918
});
2019
});
2120

2221
test('should generate correct pattern for catchall route', () => {
23-
const regex = new RegExp(manifest.dynamic[0]?.pattern ?? '');
22+
const catchallRoute = manifest.routes.find(route => route.path === '/catchall/:path*?');
23+
const regex = new RegExp(catchallRoute?.regex ?? '');
2424
expect(regex.test('/catchall/123')).toBe(true);
2525
expect(regex.test('/catchall/abc')).toBe(true);
2626
expect(regex.test('/catchall/123/456')).toBe(true);

packages/nextjs/test/config/manifest/suites/dynamic/dynamic.test.ts

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,42 @@
11
import path from 'path';
22
import { describe, expect, test } from 'vitest';
3-
import { createRouteManifest } from '../../../../../src/config/manifest/buildManifest';
3+
import { createRouteManifest } from '../../../../../src/config/manifest/createRouteManifest';
44

55
describe('dynamic', () => {
66
const manifest = createRouteManifest({ appDirPath: path.join(__dirname, 'app') });
77

8-
test('should generate a comprehensive dynamic manifest', () => {
8+
test('should generate a dynamic manifest', () => {
99
expect(manifest).toEqual({
10-
dynamic: [
10+
routes: [
11+
{ path: '/' },
1112
{
1213
path: '/dynamic/:id',
13-
dynamic: true,
14-
pattern: '^/dynamic/([^/]+)$',
14+
regex: '^/dynamic/([^/]+)$',
1515
paramNames: ['id'],
1616
},
17+
{ path: '/static/nested' },
1718
{
1819
path: '/users/:id',
19-
dynamic: true,
20-
pattern: '^/users/([^/]+)$',
20+
regex: '^/users/([^/]+)$',
2121
paramNames: ['id'],
2222
},
2323
{
2424
path: '/users/:id/posts/:postId',
25-
dynamic: true,
26-
pattern: '^/users/([^/]+)/posts/([^/]+)$',
25+
regex: '^/users/([^/]+)/posts/([^/]+)$',
2726
paramNames: ['id', 'postId'],
2827
},
2928
{
3029
path: '/users/:id/settings',
31-
dynamic: true,
32-
pattern: '^/users/([^/]+)/settings$',
30+
regex: '^/users/([^/]+)/settings$',
3331
paramNames: ['id'],
3432
},
3533
],
36-
static: [
37-
{ path: '/', dynamic: false },
38-
{ path: '/static/nested', dynamic: false },
39-
],
4034
});
4135
});
4236

4337
test('should generate correct pattern for single dynamic route', () => {
44-
const singleDynamic = manifest.dynamic.find(route => route.path === '/dynamic/:id');
45-
const regex = new RegExp(singleDynamic?.pattern ?? '');
38+
const singleDynamic = manifest.routes.find(route => route.path === '/dynamic/:id');
39+
const regex = new RegExp(singleDynamic?.regex ?? '');
4640
expect(regex.test('/dynamic/123')).toBe(true);
4741
expect(regex.test('/dynamic/abc')).toBe(true);
4842
expect(regex.test('/dynamic/123/456')).toBe(false);
@@ -51,8 +45,8 @@ describe('dynamic', () => {
5145
});
5246

5347
test('should generate correct pattern for mixed static-dynamic route', () => {
54-
const mixedRoute = manifest.dynamic.find(route => route.path === '/users/:id/settings');
55-
const regex = new RegExp(mixedRoute?.pattern ?? '');
48+
const mixedRoute = manifest.routes.find(route => route.path === '/users/:id/settings');
49+
const regex = new RegExp(mixedRoute?.regex ?? '');
5650

5751
expect(regex.test('/users/123/settings')).toBe(true);
5852
expect(regex.test('/users/john-doe/settings')).toBe(true);
@@ -62,8 +56,8 @@ describe('dynamic', () => {
6256
});
6357

6458
test('should generate correct pattern for multiple dynamic segments', () => {
65-
const multiDynamic = manifest.dynamic.find(route => route.path === '/users/:id/posts/:postId');
66-
const regex = new RegExp(multiDynamic?.pattern ?? '');
59+
const multiDynamic = manifest.routes.find(route => route.path === '/users/:id/posts/:postId');
60+
const regex = new RegExp(multiDynamic?.regex ?? '');
6761

6862
expect(regex.test('/users/123/posts/456')).toBe(true);
6963
expect(regex.test('/users/john/posts/my-post')).toBe(true);
@@ -79,11 +73,11 @@ describe('dynamic', () => {
7973

8074
test('should handle special characters in dynamic segments', () => {
8175
// Test that dynamic segments with special characters work properly
82-
const userSettingsRoute = manifest.dynamic.find(route => route.path === '/users/:id/settings');
76+
const userSettingsRoute = manifest.routes.find(route => route.path === '/users/:id/settings');
8377
expect(userSettingsRoute).toBeDefined();
84-
expect(userSettingsRoute?.pattern).toBeDefined();
78+
expect(userSettingsRoute?.regex).toBeDefined();
8579

86-
const regex = new RegExp(userSettingsRoute!.pattern!);
80+
const regex = new RegExp(userSettingsRoute!.regex!);
8781
expect(regex.test('/users/user-with-dashes/settings')).toBe(true);
8882
expect(regex.test('/users/user_with_underscores/settings')).toBe(true);
8983
expect(regex.test('/users/123/settings')).toBe(true);

packages/nextjs/test/config/manifest/suites/file-extensions/file-extensions.test.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
import path from 'path';
22
import { describe, expect, test } from 'vitest';
3-
import { createRouteManifest } from '../../../../../src/config/manifest/buildManifest';
3+
import { createRouteManifest } from '../../../../../src/config/manifest/createRouteManifest';
44

55
describe('file-extensions', () => {
66
const manifest = createRouteManifest({ appDirPath: path.join(__dirname, 'app') });
77

88
test('should detect page files with all supported extensions', () => {
99
expect(manifest).toEqual({
10-
dynamic: [],
11-
static: [
12-
{ path: '/', dynamic: false },
13-
{ path: '/javascript', dynamic: false },
14-
{ path: '/jsx-route', dynamic: false },
15-
{ path: '/mixed', dynamic: false },
16-
{ path: '/precedence', dynamic: false },
17-
{ path: '/typescript', dynamic: false },
10+
routes: [
11+
{ path: '/' },
12+
{ path: '/javascript' },
13+
{ path: '/jsx-route' },
14+
{ path: '/mixed' },
15+
{ path: '/precedence' },
16+
{ path: '/typescript' },
1817
],
1918
});
2019
});

packages/nextjs/test/config/manifest/suites/route-groups/route-groups.test.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,31 @@
11
import path from 'path';
22
import { describe, expect, test } from 'vitest';
3-
import { createRouteManifest } from '../../../../../src/config/manifest/buildManifest';
3+
import { createRouteManifest } from '../../../../../src/config/manifest/createRouteManifest';
44

55
describe('route-groups', () => {
66
const manifest = createRouteManifest({ appDirPath: path.join(__dirname, 'app') });
77

88
test('should generate a manifest with route groups', () => {
99
expect(manifest).toEqual({
10-
dynamic: [
10+
routes: [
11+
{ path: '/' },
12+
{ path: '/login' },
13+
{ path: '/signup' },
14+
{ path: '/dashboard' },
1115
{
1216
path: '/dashboard/:id',
13-
dynamic: true,
14-
pattern: '^/dashboard/([^/]+)$',
17+
regex: '^/dashboard/([^/]+)$',
1518
paramNames: ['id'],
1619
},
17-
],
18-
static: [
19-
{ path: '/', dynamic: false },
20-
{ path: '/login', dynamic: false },
21-
{ path: '/signup', dynamic: false },
22-
{ path: '/dashboard', dynamic: false },
23-
{ path: '/settings/profile', dynamic: false },
24-
{ path: '/public/about', dynamic: false },
20+
{ path: '/settings/profile' },
21+
{ path: '/public/about' },
2522
],
2623
});
2724
});
2825

2926
test('should handle dynamic routes within route groups', () => {
30-
const dynamicRoute = manifest.dynamic.find(route => route.path.includes('/dashboard/:id'));
31-
const regex = new RegExp(dynamicRoute?.pattern ?? '');
27+
const dynamicRoute = manifest.routes.find(route => route.path.includes('/dashboard/:id'));
28+
const regex = new RegExp(dynamicRoute?.regex ?? '');
3229
expect(regex.test('/dashboard/123')).toBe(true);
3330
expect(regex.test('/dashboard/abc')).toBe(true);
3431
expect(regex.test('/dashboard/123/456')).toBe(false);
Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
import path from 'path';
22
import { describe, expect, test } from 'vitest';
3-
import { createRouteManifest } from '../../../../../src/config/manifest/buildManifest';
3+
import { createRouteManifest } from '../../../../../src/config/manifest/createRouteManifest';
44

55
describe('static', () => {
66
test('should generate a static manifest', () => {
77
const manifest = createRouteManifest({ appDirPath: path.join(__dirname, 'app') });
88
expect(manifest).toEqual({
9-
dynamic: [],
10-
static: [
11-
{ path: '/', dynamic: false },
12-
{ path: '/some/nested', dynamic: false },
13-
{ path: '/user', dynamic: false },
14-
{ path: '/users', dynamic: false },
15-
],
9+
routes: [{ path: '/' }, { path: '/some/nested' }, { path: '/user' }, { path: '/users' }],
1610
});
1711
});
1812
});

0 commit comments

Comments
 (0)