@tanstack/router-generator 1.121.0-alpha.5 → 1.121.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.
- package/dist/cjs/config.cjs +23 -5
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/config.d.cts +7 -3
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs +5 -3
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs.map +1 -1
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs +1 -1
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs.map +1 -1
- package/dist/cjs/generator.cjs +828 -665
- package/dist/cjs/generator.cjs.map +1 -1
- package/dist/cjs/generator.d.cts +78 -1
- package/dist/cjs/index.cjs +5 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +7 -3
- package/dist/cjs/logger.cjs +37 -0
- package/dist/cjs/logger.cjs.map +1 -0
- package/dist/cjs/logger.d.cts +10 -0
- package/dist/cjs/plugin/default-generator-plugin.cjs +88 -0
- package/dist/cjs/plugin/default-generator-plugin.cjs.map +1 -0
- package/dist/cjs/plugin/default-generator-plugin.d.cts +2 -0
- package/dist/cjs/plugin/types.d.cts +46 -0
- package/dist/cjs/template.cjs +10 -10
- package/dist/cjs/template.cjs.map +1 -1
- package/dist/cjs/template.d.cts +2 -2
- package/dist/cjs/transform/default-transform-plugin.cjs +95 -0
- package/dist/cjs/transform/default-transform-plugin.cjs.map +1 -0
- package/dist/cjs/transform/default-transform-plugin.d.cts +2 -0
- package/dist/cjs/transform/transform.cjs +351 -0
- package/dist/cjs/transform/transform.cjs.map +1 -0
- package/dist/cjs/transform/transform.d.cts +4 -0
- package/dist/cjs/transform/types.d.cts +43 -0
- package/dist/cjs/transform/utils.cjs +36 -0
- package/dist/cjs/transform/utils.cjs.map +1 -0
- package/dist/cjs/transform/utils.d.cts +2 -0
- package/dist/cjs/types.d.cts +22 -0
- package/dist/cjs/utils.cjs +237 -40
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +76 -9
- package/dist/esm/config.d.ts +7 -3
- package/dist/esm/config.js +21 -3
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/filesystem/physical/getRouteNodes.js +3 -1
- package/dist/esm/filesystem/physical/getRouteNodes.js.map +1 -1
- package/dist/esm/filesystem/virtual/getRouteNodes.js +1 -1
- package/dist/esm/filesystem/virtual/getRouteNodes.js.map +1 -1
- package/dist/esm/generator.d.ts +78 -1
- package/dist/esm/generator.js +817 -653
- package/dist/esm/generator.js.map +1 -1
- package/dist/esm/index.d.ts +7 -3
- package/dist/esm/index.js +7 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/logger.d.ts +10 -0
- package/dist/esm/logger.js +37 -0
- package/dist/esm/logger.js.map +1 -0
- package/dist/esm/plugin/default-generator-plugin.d.ts +2 -0
- package/dist/esm/plugin/default-generator-plugin.js +88 -0
- package/dist/esm/plugin/default-generator-plugin.js.map +1 -0
- package/dist/esm/plugin/types.d.ts +46 -0
- package/dist/esm/template.d.ts +2 -2
- package/dist/esm/template.js +10 -10
- package/dist/esm/template.js.map +1 -1
- package/dist/esm/transform/default-transform-plugin.d.ts +2 -0
- package/dist/esm/transform/default-transform-plugin.js +95 -0
- package/dist/esm/transform/default-transform-plugin.js.map +1 -0
- package/dist/esm/transform/transform.d.ts +4 -0
- package/dist/esm/transform/transform.js +351 -0
- package/dist/esm/transform/transform.js.map +1 -0
- package/dist/esm/transform/types.d.ts +43 -0
- package/dist/esm/transform/utils.d.ts +2 -0
- package/dist/esm/transform/utils.js +36 -0
- package/dist/esm/transform/utils.js.map +1 -0
- package/dist/esm/types.d.ts +22 -0
- package/dist/esm/utils.d.ts +76 -9
- package/dist/esm/utils.js +237 -40
- package/dist/esm/utils.js.map +1 -1
- package/package.json +9 -10
- package/src/config.ts +23 -2
- package/src/filesystem/physical/getRouteNodes.ts +2 -1
- package/src/filesystem/virtual/getRouteNodes.ts +1 -1
- package/src/generator.ts +1108 -934
- package/src/index.ts +25 -3
- package/src/logger.ts +43 -0
- package/src/plugin/default-generator-plugin.ts +96 -0
- package/src/plugin/types.ts +51 -0
- package/src/template.ts +33 -12
- package/src/transform/default-transform-plugin.ts +103 -0
- package/src/transform/transform.ts +430 -0
- package/src/transform/types.ts +50 -0
- package/src/transform/utils.ts +42 -0
- package/src/types.ts +25 -0
- package/src/utils.ts +351 -36
package/src/utils.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import * as fsp from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
2
3
|
import * as prettier from 'prettier'
|
|
4
|
+
import { rootPathId } from './filesystem/physical/rootPathId'
|
|
5
|
+
import type { Config } from './config'
|
|
6
|
+
import type { ImportDeclaration, RouteNode } from './types'
|
|
3
7
|
|
|
4
8
|
export function multiSortBy<T>(
|
|
5
9
|
arr: Array<T>,
|
|
@@ -40,42 +44,6 @@ export function trimPathLeft(path: string) {
|
|
|
40
44
|
return path === '/' ? path : path.replace(/^\/{1,}/, '')
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
export function logging(config: { disabled: boolean }) {
|
|
44
|
-
function stripEmojis(str: string) {
|
|
45
|
-
return str.replace(
|
|
46
|
-
/[\p{Emoji_Presentation}\p{Extended_Pictographic}]/gu,
|
|
47
|
-
'',
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function formatLogArgs(args: Array<any>): Array<any> {
|
|
52
|
-
if (process.env.CI) {
|
|
53
|
-
return args.map((arg) =>
|
|
54
|
-
typeof arg === 'string' ? stripEmojis(arg) : arg,
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
return args
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
log: (...args: Array<any>) => {
|
|
62
|
-
if (!config.disabled) console.log(...formatLogArgs(args))
|
|
63
|
-
},
|
|
64
|
-
debug: (...args: Array<any>) => {
|
|
65
|
-
if (!config.disabled) console.debug(...formatLogArgs(args))
|
|
66
|
-
},
|
|
67
|
-
info: (...args: Array<any>) => {
|
|
68
|
-
if (!config.disabled) console.info(...formatLogArgs(args))
|
|
69
|
-
},
|
|
70
|
-
warn: (...args: Array<any>) => {
|
|
71
|
-
if (!config.disabled) console.warn(...formatLogArgs(args))
|
|
72
|
-
},
|
|
73
|
-
error: (...args: Array<any>) => {
|
|
74
|
-
if (!config.disabled) console.error(...formatLogArgs(args))
|
|
75
|
-
},
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
47
|
export function removeLeadingSlash(path: string): string {
|
|
80
48
|
return path.replace(/^\//, '')
|
|
81
49
|
}
|
|
@@ -268,3 +236,350 @@ export async function checkFileExists(file: string) {
|
|
|
268
236
|
return false
|
|
269
237
|
}
|
|
270
238
|
}
|
|
239
|
+
|
|
240
|
+
const possiblyNestedRouteGroupPatternRegex = /\([^/]+\)\/?/g
|
|
241
|
+
export function removeGroups(s: string) {
|
|
242
|
+
return s.replace(possiblyNestedRouteGroupPatternRegex, '')
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Removes all segments from a given path that start with an underscore ('_').
|
|
247
|
+
*
|
|
248
|
+
* @param {string} routePath - The path from which to remove segments. Defaults to '/'.
|
|
249
|
+
* @returns {string} The path with all underscore-prefixed segments removed.
|
|
250
|
+
* @example
|
|
251
|
+
* removeLayoutSegments('/workspace/_auth/foo') // '/workspace/foo'
|
|
252
|
+
*/
|
|
253
|
+
export function removeLayoutSegments(routePath: string = '/'): string {
|
|
254
|
+
const segments = routePath.split('/')
|
|
255
|
+
const newSegments = segments.filter((segment) => !segment.startsWith('_'))
|
|
256
|
+
return newSegments.join('/')
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* The `node.path` is used as the `id` in the route definition.
|
|
261
|
+
* This function checks if the given node has a parent and if so, it determines the correct path for the given node.
|
|
262
|
+
* @param node - The node to determine the path for.
|
|
263
|
+
* @returns The correct path for the given node.
|
|
264
|
+
*/
|
|
265
|
+
export function determineNodePath(node: RouteNode) {
|
|
266
|
+
return (node.path = node.parent
|
|
267
|
+
? node.routePath?.replace(node.parent.routePath ?? '', '') || '/'
|
|
268
|
+
: node.routePath)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Removes the last segment from a given path. Segments are considered to be separated by a '/'.
|
|
273
|
+
*
|
|
274
|
+
* @param {string} routePath - The path from which to remove the last segment. Defaults to '/'.
|
|
275
|
+
* @returns {string} The path with the last segment removed.
|
|
276
|
+
* @example
|
|
277
|
+
* removeLastSegmentFromPath('/workspace/_auth/foo') // '/workspace/_auth'
|
|
278
|
+
*/
|
|
279
|
+
export function removeLastSegmentFromPath(routePath: string = '/'): string {
|
|
280
|
+
const segments = routePath.split('/')
|
|
281
|
+
segments.pop() // Remove the last segment
|
|
282
|
+
return segments.join('/')
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export function hasParentRoute(
|
|
286
|
+
routes: Array<RouteNode>,
|
|
287
|
+
node: RouteNode,
|
|
288
|
+
routePathToCheck: string | undefined,
|
|
289
|
+
): RouteNode | null {
|
|
290
|
+
if (!routePathToCheck || routePathToCheck === '/') {
|
|
291
|
+
return null
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const sortedNodes = multiSortBy(routes, [
|
|
295
|
+
(d) => d.routePath!.length * -1,
|
|
296
|
+
(d) => d.variableName,
|
|
297
|
+
]).filter((d) => d.routePath !== `/${rootPathId}`)
|
|
298
|
+
|
|
299
|
+
for (const route of sortedNodes) {
|
|
300
|
+
if (route.routePath === '/') continue
|
|
301
|
+
|
|
302
|
+
if (
|
|
303
|
+
routePathToCheck.startsWith(`${route.routePath}/`) &&
|
|
304
|
+
route.routePath !== routePathToCheck
|
|
305
|
+
) {
|
|
306
|
+
return route
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const segments = routePathToCheck.split('/')
|
|
311
|
+
segments.pop() // Remove the last segment
|
|
312
|
+
const parentRoutePath = segments.join('/')
|
|
313
|
+
|
|
314
|
+
return hasParentRoute(routes, node, parentRoutePath)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Gets the final variable name for a route
|
|
319
|
+
*/
|
|
320
|
+
export const getResolvedRouteNodeVariableName = (
|
|
321
|
+
routeNode: RouteNode,
|
|
322
|
+
variableNameSuffix: string,
|
|
323
|
+
): string => {
|
|
324
|
+
return routeNode.children?.length
|
|
325
|
+
? `${routeNode.variableName}${variableNameSuffix}WithChildren`
|
|
326
|
+
: `${routeNode.variableName}${variableNameSuffix}`
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Checks if a given RouteNode is valid for augmenting it with typing based on conditions.
|
|
331
|
+
* Also asserts that the RouteNode is defined.
|
|
332
|
+
*
|
|
333
|
+
* @param routeNode - The RouteNode to check.
|
|
334
|
+
* @returns A boolean indicating whether the RouteNode is defined.
|
|
335
|
+
*/
|
|
336
|
+
export function isRouteNodeValidForAugmentation(
|
|
337
|
+
routeNode?: RouteNode,
|
|
338
|
+
): routeNode is RouteNode {
|
|
339
|
+
if (!routeNode || routeNode.isVirtual) {
|
|
340
|
+
return false
|
|
341
|
+
}
|
|
342
|
+
return true
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Infers the path for use by TS
|
|
347
|
+
*/
|
|
348
|
+
export const inferPath = (routeNode: RouteNode): string => {
|
|
349
|
+
return routeNode.cleanedPath === '/'
|
|
350
|
+
? routeNode.cleanedPath
|
|
351
|
+
: (routeNode.cleanedPath?.replace(/\/$/, '') ?? '')
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Infers the full path for use by TS
|
|
356
|
+
*/
|
|
357
|
+
export const inferFullPath = (routeNode: RouteNode): string => {
|
|
358
|
+
const fullPath = removeGroups(
|
|
359
|
+
removeUnderscores(removeLayoutSegments(routeNode.routePath)) ?? '',
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
return routeNode.cleanedPath === '/' ? fullPath : fullPath.replace(/\/$/, '')
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Creates a map from fullPath to routeNode
|
|
367
|
+
*/
|
|
368
|
+
export const createRouteNodesByFullPath = (
|
|
369
|
+
routeNodes: Array<RouteNode>,
|
|
370
|
+
): Map<string, RouteNode> => {
|
|
371
|
+
return new Map(
|
|
372
|
+
routeNodes.map((routeNode) => [inferFullPath(routeNode), routeNode]),
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Create a map from 'to' to a routeNode
|
|
378
|
+
*/
|
|
379
|
+
export const createRouteNodesByTo = (
|
|
380
|
+
routeNodes: Array<RouteNode>,
|
|
381
|
+
): Map<string, RouteNode> => {
|
|
382
|
+
return new Map(
|
|
383
|
+
dedupeBranchesAndIndexRoutes(routeNodes).map((routeNode) => [
|
|
384
|
+
inferTo(routeNode),
|
|
385
|
+
routeNode,
|
|
386
|
+
]),
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Create a map from 'id' to a routeNode
|
|
392
|
+
*/
|
|
393
|
+
export const createRouteNodesById = (
|
|
394
|
+
routeNodes: Array<RouteNode>,
|
|
395
|
+
): Map<string, RouteNode> => {
|
|
396
|
+
return new Map(
|
|
397
|
+
routeNodes.map((routeNode) => {
|
|
398
|
+
const id = routeNode.routePath ?? ''
|
|
399
|
+
return [id, routeNode]
|
|
400
|
+
}),
|
|
401
|
+
)
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Infers to path
|
|
406
|
+
*/
|
|
407
|
+
export const inferTo = (routeNode: RouteNode): string => {
|
|
408
|
+
const fullPath = inferFullPath(routeNode)
|
|
409
|
+
|
|
410
|
+
if (fullPath === '/') return fullPath
|
|
411
|
+
|
|
412
|
+
return fullPath.replace(/\/$/, '')
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Dedupes branches and index routes
|
|
417
|
+
*/
|
|
418
|
+
export const dedupeBranchesAndIndexRoutes = (
|
|
419
|
+
routes: Array<RouteNode>,
|
|
420
|
+
): Array<RouteNode> => {
|
|
421
|
+
return routes.filter((route) => {
|
|
422
|
+
if (route.children?.find((child) => child.cleanedPath === '/')) return false
|
|
423
|
+
return true
|
|
424
|
+
})
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function checkUnique<TElement>(routes: Array<TElement>, key: keyof TElement) {
|
|
428
|
+
// Check no two routes have the same `key`
|
|
429
|
+
// if they do, throw an error with the conflicting filePaths
|
|
430
|
+
const keys = routes.map((d) => d[key])
|
|
431
|
+
const uniqueKeys = new Set(keys)
|
|
432
|
+
if (keys.length !== uniqueKeys.size) {
|
|
433
|
+
const duplicateKeys = keys.filter((d, i) => keys.indexOf(d) !== i)
|
|
434
|
+
const conflictingFiles = routes.filter((d) =>
|
|
435
|
+
duplicateKeys.includes(d[key]),
|
|
436
|
+
)
|
|
437
|
+
return conflictingFiles
|
|
438
|
+
}
|
|
439
|
+
return undefined
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
export function checkRouteFullPathUniqueness(
|
|
443
|
+
_routes: Array<RouteNode>,
|
|
444
|
+
config: Config,
|
|
445
|
+
) {
|
|
446
|
+
const routes = _routes.map((d) => {
|
|
447
|
+
const inferredFullPath = inferFullPath(d)
|
|
448
|
+
return { ...d, inferredFullPath }
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
const conflictingFiles = checkUnique(routes, 'inferredFullPath')
|
|
452
|
+
|
|
453
|
+
if (conflictingFiles !== undefined) {
|
|
454
|
+
const errorMessage = `Conflicting configuration paths were found for the following route${conflictingFiles.length > 1 ? 's' : ''}: ${conflictingFiles
|
|
455
|
+
.map((p) => `"${p.inferredFullPath}"`)
|
|
456
|
+
.join(', ')}.
|
|
457
|
+
Please ensure each Route has a unique full path.
|
|
458
|
+
Conflicting files: \n ${conflictingFiles.map((d) => path.resolve(config.routesDirectory, d.filePath)).join('\n ')}\n`
|
|
459
|
+
throw new Error(errorMessage)
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export function buildRouteTreeConfig(
|
|
464
|
+
nodes: Array<RouteNode>,
|
|
465
|
+
exportName: string,
|
|
466
|
+
disableTypes: boolean,
|
|
467
|
+
depth = 1,
|
|
468
|
+
): Array<string> {
|
|
469
|
+
const children = nodes.map((node) => {
|
|
470
|
+
if (node._fsRouteType === '__root') {
|
|
471
|
+
return
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (node._fsRouteType === 'pathless_layout' && !node.children?.length) {
|
|
475
|
+
return
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const route = `${node.variableName}`
|
|
479
|
+
|
|
480
|
+
if (node.children?.length) {
|
|
481
|
+
const childConfigs = buildRouteTreeConfig(
|
|
482
|
+
node.children,
|
|
483
|
+
exportName,
|
|
484
|
+
disableTypes,
|
|
485
|
+
depth + 1,
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
const childrenDeclaration = disableTypes
|
|
489
|
+
? ''
|
|
490
|
+
: `interface ${route}${exportName}Children {
|
|
491
|
+
${node.children.map((child) => `${child.variableName}${exportName}: typeof ${getResolvedRouteNodeVariableName(child, exportName)}`).join(',')}
|
|
492
|
+
}`
|
|
493
|
+
|
|
494
|
+
const children = `const ${route}${exportName}Children${disableTypes ? '' : `: ${route}${exportName}Children`} = {
|
|
495
|
+
${node.children.map((child) => `${child.variableName}${exportName}: ${getResolvedRouteNodeVariableName(child, exportName)}`).join(',')}
|
|
496
|
+
}`
|
|
497
|
+
|
|
498
|
+
const routeWithChildren = `const ${route}${exportName}WithChildren = ${route}${exportName}._addFileChildren(${route}${exportName}Children)`
|
|
499
|
+
|
|
500
|
+
return [
|
|
501
|
+
childConfigs.join('\n'),
|
|
502
|
+
childrenDeclaration,
|
|
503
|
+
children,
|
|
504
|
+
routeWithChildren,
|
|
505
|
+
].join('\n\n')
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return undefined
|
|
509
|
+
})
|
|
510
|
+
|
|
511
|
+
return children.filter((x) => x !== undefined)
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export function buildImportString(
|
|
515
|
+
importDeclaration: ImportDeclaration,
|
|
516
|
+
): string {
|
|
517
|
+
const { source, specifiers, importKind } = importDeclaration
|
|
518
|
+
return specifiers.length
|
|
519
|
+
? `import ${importKind === 'type' ? 'type ' : ''}{ ${specifiers.map((s) => (s.local ? `${s.imported} as ${s.local}` : s.imported)).join(', ')} } from '${source}'`
|
|
520
|
+
: ''
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export function lowerCaseFirstChar(value: string) {
|
|
524
|
+
if (!value[0]) {
|
|
525
|
+
return value
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return value[0].toLowerCase() + value.slice(1)
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
export function mergeImportDeclarations(
|
|
532
|
+
imports: Array<ImportDeclaration>,
|
|
533
|
+
): Array<ImportDeclaration> {
|
|
534
|
+
const merged: Record<string, ImportDeclaration> = {}
|
|
535
|
+
|
|
536
|
+
for (const imp of imports) {
|
|
537
|
+
const key = `${imp.source}-${imp.importKind}`
|
|
538
|
+
if (!merged[key]) {
|
|
539
|
+
merged[key] = { ...imp, specifiers: [] }
|
|
540
|
+
}
|
|
541
|
+
for (const specifier of imp.specifiers) {
|
|
542
|
+
// check if the specifier already exists in the merged import
|
|
543
|
+
if (
|
|
544
|
+
!merged[key].specifiers.some(
|
|
545
|
+
(existing) =>
|
|
546
|
+
existing.imported === specifier.imported &&
|
|
547
|
+
existing.local === specifier.local,
|
|
548
|
+
)
|
|
549
|
+
) {
|
|
550
|
+
merged[key].specifiers.push(specifier)
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return Object.values(merged)
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export function hasChildWithExport(
|
|
559
|
+
node: RouteNode,
|
|
560
|
+
exportName: string,
|
|
561
|
+
): boolean {
|
|
562
|
+
return (
|
|
563
|
+
node.children?.some((child) => hasChildWithExport(child, exportName)) ??
|
|
564
|
+
false
|
|
565
|
+
)
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
export const findParent = (
|
|
569
|
+
node: RouteNode | undefined,
|
|
570
|
+
exportName: string,
|
|
571
|
+
): string => {
|
|
572
|
+
if (!node) {
|
|
573
|
+
return `root${exportName}Import`
|
|
574
|
+
}
|
|
575
|
+
if (node.parent) {
|
|
576
|
+
if (node.parent.exports?.includes(exportName)) {
|
|
577
|
+
if (node.isVirtualParentRequired) {
|
|
578
|
+
return `${node.parent.variableName}${exportName}`
|
|
579
|
+
} else {
|
|
580
|
+
return `${node.parent.variableName}${exportName}`
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return findParent(node.parent, exportName)
|
|
585
|
+
}
|