@bleedingdev/modern-js-plugin-tanstack 3.5.0-ultramodern.10 → 3.5.0-ultramodern.101
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/artifacts.js +157 -0
- package/dist/cjs/cli/index.js +8 -79
- package/dist/cjs/cli/tanstackTypes/canonicalRoutes.js +113 -0
- package/dist/cjs/cli/tanstackTypes/shared.js +123 -0
- package/dist/cjs/cli/tanstackTypes/source.js +254 -0
- package/dist/cjs/cli/tanstackTypes.js +4 -350
- package/dist/cjs/runtime/blockingSubscribe.js +57 -0
- package/dist/cjs/runtime/{pluginCore.js → clientBasepath.js} +12 -19
- package/dist/cjs/runtime/clientHydration.js +118 -0
- package/dist/cjs/runtime/dataMutation.js +11 -176
- package/dist/cjs/runtime/formData.js +116 -0
- package/dist/cjs/runtime/loaderBridge.js +7 -11
- package/dist/cjs/runtime/plugin.js +21 -125
- package/dist/cjs/runtime/plugin.node.js +45 -125
- package/dist/cjs/runtime/pluginShared.js +87 -0
- package/dist/cjs/runtime/prefetchLink.js +15 -2
- package/dist/cjs/runtime/register.js +3 -16
- package/dist/cjs/runtime/routeTree/components.js +102 -0
- package/dist/cjs/runtime/routeTree/construction.js +152 -0
- package/dist/cjs/runtime/routeTree/index.js +47 -0
- package/dist/cjs/runtime/routeTree/loaders.js +158 -0
- package/dist/cjs/runtime/routeTree/paths.js +57 -0
- package/dist/cjs/runtime/routeTree/staticData.js +63 -0
- package/dist/cjs/runtime/routeTree/tanstackRoutes.js +57 -0
- package/dist/cjs/runtime/routeTree/types.js +18 -0
- package/dist/cjs/runtime/routeTree.js +7 -320
- package/dist/cjs/runtime/router.js +15 -2
- package/dist/cjs/runtime/rsc/CompositeComponent.js +18 -13
- package/dist/cjs/runtime/rsc/ReplayableStream.js +0 -4
- package/dist/cjs/runtime/rsc/RscNodeRenderer.js +5 -16
- package/dist/cjs/runtime/rsc/client.js +8 -25
- package/dist/cjs/runtime/rsc/flightSerialization.js +132 -0
- package/dist/cjs/runtime/rsc/payloadErrors.js +99 -0
- package/dist/cjs/runtime/rsc/payloadFetch.js +105 -0
- package/dist/cjs/runtime/rsc/payloadRouter.js +21 -142
- package/dist/cjs/runtime/rsc/payloadRoutes.js +94 -0
- package/dist/cjs/runtime/rsc/payloadStorage.js +58 -0
- package/dist/cjs/runtime/rsc/server.js +14 -18
- package/dist/cjs/runtime/rsc/shared.js +68 -0
- package/dist/cjs/runtime/rsc/slotUsageSanitizer.js +1 -0
- package/dist/cjs/runtime/rsc/treeGetter.js +72 -0
- package/dist/cjs/runtime/shared/isAbsoluteUrl.js +47 -0
- package/dist/cjs/runtime/ssrManagedTags.js +103 -0
- package/dist/cjs/runtime/ssrPreload.js +89 -0
- package/dist/cjs/runtime/ssrTypes.js +18 -0
- package/dist/cjs/runtime/state.js +1 -1
- package/dist/cjs/runtime/submitAction.js +161 -0
- package/dist/cjs/runtime/utils.js +49 -86
- package/dist/esm/cli/artifacts.mjs +103 -0
- package/dist/esm/cli/index.mjs +8 -82
- package/dist/esm/cli/tanstackTypes/canonicalRoutes.mjs +75 -0
- package/dist/esm/cli/tanstackTypes/shared.mjs +61 -0
- package/dist/esm/cli/tanstackTypes/source.mjs +206 -0
- package/dist/esm/cli/tanstackTypes.mjs +2 -339
- package/dist/esm/runtime/blockingSubscribe.mjs +19 -0
- package/dist/esm/runtime/clientBasepath.mjs +10 -0
- package/dist/esm/runtime/clientHydration.mjs +71 -0
- package/dist/esm/runtime/dataMutation.mjs +2 -167
- package/dist/esm/runtime/formData.mjs +63 -0
- package/dist/esm/runtime/loaderBridge.mjs +5 -9
- package/dist/esm/runtime/plugin.mjs +14 -118
- package/dist/esm/runtime/plugin.node.mjs +41 -121
- package/dist/esm/runtime/pluginShared.mjs +40 -0
- package/dist/esm/runtime/prefetchLink.mjs +18 -5
- package/dist/esm/runtime/register.mjs +1 -14
- package/dist/esm/runtime/routeTree/components.mjs +55 -0
- package/dist/esm/runtime/routeTree/construction.mjs +111 -0
- package/dist/esm/runtime/routeTree/index.mjs +2 -0
- package/dist/esm/runtime/routeTree/loaders.mjs +117 -0
- package/dist/esm/runtime/routeTree/paths.mjs +16 -0
- package/dist/esm/runtime/routeTree/staticData.mjs +22 -0
- package/dist/esm/runtime/routeTree/tanstackRoutes.mjs +13 -0
- package/dist/esm/runtime/routeTree/types.mjs +0 -0
- package/dist/esm/runtime/routeTree.mjs +1 -318
- package/dist/esm/runtime/router.mjs +16 -2
- package/dist/esm/runtime/rsc/CompositeComponent.mjs +18 -13
- package/dist/esm/runtime/rsc/ReplayableStream.mjs +1 -1
- package/dist/esm/runtime/rsc/RscNodeRenderer.mjs +4 -15
- package/dist/esm/runtime/rsc/client.mjs +6 -26
- package/dist/esm/runtime/rsc/flightSerialization.mjs +88 -0
- package/dist/esm/runtime/rsc/payloadErrors.mjs +49 -0
- package/dist/esm/runtime/rsc/payloadFetch.mjs +55 -0
- package/dist/esm/runtime/rsc/payloadRouter.mjs +12 -133
- package/dist/esm/runtime/rsc/payloadRoutes.mjs +50 -0
- package/dist/esm/runtime/rsc/payloadStorage.mjs +14 -0
- package/dist/esm/runtime/rsc/server.mjs +17 -21
- package/dist/esm/runtime/rsc/shared.mjs +21 -0
- package/dist/esm/runtime/rsc/slotUsageSanitizer.mjs +1 -0
- package/dist/esm/runtime/rsc/treeGetter.mjs +34 -0
- package/dist/esm/runtime/shared/isAbsoluteUrl.mjs +9 -0
- package/dist/esm/runtime/ssrManagedTags.mjs +53 -0
- package/dist/esm/runtime/ssrPreload.mjs +51 -0
- package/dist/esm/runtime/ssrTypes.mjs +0 -0
- package/dist/esm/runtime/state.mjs +1 -1
- package/dist/esm/runtime/submitAction.mjs +120 -0
- package/dist/esm/runtime/utils.mjs +47 -75
- package/dist/esm-node/cli/artifacts.mjs +104 -0
- package/dist/esm-node/cli/index.mjs +8 -82
- package/dist/esm-node/cli/tanstackTypes/canonicalRoutes.mjs +76 -0
- package/dist/esm-node/cli/tanstackTypes/shared.mjs +62 -0
- package/dist/esm-node/cli/tanstackTypes/source.mjs +207 -0
- package/dist/esm-node/cli/tanstackTypes.mjs +2 -339
- package/dist/esm-node/runtime/blockingSubscribe.mjs +20 -0
- package/dist/esm-node/runtime/clientBasepath.mjs +11 -0
- package/dist/esm-node/runtime/clientHydration.mjs +72 -0
- package/dist/esm-node/runtime/dataMutation.mjs +2 -167
- package/dist/esm-node/runtime/formData.mjs +64 -0
- package/dist/esm-node/runtime/loaderBridge.mjs +5 -9
- package/dist/esm-node/runtime/plugin.mjs +14 -118
- package/dist/esm-node/runtime/plugin.node.mjs +41 -121
- package/dist/esm-node/runtime/pluginShared.mjs +41 -0
- package/dist/esm-node/runtime/prefetchLink.mjs +18 -5
- package/dist/esm-node/runtime/register.mjs +1 -14
- package/dist/esm-node/runtime/routeTree/components.mjs +56 -0
- package/dist/esm-node/runtime/routeTree/construction.mjs +112 -0
- package/dist/esm-node/runtime/routeTree/index.mjs +3 -0
- package/dist/esm-node/runtime/routeTree/loaders.mjs +118 -0
- package/dist/esm-node/runtime/routeTree/paths.mjs +17 -0
- package/dist/esm-node/runtime/routeTree/staticData.mjs +23 -0
- package/dist/esm-node/runtime/routeTree/tanstackRoutes.mjs +14 -0
- package/dist/esm-node/runtime/routeTree/types.mjs +1 -0
- package/dist/esm-node/runtime/routeTree.mjs +1 -318
- package/dist/esm-node/runtime/router.mjs +16 -2
- package/dist/esm-node/runtime/rsc/CompositeComponent.mjs +18 -13
- package/dist/esm-node/runtime/rsc/ReplayableStream.mjs +1 -1
- package/dist/esm-node/runtime/rsc/RscNodeRenderer.mjs +4 -15
- package/dist/esm-node/runtime/rsc/client.mjs +6 -26
- package/dist/esm-node/runtime/rsc/flightSerialization.mjs +89 -0
- package/dist/esm-node/runtime/rsc/payloadErrors.mjs +50 -0
- package/dist/esm-node/runtime/rsc/payloadFetch.mjs +56 -0
- package/dist/esm-node/runtime/rsc/payloadRouter.mjs +12 -133
- package/dist/esm-node/runtime/rsc/payloadRoutes.mjs +51 -0
- package/dist/esm-node/runtime/rsc/payloadStorage.mjs +15 -0
- package/dist/esm-node/runtime/rsc/server.mjs +17 -21
- package/dist/esm-node/runtime/rsc/shared.mjs +22 -0
- package/dist/esm-node/runtime/rsc/slotUsageSanitizer.mjs +1 -0
- package/dist/esm-node/runtime/rsc/treeGetter.mjs +35 -0
- package/dist/esm-node/runtime/shared/isAbsoluteUrl.mjs +10 -0
- package/dist/esm-node/runtime/ssrManagedTags.mjs +54 -0
- package/dist/esm-node/runtime/ssrPreload.mjs +52 -0
- package/dist/esm-node/runtime/ssrTypes.mjs +1 -0
- package/dist/esm-node/runtime/state.mjs +1 -1
- package/dist/esm-node/runtime/submitAction.mjs +121 -0
- package/dist/esm-node/runtime/utils.mjs +47 -75
- package/dist/types/cli/artifacts.d.ts +33 -0
- package/dist/types/cli/index.d.ts +2 -22
- package/dist/types/cli/tanstackTypes/canonicalRoutes.d.ts +22 -0
- package/dist/types/cli/tanstackTypes/shared.d.ts +20 -0
- package/dist/types/cli/tanstackTypes/source.d.ts +12 -0
- package/dist/types/cli/tanstackTypes.d.ts +3 -31
- package/dist/types/runtime/blockingSubscribe.d.ts +1 -0
- package/dist/types/runtime/clientBasepath.d.ts +1 -0
- package/dist/types/runtime/clientHydration.d.ts +10 -0
- package/dist/types/runtime/dataMutation.d.ts +3 -12
- package/dist/types/runtime/formData.d.ts +24 -0
- package/dist/types/runtime/loaderBridge.d.ts +2 -1
- package/dist/types/runtime/plugin.d.ts +1 -1
- package/dist/types/runtime/plugin.node.d.ts +1 -1
- package/dist/types/runtime/pluginShared.d.ts +38 -0
- package/dist/types/runtime/register.d.ts +10 -9
- package/dist/types/runtime/routeTree/components.d.ts +7 -0
- package/dist/types/runtime/routeTree/construction.d.ts +5 -0
- package/dist/types/runtime/routeTree/index.d.ts +2 -0
- package/dist/types/runtime/routeTree/loaders.d.ts +4 -0
- package/dist/types/runtime/routeTree/paths.d.ts +3 -0
- package/dist/types/runtime/routeTree/staticData.d.ts +19 -0
- package/dist/types/runtime/routeTree/tanstackRoutes.d.ts +4 -0
- package/dist/types/runtime/routeTree/types.d.ts +76 -0
- package/dist/types/runtime/routeTree.d.ts +1 -9
- package/dist/types/runtime/router.d.ts +6 -7
- package/dist/types/runtime/rsc/CompositeComponent.d.ts +1 -2
- package/dist/types/runtime/rsc/ReplayableStream.d.ts +3 -2
- package/dist/types/runtime/rsc/RscNodeRenderer.d.ts +2 -3
- package/dist/types/runtime/rsc/SlotContext.d.ts +2 -1
- package/dist/types/runtime/rsc/client.d.ts +2 -0
- package/dist/types/runtime/rsc/flightSerialization.d.ts +3 -0
- package/dist/types/runtime/rsc/payloadErrors.d.ts +6 -0
- package/dist/types/runtime/rsc/payloadFetch.d.ts +8 -0
- package/dist/types/runtime/rsc/payloadRouter.d.ts +2 -10
- package/dist/types/runtime/rsc/payloadRoutes.d.ts +40 -0
- package/dist/types/runtime/rsc/payloadStorage.d.ts +5 -0
- package/dist/types/runtime/rsc/shared.d.ts +18 -0
- package/dist/types/runtime/rsc/treeGetter.d.ts +1 -0
- package/dist/types/runtime/shared/isAbsoluteUrl.d.ts +1 -0
- package/dist/types/runtime/ssrManagedTags.d.ts +7 -0
- package/dist/types/runtime/ssrPreload.d.ts +2 -0
- package/dist/types/runtime/ssrTypes.d.ts +44 -0
- package/dist/types/runtime/state.d.ts +1 -1
- package/dist/types/runtime/submitAction.d.ts +14 -0
- package/dist/types/runtime/types.d.ts +4 -10
- package/dist/types/runtime/utils.d.ts +4 -24
- package/package.json +38 -17
- package/rstest.config.mts +23 -0
- package/src/cli/artifacts.ts +255 -0
- package/src/cli/index.ts +7 -185
- package/src/cli/tanstackTypes/canonicalRoutes.ts +157 -0
- package/src/cli/tanstackTypes/shared.ts +113 -0
- package/src/cli/tanstackTypes/source.ts +413 -0
- package/src/cli/tanstackTypes.ts +4 -647
- package/src/runtime/blockingSubscribe.ts +48 -0
- package/src/runtime/clientBasepath.ts +12 -0
- package/src/runtime/clientHydration.ts +149 -0
- package/src/runtime/dataMutation.tsx +9 -306
- package/src/runtime/formData.ts +153 -0
- package/src/runtime/loaderBridge.ts +11 -12
- package/src/runtime/plugin.node.tsx +76 -291
- package/src/runtime/plugin.tsx +21 -257
- package/src/runtime/pluginShared.ts +112 -0
- package/src/runtime/prefetchLink.tsx +78 -15
- package/src/runtime/register.ts +10 -42
- package/src/runtime/routeTree/components.ts +130 -0
- package/src/runtime/routeTree/construction.ts +238 -0
- package/src/runtime/routeTree/index.ts +7 -0
- package/src/runtime/routeTree/loaders.ts +232 -0
- package/src/runtime/routeTree/paths.ts +36 -0
- package/src/runtime/routeTree/staticData.ts +66 -0
- package/src/runtime/routeTree/tanstackRoutes.ts +36 -0
- package/src/runtime/routeTree/types.ts +87 -0
- package/src/runtime/routeTree.ts +5 -750
- package/src/runtime/router.ts +35 -7
- package/src/runtime/rsc/CompositeComponent.tsx +29 -20
- package/src/runtime/rsc/ReplayableStream.ts +2 -2
- package/src/runtime/rsc/RscNodeRenderer.tsx +9 -27
- package/src/runtime/rsc/SlotContext.tsx +1 -1
- package/src/runtime/rsc/client.tsx +12 -40
- package/src/runtime/rsc/flightSerialization.ts +158 -0
- package/src/runtime/rsc/payloadErrors.ts +73 -0
- package/src/runtime/rsc/payloadFetch.ts +92 -0
- package/src/runtime/rsc/payloadRouter.ts +29 -234
- package/src/runtime/rsc/payloadRoutes.ts +122 -0
- package/src/runtime/rsc/payloadStorage.ts +35 -0
- package/src/runtime/rsc/server.tsx +20 -29
- package/src/runtime/rsc/shared.ts +70 -0
- package/src/runtime/rsc/slotUsageSanitizer.ts +4 -0
- package/src/runtime/rsc/treeGetter.tsx +52 -0
- package/src/runtime/shared/isAbsoluteUrl.ts +8 -0
- package/src/runtime/ssrManagedTags.ts +107 -0
- package/src/runtime/ssrPreload.ts +125 -0
- package/src/runtime/ssrTypes.ts +51 -0
- package/src/runtime/state.ts +9 -3
- package/src/runtime/submitAction.ts +201 -0
- package/src/runtime/types.ts +4 -18
- package/src/runtime/utils.tsx +76 -110
- package/src/types/react-server-dom-rspack.d.ts +56 -0
- package/tests/realm-isolation.test.ts +114 -0
- package/tests/router/cli.test.ts +207 -96
- package/tests/router/clientHydration.test.tsx +61 -0
- package/tests/router/dataMutation.test.tsx +59 -0
- package/tests/router/fixtures/legacyRuntimeRouter.ts +10 -0
- package/tests/router/fixtures/router-gen.oxlint.json +5 -0
- package/tests/router/flightSerialization.roundtrip.test.tsx +137 -0
- package/tests/router/generateRouteArtifacts.test.ts +106 -0
- package/tests/router/hooks.test.ts +14 -0
- package/tests/router/loaderBridge.test.ts +21 -0
- package/tests/router/prefetchLink.test.tsx +106 -59
- package/tests/router/prefetchLinkPreload.test.tsx +85 -0
- package/tests/router/register.test.ts +1 -39
- package/tests/router/routeTree.test.ts +51 -11
- package/tests/router/routerCompatibility.test.ts +239 -0
- package/tests/router/rsc.test.tsx +189 -0
- package/tests/router/rscPayloadRouterMatrix.test.ts +197 -0
- package/tests/router/slotUsageSanitizer.test.ts +23 -0
- package/tests/router/ssrPreload.test.ts +30 -0
- package/tests/router/tanstackTypes.test.ts +480 -196
- package/dist/esm/runtime/pluginCore.mjs +0 -14
- package/dist/esm-node/runtime/pluginCore.mjs +0 -15
- package/dist/types/runtime/pluginCore.d.ts +0 -21
- package/src/runtime/pluginCore.ts +0 -48
|
@@ -3,24 +3,368 @@ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { promisify } from 'node:util';
|
|
6
|
+
|
|
7
|
+
const resolverDelays = new Map<string, number>();
|
|
8
|
+
|
|
9
|
+
rstest.mock('../../src/cli/tanstackTypes/shared', () => {
|
|
10
|
+
const actual = rstest.requireActual(
|
|
11
|
+
'../../src/cli/tanstackTypes/shared',
|
|
12
|
+
) as typeof import('../../src/cli/tanstackTypes/shared');
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
...actual,
|
|
16
|
+
resolveFileNoExt: async (inputNoExtPath: string) => {
|
|
17
|
+
const normalized = inputNoExtPath.replaceAll('\\', '/');
|
|
18
|
+
const delay =
|
|
19
|
+
[...resolverDelays.entries()].find(([suffix]) =>
|
|
20
|
+
normalized.endsWith(suffix),
|
|
21
|
+
)?.[1] ?? 0;
|
|
22
|
+
|
|
23
|
+
if (delay > 0) {
|
|
24
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return actual.resolveFileNoExt(inputNoExtPath);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
|
|
6
32
|
import {
|
|
7
33
|
collectCanonicalRoutesForEntry,
|
|
8
34
|
generateTanstackRouterTypesSourceForEntry,
|
|
9
35
|
} from '../../src/cli/tanstackTypes';
|
|
10
36
|
|
|
11
37
|
const execFileAsync = promisify(execFile);
|
|
38
|
+
const routerGenOxlintConfigPath = path.join(
|
|
39
|
+
__dirname,
|
|
40
|
+
'fixtures',
|
|
41
|
+
'router-gen.oxlint.json',
|
|
42
|
+
);
|
|
43
|
+
const oxlintCliPath = path.resolve(
|
|
44
|
+
__dirname,
|
|
45
|
+
'../../../../toolkit/code-tools/node_modules/oxlint/bin/oxlint',
|
|
46
|
+
);
|
|
47
|
+
const strictestTsconfigPath = path.resolve(
|
|
48
|
+
__dirname,
|
|
49
|
+
'../../node_modules/@tsconfig/strictest/tsconfig.json',
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
async function writeRuntimeTestPackage(projectDirectory: string) {
|
|
53
|
+
const runtimePackageDirectory = path.join(
|
|
54
|
+
projectDirectory,
|
|
55
|
+
'node_modules',
|
|
56
|
+
'@modern-js',
|
|
57
|
+
'plugin-tanstack',
|
|
58
|
+
);
|
|
59
|
+
await mkdir(runtimePackageDirectory, { recursive: true });
|
|
60
|
+
await writeFile(
|
|
61
|
+
path.join(runtimePackageDirectory, 'package.json'),
|
|
62
|
+
JSON.stringify({
|
|
63
|
+
name: '@modern-js/plugin-tanstack',
|
|
64
|
+
type: 'commonjs',
|
|
65
|
+
exports: {
|
|
66
|
+
'./runtime': {
|
|
67
|
+
types: './runtime.d.ts',
|
|
68
|
+
default: './runtime.js',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
);
|
|
73
|
+
await writeFile(
|
|
74
|
+
path.join(runtimePackageDirectory, 'runtime.d.ts'),
|
|
75
|
+
[
|
|
76
|
+
'export type ModernRouterContext = { request?: Request; requestContext?: unknown };',
|
|
77
|
+
'export type ModernRouteStaticData = { modernRouteId?: string; modernRouteAction?: unknown; modernRouteLoader?: unknown };',
|
|
78
|
+
'export type RouteOptions = {',
|
|
79
|
+
' component?: unknown;',
|
|
80
|
+
' getParentRoute?: (...args: never[]) => unknown;',
|
|
81
|
+
' id?: string;',
|
|
82
|
+
' loader?: (...args: never[]) => unknown;',
|
|
83
|
+
' loaderDeps?: (...args: never[]) => unknown;',
|
|
84
|
+
' path?: string;',
|
|
85
|
+
' staticData?: ModernRouteStaticData;',
|
|
86
|
+
' validateSearch?: (...args: never[]) => unknown;',
|
|
87
|
+
'};',
|
|
88
|
+
'export type Route<TOptions extends RouteOptions = RouteOptions> = {',
|
|
89
|
+
' options: TOptions;',
|
|
90
|
+
' addChildren<const TChildren extends readonly unknown[]>(children: TChildren): Route<TOptions> & { children: TChildren };',
|
|
91
|
+
'};',
|
|
92
|
+
'export const runtimeState: { adapterCalls: Array<{ hasSplat: boolean; modernLoader: unknown }> };',
|
|
93
|
+
'export function createMemoryHistory<TOptions>(options: TOptions): TOptions;',
|
|
94
|
+
'export const modernTanstackRouterFastDefaults: { defaultPreload: "intent" };',
|
|
95
|
+
'export function createRootRouteWithContext<TContext extends ModernRouterContext>(): <const TOptions extends RouteOptions>(options: TOptions) => Route<TOptions>;',
|
|
96
|
+
'export function createRoute<const TOptions extends RouteOptions>(options: TOptions): Route<TOptions>;',
|
|
97
|
+
'export function createRouter<const TOptions extends { context: ModernRouterContext; history: unknown; routeTree: unknown }>(options: TOptions): TOptions;',
|
|
98
|
+
'export function createRouteStaticData<const TData extends ModernRouteStaticData>(data: TData): TData;',
|
|
99
|
+
'export function modernLoaderToTanstack<TLoader extends (...args: never[]) => unknown>(options: { hasSplat: boolean }, modernLoader: TLoader): (context: unknown) => Promise<Awaited<ReturnType<TLoader>>>;',
|
|
100
|
+
].join('\n'),
|
|
101
|
+
);
|
|
102
|
+
await writeFile(
|
|
103
|
+
path.join(runtimePackageDirectory, 'runtime.js'),
|
|
104
|
+
[
|
|
105
|
+
'const runtimeState = { adapterCalls: [] };',
|
|
106
|
+
'const createRouteRecord = options => ({',
|
|
107
|
+
' options,',
|
|
108
|
+
' addChildren(children) {',
|
|
109
|
+
' this.children = children;',
|
|
110
|
+
' return this;',
|
|
111
|
+
' },',
|
|
112
|
+
'});',
|
|
113
|
+
'const createMemoryHistory = options => options;',
|
|
114
|
+
'const modernTanstackRouterFastDefaults = { defaultPreload: "intent" };',
|
|
115
|
+
'const createRootRouteWithContext = () => options => createRouteRecord(options);',
|
|
116
|
+
'const createRoute = options => createRouteRecord(options);',
|
|
117
|
+
'const createRouter = options => options;',
|
|
118
|
+
'const createRouteStaticData = data => data;',
|
|
119
|
+
'const modernLoaderToTanstack = (options, modernLoader) => {',
|
|
120
|
+
' runtimeState.adapterCalls.push({ ...options, modernLoader });',
|
|
121
|
+
' return async context => modernLoader(context);',
|
|
122
|
+
'};',
|
|
123
|
+
'module.exports = { createMemoryHistory, createRootRouteWithContext, createRoute, createRouter, createRouteStaticData, modernLoaderToTanstack, modernTanstackRouterFastDefaults, runtimeState };',
|
|
124
|
+
].join('\n'),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function compileAndRunGeneratedRouter(options: {
|
|
129
|
+
projectDirectory: string;
|
|
130
|
+
routerGenTs: string;
|
|
131
|
+
runtimeCheck: string;
|
|
132
|
+
}) {
|
|
133
|
+
const { projectDirectory, routerGenTs, runtimeCheck } = options;
|
|
134
|
+
const generatedDirectory = path.join(
|
|
135
|
+
projectDirectory,
|
|
136
|
+
'src',
|
|
137
|
+
'modern-tanstack',
|
|
138
|
+
'index',
|
|
139
|
+
);
|
|
140
|
+
await mkdir(generatedDirectory, { recursive: true });
|
|
141
|
+
await writeFile(path.join(generatedDirectory, 'router.gen.ts'), routerGenTs);
|
|
142
|
+
await writeFile(
|
|
143
|
+
path.join(projectDirectory, 'src', 'runtime-check.ts'),
|
|
144
|
+
runtimeCheck,
|
|
145
|
+
);
|
|
146
|
+
await writeRuntimeTestPackage(projectDirectory);
|
|
147
|
+
await writeFile(
|
|
148
|
+
path.join(projectDirectory, 'package.json'),
|
|
149
|
+
JSON.stringify({ private: true, type: 'commonjs' }),
|
|
150
|
+
);
|
|
151
|
+
await writeFile(
|
|
152
|
+
path.join(projectDirectory, 'tsconfig.json'),
|
|
153
|
+
JSON.stringify(
|
|
154
|
+
{
|
|
155
|
+
extends: strictestTsconfigPath,
|
|
156
|
+
compilerOptions: {
|
|
157
|
+
lib: ['ESNext', 'DOM'],
|
|
158
|
+
jsx: 'react-jsx',
|
|
159
|
+
module: 'Node16',
|
|
160
|
+
moduleResolution: 'Node16',
|
|
161
|
+
outDir: 'dist',
|
|
162
|
+
rootDir: 'src',
|
|
163
|
+
target: 'ES2022',
|
|
164
|
+
types: [],
|
|
165
|
+
verbatimModuleSyntax: false,
|
|
166
|
+
},
|
|
167
|
+
include: ['src/**/*.ts', 'src/**/*.tsx'],
|
|
168
|
+
},
|
|
169
|
+
null,
|
|
170
|
+
2,
|
|
171
|
+
),
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
await execFileAsync(
|
|
176
|
+
process.platform === 'win32' ? 'tsgo.cmd' : 'tsgo',
|
|
177
|
+
['-p', 'tsconfig.json'],
|
|
178
|
+
{
|
|
179
|
+
cwd: projectDirectory,
|
|
180
|
+
shell: process.platform === 'win32',
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
if (
|
|
185
|
+
error &&
|
|
186
|
+
typeof error === 'object' &&
|
|
187
|
+
'stdout' in error &&
|
|
188
|
+
typeof error.stdout === 'string'
|
|
189
|
+
) {
|
|
190
|
+
throw new Error(error.stdout, { cause: error });
|
|
191
|
+
}
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
await execFileAsync(
|
|
195
|
+
process.execPath,
|
|
196
|
+
[path.join(projectDirectory, 'dist', 'runtime-check.js')],
|
|
197
|
+
{ cwd: projectDirectory },
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function writeComprehensiveRouterFixture(srcDirectory: string) {
|
|
202
|
+
const files = new Map([
|
|
203
|
+
[
|
|
204
|
+
'routes/(app)/layout.tsx',
|
|
205
|
+
'export default function AppLayout() { return null; }',
|
|
206
|
+
],
|
|
207
|
+
[
|
|
208
|
+
'routes/(app)/users/(userId)/page.tsx',
|
|
209
|
+
'export default function UserPage() { return null; }',
|
|
210
|
+
],
|
|
211
|
+
[
|
|
212
|
+
'routes/(app)/users/(userId)/page.data.ts',
|
|
213
|
+
[
|
|
214
|
+
'export const loader = () => ({ userId: "42" });',
|
|
215
|
+
'export const action = () => Response.json({ ok: true });',
|
|
216
|
+
].join('\n'),
|
|
217
|
+
],
|
|
218
|
+
[
|
|
219
|
+
'routes/(app)/docs/splat.tsx',
|
|
220
|
+
'export default function DocsSplatPage() { return null; }',
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
'routes/search.contract.ts',
|
|
224
|
+
[
|
|
225
|
+
'export const validateSearch = (search: { tab?: string }) => ({ tab: search.tab ?? "overview" });',
|
|
226
|
+
'export const loaderDeps = ({ search }: { search: { tab: string } }) => ({ tab: search.tab });',
|
|
227
|
+
].join('\n'),
|
|
228
|
+
],
|
|
229
|
+
]);
|
|
230
|
+
|
|
231
|
+
for (const [relativePath, contents] of files) {
|
|
232
|
+
const filePath = path.join(srcDirectory, relativePath);
|
|
233
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
234
|
+
await writeFile(filePath, contents);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async function generateComprehensiveRouterGen(srcDirectory: string) {
|
|
239
|
+
await writeComprehensiveRouterFixture(srcDirectory);
|
|
240
|
+
|
|
241
|
+
const { routerGenTs } = await generateTanstackRouterTypesSourceForEntry({
|
|
242
|
+
appContext: {
|
|
243
|
+
srcDirectory,
|
|
244
|
+
internalSrcAlias: '@/_',
|
|
245
|
+
} as any,
|
|
246
|
+
entryName: 'golden',
|
|
247
|
+
routes: [
|
|
248
|
+
{
|
|
249
|
+
type: 'nested',
|
|
250
|
+
id: 'layout',
|
|
251
|
+
isRoot: true,
|
|
252
|
+
children: [
|
|
253
|
+
{
|
|
254
|
+
type: 'nested',
|
|
255
|
+
id: '(app)/layout',
|
|
256
|
+
_component: '@/_/routes/(app)/layout',
|
|
257
|
+
children: [
|
|
258
|
+
{
|
|
259
|
+
type: 'nested',
|
|
260
|
+
id: '(app)/users/(userId)/page',
|
|
261
|
+
path: 'users/:userId',
|
|
262
|
+
_component: '@/_/routes/(app)/users/(userId)/page',
|
|
263
|
+
data: '@/_/routes/(app)/users/(userId)/page.data',
|
|
264
|
+
action: '@/_/routes/(app)/users/(userId)/page.data',
|
|
265
|
+
validateSearch: '@/_/routes/search.contract',
|
|
266
|
+
loaderDeps: '@/_/routes/search.contract',
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
type: 'nested',
|
|
270
|
+
id: '(app)/docs/splat/page',
|
|
271
|
+
path: 'docs/*',
|
|
272
|
+
_component: '@/_/routes/(app)/docs/splat',
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
],
|
|
277
|
+
},
|
|
278
|
+
] as any,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
return routerGenTs;
|
|
282
|
+
}
|
|
12
283
|
|
|
13
284
|
describe('tanstack router type generation', () => {
|
|
14
285
|
let tempDir: string | undefined;
|
|
15
286
|
|
|
16
287
|
afterEach(async () => {
|
|
288
|
+
resolverDelays.clear();
|
|
17
289
|
if (tempDir) {
|
|
18
290
|
await rm(tempDir, { recursive: true, force: true });
|
|
19
291
|
tempDir = undefined;
|
|
20
292
|
}
|
|
21
293
|
});
|
|
22
294
|
|
|
23
|
-
test('
|
|
295
|
+
test('strictly compiles and executes a loader-free conventional route tree', async () => {
|
|
296
|
+
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-types-'));
|
|
297
|
+
const srcDirectory = path.join(tempDir, 'src');
|
|
298
|
+
const files = new Map([
|
|
299
|
+
[
|
|
300
|
+
'routes/layout.tsx',
|
|
301
|
+
'export default function Layout() { return null; }',
|
|
302
|
+
],
|
|
303
|
+
['routes/page.tsx', 'export default function Home() { return null; }'],
|
|
304
|
+
[
|
|
305
|
+
'routes/reviews/[scanId]/page.tsx',
|
|
306
|
+
'export default function Review() { return null; }',
|
|
307
|
+
],
|
|
308
|
+
]);
|
|
309
|
+
|
|
310
|
+
for (const [relativePath, contents] of files) {
|
|
311
|
+
const filePath = path.join(srcDirectory, relativePath);
|
|
312
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
313
|
+
await writeFile(filePath, contents);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const { routerGenTs } = await generateTanstackRouterTypesSourceForEntry({
|
|
317
|
+
appContext: {
|
|
318
|
+
srcDirectory,
|
|
319
|
+
internalSrcAlias: '@/_',
|
|
320
|
+
} as any,
|
|
321
|
+
entryName: 'index',
|
|
322
|
+
routes: [
|
|
323
|
+
{
|
|
324
|
+
type: 'nested',
|
|
325
|
+
id: 'layout',
|
|
326
|
+
isRoot: true,
|
|
327
|
+
_component: '@/_/routes/layout',
|
|
328
|
+
children: [
|
|
329
|
+
{
|
|
330
|
+
type: 'nested',
|
|
331
|
+
id: 'page',
|
|
332
|
+
index: true,
|
|
333
|
+
_component: '@/_/routes/page',
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
type: 'nested',
|
|
337
|
+
id: 'reviews/(scanId)/page',
|
|
338
|
+
path: 'reviews/:scanId',
|
|
339
|
+
_component: '@/_/routes/reviews/[scanId]/page',
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
},
|
|
343
|
+
] as any,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
await compileAndRunGeneratedRouter({
|
|
347
|
+
projectDirectory: tempDir,
|
|
348
|
+
routerGenTs,
|
|
349
|
+
runtimeCheck: [
|
|
350
|
+
"import { runtimeState } from '@modern-js/plugin-tanstack/runtime';",
|
|
351
|
+
"import Layout from './routes/layout';",
|
|
352
|
+
"import Home from './routes/page';",
|
|
353
|
+
"import Review from './routes/reviews/[scanId]/page';",
|
|
354
|
+
"import { rootRoute, routeTree, router } from './modern-tanstack/index/router.gen';",
|
|
355
|
+
'',
|
|
356
|
+
'if (runtimeState.adapterCalls.length !== 0) throw new Error("loader adapter registered without a loader");',
|
|
357
|
+
'if (Object.keys(router.context).length !== 0) throw new Error("router context is not empty");',
|
|
358
|
+
'if (rootRoute.options.component !== Layout) throw new Error("root component was not wired");',
|
|
359
|
+
'const [homeRoute, reviewRoute] = routeTree.children;',
|
|
360
|
+
'if (homeRoute.options.component !== Home) throw new Error("index component was not wired");',
|
|
361
|
+
'if (reviewRoute.options.component !== Review) throw new Error("review component was not wired");',
|
|
362
|
+
'if (reviewRoute.options.path !== "reviews/$scanId") throw new Error("route params were not translated");',
|
|
363
|
+
].join('\n'),
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
test('executes generated loader and action wiring through route static data', async () => {
|
|
24
368
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-types-'));
|
|
25
369
|
const srcDirectory = path.join(tempDir, 'src');
|
|
26
370
|
const routeDir = path.join(srcDirectory, 'routes', 'mf');
|
|
@@ -57,41 +401,46 @@ describe('tanstack router type generation', () => {
|
|
|
57
401
|
] as any,
|
|
58
402
|
});
|
|
59
403
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
404
|
+
await compileAndRunGeneratedRouter({
|
|
405
|
+
projectDirectory: tempDir,
|
|
406
|
+
routerGenTs,
|
|
407
|
+
runtimeCheck: [
|
|
408
|
+
"import { runtimeState } from '@modern-js/plugin-tanstack/runtime';",
|
|
409
|
+
"import { action, loader } from './routes/mf/page.data';",
|
|
410
|
+
"import { routeTree } from './modern-tanstack/index/router.gen';",
|
|
411
|
+
'',
|
|
412
|
+
'async function main() {',
|
|
413
|
+
'const [mfRoute] = routeTree.children;',
|
|
414
|
+
'if (runtimeState.adapterCalls.length !== 1) throw new Error("loader adapter was not registered exactly once");',
|
|
415
|
+
'if (runtimeState.adapterCalls[0]?.modernLoader !== loader) throw new Error("wrong loader was adapted");',
|
|
416
|
+
'const result = await mfRoute.options.loader({});',
|
|
417
|
+
'if (result.count !== 0) throw new Error("adapted loader returned the wrong value");',
|
|
418
|
+
'if (mfRoute.options.staticData.modernRouteLoader !== loader) throw new Error("loader static data was not wired");',
|
|
419
|
+
'if (mfRoute.options.staticData.modernRouteAction !== action) throw new Error("action static data was not wired");',
|
|
420
|
+
'}',
|
|
421
|
+
'void main();',
|
|
422
|
+
].join('\n'),
|
|
423
|
+
});
|
|
80
424
|
});
|
|
81
425
|
|
|
82
|
-
test('
|
|
426
|
+
test('executes component sharing correctly when module resolution races', async () => {
|
|
83
427
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-types-'));
|
|
84
428
|
const srcDirectory = path.join(tempDir, 'src');
|
|
429
|
+
|
|
85
430
|
for (const componentFile of [
|
|
86
|
-
'routes/
|
|
87
|
-
'routes/page.tsx',
|
|
88
|
-
'routes/
|
|
431
|
+
'routes/slow-page.tsx',
|
|
432
|
+
'routes/fast-page.tsx',
|
|
433
|
+
'routes/shared-page.tsx',
|
|
89
434
|
]) {
|
|
90
435
|
const componentPath = path.join(srcDirectory, componentFile);
|
|
91
436
|
await mkdir(path.dirname(componentPath), { recursive: true });
|
|
92
|
-
await writeFile(
|
|
437
|
+
await writeFile(
|
|
438
|
+
componentPath,
|
|
439
|
+
'export default function Page() { return null; }',
|
|
440
|
+
);
|
|
93
441
|
}
|
|
94
442
|
|
|
443
|
+
resolverDelays.set('/routes/slow-page', 25);
|
|
95
444
|
const { routerGenTs } = await generateTanstackRouterTypesSourceForEntry({
|
|
96
445
|
appContext: {
|
|
97
446
|
srcDirectory,
|
|
@@ -103,29 +452,32 @@ describe('tanstack router type generation', () => {
|
|
|
103
452
|
type: 'nested',
|
|
104
453
|
id: 'layout',
|
|
105
454
|
isRoot: true,
|
|
106
|
-
_component: '@/_/routes/layout',
|
|
107
455
|
children: [
|
|
108
456
|
{
|
|
109
457
|
type: 'nested',
|
|
110
|
-
id: 'page',
|
|
111
|
-
|
|
112
|
-
_component: '@/_/routes/page',
|
|
458
|
+
id: 'slow/page',
|
|
459
|
+
path: 'slow',
|
|
460
|
+
_component: '@/_/routes/slow-page',
|
|
113
461
|
},
|
|
114
462
|
{
|
|
115
463
|
type: 'nested',
|
|
116
|
-
id: '
|
|
117
|
-
path: '
|
|
118
|
-
_component: '@/_/routes/
|
|
464
|
+
id: 'fast/page',
|
|
465
|
+
path: 'fast',
|
|
466
|
+
_component: '@/_/routes/fast-page',
|
|
119
467
|
},
|
|
120
468
|
{
|
|
121
|
-
// Shares the page component module: the import must be reused.
|
|
122
469
|
type: 'nested',
|
|
123
|
-
id: '
|
|
124
|
-
path: '
|
|
125
|
-
_component: '@/_/routes/
|
|
470
|
+
id: 'shared-a/page',
|
|
471
|
+
path: 'shared-a',
|
|
472
|
+
_component: '@/_/routes/shared-page',
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
type: 'nested',
|
|
476
|
+
id: 'shared-b/page',
|
|
477
|
+
path: 'shared-b',
|
|
478
|
+
_component: '@/_/routes/shared-page',
|
|
126
479
|
},
|
|
127
480
|
{
|
|
128
|
-
// No _component: no component option may be emitted.
|
|
129
481
|
type: 'nested',
|
|
130
482
|
id: 'data-only/page',
|
|
131
483
|
path: 'data-only',
|
|
@@ -135,162 +487,92 @@ describe('tanstack router type generation', () => {
|
|
|
135
487
|
] as any,
|
|
136
488
|
});
|
|
137
489
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
routerGenTs.match(/from "\.\.\/\.\.\/routes\/about\/page";/g),
|
|
155
|
-
).toHaveLength(1);
|
|
156
|
-
|
|
157
|
-
expect(routerGenTs).toContain('component: component_0,');
|
|
158
|
-
// The shared component import is referenced by both aliased routes.
|
|
159
|
-
expect(routerGenTs.match(/component: component_1,/g)).toHaveLength(2);
|
|
160
|
-
// The root route gets its component option.
|
|
161
|
-
expect(routerGenTs).toContain('component: component_2,');
|
|
162
|
-
|
|
163
|
-
const dataOnlyRoute = routerGenTs
|
|
164
|
-
.split('const ')
|
|
165
|
-
.find(block => block.includes('path: "data-only",'));
|
|
166
|
-
expect(dataOnlyRoute).toBeDefined();
|
|
167
|
-
expect(dataOnlyRoute).not.toContain('component:');
|
|
490
|
+
await compileAndRunGeneratedRouter({
|
|
491
|
+
projectDirectory: tempDir,
|
|
492
|
+
routerGenTs,
|
|
493
|
+
runtimeCheck: [
|
|
494
|
+
"import SlowPage from './routes/slow-page';",
|
|
495
|
+
"import FastPage from './routes/fast-page';",
|
|
496
|
+
"import SharedPage from './routes/shared-page';",
|
|
497
|
+
"import { routeTree } from './modern-tanstack/index/router.gen';",
|
|
498
|
+
'',
|
|
499
|
+
'const [slowRoute, fastRoute, sharedA, sharedB, dataOnly] = routeTree.children;',
|
|
500
|
+
'if (slowRoute.options.component !== SlowPage) throw new Error("slow component was crossed during resolution");',
|
|
501
|
+
'if (fastRoute.options.component !== FastPage) throw new Error("fast component was crossed during resolution");',
|
|
502
|
+
'if (sharedA.options.component !== SharedPage || sharedB.options.component !== SharedPage) throw new Error("shared component identity was not preserved");',
|
|
503
|
+
'if (Reflect.has(dataOnly.options, "component")) throw new Error("data-only route gained a component");',
|
|
504
|
+
].join('\n'),
|
|
505
|
+
});
|
|
168
506
|
});
|
|
169
507
|
|
|
170
|
-
test('
|
|
508
|
+
test('strictly compiles and executes nested loader and search contracts', async () => {
|
|
171
509
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-types-'));
|
|
172
510
|
const srcDirectory = path.join(tempDir, 'src');
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
await
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
511
|
+
const routerGenTs = await generateComprehensiveRouterGen(srcDirectory);
|
|
512
|
+
|
|
513
|
+
await compileAndRunGeneratedRouter({
|
|
514
|
+
projectDirectory: tempDir,
|
|
515
|
+
routerGenTs,
|
|
516
|
+
runtimeCheck: [
|
|
517
|
+
"import { runtimeState } from '@modern-js/plugin-tanstack/runtime';",
|
|
518
|
+
"import { action, loader } from './routes/(app)/users/(userId)/page.data';",
|
|
519
|
+
"import { loaderDeps, validateSearch } from './routes/search.contract';",
|
|
520
|
+
"import { routeTree } from './modern-tanstack/index/router.gen';",
|
|
521
|
+
'',
|
|
522
|
+
'async function main() {',
|
|
523
|
+
'const [appRoute] = routeTree.children;',
|
|
524
|
+
'const [userRoute, docsRoute] = appRoute.children;',
|
|
525
|
+
'if (runtimeState.adapterCalls.length !== 1) throw new Error("nested loader was not adapted");',
|
|
526
|
+
'if (userRoute.options.validateSearch !== validateSearch) throw new Error("search validator was not wired");',
|
|
527
|
+
'if (userRoute.options.loaderDeps !== loaderDeps) throw new Error("loader dependencies were not wired");',
|
|
528
|
+
'if (userRoute.options.staticData.modernRouteLoader !== loader) throw new Error("nested static loader was not wired");',
|
|
529
|
+
'if (userRoute.options.staticData.modernRouteAction !== action) throw new Error("nested static action was not wired");',
|
|
530
|
+
'const user = await userRoute.options.loader({});',
|
|
531
|
+
'if (user.userId !== "42") throw new Error("nested loader result was lost");',
|
|
532
|
+
'if (userRoute.options.path !== "users/$userId") throw new Error("required route param was not translated");',
|
|
533
|
+
'if (docsRoute.options.path !== "docs/$") throw new Error("splat route was not translated");',
|
|
534
|
+
'const search = userRoute.options.validateSearch({});',
|
|
535
|
+
'if (search.tab !== "overview") throw new Error("search contract returned the wrong value");',
|
|
536
|
+
'}',
|
|
537
|
+
'void main();',
|
|
182
538
|
].join('\n'),
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
const { routerGenTs } = await generateTanstackRouterTypesSourceForEntry({
|
|
186
|
-
appContext: {
|
|
187
|
-
srcDirectory,
|
|
188
|
-
internalSrcAlias: '@/_',
|
|
189
|
-
} as any,
|
|
190
|
-
entryName: 'index',
|
|
191
|
-
routes: [
|
|
192
|
-
{
|
|
193
|
-
type: 'nested',
|
|
194
|
-
id: 'layout',
|
|
195
|
-
isRoot: true,
|
|
196
|
-
validateSearch: '@/_/routes/search.contract',
|
|
197
|
-
loaderDeps: '@/_/routes/search.contract',
|
|
198
|
-
children: [
|
|
199
|
-
{
|
|
200
|
-
type: 'nested',
|
|
201
|
-
id: 'search/page',
|
|
202
|
-
path: 'search',
|
|
203
|
-
validateSearch: '@/_/routes/search.contract',
|
|
204
|
-
loaderDeps: '@/_/routes/search.contract',
|
|
205
|
-
},
|
|
206
|
-
],
|
|
207
|
-
},
|
|
208
|
-
] as any,
|
|
209
539
|
});
|
|
540
|
+
});
|
|
210
541
|
|
|
211
|
-
|
|
212
|
-
await
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
' loaderDeps?: unknown;',
|
|
221
|
-
' path?: string;',
|
|
222
|
-
' staticData?: unknown;',
|
|
223
|
-
' validateSearch?: unknown;',
|
|
224
|
-
' };',
|
|
225
|
-
' type Route<TOptions extends RouteOptions> = {',
|
|
226
|
-
' options: TOptions;',
|
|
227
|
-
' addChildren<TChildren extends readonly unknown[]>(children: TChildren): Route<TOptions> & { children: TChildren };',
|
|
228
|
-
' };',
|
|
229
|
-
' export type ModernRouterContext = {',
|
|
230
|
-
' request?: Request;',
|
|
231
|
-
' requestContext?: unknown;',
|
|
232
|
-
' };',
|
|
233
|
-
' export function createMemoryHistory(options: unknown): unknown;',
|
|
234
|
-
' export const modernTanstackRouterFastDefaults: Record<string, unknown>;',
|
|
235
|
-
' export function createRootRouteWithContext<TContext>(): <TOptions extends RouteOptions>(options: TOptions) => Route<TOptions>;',
|
|
236
|
-
' export function createRoute<TOptions extends RouteOptions>(options: TOptions): Route<TOptions>;',
|
|
237
|
-
' export function createRouter<TOptions extends Record<string, unknown>>(options: TOptions): TOptions;',
|
|
238
|
-
' export function createRouteStaticData(opts: { modernRouteId?: string; modernRouteAction?: unknown; modernRouteLoader?: unknown }): Record<string, unknown>;',
|
|
239
|
-
' export function modernLoaderToTanstack<TLoader extends (args: never) => unknown>(opts: { hasSplat: boolean }, modernLoader: TLoader): (ctx: unknown) => Promise<Awaited<ReturnType<TLoader>>>;',
|
|
240
|
-
'}',
|
|
241
|
-
].join('\n'),
|
|
542
|
+
test('passes the generated-artifact lint contract', async () => {
|
|
543
|
+
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-types-'));
|
|
544
|
+
const srcDirectory = path.join(tempDir, 'src');
|
|
545
|
+
const routerGenTs = await generateComprehensiveRouterGen(srcDirectory);
|
|
546
|
+
const routerGenPath = path.join(
|
|
547
|
+
srcDirectory,
|
|
548
|
+
'modern-tanstack',
|
|
549
|
+
'golden',
|
|
550
|
+
'router.gen.ts',
|
|
242
551
|
);
|
|
243
|
-
|
|
244
|
-
|
|
552
|
+
|
|
553
|
+
await mkdir(path.dirname(routerGenPath), { recursive: true });
|
|
554
|
+
await writeFile(routerGenPath, routerGenTs);
|
|
555
|
+
|
|
556
|
+
const { stderr, stdout } = await execFileAsync(
|
|
557
|
+
process.execPath,
|
|
245
558
|
[
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
'',
|
|
249
|
-
|
|
250
|
-
'
|
|
251
|
-
'
|
|
252
|
-
'
|
|
253
|
-
'',
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
"childLoaderDeps({ search: { q: 'child' } });",
|
|
258
|
-
].join('\n'),
|
|
259
|
-
);
|
|
260
|
-
await writeFile(
|
|
261
|
-
path.join(tempDir, 'tsconfig.json'),
|
|
262
|
-
JSON.stringify(
|
|
263
|
-
{
|
|
264
|
-
compilerOptions: {
|
|
265
|
-
lib: ['ESNext', 'DOM'],
|
|
266
|
-
module: 'Preserve',
|
|
267
|
-
moduleResolution: 'Bundler',
|
|
268
|
-
noEmit: true,
|
|
269
|
-
skipLibCheck: true,
|
|
270
|
-
strict: true,
|
|
271
|
-
target: 'ESNext',
|
|
272
|
-
types: [],
|
|
273
|
-
},
|
|
274
|
-
include: ['src/**/*.ts', 'src/**/*.d.ts'],
|
|
275
|
-
},
|
|
276
|
-
null,
|
|
277
|
-
2,
|
|
278
|
-
),
|
|
559
|
+
oxlintCliPath,
|
|
560
|
+
routerGenPath,
|
|
561
|
+
'--config',
|
|
562
|
+
routerGenOxlintConfigPath,
|
|
563
|
+
'--no-ignore',
|
|
564
|
+
'--report-unused-disable-directives-severity',
|
|
565
|
+
'error',
|
|
566
|
+
'--format',
|
|
567
|
+
'unix',
|
|
568
|
+
],
|
|
569
|
+
{ cwd: tempDir },
|
|
279
570
|
);
|
|
280
571
|
|
|
281
|
-
|
|
282
|
-
execFileAsync(
|
|
283
|
-
process.platform === 'win32' ? 'tsgo.cmd' : 'tsgo',
|
|
284
|
-
['--noEmit', '-p', 'tsconfig.json'],
|
|
285
|
-
{
|
|
286
|
-
cwd: tempDir,
|
|
287
|
-
shell: process.platform === 'win32',
|
|
288
|
-
},
|
|
289
|
-
),
|
|
290
|
-
).resolves.toBeDefined();
|
|
572
|
+
expect(`${stdout}${stderr}`).toBe('');
|
|
291
573
|
});
|
|
292
574
|
|
|
293
|
-
test('
|
|
575
|
+
test('executes localized aliases with typed children and correct parents', async () => {
|
|
294
576
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-types-'));
|
|
295
577
|
const srcDirectory = path.join(tempDir, 'src');
|
|
296
578
|
|
|
@@ -333,21 +615,23 @@ describe('tanstack router type generation', () => {
|
|
|
333
615
|
] as any,
|
|
334
616
|
});
|
|
335
617
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
618
|
+
await compileAndRunGeneratedRouter({
|
|
619
|
+
projectDirectory: tempDir,
|
|
620
|
+
routerGenTs,
|
|
621
|
+
runtimeCheck: [
|
|
622
|
+
"import { routeTree } from './modern-tanstack/index/router.gen';",
|
|
623
|
+
'',
|
|
624
|
+
'const [localeRoute] = routeTree.children;',
|
|
625
|
+
'const [productRoute, localizedProductRoute, optionalRoute] = localeRoute.children;',
|
|
626
|
+
'if (localeRoute.options.path !== "$lang") throw new Error("locale param was not translated");',
|
|
627
|
+
'if (productRoute.options.path !== "products/$slug") throw new Error("product param was not translated");',
|
|
628
|
+
'if (localizedProductRoute.options.path !== "produkty/$slug") throw new Error("localized param was not translated");',
|
|
629
|
+
'if (optionalRoute.options.path !== "volitelne/{-$slug}") throw new Error("optional param was not translated");',
|
|
630
|
+
'for (const child of localeRoute.children) {',
|
|
631
|
+
' if (child.options.getParentRoute() !== localeRoute) throw new Error("localized child points at the wrong parent");',
|
|
632
|
+
'}',
|
|
633
|
+
].join('\n'),
|
|
634
|
+
});
|
|
351
635
|
});
|
|
352
636
|
});
|
|
353
637
|
|