@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
package/tests/router/cli.test.ts
CHANGED
|
@@ -1,16 +1,132 @@
|
|
|
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';
|
|
7
9
|
import {
|
|
8
10
|
createTanstackRsbuildRouteSplittingProfile,
|
|
11
|
+
generateTanstackRouteArtifacts,
|
|
9
12
|
tanstackRouterPlugin,
|
|
10
13
|
writeTanstackRegisterFile,
|
|
11
14
|
writeTanstackRouterTypesForEntries,
|
|
12
15
|
} from '../../src/cli';
|
|
13
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
|
+
|
|
14
130
|
const runtimeCliMocks = {
|
|
15
131
|
handleFileChange: rstest.fn(),
|
|
16
132
|
handleGeneratorEntryCode: rstest.fn(),
|
|
@@ -85,7 +201,7 @@ describe('tanstack router cli plugin', () => {
|
|
|
85
201
|
}
|
|
86
202
|
});
|
|
87
203
|
|
|
88
|
-
test('
|
|
204
|
+
test('typechecks plugin-owned routers and register metadata under strictest', async () => {
|
|
89
205
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
|
|
90
206
|
const srcDirectory = path.join(tempDir, 'src');
|
|
91
207
|
await mkdir(srcDirectory, { recursive: true });
|
|
@@ -101,33 +217,33 @@ describe('tanstack router cli plugin', () => {
|
|
|
101
217
|
} as any,
|
|
102
218
|
generatedDirName: 'generated-router',
|
|
103
219
|
routesByEntry: {
|
|
104
|
-
dashboard: [
|
|
105
|
-
|
|
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
|
+
],
|
|
106
236
|
},
|
|
107
237
|
});
|
|
108
238
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
'
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
"} from '@modern-js/plugin-tanstack/runtime';",
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
const register = await readFile(
|
|
118
|
-
path.join(srcDirectory, 'generated-router', 'register.gen.d.ts'),
|
|
119
|
-
'utf-8',
|
|
120
|
-
);
|
|
121
|
-
expect(register).toContain("from './main/router.gen'");
|
|
122
|
-
expect(register.indexOf("from './main/router.gen'")).toBeLessThan(
|
|
123
|
-
register.indexOf("from './dashboard/router.gen'"),
|
|
124
|
-
);
|
|
125
|
-
expect(register).toContain(
|
|
126
|
-
"declare module '@modern-js/plugin-tanstack/runtime'",
|
|
127
|
-
);
|
|
239
|
+
await typecheckGeneratedRegistration({
|
|
240
|
+
entries: ['main', 'dashboard'],
|
|
241
|
+
generatedDirName: 'generated-router',
|
|
242
|
+
srcDirectory,
|
|
243
|
+
});
|
|
128
244
|
});
|
|
129
245
|
|
|
130
|
-
test('
|
|
246
|
+
test('typechecks register metadata for custom entry lists without routes', async () => {
|
|
131
247
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
|
|
132
248
|
const srcDirectory = path.join(tempDir, 'src');
|
|
133
249
|
|
|
@@ -137,17 +253,14 @@ describe('tanstack router cli plugin', () => {
|
|
|
137
253
|
srcDirectory,
|
|
138
254
|
});
|
|
139
255
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
'
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
expect(register).toContain(
|
|
146
|
-
"declare module '@modern-js/plugin-tanstack/runtime'",
|
|
147
|
-
);
|
|
256
|
+
await typecheckGeneratedRegistration({
|
|
257
|
+
entries: ['main'],
|
|
258
|
+
generatedDirName: 'tanstack',
|
|
259
|
+
srcDirectory,
|
|
260
|
+
});
|
|
148
261
|
});
|
|
149
262
|
|
|
150
|
-
test('
|
|
263
|
+
test('exposes canonical route params through plugin-i18n types', async () => {
|
|
151
264
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
|
|
152
265
|
const srcDirectory = path.join(tempDir, 'src');
|
|
153
266
|
|
|
@@ -161,20 +274,22 @@ describe('tanstack router cli plugin', () => {
|
|
|
161
274
|
},
|
|
162
275
|
});
|
|
163
276
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
'
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
+
});
|
|
175
290
|
});
|
|
176
291
|
|
|
177
|
-
test('
|
|
292
|
+
test('typechecks a plain TanStack register without plugin-i18n installed', async () => {
|
|
178
293
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
|
|
179
294
|
const srcDirectory = path.join(tempDir, 'src');
|
|
180
295
|
|
|
@@ -182,23 +297,16 @@ describe('tanstack router cli plugin', () => {
|
|
|
182
297
|
entries: ['main'],
|
|
183
298
|
generatedDirName: 'tanstack',
|
|
184
299
|
srcDirectory,
|
|
185
|
-
// No canonicalRoutes provided at all — plain TanStack app
|
|
186
300
|
});
|
|
187
301
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
'
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
expect(register).not.toContain('plugin-i18n');
|
|
194
|
-
expect(register).not.toContain('UltramodernCanonicalRoutes');
|
|
195
|
-
// But the standard TanStack runtime augmentation must still be present.
|
|
196
|
-
expect(register).toContain(
|
|
197
|
-
"declare module '@modern-js/plugin-tanstack/runtime'",
|
|
198
|
-
);
|
|
302
|
+
await typecheckGeneratedRegistration({
|
|
303
|
+
entries: ['main'],
|
|
304
|
+
generatedDirName: 'tanstack',
|
|
305
|
+
srcDirectory,
|
|
306
|
+
});
|
|
199
307
|
});
|
|
200
308
|
|
|
201
|
-
test('
|
|
309
|
+
test('exposes canonical route params through a custom i18n runtime module', async () => {
|
|
202
310
|
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
|
|
203
311
|
const srcDirectory = path.join(tempDir, 'src');
|
|
204
312
|
|
|
@@ -212,15 +320,17 @@ describe('tanstack router cli plugin', () => {
|
|
|
212
320
|
i18nRuntimeModule: '@my-org/i18n/runtime',
|
|
213
321
|
});
|
|
214
322
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
'
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
+
});
|
|
224
334
|
});
|
|
225
335
|
|
|
226
336
|
test('claims custom routes, injects runtime plugin, and merges route specs', async () => {
|
|
@@ -575,32 +685,36 @@ describe('tanstack router cli plugin', () => {
|
|
|
575
685
|
tanstackRouterPlugin().setup!(api as any);
|
|
576
686
|
await taps.generateEntryCode({ entrypoints: [entrypoint] });
|
|
577
687
|
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
'utf-8',
|
|
688
|
+
const hasI18n = registeredPlugins.some(
|
|
689
|
+
plugin => plugin.name === '@modern-js/plugin-i18n',
|
|
581
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
|
+
});
|
|
582
706
|
await rm(dir, { recursive: true, force: true });
|
|
583
|
-
return register;
|
|
584
707
|
};
|
|
585
708
|
|
|
586
709
|
// A hand-rolled `/:lang/` app WITHOUT plugin-i18n must not get the
|
|
587
710
|
// augmentation — it would reference an unresolvable module (TS2664).
|
|
588
|
-
|
|
589
|
-
expect(withoutI18n).not.toContain('plugin-i18n');
|
|
590
|
-
expect(withoutI18n).not.toContain('UltramodernCanonicalRoutes');
|
|
591
|
-
expect(withoutI18n).toContain(
|
|
592
|
-
"declare module '@modern-js/plugin-tanstack/runtime'",
|
|
593
|
-
);
|
|
711
|
+
await runGenerate([{ name: '@modern-js/app-tools' }]);
|
|
594
712
|
|
|
595
713
|
// With plugin-i18n registered the canonical route map is emitted.
|
|
596
|
-
|
|
714
|
+
await runGenerate([
|
|
597
715
|
{ name: '@modern-js/app-tools' },
|
|
598
716
|
{ name: '@modern-js/plugin-i18n' },
|
|
599
717
|
]);
|
|
600
|
-
expect(withI18n).toContain(
|
|
601
|
-
"declare module '@modern-js/plugin-i18n/runtime'",
|
|
602
|
-
);
|
|
603
|
-
expect(withI18n).toContain("'/about': Record<string, never>;");
|
|
604
718
|
});
|
|
605
719
|
|
|
606
720
|
test('generates plugin-owned TanStack route files through core route generation', async () => {
|
|
@@ -691,20 +805,11 @@ describe('tanstack router cli plugin', () => {
|
|
|
691
805
|
},
|
|
692
806
|
);
|
|
693
807
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
'
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
expect(routerGen).toContain('modernRouteAction: action_0');
|
|
700
|
-
|
|
701
|
-
const register = await readFile(
|
|
702
|
-
path.join(srcDirectory, 'tanstack-generated', 'register.gen.d.ts'),
|
|
703
|
-
'utf-8',
|
|
704
|
-
);
|
|
705
|
-
expect(register).toContain(
|
|
706
|
-
"declare module '@modern-js/plugin-tanstack/runtime'",
|
|
707
|
-
);
|
|
808
|
+
await typecheckGeneratedRegistration({
|
|
809
|
+
entries: ['main'],
|
|
810
|
+
generatedDirName: 'tanstack-generated',
|
|
811
|
+
srcDirectory,
|
|
812
|
+
});
|
|
708
813
|
});
|
|
709
814
|
|
|
710
815
|
test('regenerates plugin-owned TanStack files for scoped file changes', async () => {
|
|
@@ -977,3 +1082,9 @@ describe('tanstack router cli plugin', () => {
|
|
|
977
1082
|
});
|
|
978
1083
|
});
|
|
979
1084
|
});
|
|
1085
|
+
|
|
1086
|
+
describe('generateTanstackRouteArtifacts export', () => {
|
|
1087
|
+
test('is exported as a function', () => {
|
|
1088
|
+
expect(typeof generateTanstackRouteArtifacts).toBe('function');
|
|
1089
|
+
});
|
|
1090
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { AnyRouter } from '@tanstack/react-router';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import React, { Suspense } from 'react';
|
|
4
|
+
import { ModernRouterClient } from '../../src/runtime/clientHydration';
|
|
5
|
+
|
|
6
|
+
let hydrateImpl: () => Promise<unknown>;
|
|
7
|
+
|
|
8
|
+
rstest.mock('@tanstack/react-router', () => ({
|
|
9
|
+
RouterProvider: ({ router }: { router: { label: string } }) => (
|
|
10
|
+
<div data-testid="router-provider">{router.label}</div>
|
|
11
|
+
),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
rstest.mock('@tanstack/react-router/ssr/client', () => ({
|
|
15
|
+
hydrate: () => hydrateImpl(),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
function createDeferred<T>() {
|
|
19
|
+
let resolve!: (value: T | PromiseLike<T>) => void;
|
|
20
|
+
let reject!: (reason?: unknown) => void;
|
|
21
|
+
const promise = new Promise<T>((resolvePromise, rejectPromise) => {
|
|
22
|
+
resolve = resolvePromise;
|
|
23
|
+
reject = rejectPromise;
|
|
24
|
+
});
|
|
25
|
+
return { promise, reject, resolve };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function createRouter(label: string): AnyRouter {
|
|
29
|
+
return {
|
|
30
|
+
label,
|
|
31
|
+
routesById: {},
|
|
32
|
+
stores: {
|
|
33
|
+
matches: {
|
|
34
|
+
get: () => [],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
} as unknown as AnyRouter;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe('TanStack SSR client hydration', () => {
|
|
41
|
+
it('keeps the router behind Suspense until late SSR hydration completes', async () => {
|
|
42
|
+
const hydration = createDeferred<void>();
|
|
43
|
+
hydrateImpl = () => hydration.promise;
|
|
44
|
+
|
|
45
|
+
render(
|
|
46
|
+
<Suspense fallback={<div data-testid="hydrating">hydrating</div>}>
|
|
47
|
+
<ModernRouterClient router={createRouter('inventory')} />
|
|
48
|
+
</Suspense>,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
expect(screen.getByTestId('hydrating')).toBeTruthy();
|
|
52
|
+
expect(screen.queryByTestId('router-provider')).toBeNull();
|
|
53
|
+
|
|
54
|
+
hydration.resolve();
|
|
55
|
+
|
|
56
|
+
expect(
|
|
57
|
+
(await screen.findByTestId('router-provider')).textContent,
|
|
58
|
+
).toContain('inventory');
|
|
59
|
+
expect(screen.queryByTestId('hydrating')).toBeNull();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -2,6 +2,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
|
2
2
|
import React, { act } from 'react';
|
|
3
3
|
import type { Fetcher } from '../../src/runtime/dataMutation';
|
|
4
4
|
import { Form, useFetcher } from '../../src/runtime/dataMutation';
|
|
5
|
+
import { createFormDataFromSubmit } from '../../src/runtime/formData';
|
|
5
6
|
|
|
6
7
|
type RouteHandler = (args: {
|
|
7
8
|
request: Request;
|
|
@@ -276,6 +277,28 @@ describe('tanstack data mutation fetcher', () => {
|
|
|
276
277
|
expect(states).toEqual(['idle', 'loading', 'idle']);
|
|
277
278
|
});
|
|
278
279
|
|
|
280
|
+
test('GET Form navigation replaces action query before hash', async () => {
|
|
281
|
+
currentRouter = createRouter({});
|
|
282
|
+
|
|
283
|
+
render(
|
|
284
|
+
<Form method="get" action="/products?sort=old#results">
|
|
285
|
+
<input name="q" defaultValue="boots" />
|
|
286
|
+
<button type="submit">Search</button>
|
|
287
|
+
</Form>,
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
const form = document.querySelector('form');
|
|
291
|
+
expect(form).toBeTruthy();
|
|
292
|
+
|
|
293
|
+
await act(async () => {
|
|
294
|
+
fireEvent.submit(form!);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
expect(currentRouter.navigate).toHaveBeenCalledWith({
|
|
298
|
+
href: '/products?q=boots#results',
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
279
302
|
test('keeps non-idle state while overlapping mutation submits are still active', async () => {
|
|
280
303
|
const actionResults = [
|
|
281
304
|
createDeferred<Response>(),
|
|
@@ -361,6 +384,42 @@ describe('tanstack data mutation fetcher', () => {
|
|
|
361
384
|
expect(screen.getByTestId('data').textContent).toBe('{"count":3}');
|
|
362
385
|
});
|
|
363
386
|
|
|
387
|
+
test('preserves submitter name value when FormData submitter overload is unavailable', () => {
|
|
388
|
+
const NativeFormData = globalThis.FormData;
|
|
389
|
+
|
|
390
|
+
class SingleArgumentFormData extends NativeFormData {
|
|
391
|
+
constructor(form?: HTMLFormElement, submitter?: HTMLElement) {
|
|
392
|
+
if (submitter) {
|
|
393
|
+
throw new TypeError('FormData submitter overload unavailable');
|
|
394
|
+
}
|
|
395
|
+
super(form);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
globalThis.FormData = SingleArgumentFormData as typeof FormData;
|
|
400
|
+
|
|
401
|
+
try {
|
|
402
|
+
const form = document.createElement('form');
|
|
403
|
+
form.innerHTML = `
|
|
404
|
+
<input name="amount" value="2" />
|
|
405
|
+
<button type="submit" name="intent" value="save">Save</button>
|
|
406
|
+
`;
|
|
407
|
+
|
|
408
|
+
const submitter = form.querySelector('button');
|
|
409
|
+
expect(submitter).toBeInstanceOf(HTMLButtonElement);
|
|
410
|
+
|
|
411
|
+
const formData = createFormDataFromSubmit({
|
|
412
|
+
form,
|
|
413
|
+
submitter,
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
expect(formData.get('amount')).toBe('2');
|
|
417
|
+
expect(formData.get('intent')).toBe('save');
|
|
418
|
+
} finally {
|
|
419
|
+
globalThis.FormData = NativeFormData;
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
|
|
364
423
|
test('does not throw for Form submit with non-2xx response and still invalidates', async () => {
|
|
365
424
|
const action = rstest.fn(
|
|
366
425
|
async () =>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
let invocationCount = 0;
|
|
2
|
+
|
|
3
|
+
export const routerPlugin = (
|
|
4
|
+
_userConfig: Record<string, unknown> = {},
|
|
5
|
+
): { name?: string; setup?: (...args: unknown[]) => unknown } => {
|
|
6
|
+
invocationCount += 1;
|
|
7
|
+
throw new Error('The legacy global router wrapper must not be invoked.');
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const getLegacyRouterPluginInvocationCount = () => invocationCount;
|