@bleedingdev/modern-js-plugin-tanstack 3.5.0-ultramodern.30 → 3.5.0-ultramodern.31
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 +6 -103
- package/dist/cjs/cli/tanstackTypes/canonicalRoutes.js +113 -0
- package/dist/cjs/cli/tanstackTypes/shared.js +130 -0
- package/dist/cjs/cli/tanstackTypes/source.js +251 -0
- package/dist/cjs/cli/tanstackTypes.js +4 -350
- package/dist/cjs/runtime/blockingSubscribe.js +64 -0
- package/dist/cjs/runtime/{pluginCore.js → clientBasepath.js} +12 -19
- package/dist/cjs/runtime/clientHydration.js +129 -0
- package/dist/cjs/runtime/dataMutation.js +11 -176
- package/dist/cjs/runtime/formData.js +116 -0
- package/dist/cjs/runtime/loaderBridge.js +4 -1
- package/dist/cjs/runtime/plugin.js +21 -125
- package/dist/cjs/runtime/plugin.node.js +38 -119
- package/dist/cjs/runtime/pluginShared.js +90 -0
- 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/rsc/CompositeComponent.js +18 -13
- 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 +117 -0
- package/dist/cjs/runtime/rsc/payloadRouter.js +21 -142
- package/dist/cjs/runtime/rsc/payloadRoutes.js +106 -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 +71 -0
- package/dist/cjs/runtime/rsc/treeGetter.js +72 -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/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 +4 -101
- package/dist/esm/cli/tanstackTypes/canonicalRoutes.mjs +75 -0
- package/dist/esm/cli/tanstackTypes/shared.mjs +68 -0
- package/dist/esm/cli/tanstackTypes/source.mjs +203 -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 +70 -0
- package/dist/esm/runtime/dataMutation.mjs +2 -167
- package/dist/esm/runtime/formData.mjs +63 -0
- package/dist/esm/runtime/loaderBridge.mjs +4 -1
- package/dist/esm/runtime/plugin.mjs +14 -118
- package/dist/esm/runtime/plugin.node.mjs +33 -114
- package/dist/esm/runtime/pluginShared.mjs +40 -0
- 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/rsc/CompositeComponent.mjs +18 -13
- 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 +61 -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/treeGetter.mjs +34 -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/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 +4 -101
- package/dist/esm-node/cli/tanstackTypes/canonicalRoutes.mjs +76 -0
- package/dist/esm-node/cli/tanstackTypes/shared.mjs +69 -0
- package/dist/esm-node/cli/tanstackTypes/source.mjs +204 -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 +71 -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 +4 -1
- package/dist/esm-node/runtime/plugin.mjs +14 -118
- package/dist/esm-node/runtime/plugin.node.mjs +33 -114
- package/dist/esm-node/runtime/pluginShared.mjs +41 -0
- 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/rsc/CompositeComponent.mjs +18 -13
- 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 +62 -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/treeGetter.mjs +35 -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/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 -33
- 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 +10 -0
- package/dist/types/cli/tanstackTypes.d.ts +3 -31
- package/dist/types/runtime/blockingSubscribe.d.ts +3 -0
- package/dist/types/runtime/clientBasepath.d.ts +1 -0
- package/dist/types/runtime/clientHydration.d.ts +19 -0
- package/dist/types/runtime/dataMutation.d.ts +3 -12
- package/dist/types/runtime/formData.d.ts +23 -0
- package/dist/types/runtime/plugin.d.ts +1 -1
- package/dist/types/runtime/plugin.node.d.ts +1 -1
- package/dist/types/runtime/{pluginCore.d.ts → pluginShared.d.ts} +14 -0
- 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 +75 -0
- package/dist/types/runtime/routeTree.d.ts +1 -9
- package/dist/types/runtime/rsc/CompositeComponent.d.ts +1 -2
- package/dist/types/runtime/rsc/RscNodeRenderer.d.ts +2 -3
- 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 +10 -0
- package/dist/types/runtime/rsc/payloadRouter.d.ts +2 -10
- package/dist/types/runtime/rsc/payloadRoutes.d.ts +43 -0
- package/dist/types/runtime/rsc/payloadStorage.d.ts +5 -0
- package/dist/types/runtime/rsc/shared.d.ts +19 -0
- package/dist/types/runtime/rsc/treeGetter.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 +43 -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 +3 -46
- package/dist/types/runtime/utils.d.ts +1 -22
- package/package.json +30 -9
- package/rstest.config.mts +1 -0
- package/src/cli/artifacts.ts +255 -0
- package/src/cli/index.ts +6 -246
- package/src/cli/tanstackTypes/canonicalRoutes.ts +157 -0
- package/src/cli/tanstackTypes/shared.ts +119 -0
- package/src/cli/tanstackTypes/source.ts +405 -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 +151 -0
- package/src/runtime/dataMutation.tsx +9 -306
- package/src/runtime/formData.ts +153 -0
- package/src/runtime/loaderBridge.ts +8 -3
- package/src/runtime/plugin.node.tsx +60 -284
- package/src/runtime/plugin.tsx +21 -257
- package/src/runtime/pluginShared.ts +112 -0
- 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/rsc/CompositeComponent.tsx +29 -20
- package/src/runtime/rsc/RscNodeRenderer.tsx +9 -27
- 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 +97 -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/treeGetter.tsx +52 -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 +4 -2
- package/src/runtime/submitAction.ts +194 -0
- package/src/runtime/types.ts +14 -51
- package/src/runtime/utils.tsx +72 -108
- package/src/types/react-server-dom-rspack.d.ts +56 -0
- package/tests/castRatchet.test.ts +85 -0
- package/tests/router/dataMutation.test.tsx +59 -0
- package/tests/router/fixtures/router-gen.golden.txt +72 -0
- package/tests/router/loaderBridge.test.ts +21 -0
- package/tests/router/routeTree.test.ts +46 -11
- package/tests/router/rsc.test.tsx +189 -0
- package/tests/router/ssrPreload.test.ts +30 -0
- package/tests/router/tanstackTypes.test.ts +254 -1
- package/dist/esm/runtime/pluginCore.mjs +0 -14
- package/dist/esm-node/runtime/pluginCore.mjs +0 -15
- package/src/runtime/pluginCore.ts +0 -56
package/src/runtime/utils.tsx
CHANGED
|
@@ -21,101 +21,91 @@ type GlobalAppProps = {
|
|
|
21
21
|
[key: string]: unknown;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
type ModernRouteObject = RouteObject & {
|
|
25
|
+
Component?: React.ComponentType | string;
|
|
26
|
+
action?: unknown;
|
|
27
|
+
clientData?: unknown;
|
|
28
|
+
config?: { handle?: Record<string, unknown> } | unknown;
|
|
29
|
+
handle?: Record<string, unknown>;
|
|
30
|
+
hasAction?: boolean;
|
|
26
31
|
hasClientLoader?: boolean;
|
|
27
32
|
hasLoader?: boolean;
|
|
28
|
-
hasAction?: boolean;
|
|
29
33
|
inValidSSRRoute?: boolean;
|
|
34
|
+
isClientComponent?: boolean;
|
|
30
35
|
lazyImport?: () => Promise<{ default: React.ComponentType }>;
|
|
31
36
|
};
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
globalApp?: React.ComponentType<GlobalAppProps>;
|
|
41
|
-
ssrMode?: SSRMode;
|
|
42
|
-
props?: Record<string, unknown>;
|
|
43
|
-
},
|
|
44
|
-
) {
|
|
45
|
-
const createLayoutElement = (
|
|
46
|
-
Component: React.ComponentType,
|
|
47
|
-
): React.ComponentType => {
|
|
48
|
-
const GlobalLayout = globalApp;
|
|
49
|
-
if (!GlobalLayout) {
|
|
50
|
-
return Component;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const LayoutWrapper = (props: LayoutWrapperProps) => {
|
|
54
|
-
const LayoutComponent = GlobalLayout;
|
|
55
|
-
return <LayoutComponent Component={Component} {...props} />;
|
|
56
|
-
};
|
|
38
|
+
function withGlobalLayout(
|
|
39
|
+
Component: React.ComponentType,
|
|
40
|
+
globalApp?: React.ComponentType<GlobalAppProps>,
|
|
41
|
+
): React.ComponentType {
|
|
42
|
+
if (!globalApp) {
|
|
43
|
+
return Component;
|
|
44
|
+
}
|
|
57
45
|
|
|
58
|
-
|
|
46
|
+
const GlobalLayout = globalApp;
|
|
47
|
+
return function LayoutWrapper(props: LayoutWrapperProps) {
|
|
48
|
+
return <GlobalLayout Component={Component} {...props} />;
|
|
59
49
|
};
|
|
50
|
+
}
|
|
60
51
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
id: route.id,
|
|
68
|
-
loader: route.loader,
|
|
69
|
-
action: route.action,
|
|
70
|
-
shouldRevalidate: route.shouldRevalidate,
|
|
71
|
-
handle: {
|
|
72
|
-
...route.handle,
|
|
73
|
-
...(typeof route.config === 'object' ? route.config?.handle : {}),
|
|
74
|
-
},
|
|
75
|
-
index: route.index,
|
|
76
|
-
hasLoader: Boolean(route.loader),
|
|
77
|
-
hasClientLoader: Boolean(route.clientData),
|
|
78
|
-
hasAction: Boolean(route.action),
|
|
79
|
-
...(route.isClientComponent ? { isClientComponent: true } : {}),
|
|
80
|
-
...(route.inValidSSRRoute ? { inValidSSRRoute: true } : {}),
|
|
81
|
-
lazyImport: route.lazyImport,
|
|
82
|
-
Component: route.component ? route.component : undefined,
|
|
83
|
-
errorElement: route.error ? <route.error /> : undefined,
|
|
84
|
-
children: route.children
|
|
85
|
-
? route.children.map(
|
|
86
|
-
child =>
|
|
87
|
-
getRouteObjects([child], { globalApp, ssrMode, props })[0],
|
|
88
|
-
)
|
|
89
|
-
: undefined,
|
|
90
|
-
} as ModernRouteObject;
|
|
52
|
+
function getRouteHandle(route: ModernRoute) {
|
|
53
|
+
return {
|
|
54
|
+
...route.handle,
|
|
55
|
+
...(typeof route.config === 'object' ? route.config?.handle : {}),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
91
58
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
59
|
+
function toTanstackRouteObject(
|
|
60
|
+
route: ModernRoute,
|
|
61
|
+
globalApp?: React.ComponentType<GlobalAppProps>,
|
|
62
|
+
): RouteObject | null {
|
|
63
|
+
if (route.type === 'nested') {
|
|
64
|
+
return {
|
|
65
|
+
path: route.path,
|
|
66
|
+
id: route.id,
|
|
67
|
+
loader: route.loader,
|
|
68
|
+
action: route.action,
|
|
69
|
+
shouldRevalidate: route.shouldRevalidate,
|
|
70
|
+
handle: getRouteHandle(route),
|
|
71
|
+
index: route.index,
|
|
72
|
+
hasLoader: Boolean(route.loader),
|
|
73
|
+
hasClientLoader: Boolean(route.clientData),
|
|
74
|
+
hasAction: Boolean(route.action),
|
|
75
|
+
...(route.isClientComponent ? { isClientComponent: true } : {}),
|
|
76
|
+
...(route.inValidSSRRoute ? { inValidSSRRoute: true } : {}),
|
|
77
|
+
lazyImport: route.lazyImport,
|
|
78
|
+
Component: route.component ? route.component : undefined,
|
|
79
|
+
errorElement: route.error
|
|
80
|
+
? React.createElement(route.error as React.ComponentType)
|
|
81
|
+
: undefined,
|
|
82
|
+
children: route.children
|
|
83
|
+
? route.children
|
|
84
|
+
.map(child => toTanstackRouteObject(child, globalApp))
|
|
85
|
+
.filter((child): child is RouteObject => child !== null)
|
|
86
|
+
: undefined,
|
|
87
|
+
} as ModernRouteObject;
|
|
88
|
+
}
|
|
104
89
|
|
|
105
|
-
|
|
106
|
-
|
|
90
|
+
if (
|
|
91
|
+
typeof route.component !== 'function' &&
|
|
92
|
+
typeof route.component !== 'object'
|
|
93
|
+
) {
|
|
94
|
+
return null;
|
|
107
95
|
}
|
|
108
96
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
97
|
+
const LayoutComponent = withGlobalLayout(
|
|
98
|
+
route.component as React.ComponentType,
|
|
99
|
+
globalApp,
|
|
100
|
+
);
|
|
101
|
+
return {
|
|
102
|
+
path: route.path,
|
|
103
|
+
element: React.createElement(LayoutComponent),
|
|
104
|
+
};
|
|
113
105
|
}
|
|
114
106
|
|
|
115
|
-
export function
|
|
107
|
+
export function createTanstackRouteObjectsFromConfig({
|
|
116
108
|
routesConfig,
|
|
117
|
-
props,
|
|
118
|
-
ssrMode,
|
|
119
109
|
}: {
|
|
120
110
|
routesConfig: RouterConfig['routesConfig'];
|
|
121
111
|
props?: Record<string, unknown>;
|
|
@@ -128,33 +118,7 @@ export function createRouteObjectsFromConfig({
|
|
|
128
118
|
if (!routes) {
|
|
129
119
|
return null;
|
|
130
120
|
}
|
|
131
|
-
return
|
|
132
|
-
globalApp
|
|
133
|
-
|
|
134
|
-
props,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export const urlJoin = (...parts: string[]) => {
|
|
139
|
-
const separator = '/';
|
|
140
|
-
const replace = new RegExp(`${separator}{1,}`, 'g');
|
|
141
|
-
return standardSlash(parts.join(separator).replace(replace, separator));
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
export function standardSlash(str: string) {
|
|
145
|
-
let addr = str;
|
|
146
|
-
if (!addr || typeof addr !== 'string') {
|
|
147
|
-
return addr;
|
|
148
|
-
}
|
|
149
|
-
if (addr.startsWith('.')) {
|
|
150
|
-
addr = addr.slice(1);
|
|
151
|
-
}
|
|
152
|
-
if (!addr.startsWith('/')) {
|
|
153
|
-
addr = `/${addr}`;
|
|
154
|
-
}
|
|
155
|
-
if (addr.endsWith('/') && addr !== '/') {
|
|
156
|
-
addr = addr.slice(0, addr.length - 1);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return addr;
|
|
121
|
+
return routes
|
|
122
|
+
.map(route => toTanstackRouteObject(route, globalApp))
|
|
123
|
+
.filter((route): route is RouteObject => route !== null);
|
|
160
124
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
declare module 'react-server-dom-rspack/client.edge' {
|
|
2
|
+
import type { TemporaryReferenceSet } from 'react-server-dom-rspack';
|
|
3
|
+
|
|
4
|
+
export type { TemporaryReferenceSet };
|
|
5
|
+
|
|
6
|
+
export const createTemporaryReferenceSet: (
|
|
7
|
+
...args: unknown[]
|
|
8
|
+
) => TemporaryReferenceSet;
|
|
9
|
+
|
|
10
|
+
export function createServerReference(
|
|
11
|
+
id: string,
|
|
12
|
+
): (...args: unknown[]) => Promise<unknown>;
|
|
13
|
+
|
|
14
|
+
export type EncodeFormActionCallback = <A>(
|
|
15
|
+
id: unknown,
|
|
16
|
+
args: Promise<A>,
|
|
17
|
+
) => ReactCustomFormAction;
|
|
18
|
+
|
|
19
|
+
export type ReactCustomFormAction = {
|
|
20
|
+
name?: string;
|
|
21
|
+
action?: string;
|
|
22
|
+
encType?: string;
|
|
23
|
+
method?: string;
|
|
24
|
+
target?: string;
|
|
25
|
+
data?: null | FormData;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export interface Options {
|
|
29
|
+
nonce?: string;
|
|
30
|
+
encodeFormAction?: EncodeFormActionCallback;
|
|
31
|
+
temporaryReferences?: TemporaryReferenceSet;
|
|
32
|
+
replayConsoleLogs?: boolean;
|
|
33
|
+
environmentName?: string;
|
|
34
|
+
debugChannel?: {
|
|
35
|
+
readable?: ReadableStream;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function createFromFetch<T>(
|
|
40
|
+
promiseForResponse: Promise<Response>,
|
|
41
|
+
options?: Options,
|
|
42
|
+
): Promise<T>;
|
|
43
|
+
|
|
44
|
+
export function createFromReadableStream<T>(
|
|
45
|
+
stream: ReadableStream,
|
|
46
|
+
options?: Options,
|
|
47
|
+
): Promise<T>;
|
|
48
|
+
|
|
49
|
+
export const encodeReply: (
|
|
50
|
+
value: unknown,
|
|
51
|
+
options?: {
|
|
52
|
+
temporaryReferences?: TemporaryReferenceSet;
|
|
53
|
+
signal?: AbortSignal;
|
|
54
|
+
},
|
|
55
|
+
) => Promise<string | FormData>;
|
|
56
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const SRC_DIR = path.join(__dirname, '../src');
|
|
5
|
+
const CAST_RATCHET_BASELINE = 40;
|
|
6
|
+
const CAST_PATTERN = /\bas\s+unknown\s+as\b|\bas\s+any\b/g;
|
|
7
|
+
const SOURCE_FILE_PATTERN = /\.(?:ts|tsx)$/u;
|
|
8
|
+
|
|
9
|
+
type CastLocation = {
|
|
10
|
+
cast: string;
|
|
11
|
+
columnNumber: number;
|
|
12
|
+
filePath: string;
|
|
13
|
+
lineNumber: number;
|
|
14
|
+
sourceLine: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const collectSourceFiles = (directory: string): string[] => {
|
|
18
|
+
const entries = readdirSync(directory, { withFileTypes: true }).sort((a, b) =>
|
|
19
|
+
a.name.localeCompare(b.name),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
return entries.flatMap(entry => {
|
|
23
|
+
const entryPath = path.join(directory, entry.name);
|
|
24
|
+
|
|
25
|
+
if (entry.isDirectory()) {
|
|
26
|
+
return collectSourceFiles(entryPath);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return SOURCE_FILE_PATTERN.test(entry.name) ? [entryPath] : [];
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const collectCastLocations = (): CastLocation[] =>
|
|
34
|
+
collectSourceFiles(SRC_DIR).flatMap(filePath => {
|
|
35
|
+
const relativeFilePath = path
|
|
36
|
+
.relative(SRC_DIR, filePath)
|
|
37
|
+
.split(path.sep)
|
|
38
|
+
.join('/');
|
|
39
|
+
const lines = readFileSync(filePath, 'utf-8').split(/\r?\n/u);
|
|
40
|
+
const locations: CastLocation[] = [];
|
|
41
|
+
|
|
42
|
+
lines.forEach((sourceLine, index) => {
|
|
43
|
+
CAST_PATTERN.lastIndex = 0;
|
|
44
|
+
|
|
45
|
+
let match: RegExpExecArray | null;
|
|
46
|
+
while ((match = CAST_PATTERN.exec(sourceLine))) {
|
|
47
|
+
locations.push({
|
|
48
|
+
cast: match[0],
|
|
49
|
+
columnNumber: match.index + 1,
|
|
50
|
+
filePath: relativeFilePath,
|
|
51
|
+
lineNumber: index + 1,
|
|
52
|
+
sourceLine: sourceLine.trim(),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return locations;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const formatCastLocations = (locations: CastLocation[]): string =>
|
|
61
|
+
locations
|
|
62
|
+
.map(
|
|
63
|
+
location =>
|
|
64
|
+
` ${location.filePath}:${location.lineNumber}:${location.columnNumber} ${location.cast} :: ${location.sourceLine}`,
|
|
65
|
+
)
|
|
66
|
+
.join('\n');
|
|
67
|
+
|
|
68
|
+
describe('tanstack unsafe cast ratchet', () => {
|
|
69
|
+
test('does not add new as-any casts in src', () => {
|
|
70
|
+
const castLocations = collectCastLocations();
|
|
71
|
+
|
|
72
|
+
if (castLocations.length > CAST_RATCHET_BASELINE) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
[
|
|
75
|
+
`Expected at most ${CAST_RATCHET_BASELINE} unsafe casts in plugin-tanstack src, found ${castLocations.length}.`,
|
|
76
|
+
'Remove the new cast or lower the ratchet baseline after deleting existing casts.',
|
|
77
|
+
'Current cast locations:',
|
|
78
|
+
formatCastLocations(castLocations),
|
|
79
|
+
].join('\n'),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
expect(castLocations.length).toBeLessThanOrEqual(CAST_RATCHET_BASELINE);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -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,72 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// This file is auto-generated by Modern.js. Do not edit manually.
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
createMemoryHistory,
|
|
6
|
+
createRootRouteWithContext,
|
|
7
|
+
createRoute,
|
|
8
|
+
createRouter,
|
|
9
|
+
createRouteStaticData,
|
|
10
|
+
type ModernRouterContext,
|
|
11
|
+
modernLoaderToTanstack,
|
|
12
|
+
modernTanstackRouterFastDefaults,
|
|
13
|
+
} from '@modern-js/plugin-tanstack/runtime';
|
|
14
|
+
|
|
15
|
+
import component_0 from "../../routes/(app)/layout";
|
|
16
|
+
import { loader as loader_0, action as action_0 } from "../../routes/(app)/users/(userId)/page.data";
|
|
17
|
+
import { validateSearch as validateSearch_0 } from "../../routes/search.contract";
|
|
18
|
+
import { loaderDeps as loaderDeps_0 } from "../../routes/search.contract";
|
|
19
|
+
import component_1 from "../../routes/(app)/users/(userId)/page";
|
|
20
|
+
import component_2 from "../../routes/(app)/docs/splat";
|
|
21
|
+
|
|
22
|
+
export const rootRoute = createRootRouteWithContext<ModernRouterContext>()({
|
|
23
|
+
|
|
24
|
+
staticData: createRouteStaticData({
|
|
25
|
+
modernRouteId: "layout",
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const route__app__layout__base = createRoute({
|
|
30
|
+
getParentRoute: () => rootRoute,
|
|
31
|
+
component: component_0,
|
|
32
|
+
id: "(app)/layout",
|
|
33
|
+
staticData: createRouteStaticData({
|
|
34
|
+
modernRouteId: "(app)/layout",
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const route__app__users__userId__page = createRoute({
|
|
39
|
+
getParentRoute: () => route__app__layout__base,
|
|
40
|
+
component: component_1,
|
|
41
|
+
path: "users/$userId",
|
|
42
|
+
loader: modernLoaderToTanstack({ hasSplat: false }, loader_0),
|
|
43
|
+
validateSearch: validateSearch_0,
|
|
44
|
+
loaderDeps: loaderDeps_0,
|
|
45
|
+
staticData: createRouteStaticData({
|
|
46
|
+
modernRouteId: "(app)/users/(userId)/page",
|
|
47
|
+
modernRouteLoader: loader_0,
|
|
48
|
+
modernRouteAction: action_0,
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const route__app__docs_splat_page = createRoute({
|
|
53
|
+
getParentRoute: () => route__app__layout__base,
|
|
54
|
+
component: component_2,
|
|
55
|
+
path: "docs/$",
|
|
56
|
+
staticData: createRouteStaticData({
|
|
57
|
+
modernRouteId: "(app)/docs/splat/page",
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const route__app__layout = route__app__layout__base.addChildren([route__app__users__userId__page, route__app__docs_splat_page]);
|
|
62
|
+
|
|
63
|
+
export const routeTree = rootRoute.addChildren([route__app__layout]);
|
|
64
|
+
|
|
65
|
+
export const router = createRouter({
|
|
66
|
+
...modernTanstackRouterFastDefaults,
|
|
67
|
+
routeTree,
|
|
68
|
+
history: createMemoryHistory({
|
|
69
|
+
initialEntries: ['/'],
|
|
70
|
+
}),
|
|
71
|
+
context: {} as ModernRouterContext,
|
|
72
|
+
});
|
|
@@ -117,6 +117,27 @@ describe('modernLoaderToTanstack', () => {
|
|
|
117
117
|
expect(seen.context).toEqual({ user: 'u1' });
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
+
test('uses current location when context carries a previous request', async () => {
|
|
121
|
+
const seen: { request?: Request } = {};
|
|
122
|
+
const loader = modernLoaderToTanstack({ hasSplat: false }, (args: any) => {
|
|
123
|
+
seen.request = args.request;
|
|
124
|
+
return { ok: true };
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
await expect(
|
|
128
|
+
loader({
|
|
129
|
+
...baseCtx,
|
|
130
|
+
location: { href: 'http://localhost/products/2?sort=price' },
|
|
131
|
+
context: {
|
|
132
|
+
request: new Request('http://localhost/products/1?sort=name'),
|
|
133
|
+
},
|
|
134
|
+
}),
|
|
135
|
+
).resolves.toEqual({ ok: true });
|
|
136
|
+
|
|
137
|
+
expect(seen.request).toBeInstanceOf(Request);
|
|
138
|
+
expect(seen.request?.url).toBe('http://localhost/products/2?sort=price');
|
|
139
|
+
});
|
|
140
|
+
|
|
120
141
|
test('translates an absolute-URL redirect Response into redirect({ href })', async () => {
|
|
121
142
|
const loader = modernLoaderToTanstack({ hasSplat: false }, () =>
|
|
122
143
|
Response.redirect('https://example.com/away', 302),
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
getModernRouteIdsFromMatches,
|
|
16
16
|
} from '../../src/runtime/routeTree';
|
|
17
17
|
import { __setTanstackRscPayloadDecoderForTests } from '../../src/runtime/rsc/payloadRouter';
|
|
18
|
-
import {
|
|
18
|
+
import { createTanstackRouteObjectsFromConfig } from '../../src/runtime/utils';
|
|
19
19
|
|
|
20
20
|
type LoaderArgs = {
|
|
21
21
|
params: Record<string, string>;
|
|
@@ -151,15 +151,15 @@ describe('tanstack runtime public exports', () => {
|
|
|
151
151
|
};
|
|
152
152
|
|
|
153
153
|
expect(packageJson.exports['./runtime/rsc']).toBeUndefined();
|
|
154
|
-
expect(packageJson.exports['./runtime/rsc/client']).
|
|
155
|
-
expect(packageJson.exports['./runtime/rsc/server']).
|
|
154
|
+
expect(packageJson.exports['./runtime/rsc/client']).toBeDefined();
|
|
155
|
+
expect(packageJson.exports['./runtime/rsc/server']).toBeDefined();
|
|
156
156
|
expect(packageJson.typesVersions?.['*']?.['runtime/rsc']).toBeUndefined();
|
|
157
|
-
expect(
|
|
158
|
-
|
|
159
|
-
)
|
|
160
|
-
expect(
|
|
161
|
-
|
|
162
|
-
)
|
|
157
|
+
expect(packageJson.typesVersions?.['*']?.['runtime/rsc/client']).toEqual([
|
|
158
|
+
'./dist/types/runtime/rsc/client.d.ts',
|
|
159
|
+
]);
|
|
160
|
+
expect(packageJson.typesVersions?.['*']?.['runtime/rsc/server']).toEqual([
|
|
161
|
+
'./dist/types/runtime/rsc/server.d.ts',
|
|
162
|
+
]);
|
|
163
163
|
});
|
|
164
164
|
});
|
|
165
165
|
|
|
@@ -201,6 +201,41 @@ describe('tanstack route tree from RouteObject[]', () => {
|
|
|
201
201
|
expect(userMatch?.loaderData).toEqual({ id: '123' });
|
|
202
202
|
});
|
|
203
203
|
|
|
204
|
+
test('keeps unnamed sibling pathless layouts distinct', async () => {
|
|
205
|
+
const routes: RouteObject[] = [
|
|
206
|
+
{
|
|
207
|
+
Component: () => null,
|
|
208
|
+
children: [
|
|
209
|
+
{
|
|
210
|
+
path: 'alpha',
|
|
211
|
+
loader: () => ({ value: 'alpha' }),
|
|
212
|
+
Component: () => null,
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
Component: () => null,
|
|
218
|
+
children: [
|
|
219
|
+
{
|
|
220
|
+
path: 'beta',
|
|
221
|
+
loader: () => ({ value: 'beta' }),
|
|
222
|
+
Component: () => null,
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
const routeTree = createRouteTreeFromRouteObjects(routes);
|
|
229
|
+
const router = await loadRouteTree(routeTree, '/beta');
|
|
230
|
+
|
|
231
|
+
const matchedLoaderData = router.state.matches
|
|
232
|
+
.map(match => match.loaderData)
|
|
233
|
+
.filter(Boolean);
|
|
234
|
+
|
|
235
|
+
expect(matchedLoaderData).toContainEqual({ value: 'beta' });
|
|
236
|
+
expect(matchedLoaderData).not.toContainEqual({ value: 'alpha' });
|
|
237
|
+
});
|
|
238
|
+
|
|
204
239
|
test('reports native TanStack unknown routes as HTTP 404', async () => {
|
|
205
240
|
const routes: RouteObject[] = [
|
|
206
241
|
{
|
|
@@ -780,7 +815,7 @@ describe('tanstack route tree from RouteObject[]', () => {
|
|
|
780
815
|
],
|
|
781
816
|
},
|
|
782
817
|
];
|
|
783
|
-
const routeObjects =
|
|
818
|
+
const routeObjects = createTanstackRouteObjectsFromConfig({
|
|
784
819
|
routesConfig: { routes: modernRoutes },
|
|
785
820
|
});
|
|
786
821
|
const routeTree = createRouteTreeFromRouteObjects(routeObjects || []);
|
|
@@ -825,7 +860,7 @@ describe('tanstack route tree from RouteObject[]', () => {
|
|
|
825
860
|
},
|
|
826
861
|
];
|
|
827
862
|
|
|
828
|
-
const routeObjects =
|
|
863
|
+
const routeObjects = createTanstackRouteObjectsFromConfig({
|
|
829
864
|
routesConfig: { routes: modernRoutes },
|
|
830
865
|
});
|
|
831
866
|
const rootRoute = routeObjects?.[0];
|