@bleedingdev/modern-js-plugin-tanstack 3.5.0-ultramodern.100 → 3.5.0-ultramodern.102
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli/index.js +6 -2
- package/dist/cjs/cli/tanstackTypes/source.js +2 -3
- package/dist/esm/cli/index.mjs +6 -2
- package/dist/esm/cli/tanstackTypes/source.mjs +2 -3
- package/dist/esm-node/cli/index.mjs +6 -2
- package/dist/esm-node/cli/tanstackTypes/source.mjs +2 -3
- package/package.json +10 -9
- package/src/cli/index.ts +6 -0
- package/src/cli/tanstackTypes/source.ts +2 -3
- package/tests/router/cli.test.ts +202 -96
- package/tests/router/routerCompatibility.test.ts +0 -6
- package/tests/router/tanstackTypes.test.ts +333 -346
- package/tests/castRatchet.test.ts +0 -85
- package/tests/router/fixtures/router-gen.golden.txt +0 -71
package/dist/cjs/cli/index.js
CHANGED
|
@@ -169,7 +169,9 @@ var __webpack_exports__ = {};
|
|
|
169
169
|
if (0 === tanstackEntrypoints.length) return;
|
|
170
170
|
const { handleGeneratorEntryCode } = getRuntimeRouterCli();
|
|
171
171
|
const routesByEntry = await handleGeneratorEntryCode(api, tanstackEntrypoints, {
|
|
172
|
-
entrypointsKey: ENTRYPOINTS_KEY
|
|
172
|
+
entrypointsKey: ENTRYPOINTS_KEY,
|
|
173
|
+
hydrateRscClientRoutes: true,
|
|
174
|
+
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
173
175
|
});
|
|
174
176
|
await (0, external_artifacts_js_namespaceObject.writeTanstackRouterTypesForEntries)({
|
|
175
177
|
appContext: api.getAppContext(),
|
|
@@ -189,7 +191,9 @@ var __webpack_exports__ = {};
|
|
|
189
191
|
regenerate: async ({ api, entrypoints })=>{
|
|
190
192
|
const { handleGeneratorEntryCode } = getRuntimeRouterCli();
|
|
191
193
|
const routesByEntry = await handleGeneratorEntryCode(api, entrypoints, {
|
|
192
|
-
entrypointsKey: ENTRYPOINTS_KEY
|
|
194
|
+
entrypointsKey: ENTRYPOINTS_KEY,
|
|
195
|
+
hydrateRscClientRoutes: true,
|
|
196
|
+
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
193
197
|
});
|
|
194
198
|
await (0, external_artifacts_js_namespaceObject.writeTanstackRouterTypesForEntries)({
|
|
195
199
|
appContext: api.getAppContext(),
|
|
@@ -214,8 +214,7 @@ import {
|
|
|
214
214
|
createRouter,
|
|
215
215
|
createRouteStaticData,
|
|
216
216
|
type ModernRouterContext,
|
|
217
|
-
modernLoaderToTanstack,
|
|
218
|
-
modernTanstackRouterFastDefaults,
|
|
217
|
+
${loaderImportMap.size > 0 ? ' modernLoaderToTanstack,\n' : ''} modernTanstackRouterFastDefaults,
|
|
219
218
|
} from '@modern-js/plugin-tanstack/runtime';
|
|
220
219
|
|
|
221
220
|
${imports.join('\n')}
|
|
@@ -239,7 +238,7 @@ export const router = createRouter({
|
|
|
239
238
|
history: createMemoryHistory({
|
|
240
239
|
initialEntries: ['/'],
|
|
241
240
|
}),
|
|
242
|
-
context: {}
|
|
241
|
+
context: {},
|
|
243
242
|
});
|
|
244
243
|
`;
|
|
245
244
|
return {
|
package/dist/esm/cli/index.mjs
CHANGED
|
@@ -110,7 +110,9 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
110
110
|
if (0 === tanstackEntrypoints.length) return;
|
|
111
111
|
const { handleGeneratorEntryCode } = getRuntimeRouterCli();
|
|
112
112
|
const routesByEntry = await handleGeneratorEntryCode(api, tanstackEntrypoints, {
|
|
113
|
-
entrypointsKey: ENTRYPOINTS_KEY
|
|
113
|
+
entrypointsKey: ENTRYPOINTS_KEY,
|
|
114
|
+
hydrateRscClientRoutes: true,
|
|
115
|
+
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
114
116
|
});
|
|
115
117
|
await writeTanstackRouterTypesForEntries({
|
|
116
118
|
appContext: api.getAppContext(),
|
|
@@ -130,7 +132,9 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
130
132
|
regenerate: async ({ api, entrypoints })=>{
|
|
131
133
|
const { handleGeneratorEntryCode } = getRuntimeRouterCli();
|
|
132
134
|
const routesByEntry = await handleGeneratorEntryCode(api, entrypoints, {
|
|
133
|
-
entrypointsKey: ENTRYPOINTS_KEY
|
|
135
|
+
entrypointsKey: ENTRYPOINTS_KEY,
|
|
136
|
+
hydrateRscClientRoutes: true,
|
|
137
|
+
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
134
138
|
});
|
|
135
139
|
await writeTanstackRouterTypesForEntries({
|
|
136
140
|
appContext: api.getAppContext(),
|
|
@@ -172,8 +172,7 @@ import {
|
|
|
172
172
|
createRouter,
|
|
173
173
|
createRouteStaticData,
|
|
174
174
|
type ModernRouterContext,
|
|
175
|
-
modernLoaderToTanstack,
|
|
176
|
-
modernTanstackRouterFastDefaults,
|
|
175
|
+
${loaderImportMap.size > 0 ? ' modernLoaderToTanstack,\n' : ''} modernTanstackRouterFastDefaults,
|
|
177
176
|
} from '@modern-js/plugin-tanstack/runtime';
|
|
178
177
|
|
|
179
178
|
${imports.join('\n')}
|
|
@@ -197,7 +196,7 @@ export const router = createRouter({
|
|
|
197
196
|
history: createMemoryHistory({
|
|
198
197
|
initialEntries: ['/'],
|
|
199
198
|
}),
|
|
200
|
-
context: {}
|
|
199
|
+
context: {},
|
|
201
200
|
});
|
|
202
201
|
`;
|
|
203
202
|
return {
|
|
@@ -114,7 +114,9 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
114
114
|
if (0 === tanstackEntrypoints.length) return;
|
|
115
115
|
const { handleGeneratorEntryCode } = getRuntimeRouterCli();
|
|
116
116
|
const routesByEntry = await handleGeneratorEntryCode(api, tanstackEntrypoints, {
|
|
117
|
-
entrypointsKey: ENTRYPOINTS_KEY
|
|
117
|
+
entrypointsKey: ENTRYPOINTS_KEY,
|
|
118
|
+
hydrateRscClientRoutes: true,
|
|
119
|
+
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
118
120
|
});
|
|
119
121
|
await writeTanstackRouterTypesForEntries({
|
|
120
122
|
appContext: api.getAppContext(),
|
|
@@ -134,7 +136,9 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
134
136
|
regenerate: async ({ api, entrypoints })=>{
|
|
135
137
|
const { handleGeneratorEntryCode } = getRuntimeRouterCli();
|
|
136
138
|
const routesByEntry = await handleGeneratorEntryCode(api, entrypoints, {
|
|
137
|
-
entrypointsKey: ENTRYPOINTS_KEY
|
|
139
|
+
entrypointsKey: ENTRYPOINTS_KEY,
|
|
140
|
+
hydrateRscClientRoutes: true,
|
|
141
|
+
serverRoutesFileName: 'tanstack-routes.server.js'
|
|
138
142
|
});
|
|
139
143
|
await writeTanstackRouterTypesForEntries({
|
|
140
144
|
appContext: api.getAppContext(),
|
|
@@ -173,8 +173,7 @@ import {
|
|
|
173
173
|
createRouter,
|
|
174
174
|
createRouteStaticData,
|
|
175
175
|
type ModernRouterContext,
|
|
176
|
-
modernLoaderToTanstack,
|
|
177
|
-
modernTanstackRouterFastDefaults,
|
|
176
|
+
${loaderImportMap.size > 0 ? ' modernLoaderToTanstack,\n' : ''} modernTanstackRouterFastDefaults,
|
|
178
177
|
} from '@modern-js/plugin-tanstack/runtime';
|
|
179
178
|
|
|
180
179
|
${imports.join('\n')}
|
|
@@ -198,7 +197,7 @@ export const router = createRouter({
|
|
|
198
197
|
history: createMemoryHistory({
|
|
199
198
|
initialEntries: ['/'],
|
|
200
199
|
}),
|
|
201
|
-
context: {}
|
|
200
|
+
context: {},
|
|
202
201
|
});
|
|
203
202
|
`;
|
|
204
203
|
return {
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"modern.js",
|
|
19
19
|
"tanstack-router"
|
|
20
20
|
],
|
|
21
|
-
"version": "3.5.0-ultramodern.
|
|
21
|
+
"version": "3.5.0-ultramodern.102",
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=20"
|
|
24
24
|
},
|
|
@@ -94,28 +94,29 @@
|
|
|
94
94
|
}
|
|
95
95
|
},
|
|
96
96
|
"dependencies": {
|
|
97
|
-
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.
|
|
98
|
-
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.5.0-ultramodern.
|
|
99
|
-
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.
|
|
100
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.
|
|
97
|
+
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.102",
|
|
98
|
+
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.5.0-ultramodern.102",
|
|
99
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.102",
|
|
100
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.102",
|
|
101
101
|
"@swc/helpers": "^0.5.23",
|
|
102
102
|
"@tanstack/react-router": "1.170.17",
|
|
103
103
|
"@tanstack/router-core": "1.171.14",
|
|
104
104
|
"react-server-dom-rspack": "0.0.2"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
|
-
"@modern-js/app-tools": "3.5.0-ultramodern.
|
|
108
|
-
"@modern-js/runtime": "3.5.0-ultramodern.
|
|
107
|
+
"@modern-js/app-tools": "3.5.0-ultramodern.102",
|
|
108
|
+
"@modern-js/runtime": "3.5.0-ultramodern.102",
|
|
109
109
|
"react": "^19.2.7",
|
|
110
110
|
"react-dom": "^19.2.7"
|
|
111
111
|
},
|
|
112
112
|
"devDependencies": {
|
|
113
|
-
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.
|
|
114
|
-
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.
|
|
113
|
+
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.102",
|
|
114
|
+
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.102",
|
|
115
115
|
"@rslib/core": "0.23.2",
|
|
116
116
|
"@scripts/rstest-config": "2.66.0",
|
|
117
117
|
"@tanstack/history": "1.162.0",
|
|
118
118
|
"@testing-library/react": "^16.3.2",
|
|
119
|
+
"@tsconfig/strictest": "2.0.8",
|
|
119
120
|
"@types/node": "^26.1.1",
|
|
120
121
|
"@types/react": "^19.2.17",
|
|
121
122
|
"@types/react-dom": "^19.2.3",
|
package/src/cli/index.ts
CHANGED
|
@@ -75,6 +75,8 @@ type RuntimeRouterCliHelpers = {
|
|
|
75
75
|
entrypoints: Entrypoint[],
|
|
76
76
|
options?: {
|
|
77
77
|
entrypointsKey?: string;
|
|
78
|
+
hydrateRscClientRoutes?: boolean;
|
|
79
|
+
serverRoutesFileName?: string;
|
|
78
80
|
},
|
|
79
81
|
) => Promise<Record<string, (NestedRouteForCli | PageRoute)[]>>;
|
|
80
82
|
handleModifyEntrypoints: (
|
|
@@ -265,6 +267,8 @@ export function tanstackRouterPlugin(
|
|
|
265
267
|
tanstackEntrypoints,
|
|
266
268
|
{
|
|
267
269
|
entrypointsKey: ENTRYPOINTS_KEY,
|
|
270
|
+
hydrateRscClientRoutes: true,
|
|
271
|
+
serverRoutesFileName: 'tanstack-routes.server.js',
|
|
268
272
|
},
|
|
269
273
|
);
|
|
270
274
|
|
|
@@ -291,6 +295,8 @@ export function tanstackRouterPlugin(
|
|
|
291
295
|
entrypoints,
|
|
292
296
|
{
|
|
293
297
|
entrypointsKey: ENTRYPOINTS_KEY,
|
|
298
|
+
hydrateRscClientRoutes: true,
|
|
299
|
+
serverRoutesFileName: 'tanstack-routes.server.js',
|
|
294
300
|
},
|
|
295
301
|
);
|
|
296
302
|
|
|
@@ -379,8 +379,7 @@ import {
|
|
|
379
379
|
createRouter,
|
|
380
380
|
createRouteStaticData,
|
|
381
381
|
type ModernRouterContext,
|
|
382
|
-
modernLoaderToTanstack,
|
|
383
|
-
modernTanstackRouterFastDefaults,
|
|
382
|
+
${loaderImportMap.size > 0 ? ' modernLoaderToTanstack,\n' : ''} modernTanstackRouterFastDefaults,
|
|
384
383
|
} from '@modern-js/plugin-tanstack/runtime';
|
|
385
384
|
|
|
386
385
|
${imports.join('\n')}
|
|
@@ -406,7 +405,7 @@ export const router = createRouter({
|
|
|
406
405
|
history: createMemoryHistory({
|
|
407
406
|
initialEntries: ['/'],
|
|
408
407
|
}),
|
|
409
|
-
context: {}
|
|
408
|
+
context: {},
|
|
410
409
|
});
|
|
411
410
|
`;
|
|
412
411
|
|
package/tests/router/cli.test.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { mkdir, mkdtemp, rm } from 'node:fs/promises';
|
|
2
3
|
import { tmpdir } from 'node:os';
|
|
3
4
|
import path from 'node:path';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
4
6
|
import { mergeConfig } from '@modern-js/plugin/cli';
|
|
5
7
|
import type { Entrypoint } from '@modern-js/types';
|
|
6
8
|
import { fs, NESTED_ROUTE_SPEC_FILE } from '@modern-js/utils';
|
|
@@ -12,6 +14,119 @@ import {
|
|
|
12
14
|
writeTanstackRouterTypesForEntries,
|
|
13
15
|
} from '../../src/cli';
|
|
14
16
|
|
|
17
|
+
const execFileAsync = promisify(execFile);
|
|
18
|
+
const strictestTsconfigPath = path.resolve(
|
|
19
|
+
__dirname,
|
|
20
|
+
'../../node_modules/@tsconfig/strictest/tsconfig.json',
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
async function typecheckGeneratedRegistration(options: {
|
|
24
|
+
entries: string[];
|
|
25
|
+
generatedDirName: string;
|
|
26
|
+
srcDirectory: string;
|
|
27
|
+
runtimeModule?: string;
|
|
28
|
+
i18nRuntimeModule?: string;
|
|
29
|
+
canonicalTypeChecks?: string[];
|
|
30
|
+
}) {
|
|
31
|
+
const {
|
|
32
|
+
entries,
|
|
33
|
+
generatedDirName,
|
|
34
|
+
srcDirectory,
|
|
35
|
+
runtimeModule = '@modern-js/plugin-tanstack/runtime',
|
|
36
|
+
i18nRuntimeModule,
|
|
37
|
+
canonicalTypeChecks = [],
|
|
38
|
+
} = options;
|
|
39
|
+
const projectDirectory = path.dirname(srcDirectory);
|
|
40
|
+
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
const routerPath = path.join(
|
|
43
|
+
srcDirectory,
|
|
44
|
+
generatedDirName,
|
|
45
|
+
entry,
|
|
46
|
+
'router.gen.ts',
|
|
47
|
+
);
|
|
48
|
+
if (!(await fs.pathExists(routerPath))) {
|
|
49
|
+
await fs.outputFile(routerPath, 'export const router = { context: {} };');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const runtimeDeclaration = [
|
|
54
|
+
`declare module '${runtimeModule}' {`,
|
|
55
|
+
' export interface Register {}',
|
|
56
|
+
' export type ModernRouterContext = { request?: Request; requestContext?: unknown };',
|
|
57
|
+
' type RouteOptions = { getParentRoute?: (...args: never[]) => unknown; id?: string; loader?: (...args: never[]) => unknown; path?: string; staticData?: unknown };',
|
|
58
|
+
' type Route<TOptions extends RouteOptions = RouteOptions> = { options: TOptions; addChildren<const TChildren extends readonly unknown[]>(children: TChildren): Route<TOptions> & { children: TChildren } };',
|
|
59
|
+
' export function createMemoryHistory<TOptions>(options: TOptions): TOptions;',
|
|
60
|
+
' export function createRootRouteWithContext<TContext extends ModernRouterContext>(): <const TOptions extends RouteOptions>(options: TOptions) => Route<TOptions>;',
|
|
61
|
+
' export function createRoute<const TOptions extends RouteOptions>(options: TOptions): Route<TOptions>;',
|
|
62
|
+
' export function createRouter<const TOptions extends { context: ModernRouterContext; routeTree: unknown }>(options: TOptions): TOptions;',
|
|
63
|
+
' export function createRouteStaticData<const TData extends Record<string, unknown>>(data: TData): TData;',
|
|
64
|
+
' export function modernLoaderToTanstack<TLoader extends (...args: never[]) => unknown>(options: { hasSplat: boolean }, loader: TLoader): (context: unknown) => Promise<Awaited<ReturnType<TLoader>>>;',
|
|
65
|
+
' export const modernTanstackRouterFastDefaults: Record<string, unknown>;',
|
|
66
|
+
'}',
|
|
67
|
+
];
|
|
68
|
+
if (i18nRuntimeModule) {
|
|
69
|
+
runtimeDeclaration.push(
|
|
70
|
+
`declare module '${i18nRuntimeModule}' { export interface UltramodernCanonicalRoutes {} }`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
await fs.outputFile(
|
|
74
|
+
path.join(srcDirectory, 'generated-runtime-shim.d.ts'),
|
|
75
|
+
runtimeDeclaration.join('\n'),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const contractLines = [
|
|
79
|
+
`import type { Register } from '${runtimeModule}';`,
|
|
80
|
+
...entries.map(
|
|
81
|
+
(entry, index) =>
|
|
82
|
+
`import { router as router${index} } from './${generatedDirName}/${entry}/router.gen';`,
|
|
83
|
+
),
|
|
84
|
+
...entries.map(
|
|
85
|
+
(_, index) =>
|
|
86
|
+
`const registeredRouter${index}: Register['router'] = router${index};`,
|
|
87
|
+
),
|
|
88
|
+
...entries.map((_, index) => `void registeredRouter${index};`),
|
|
89
|
+
...canonicalTypeChecks,
|
|
90
|
+
];
|
|
91
|
+
await fs.outputFile(
|
|
92
|
+
path.join(srcDirectory, 'registration-contract.ts'),
|
|
93
|
+
contractLines.join('\n'),
|
|
94
|
+
);
|
|
95
|
+
await fs.outputJSON(path.join(projectDirectory, 'tsconfig.json'), {
|
|
96
|
+
extends: strictestTsconfigPath,
|
|
97
|
+
compilerOptions: {
|
|
98
|
+
lib: ['ESNext', 'DOM'],
|
|
99
|
+
module: 'Preserve',
|
|
100
|
+
moduleResolution: 'Bundler',
|
|
101
|
+
noEmit: true,
|
|
102
|
+
target: 'ESNext',
|
|
103
|
+
types: [],
|
|
104
|
+
},
|
|
105
|
+
include: ['src/**/*.ts', 'src/**/*.d.ts'],
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
await execFileAsync(
|
|
110
|
+
process.platform === 'win32' ? 'tsgo.cmd' : 'tsgo',
|
|
111
|
+
['-p', 'tsconfig.json'],
|
|
112
|
+
{
|
|
113
|
+
cwd: projectDirectory,
|
|
114
|
+
shell: process.platform === 'win32',
|
|
115
|
+
},
|
|
116
|
+
);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
if (
|
|
119
|
+
error &&
|
|
120
|
+
typeof error === 'object' &&
|
|
121
|
+
'stdout' in error &&
|
|
122
|
+
typeof error.stdout === 'string'
|
|
123
|
+
) {
|
|
124
|
+
throw new Error(error.stdout, { cause: error });
|
|
125
|
+
}
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
15
130
|
const runtimeCliMocks = {
|
|
16
131
|
handleFileChange: rstest.fn(),
|
|
17
132
|
handleGeneratorEntryCode: rstest.fn(),
|
|
@@ -86,7 +201,7 @@ describe('tanstack router cli plugin', () => {
|
|
|
86
201
|
}
|
|
87
202
|
});
|
|
88
203
|
|
|
89
|
-
test('
|
|
204
|
+
test('typechecks plugin-owned routers and register metadata under strictest', async () => {
|
|
90
205
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
|
|
91
206
|
const srcDirectory = path.join(tempDir, 'src');
|
|
92
207
|
await mkdir(srcDirectory, { recursive: true });
|
|
@@ -102,33 +217,33 @@ describe('tanstack router cli plugin', () => {
|
|
|
102
217
|
} as any,
|
|
103
218
|
generatedDirName: 'generated-router',
|
|
104
219
|
routesByEntry: {
|
|
105
|
-
dashboard: [
|
|
106
|
-
|
|
220
|
+
dashboard: [
|
|
221
|
+
{
|
|
222
|
+
type: 'nested',
|
|
223
|
+
id: 'layout',
|
|
224
|
+
isRoot: true,
|
|
225
|
+
children: [{ type: 'nested', id: 'page', index: true }],
|
|
226
|
+
},
|
|
227
|
+
],
|
|
228
|
+
main: [
|
|
229
|
+
{
|
|
230
|
+
type: 'nested',
|
|
231
|
+
id: 'layout',
|
|
232
|
+
isRoot: true,
|
|
233
|
+
children: [{ type: 'nested', id: 'page', index: true }],
|
|
234
|
+
},
|
|
235
|
+
],
|
|
107
236
|
},
|
|
108
237
|
});
|
|
109
238
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
'
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
"} from '@modern-js/plugin-tanstack/runtime';",
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
const register = await readFile(
|
|
119
|
-
path.join(srcDirectory, 'generated-router', 'register.gen.d.ts'),
|
|
120
|
-
'utf-8',
|
|
121
|
-
);
|
|
122
|
-
expect(register).toContain("from './main/router.gen'");
|
|
123
|
-
expect(register.indexOf("from './main/router.gen'")).toBeLessThan(
|
|
124
|
-
register.indexOf("from './dashboard/router.gen'"),
|
|
125
|
-
);
|
|
126
|
-
expect(register).toContain(
|
|
127
|
-
"declare module '@modern-js/plugin-tanstack/runtime'",
|
|
128
|
-
);
|
|
239
|
+
await typecheckGeneratedRegistration({
|
|
240
|
+
entries: ['main', 'dashboard'],
|
|
241
|
+
generatedDirName: 'generated-router',
|
|
242
|
+
srcDirectory,
|
|
243
|
+
});
|
|
129
244
|
});
|
|
130
245
|
|
|
131
|
-
test('
|
|
246
|
+
test('typechecks register metadata for custom entry lists without routes', async () => {
|
|
132
247
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
|
|
133
248
|
const srcDirectory = path.join(tempDir, 'src');
|
|
134
249
|
|
|
@@ -138,17 +253,14 @@ describe('tanstack router cli plugin', () => {
|
|
|
138
253
|
srcDirectory,
|
|
139
254
|
});
|
|
140
255
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
'
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
expect(register).toContain(
|
|
147
|
-
"declare module '@modern-js/plugin-tanstack/runtime'",
|
|
148
|
-
);
|
|
256
|
+
await typecheckGeneratedRegistration({
|
|
257
|
+
entries: ['main'],
|
|
258
|
+
generatedDirName: 'tanstack',
|
|
259
|
+
srcDirectory,
|
|
260
|
+
});
|
|
149
261
|
});
|
|
150
262
|
|
|
151
|
-
test('
|
|
263
|
+
test('exposes canonical route params through plugin-i18n types', async () => {
|
|
152
264
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
|
|
153
265
|
const srcDirectory = path.join(tempDir, 'src');
|
|
154
266
|
|
|
@@ -162,20 +274,22 @@ describe('tanstack router cli plugin', () => {
|
|
|
162
274
|
},
|
|
163
275
|
});
|
|
164
276
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
'
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
277
|
+
await typecheckGeneratedRegistration({
|
|
278
|
+
entries: ['main'],
|
|
279
|
+
generatedDirName: 'tanstack',
|
|
280
|
+
srcDirectory,
|
|
281
|
+
i18nRuntimeModule: '@modern-js/plugin-i18n/runtime',
|
|
282
|
+
canonicalTypeChecks: [
|
|
283
|
+
"import type { UltramodernCanonicalRoutes } from '@modern-js/plugin-i18n/runtime';",
|
|
284
|
+
"const rootParams: UltramodernCanonicalRoutes['/'] = {};",
|
|
285
|
+
"const productParams: UltramodernCanonicalRoutes['/products/$slug'] = { slug: 'tractor' };",
|
|
286
|
+
'void rootParams;',
|
|
287
|
+
'void productParams;',
|
|
288
|
+
],
|
|
289
|
+
});
|
|
176
290
|
});
|
|
177
291
|
|
|
178
|
-
test('
|
|
292
|
+
test('typechecks a plain TanStack register without plugin-i18n installed', async () => {
|
|
179
293
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
|
|
180
294
|
const srcDirectory = path.join(tempDir, 'src');
|
|
181
295
|
|
|
@@ -183,23 +297,16 @@ describe('tanstack router cli plugin', () => {
|
|
|
183
297
|
entries: ['main'],
|
|
184
298
|
generatedDirName: 'tanstack',
|
|
185
299
|
srcDirectory,
|
|
186
|
-
// No canonicalRoutes provided at all — plain TanStack app
|
|
187
300
|
});
|
|
188
301
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
'
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
expect(register).not.toContain('plugin-i18n');
|
|
195
|
-
expect(register).not.toContain('UltramodernCanonicalRoutes');
|
|
196
|
-
// But the standard TanStack runtime augmentation must still be present.
|
|
197
|
-
expect(register).toContain(
|
|
198
|
-
"declare module '@modern-js/plugin-tanstack/runtime'",
|
|
199
|
-
);
|
|
302
|
+
await typecheckGeneratedRegistration({
|
|
303
|
+
entries: ['main'],
|
|
304
|
+
generatedDirName: 'tanstack',
|
|
305
|
+
srcDirectory,
|
|
306
|
+
});
|
|
200
307
|
});
|
|
201
308
|
|
|
202
|
-
test('
|
|
309
|
+
test('exposes canonical route params through a custom i18n runtime module', async () => {
|
|
203
310
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
|
|
204
311
|
const srcDirectory = path.join(tempDir, 'src');
|
|
205
312
|
|
|
@@ -213,15 +320,17 @@ describe('tanstack router cli plugin', () => {
|
|
|
213
320
|
i18nRuntimeModule: '@my-org/i18n/runtime',
|
|
214
321
|
});
|
|
215
322
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
'
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
323
|
+
await typecheckGeneratedRegistration({
|
|
324
|
+
entries: ['main'],
|
|
325
|
+
generatedDirName: 'tanstack',
|
|
326
|
+
srcDirectory,
|
|
327
|
+
i18nRuntimeModule: '@my-org/i18n/runtime',
|
|
328
|
+
canonicalTypeChecks: [
|
|
329
|
+
"import type { UltramodernCanonicalRoutes } from '@my-org/i18n/runtime';",
|
|
330
|
+
"const talksParams: UltramodernCanonicalRoutes['/talks'] = {};",
|
|
331
|
+
'void talksParams;',
|
|
332
|
+
],
|
|
333
|
+
});
|
|
225
334
|
});
|
|
226
335
|
|
|
227
336
|
test('claims custom routes, injects runtime plugin, and merges route specs', async () => {
|
|
@@ -576,32 +685,36 @@ describe('tanstack router cli plugin', () => {
|
|
|
576
685
|
tanstackRouterPlugin().setup!(api as any);
|
|
577
686
|
await taps.generateEntryCode({ entrypoints: [entrypoint] });
|
|
578
687
|
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
'utf-8',
|
|
688
|
+
const hasI18n = registeredPlugins.some(
|
|
689
|
+
plugin => plugin.name === '@modern-js/plugin-i18n',
|
|
582
690
|
);
|
|
691
|
+
await typecheckGeneratedRegistration({
|
|
692
|
+
entries: ['main'],
|
|
693
|
+
generatedDirName: 'modern-tanstack',
|
|
694
|
+
srcDirectory,
|
|
695
|
+
...(hasI18n && {
|
|
696
|
+
i18nRuntimeModule: '@modern-js/plugin-i18n/runtime',
|
|
697
|
+
}),
|
|
698
|
+
canonicalTypeChecks: hasI18n
|
|
699
|
+
? [
|
|
700
|
+
"import type { UltramodernCanonicalRoutes } from '@modern-js/plugin-i18n/runtime';",
|
|
701
|
+
"const aboutParams: UltramodernCanonicalRoutes['/about'] = {};",
|
|
702
|
+
'void aboutParams;',
|
|
703
|
+
]
|
|
704
|
+
: [],
|
|
705
|
+
});
|
|
583
706
|
await rm(dir, { recursive: true, force: true });
|
|
584
|
-
return register;
|
|
585
707
|
};
|
|
586
708
|
|
|
587
709
|
// A hand-rolled `/:lang/` app WITHOUT plugin-i18n must not get the
|
|
588
710
|
// augmentation — it would reference an unresolvable module (TS2664).
|
|
589
|
-
|
|
590
|
-
expect(withoutI18n).not.toContain('plugin-i18n');
|
|
591
|
-
expect(withoutI18n).not.toContain('UltramodernCanonicalRoutes');
|
|
592
|
-
expect(withoutI18n).toContain(
|
|
593
|
-
"declare module '@modern-js/plugin-tanstack/runtime'",
|
|
594
|
-
);
|
|
711
|
+
await runGenerate([{ name: '@modern-js/app-tools' }]);
|
|
595
712
|
|
|
596
713
|
// With plugin-i18n registered the canonical route map is emitted.
|
|
597
|
-
|
|
714
|
+
await runGenerate([
|
|
598
715
|
{ name: '@modern-js/app-tools' },
|
|
599
716
|
{ name: '@modern-js/plugin-i18n' },
|
|
600
717
|
]);
|
|
601
|
-
expect(withI18n).toContain(
|
|
602
|
-
"declare module '@modern-js/plugin-i18n/runtime'",
|
|
603
|
-
);
|
|
604
|
-
expect(withI18n).toContain("'/about': Record<string, never>;");
|
|
605
718
|
});
|
|
606
719
|
|
|
607
720
|
test('generates plugin-owned TanStack route files through core route generation', async () => {
|
|
@@ -689,23 +802,16 @@ describe('tanstack router cli plugin', () => {
|
|
|
689
802
|
[entrypoint],
|
|
690
803
|
{
|
|
691
804
|
entrypointsKey: '@modern-js/plugin-tanstack',
|
|
805
|
+
hydrateRscClientRoutes: true,
|
|
806
|
+
serverRoutesFileName: 'tanstack-routes.server.js',
|
|
692
807
|
},
|
|
693
808
|
);
|
|
694
809
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
'
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
expect(routerGen).toContain('modernRouteAction: action_0');
|
|
701
|
-
|
|
702
|
-
const register = await readFile(
|
|
703
|
-
path.join(srcDirectory, 'tanstack-generated', 'register.gen.d.ts'),
|
|
704
|
-
'utf-8',
|
|
705
|
-
);
|
|
706
|
-
expect(register).toContain(
|
|
707
|
-
"declare module '@modern-js/plugin-tanstack/runtime'",
|
|
708
|
-
);
|
|
810
|
+
await typecheckGeneratedRegistration({
|
|
811
|
+
entries: ['main'],
|
|
812
|
+
generatedDirName: 'tanstack-generated',
|
|
813
|
+
srcDirectory,
|
|
814
|
+
});
|
|
709
815
|
});
|
|
710
816
|
|
|
711
817
|
test('regenerates plugin-owned TanStack files for scoped file changes', async () => {
|
|
@@ -199,12 +199,6 @@ describe('runtime router compatibility', () => {
|
|
|
199
199
|
runTsgo(tsgoBin, path.join(tempRoot, 'emit.json'));
|
|
200
200
|
|
|
201
201
|
const declarationPath = path.join(emittedRoot, 'router.d.ts');
|
|
202
|
-
const declaration = readFileSync(declarationPath, 'utf8');
|
|
203
|
-
expect(declaration).not.toMatch(
|
|
204
|
-
/\b(?:createRouterPlugin|RouterPluginFactory)\b/u,
|
|
205
|
-
);
|
|
206
|
-
expect(declaration).toContain("['routerPlugin']");
|
|
207
|
-
|
|
208
202
|
writeFileSync(
|
|
209
203
|
path.join(tempRoot, 'legacyRuntimeRouter.ts'),
|
|
210
204
|
readFileSync(legacyFixturePath, 'utf8'),
|