@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.120 → 3.2.0-ultramodern.121
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 +47 -27
- package/dist/cjs/cli/routeSplitting.js +0 -32
- package/dist/cjs/cli/tanstackTypes.js +34 -199
- package/dist/cjs/runtime/hooks.js +11 -14
- package/dist/cjs/runtime/index.js +107 -319
- package/dist/cjs/runtime/lifecycle.js +12 -86
- package/dist/cjs/runtime/loaderBridge.js +173 -0
- package/dist/cjs/runtime/plugin.js +6 -30
- package/dist/cjs/runtime/plugin.node.js +7 -29
- package/dist/cjs/runtime/pluginCore.js +55 -0
- package/dist/cjs/runtime/register.js +56 -0
- package/dist/cjs/runtime/routeTree.js +10 -207
- package/dist/cjs/runtime/{DefaultNotFound.js → router.js} +5 -15
- package/dist/cjs/runtime/rsc/payloadRouter.js +35 -1
- package/dist/cjs/runtime/state.js +45 -0
- package/dist/cjs/runtime/utils.js +0 -5
- package/dist/esm/cli/index.mjs +52 -26
- package/dist/esm/cli/routeSplitting.mjs +1 -30
- package/dist/esm/cli/tanstackTypes.mjs +32 -194
- package/dist/esm/runtime/hooks.mjs +1 -8
- package/dist/esm/runtime/index.mjs +4 -2
- package/dist/esm/runtime/lifecycle.mjs +1 -82
- package/dist/esm/runtime/loaderBridge.mjs +114 -0
- package/dist/esm/runtime/plugin.mjs +8 -32
- package/dist/esm/runtime/plugin.node.mjs +10 -32
- package/dist/esm/runtime/pluginCore.mjs +14 -0
- package/dist/esm/runtime/register.mjs +18 -0
- package/dist/esm/runtime/routeTree.mjs +4 -198
- package/dist/esm/runtime/router.mjs +2 -0
- package/dist/esm/runtime/rsc/payloadRouter.mjs +35 -1
- package/dist/esm/runtime/state.mjs +7 -0
- package/dist/esm/runtime/utils.mjs +0 -5
- package/dist/esm-node/cli/index.mjs +52 -26
- package/dist/esm-node/cli/routeSplitting.mjs +1 -30
- package/dist/esm-node/cli/tanstackTypes.mjs +32 -194
- package/dist/esm-node/runtime/hooks.mjs +1 -8
- package/dist/esm-node/runtime/index.mjs +4 -2
- package/dist/esm-node/runtime/lifecycle.mjs +1 -82
- package/dist/esm-node/runtime/loaderBridge.mjs +115 -0
- package/dist/esm-node/runtime/plugin.mjs +8 -32
- package/dist/esm-node/runtime/plugin.node.mjs +10 -32
- package/dist/esm-node/runtime/pluginCore.mjs +15 -0
- package/dist/esm-node/runtime/register.mjs +19 -0
- package/dist/esm-node/runtime/routeTree.mjs +4 -198
- package/dist/esm-node/runtime/router.mjs +3 -0
- package/dist/esm-node/runtime/rsc/payloadRouter.mjs +35 -1
- package/dist/esm-node/runtime/state.mjs +8 -0
- package/dist/esm-node/runtime/utils.mjs +0 -5
- package/dist/types/cli/index.d.ts +9 -2
- package/dist/types/cli/routeSplitting.d.ts +6 -15
- package/dist/types/cli/tanstackTypes.d.ts +13 -2
- package/dist/types/runtime/hooks.d.ts +8 -18
- package/dist/types/runtime/index.d.ts +6 -4
- package/dist/types/runtime/lifecycle.d.ts +7 -22
- package/dist/types/runtime/loaderBridge.d.ts +48 -0
- package/dist/types/runtime/plugin.d.ts +1 -14
- package/dist/types/runtime/plugin.node.d.ts +1 -14
- package/dist/types/runtime/pluginCore.d.ts +21 -0
- package/dist/types/runtime/register.d.ts +9 -0
- package/dist/types/runtime/routeTree.d.ts +0 -2
- package/dist/types/runtime/router.d.ts +14 -0
- package/dist/types/runtime/state.d.ts +16 -0
- package/dist/types/runtime/types.d.ts +7 -53
- package/package.json +30 -28
- package/rstest.config.mts +6 -0
- package/src/cli/index.ts +111 -29
- package/src/cli/routeSplitting.ts +6 -44
- package/src/cli/tanstackTypes.ts +78 -214
- package/src/runtime/hooks.ts +10 -27
- package/src/runtime/index.tsx +12 -107
- package/src/runtime/lifecycle.ts +16 -151
- package/src/runtime/loaderBridge.ts +257 -0
- package/src/runtime/plugin.node.tsx +14 -77
- package/src/runtime/plugin.tsx +12 -72
- package/src/runtime/pluginCore.ts +48 -0
- package/src/runtime/register.ts +58 -0
- package/src/runtime/routeTree.ts +8 -370
- package/src/runtime/router.ts +15 -0
- package/src/runtime/rsc/payloadRouter.ts +45 -2
- package/src/runtime/state.ts +29 -0
- package/src/runtime/types.ts +20 -67
- package/src/runtime/utils.tsx +3 -6
- package/tests/router/cli.test.ts +297 -31
- package/tests/router/hooks.test.ts +26 -0
- package/tests/router/loaderBridge.test.ts +211 -0
- package/tests/router/packageSurface.test.ts +24 -0
- package/tests/router/register.test.ts +46 -0
- package/tests/router/routeTree.test.ts +65 -180
- package/tests/router/rsc.test.tsx +70 -0
- package/tests/router/tanstackTypes.test.ts +164 -6
- package/dist/esm/runtime/DefaultNotFound.mjs +0 -13
- package/dist/esm-node/runtime/DefaultNotFound.mjs +0 -14
- package/dist/types/runtime/DefaultNotFound.d.ts +0 -2
- package/src/runtime/DefaultNotFound.tsx +0 -15
|
@@ -62,15 +62,109 @@ describe('tanstack router type generation', () => {
|
|
|
62
62
|
);
|
|
63
63
|
expect(routerGenTs).toContain('modernRouteLoader: loader_0');
|
|
64
64
|
expect(routerGenTs).toContain('modernRouteAction: action_0');
|
|
65
|
-
expect(routerGenTs).toContain('modernRouteId?: string;');
|
|
66
|
-
expect(routerGenTs).not.toContain(
|
|
67
|
-
'return Object.keys(staticData).length > 0 ? staticData : undefined;',
|
|
68
|
-
);
|
|
69
65
|
expect(routerGenTs).toContain(
|
|
70
66
|
"} from '@modern-js/plugin-tanstack/runtime';",
|
|
71
67
|
);
|
|
72
68
|
expect(routerGenTs).toContain('modernTanstackRouterFastDefaults,');
|
|
73
69
|
expect(routerGenTs).toContain('...modernTanstackRouterFastDefaults,');
|
|
70
|
+
|
|
71
|
+
// The loader-bridge helpers are imported from the package runtime instead
|
|
72
|
+
// of being inlined into every generated file (bugfixes ship via package
|
|
73
|
+
// update, and the broken inline absolute-redirect handler is gone).
|
|
74
|
+
expect(routerGenTs).toContain('createRouteStaticData,');
|
|
75
|
+
expect(routerGenTs).toContain('modernLoaderToTanstack,');
|
|
76
|
+
expect(routerGenTs).toContain('type ModernRouterContext,');
|
|
77
|
+
expect(routerGenTs).not.toContain('function modernLoaderToTanstack');
|
|
78
|
+
expect(routerGenTs).not.toContain('function createRouteStaticData');
|
|
79
|
+
expect(routerGenTs).not.toContain('function throwTanstackRedirect');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('emits resolvable relative component imports for routes carrying _component', async () => {
|
|
83
|
+
tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-types-'));
|
|
84
|
+
const srcDirectory = path.join(tempDir, 'src');
|
|
85
|
+
for (const componentFile of [
|
|
86
|
+
'routes/layout.tsx',
|
|
87
|
+
'routes/page.tsx',
|
|
88
|
+
'routes/about/page.tsx',
|
|
89
|
+
]) {
|
|
90
|
+
const componentPath = path.join(srcDirectory, componentFile);
|
|
91
|
+
await mkdir(path.dirname(componentPath), { recursive: true });
|
|
92
|
+
await writeFile(componentPath, 'export default () => null;');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const { routerGenTs } = await generateTanstackRouterTypesSourceForEntry({
|
|
96
|
+
appContext: {
|
|
97
|
+
srcDirectory,
|
|
98
|
+
internalSrcAlias: '@/_',
|
|
99
|
+
} as any,
|
|
100
|
+
entryName: 'index',
|
|
101
|
+
routes: [
|
|
102
|
+
{
|
|
103
|
+
type: 'nested',
|
|
104
|
+
id: 'layout',
|
|
105
|
+
isRoot: true,
|
|
106
|
+
_component: '@/_/routes/layout',
|
|
107
|
+
children: [
|
|
108
|
+
{
|
|
109
|
+
type: 'nested',
|
|
110
|
+
id: 'page',
|
|
111
|
+
index: true,
|
|
112
|
+
_component: '@/_/routes/page',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
type: 'nested',
|
|
116
|
+
id: 'about/page',
|
|
117
|
+
path: 'about',
|
|
118
|
+
_component: '@/_/routes/about/page',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
// Shares the page component module: the import must be reused.
|
|
122
|
+
type: 'nested',
|
|
123
|
+
id: 'about-alias/page',
|
|
124
|
+
path: 'about-alias',
|
|
125
|
+
_component: '@/_/routes/about/page',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
// No _component: no component option may be emitted.
|
|
129
|
+
type: 'nested',
|
|
130
|
+
id: 'data-only/page',
|
|
131
|
+
path: 'data-only',
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
] as any,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Children are emitted first, the root route component import last.
|
|
139
|
+
// Imports are relative (resolved like loader modules) — the raw
|
|
140
|
+
// `@/_` internal alias is not mapped by app tsconfigs.
|
|
141
|
+
expect(routerGenTs).toContain(
|
|
142
|
+
'import component_0 from "../../routes/page";',
|
|
143
|
+
);
|
|
144
|
+
expect(routerGenTs).toContain(
|
|
145
|
+
'import component_1 from "../../routes/about/page";',
|
|
146
|
+
);
|
|
147
|
+
expect(routerGenTs).toContain(
|
|
148
|
+
'import component_2 from "../../routes/layout";',
|
|
149
|
+
);
|
|
150
|
+
expect(routerGenTs).not.toContain('@/_/routes');
|
|
151
|
+
// The shared module is imported exactly once.
|
|
152
|
+
expect(routerGenTs).not.toContain('component_3');
|
|
153
|
+
expect(
|
|
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:');
|
|
74
168
|
});
|
|
75
169
|
|
|
76
170
|
test('typechecks generated TanStack search contracts', async () => {
|
|
@@ -132,13 +226,17 @@ describe('tanstack router type generation', () => {
|
|
|
132
226
|
' options: TOptions;',
|
|
133
227
|
' addChildren<TChildren extends readonly unknown[]>(children: TChildren): Route<TOptions> & { children: TChildren };',
|
|
134
228
|
' };',
|
|
229
|
+
' export type ModernRouterContext = {',
|
|
230
|
+
' request?: Request;',
|
|
231
|
+
' requestContext?: unknown;',
|
|
232
|
+
' };',
|
|
135
233
|
' export function createMemoryHistory(options: unknown): unknown;',
|
|
136
234
|
' export const modernTanstackRouterFastDefaults: Record<string, unknown>;',
|
|
137
235
|
' export function createRootRouteWithContext<TContext>(): <TOptions extends RouteOptions>(options: TOptions) => Route<TOptions>;',
|
|
138
236
|
' export function createRoute<TOptions extends RouteOptions>(options: TOptions): Route<TOptions>;',
|
|
139
237
|
' export function createRouter<TOptions extends Record<string, unknown>>(options: TOptions): TOptions;',
|
|
140
|
-
' export function
|
|
141
|
-
' export function
|
|
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>>>;',
|
|
142
240
|
'}',
|
|
143
241
|
].join('\n'),
|
|
144
242
|
);
|
|
@@ -273,6 +371,66 @@ describe('collectCanonicalRoutesForEntry', () => {
|
|
|
273
371
|
expect(result).toBeNull();
|
|
274
372
|
});
|
|
275
373
|
|
|
374
|
+
test('ignores a leading :lang param when the locale-param heuristic is disabled (no plugin-i18n)', () => {
|
|
375
|
+
const routes = [
|
|
376
|
+
{
|
|
377
|
+
type: 'nested',
|
|
378
|
+
id: 'layout',
|
|
379
|
+
isRoot: true,
|
|
380
|
+
children: [
|
|
381
|
+
{
|
|
382
|
+
type: 'nested',
|
|
383
|
+
id: '(lang)/layout',
|
|
384
|
+
path: ':lang',
|
|
385
|
+
children: [
|
|
386
|
+
{
|
|
387
|
+
type: 'nested',
|
|
388
|
+
id: '(lang)/about/page',
|
|
389
|
+
path: 'about',
|
|
390
|
+
},
|
|
391
|
+
],
|
|
392
|
+
},
|
|
393
|
+
],
|
|
394
|
+
},
|
|
395
|
+
] as any;
|
|
396
|
+
|
|
397
|
+
// Without plugin-i18n, a hand-rolled `/:lang/` param must NOT trigger the
|
|
398
|
+
// i18n surface (the emitted module augmentation would break typechecking).
|
|
399
|
+
expect(
|
|
400
|
+
collectCanonicalRoutesForEntry(routes, { localeParamHeuristic: false }),
|
|
401
|
+
).toBeNull();
|
|
402
|
+
// With plugin-i18n installed the heuristic strips the locale prefix.
|
|
403
|
+
expect(
|
|
404
|
+
collectCanonicalRoutesForEntry(routes, { localeParamHeuristic: true }),
|
|
405
|
+
).toEqual({
|
|
406
|
+
'/about': 'Record<string, never>',
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test('still honors modernCanonicalPath metadata when the heuristic is disabled', () => {
|
|
411
|
+
const result = collectCanonicalRoutesForEntry(
|
|
412
|
+
[
|
|
413
|
+
{
|
|
414
|
+
type: 'nested',
|
|
415
|
+
id: 'layout',
|
|
416
|
+
isRoot: true,
|
|
417
|
+
children: [
|
|
418
|
+
{
|
|
419
|
+
type: 'nested',
|
|
420
|
+
id: '(lang)/products/(slug)/page',
|
|
421
|
+
path: 'products/:slug',
|
|
422
|
+
modernCanonicalPath: '/products/:slug',
|
|
423
|
+
},
|
|
424
|
+
],
|
|
425
|
+
},
|
|
426
|
+
] as any,
|
|
427
|
+
{ localeParamHeuristic: false },
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
expect(result).not.toBeNull();
|
|
431
|
+
expect(result!['/products/$slug']).toBe('{ "slug": string }');
|
|
432
|
+
});
|
|
433
|
+
|
|
276
434
|
test('strips leading :lang param and maps index under :lang to "/"', () => {
|
|
277
435
|
const result = collectCanonicalRoutesForEntry([
|
|
278
436
|
{
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import "react";
|
|
3
|
-
const DefaultNotFound = ()=>/*#__PURE__*/ jsx("div", {
|
|
4
|
-
style: {
|
|
5
|
-
margin: '150px auto',
|
|
6
|
-
textAlign: 'center',
|
|
7
|
-
display: 'flex',
|
|
8
|
-
alignItems: 'center',
|
|
9
|
-
justifyContent: 'center'
|
|
10
|
-
},
|
|
11
|
-
children: "404"
|
|
12
|
-
});
|
|
13
|
-
export { DefaultNotFound };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import "node:module";
|
|
2
|
-
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import "react";
|
|
4
|
-
const DefaultNotFound = ()=>/*#__PURE__*/ jsx("div", {
|
|
5
|
-
style: {
|
|
6
|
-
margin: '150px auto',
|
|
7
|
-
textAlign: 'center',
|
|
8
|
-
display: 'flex',
|
|
9
|
-
alignItems: 'center',
|
|
10
|
-
justifyContent: 'center'
|
|
11
|
-
},
|
|
12
|
-
children: "404"
|
|
13
|
-
});
|
|
14
|
-
export { DefaultNotFound };
|