@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.
Files changed (221) hide show
  1. package/dist/cjs/cli/artifacts.js +157 -0
  2. package/dist/cjs/cli/index.js +6 -103
  3. package/dist/cjs/cli/tanstackTypes/canonicalRoutes.js +113 -0
  4. package/dist/cjs/cli/tanstackTypes/shared.js +130 -0
  5. package/dist/cjs/cli/tanstackTypes/source.js +251 -0
  6. package/dist/cjs/cli/tanstackTypes.js +4 -350
  7. package/dist/cjs/runtime/blockingSubscribe.js +64 -0
  8. package/dist/cjs/runtime/{pluginCore.js → clientBasepath.js} +12 -19
  9. package/dist/cjs/runtime/clientHydration.js +129 -0
  10. package/dist/cjs/runtime/dataMutation.js +11 -176
  11. package/dist/cjs/runtime/formData.js +116 -0
  12. package/dist/cjs/runtime/loaderBridge.js +4 -1
  13. package/dist/cjs/runtime/plugin.js +21 -125
  14. package/dist/cjs/runtime/plugin.node.js +38 -119
  15. package/dist/cjs/runtime/pluginShared.js +90 -0
  16. package/dist/cjs/runtime/routeTree/components.js +102 -0
  17. package/dist/cjs/runtime/routeTree/construction.js +152 -0
  18. package/dist/cjs/runtime/routeTree/index.js +47 -0
  19. package/dist/cjs/runtime/routeTree/loaders.js +158 -0
  20. package/dist/cjs/runtime/routeTree/paths.js +57 -0
  21. package/dist/cjs/runtime/routeTree/staticData.js +63 -0
  22. package/dist/cjs/runtime/routeTree/tanstackRoutes.js +57 -0
  23. package/dist/cjs/runtime/routeTree/types.js +18 -0
  24. package/dist/cjs/runtime/routeTree.js +7 -320
  25. package/dist/cjs/runtime/rsc/CompositeComponent.js +18 -13
  26. package/dist/cjs/runtime/rsc/RscNodeRenderer.js +5 -16
  27. package/dist/cjs/runtime/rsc/client.js +8 -25
  28. package/dist/cjs/runtime/rsc/flightSerialization.js +132 -0
  29. package/dist/cjs/runtime/rsc/payloadErrors.js +99 -0
  30. package/dist/cjs/runtime/rsc/payloadFetch.js +117 -0
  31. package/dist/cjs/runtime/rsc/payloadRouter.js +21 -142
  32. package/dist/cjs/runtime/rsc/payloadRoutes.js +106 -0
  33. package/dist/cjs/runtime/rsc/payloadStorage.js +58 -0
  34. package/dist/cjs/runtime/rsc/server.js +14 -18
  35. package/dist/cjs/runtime/rsc/shared.js +71 -0
  36. package/dist/cjs/runtime/rsc/treeGetter.js +72 -0
  37. package/dist/cjs/runtime/ssrManagedTags.js +103 -0
  38. package/dist/cjs/runtime/ssrPreload.js +89 -0
  39. package/dist/cjs/runtime/ssrTypes.js +18 -0
  40. package/dist/cjs/runtime/submitAction.js +161 -0
  41. package/dist/cjs/runtime/utils.js +49 -86
  42. package/dist/esm/cli/artifacts.mjs +103 -0
  43. package/dist/esm/cli/index.mjs +4 -101
  44. package/dist/esm/cli/tanstackTypes/canonicalRoutes.mjs +75 -0
  45. package/dist/esm/cli/tanstackTypes/shared.mjs +68 -0
  46. package/dist/esm/cli/tanstackTypes/source.mjs +203 -0
  47. package/dist/esm/cli/tanstackTypes.mjs +2 -339
  48. package/dist/esm/runtime/blockingSubscribe.mjs +19 -0
  49. package/dist/esm/runtime/clientBasepath.mjs +10 -0
  50. package/dist/esm/runtime/clientHydration.mjs +70 -0
  51. package/dist/esm/runtime/dataMutation.mjs +2 -167
  52. package/dist/esm/runtime/formData.mjs +63 -0
  53. package/dist/esm/runtime/loaderBridge.mjs +4 -1
  54. package/dist/esm/runtime/plugin.mjs +14 -118
  55. package/dist/esm/runtime/plugin.node.mjs +33 -114
  56. package/dist/esm/runtime/pluginShared.mjs +40 -0
  57. package/dist/esm/runtime/routeTree/components.mjs +55 -0
  58. package/dist/esm/runtime/routeTree/construction.mjs +111 -0
  59. package/dist/esm/runtime/routeTree/index.mjs +2 -0
  60. package/dist/esm/runtime/routeTree/loaders.mjs +117 -0
  61. package/dist/esm/runtime/routeTree/paths.mjs +16 -0
  62. package/dist/esm/runtime/routeTree/staticData.mjs +22 -0
  63. package/dist/esm/runtime/routeTree/tanstackRoutes.mjs +13 -0
  64. package/dist/esm/runtime/routeTree/types.mjs +0 -0
  65. package/dist/esm/runtime/routeTree.mjs +1 -318
  66. package/dist/esm/runtime/rsc/CompositeComponent.mjs +18 -13
  67. package/dist/esm/runtime/rsc/RscNodeRenderer.mjs +4 -15
  68. package/dist/esm/runtime/rsc/client.mjs +6 -26
  69. package/dist/esm/runtime/rsc/flightSerialization.mjs +88 -0
  70. package/dist/esm/runtime/rsc/payloadErrors.mjs +49 -0
  71. package/dist/esm/runtime/rsc/payloadFetch.mjs +61 -0
  72. package/dist/esm/runtime/rsc/payloadRouter.mjs +12 -133
  73. package/dist/esm/runtime/rsc/payloadRoutes.mjs +50 -0
  74. package/dist/esm/runtime/rsc/payloadStorage.mjs +14 -0
  75. package/dist/esm/runtime/rsc/server.mjs +17 -21
  76. package/dist/esm/runtime/rsc/shared.mjs +21 -0
  77. package/dist/esm/runtime/rsc/treeGetter.mjs +34 -0
  78. package/dist/esm/runtime/ssrManagedTags.mjs +53 -0
  79. package/dist/esm/runtime/ssrPreload.mjs +51 -0
  80. package/dist/esm/runtime/ssrTypes.mjs +0 -0
  81. package/dist/esm/runtime/submitAction.mjs +120 -0
  82. package/dist/esm/runtime/utils.mjs +47 -75
  83. package/dist/esm-node/cli/artifacts.mjs +104 -0
  84. package/dist/esm-node/cli/index.mjs +4 -101
  85. package/dist/esm-node/cli/tanstackTypes/canonicalRoutes.mjs +76 -0
  86. package/dist/esm-node/cli/tanstackTypes/shared.mjs +69 -0
  87. package/dist/esm-node/cli/tanstackTypes/source.mjs +204 -0
  88. package/dist/esm-node/cli/tanstackTypes.mjs +2 -339
  89. package/dist/esm-node/runtime/blockingSubscribe.mjs +20 -0
  90. package/dist/esm-node/runtime/clientBasepath.mjs +11 -0
  91. package/dist/esm-node/runtime/clientHydration.mjs +71 -0
  92. package/dist/esm-node/runtime/dataMutation.mjs +2 -167
  93. package/dist/esm-node/runtime/formData.mjs +64 -0
  94. package/dist/esm-node/runtime/loaderBridge.mjs +4 -1
  95. package/dist/esm-node/runtime/plugin.mjs +14 -118
  96. package/dist/esm-node/runtime/plugin.node.mjs +33 -114
  97. package/dist/esm-node/runtime/pluginShared.mjs +41 -0
  98. package/dist/esm-node/runtime/routeTree/components.mjs +56 -0
  99. package/dist/esm-node/runtime/routeTree/construction.mjs +112 -0
  100. package/dist/esm-node/runtime/routeTree/index.mjs +3 -0
  101. package/dist/esm-node/runtime/routeTree/loaders.mjs +118 -0
  102. package/dist/esm-node/runtime/routeTree/paths.mjs +17 -0
  103. package/dist/esm-node/runtime/routeTree/staticData.mjs +23 -0
  104. package/dist/esm-node/runtime/routeTree/tanstackRoutes.mjs +14 -0
  105. package/dist/esm-node/runtime/routeTree/types.mjs +1 -0
  106. package/dist/esm-node/runtime/routeTree.mjs +1 -318
  107. package/dist/esm-node/runtime/rsc/CompositeComponent.mjs +18 -13
  108. package/dist/esm-node/runtime/rsc/RscNodeRenderer.mjs +4 -15
  109. package/dist/esm-node/runtime/rsc/client.mjs +6 -26
  110. package/dist/esm-node/runtime/rsc/flightSerialization.mjs +89 -0
  111. package/dist/esm-node/runtime/rsc/payloadErrors.mjs +50 -0
  112. package/dist/esm-node/runtime/rsc/payloadFetch.mjs +62 -0
  113. package/dist/esm-node/runtime/rsc/payloadRouter.mjs +12 -133
  114. package/dist/esm-node/runtime/rsc/payloadRoutes.mjs +51 -0
  115. package/dist/esm-node/runtime/rsc/payloadStorage.mjs +15 -0
  116. package/dist/esm-node/runtime/rsc/server.mjs +17 -21
  117. package/dist/esm-node/runtime/rsc/shared.mjs +22 -0
  118. package/dist/esm-node/runtime/rsc/treeGetter.mjs +35 -0
  119. package/dist/esm-node/runtime/ssrManagedTags.mjs +54 -0
  120. package/dist/esm-node/runtime/ssrPreload.mjs +52 -0
  121. package/dist/esm-node/runtime/ssrTypes.mjs +1 -0
  122. package/dist/esm-node/runtime/submitAction.mjs +121 -0
  123. package/dist/esm-node/runtime/utils.mjs +47 -75
  124. package/dist/types/cli/artifacts.d.ts +33 -0
  125. package/dist/types/cli/index.d.ts +2 -33
  126. package/dist/types/cli/tanstackTypes/canonicalRoutes.d.ts +22 -0
  127. package/dist/types/cli/tanstackTypes/shared.d.ts +20 -0
  128. package/dist/types/cli/tanstackTypes/source.d.ts +10 -0
  129. package/dist/types/cli/tanstackTypes.d.ts +3 -31
  130. package/dist/types/runtime/blockingSubscribe.d.ts +3 -0
  131. package/dist/types/runtime/clientBasepath.d.ts +1 -0
  132. package/dist/types/runtime/clientHydration.d.ts +19 -0
  133. package/dist/types/runtime/dataMutation.d.ts +3 -12
  134. package/dist/types/runtime/formData.d.ts +23 -0
  135. package/dist/types/runtime/plugin.d.ts +1 -1
  136. package/dist/types/runtime/plugin.node.d.ts +1 -1
  137. package/dist/types/runtime/{pluginCore.d.ts → pluginShared.d.ts} +14 -0
  138. package/dist/types/runtime/routeTree/components.d.ts +7 -0
  139. package/dist/types/runtime/routeTree/construction.d.ts +5 -0
  140. package/dist/types/runtime/routeTree/index.d.ts +2 -0
  141. package/dist/types/runtime/routeTree/loaders.d.ts +4 -0
  142. package/dist/types/runtime/routeTree/paths.d.ts +3 -0
  143. package/dist/types/runtime/routeTree/staticData.d.ts +19 -0
  144. package/dist/types/runtime/routeTree/tanstackRoutes.d.ts +4 -0
  145. package/dist/types/runtime/routeTree/types.d.ts +75 -0
  146. package/dist/types/runtime/routeTree.d.ts +1 -9
  147. package/dist/types/runtime/rsc/CompositeComponent.d.ts +1 -2
  148. package/dist/types/runtime/rsc/RscNodeRenderer.d.ts +2 -3
  149. package/dist/types/runtime/rsc/client.d.ts +2 -0
  150. package/dist/types/runtime/rsc/flightSerialization.d.ts +3 -0
  151. package/dist/types/runtime/rsc/payloadErrors.d.ts +6 -0
  152. package/dist/types/runtime/rsc/payloadFetch.d.ts +10 -0
  153. package/dist/types/runtime/rsc/payloadRouter.d.ts +2 -10
  154. package/dist/types/runtime/rsc/payloadRoutes.d.ts +43 -0
  155. package/dist/types/runtime/rsc/payloadStorage.d.ts +5 -0
  156. package/dist/types/runtime/rsc/shared.d.ts +19 -0
  157. package/dist/types/runtime/rsc/treeGetter.d.ts +1 -0
  158. package/dist/types/runtime/ssrManagedTags.d.ts +7 -0
  159. package/dist/types/runtime/ssrPreload.d.ts +2 -0
  160. package/dist/types/runtime/ssrTypes.d.ts +43 -0
  161. package/dist/types/runtime/state.d.ts +1 -1
  162. package/dist/types/runtime/submitAction.d.ts +14 -0
  163. package/dist/types/runtime/types.d.ts +3 -46
  164. package/dist/types/runtime/utils.d.ts +1 -22
  165. package/package.json +30 -9
  166. package/rstest.config.mts +1 -0
  167. package/src/cli/artifacts.ts +255 -0
  168. package/src/cli/index.ts +6 -246
  169. package/src/cli/tanstackTypes/canonicalRoutes.ts +157 -0
  170. package/src/cli/tanstackTypes/shared.ts +119 -0
  171. package/src/cli/tanstackTypes/source.ts +405 -0
  172. package/src/cli/tanstackTypes.ts +4 -647
  173. package/src/runtime/blockingSubscribe.ts +48 -0
  174. package/src/runtime/clientBasepath.ts +12 -0
  175. package/src/runtime/clientHydration.ts +151 -0
  176. package/src/runtime/dataMutation.tsx +9 -306
  177. package/src/runtime/formData.ts +153 -0
  178. package/src/runtime/loaderBridge.ts +8 -3
  179. package/src/runtime/plugin.node.tsx +60 -284
  180. package/src/runtime/plugin.tsx +21 -257
  181. package/src/runtime/pluginShared.ts +112 -0
  182. package/src/runtime/routeTree/components.ts +130 -0
  183. package/src/runtime/routeTree/construction.ts +238 -0
  184. package/src/runtime/routeTree/index.ts +7 -0
  185. package/src/runtime/routeTree/loaders.ts +232 -0
  186. package/src/runtime/routeTree/paths.ts +36 -0
  187. package/src/runtime/routeTree/staticData.ts +66 -0
  188. package/src/runtime/routeTree/tanstackRoutes.ts +36 -0
  189. package/src/runtime/routeTree/types.ts +87 -0
  190. package/src/runtime/routeTree.ts +5 -750
  191. package/src/runtime/rsc/CompositeComponent.tsx +29 -20
  192. package/src/runtime/rsc/RscNodeRenderer.tsx +9 -27
  193. package/src/runtime/rsc/client.tsx +12 -40
  194. package/src/runtime/rsc/flightSerialization.ts +158 -0
  195. package/src/runtime/rsc/payloadErrors.ts +73 -0
  196. package/src/runtime/rsc/payloadFetch.ts +97 -0
  197. package/src/runtime/rsc/payloadRouter.ts +29 -234
  198. package/src/runtime/rsc/payloadRoutes.ts +122 -0
  199. package/src/runtime/rsc/payloadStorage.ts +35 -0
  200. package/src/runtime/rsc/server.tsx +20 -29
  201. package/src/runtime/rsc/shared.ts +70 -0
  202. package/src/runtime/rsc/treeGetter.tsx +52 -0
  203. package/src/runtime/ssrManagedTags.ts +107 -0
  204. package/src/runtime/ssrPreload.ts +125 -0
  205. package/src/runtime/ssrTypes.ts +51 -0
  206. package/src/runtime/state.ts +4 -2
  207. package/src/runtime/submitAction.ts +194 -0
  208. package/src/runtime/types.ts +14 -51
  209. package/src/runtime/utils.tsx +72 -108
  210. package/src/types/react-server-dom-rspack.d.ts +56 -0
  211. package/tests/castRatchet.test.ts +85 -0
  212. package/tests/router/dataMutation.test.tsx +59 -0
  213. package/tests/router/fixtures/router-gen.golden.txt +72 -0
  214. package/tests/router/loaderBridge.test.ts +21 -0
  215. package/tests/router/routeTree.test.ts +46 -11
  216. package/tests/router/rsc.test.tsx +189 -0
  217. package/tests/router/ssrPreload.test.ts +30 -0
  218. package/tests/router/tanstackTypes.test.ts +254 -1
  219. package/dist/esm/runtime/pluginCore.mjs +0 -14
  220. package/dist/esm-node/runtime/pluginCore.mjs +0 -15
  221. package/src/runtime/pluginCore.ts +0 -56
@@ -0,0 +1,103 @@
1
+ import node_path from "node:path";
2
+ import { fs } from "@modern-js/utils";
3
+ import { collectCanonicalRoutesForEntry, generateTanstackRouterTypesSourceForEntry } from "./tanstackTypes.mjs";
4
+ const DEFAULT_GENERATED_DIR_NAME = 'modern-tanstack';
5
+ async function writeFileIfChanged(filePath, content) {
6
+ try {
7
+ const previous = await fs.pathExists(filePath) ? await fs.readFile(filePath, 'utf-8') : null;
8
+ if (previous === content) return;
9
+ } catch {}
10
+ await fs.outputFile(filePath, content, 'utf-8');
11
+ }
12
+ function createRegisterDtsContent(opts) {
13
+ const importStatements = opts.entries.map((entryName, index)=>`import type { router as router${index} } from './${entryName}/router.gen';`).join('\n');
14
+ const routerUnionType = opts.entries.map((_, index)=>`typeof router${index}`).join(' | ');
15
+ const canonicalEntries = Object.entries(opts.canonicalRoutes ?? {});
16
+ const canonicalRoutesAugmentation = canonicalEntries.length > 0 ? `
17
+ declare module '${opts.i18nRuntimeModule || '@modern-js/plugin-i18n/runtime'}' {
18
+ interface UltramodernCanonicalRoutes {
19
+ ${canonicalEntries.map(([routePath, paramsType])=>` '${routePath}': ${paramsType};`).join('\n')}
20
+ }
21
+ }
22
+ ` : '';
23
+ return `// This file is auto-generated by Modern.js. Do not edit manually.
24
+
25
+ ${importStatements}
26
+
27
+ declare module '${opts.runtimeModule}' {
28
+ interface Register {
29
+ router: ${routerUnionType};
30
+ }
31
+ }
32
+ ${canonicalRoutesAugmentation}`;
33
+ }
34
+ async function writeTanstackRegisterFile(opts) {
35
+ const { entries, generatedDirName = DEFAULT_GENERATED_DIR_NAME, runtimeModule = '@modern-js/plugin-tanstack/runtime', srcDirectory, canonicalRoutes, i18nRuntimeModule } = opts;
36
+ if (0 === entries.length) return;
37
+ const registerDtsPath = node_path.join(srcDirectory, generatedDirName, 'register.gen.d.ts');
38
+ await writeFileIfChanged(registerDtsPath, createRegisterDtsContent({
39
+ entries,
40
+ runtimeModule,
41
+ canonicalRoutes,
42
+ i18nRuntimeModule
43
+ }));
44
+ }
45
+ async function writeTanstackRouterTypesForEntries(opts) {
46
+ const { appContext, generatedDirName = DEFAULT_GENERATED_DIR_NAME, routesByEntry, i18nPluginInstalled = false } = opts;
47
+ const entryNames = Object.keys(routesByEntry);
48
+ await Promise.all(entryNames.map(async (entryName)=>{
49
+ const { routerGenTs } = await generateTanstackRouterTypesSourceForEntry({
50
+ appContext,
51
+ entryName,
52
+ generatedDirName,
53
+ routes: routesByEntry[entryName]
54
+ });
55
+ await writeFileIfChanged(node_path.join(appContext.srcDirectory, generatedDirName, entryName, 'router.gen.ts'), routerGenTs);
56
+ }));
57
+ const mainEntryName = appContext.entrypoints?.find((entrypoint)=>entrypoint.isMainEntry)?.entryName;
58
+ const registerEntries = entryNames.sort((a, b)=>{
59
+ if (mainEntryName && a === mainEntryName) return -1;
60
+ if (mainEntryName && b === mainEntryName) return 1;
61
+ return a.localeCompare(b);
62
+ });
63
+ let canonicalRoutes = null;
64
+ if (i18nPluginInstalled) for (const entryName of registerEntries){
65
+ const entryCanonicalRoutes = collectCanonicalRoutesForEntry(routesByEntry[entryName], {
66
+ localeParamHeuristic: true
67
+ });
68
+ if (entryCanonicalRoutes) canonicalRoutes = {
69
+ ...entryCanonicalRoutes,
70
+ ...canonicalRoutes ?? {}
71
+ };
72
+ }
73
+ await writeTanstackRegisterFile({
74
+ entries: registerEntries,
75
+ generatedDirName,
76
+ srcDirectory: appContext.srcDirectory,
77
+ canonicalRoutes
78
+ });
79
+ }
80
+ async function generateTanstackRouteArtifacts(opts) {
81
+ const [{ createRunOptions }, { cli }, utils] = await Promise.all([
82
+ import("@modern-js/app-tools/cli/run"),
83
+ import("@modern-js/plugin/cli"),
84
+ import("@modern-js/utils")
85
+ ]);
86
+ process.env.MODERN_ARGV = 'node modern build';
87
+ process.env.NODE_ENV = process.env.NODE_ENV || 'production';
88
+ const { findExists, CONFIG_FILE_EXTENSIONS } = utils;
89
+ const configFileBase = node_path.resolve(opts.appDirectory, 'modern.config');
90
+ const resolvedConfigFile = findExists(CONFIG_FILE_EXTENSIONS.map((extension)=>`${configFileBase}${extension}`));
91
+ 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.`);
92
+ const runOptions = await createRunOptions({
93
+ cwd: opts.appDirectory,
94
+ configFile: configFileBase,
95
+ version: opts.version || process.env.MODERN_JS_VERSION || '0.0.0-routes-generate',
96
+ internalPlugins: utils.INTERNAL_RUNTIME_PLUGINS
97
+ });
98
+ await cli.init({
99
+ ...runOptions,
100
+ command: 'build'
101
+ });
102
+ }
103
+ export { generateTanstackRouteArtifacts, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries };
@@ -1,7 +1,7 @@
1
1
  import node_path from "node:path";
2
- import { NESTED_ROUTE_SPEC_FILE, filterRoutesForServer, fs } from "@modern-js/utils";
2
+ import { NESTED_ROUTE_SPEC_FILE, filterRoutesForServer } from "@modern-js/utils";
3
+ import { generateTanstackRouteArtifacts, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries } from "./artifacts.mjs";
3
4
  import { createTanstackRsbuildRouteSplittingProfile, resolveTanstackRouteCodeSplittingEnabled } from "./routeSplitting.mjs";
4
- import { collectCanonicalRoutesForEntry, generateTanstackRouterTypesSourceForEntry } from "./tanstackTypes.mjs";
5
5
  import { __webpack_require__ } from "../rslib-runtime.mjs";
6
6
  import * as __rspack_external__modern_js_runtime_cli_401ee077 from "@modern-js/runtime/cli";
7
7
  __webpack_require__.add({
@@ -22,81 +22,6 @@ function getRuntimeRouterCli() {
22
22
  }
23
23
  throw new Error('@modern-js/plugin-tanstack requires @modern-js/runtime/cli router helper exports.');
24
24
  }
25
- async function writeFileIfChanged(filePath, content) {
26
- try {
27
- const previous = await fs.pathExists(filePath) ? await fs.readFile(filePath, 'utf-8') : null;
28
- if (previous === content) return;
29
- } catch {}
30
- await fs.outputFile(filePath, content, 'utf-8');
31
- }
32
- function createRegisterDtsContent(opts) {
33
- const importStatements = opts.entries.map((entryName, index)=>`import type { router as router${index} } from './${entryName}/router.gen';`).join('\n');
34
- const routerUnionType = opts.entries.map((_, index)=>`typeof router${index}`).join(' | ');
35
- const canonicalEntries = Object.entries(opts.canonicalRoutes ?? {});
36
- const canonicalRoutesAugmentation = canonicalEntries.length > 0 ? `
37
- declare module '${opts.i18nRuntimeModule || '@modern-js/plugin-i18n/runtime'}' {
38
- interface UltramodernCanonicalRoutes {
39
- ${canonicalEntries.map(([routePath, paramsType])=>` '${routePath}': ${paramsType};`).join('\n')}
40
- }
41
- }
42
- ` : '';
43
- return `// This file is auto-generated by Modern.js. Do not edit manually.
44
-
45
- ${importStatements}
46
-
47
- declare module '${opts.runtimeModule}' {
48
- interface Register {
49
- router: ${routerUnionType};
50
- }
51
- }
52
- ${canonicalRoutesAugmentation}`;
53
- }
54
- async function writeTanstackRegisterFile(opts) {
55
- const { entries, generatedDirName = DEFAULT_GENERATED_DIR_NAME, runtimeModule = '@modern-js/plugin-tanstack/runtime', srcDirectory, canonicalRoutes, i18nRuntimeModule } = opts;
56
- if (0 === entries.length) return;
57
- const registerDtsPath = node_path.join(srcDirectory, generatedDirName, 'register.gen.d.ts');
58
- await writeFileIfChanged(registerDtsPath, createRegisterDtsContent({
59
- entries,
60
- runtimeModule,
61
- canonicalRoutes,
62
- i18nRuntimeModule
63
- }));
64
- }
65
- async function writeTanstackRouterTypesForEntries(opts) {
66
- const { appContext, generatedDirName = DEFAULT_GENERATED_DIR_NAME, routesByEntry, i18nPluginInstalled = false } = opts;
67
- const entryNames = Object.keys(routesByEntry);
68
- await Promise.all(entryNames.map(async (entryName)=>{
69
- const { routerGenTs } = await generateTanstackRouterTypesSourceForEntry({
70
- appContext,
71
- entryName,
72
- generatedDirName,
73
- routes: routesByEntry[entryName]
74
- });
75
- await writeFileIfChanged(node_path.join(appContext.srcDirectory, generatedDirName, entryName, 'router.gen.ts'), routerGenTs);
76
- }));
77
- const mainEntryName = appContext.entrypoints?.find((entrypoint)=>entrypoint.isMainEntry)?.entryName;
78
- const registerEntries = entryNames.sort((a, b)=>{
79
- if (mainEntryName && a === mainEntryName) return -1;
80
- if (mainEntryName && b === mainEntryName) return 1;
81
- return a.localeCompare(b);
82
- });
83
- let canonicalRoutes = null;
84
- if (i18nPluginInstalled) for (const entryName of registerEntries){
85
- const entryCanonicalRoutes = collectCanonicalRoutesForEntry(routesByEntry[entryName], {
86
- localeParamHeuristic: true
87
- });
88
- if (entryCanonicalRoutes) canonicalRoutes = {
89
- ...entryCanonicalRoutes,
90
- ...canonicalRoutes ?? {}
91
- };
92
- }
93
- await writeTanstackRegisterFile({
94
- entries: registerEntries,
95
- generatedDirName,
96
- srcDirectory: appContext.srcDirectory,
97
- canonicalRoutes
98
- });
99
- }
100
25
  function tanstackRouterPlugin(options = {}) {
101
26
  const routesDir = options.routesDir || DEFAULT_ROUTES_DIR;
102
27
  const generatedDirName = options.generatedDirName || DEFAULT_GENERATED_DIR_NAME;
@@ -238,29 +163,7 @@ function tanstackRouterPlugin(options = {}) {
238
163
  }
239
164
  };
240
165
  }
241
- async function generateTanstackRouteArtifacts(opts) {
242
- const [{ createRunOptions }, { cli }, utils] = await Promise.all([
243
- import("@modern-js/app-tools/cli/run"),
244
- import("@modern-js/plugin/cli"),
245
- import("@modern-js/utils")
246
- ]);
247
- process.env.MODERN_ARGV = 'node modern build';
248
- process.env.NODE_ENV = process.env.NODE_ENV || 'production';
249
- const { findExists, CONFIG_FILE_EXTENSIONS } = utils;
250
- const configFileBase = node_path.resolve(opts.appDirectory, 'modern.config');
251
- const resolvedConfigFile = findExists(CONFIG_FILE_EXTENSIONS.map((extension)=>`${configFileBase}${extension}`));
252
- 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.`);
253
- const runOptions = await createRunOptions({
254
- cwd: opts.appDirectory,
255
- configFile: configFileBase,
256
- version: opts.version || process.env.MODERN_JS_VERSION || '0.0.0-routes-generate',
257
- internalPlugins: utils.INTERNAL_RUNTIME_PLUGINS
258
- });
259
- await cli.init({
260
- ...runOptions,
261
- command: 'build'
262
- });
263
- }
264
166
  const src_cli = tanstackRouterPlugin;
167
+ export { collectCanonicalRoutesForEntry, generateTanstackRouterTypesSourceForEntry } from "./tanstackTypes.mjs";
265
168
  export default src_cli;
266
- export { collectCanonicalRoutesForEntry, createTanstackRsbuildRouteSplittingProfile, generateTanstackRouteArtifacts, generateTanstackRouterTypesSourceForEntry, resolveTanstackRouteCodeSplittingEnabled, tanstackRouterPlugin, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries };
169
+ export { createTanstackRsbuildRouteSplittingProfile, generateTanstackRouteArtifacts, resolveTanstackRouteCodeSplittingEnabled, tanstackRouterPlugin, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries };
@@ -0,0 +1,75 @@
1
+ import { toTanstackPath } from "./shared.mjs";
2
+ const LOCALE_PARAM_SEGMENTS = new Set([
3
+ ':lang',
4
+ ':locale',
5
+ ':language',
6
+ '$lang',
7
+ '$locale',
8
+ '$language'
9
+ ]);
10
+ function paramsTypeForCanonicalPath(canonicalPath) {
11
+ const fields = [];
12
+ for (const segment of canonicalPath.split('/'))if (segment) {
13
+ if ('*' === segment || '$' === segment) {
14
+ fields.push("'_splat'?: string");
15
+ continue;
16
+ }
17
+ if (segment.startsWith('{-$') && segment.endsWith('}')) {
18
+ fields.push(`${JSON.stringify(segment.slice(3, -1))}?: string`);
19
+ continue;
20
+ }
21
+ if (segment.startsWith('$')) {
22
+ fields.push(`${JSON.stringify(segment.slice(1))}: string`);
23
+ continue;
24
+ }
25
+ if (segment.startsWith(':')) {
26
+ const optional = segment.endsWith('?');
27
+ const name = segment.slice(1, optional ? void 0 : segment.length);
28
+ fields.push(`${JSON.stringify(optional ? name.slice(0, -1) : name)}${optional ? '?' : ''}: string`);
29
+ }
30
+ }
31
+ return fields.length > 0 ? `{ ${fields.join('; ')} }` : 'Record<string, never>';
32
+ }
33
+ function collectCanonicalRoutesForEntry(routes, options = {}) {
34
+ const { localeParamHeuristic = true } = options;
35
+ const canonicalParams = new Map();
36
+ let hasI18nSurface = false;
37
+ const normalizeJoined = (joined)=>{
38
+ const collapsed = joined.replace(/\/+/g, '/');
39
+ const withLeading = collapsed.startsWith('/') ? collapsed : `/${collapsed}`;
40
+ return withLeading.length > 1 ? withLeading.replace(/\/+$/, '') : withLeading;
41
+ };
42
+ const record = (canonicalPath)=>{
43
+ const normalized = normalizeJoined(canonicalPath || '/');
44
+ const key = toTanstackPath(normalized);
45
+ if (!canonicalParams.has(key)) canonicalParams.set(key, paramsTypeForCanonicalPath(normalized));
46
+ };
47
+ const visit = (route, parentPath)=>{
48
+ let currentPath = parentPath;
49
+ if ('string' == typeof route.modernCanonicalPath) {
50
+ hasI18nSurface = true;
51
+ currentPath = normalizeJoined(route.modernCanonicalPath);
52
+ } else if ('string' == typeof route.path && route.path.length > 0) {
53
+ const segments = route.path.replace(/\[(.+?)\]/g, ':$1').split('/').filter(Boolean);
54
+ if (localeParamHeuristic && '' === parentPath && LOCALE_PARAM_SEGMENTS.has(segments[0])) {
55
+ hasI18nSurface = true;
56
+ segments.shift();
57
+ }
58
+ currentPath = segments.length ? normalizeJoined(`${parentPath}/${segments.join('/')}`) : parentPath;
59
+ }
60
+ const children = route.children;
61
+ if (children && children.length > 0) {
62
+ for (const child of children)visit(child, currentPath);
63
+ return;
64
+ }
65
+ record(currentPath || '/');
66
+ };
67
+ const rootModern = routes.find((route)=>route.isRoot);
68
+ const topLevel = rootModern ? rootModern.children ?? [] : routes;
69
+ for (const route of topLevel)visit(route, '');
70
+ if (!hasI18nSurface || 0 === canonicalParams.size) return null;
71
+ return Object.fromEntries([
72
+ ...canonicalParams.entries()
73
+ ].sort(([a], [b])=>a.localeCompare(b)));
74
+ }
75
+ export { collectCanonicalRoutesForEntry };
@@ -0,0 +1,68 @@
1
+ import { getPathWithoutExt } from "@modern-js/runtime/cli";
2
+ import { findExists, formatImportPath, slash } from "@modern-js/utils";
3
+ const JS_OR_TS_EXTS = [
4
+ '.js',
5
+ '.jsx',
6
+ '.ts',
7
+ '.tsx',
8
+ '.mjs',
9
+ '.mts',
10
+ '.cjs',
11
+ '.cts'
12
+ ];
13
+ function toTanstackPath(pathname) {
14
+ return pathname.split('/').map((segment)=>{
15
+ if (!segment) return segment;
16
+ if ('*' === segment) return '$';
17
+ if (segment.startsWith(':')) {
18
+ const name = segment.slice(1);
19
+ if (name.endsWith('?')) return `{-$${name.slice(0, -1)}}`;
20
+ return `$${name}`;
21
+ }
22
+ return segment;
23
+ }).join('/');
24
+ }
25
+ async function resolveFileNoExt(inputNoExtPath) {
26
+ const file = findExists(JS_OR_TS_EXTS.map((ext)=>`${inputNoExtPath}${ext}`));
27
+ return file ? getPathWithoutExt(file) : null;
28
+ }
29
+ function quote(str) {
30
+ return JSON.stringify(str);
31
+ }
32
+ function normalizeRelativeImport(p) {
33
+ const normalized = formatImportPath(slash(p));
34
+ if (normalized.startsWith('.')) return normalized;
35
+ return `./${normalized}`;
36
+ }
37
+ function pickModernLoaderModule(route) {
38
+ const loaderPath = route.data || route.loader;
39
+ if (!loaderPath || 'string' != typeof loaderPath) return null;
40
+ const inline = Boolean(route.data);
41
+ return {
42
+ loaderPath,
43
+ inline
44
+ };
45
+ }
46
+ function pickRouteSearchContractModules(route) {
47
+ const validateSearchPath = route.validateSearch;
48
+ const loaderDepsPath = route.loaderDeps;
49
+ return {
50
+ validateSearchPath: 'string' == typeof validateSearchPath ? validateSearchPath : null,
51
+ loaderDepsPath: 'string' == typeof loaderDepsPath ? loaderDepsPath : null
52
+ };
53
+ }
54
+ function isPathlessLayout(route) {
55
+ return 'nested' === route.type && 'boolean' != typeof route.index && void 0 === route.path;
56
+ }
57
+ function isIndexRoute(route) {
58
+ return 'nested' === route.type && Boolean(route.index);
59
+ }
60
+ function createRouteStaticDataSnippet(opts) {
61
+ const staticDataLines = [];
62
+ if (opts.modernRouteId) staticDataLines.push(`modernRouteId: ${quote(opts.modernRouteId)},`);
63
+ if (opts.loaderName) staticDataLines.push(`modernRouteLoader: ${opts.loaderName},`);
64
+ if (opts.actionName) staticDataLines.push(`modernRouteAction: ${opts.actionName},`);
65
+ if (!staticDataLines.length) return null;
66
+ return `staticData: createRouteStaticData({\n ${staticDataLines.join('\n ')}\n }),`;
67
+ }
68
+ export { createRouteStaticDataSnippet, isIndexRoute, isPathlessLayout, normalizeRelativeImport, pickModernLoaderModule, pickRouteSearchContractModules, quote, resolveFileNoExt, toTanstackPath };
@@ -0,0 +1,203 @@
1
+ import { makeLegalIdentifier } from "@modern-js/runtime/cli";
2
+ import path from "path";
3
+ import { createRouteStaticDataSnippet, isIndexRoute, isPathlessLayout, normalizeRelativeImport, pickModernLoaderModule, pickRouteSearchContractModules, quote, resolveFileNoExt, toTanstackPath } from "./shared.mjs";
4
+ async function generateTanstackRouterTypesSourceForEntry(opts) {
5
+ const { appContext, entryName, generatedDirName = 'modern-tanstack', routes } = opts;
6
+ const outDir = path.join(appContext.srcDirectory, generatedDirName, entryName);
7
+ const rootModern = routes.find((r)=>r && 'nested' === r.type && r.isRoot);
8
+ const topLevel = rootModern ? rootModern.children || [] : routes;
9
+ const imports = [];
10
+ const statements = [];
11
+ const loaderImportMap = new Map();
12
+ const componentImportMap = new Map();
13
+ const searchContractImportMap = new Map();
14
+ const usedRouteVarNames = new Set();
15
+ let loaderIndex = 0;
16
+ let componentIndex = 0;
17
+ let validateSearchIndex = 0;
18
+ let loaderDepsIndex = 0;
19
+ let routeIndex = 0;
20
+ const getImportNameForComponent = (componentPath)=>{
21
+ if ('string' != typeof componentPath || 0 === componentPath.length) return Promise.resolve(null);
22
+ let pendingImportName = componentImportMap.get(componentPath);
23
+ if (!pendingImportName) {
24
+ pendingImportName = (async ()=>{
25
+ const resolvedNoExt = await resolveRouteModuleNoExt(componentPath);
26
+ if (!resolvedNoExt) return null;
27
+ const relImport = normalizeRelativeImport(path.relative(outDir, resolvedNoExt));
28
+ const componentName = `component_${componentIndex++}`;
29
+ imports.push(`import ${componentName} from ${quote(relImport)};`);
30
+ return componentName;
31
+ })();
32
+ componentImportMap.set(componentPath, pendingImportName);
33
+ }
34
+ return pendingImportName;
35
+ };
36
+ const resolveRouteModuleNoExt = async (aliasedNoExtPath)=>{
37
+ const prefix = `${appContext.internalSrcAlias}/`;
38
+ let absNoExt;
39
+ if (aliasedNoExtPath.startsWith(prefix)) {
40
+ const rel = aliasedNoExtPath.slice(prefix.length);
41
+ absNoExt = path.join(appContext.srcDirectory, rel);
42
+ } else absNoExt = path.isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : path.join(appContext.srcDirectory, aliasedNoExtPath);
43
+ return resolveFileNoExt(absNoExt);
44
+ };
45
+ const getImportNamesForLoader = async (aliasedNoExtPath, inline, hasAction)=>{
46
+ const key = `${inline ? 'inline' : 'default'}:${hasAction ? 'action' : 'loader'}:${aliasedNoExtPath}`;
47
+ const existing = loaderImportMap.get(key);
48
+ if (existing) return {
49
+ loaderName: existing,
50
+ actionName: hasAction ? existing.replace(/^loader_/, 'action_') : null
51
+ };
52
+ const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
53
+ if (!resolvedNoExt) return null;
54
+ const relImport = normalizeRelativeImport(path.relative(outDir, resolvedNoExt));
55
+ const importName = `loader_${loaderIndex++}`;
56
+ const actionName = hasAction ? importName.replace(/^loader_/, 'action_') : null;
57
+ if (inline) {
58
+ const specifiers = [
59
+ `loader as ${importName}`
60
+ ];
61
+ if (actionName) specifiers.push(`action as ${actionName}`);
62
+ imports.push(`import { ${specifiers.join(', ')} } from ${quote(relImport)};`);
63
+ } else imports.push(`import ${importName} from ${quote(relImport)};`);
64
+ loaderImportMap.set(key, importName);
65
+ return {
66
+ loaderName: importName,
67
+ actionName
68
+ };
69
+ };
70
+ const getImportNameForSearchContract = async (aliasedNoExtPath, exportName)=>{
71
+ const key = `${exportName}:${aliasedNoExtPath}`;
72
+ const existing = searchContractImportMap.get(key);
73
+ if (existing) return existing;
74
+ const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
75
+ if (!resolvedNoExt) return null;
76
+ const relImport = normalizeRelativeImport(path.relative(outDir, resolvedNoExt));
77
+ const importName = 'validateSearch' === exportName ? `validateSearch_${validateSearchIndex++}` : `loaderDeps_${loaderDepsIndex++}`;
78
+ imports.push(`import { ${exportName} as ${importName} } from ${quote(relImport)};`);
79
+ searchContractImportMap.set(key, importName);
80
+ return importName;
81
+ };
82
+ const reserveRouteVarName = (preferred)=>{
83
+ let candidate = preferred;
84
+ let suffix = 1;
85
+ while(usedRouteVarNames.has(candidate))candidate = `${preferred}_${suffix++}`;
86
+ usedRouteVarNames.add(candidate);
87
+ return candidate;
88
+ };
89
+ const createRouteVarName = (route)=>{
90
+ const id = route.id;
91
+ const base = id ? makeLegalIdentifier(id) : `r_${routeIndex++}`;
92
+ return reserveRouteVarName(`route_${base}`);
93
+ };
94
+ const buildRoute = async (opts)=>{
95
+ const { parentVar, route } = opts;
96
+ const varName = createRouteVarName(route);
97
+ const loaderInfo = pickModernLoaderModule(route);
98
+ const routeAction = route.action;
99
+ const loaderImports = loaderInfo ? await getImportNamesForLoader(loaderInfo.loaderPath, loaderInfo.inline, Boolean(loaderInfo.inline && routeAction === loaderInfo.loaderPath)) : null;
100
+ const loaderName = loaderImports?.loaderName || null;
101
+ const actionName = loaderImports?.actionName || null;
102
+ const searchContractInfo = pickRouteSearchContractModules(route);
103
+ const validateSearchName = searchContractInfo.validateSearchPath ? await getImportNameForSearchContract(searchContractInfo.validateSearchPath, 'validateSearch') : null;
104
+ const loaderDepsName = searchContractInfo.loaderDepsPath ? await getImportNameForSearchContract(searchContractInfo.loaderDepsPath, 'loaderDeps') : null;
105
+ const rawPath = route.path;
106
+ const hasSplat = 'string' == typeof rawPath && rawPath.includes('*');
107
+ const routeOpts = [
108
+ `getParentRoute: () => ${parentVar},`
109
+ ];
110
+ const componentName = await getImportNameForComponent(route._component);
111
+ if (componentName) routeOpts.push(`component: ${componentName},`);
112
+ if (isPathlessLayout(route)) {
113
+ const id = route.id;
114
+ routeOpts.push(`id: ${quote(id || 'pathless')},`);
115
+ } else {
116
+ const p = isIndexRoute(route) ? '/' : toTanstackPath(rawPath || '');
117
+ routeOpts.push(`path: ${quote(p)},`);
118
+ }
119
+ if (loaderName) routeOpts.push(`loader: modernLoaderToTanstack({ hasSplat: ${hasSplat} }, ${loaderName}),`);
120
+ if (validateSearchName) routeOpts.push(`validateSearch: ${validateSearchName},`);
121
+ if (loaderDepsName) routeOpts.push(`loaderDeps: ${loaderDepsName},`);
122
+ const staticDataSnippet = createRouteStaticDataSnippet({
123
+ modernRouteId: route.id,
124
+ loaderName,
125
+ actionName
126
+ });
127
+ if (staticDataSnippet) routeOpts.push(staticDataSnippet);
128
+ const children = route.children;
129
+ const hasChildren = Boolean(children && children.length > 0);
130
+ const routeCtorVarName = hasChildren ? reserveRouteVarName(`${varName}__base`) : varName;
131
+ statements.push(`const ${routeCtorVarName} = createRoute({\n ${routeOpts.join('\n ')}\n});`);
132
+ if (children && children.length > 0) {
133
+ const childVars = [];
134
+ for (const child of children)childVars.push(await buildRoute({
135
+ parentVar: routeCtorVarName,
136
+ route: child
137
+ }));
138
+ statements.push(`const ${varName} = ${routeCtorVarName}.addChildren([${childVars.join(', ')}]);`);
139
+ }
140
+ return varName;
141
+ };
142
+ const rootLoaderInfo = rootModern ? pickModernLoaderModule(rootModern) : null;
143
+ const rootAction = rootModern?.action;
144
+ const rootLoaderImports = rootLoaderInfo?.loaderPath ? await getImportNamesForLoader(rootLoaderInfo.loaderPath, rootLoaderInfo.inline, Boolean(rootLoaderInfo.inline && rootAction === rootLoaderInfo.loaderPath)) : null;
145
+ const rootLoaderName = rootLoaderImports?.loaderName || null;
146
+ const rootActionName = rootLoaderImports?.actionName || null;
147
+ const rootSearchContractInfo = rootModern ? pickRouteSearchContractModules(rootModern) : null;
148
+ const rootValidateSearchName = rootSearchContractInfo?.validateSearchPath ? await getImportNameForSearchContract(rootSearchContractInfo.validateSearchPath, 'validateSearch') : null;
149
+ const rootLoaderDepsName = rootSearchContractInfo?.loaderDepsPath ? await getImportNameForSearchContract(rootSearchContractInfo.loaderDepsPath, 'loaderDeps') : null;
150
+ const topLevelVars = [];
151
+ for (const route of topLevel)topLevelVars.push(await buildRoute({
152
+ parentVar: 'rootRoute',
153
+ route
154
+ }));
155
+ const rootOpts = [];
156
+ const rootComponentName = await getImportNameForComponent(rootModern?._component);
157
+ if (rootComponentName) rootOpts.push(`component: ${rootComponentName},`);
158
+ if (rootLoaderName) rootOpts.push(`loader: modernLoaderToTanstack({ hasSplat: false }, ${rootLoaderName}),`);
159
+ if (rootValidateSearchName) rootOpts.push(`validateSearch: ${rootValidateSearchName},`);
160
+ if (rootLoaderDepsName) rootOpts.push(`loaderDeps: ${rootLoaderDepsName},`);
161
+ const routerGenTs = `/* eslint-disable */
162
+ // This file is auto-generated by Modern.js. Do not edit manually.
163
+
164
+ import {
165
+ createMemoryHistory,
166
+ createRootRouteWithContext,
167
+ createRoute,
168
+ createRouter,
169
+ createRouteStaticData,
170
+ type ModernRouterContext,
171
+ modernLoaderToTanstack,
172
+ modernTanstackRouterFastDefaults,
173
+ } from '@modern-js/plugin-tanstack/runtime';
174
+
175
+ ${imports.join('\n')}
176
+
177
+ export const rootRoute = createRootRouteWithContext<ModernRouterContext>()({
178
+ ${rootOpts.join('\n ')}
179
+ ${createRouteStaticDataSnippet({
180
+ modernRouteId: rootModern?.id,
181
+ loaderName: rootLoaderName,
182
+ actionName: rootActionName
183
+ }) || ''}
184
+ });
185
+
186
+ ${statements.join('\n\n')}
187
+
188
+ export const routeTree = rootRoute.addChildren([${topLevelVars.join(', ')}]);
189
+
190
+ export const router = createRouter({
191
+ ...modernTanstackRouterFastDefaults,
192
+ routeTree,
193
+ history: createMemoryHistory({
194
+ initialEntries: ['/'],
195
+ }),
196
+ context: {} as ModernRouterContext,
197
+ });
198
+ `;
199
+ return {
200
+ routerGenTs
201
+ };
202
+ }
203
+ export { generateTanstackRouterTypesSourceForEntry };