@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
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function isPromiseLike(value) {
|
|
2
|
+
return Boolean(value && 'function' == typeof value.then);
|
|
3
|
+
}
|
|
4
|
+
function isPreloadableRouteComponent(component) {
|
|
5
|
+
if (!component || 'function' != typeof component) return false;
|
|
6
|
+
const preloadable = component;
|
|
7
|
+
return 'function' == typeof preloadable.load || 'function' == typeof preloadable.preload;
|
|
8
|
+
}
|
|
9
|
+
function isReactLazyRouteComponent(component) {
|
|
10
|
+
return null != component && 'object' == typeof component && 'function' == typeof component._init && '_payload' in component;
|
|
11
|
+
}
|
|
12
|
+
async function preloadReactLazyRouteComponent(component) {
|
|
13
|
+
try {
|
|
14
|
+
component._init?.(component._payload);
|
|
15
|
+
} catch (thrown) {
|
|
16
|
+
if (!isPromiseLike(thrown)) throw thrown;
|
|
17
|
+
await thrown;
|
|
18
|
+
component._init?.(component._payload);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function preloadRouteComponent(component, preloadedComponents) {
|
|
22
|
+
if (isReactLazyRouteComponent(component)) {
|
|
23
|
+
if (preloadedComponents.has(component)) return;
|
|
24
|
+
preloadedComponents.add(component);
|
|
25
|
+
await preloadReactLazyRouteComponent(component);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (!isPreloadableRouteComponent(component)) return;
|
|
29
|
+
if (preloadedComponents.has(component)) return;
|
|
30
|
+
preloadedComponents.add(component);
|
|
31
|
+
if ('function' == typeof component.load) return void await component.load({});
|
|
32
|
+
await component.preload?.({});
|
|
33
|
+
}
|
|
34
|
+
async function preloadMatchedRouteComponents(tanstackRouter) {
|
|
35
|
+
const matches = Array.isArray(tanstackRouter.state.matches) ? tanstackRouter.state.matches : [];
|
|
36
|
+
const routesById = tanstackRouter.routesById || {};
|
|
37
|
+
const preloadedComponents = new Set();
|
|
38
|
+
await Promise.all(matches.map(async (match)=>{
|
|
39
|
+
const routeId = 'string' == typeof match.routeId ? match.routeId : 'string' == typeof match.route?.id ? match.route.id : void 0;
|
|
40
|
+
const route = routeId ? routesById[routeId] : match.route;
|
|
41
|
+
const options = route?.options;
|
|
42
|
+
if (!options) return;
|
|
43
|
+
await Promise.all([
|
|
44
|
+
preloadRouteComponent(options.component, preloadedComponents),
|
|
45
|
+
preloadRouteComponent(options.pendingComponent, preloadedComponents),
|
|
46
|
+
preloadRouteComponent(options.errorComponent, preloadedComponents),
|
|
47
|
+
preloadRouteComponent(options.notFoundComponent, preloadedComponents)
|
|
48
|
+
]);
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
export { preloadMatchedRouteComponents };
|
|
File without changes
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { formDataToTextPlain, formDataToUrlSearchParams, toFormData } from "./formData.mjs";
|
|
2
|
+
class RouteActionResponseError extends Error {
|
|
3
|
+
constructor(response, data){
|
|
4
|
+
super(`Route action failed with status ${response.status}`);
|
|
5
|
+
this.name = 'RouteActionResponseError';
|
|
6
|
+
this.response = response;
|
|
7
|
+
this.data = data;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function resolveRouteHandlers(router, actionTo) {
|
|
11
|
+
const builtLocation = router.buildLocation({
|
|
12
|
+
to: actionTo
|
|
13
|
+
});
|
|
14
|
+
const href = router.getParsedLocationHref(builtLocation);
|
|
15
|
+
const matchedRoutes = router.getMatchedRoutes(builtLocation.pathname);
|
|
16
|
+
const routeStaticData = matchedRoutes.foundRoute?.options?.staticData;
|
|
17
|
+
const action = routeStaticData?.modernRouteAction;
|
|
18
|
+
const loader = routeStaticData?.modernRouteLoader;
|
|
19
|
+
return {
|
|
20
|
+
action,
|
|
21
|
+
loader,
|
|
22
|
+
href,
|
|
23
|
+
params: matchedRoutes.routeParams || {}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function isRedirectResponse(value) {
|
|
27
|
+
if (!(value instanceof Response)) return false;
|
|
28
|
+
return [
|
|
29
|
+
301,
|
|
30
|
+
302,
|
|
31
|
+
303,
|
|
32
|
+
307,
|
|
33
|
+
308
|
|
34
|
+
].includes(value.status);
|
|
35
|
+
}
|
|
36
|
+
async function parseResponseData(response) {
|
|
37
|
+
if (204 === response.status) return null;
|
|
38
|
+
const contentType = response.headers.get('Content-Type') || '';
|
|
39
|
+
if (contentType.includes('application/json')) return response.json();
|
|
40
|
+
return response.text();
|
|
41
|
+
}
|
|
42
|
+
async function parseResponseResultOrThrow(response) {
|
|
43
|
+
const parsed = await parseResponseData(response);
|
|
44
|
+
if (!response.ok) throw new RouteActionResponseError(response, parsed);
|
|
45
|
+
return parsed;
|
|
46
|
+
}
|
|
47
|
+
async function submitRouteAction({ router, target, options = {}, isFetcher = false, onInvalidateStart }) {
|
|
48
|
+
const method = (options.method || 'post').toLowerCase();
|
|
49
|
+
const encType = options.encType || 'application/x-www-form-urlencoded';
|
|
50
|
+
const actionTo = options.action || '.';
|
|
51
|
+
const formData = toFormData(target);
|
|
52
|
+
const resolved = resolveRouteHandlers(router, actionTo);
|
|
53
|
+
if ('get' === method) {
|
|
54
|
+
const search = formDataToUrlSearchParams(formData).toString();
|
|
55
|
+
const requestUrl = new URL(resolved.href, window.location.origin);
|
|
56
|
+
requestUrl.search = search;
|
|
57
|
+
if (isFetcher && resolved.loader) {
|
|
58
|
+
const result = await resolved.loader({
|
|
59
|
+
request: new Request(requestUrl, {
|
|
60
|
+
method: 'GET'
|
|
61
|
+
}),
|
|
62
|
+
params: resolved.params
|
|
63
|
+
});
|
|
64
|
+
if (result instanceof Response) {
|
|
65
|
+
const redirectTo = result.headers.get('X-Modernjs-Redirect') || result.headers.get('Location');
|
|
66
|
+
if (redirectTo || isRedirectResponse(result)) {
|
|
67
|
+
await router.navigate({
|
|
68
|
+
to: redirectTo || '/'
|
|
69
|
+
});
|
|
70
|
+
return parseResponseData(result);
|
|
71
|
+
}
|
|
72
|
+
return parseResponseResultOrThrow(result);
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
await router.navigate({
|
|
77
|
+
href: `${requestUrl.pathname}${requestUrl.search}${requestUrl.hash}`
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (!resolved.action) throw new Error(`No route action found for "${actionTo}"`);
|
|
82
|
+
const headers = new Headers();
|
|
83
|
+
let body = null;
|
|
84
|
+
if (encType.includes('application/json')) {
|
|
85
|
+
headers.set('Content-Type', 'application/json');
|
|
86
|
+
body = JSON.stringify(Object.fromEntries(formDataToUrlSearchParams(formData).entries()));
|
|
87
|
+
} else if (encType.includes('text/plain')) {
|
|
88
|
+
headers.set('Content-Type', 'text/plain;charset=UTF-8');
|
|
89
|
+
body = formDataToTextPlain(formData);
|
|
90
|
+
} else if (encType.includes('application/x-www-form-urlencoded')) {
|
|
91
|
+
headers.set('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
|
|
92
|
+
body = formDataToUrlSearchParams(formData);
|
|
93
|
+
} else body = formData;
|
|
94
|
+
const request = new Request(new URL(resolved.href, window.location.origin), {
|
|
95
|
+
method: method.toUpperCase(),
|
|
96
|
+
headers,
|
|
97
|
+
body
|
|
98
|
+
});
|
|
99
|
+
const result = await resolved.action({
|
|
100
|
+
request,
|
|
101
|
+
params: resolved.params
|
|
102
|
+
});
|
|
103
|
+
if (result instanceof Response) {
|
|
104
|
+
const redirectTo = result.headers.get('X-Modernjs-Redirect') || result.headers.get('Location');
|
|
105
|
+
if (redirectTo || isRedirectResponse(result)) {
|
|
106
|
+
await router.navigate({
|
|
107
|
+
to: redirectTo || '/'
|
|
108
|
+
});
|
|
109
|
+
return parseResponseData(result);
|
|
110
|
+
}
|
|
111
|
+
const parsed = isFetcher ? await parseResponseResultOrThrow(result) : await parseResponseData(result);
|
|
112
|
+
onInvalidateStart?.();
|
|
113
|
+
await router.invalidate();
|
|
114
|
+
return parsed;
|
|
115
|
+
}
|
|
116
|
+
onInvalidateStart?.();
|
|
117
|
+
await router.invalidate();
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
export { RouteActionResponseError, submitRouteAction };
|
|
@@ -1,83 +1,55 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import react from "react";
|
|
3
|
-
function
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
...props
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
|
-
return LayoutWrapper;
|
|
3
|
+
function withGlobalLayout(Component, globalApp) {
|
|
4
|
+
if (!globalApp) return Component;
|
|
5
|
+
const GlobalLayout = globalApp;
|
|
6
|
+
return function(props) {
|
|
7
|
+
return /*#__PURE__*/ jsx(GlobalLayout, {
|
|
8
|
+
Component: Component,
|
|
9
|
+
...props
|
|
10
|
+
});
|
|
15
11
|
};
|
|
16
|
-
const routeObjects = [];
|
|
17
|
-
for (const route of routes)if ('nested' === route.type) {
|
|
18
|
-
const nestedRouteObject = {
|
|
19
|
-
path: route.path,
|
|
20
|
-
id: route.id,
|
|
21
|
-
loader: route.loader,
|
|
22
|
-
action: route.action,
|
|
23
|
-
shouldRevalidate: route.shouldRevalidate,
|
|
24
|
-
handle: {
|
|
25
|
-
...route.handle,
|
|
26
|
-
...'object' == typeof route.config ? route.config?.handle : {}
|
|
27
|
-
},
|
|
28
|
-
index: route.index,
|
|
29
|
-
hasLoader: Boolean(route.loader),
|
|
30
|
-
hasClientLoader: Boolean(route.clientData),
|
|
31
|
-
hasAction: Boolean(route.action),
|
|
32
|
-
...route.isClientComponent ? {
|
|
33
|
-
isClientComponent: true
|
|
34
|
-
} : {},
|
|
35
|
-
...route.inValidSSRRoute ? {
|
|
36
|
-
inValidSSRRoute: true
|
|
37
|
-
} : {},
|
|
38
|
-
lazyImport: route.lazyImport,
|
|
39
|
-
Component: route.component ? route.component : void 0,
|
|
40
|
-
errorElement: route.error ? /*#__PURE__*/ jsx(route.error, {}) : void 0,
|
|
41
|
-
children: route.children ? route.children.map((child)=>getRouteObjects([
|
|
42
|
-
child
|
|
43
|
-
], {
|
|
44
|
-
globalApp,
|
|
45
|
-
ssrMode,
|
|
46
|
-
props
|
|
47
|
-
})[0]) : void 0
|
|
48
|
-
};
|
|
49
|
-
routeObjects.push(nestedRouteObject);
|
|
50
|
-
} else if ('function' == typeof route.component || 'object' == typeof route.component) {
|
|
51
|
-
const LayoutComponent = createLayoutElement(route.component);
|
|
52
|
-
const routeObject = {
|
|
53
|
-
path: route.path,
|
|
54
|
-
element: /*#__PURE__*/ react.createElement(LayoutComponent)
|
|
55
|
-
};
|
|
56
|
-
routeObjects.push(routeObject);
|
|
57
|
-
}
|
|
58
|
-
return routeObjects;
|
|
59
12
|
}
|
|
60
|
-
function
|
|
13
|
+
function getRouteHandle(route) {
|
|
14
|
+
return {
|
|
15
|
+
...route.handle,
|
|
16
|
+
...'object' == typeof route.config ? route.config?.handle : {}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function toTanstackRouteObject(route, globalApp) {
|
|
20
|
+
if ('nested' === route.type) return {
|
|
21
|
+
path: route.path,
|
|
22
|
+
id: route.id,
|
|
23
|
+
loader: route.loader,
|
|
24
|
+
action: route.action,
|
|
25
|
+
shouldRevalidate: route.shouldRevalidate,
|
|
26
|
+
handle: getRouteHandle(route),
|
|
27
|
+
index: route.index,
|
|
28
|
+
hasLoader: Boolean(route.loader),
|
|
29
|
+
hasClientLoader: Boolean(route.clientData),
|
|
30
|
+
hasAction: Boolean(route.action),
|
|
31
|
+
...route.isClientComponent ? {
|
|
32
|
+
isClientComponent: true
|
|
33
|
+
} : {},
|
|
34
|
+
...route.inValidSSRRoute ? {
|
|
35
|
+
inValidSSRRoute: true
|
|
36
|
+
} : {},
|
|
37
|
+
lazyImport: route.lazyImport,
|
|
38
|
+
Component: route.component ? route.component : void 0,
|
|
39
|
+
errorElement: route.error ? /*#__PURE__*/ react.createElement(route.error) : void 0,
|
|
40
|
+
children: route.children ? route.children.map((child)=>toTanstackRouteObject(child, globalApp)).filter((child)=>null !== child) : void 0
|
|
41
|
+
};
|
|
42
|
+
if ('function' != typeof route.component && 'object' != typeof route.component) return null;
|
|
43
|
+
const LayoutComponent = withGlobalLayout(route.component, globalApp);
|
|
44
|
+
return {
|
|
45
|
+
path: route.path,
|
|
46
|
+
element: /*#__PURE__*/ react.createElement(LayoutComponent)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function createTanstackRouteObjectsFromConfig({ routesConfig }) {
|
|
61
50
|
if (!routesConfig) return null;
|
|
62
51
|
const { routes, globalApp } = routesConfig;
|
|
63
52
|
if (!routes) return null;
|
|
64
|
-
return
|
|
65
|
-
globalApp,
|
|
66
|
-
ssrMode,
|
|
67
|
-
props
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
const urlJoin = (...parts)=>{
|
|
71
|
-
const separator = '/';
|
|
72
|
-
const replace = new RegExp(`${separator}{1,}`, 'g');
|
|
73
|
-
return standardSlash(parts.join(separator).replace(replace, separator));
|
|
74
|
-
};
|
|
75
|
-
function standardSlash(str) {
|
|
76
|
-
let addr = str;
|
|
77
|
-
if (!addr || 'string' != typeof addr) return addr;
|
|
78
|
-
if (addr.startsWith('.')) addr = addr.slice(1);
|
|
79
|
-
if (!addr.startsWith('/')) addr = `/${addr}`;
|
|
80
|
-
if (addr.endsWith('/') && '/' !== addr) addr = addr.slice(0, addr.length - 1);
|
|
81
|
-
return addr;
|
|
53
|
+
return routes.map((route)=>toTanstackRouteObject(route, globalApp)).filter((route)=>null !== route);
|
|
82
54
|
}
|
|
83
|
-
export {
|
|
55
|
+
export { createTanstackRouteObjectsFromConfig };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import node_path from "node:path";
|
|
3
|
+
import { fs } from "@modern-js/utils";
|
|
4
|
+
import { collectCanonicalRoutesForEntry, generateTanstackRouterTypesSourceForEntry } from "./tanstackTypes.mjs";
|
|
5
|
+
const DEFAULT_GENERATED_DIR_NAME = 'modern-tanstack';
|
|
6
|
+
async function writeFileIfChanged(filePath, content) {
|
|
7
|
+
try {
|
|
8
|
+
const previous = await fs.pathExists(filePath) ? await fs.readFile(filePath, 'utf-8') : null;
|
|
9
|
+
if (previous === content) return;
|
|
10
|
+
} catch {}
|
|
11
|
+
await fs.outputFile(filePath, content, 'utf-8');
|
|
12
|
+
}
|
|
13
|
+
function createRegisterDtsContent(opts) {
|
|
14
|
+
const importStatements = opts.entries.map((entryName, index)=>`import type { router as router${index} } from './${entryName}/router.gen';`).join('\n');
|
|
15
|
+
const routerUnionType = opts.entries.map((_, index)=>`typeof router${index}`).join(' | ');
|
|
16
|
+
const canonicalEntries = Object.entries(opts.canonicalRoutes ?? {});
|
|
17
|
+
const canonicalRoutesAugmentation = canonicalEntries.length > 0 ? `
|
|
18
|
+
declare module '${opts.i18nRuntimeModule || '@modern-js/plugin-i18n/runtime'}' {
|
|
19
|
+
interface UltramodernCanonicalRoutes {
|
|
20
|
+
${canonicalEntries.map(([routePath, paramsType])=>` '${routePath}': ${paramsType};`).join('\n')}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
` : '';
|
|
24
|
+
return `// This file is auto-generated by Modern.js. Do not edit manually.
|
|
25
|
+
|
|
26
|
+
${importStatements}
|
|
27
|
+
|
|
28
|
+
declare module '${opts.runtimeModule}' {
|
|
29
|
+
interface Register {
|
|
30
|
+
router: ${routerUnionType};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
${canonicalRoutesAugmentation}`;
|
|
34
|
+
}
|
|
35
|
+
async function writeTanstackRegisterFile(opts) {
|
|
36
|
+
const { entries, generatedDirName = DEFAULT_GENERATED_DIR_NAME, runtimeModule = '@modern-js/plugin-tanstack/runtime', srcDirectory, canonicalRoutes, i18nRuntimeModule } = opts;
|
|
37
|
+
if (0 === entries.length) return;
|
|
38
|
+
const registerDtsPath = node_path.join(srcDirectory, generatedDirName, 'register.gen.d.ts');
|
|
39
|
+
await writeFileIfChanged(registerDtsPath, createRegisterDtsContent({
|
|
40
|
+
entries,
|
|
41
|
+
runtimeModule,
|
|
42
|
+
canonicalRoutes,
|
|
43
|
+
i18nRuntimeModule
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
async function writeTanstackRouterTypesForEntries(opts) {
|
|
47
|
+
const { appContext, generatedDirName = DEFAULT_GENERATED_DIR_NAME, routesByEntry, i18nPluginInstalled = false } = opts;
|
|
48
|
+
const entryNames = Object.keys(routesByEntry);
|
|
49
|
+
await Promise.all(entryNames.map(async (entryName)=>{
|
|
50
|
+
const { routerGenTs } = await generateTanstackRouterTypesSourceForEntry({
|
|
51
|
+
appContext,
|
|
52
|
+
entryName,
|
|
53
|
+
generatedDirName,
|
|
54
|
+
routes: routesByEntry[entryName]
|
|
55
|
+
});
|
|
56
|
+
await writeFileIfChanged(node_path.join(appContext.srcDirectory, generatedDirName, entryName, 'router.gen.ts'), routerGenTs);
|
|
57
|
+
}));
|
|
58
|
+
const mainEntryName = appContext.entrypoints?.find((entrypoint)=>entrypoint.isMainEntry)?.entryName;
|
|
59
|
+
const registerEntries = entryNames.sort((a, b)=>{
|
|
60
|
+
if (mainEntryName && a === mainEntryName) return -1;
|
|
61
|
+
if (mainEntryName && b === mainEntryName) return 1;
|
|
62
|
+
return a.localeCompare(b);
|
|
63
|
+
});
|
|
64
|
+
let canonicalRoutes = null;
|
|
65
|
+
if (i18nPluginInstalled) for (const entryName of registerEntries){
|
|
66
|
+
const entryCanonicalRoutes = collectCanonicalRoutesForEntry(routesByEntry[entryName], {
|
|
67
|
+
localeParamHeuristic: true
|
|
68
|
+
});
|
|
69
|
+
if (entryCanonicalRoutes) canonicalRoutes = {
|
|
70
|
+
...entryCanonicalRoutes,
|
|
71
|
+
...canonicalRoutes ?? {}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
await writeTanstackRegisterFile({
|
|
75
|
+
entries: registerEntries,
|
|
76
|
+
generatedDirName,
|
|
77
|
+
srcDirectory: appContext.srcDirectory,
|
|
78
|
+
canonicalRoutes
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async function generateTanstackRouteArtifacts(opts) {
|
|
82
|
+
const [{ createRunOptions }, { cli }, utils] = await Promise.all([
|
|
83
|
+
import("@modern-js/app-tools/cli/run"),
|
|
84
|
+
import("@modern-js/plugin/cli"),
|
|
85
|
+
import("@modern-js/utils")
|
|
86
|
+
]);
|
|
87
|
+
process.env.MODERN_ARGV = 'node modern build';
|
|
88
|
+
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
|
|
89
|
+
const { findExists, CONFIG_FILE_EXTENSIONS } = utils;
|
|
90
|
+
const configFileBase = node_path.resolve(opts.appDirectory, 'modern.config');
|
|
91
|
+
const resolvedConfigFile = findExists(CONFIG_FILE_EXTENSIONS.map((extension)=>`${configFileBase}${extension}`));
|
|
92
|
+
if (!resolvedConfigFile) throw new Error(`[plugin-tanstack] Unable to locate a Modern.js config file (modern.config.{${CONFIG_FILE_EXTENSIONS.map((extension)=>extension.slice(1)).join(',')}}) in ${opts.appDirectory}. TanStack route generation requires the app config to resolve its plugins.`);
|
|
93
|
+
const runOptions = await createRunOptions({
|
|
94
|
+
cwd: opts.appDirectory,
|
|
95
|
+
configFile: configFileBase,
|
|
96
|
+
version: opts.version || process.env.MODERN_JS_VERSION || '0.0.0-routes-generate',
|
|
97
|
+
internalPlugins: utils.INTERNAL_RUNTIME_PLUGINS
|
|
98
|
+
});
|
|
99
|
+
await cli.init({
|
|
100
|
+
...runOptions,
|
|
101
|
+
command: 'build'
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
export { generateTanstackRouteArtifacts, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import node_path from "node:path";
|
|
3
|
-
import { NESTED_ROUTE_SPEC_FILE, filterRoutesForServer
|
|
3
|
+
import { NESTED_ROUTE_SPEC_FILE, filterRoutesForServer } from "@modern-js/utils";
|
|
4
|
+
import { generateTanstackRouteArtifacts, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries } from "./artifacts.mjs";
|
|
4
5
|
import { createTanstackRsbuildRouteSplittingProfile, resolveTanstackRouteCodeSplittingEnabled } from "./routeSplitting.mjs";
|
|
5
|
-
import { collectCanonicalRoutesForEntry, generateTanstackRouterTypesSourceForEntry } from "./tanstackTypes.mjs";
|
|
6
6
|
import { __webpack_require__ } from "../rslib-runtime.mjs";
|
|
7
7
|
import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
|
|
8
8
|
import { dirname as __rspack_dirname } from "node:path";
|
|
@@ -26,81 +26,6 @@ function getRuntimeRouterCli() {
|
|
|
26
26
|
}
|
|
27
27
|
throw new Error('@modern-js/plugin-tanstack requires @modern-js/runtime/cli router helper exports.');
|
|
28
28
|
}
|
|
29
|
-
async function writeFileIfChanged(filePath, content) {
|
|
30
|
-
try {
|
|
31
|
-
const previous = await fs.pathExists(filePath) ? await fs.readFile(filePath, 'utf-8') : null;
|
|
32
|
-
if (previous === content) return;
|
|
33
|
-
} catch {}
|
|
34
|
-
await fs.outputFile(filePath, content, 'utf-8');
|
|
35
|
-
}
|
|
36
|
-
function createRegisterDtsContent(opts) {
|
|
37
|
-
const importStatements = opts.entries.map((entryName, index)=>`import type { router as router${index} } from './${entryName}/router.gen';`).join('\n');
|
|
38
|
-
const routerUnionType = opts.entries.map((_, index)=>`typeof router${index}`).join(' | ');
|
|
39
|
-
const canonicalEntries = Object.entries(opts.canonicalRoutes ?? {});
|
|
40
|
-
const canonicalRoutesAugmentation = canonicalEntries.length > 0 ? `
|
|
41
|
-
declare module '${opts.i18nRuntimeModule || '@modern-js/plugin-i18n/runtime'}' {
|
|
42
|
-
interface UltramodernCanonicalRoutes {
|
|
43
|
-
${canonicalEntries.map(([routePath, paramsType])=>` '${routePath}': ${paramsType};`).join('\n')}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
` : '';
|
|
47
|
-
return `// This file is auto-generated by Modern.js. Do not edit manually.
|
|
48
|
-
|
|
49
|
-
${importStatements}
|
|
50
|
-
|
|
51
|
-
declare module '${opts.runtimeModule}' {
|
|
52
|
-
interface Register {
|
|
53
|
-
router: ${routerUnionType};
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
${canonicalRoutesAugmentation}`;
|
|
57
|
-
}
|
|
58
|
-
async function writeTanstackRegisterFile(opts) {
|
|
59
|
-
const { entries, generatedDirName = DEFAULT_GENERATED_DIR_NAME, runtimeModule = '@modern-js/plugin-tanstack/runtime', srcDirectory, canonicalRoutes, i18nRuntimeModule } = opts;
|
|
60
|
-
if (0 === entries.length) return;
|
|
61
|
-
const registerDtsPath = node_path.join(srcDirectory, generatedDirName, 'register.gen.d.ts');
|
|
62
|
-
await writeFileIfChanged(registerDtsPath, createRegisterDtsContent({
|
|
63
|
-
entries,
|
|
64
|
-
runtimeModule,
|
|
65
|
-
canonicalRoutes,
|
|
66
|
-
i18nRuntimeModule
|
|
67
|
-
}));
|
|
68
|
-
}
|
|
69
|
-
async function writeTanstackRouterTypesForEntries(opts) {
|
|
70
|
-
const { appContext, generatedDirName = DEFAULT_GENERATED_DIR_NAME, routesByEntry, i18nPluginInstalled = false } = opts;
|
|
71
|
-
const entryNames = Object.keys(routesByEntry);
|
|
72
|
-
await Promise.all(entryNames.map(async (entryName)=>{
|
|
73
|
-
const { routerGenTs } = await generateTanstackRouterTypesSourceForEntry({
|
|
74
|
-
appContext,
|
|
75
|
-
entryName,
|
|
76
|
-
generatedDirName,
|
|
77
|
-
routes: routesByEntry[entryName]
|
|
78
|
-
});
|
|
79
|
-
await writeFileIfChanged(node_path.join(appContext.srcDirectory, generatedDirName, entryName, 'router.gen.ts'), routerGenTs);
|
|
80
|
-
}));
|
|
81
|
-
const mainEntryName = appContext.entrypoints?.find((entrypoint)=>entrypoint.isMainEntry)?.entryName;
|
|
82
|
-
const registerEntries = entryNames.sort((a, b)=>{
|
|
83
|
-
if (mainEntryName && a === mainEntryName) return -1;
|
|
84
|
-
if (mainEntryName && b === mainEntryName) return 1;
|
|
85
|
-
return a.localeCompare(b);
|
|
86
|
-
});
|
|
87
|
-
let canonicalRoutes = null;
|
|
88
|
-
if (i18nPluginInstalled) for (const entryName of registerEntries){
|
|
89
|
-
const entryCanonicalRoutes = collectCanonicalRoutesForEntry(routesByEntry[entryName], {
|
|
90
|
-
localeParamHeuristic: true
|
|
91
|
-
});
|
|
92
|
-
if (entryCanonicalRoutes) canonicalRoutes = {
|
|
93
|
-
...entryCanonicalRoutes,
|
|
94
|
-
...canonicalRoutes ?? {}
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
await writeTanstackRegisterFile({
|
|
98
|
-
entries: registerEntries,
|
|
99
|
-
generatedDirName,
|
|
100
|
-
srcDirectory: appContext.srcDirectory,
|
|
101
|
-
canonicalRoutes
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
29
|
function tanstackRouterPlugin(options = {}) {
|
|
105
30
|
const routesDir = options.routesDir || DEFAULT_ROUTES_DIR;
|
|
106
31
|
const generatedDirName = options.generatedDirName || DEFAULT_GENERATED_DIR_NAME;
|
|
@@ -242,29 +167,7 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
242
167
|
}
|
|
243
168
|
};
|
|
244
169
|
}
|
|
245
|
-
async function generateTanstackRouteArtifacts(opts) {
|
|
246
|
-
const [{ createRunOptions }, { cli }, utils] = await Promise.all([
|
|
247
|
-
import("@modern-js/app-tools/cli/run"),
|
|
248
|
-
import("@modern-js/plugin/cli"),
|
|
249
|
-
import("@modern-js/utils")
|
|
250
|
-
]);
|
|
251
|
-
process.env.MODERN_ARGV = 'node modern build';
|
|
252
|
-
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
|
|
253
|
-
const { findExists, CONFIG_FILE_EXTENSIONS } = utils;
|
|
254
|
-
const configFileBase = node_path.resolve(opts.appDirectory, 'modern.config');
|
|
255
|
-
const resolvedConfigFile = findExists(CONFIG_FILE_EXTENSIONS.map((extension)=>`${configFileBase}${extension}`));
|
|
256
|
-
if (!resolvedConfigFile) throw new Error(`[plugin-tanstack] Unable to locate a Modern.js config file (modern.config.{${CONFIG_FILE_EXTENSIONS.map((extension)=>extension.slice(1)).join(',')}}) in ${opts.appDirectory}. TanStack route generation requires the app config to resolve its plugins.`);
|
|
257
|
-
const runOptions = await createRunOptions({
|
|
258
|
-
cwd: opts.appDirectory,
|
|
259
|
-
configFile: configFileBase,
|
|
260
|
-
version: opts.version || process.env.MODERN_JS_VERSION || '0.0.0-routes-generate',
|
|
261
|
-
internalPlugins: utils.INTERNAL_RUNTIME_PLUGINS
|
|
262
|
-
});
|
|
263
|
-
await cli.init({
|
|
264
|
-
...runOptions,
|
|
265
|
-
command: 'build'
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
170
|
const src_cli = tanstackRouterPlugin;
|
|
171
|
+
export { collectCanonicalRoutesForEntry, generateTanstackRouterTypesSourceForEntry } from "./tanstackTypes.mjs";
|
|
269
172
|
export default src_cli;
|
|
270
|
-
export {
|
|
173
|
+
export { createTanstackRsbuildRouteSplittingProfile, generateTanstackRouteArtifacts, resolveTanstackRouteCodeSplittingEnabled, tanstackRouterPlugin, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { toTanstackPath } from "./shared.mjs";
|
|
3
|
+
const LOCALE_PARAM_SEGMENTS = new Set([
|
|
4
|
+
':lang',
|
|
5
|
+
':locale',
|
|
6
|
+
':language',
|
|
7
|
+
'$lang',
|
|
8
|
+
'$locale',
|
|
9
|
+
'$language'
|
|
10
|
+
]);
|
|
11
|
+
function paramsTypeForCanonicalPath(canonicalPath) {
|
|
12
|
+
const fields = [];
|
|
13
|
+
for (const segment of canonicalPath.split('/'))if (segment) {
|
|
14
|
+
if ('*' === segment || '$' === segment) {
|
|
15
|
+
fields.push("'_splat'?: string");
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (segment.startsWith('{-$') && segment.endsWith('}')) {
|
|
19
|
+
fields.push(`${JSON.stringify(segment.slice(3, -1))}?: string`);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (segment.startsWith('$')) {
|
|
23
|
+
fields.push(`${JSON.stringify(segment.slice(1))}: string`);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (segment.startsWith(':')) {
|
|
27
|
+
const optional = segment.endsWith('?');
|
|
28
|
+
const name = segment.slice(1, optional ? void 0 : segment.length);
|
|
29
|
+
fields.push(`${JSON.stringify(optional ? name.slice(0, -1) : name)}${optional ? '?' : ''}: string`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return fields.length > 0 ? `{ ${fields.join('; ')} }` : 'Record<string, never>';
|
|
33
|
+
}
|
|
34
|
+
function collectCanonicalRoutesForEntry(routes, options = {}) {
|
|
35
|
+
const { localeParamHeuristic = true } = options;
|
|
36
|
+
const canonicalParams = new Map();
|
|
37
|
+
let hasI18nSurface = false;
|
|
38
|
+
const normalizeJoined = (joined)=>{
|
|
39
|
+
const collapsed = joined.replace(/\/+/g, '/');
|
|
40
|
+
const withLeading = collapsed.startsWith('/') ? collapsed : `/${collapsed}`;
|
|
41
|
+
return withLeading.length > 1 ? withLeading.replace(/\/+$/, '') : withLeading;
|
|
42
|
+
};
|
|
43
|
+
const record = (canonicalPath)=>{
|
|
44
|
+
const normalized = normalizeJoined(canonicalPath || '/');
|
|
45
|
+
const key = toTanstackPath(normalized);
|
|
46
|
+
if (!canonicalParams.has(key)) canonicalParams.set(key, paramsTypeForCanonicalPath(normalized));
|
|
47
|
+
};
|
|
48
|
+
const visit = (route, parentPath)=>{
|
|
49
|
+
let currentPath = parentPath;
|
|
50
|
+
if ('string' == typeof route.modernCanonicalPath) {
|
|
51
|
+
hasI18nSurface = true;
|
|
52
|
+
currentPath = normalizeJoined(route.modernCanonicalPath);
|
|
53
|
+
} else if ('string' == typeof route.path && route.path.length > 0) {
|
|
54
|
+
const segments = route.path.replace(/\[(.+?)\]/g, ':$1').split('/').filter(Boolean);
|
|
55
|
+
if (localeParamHeuristic && '' === parentPath && LOCALE_PARAM_SEGMENTS.has(segments[0])) {
|
|
56
|
+
hasI18nSurface = true;
|
|
57
|
+
segments.shift();
|
|
58
|
+
}
|
|
59
|
+
currentPath = segments.length ? normalizeJoined(`${parentPath}/${segments.join('/')}`) : parentPath;
|
|
60
|
+
}
|
|
61
|
+
const children = route.children;
|
|
62
|
+
if (children && children.length > 0) {
|
|
63
|
+
for (const child of children)visit(child, currentPath);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
record(currentPath || '/');
|
|
67
|
+
};
|
|
68
|
+
const rootModern = routes.find((route)=>route.isRoot);
|
|
69
|
+
const topLevel = rootModern ? rootModern.children ?? [] : routes;
|
|
70
|
+
for (const route of topLevel)visit(route, '');
|
|
71
|
+
if (!hasI18nSurface || 0 === canonicalParams.size) return null;
|
|
72
|
+
return Object.fromEntries([
|
|
73
|
+
...canonicalParams.entries()
|
|
74
|
+
].sort(([a], [b])=>a.localeCompare(b)));
|
|
75
|
+
}
|
|
76
|
+
export { collectCanonicalRoutesForEntry };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { getPathWithoutExt } from "@modern-js/runtime/cli";
|
|
3
|
+
import { findExists, formatImportPath, slash } from "@modern-js/utils";
|
|
4
|
+
const JS_OR_TS_EXTS = [
|
|
5
|
+
'.js',
|
|
6
|
+
'.jsx',
|
|
7
|
+
'.ts',
|
|
8
|
+
'.tsx',
|
|
9
|
+
'.mjs',
|
|
10
|
+
'.mts',
|
|
11
|
+
'.cjs',
|
|
12
|
+
'.cts'
|
|
13
|
+
];
|
|
14
|
+
function toTanstackPath(pathname) {
|
|
15
|
+
return pathname.split('/').map((segment)=>{
|
|
16
|
+
if (!segment) return segment;
|
|
17
|
+
if ('*' === segment) return '$';
|
|
18
|
+
if (segment.startsWith(':')) {
|
|
19
|
+
const name = segment.slice(1);
|
|
20
|
+
if (name.endsWith('?')) return `{-$${name.slice(0, -1)}}`;
|
|
21
|
+
return `$${name}`;
|
|
22
|
+
}
|
|
23
|
+
return segment;
|
|
24
|
+
}).join('/');
|
|
25
|
+
}
|
|
26
|
+
async function resolveFileNoExt(inputNoExtPath) {
|
|
27
|
+
const file = findExists(JS_OR_TS_EXTS.map((ext)=>`${inputNoExtPath}${ext}`));
|
|
28
|
+
return file ? getPathWithoutExt(file) : null;
|
|
29
|
+
}
|
|
30
|
+
function quote(str) {
|
|
31
|
+
return JSON.stringify(str);
|
|
32
|
+
}
|
|
33
|
+
function normalizeRelativeImport(p) {
|
|
34
|
+
const normalized = formatImportPath(slash(p));
|
|
35
|
+
if (normalized.startsWith('.')) return normalized;
|
|
36
|
+
return `./${normalized}`;
|
|
37
|
+
}
|
|
38
|
+
function pickModernLoaderModule(route) {
|
|
39
|
+
const loaderPath = route.data || route.loader;
|
|
40
|
+
if (!loaderPath || 'string' != typeof loaderPath) return null;
|
|
41
|
+
const inline = Boolean(route.data);
|
|
42
|
+
return {
|
|
43
|
+
loaderPath,
|
|
44
|
+
inline
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function pickRouteSearchContractModules(route) {
|
|
48
|
+
const validateSearchPath = route.validateSearch;
|
|
49
|
+
const loaderDepsPath = route.loaderDeps;
|
|
50
|
+
return {
|
|
51
|
+
validateSearchPath: 'string' == typeof validateSearchPath ? validateSearchPath : null,
|
|
52
|
+
loaderDepsPath: 'string' == typeof loaderDepsPath ? loaderDepsPath : null
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function isPathlessLayout(route) {
|
|
56
|
+
return 'nested' === route.type && 'boolean' != typeof route.index && void 0 === route.path;
|
|
57
|
+
}
|
|
58
|
+
function isIndexRoute(route) {
|
|
59
|
+
return 'nested' === route.type && Boolean(route.index);
|
|
60
|
+
}
|
|
61
|
+
function createRouteStaticDataSnippet(opts) {
|
|
62
|
+
const staticDataLines = [];
|
|
63
|
+
if (opts.modernRouteId) staticDataLines.push(`modernRouteId: ${quote(opts.modernRouteId)},`);
|
|
64
|
+
if (opts.loaderName) staticDataLines.push(`modernRouteLoader: ${opts.loaderName},`);
|
|
65
|
+
if (opts.actionName) staticDataLines.push(`modernRouteAction: ${opts.actionName},`);
|
|
66
|
+
if (!staticDataLines.length) return null;
|
|
67
|
+
return `staticData: createRouteStaticData({\n ${staticDataLines.join('\n ')}\n }),`;
|
|
68
|
+
}
|
|
69
|
+
export { createRouteStaticDataSnippet, isIndexRoute, isPathlessLayout, normalizeRelativeImport, pickModernLoaderModule, pickRouteSearchContractModules, quote, resolveFileNoExt, toTanstackPath };
|