@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.0

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 (183) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/cli/index.js +268 -0
  3. package/dist/cjs/cli/tanstackTypes.js +388 -0
  4. package/dist/cjs/cli.js +65 -0
  5. package/dist/cjs/runtime/DefaultNotFound.js +47 -0
  6. package/dist/cjs/runtime/basepathRewrite.js +62 -0
  7. package/dist/cjs/runtime/dataMutation.js +345 -0
  8. package/dist/cjs/runtime/hooks.js +57 -0
  9. package/dist/cjs/runtime/index.js +114 -0
  10. package/dist/cjs/runtime/lifecycle.js +125 -0
  11. package/dist/cjs/runtime/plugin.js +250 -0
  12. package/dist/cjs/runtime/plugin.node.js +304 -0
  13. package/dist/cjs/runtime/prefetchLink.js +55 -0
  14. package/dist/cjs/runtime/routeTree.js +492 -0
  15. package/dist/cjs/runtime/rsc/ClientSlot.js +53 -0
  16. package/dist/cjs/runtime/rsc/CompositeComponent.js +75 -0
  17. package/dist/cjs/runtime/rsc/ReplayableStream.js +141 -0
  18. package/dist/cjs/runtime/rsc/RscNodeRenderer.js +65 -0
  19. package/dist/cjs/runtime/rsc/SlotContext.js +54 -0
  20. package/dist/cjs/runtime/rsc/client.js +93 -0
  21. package/dist/cjs/runtime/rsc/createRscProxy.js +141 -0
  22. package/dist/cjs/runtime/rsc/index.js +42 -0
  23. package/dist/cjs/runtime/rsc/payloadRouter.js +211 -0
  24. package/dist/cjs/runtime/rsc/server.js +246 -0
  25. package/dist/cjs/runtime/rsc/slotUsageSanitizer.js +65 -0
  26. package/dist/cjs/runtime/rsc/symbols.js +72 -0
  27. package/dist/cjs/runtime/types.js +18 -0
  28. package/dist/cjs/runtime/utils.js +142 -0
  29. package/dist/cjs/runtime.js +58 -0
  30. package/dist/esm/cli/index.mjs +201 -0
  31. package/dist/esm/cli/tanstackTypes.mjs +341 -0
  32. package/dist/esm/cli.mjs +2 -0
  33. package/dist/esm/rslib-runtime.mjs +18 -0
  34. package/dist/esm/runtime/DefaultNotFound.mjs +13 -0
  35. package/dist/esm/runtime/basepathRewrite.mjs +28 -0
  36. package/dist/esm/runtime/dataMutation.mjs +305 -0
  37. package/dist/esm/runtime/hooks.mjs +8 -0
  38. package/dist/esm/runtime/index.mjs +6 -0
  39. package/dist/esm/runtime/lifecycle.mjs +82 -0
  40. package/dist/esm/runtime/plugin.mjs +214 -0
  41. package/dist/esm/runtime/plugin.node.mjs +268 -0
  42. package/dist/esm/runtime/prefetchLink.mjs +18 -0
  43. package/dist/esm/runtime/routeTree.mjs +452 -0
  44. package/dist/esm/runtime/rsc/ClientSlot.mjs +19 -0
  45. package/dist/esm/runtime/rsc/CompositeComponent.mjs +41 -0
  46. package/dist/esm/runtime/rsc/ReplayableStream.mjs +104 -0
  47. package/dist/esm/runtime/rsc/RscNodeRenderer.mjs +31 -0
  48. package/dist/esm/runtime/rsc/SlotContext.mjs +17 -0
  49. package/dist/esm/runtime/rsc/client.mjs +53 -0
  50. package/dist/esm/runtime/rsc/createRscProxy.mjs +107 -0
  51. package/dist/esm/runtime/rsc/index.mjs +1 -0
  52. package/dist/esm/runtime/rsc/payloadRouter.mjs +162 -0
  53. package/dist/esm/runtime/rsc/server.mjs +200 -0
  54. package/dist/esm/runtime/rsc/slotUsageSanitizer.mjs +31 -0
  55. package/dist/esm/runtime/rsc/symbols.mjs +17 -0
  56. package/dist/esm/runtime/types.mjs +0 -0
  57. package/dist/esm/runtime/utils.mjs +89 -0
  58. package/dist/esm/runtime.mjs +1 -0
  59. package/dist/esm-node/cli/index.mjs +205 -0
  60. package/dist/esm-node/cli/tanstackTypes.mjs +342 -0
  61. package/dist/esm-node/cli.mjs +3 -0
  62. package/dist/esm-node/rslib-runtime.mjs +19 -0
  63. package/dist/esm-node/runtime/DefaultNotFound.mjs +14 -0
  64. package/dist/esm-node/runtime/basepathRewrite.mjs +29 -0
  65. package/dist/esm-node/runtime/dataMutation.mjs +306 -0
  66. package/dist/esm-node/runtime/hooks.mjs +9 -0
  67. package/dist/esm-node/runtime/index.mjs +7 -0
  68. package/dist/esm-node/runtime/lifecycle.mjs +83 -0
  69. package/dist/esm-node/runtime/plugin.mjs +215 -0
  70. package/dist/esm-node/runtime/plugin.node.mjs +269 -0
  71. package/dist/esm-node/runtime/prefetchLink.mjs +19 -0
  72. package/dist/esm-node/runtime/routeTree.mjs +453 -0
  73. package/dist/esm-node/runtime/rsc/ClientSlot.mjs +20 -0
  74. package/dist/esm-node/runtime/rsc/CompositeComponent.mjs +42 -0
  75. package/dist/esm-node/runtime/rsc/ReplayableStream.mjs +105 -0
  76. package/dist/esm-node/runtime/rsc/RscNodeRenderer.mjs +32 -0
  77. package/dist/esm-node/runtime/rsc/SlotContext.mjs +18 -0
  78. package/dist/esm-node/runtime/rsc/client.mjs +54 -0
  79. package/dist/esm-node/runtime/rsc/createRscProxy.mjs +108 -0
  80. package/dist/esm-node/runtime/rsc/index.mjs +2 -0
  81. package/dist/esm-node/runtime/rsc/payloadRouter.mjs +163 -0
  82. package/dist/esm-node/runtime/rsc/server.mjs +201 -0
  83. package/dist/esm-node/runtime/rsc/slotUsageSanitizer.mjs +32 -0
  84. package/dist/esm-node/runtime/rsc/symbols.mjs +18 -0
  85. package/dist/esm-node/runtime/types.mjs +1 -0
  86. package/dist/esm-node/runtime/utils.mjs +90 -0
  87. package/dist/esm-node/runtime.mjs +2 -0
  88. package/dist/types/cli/index.d.ts +20 -0
  89. package/dist/types/cli/tanstackTypes.d.ts +11 -0
  90. package/dist/types/cli.d.ts +2 -0
  91. package/dist/types/runtime/DefaultNotFound.d.ts +2 -0
  92. package/dist/types/runtime/basepathRewrite.d.ts +8 -0
  93. package/dist/types/runtime/dataMutation.d.ts +29 -0
  94. package/dist/types/runtime/hooks.d.ts +18 -0
  95. package/dist/types/runtime/index.d.ts +9 -0
  96. package/dist/types/runtime/lifecycle.d.ts +22 -0
  97. package/dist/types/runtime/plugin.d.ts +17 -0
  98. package/dist/types/runtime/plugin.node.d.ts +17 -0
  99. package/dist/types/runtime/prefetchLink.d.ts +11 -0
  100. package/dist/types/runtime/routeTree.d.ts +11 -0
  101. package/dist/types/runtime/rsc/ClientSlot.d.ts +5 -0
  102. package/dist/types/runtime/rsc/CompositeComponent.d.ts +3 -0
  103. package/dist/types/runtime/rsc/ReplayableStream.d.ts +24 -0
  104. package/dist/types/runtime/rsc/RscNodeRenderer.d.ts +5 -0
  105. package/dist/types/runtime/rsc/SlotContext.d.ts +11 -0
  106. package/dist/types/runtime/rsc/client.d.ts +11 -0
  107. package/dist/types/runtime/rsc/createRscProxy.d.ts +7 -0
  108. package/dist/types/runtime/rsc/index.d.ts +2 -0
  109. package/dist/types/runtime/rsc/payloadRouter.d.ts +24 -0
  110. package/dist/types/runtime/rsc/server.d.ts +14 -0
  111. package/dist/types/runtime/rsc/slotUsageSanitizer.d.ts +2 -0
  112. package/dist/types/runtime/rsc/symbols.d.ts +46 -0
  113. package/dist/types/runtime/types.d.ts +68 -0
  114. package/dist/types/runtime/utils.d.ts +36 -0
  115. package/dist/types/runtime.d.ts +1 -0
  116. package/dist/types-direct/cli/index.d.ts +20 -0
  117. package/dist/types-direct/cli/tanstackTypes.d.ts +11 -0
  118. package/dist/types-direct/cli.d.ts +2 -0
  119. package/dist/types-direct/runtime/DefaultNotFound.d.ts +2 -0
  120. package/dist/types-direct/runtime/basepathRewrite.d.ts +8 -0
  121. package/dist/types-direct/runtime/dataMutation.d.ts +29 -0
  122. package/dist/types-direct/runtime/hooks.d.ts +18 -0
  123. package/dist/types-direct/runtime/index.d.ts +9 -0
  124. package/dist/types-direct/runtime/lifecycle.d.ts +22 -0
  125. package/dist/types-direct/runtime/plugin.d.ts +17 -0
  126. package/dist/types-direct/runtime/plugin.node.d.ts +17 -0
  127. package/dist/types-direct/runtime/prefetchLink.d.ts +11 -0
  128. package/dist/types-direct/runtime/routeTree.d.ts +11 -0
  129. package/dist/types-direct/runtime/rsc/ClientSlot.d.ts +5 -0
  130. package/dist/types-direct/runtime/rsc/CompositeComponent.d.ts +3 -0
  131. package/dist/types-direct/runtime/rsc/ReplayableStream.d.ts +24 -0
  132. package/dist/types-direct/runtime/rsc/RscNodeRenderer.d.ts +5 -0
  133. package/dist/types-direct/runtime/rsc/SlotContext.d.ts +11 -0
  134. package/dist/types-direct/runtime/rsc/client.d.ts +11 -0
  135. package/dist/types-direct/runtime/rsc/createRscProxy.d.ts +7 -0
  136. package/dist/types-direct/runtime/rsc/index.d.ts +2 -0
  137. package/dist/types-direct/runtime/rsc/payloadRouter.d.ts +24 -0
  138. package/dist/types-direct/runtime/rsc/server.d.ts +14 -0
  139. package/dist/types-direct/runtime/rsc/slotUsageSanitizer.d.ts +2 -0
  140. package/dist/types-direct/runtime/rsc/symbols.d.ts +46 -0
  141. package/dist/types-direct/runtime/types.d.ts +68 -0
  142. package/dist/types-direct/runtime/utils.d.ts +36 -0
  143. package/dist/types-direct/runtime.d.ts +1 -0
  144. package/package.json +126 -0
  145. package/rslib.config.mts +4 -0
  146. package/rstest.config.mts +43 -0
  147. package/src/cli/index.ts +388 -0
  148. package/src/cli/tanstackTypes.ts +503 -0
  149. package/src/cli.ts +2 -0
  150. package/src/runtime/DefaultNotFound.tsx +15 -0
  151. package/src/runtime/basepathRewrite.ts +59 -0
  152. package/src/runtime/dataMutation.tsx +517 -0
  153. package/src/runtime/hooks.ts +34 -0
  154. package/src/runtime/index.tsx +30 -0
  155. package/src/runtime/lifecycle.ts +150 -0
  156. package/src/runtime/plugin.node.tsx +534 -0
  157. package/src/runtime/plugin.tsx +395 -0
  158. package/src/runtime/prefetchLink.tsx +87 -0
  159. package/src/runtime/routeTree.ts +942 -0
  160. package/src/runtime/rsc/ClientSlot.tsx +25 -0
  161. package/src/runtime/rsc/CompositeComponent.tsx +65 -0
  162. package/src/runtime/rsc/ReplayableStream.ts +155 -0
  163. package/src/runtime/rsc/RscNodeRenderer.tsx +45 -0
  164. package/src/runtime/rsc/SlotContext.tsx +31 -0
  165. package/src/runtime/rsc/client.tsx +90 -0
  166. package/src/runtime/rsc/createRscProxy.tsx +189 -0
  167. package/src/runtime/rsc/index.ts +10 -0
  168. package/src/runtime/rsc/payloadRouter.ts +318 -0
  169. package/src/runtime/rsc/server.tsx +303 -0
  170. package/src/runtime/rsc/slotUsageSanitizer.ts +76 -0
  171. package/src/runtime/rsc/symbols.ts +106 -0
  172. package/src/runtime/ssr-shim.d.ts +12 -0
  173. package/src/runtime/types.ts +83 -0
  174. package/src/runtime/utils.tsx +161 -0
  175. package/src/runtime.ts +1 -0
  176. package/tests/router/cli.test.ts +386 -0
  177. package/tests/router/dataMutation.test.tsx +396 -0
  178. package/tests/router/prefetchLink.test.tsx +43 -0
  179. package/tests/router/routeTree.test.ts +502 -0
  180. package/tests/router/rsc.test.tsx +256 -0
  181. package/tests/router/tanstackTypes.test.ts +62 -0
  182. package/tsconfig.json +12 -0
  183. package/tsconfig.tsgo.json +6 -0
@@ -0,0 +1,386 @@
1
+ import { mkdir, mkdtemp, readFile, rm } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import path from 'node:path';
4
+ import type { Entrypoint } from '@modern-js/types';
5
+ import { fs, NESTED_ROUTE_SPEC_FILE } from '@modern-js/utils';
6
+ import {
7
+ tanstackRouterPlugin,
8
+ writeTanstackRegisterFile,
9
+ writeTanstackRouterTypesForEntries,
10
+ } from '../../src/cli';
11
+
12
+ const runtimeCliMocks = {
13
+ handleFileChange: rstest.fn(),
14
+ handleGeneratorEntryCode: rstest.fn(),
15
+ };
16
+
17
+ rstest.mock('@modern-js/runtime/cli', () => {
18
+ const routesDirMetaKey = '__modernRoutesDir';
19
+
20
+ return {
21
+ __esModule: true,
22
+ getEntrypointRoutesDir: (entrypoint: any) =>
23
+ entrypoint[routesDirMetaKey] ||
24
+ (entrypoint.nestedRoutesEntry
25
+ ? path.basename(entrypoint.nestedRoutesEntry)
26
+ : null),
27
+ handleFileChange: runtimeCliMocks.handleFileChange,
28
+ handleGeneratorEntryCode: runtimeCliMocks.handleGeneratorEntryCode,
29
+ handleModifyEntrypoints: async (
30
+ entrypoints: Entrypoint[],
31
+ routesDir = 'routes',
32
+ ) =>
33
+ entrypoints.map(entrypoint => {
34
+ const routesEntry = path.join(entrypoint.absoluteEntryDir!, routesDir);
35
+ return {
36
+ ...entrypoint,
37
+ nestedRoutesEntry: routesEntry,
38
+ [routesDirMetaKey]: routesDir,
39
+ };
40
+ }),
41
+ isRouteEntry: (dir: string, routesDir = 'routes') => {
42
+ const routesEntry = path.join(dir, routesDir);
43
+ return fs.existsSync(routesEntry) ? routesEntry : false;
44
+ },
45
+ };
46
+ });
47
+
48
+ describe('tanstack router cli plugin', () => {
49
+ let tempDir: string | undefined;
50
+
51
+ afterEach(async () => {
52
+ runtimeCliMocks.handleFileChange.mockReset();
53
+ runtimeCliMocks.handleGeneratorEntryCode.mockReset();
54
+
55
+ if (tempDir) {
56
+ await rm(tempDir, { recursive: true, force: true });
57
+ tempDir = undefined;
58
+ }
59
+ });
60
+
61
+ test('writes plugin-owned router types and register metadata', async () => {
62
+ tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
63
+ const srcDirectory = path.join(tempDir, 'src');
64
+ await mkdir(srcDirectory, { recursive: true });
65
+
66
+ await writeTanstackRouterTypesForEntries({
67
+ appContext: {
68
+ srcDirectory,
69
+ internalSrcAlias: '@/_',
70
+ entrypoints: [
71
+ { entryName: 'dashboard', isMainEntry: false },
72
+ { entryName: 'main', isMainEntry: true },
73
+ ],
74
+ } as any,
75
+ generatedDirName: 'generated-router',
76
+ routesByEntry: {
77
+ dashboard: [],
78
+ main: [],
79
+ },
80
+ });
81
+
82
+ const mainRouter = await readFile(
83
+ path.join(srcDirectory, 'generated-router', 'main', 'router.gen.ts'),
84
+ 'utf-8',
85
+ );
86
+ expect(mainRouter).toContain(
87
+ "} from '@modern-js/plugin-tanstack/runtime';",
88
+ );
89
+
90
+ const register = await readFile(
91
+ path.join(srcDirectory, 'generated-router', 'register.gen.d.ts'),
92
+ 'utf-8',
93
+ );
94
+ expect(register).toContain("from './main/router.gen'");
95
+ expect(register.indexOf("from './main/router.gen'")).toBeLessThan(
96
+ register.indexOf("from './dashboard/router.gen'"),
97
+ );
98
+ expect(register).toContain(
99
+ "declare module '@modern-js/plugin-tanstack/runtime'",
100
+ );
101
+ });
102
+
103
+ test('can write register metadata without routes for custom entry lists', async () => {
104
+ tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
105
+ const srcDirectory = path.join(tempDir, 'src');
106
+
107
+ await writeTanstackRegisterFile({
108
+ entries: ['main'],
109
+ generatedDirName: 'tanstack',
110
+ srcDirectory,
111
+ });
112
+
113
+ const register = await readFile(
114
+ path.join(srcDirectory, 'tanstack', 'register.gen.d.ts'),
115
+ 'utf-8',
116
+ );
117
+ expect(register).toContain('router: typeof router0');
118
+ expect(register).toContain(
119
+ "declare module '@modern-js/plugin-tanstack/runtime'",
120
+ );
121
+ });
122
+
123
+ test('claims custom routes, injects runtime plugin, and merges route specs', async () => {
124
+ tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
125
+ const srcDirectory = path.join(tempDir, 'src');
126
+ const distDirectory = path.join(tempDir, 'dist');
127
+ const entryDir = path.join(srcDirectory, 'main');
128
+ const viewsDir = path.join(entryDir, 'views');
129
+ await mkdir(viewsDir, { recursive: true });
130
+
131
+ const taps: Record<string, any> = {};
132
+ const api = {
133
+ getAppContext: () => ({
134
+ srcDirectory,
135
+ distDirectory,
136
+ metaName: 'modern-js',
137
+ serverRoutes: [{ entryName: 'main', urlPath: '/dashboard' }],
138
+ }),
139
+ _internalRuntimePlugins: (tap: any) => {
140
+ taps.internalRuntimePlugins = tap;
141
+ },
142
+ checkEntryPoint: (tap: any) => {
143
+ taps.checkEntryPoint = tap;
144
+ },
145
+ config: (tap: any) => {
146
+ taps.config = tap;
147
+ },
148
+ modifyEntrypoints: (tap: any) => {
149
+ taps.modifyEntrypoints = tap;
150
+ },
151
+ generateEntryCode: (tap: any) => {
152
+ taps.generateEntryCode = tap;
153
+ },
154
+ onFileChanged: (tap: any) => {
155
+ taps.onFileChanged = tap;
156
+ },
157
+ modifyFileSystemRoutes: (tap: any) => {
158
+ taps.modifyFileSystemRoutes = tap;
159
+ },
160
+ onBeforeGenerateRoutes: (tap: any) => {
161
+ taps.onBeforeGenerateRoutes = tap;
162
+ },
163
+ };
164
+
165
+ tanstackRouterPlugin({ routesDir: 'views' }).setup!(api as any);
166
+
167
+ expect(taps.checkEntryPoint({ path: entryDir, entry: false })).toEqual({
168
+ path: entryDir,
169
+ entry: viewsDir,
170
+ });
171
+
172
+ const { entrypoints } = await taps.modifyEntrypoints({
173
+ entrypoints: [
174
+ {
175
+ entryName: 'main',
176
+ entry: entryDir,
177
+ absoluteEntryDir: entryDir,
178
+ isAutoMount: true,
179
+ isMainEntry: true,
180
+ } as Entrypoint,
181
+ ],
182
+ });
183
+ const [entrypoint] = entrypoints;
184
+ expect(entrypoint.nestedRoutesEntry).toBe(viewsDir);
185
+
186
+ expect(
187
+ taps.internalRuntimePlugins({ entrypoint, plugins: [] }).plugins,
188
+ ).toEqual([
189
+ {
190
+ name: 'tanstackRouter',
191
+ path: '@modern-js/plugin-tanstack/runtime',
192
+ config: { serverBase: ['/dashboard'] },
193
+ },
194
+ ]);
195
+
196
+ const specPath = path.join(distDirectory, NESTED_ROUTE_SPEC_FILE);
197
+ await fs.outputJSON(specPath, {
198
+ existing: [{ id: 'keep-me' }],
199
+ });
200
+
201
+ await taps.modifyFileSystemRoutes({
202
+ entrypoint,
203
+ routes: [
204
+ {
205
+ id: 'main-route',
206
+ type: 'nested',
207
+ origin: 'file-system',
208
+ },
209
+ ],
210
+ });
211
+ await taps.onBeforeGenerateRoutes({ entrypoint, code: '' });
212
+
213
+ expect(await fs.readJSON(specPath)).toEqual({
214
+ existing: [{ id: 'keep-me' }],
215
+ main: [
216
+ {
217
+ id: 'main-route',
218
+ type: 'nested',
219
+ origin: 'file-system',
220
+ },
221
+ ],
222
+ });
223
+ });
224
+
225
+ test('generates plugin-owned TanStack route files through core route generation', async () => {
226
+ tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
227
+ const srcDirectory = path.join(tempDir, 'src');
228
+ const entryDir = path.join(srcDirectory, 'main');
229
+ const viewsDir = path.join(entryDir, 'views');
230
+ await mkdir(path.join(viewsDir, 'mf'), { recursive: true });
231
+ await fs.outputFile(
232
+ path.join(viewsDir, 'mf', 'page.data.ts'),
233
+ [
234
+ 'export const loader = () => ({ count: 0 });',
235
+ 'export const action = () => Response.json({ count: 1 });',
236
+ ].join('\n'),
237
+ );
238
+
239
+ const entrypoint = {
240
+ entryName: 'main',
241
+ entry: entryDir,
242
+ absoluteEntryDir: entryDir,
243
+ isAutoMount: true,
244
+ isMainEntry: true,
245
+ nestedRoutesEntry: viewsDir,
246
+ __modernRoutesDir: 'views',
247
+ } as Entrypoint;
248
+ runtimeCliMocks.handleGeneratorEntryCode.mockResolvedValue({
249
+ main: [
250
+ {
251
+ type: 'nested',
252
+ id: 'layout',
253
+ isRoot: true,
254
+ children: [
255
+ {
256
+ type: 'nested',
257
+ id: 'mf/page',
258
+ path: 'mf',
259
+ data: '@/_/main/views/mf/page.data',
260
+ action: '@/_/main/views/mf/page.data',
261
+ },
262
+ ],
263
+ },
264
+ ],
265
+ });
266
+
267
+ const taps: Record<string, any> = {};
268
+ const api = {
269
+ getAppContext: () => ({
270
+ srcDirectory,
271
+ internalSrcAlias: '@/_',
272
+ entrypoints: [entrypoint],
273
+ }),
274
+ _internalRuntimePlugins: () => {},
275
+ checkEntryPoint: (tap: any) => {
276
+ taps.checkEntryPoint = tap;
277
+ },
278
+ config: (tap: any) => {
279
+ taps.config = tap;
280
+ },
281
+ modifyEntrypoints: (tap: any) => {
282
+ taps.modifyEntrypoints = tap;
283
+ },
284
+ generateEntryCode: (tap: any) => {
285
+ taps.generateEntryCode = tap;
286
+ },
287
+ onFileChanged: (tap: any) => {
288
+ taps.onFileChanged = tap;
289
+ },
290
+ modifyFileSystemRoutes: (tap: any) => {
291
+ taps.modifyFileSystemRoutes = tap;
292
+ },
293
+ onBeforeGenerateRoutes: (tap: any) => {
294
+ taps.onBeforeGenerateRoutes = tap;
295
+ },
296
+ };
297
+
298
+ tanstackRouterPlugin({
299
+ generatedDirName: 'tanstack-generated',
300
+ routesDir: 'views',
301
+ }).setup!(api as any);
302
+
303
+ await taps.generateEntryCode({ entrypoints: [entrypoint] });
304
+
305
+ expect(runtimeCliMocks.handleGeneratorEntryCode).toHaveBeenCalledWith(
306
+ api,
307
+ [entrypoint],
308
+ {
309
+ entrypointsKey: '@modern-js/plugin-tanstack',
310
+ generateCodeOptions: {
311
+ enableTanstackTypes: false,
312
+ },
313
+ },
314
+ );
315
+
316
+ const routerGen = await readFile(
317
+ path.join(srcDirectory, 'tanstack-generated', 'main', 'router.gen.ts'),
318
+ 'utf-8',
319
+ );
320
+ expect(routerGen).toContain("} from '@modern-js/plugin-tanstack/runtime';");
321
+ expect(routerGen).toContain('modernRouteAction: action_0');
322
+
323
+ const register = await readFile(
324
+ path.join(srcDirectory, 'tanstack-generated', 'register.gen.d.ts'),
325
+ 'utf-8',
326
+ );
327
+ expect(register).toContain(
328
+ "declare module '@modern-js/plugin-tanstack/runtime'",
329
+ );
330
+ });
331
+
332
+ test('regenerates plugin-owned TanStack files for scoped file changes', async () => {
333
+ const regenerateEvent = {
334
+ eventType: 'add',
335
+ filename: 'src/main/views/page.tsx',
336
+ };
337
+ const entrypoint = {
338
+ entryName: 'main',
339
+ __modernRoutesDir: 'views',
340
+ } as any as Entrypoint;
341
+ const api = {
342
+ getAppContext: () => ({
343
+ srcDirectory: '/tmp/app/src',
344
+ internalSrcAlias: '@/_',
345
+ entrypoints: [entrypoint],
346
+ }),
347
+ _internalRuntimePlugins: () => {},
348
+ checkEntryPoint: () => {},
349
+ config: () => {},
350
+ modifyEntrypoints: () => {},
351
+ generateEntryCode: () => {},
352
+ onFileChanged: (tap: any) => {
353
+ api.onFileChangedTap = tap;
354
+ },
355
+ modifyFileSystemRoutes: () => {},
356
+ onBeforeGenerateRoutes: () => {},
357
+ onFileChangedTap: undefined as any,
358
+ };
359
+
360
+ tanstackRouterPlugin({ routesDir: 'views' }).setup!(api as any);
361
+
362
+ runtimeCliMocks.handleFileChange.mockImplementationOnce(
363
+ async (_api, _event, options) => {
364
+ expect(options.entrypointsKey).toBe('@modern-js/plugin-tanstack');
365
+ expect(options.includeEntry(entrypoint)).toBe(true);
366
+ expect(
367
+ options.includeEntry({
368
+ ...entrypoint,
369
+ __modernRoutesDir: 'routes',
370
+ }),
371
+ ).toBe(false);
372
+ expect(typeof options.regenerate).toBe('function');
373
+ },
374
+ );
375
+
376
+ await api.onFileChangedTap(regenerateEvent);
377
+
378
+ expect(runtimeCliMocks.handleFileChange).toHaveBeenCalledWith(
379
+ api,
380
+ regenerateEvent,
381
+ expect.objectContaining({
382
+ entrypointsKey: '@modern-js/plugin-tanstack',
383
+ }),
384
+ );
385
+ });
386
+ });