@tanstack/router-generator 1.141.8 → 1.142.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 +1 -3
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/config.d.cts +10 -15
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs +69 -37
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs.map +1 -1
- package/dist/cjs/filesystem/physical/getRouteNodes.d.cts +4 -3
- package/dist/cjs/generator.cjs +29 -20
- package/dist/cjs/generator.cjs.map +1 -1
- package/dist/cjs/types.d.cts +0 -1
- package/dist/cjs/utils.cjs +80 -144
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +48 -25
- package/dist/esm/config.d.ts +10 -15
- package/dist/esm/config.js +1 -3
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/filesystem/physical/getRouteNodes.d.ts +4 -3
- package/dist/esm/filesystem/physical/getRouteNodes.js +70 -38
- package/dist/esm/filesystem/physical/getRouteNodes.js.map +1 -1
- package/dist/esm/generator.js +30 -21
- package/dist/esm/generator.js.map +1 -1
- package/dist/esm/types.d.ts +0 -1
- package/dist/esm/utils.d.ts +48 -25
- package/dist/esm/utils.js +80 -144
- package/dist/esm/utils.js.map +1 -1
- package/package.json +3 -3
- package/src/config.ts +0 -2
- package/src/filesystem/physical/getRouteNodes.ts +120 -42
- package/src/generator.ts +36 -27
- package/src/types.ts +0 -1
- package/src/utils.ts +163 -203
package/src/utils.ts
CHANGED
|
@@ -14,7 +14,6 @@ import type { ImportDeclaration, RouteNode } from './types'
|
|
|
14
14
|
export class RoutePrefixMap {
|
|
15
15
|
private prefixToRoute: Map<string, RouteNode> = new Map()
|
|
16
16
|
private layoutRoutes: Array<RouteNode> = []
|
|
17
|
-
private nonNestedRoutes: Array<RouteNode> = []
|
|
18
17
|
|
|
19
18
|
constructor(routes: Array<RouteNode>) {
|
|
20
19
|
for (const route of routes) {
|
|
@@ -23,7 +22,6 @@ export class RoutePrefixMap {
|
|
|
23
22
|
// Index by exact path for direct lookups
|
|
24
23
|
this.prefixToRoute.set(route.routePath, route)
|
|
25
24
|
|
|
26
|
-
// Track layout routes separately for non-nested route handling
|
|
27
25
|
if (
|
|
28
26
|
route._fsRouteType === 'pathless_layout' ||
|
|
29
27
|
route._fsRouteType === 'layout' ||
|
|
@@ -31,20 +29,12 @@ export class RoutePrefixMap {
|
|
|
31
29
|
) {
|
|
32
30
|
this.layoutRoutes.push(route)
|
|
33
31
|
}
|
|
34
|
-
|
|
35
|
-
// Track non-nested routes separately
|
|
36
|
-
if (route._isExperimentalNonNestedRoute) {
|
|
37
|
-
this.nonNestedRoutes.push(route)
|
|
38
|
-
}
|
|
39
32
|
}
|
|
40
33
|
|
|
41
34
|
// Sort by path length descending for longest-match-first
|
|
42
35
|
this.layoutRoutes.sort(
|
|
43
36
|
(a, b) => (b.routePath?.length ?? 0) - (a.routePath?.length ?? 0),
|
|
44
37
|
)
|
|
45
|
-
this.nonNestedRoutes.sort(
|
|
46
|
-
(a, b) => (b.routePath?.length ?? 0) - (a.routePath?.length ?? 0),
|
|
47
|
-
)
|
|
48
38
|
}
|
|
49
39
|
|
|
50
40
|
/**
|
|
@@ -69,48 +59,6 @@ export class RoutePrefixMap {
|
|
|
69
59
|
return null
|
|
70
60
|
}
|
|
71
61
|
|
|
72
|
-
/**
|
|
73
|
-
* Find parent for non-nested routes (needs layout route matching).
|
|
74
|
-
*/
|
|
75
|
-
findParentForNonNested(
|
|
76
|
-
routePath: string,
|
|
77
|
-
originalRoutePath: string | undefined,
|
|
78
|
-
nonNestedSegments: Array<string>,
|
|
79
|
-
): RouteNode | null {
|
|
80
|
-
// First check for other non-nested routes that are prefixes
|
|
81
|
-
// Use pre-sorted array for longest-match-first
|
|
82
|
-
for (const route of this.nonNestedRoutes) {
|
|
83
|
-
if (
|
|
84
|
-
route.routePath !== routePath &&
|
|
85
|
-
originalRoutePath?.startsWith(`${route.originalRoutePath}/`)
|
|
86
|
-
) {
|
|
87
|
-
return route
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Then check layout routes
|
|
92
|
-
for (const route of this.layoutRoutes) {
|
|
93
|
-
if (route.routePath === '/') continue
|
|
94
|
-
|
|
95
|
-
// Skip if this route's original path + underscore matches a non-nested segment
|
|
96
|
-
if (
|
|
97
|
-
nonNestedSegments.some((seg) => seg === `${route.originalRoutePath}_`)
|
|
98
|
-
) {
|
|
99
|
-
continue
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Check if this layout route is a prefix of the path we're looking for
|
|
103
|
-
if (
|
|
104
|
-
routePath.startsWith(`${route.routePath}/`) &&
|
|
105
|
-
route.routePath !== routePath
|
|
106
|
-
) {
|
|
107
|
-
return route
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return null
|
|
112
|
-
}
|
|
113
|
-
|
|
114
62
|
/**
|
|
115
63
|
* Check if a route exists at the given path.
|
|
116
64
|
*/
|
|
@@ -192,55 +140,32 @@ export function removeTrailingSlash(s: string) {
|
|
|
192
140
|
const BRACKET_CONTENT_RE = /\[(.*?)\]/g
|
|
193
141
|
const SPLIT_REGEX = /(?<!\[)\.(?!\])/g
|
|
194
142
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Characters that cannot be escaped in square brackets.
|
|
145
|
+
* These are characters that would cause issues in URLs or file systems.
|
|
146
|
+
*/
|
|
147
|
+
const DISALLOWED_ESCAPE_CHARS = new Set([
|
|
148
|
+
'/',
|
|
149
|
+
'\\',
|
|
150
|
+
'?',
|
|
151
|
+
'#',
|
|
152
|
+
':',
|
|
153
|
+
'*',
|
|
154
|
+
'<',
|
|
155
|
+
'>',
|
|
156
|
+
'|',
|
|
157
|
+
'!',
|
|
158
|
+
'$',
|
|
159
|
+
'%',
|
|
160
|
+
])
|
|
161
|
+
|
|
162
|
+
export function determineInitialRoutePath(routePath: string) {
|
|
214
163
|
const originalRoutePath =
|
|
215
164
|
cleanPath(
|
|
216
165
|
`/${(cleanPath(routePath) || '').split(SPLIT_REGEX).join('/')}`,
|
|
217
166
|
) || ''
|
|
218
167
|
|
|
219
|
-
|
|
220
|
-
// TODO with new major rename to reflect not experimental anymore
|
|
221
|
-
const isExperimentalNonNestedRoute = isValidNonNestedRoute(
|
|
222
|
-
originalRoutePath,
|
|
223
|
-
config,
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
let cleanedRoutePath = routePath
|
|
227
|
-
|
|
228
|
-
// we already identified the path as non-nested and can now remove the trailing underscores
|
|
229
|
-
// we need to do this now before we encounter any escaped trailing underscores
|
|
230
|
-
// this way we can be sure any remaining trailing underscores should remain
|
|
231
|
-
// TODO with new major we can remove check and always remove leading underscores
|
|
232
|
-
if (config?.experimental?.nonNestedRoutes) {
|
|
233
|
-
// we should leave trailing underscores if the route path is the root path
|
|
234
|
-
if (originalRoutePath !== `/${rootPathId}`) {
|
|
235
|
-
// remove trailing underscores on various path segments
|
|
236
|
-
cleanedRoutePath = removeTrailingUnderscores(
|
|
237
|
-
originalRoutePath,
|
|
238
|
-
config.routeToken,
|
|
239
|
-
)
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const parts = cleanedRoutePath.split(SPLIT_REGEX)
|
|
168
|
+
const parts = routePath.split(SPLIT_REGEX)
|
|
244
169
|
|
|
245
170
|
// Escape any characters that in square brackets
|
|
246
171
|
// we keep the original path untouched
|
|
@@ -275,11 +200,51 @@ export function determineInitialRoutePath(
|
|
|
275
200
|
|
|
276
201
|
return {
|
|
277
202
|
routePath: final,
|
|
278
|
-
isExperimentalNonNestedRoute,
|
|
279
203
|
originalRoutePath,
|
|
280
204
|
}
|
|
281
205
|
}
|
|
282
206
|
|
|
207
|
+
/**
|
|
208
|
+
* Checks if a segment is fully escaped (entirely wrapped in brackets with no nested brackets).
|
|
209
|
+
* E.g., "[index]" -> true, "[_layout]" -> true, "foo[.]bar" -> false, "index" -> false
|
|
210
|
+
*/
|
|
211
|
+
function isFullyEscapedSegment(originalSegment: string): boolean {
|
|
212
|
+
return (
|
|
213
|
+
originalSegment.startsWith('[') &&
|
|
214
|
+
originalSegment.endsWith(']') &&
|
|
215
|
+
!originalSegment.slice(1, -1).includes('[') &&
|
|
216
|
+
!originalSegment.slice(1, -1).includes(']')
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Checks if the leading underscore in a segment is escaped.
|
|
222
|
+
* Returns true if:
|
|
223
|
+
* - Segment starts with [_] pattern: "[_]layout" -> "_layout"
|
|
224
|
+
* - Segment is fully escaped and content starts with _: "[_1nd3x]" -> "_1nd3x"
|
|
225
|
+
*/
|
|
226
|
+
export function hasEscapedLeadingUnderscore(originalSegment: string): boolean {
|
|
227
|
+
// Pattern: [_]something or [_something]
|
|
228
|
+
return (
|
|
229
|
+
originalSegment.startsWith('[_]') ||
|
|
230
|
+
(originalSegment.startsWith('[_') && isFullyEscapedSegment(originalSegment))
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Checks if the trailing underscore in a segment is escaped.
|
|
236
|
+
* Returns true if:
|
|
237
|
+
* - Segment ends with [_] pattern: "blog[_]" -> "blog_"
|
|
238
|
+
* - Segment is fully escaped and content ends with _: "[_r0ut3_]" -> "_r0ut3_"
|
|
239
|
+
*/
|
|
240
|
+
export function hasEscapedTrailingUnderscore(originalSegment: string): boolean {
|
|
241
|
+
// Pattern: something[_] or [something_]
|
|
242
|
+
return (
|
|
243
|
+
originalSegment.endsWith('[_]') ||
|
|
244
|
+
(originalSegment.endsWith('_]') && isFullyEscapedSegment(originalSegment))
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
|
|
283
248
|
const backslashRegex = /\\/g
|
|
284
249
|
|
|
285
250
|
export function replaceBackslash(s: string) {
|
|
@@ -350,6 +315,92 @@ export function removeUnderscores(s?: string) {
|
|
|
350
315
|
.replace(underscoreSlashRegex, '/')
|
|
351
316
|
}
|
|
352
317
|
|
|
318
|
+
/**
|
|
319
|
+
* Removes underscores from a path, but preserves underscores that were escaped
|
|
320
|
+
* in the original path (indicated by [_] syntax).
|
|
321
|
+
*
|
|
322
|
+
* @param routePath - The path with brackets removed
|
|
323
|
+
* @param originalPath - The original path that may contain [_] escape sequences
|
|
324
|
+
* @returns The path with non-escaped underscores removed
|
|
325
|
+
*/
|
|
326
|
+
export function removeUnderscoresWithEscape(
|
|
327
|
+
routePath?: string,
|
|
328
|
+
originalPath?: string,
|
|
329
|
+
): string {
|
|
330
|
+
if (!routePath) return ''
|
|
331
|
+
if (!originalPath) return removeUnderscores(routePath) ?? ''
|
|
332
|
+
|
|
333
|
+
const routeSegments = routePath.split('/')
|
|
334
|
+
const originalSegments = originalPath.split('/')
|
|
335
|
+
|
|
336
|
+
const newSegments = routeSegments.map((segment, i) => {
|
|
337
|
+
const originalSegment = originalSegments[i] || ''
|
|
338
|
+
|
|
339
|
+
// Check if leading underscore is escaped
|
|
340
|
+
const leadingEscaped = hasEscapedLeadingUnderscore(originalSegment)
|
|
341
|
+
// Check if trailing underscore is escaped
|
|
342
|
+
const trailingEscaped = hasEscapedTrailingUnderscore(originalSegment)
|
|
343
|
+
|
|
344
|
+
let result = segment
|
|
345
|
+
|
|
346
|
+
// Remove leading underscore only if not escaped
|
|
347
|
+
if (result.startsWith('_') && !leadingEscaped) {
|
|
348
|
+
result = result.slice(1)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Remove trailing underscore only if not escaped
|
|
352
|
+
if (result.endsWith('_') && !trailingEscaped) {
|
|
353
|
+
result = result.slice(0, -1)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return result
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
return newSegments.join('/')
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Removes layout segments (segments starting with underscore) from a path,
|
|
364
|
+
* but preserves segments where the underscore was escaped.
|
|
365
|
+
*
|
|
366
|
+
* @param routePath - The path with brackets removed
|
|
367
|
+
* @param originalPath - The original path that may contain [_] escape sequences
|
|
368
|
+
* @returns The path with non-escaped layout segments removed
|
|
369
|
+
*/
|
|
370
|
+
export function removeLayoutSegmentsWithEscape(
|
|
371
|
+
routePath: string = '/',
|
|
372
|
+
originalPath?: string,
|
|
373
|
+
): string {
|
|
374
|
+
if (!originalPath) return removeLayoutSegments(routePath)
|
|
375
|
+
|
|
376
|
+
const routeSegments = routePath.split('/')
|
|
377
|
+
const originalSegments = originalPath.split('/')
|
|
378
|
+
|
|
379
|
+
// Keep segments that are NOT pathless (i.e., don't start with unescaped underscore)
|
|
380
|
+
const newSegments = routeSegments.filter((segment, i) => {
|
|
381
|
+
const originalSegment = originalSegments[i] || ''
|
|
382
|
+
return !isSegmentPathless(segment, originalSegment)
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
return newSegments.join('/')
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Checks if a segment should be treated as a pathless/layout segment.
|
|
390
|
+
* A segment is pathless if it starts with underscore and the underscore is not escaped.
|
|
391
|
+
*
|
|
392
|
+
* @param segment - The segment from routePath (brackets removed)
|
|
393
|
+
* @param originalSegment - The segment from originalRoutePath (may contain brackets)
|
|
394
|
+
* @returns true if the segment is pathless (has non-escaped leading underscore)
|
|
395
|
+
*/
|
|
396
|
+
export function isSegmentPathless(
|
|
397
|
+
segment: string,
|
|
398
|
+
originalSegment: string,
|
|
399
|
+
): boolean {
|
|
400
|
+
if (!segment.startsWith('_')) return false
|
|
401
|
+
return !hasEscapedLeadingUnderscore(originalSegment)
|
|
402
|
+
}
|
|
403
|
+
|
|
353
404
|
function escapeRegExp(s: string): string {
|
|
354
405
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
355
406
|
}
|
|
@@ -518,30 +569,6 @@ export function removeLastSegmentFromPath(routePath: string = '/'): string {
|
|
|
518
569
|
return segments.join('/')
|
|
519
570
|
}
|
|
520
571
|
|
|
521
|
-
const nonNestedSegmentRegex = /_(?=\/|$)/g
|
|
522
|
-
const openBracketRegex = /\[/g
|
|
523
|
-
const closeBracketRegex = /\]/g
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Extracts non-nested segments from a route path.
|
|
527
|
-
* Used for determining parent routes in non-nested route scenarios.
|
|
528
|
-
*/
|
|
529
|
-
export function getNonNestedSegments(routePath: string): Array<string> {
|
|
530
|
-
nonNestedSegmentRegex.lastIndex = 0
|
|
531
|
-
const result: Array<string> = []
|
|
532
|
-
for (const match of routePath.matchAll(nonNestedSegmentRegex)) {
|
|
533
|
-
const beforeStr = routePath.substring(0, match.index)
|
|
534
|
-
openBracketRegex.lastIndex = 0
|
|
535
|
-
closeBracketRegex.lastIndex = 0
|
|
536
|
-
const openBrackets = beforeStr.match(openBracketRegex)?.length ?? 0
|
|
537
|
-
const closeBrackets = beforeStr.match(closeBracketRegex)?.length ?? 0
|
|
538
|
-
if (openBrackets === closeBrackets) {
|
|
539
|
-
result.push(routePath.substring(0, match.index + 1))
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
return result.reverse()
|
|
543
|
-
}
|
|
544
|
-
|
|
545
572
|
/**
|
|
546
573
|
* Find parent route using RoutePrefixMap for O(k) lookups instead of O(n).
|
|
547
574
|
*/
|
|
@@ -549,21 +576,11 @@ export function hasParentRoute(
|
|
|
549
576
|
prefixMap: RoutePrefixMap,
|
|
550
577
|
node: RouteNode,
|
|
551
578
|
routePathToCheck: string | undefined,
|
|
552
|
-
originalRoutePathToCheck: string | undefined,
|
|
553
579
|
): RouteNode | null {
|
|
554
580
|
if (!routePathToCheck || routePathToCheck === '/') {
|
|
555
581
|
return null
|
|
556
582
|
}
|
|
557
583
|
|
|
558
|
-
if (node._isExperimentalNonNestedRoute && originalRoutePathToCheck) {
|
|
559
|
-
const nonNestedSegments = getNonNestedSegments(originalRoutePathToCheck)
|
|
560
|
-
return prefixMap.findParentForNonNested(
|
|
561
|
-
routePathToCheck,
|
|
562
|
-
originalRoutePathToCheck,
|
|
563
|
-
nonNestedSegments,
|
|
564
|
-
)
|
|
565
|
-
}
|
|
566
|
-
|
|
567
584
|
return prefixMap.findParent(routePathToCheck)
|
|
568
585
|
}
|
|
569
586
|
|
|
@@ -606,16 +623,15 @@ export const inferPath = (routeNode: RouteNode): string => {
|
|
|
606
623
|
/**
|
|
607
624
|
* Infers the full path for use by TS
|
|
608
625
|
*/
|
|
609
|
-
export const inferFullPath = (
|
|
610
|
-
routeNode: RouteNode,
|
|
611
|
-
config?: Pick<Config, 'experimental' | 'routeToken'>,
|
|
612
|
-
): string => {
|
|
613
|
-
// with new nonNestedPaths feature we can be sure any remaining trailing underscores are escaped and should remain
|
|
614
|
-
// TODO with new major we can remove check and only remove leading underscores
|
|
626
|
+
export const inferFullPath = (routeNode: RouteNode): string => {
|
|
615
627
|
const fullPath = removeGroups(
|
|
616
|
-
(
|
|
617
|
-
|
|
618
|
-
|
|
628
|
+
removeUnderscoresWithEscape(
|
|
629
|
+
removeLayoutSegmentsWithEscape(
|
|
630
|
+
routeNode.routePath,
|
|
631
|
+
routeNode.originalRoutePath,
|
|
632
|
+
),
|
|
633
|
+
routeNode.originalRoutePath,
|
|
634
|
+
),
|
|
619
635
|
)
|
|
620
636
|
|
|
621
637
|
return routeNode.cleanedPath === '/' ? fullPath : fullPath.replace(/\/$/, '')
|
|
@@ -626,13 +642,9 @@ export const inferFullPath = (
|
|
|
626
642
|
*/
|
|
627
643
|
export const createRouteNodesByFullPath = (
|
|
628
644
|
routeNodes: Array<RouteNode>,
|
|
629
|
-
config?: Pick<Config, 'experimental' | 'routeToken'>,
|
|
630
645
|
): Map<string, RouteNode> => {
|
|
631
646
|
return new Map(
|
|
632
|
-
routeNodes.map((routeNode) => [
|
|
633
|
-
inferFullPath(routeNode, config),
|
|
634
|
-
routeNode,
|
|
635
|
-
]),
|
|
647
|
+
routeNodes.map((routeNode) => [inferFullPath(routeNode), routeNode]),
|
|
636
648
|
)
|
|
637
649
|
}
|
|
638
650
|
|
|
@@ -641,11 +653,10 @@ export const createRouteNodesByFullPath = (
|
|
|
641
653
|
*/
|
|
642
654
|
export const createRouteNodesByTo = (
|
|
643
655
|
routeNodes: Array<RouteNode>,
|
|
644
|
-
config?: Pick<Config, 'experimental' | 'routeToken'>,
|
|
645
656
|
): Map<string, RouteNode> => {
|
|
646
657
|
return new Map(
|
|
647
658
|
dedupeBranchesAndIndexRoutes(routeNodes).map((routeNode) => [
|
|
648
|
-
inferTo(routeNode
|
|
659
|
+
inferTo(routeNode),
|
|
649
660
|
routeNode,
|
|
650
661
|
]),
|
|
651
662
|
)
|
|
@@ -668,11 +679,8 @@ export const createRouteNodesById = (
|
|
|
668
679
|
/**
|
|
669
680
|
* Infers to path
|
|
670
681
|
*/
|
|
671
|
-
export const inferTo = (
|
|
672
|
-
routeNode
|
|
673
|
-
config?: Pick<Config, 'experimental' | 'routeToken'>,
|
|
674
|
-
): string => {
|
|
675
|
-
const fullPath = inferFullPath(routeNode, config)
|
|
682
|
+
export const inferTo = (routeNode: RouteNode): string => {
|
|
683
|
+
const fullPath = inferFullPath(routeNode)
|
|
676
684
|
|
|
677
685
|
if (fullPath === '/') return fullPath
|
|
678
686
|
|
|
@@ -711,7 +719,7 @@ export function checkRouteFullPathUniqueness(
|
|
|
711
719
|
config: Config,
|
|
712
720
|
) {
|
|
713
721
|
const routes = _routes.map((d) => {
|
|
714
|
-
const inferredFullPath = inferFullPath(d
|
|
722
|
+
const inferredFullPath = inferFullPath(d)
|
|
715
723
|
return { ...d, inferredFullPath }
|
|
716
724
|
})
|
|
717
725
|
|
|
@@ -849,7 +857,7 @@ export function buildFileRoutesByPathInterface(opts: {
|
|
|
849
857
|
routeNodes: Array<RouteNode>
|
|
850
858
|
module: string
|
|
851
859
|
interfaceName: string
|
|
852
|
-
config?: Pick<Config, '
|
|
860
|
+
config?: Pick<Config, 'routeToken'>
|
|
853
861
|
}): string {
|
|
854
862
|
return `declare module '${opts.module}' {
|
|
855
863
|
interface ${opts.interfaceName} {
|
|
@@ -863,7 +871,7 @@ export function buildFileRoutesByPathInterface(opts: {
|
|
|
863
871
|
return `'${filePathId}': {
|
|
864
872
|
id: '${filePathId}'
|
|
865
873
|
path: '${inferPath(routeNode)}'
|
|
866
|
-
fullPath: '${inferFullPath(routeNode
|
|
874
|
+
fullPath: '${inferFullPath(routeNode)}'
|
|
867
875
|
preLoaderRoute: ${preloaderRoute}
|
|
868
876
|
parentRoute: typeof ${parent}
|
|
869
877
|
}`
|
|
@@ -916,51 +924,3 @@ export function getImportForRouteNode(
|
|
|
916
924
|
],
|
|
917
925
|
} satisfies ImportDeclaration
|
|
918
926
|
}
|
|
919
|
-
|
|
920
|
-
/**
|
|
921
|
-
* Used to validate if a route is a pathless layout route
|
|
922
|
-
* @param normalizedRoutePath Normalized route path, i.e `/foo/_layout/route.tsx` and `/foo._layout.route.tsx` to `/foo/_layout/route`
|
|
923
|
-
* @param config The `router-generator` configuration object
|
|
924
|
-
* @returns Boolean indicating if the route is a pathless layout route
|
|
925
|
-
*/
|
|
926
|
-
export function isValidNonNestedRoute(
|
|
927
|
-
normalizedRoutePath: string,
|
|
928
|
-
config?: Pick<Config, 'experimental' | 'routeToken' | 'indexToken'>,
|
|
929
|
-
): boolean {
|
|
930
|
-
if (!config?.experimental?.nonNestedRoutes) {
|
|
931
|
-
return false
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
const segments = normalizedRoutePath.split('/').filter(Boolean)
|
|
935
|
-
|
|
936
|
-
if (segments.length === 0) {
|
|
937
|
-
return false
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
const lastRouteSegment = segments[segments.length - 1]!
|
|
941
|
-
|
|
942
|
-
// If segment === __root, then exit as false
|
|
943
|
-
if (lastRouteSegment === rootPathId) {
|
|
944
|
-
return false
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
if (
|
|
948
|
-
lastRouteSegment !== config.indexToken &&
|
|
949
|
-
lastRouteSegment !== config.routeToken &&
|
|
950
|
-
lastRouteSegment.endsWith('_')
|
|
951
|
-
) {
|
|
952
|
-
return true
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
for (const segment of segments.slice(0, -1).reverse()) {
|
|
956
|
-
if (segment === config.routeToken) {
|
|
957
|
-
return false
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
if (segment.endsWith('_')) {
|
|
961
|
-
return true
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
return false
|
|
966
|
-
}
|