@tanstack/router-generator 1.51.6 → 1.54.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 +38 -14
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/config.d.cts +9 -0
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs +125 -0
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs.map +1 -0
- package/dist/cjs/filesystem/physical/getRouteNodes.d.cts +3 -0
- package/dist/cjs/filesystem/physical/rootPathId.cjs +5 -0
- package/dist/cjs/filesystem/physical/rootPathId.cjs.map +1 -0
- package/dist/cjs/filesystem/physical/rootPathId.d.cts +1 -0
- package/dist/cjs/filesystem/virtual/config.cjs +37 -0
- package/dist/cjs/filesystem/virtual/config.cjs.map +1 -0
- package/dist/cjs/filesystem/virtual/config.d.cts +3 -0
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs +119 -0
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs.map +1 -0
- package/dist/cjs/filesystem/virtual/getRouteNodes.d.cts +5 -0
- package/dist/cjs/generator.cjs +48 -171
- package/dist/cjs/generator.cjs.map +1 -1
- package/dist/cjs/generator.d.cts +2 -27
- package/dist/cjs/types.d.cts +27 -0
- package/dist/cjs/utils.cjs +34 -0
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +8 -0
- package/dist/esm/config.d.ts +9 -0
- package/dist/esm/config.js +24 -0
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/filesystem/physical/getRouteNodes.d.ts +3 -0
- package/dist/esm/filesystem/physical/getRouteNodes.js +108 -0
- package/dist/esm/filesystem/physical/getRouteNodes.js.map +1 -0
- package/dist/esm/filesystem/physical/rootPathId.d.ts +1 -0
- package/dist/esm/filesystem/physical/rootPathId.js +5 -0
- package/dist/esm/filesystem/physical/rootPathId.js.map +1 -0
- package/dist/esm/filesystem/virtual/config.d.ts +3 -0
- package/dist/esm/filesystem/virtual/config.js +37 -0
- package/dist/esm/filesystem/virtual/config.js.map +1 -0
- package/dist/esm/filesystem/virtual/getRouteNodes.d.ts +5 -0
- package/dist/esm/filesystem/virtual/getRouteNodes.js +119 -0
- package/dist/esm/filesystem/virtual/getRouteNodes.js.map +1 -0
- package/dist/esm/generator.d.ts +2 -27
- package/dist/esm/generator.js +34 -157
- package/dist/esm/generator.js.map +1 -1
- package/dist/esm/types.d.ts +27 -0
- package/dist/esm/utils.d.ts +8 -0
- package/dist/esm/utils.js +34 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +3 -2
- package/src/config.ts +25 -0
- package/src/filesystem/physical/getRouteNodes.ts +151 -0
- package/src/filesystem/physical/rootPathId.ts +1 -0
- package/src/filesystem/virtual/config.ts +45 -0
- package/src/filesystem/virtual/getRouteNodes.ts +141 -0
- package/src/generator.ts +52 -236
- package/src/types.ts +28 -0
- package/src/utils.ts +43 -0
package/src/generator.ts
CHANGED
|
@@ -2,168 +2,25 @@ import path from 'node:path'
|
|
|
2
2
|
import * as fs from 'node:fs'
|
|
3
3
|
import * as fsp from 'node:fs/promises'
|
|
4
4
|
import * as prettier from 'prettier'
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
determineInitialRoutePath,
|
|
7
|
+
logging,
|
|
8
|
+
removeExt,
|
|
9
|
+
removeTrailingSlash,
|
|
10
|
+
removeUnderscores,
|
|
11
|
+
replaceBackslash,
|
|
12
|
+
routePathToVariable,
|
|
13
|
+
trimPathLeft,
|
|
14
|
+
} from './utils'
|
|
15
|
+
import { getRouteNodes as physicalGetRouteNodes } from './filesystem/physical/getRouteNodes'
|
|
16
|
+
import { getRouteNodes as virtualGetRouteNodes } from './filesystem/virtual/getRouteNodes'
|
|
17
|
+
import { rootPathId } from './filesystem/physical/rootPathId'
|
|
18
|
+
import type { GetRouteNodesResult, RouteNode } from './types'
|
|
6
19
|
import type { Config } from './config'
|
|
7
20
|
|
|
8
21
|
let latestTask = 0
|
|
9
|
-
export const rootPathId = '__root'
|
|
10
22
|
const routeGroupPatternRegex = /\(.+\)/g
|
|
11
23
|
const possiblyNestedRouteGroupPatternRegex = /\([^/]+\)\/?/g
|
|
12
|
-
const disallowedRouteGroupConfiguration = /\(([^)]+)\).(ts|js|tsx|jsx)/
|
|
13
|
-
|
|
14
|
-
export type RouteNode = {
|
|
15
|
-
filePath: string
|
|
16
|
-
fullPath: string
|
|
17
|
-
variableName: string
|
|
18
|
-
routePath?: string
|
|
19
|
-
cleanedPath?: string
|
|
20
|
-
path?: string
|
|
21
|
-
isNonPath?: boolean
|
|
22
|
-
isNonLayout?: boolean
|
|
23
|
-
isLayout?: boolean
|
|
24
|
-
isVirtualParentRequired?: boolean
|
|
25
|
-
isVirtualParentRoute?: boolean
|
|
26
|
-
isRoute?: boolean
|
|
27
|
-
isAPIRoute?: boolean
|
|
28
|
-
isLoader?: boolean
|
|
29
|
-
isComponent?: boolean
|
|
30
|
-
isErrorComponent?: boolean
|
|
31
|
-
isPendingComponent?: boolean
|
|
32
|
-
isVirtual?: boolean
|
|
33
|
-
isLazy?: boolean
|
|
34
|
-
isRoot?: boolean
|
|
35
|
-
children?: Array<RouteNode>
|
|
36
|
-
parent?: RouteNode
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async function getRouteNodes(config: Config) {
|
|
40
|
-
const { routeFilePrefix, routeFileIgnorePrefix, routeFileIgnorePattern } =
|
|
41
|
-
config
|
|
42
|
-
const logger = logging({ disabled: config.disableLogging })
|
|
43
|
-
const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? '', 'g')
|
|
44
|
-
|
|
45
|
-
const routeNodes: Array<RouteNode> = []
|
|
46
|
-
|
|
47
|
-
async function recurse(dir: string) {
|
|
48
|
-
const fullDir = path.resolve(config.routesDirectory, dir)
|
|
49
|
-
let dirList = await fsp.readdir(fullDir, { withFileTypes: true })
|
|
50
|
-
|
|
51
|
-
dirList = dirList.filter((d) => {
|
|
52
|
-
if (
|
|
53
|
-
d.name.startsWith('.') ||
|
|
54
|
-
(routeFileIgnorePrefix && d.name.startsWith(routeFileIgnorePrefix))
|
|
55
|
-
) {
|
|
56
|
-
return false
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (routeFilePrefix) {
|
|
60
|
-
return d.name.startsWith(routeFilePrefix)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (routeFileIgnorePattern) {
|
|
64
|
-
return !d.name.match(routeFileIgnoreRegExp)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return true
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
await Promise.all(
|
|
71
|
-
dirList.map(async (dirent) => {
|
|
72
|
-
const fullPath = path.join(fullDir, dirent.name)
|
|
73
|
-
const relativePath = path.join(dir, dirent.name)
|
|
74
|
-
|
|
75
|
-
if (dirent.isDirectory()) {
|
|
76
|
-
await recurse(relativePath)
|
|
77
|
-
} else if (fullPath.match(/\.(tsx|ts|jsx|js)$/)) {
|
|
78
|
-
const filePath = replaceBackslash(path.join(dir, dirent.name))
|
|
79
|
-
const filePathNoExt = removeExt(filePath)
|
|
80
|
-
let routePath = determineInitialRoutePath(filePathNoExt)
|
|
81
|
-
|
|
82
|
-
if (routeFilePrefix) {
|
|
83
|
-
routePath = routePath.replaceAll(routeFilePrefix, '')
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (disallowedRouteGroupConfiguration.test(dirent.name)) {
|
|
87
|
-
const errorMessage = `A route configuration for a route group was found at \`${filePath}\`. This is not supported. Did you mean to use a layout/pathless route instead?`
|
|
88
|
-
logger.error(`ERROR: ${errorMessage}`)
|
|
89
|
-
throw new Error(errorMessage)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const variableName = routePathToVariable(routePath)
|
|
93
|
-
|
|
94
|
-
// Remove the index from the route path and
|
|
95
|
-
// if the route path is empty, use `/'
|
|
96
|
-
|
|
97
|
-
const isLazy = routePath.endsWith('/lazy')
|
|
98
|
-
|
|
99
|
-
if (isLazy) {
|
|
100
|
-
routePath = routePath.replace(/\/lazy$/, '')
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const isRoute = routePath.endsWith('/route')
|
|
104
|
-
const isComponent = routePath.endsWith('/component')
|
|
105
|
-
const isErrorComponent = routePath.endsWith('/errorComponent')
|
|
106
|
-
const isPendingComponent = routePath.endsWith('/pendingComponent')
|
|
107
|
-
const isLoader = routePath.endsWith('/loader')
|
|
108
|
-
const isAPIRoute = routePath.startsWith(
|
|
109
|
-
`${removeTrailingSlash(config.apiBase)}/`,
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
const segments = routePath.split('/')
|
|
113
|
-
const isLayout =
|
|
114
|
-
segments[segments.length - 1]?.startsWith('_') || false
|
|
115
|
-
|
|
116
|
-
;(
|
|
117
|
-
[
|
|
118
|
-
[isComponent, 'component'],
|
|
119
|
-
[isErrorComponent, 'errorComponent'],
|
|
120
|
-
[isPendingComponent, 'pendingComponent'],
|
|
121
|
-
[isLoader, 'loader'],
|
|
122
|
-
] as const
|
|
123
|
-
).forEach(([isType, type]) => {
|
|
124
|
-
if (isType) {
|
|
125
|
-
logger.warn(
|
|
126
|
-
`WARNING: The \`.${type}.tsx\` suffix used for the ${filePath} file is deprecated. Use the new \`.lazy.tsx\` suffix instead.`,
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
routePath = routePath.replace(
|
|
132
|
-
/\/(component|errorComponent|pendingComponent|loader|route|lazy)$/,
|
|
133
|
-
'',
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
if (routePath === 'index') {
|
|
137
|
-
routePath = '/'
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
routePath = routePath.replace(/\/index$/, '/') || '/'
|
|
141
|
-
|
|
142
|
-
routeNodes.push({
|
|
143
|
-
filePath,
|
|
144
|
-
fullPath,
|
|
145
|
-
routePath,
|
|
146
|
-
variableName,
|
|
147
|
-
isRoute,
|
|
148
|
-
isComponent,
|
|
149
|
-
isErrorComponent,
|
|
150
|
-
isPendingComponent,
|
|
151
|
-
isLoader,
|
|
152
|
-
isLazy,
|
|
153
|
-
isLayout,
|
|
154
|
-
isAPIRoute,
|
|
155
|
-
})
|
|
156
|
-
}
|
|
157
|
-
}),
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
return routeNodes
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
await recurse('./')
|
|
164
|
-
|
|
165
|
-
return routeNodes
|
|
166
|
-
}
|
|
167
24
|
|
|
168
25
|
let isFirst = false
|
|
169
26
|
let skipMessage = false
|
|
@@ -209,23 +66,31 @@ export async function generator(config: Config) {
|
|
|
209
66
|
parser: 'typescript',
|
|
210
67
|
}
|
|
211
68
|
|
|
212
|
-
|
|
213
|
-
const beforeRouteNodes = await getRouteNodes(config)
|
|
214
|
-
const rootRouteNode = beforeRouteNodes.find(
|
|
215
|
-
(d) => d.routePath === `/${rootPathId}`,
|
|
216
|
-
)
|
|
69
|
+
let getRouteNodesResult: GetRouteNodesResult
|
|
217
70
|
|
|
71
|
+
if (config.virtualRouteConfig) {
|
|
72
|
+
getRouteNodesResult = await virtualGetRouteNodes(config)
|
|
73
|
+
} else {
|
|
74
|
+
getRouteNodesResult = await physicalGetRouteNodes(config)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const { rootRouteNode, routeNodes: beforeRouteNodes } = getRouteNodesResult
|
|
78
|
+
if (rootRouteNode === undefined) {
|
|
79
|
+
throw new Error(`rootRouteNode must not be undefined`)
|
|
80
|
+
}
|
|
218
81
|
const preRouteNodes = multiSortBy(beforeRouteNodes, [
|
|
219
82
|
(d) => (d.routePath === '/' ? -1 : 1),
|
|
220
83
|
(d) => d.routePath?.split('/').length,
|
|
221
|
-
(d) =>
|
|
84
|
+
(d) =>
|
|
85
|
+
d.filePath.match(new RegExp(`[./]${config.indexToken}[.]`)) ? 1 : -1,
|
|
222
86
|
(d) =>
|
|
223
87
|
d.filePath.match(
|
|
224
88
|
/[./](component|errorComponent|pendingComponent|loader|lazy)[.]/,
|
|
225
89
|
)
|
|
226
90
|
? 1
|
|
227
91
|
: -1,
|
|
228
|
-
(d) =>
|
|
92
|
+
(d) =>
|
|
93
|
+
d.filePath.match(new RegExp(`[./]${config.routeToken}[.]`)) ? -1 : 1,
|
|
229
94
|
(d) => (d.routePath?.endsWith('/') ? -1 : 1),
|
|
230
95
|
(d) => d.routePath,
|
|
231
96
|
]).filter((d) => ![`/${rootPathId}`].includes(d.routePath || ''))
|
|
@@ -298,13 +163,11 @@ export const Route = createRootRoute({
|
|
|
298
163
|
const trimmedPath = trimPathLeft(node.path ?? '')
|
|
299
164
|
|
|
300
165
|
const split = trimmedPath.split('/')
|
|
301
|
-
const first = split[0] ?? trimmedPath
|
|
302
166
|
const lastRouteSegment = split[split.length - 1] ?? trimmedPath
|
|
303
167
|
|
|
304
168
|
node.isNonPath =
|
|
305
169
|
lastRouteSegment.startsWith('_') ||
|
|
306
170
|
routeGroupPatternRegex.test(lastRouteSegment)
|
|
307
|
-
node.isNonLayout = first.endsWith('_')
|
|
308
171
|
|
|
309
172
|
node.cleanedPath = removeGroups(
|
|
310
173
|
removeUnderscores(removeLayoutSegments(node.path)) ?? '',
|
|
@@ -542,7 +405,7 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
|
|
|
542
405
|
const sortedRouteNodes = multiSortBy(routeNodes, [
|
|
543
406
|
(d) => (d.routePath?.includes(`/${rootPathId}`) ? -1 : 1),
|
|
544
407
|
(d) => d.routePath?.split('/').length,
|
|
545
|
-
(d) => (d.routePath?.endsWith(
|
|
408
|
+
(d) => (d.routePath?.endsWith(config.indexToken) ? -1 : 1),
|
|
546
409
|
(d) => d,
|
|
547
410
|
])
|
|
548
411
|
|
|
@@ -562,11 +425,18 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
|
|
|
562
425
|
.map((d) => d[0])
|
|
563
426
|
|
|
564
427
|
const virtualRouteNodes = sortedRouteNodes.filter((d) => d.isVirtual)
|
|
565
|
-
const rootPathIdExtension =
|
|
566
|
-
config.addExtensions && rootRouteNode
|
|
567
|
-
? path.extname(rootRouteNode.filePath)
|
|
568
|
-
: ''
|
|
569
428
|
|
|
429
|
+
function getImportPath(node: RouteNode) {
|
|
430
|
+
return replaceBackslash(
|
|
431
|
+
removeExt(
|
|
432
|
+
path.relative(
|
|
433
|
+
path.dirname(config.generatedRouteTree),
|
|
434
|
+
path.resolve(config.routesDirectory, node.filePath),
|
|
435
|
+
),
|
|
436
|
+
config.addExtensions,
|
|
437
|
+
),
|
|
438
|
+
)
|
|
439
|
+
}
|
|
570
440
|
const routeImports = [
|
|
571
441
|
...config.routeTreeFileHeader,
|
|
572
442
|
'// This file is auto-generated by TanStack Router',
|
|
@@ -575,29 +445,13 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
|
|
|
575
445
|
: '',
|
|
576
446
|
'// Import Routes',
|
|
577
447
|
[
|
|
578
|
-
`import { Route as rootRoute } from './${
|
|
579
|
-
path.relative(
|
|
580
|
-
path.dirname(config.generatedRouteTree),
|
|
581
|
-
path.resolve(
|
|
582
|
-
config.routesDirectory,
|
|
583
|
-
`${routePathIdPrefix}${rootPathId}${rootPathIdExtension}`,
|
|
584
|
-
),
|
|
585
|
-
),
|
|
586
|
-
)}'`,
|
|
448
|
+
`import { Route as rootRoute } from './${getImportPath(rootRouteNode)}'`,
|
|
587
449
|
...sortedRouteNodes
|
|
588
450
|
.filter((d) => !d.isVirtual)
|
|
589
451
|
.map((node) => {
|
|
590
452
|
return `import { Route as ${
|
|
591
453
|
node.variableName
|
|
592
|
-
}Import } from './${
|
|
593
|
-
removeExt(
|
|
594
|
-
path.relative(
|
|
595
|
-
path.dirname(config.generatedRouteTree),
|
|
596
|
-
path.resolve(config.routesDirectory, node.filePath),
|
|
597
|
-
),
|
|
598
|
-
config.addExtensions,
|
|
599
|
-
),
|
|
600
|
-
)}'`
|
|
454
|
+
}Import } from './${getImportPath(node)}'`
|
|
601
455
|
}),
|
|
602
456
|
].join('\n'),
|
|
603
457
|
virtualRouteNodes.length ? '// Create Virtual Routes' : '',
|
|
@@ -695,7 +549,7 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
|
|
|
695
549
|
${routeNodes
|
|
696
550
|
.map((routeNode) => {
|
|
697
551
|
const [filePathId, routeId] = getFilePathIdAndRouteIdFromPath(
|
|
698
|
-
routeNode.routePath
|
|
552
|
+
routeNode.routePath,
|
|
699
553
|
)
|
|
700
554
|
|
|
701
555
|
return `'${filePathId}': {
|
|
@@ -726,14 +580,14 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
|
|
|
726
580
|
const createRouteManifest = () => {
|
|
727
581
|
const routesManifest = {
|
|
728
582
|
__root__: {
|
|
729
|
-
filePath: rootRouteNode
|
|
583
|
+
filePath: rootRouteNode.filePath,
|
|
730
584
|
children: routeTree.map(
|
|
731
|
-
(d) => getFilePathIdAndRouteIdFromPath(d.routePath
|
|
585
|
+
(d) => getFilePathIdAndRouteIdFromPath(d.routePath)[1],
|
|
732
586
|
),
|
|
733
587
|
},
|
|
734
588
|
...Object.fromEntries(
|
|
735
589
|
routeNodes.map((d) => {
|
|
736
|
-
const [_, routeId] = getFilePathIdAndRouteIdFromPath(d.routePath
|
|
590
|
+
const [_, routeId] = getFilePathIdAndRouteIdFromPath(d.routePath)
|
|
737
591
|
|
|
738
592
|
return [
|
|
739
593
|
routeId,
|
|
@@ -744,7 +598,7 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
|
|
|
744
598
|
: undefined,
|
|
745
599
|
children: d.children?.map(
|
|
746
600
|
(childRoute) =>
|
|
747
|
-
getFilePathIdAndRouteIdFromPath(childRoute.routePath
|
|
601
|
+
getFilePathIdAndRouteIdFromPath(childRoute.routePath)[1],
|
|
748
602
|
),
|
|
749
603
|
},
|
|
750
604
|
]
|
|
@@ -811,24 +665,6 @@ export const Route = createAPIFileRoute('${escapedRoutePath}')({
|
|
|
811
665
|
)
|
|
812
666
|
}
|
|
813
667
|
|
|
814
|
-
function routePathToVariable(routePath: string): string {
|
|
815
|
-
return (
|
|
816
|
-
removeUnderscores(routePath)
|
|
817
|
-
?.replace(/\/\$\//g, '/splat/')
|
|
818
|
-
.replace(/\$$/g, 'splat')
|
|
819
|
-
.replace(/\$/g, '')
|
|
820
|
-
.split(/[/-]/g)
|
|
821
|
-
.map((d, i) => (i > 0 ? capitalize(d) : d))
|
|
822
|
-
.join('')
|
|
823
|
-
.replace(/([^a-zA-Z0-9]|[.])/gm, '')
|
|
824
|
-
.replace(/^(\d)/g, 'R$1') ?? ''
|
|
825
|
-
)
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
export function removeExt(d: string, keepExtension: boolean = false) {
|
|
829
|
-
return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d
|
|
830
|
-
}
|
|
831
|
-
|
|
832
668
|
function spaces(d: number): string {
|
|
833
669
|
return Array.from({ length: d })
|
|
834
670
|
.map(() => ' ')
|
|
@@ -865,35 +701,14 @@ export function multiSortBy<T>(
|
|
|
865
701
|
.map(([d]) => d)
|
|
866
702
|
}
|
|
867
703
|
|
|
868
|
-
function capitalize(s: string) {
|
|
869
|
-
if (typeof s !== 'string') return ''
|
|
870
|
-
return s.charAt(0).toUpperCase() + s.slice(1)
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
function removeUnderscores(s?: string) {
|
|
874
|
-
return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\/_|_\/)/gi, '/')
|
|
875
|
-
}
|
|
876
|
-
|
|
877
704
|
function removeTrailingUnderscores(s?: string) {
|
|
878
705
|
return s?.replaceAll(/(_$)/gi, '').replaceAll(/(_\/)/gi, '/')
|
|
879
706
|
}
|
|
880
707
|
|
|
881
|
-
function replaceBackslash(s: string) {
|
|
882
|
-
return s.replaceAll(/\\/gi, '/')
|
|
883
|
-
}
|
|
884
|
-
|
|
885
708
|
function removeGroups(s: string) {
|
|
886
709
|
return s.replace(possiblyNestedRouteGroupPatternRegex, '')
|
|
887
710
|
}
|
|
888
711
|
|
|
889
|
-
function removeTrailingSlash(s: string) {
|
|
890
|
-
return s.replace(/\/$/, '')
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
function determineInitialRoutePath(routePath: string) {
|
|
894
|
-
return cleanPath(`/${routePath.split('.').join('/')}`) || ''
|
|
895
|
-
}
|
|
896
|
-
|
|
897
712
|
/**
|
|
898
713
|
* The `node.path` is used as the `id` in the route definition.
|
|
899
714
|
* This function checks if the given node has a parent and if so, it determines the correct path for the given node.
|
|
@@ -902,7 +717,7 @@ function determineInitialRoutePath(routePath: string) {
|
|
|
902
717
|
*/
|
|
903
718
|
function determineNodePath(node: RouteNode) {
|
|
904
719
|
return (node.path = node.parent
|
|
905
|
-
? node.routePath?.replace(node.parent.routePath
|
|
720
|
+
? node.routePath?.replace(node.parent.routePath ?? '', '') || '/'
|
|
906
721
|
: node.routePath)
|
|
907
722
|
}
|
|
908
723
|
|
|
@@ -986,7 +801,7 @@ export const inferPath = (routeNode: RouteNode): string => {
|
|
|
986
801
|
: (routeNode.cleanedPath?.replace(/\/$/, '') ?? '')
|
|
987
802
|
}
|
|
988
803
|
|
|
989
|
-
function getFilePathIdAndRouteIdFromPath(pathname
|
|
804
|
+
function getFilePathIdAndRouteIdFromPath(pathname?: string) {
|
|
990
805
|
const filePathId = removeTrailingUnderscores(pathname)
|
|
991
806
|
const id = removeGroups(filePathId ?? '')
|
|
992
807
|
|
|
@@ -1044,13 +859,14 @@ export type StartAPIRoutePathSegment = {
|
|
|
1044
859
|
*/
|
|
1045
860
|
export function startAPIRouteSegmentsFromTSRFilePath(
|
|
1046
861
|
src: string,
|
|
862
|
+
config: Config,
|
|
1047
863
|
): Array<StartAPIRoutePathSegment> {
|
|
1048
864
|
const routePath = determineInitialRoutePath(src)
|
|
1049
865
|
|
|
1050
866
|
const parts = routePath
|
|
1051
867
|
.replaceAll('.', '/')
|
|
1052
868
|
.split('/')
|
|
1053
|
-
.filter((p) => !!p && p !==
|
|
869
|
+
.filter((p) => !!p && p !== config.indexToken)
|
|
1054
870
|
const segments: Array<StartAPIRoutePathSegment> = parts.map((part) => {
|
|
1055
871
|
if (part.startsWith('$')) {
|
|
1056
872
|
if (part === '$') {
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type RouteNode = {
|
|
2
|
+
filePath: string
|
|
3
|
+
fullPath: string
|
|
4
|
+
variableName: string
|
|
5
|
+
routePath?: string
|
|
6
|
+
cleanedPath?: string
|
|
7
|
+
path?: string
|
|
8
|
+
isNonPath?: boolean
|
|
9
|
+
isLayout?: boolean
|
|
10
|
+
isVirtualParentRequired?: boolean
|
|
11
|
+
isVirtualParentRoute?: boolean
|
|
12
|
+
isRoute?: boolean
|
|
13
|
+
isAPIRoute?: boolean
|
|
14
|
+
isLoader?: boolean
|
|
15
|
+
isComponent?: boolean
|
|
16
|
+
isErrorComponent?: boolean
|
|
17
|
+
isPendingComponent?: boolean
|
|
18
|
+
isVirtual?: boolean
|
|
19
|
+
isLazy?: boolean
|
|
20
|
+
isRoot?: boolean
|
|
21
|
+
children?: Array<RouteNode>
|
|
22
|
+
parent?: RouteNode
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface GetRouteNodesResult {
|
|
26
|
+
rootRouteNode?: RouteNode
|
|
27
|
+
routeNodes: Array<RouteNode>
|
|
28
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -26,3 +26,46 @@ export function logging(config: { disabled: boolean }) {
|
|
|
26
26
|
},
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
export function removeLeadingSlash(path: string): string {
|
|
31
|
+
return path.replace(/^\//, '')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function removeTrailingSlash(s: string) {
|
|
35
|
+
return s.replace(/\/$/, '')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function determineInitialRoutePath(routePath: string) {
|
|
39
|
+
return cleanPath(`/${routePath.split('.').join('/')}`) || ''
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function replaceBackslash(s: string) {
|
|
43
|
+
return s.replaceAll(/\\/gi, '/')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function routePathToVariable(routePath: string): string {
|
|
47
|
+
return (
|
|
48
|
+
removeUnderscores(routePath)
|
|
49
|
+
?.replace(/\/\$\//g, '/splat/')
|
|
50
|
+
.replace(/\$$/g, 'splat')
|
|
51
|
+
.replace(/\$/g, '')
|
|
52
|
+
.split(/[/-]/g)
|
|
53
|
+
.map((d, i) => (i > 0 ? capitalize(d) : d))
|
|
54
|
+
.join('')
|
|
55
|
+
.replace(/([^a-zA-Z0-9]|[.])/gm, '')
|
|
56
|
+
.replace(/^(\d)/g, 'R$1') ?? ''
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function removeUnderscores(s?: string) {
|
|
61
|
+
return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\/_|_\/)/gi, '/')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function capitalize(s: string) {
|
|
65
|
+
if (typeof s !== 'string') return ''
|
|
66
|
+
return s.charAt(0).toUpperCase() + s.slice(1)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function removeExt(d: string, keepExtension: boolean = false) {
|
|
70
|
+
return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d
|
|
71
|
+
}
|