@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/dist/esm/utils.js
CHANGED
|
@@ -6,23 +6,16 @@ class RoutePrefixMap {
|
|
|
6
6
|
constructor(routes) {
|
|
7
7
|
this.prefixToRoute = /* @__PURE__ */ new Map();
|
|
8
8
|
this.layoutRoutes = [];
|
|
9
|
-
this.nonNestedRoutes = [];
|
|
10
9
|
for (const route of routes) {
|
|
11
10
|
if (!route.routePath || route.routePath === `/${rootPathId}`) continue;
|
|
12
11
|
this.prefixToRoute.set(route.routePath, route);
|
|
13
12
|
if (route._fsRouteType === "pathless_layout" || route._fsRouteType === "layout" || route._fsRouteType === "__root") {
|
|
14
13
|
this.layoutRoutes.push(route);
|
|
15
14
|
}
|
|
16
|
-
if (route._isExperimentalNonNestedRoute) {
|
|
17
|
-
this.nonNestedRoutes.push(route);
|
|
18
|
-
}
|
|
19
15
|
}
|
|
20
16
|
this.layoutRoutes.sort(
|
|
21
17
|
(a, b) => (b.routePath?.length ?? 0) - (a.routePath?.length ?? 0)
|
|
22
18
|
);
|
|
23
|
-
this.nonNestedRoutes.sort(
|
|
24
|
-
(a, b) => (b.routePath?.length ?? 0) - (a.routePath?.length ?? 0)
|
|
25
|
-
);
|
|
26
19
|
}
|
|
27
20
|
/**
|
|
28
21
|
* Find the longest matching parent route for a given path.
|
|
@@ -42,26 +35,6 @@ class RoutePrefixMap {
|
|
|
42
35
|
}
|
|
43
36
|
return null;
|
|
44
37
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Find parent for non-nested routes (needs layout route matching).
|
|
47
|
-
*/
|
|
48
|
-
findParentForNonNested(routePath, originalRoutePath, nonNestedSegments) {
|
|
49
|
-
for (const route of this.nonNestedRoutes) {
|
|
50
|
-
if (route.routePath !== routePath && originalRoutePath?.startsWith(`${route.originalRoutePath}/`)) {
|
|
51
|
-
return route;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
for (const route of this.layoutRoutes) {
|
|
55
|
-
if (route.routePath === "/") continue;
|
|
56
|
-
if (nonNestedSegments.some((seg) => seg === `${route.originalRoutePath}_`)) {
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
if (routePath.startsWith(`${route.routePath}/`) && route.routePath !== routePath) {
|
|
60
|
-
return route;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
38
|
/**
|
|
66
39
|
* Check if a route exists at the given path.
|
|
67
40
|
*/
|
|
@@ -123,38 +96,25 @@ function removeTrailingSlash(s) {
|
|
|
123
96
|
}
|
|
124
97
|
const BRACKET_CONTENT_RE = /\[(.*?)\]/g;
|
|
125
98
|
const SPLIT_REGEX = new RegExp("(?<!\\[)\\.(?!\\])", "g");
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
99
|
+
const DISALLOWED_ESCAPE_CHARS = /* @__PURE__ */ new Set([
|
|
100
|
+
"/",
|
|
101
|
+
"\\",
|
|
102
|
+
"?",
|
|
103
|
+
"#",
|
|
104
|
+
":",
|
|
105
|
+
"*",
|
|
106
|
+
"<",
|
|
107
|
+
">",
|
|
108
|
+
"|",
|
|
109
|
+
"!",
|
|
110
|
+
"$",
|
|
111
|
+
"%"
|
|
112
|
+
]);
|
|
113
|
+
function determineInitialRoutePath(routePath) {
|
|
141
114
|
const originalRoutePath = cleanPath(
|
|
142
115
|
`/${(cleanPath(routePath) || "").split(SPLIT_REGEX).join("/")}`
|
|
143
116
|
) || "";
|
|
144
|
-
const
|
|
145
|
-
originalRoutePath,
|
|
146
|
-
config
|
|
147
|
-
);
|
|
148
|
-
let cleanedRoutePath = routePath;
|
|
149
|
-
if (config?.experimental?.nonNestedRoutes) {
|
|
150
|
-
if (originalRoutePath !== `/${rootPathId}`) {
|
|
151
|
-
cleanedRoutePath = removeTrailingUnderscores(
|
|
152
|
-
originalRoutePath,
|
|
153
|
-
config.routeToken
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
const parts = cleanedRoutePath.split(SPLIT_REGEX);
|
|
117
|
+
const parts = routePath.split(SPLIT_REGEX);
|
|
158
118
|
const escapedParts = parts.map((part) => {
|
|
159
119
|
let match;
|
|
160
120
|
while ((match = BRACKET_CONTENT_RE.exec(part)) !== null) {
|
|
@@ -176,10 +136,18 @@ Please remove and/or replace them.`
|
|
|
176
136
|
const final = cleanPath(`/${escapedParts.join("/")}`) || "";
|
|
177
137
|
return {
|
|
178
138
|
routePath: final,
|
|
179
|
-
isExperimentalNonNestedRoute,
|
|
180
139
|
originalRoutePath
|
|
181
140
|
};
|
|
182
141
|
}
|
|
142
|
+
function isFullyEscapedSegment(originalSegment) {
|
|
143
|
+
return originalSegment.startsWith("[") && originalSegment.endsWith("]") && !originalSegment.slice(1, -1).includes("[") && !originalSegment.slice(1, -1).includes("]");
|
|
144
|
+
}
|
|
145
|
+
function hasEscapedLeadingUnderscore(originalSegment) {
|
|
146
|
+
return originalSegment.startsWith("[_]") || originalSegment.startsWith("[_") && isFullyEscapedSegment(originalSegment);
|
|
147
|
+
}
|
|
148
|
+
function hasEscapedTrailingUnderscore(originalSegment) {
|
|
149
|
+
return originalSegment.endsWith("[_]") || originalSegment.endsWith("_]") && isFullyEscapedSegment(originalSegment);
|
|
150
|
+
}
|
|
183
151
|
const backslashRegex = /\\/g;
|
|
184
152
|
function replaceBackslash(s) {
|
|
185
153
|
return s.replace(backslashRegex, "/");
|
|
@@ -234,24 +202,39 @@ const underscoreSlashRegex = /(\/_|_\/)/gi;
|
|
|
234
202
|
function removeUnderscores(s) {
|
|
235
203
|
return s?.replace(underscoreStartEndRegex, "").replace(underscoreSlashRegex, "/");
|
|
236
204
|
}
|
|
237
|
-
function
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
205
|
+
function removeUnderscoresWithEscape(routePath, originalPath) {
|
|
206
|
+
if (!routePath) return "";
|
|
207
|
+
if (!originalPath) return removeUnderscores(routePath) ?? "";
|
|
208
|
+
const routeSegments = routePath.split("/");
|
|
209
|
+
const originalSegments = originalPath.split("/");
|
|
210
|
+
const newSegments = routeSegments.map((segment, i) => {
|
|
211
|
+
const originalSegment = originalSegments[i] || "";
|
|
212
|
+
const leadingEscaped = hasEscapedLeadingUnderscore(originalSegment);
|
|
213
|
+
const trailingEscaped = hasEscapedTrailingUnderscore(originalSegment);
|
|
214
|
+
let result = segment;
|
|
215
|
+
if (result.startsWith("_") && !leadingEscaped) {
|
|
216
|
+
result = result.slice(1);
|
|
217
|
+
}
|
|
218
|
+
if (result.endsWith("_") && !trailingEscaped) {
|
|
219
|
+
result = result.slice(0, -1);
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
});
|
|
223
|
+
return newSegments.join("/");
|
|
224
|
+
}
|
|
225
|
+
function removeLayoutSegmentsWithEscape(routePath = "/", originalPath) {
|
|
226
|
+
if (!originalPath) return removeLayoutSegments(routePath);
|
|
227
|
+
const routeSegments = routePath.split("/");
|
|
228
|
+
const originalSegments = originalPath.split("/");
|
|
229
|
+
const newSegments = routeSegments.filter((segment, i) => {
|
|
230
|
+
const originalSegment = originalSegments[i] || "";
|
|
231
|
+
return !isSegmentPathless(segment, originalSegment);
|
|
232
|
+
});
|
|
233
|
+
return newSegments.join("/");
|
|
234
|
+
}
|
|
235
|
+
function isSegmentPathless(segment, originalSegment) {
|
|
236
|
+
if (!segment.startsWith("_")) return false;
|
|
237
|
+
return !hasEscapedLeadingUnderscore(originalSegment);
|
|
255
238
|
}
|
|
256
239
|
function capitalize(s) {
|
|
257
240
|
if (typeof s !== "string") return "";
|
|
@@ -306,36 +289,10 @@ function removeLastSegmentFromPath(routePath = "/") {
|
|
|
306
289
|
segments.pop();
|
|
307
290
|
return segments.join("/");
|
|
308
291
|
}
|
|
309
|
-
|
|
310
|
-
const openBracketRegex = /\[/g;
|
|
311
|
-
const closeBracketRegex = /\]/g;
|
|
312
|
-
function getNonNestedSegments(routePath) {
|
|
313
|
-
nonNestedSegmentRegex.lastIndex = 0;
|
|
314
|
-
const result = [];
|
|
315
|
-
for (const match of routePath.matchAll(nonNestedSegmentRegex)) {
|
|
316
|
-
const beforeStr = routePath.substring(0, match.index);
|
|
317
|
-
openBracketRegex.lastIndex = 0;
|
|
318
|
-
closeBracketRegex.lastIndex = 0;
|
|
319
|
-
const openBrackets = beforeStr.match(openBracketRegex)?.length ?? 0;
|
|
320
|
-
const closeBrackets = beforeStr.match(closeBracketRegex)?.length ?? 0;
|
|
321
|
-
if (openBrackets === closeBrackets) {
|
|
322
|
-
result.push(routePath.substring(0, match.index + 1));
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
return result.reverse();
|
|
326
|
-
}
|
|
327
|
-
function hasParentRoute(prefixMap, node, routePathToCheck, originalRoutePathToCheck) {
|
|
292
|
+
function hasParentRoute(prefixMap, node, routePathToCheck) {
|
|
328
293
|
if (!routePathToCheck || routePathToCheck === "/") {
|
|
329
294
|
return null;
|
|
330
295
|
}
|
|
331
|
-
if (node._isExperimentalNonNestedRoute && originalRoutePathToCheck) {
|
|
332
|
-
const nonNestedSegments = getNonNestedSegments(originalRoutePathToCheck);
|
|
333
|
-
return prefixMap.findParentForNonNested(
|
|
334
|
-
routePathToCheck,
|
|
335
|
-
originalRoutePathToCheck,
|
|
336
|
-
nonNestedSegments
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
296
|
return prefixMap.findParent(routePathToCheck);
|
|
340
297
|
}
|
|
341
298
|
const getResolvedRouteNodeVariableName = (routeNode) => {
|
|
@@ -350,24 +307,27 @@ function isRouteNodeValidForAugmentation(routeNode) {
|
|
|
350
307
|
const inferPath = (routeNode) => {
|
|
351
308
|
return routeNode.cleanedPath === "/" ? routeNode.cleanedPath : routeNode.cleanedPath?.replace(/\/$/, "") ?? "";
|
|
352
309
|
};
|
|
353
|
-
const inferFullPath = (routeNode
|
|
310
|
+
const inferFullPath = (routeNode) => {
|
|
354
311
|
const fullPath = removeGroups(
|
|
355
|
-
(
|
|
312
|
+
removeUnderscoresWithEscape(
|
|
313
|
+
removeLayoutSegmentsWithEscape(
|
|
314
|
+
routeNode.routePath,
|
|
315
|
+
routeNode.originalRoutePath
|
|
316
|
+
),
|
|
317
|
+
routeNode.originalRoutePath
|
|
318
|
+
)
|
|
356
319
|
);
|
|
357
320
|
return routeNode.cleanedPath === "/" ? fullPath : fullPath.replace(/\/$/, "");
|
|
358
321
|
};
|
|
359
|
-
const createRouteNodesByFullPath = (routeNodes
|
|
322
|
+
const createRouteNodesByFullPath = (routeNodes) => {
|
|
360
323
|
return new Map(
|
|
361
|
-
routeNodes.map((routeNode) => [
|
|
362
|
-
inferFullPath(routeNode, config),
|
|
363
|
-
routeNode
|
|
364
|
-
])
|
|
324
|
+
routeNodes.map((routeNode) => [inferFullPath(routeNode), routeNode])
|
|
365
325
|
);
|
|
366
326
|
};
|
|
367
|
-
const createRouteNodesByTo = (routeNodes
|
|
327
|
+
const createRouteNodesByTo = (routeNodes) => {
|
|
368
328
|
return new Map(
|
|
369
329
|
dedupeBranchesAndIndexRoutes(routeNodes).map((routeNode) => [
|
|
370
|
-
inferTo(routeNode
|
|
330
|
+
inferTo(routeNode),
|
|
371
331
|
routeNode
|
|
372
332
|
])
|
|
373
333
|
);
|
|
@@ -380,8 +340,8 @@ const createRouteNodesById = (routeNodes) => {
|
|
|
380
340
|
})
|
|
381
341
|
);
|
|
382
342
|
};
|
|
383
|
-
const inferTo = (routeNode
|
|
384
|
-
const fullPath = inferFullPath(routeNode
|
|
343
|
+
const inferTo = (routeNode) => {
|
|
344
|
+
const fullPath = inferFullPath(routeNode);
|
|
385
345
|
if (fullPath === "/") return fullPath;
|
|
386
346
|
return fullPath.replace(/\/$/, "");
|
|
387
347
|
};
|
|
@@ -405,7 +365,7 @@ function checkUnique(routes, key) {
|
|
|
405
365
|
}
|
|
406
366
|
function checkRouteFullPathUniqueness(_routes, config) {
|
|
407
367
|
const routes = _routes.map((d) => {
|
|
408
|
-
const inferredFullPath = inferFullPath(d
|
|
368
|
+
const inferredFullPath = inferFullPath(d);
|
|
409
369
|
return { ...d, inferredFullPath };
|
|
410
370
|
});
|
|
411
371
|
const conflictingFiles = checkUnique(routes, "inferredFullPath");
|
|
@@ -504,7 +464,7 @@ function buildFileRoutesByPathInterface(opts) {
|
|
|
504
464
|
return `'${filePathId}': {
|
|
505
465
|
id: '${filePathId}'
|
|
506
466
|
path: '${inferPath(routeNode)}'
|
|
507
|
-
fullPath: '${inferFullPath(routeNode
|
|
467
|
+
fullPath: '${inferFullPath(routeNode)}'
|
|
508
468
|
preLoaderRoute: ${preloaderRoute}
|
|
509
469
|
parentRoute: typeof ${parent}
|
|
510
470
|
}`;
|
|
@@ -545,31 +505,6 @@ function getImportForRouteNode(node, config, generatedRouteTreePath, root) {
|
|
|
545
505
|
]
|
|
546
506
|
};
|
|
547
507
|
}
|
|
548
|
-
function isValidNonNestedRoute(normalizedRoutePath, config) {
|
|
549
|
-
if (!config?.experimental?.nonNestedRoutes) {
|
|
550
|
-
return false;
|
|
551
|
-
}
|
|
552
|
-
const segments = normalizedRoutePath.split("/").filter(Boolean);
|
|
553
|
-
if (segments.length === 0) {
|
|
554
|
-
return false;
|
|
555
|
-
}
|
|
556
|
-
const lastRouteSegment = segments[segments.length - 1];
|
|
557
|
-
if (lastRouteSegment === rootPathId) {
|
|
558
|
-
return false;
|
|
559
|
-
}
|
|
560
|
-
if (lastRouteSegment !== config.indexToken && lastRouteSegment !== config.routeToken && lastRouteSegment.endsWith("_")) {
|
|
561
|
-
return true;
|
|
562
|
-
}
|
|
563
|
-
for (const segment of segments.slice(0, -1).reverse()) {
|
|
564
|
-
if (segment === config.routeToken) {
|
|
565
|
-
return false;
|
|
566
|
-
}
|
|
567
|
-
if (segment.endsWith("_")) {
|
|
568
|
-
return true;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
return false;
|
|
572
|
-
}
|
|
573
508
|
export {
|
|
574
509
|
RoutePrefixMap,
|
|
575
510
|
buildFileRoutesByPathInterface,
|
|
@@ -589,25 +524,26 @@ export {
|
|
|
589
524
|
format,
|
|
590
525
|
getImportForRouteNode,
|
|
591
526
|
getImportPath,
|
|
592
|
-
getNonNestedSegments,
|
|
593
527
|
getResolvedRouteNodeVariableName,
|
|
528
|
+
hasEscapedLeadingUnderscore,
|
|
529
|
+
hasEscapedTrailingUnderscore,
|
|
594
530
|
hasParentRoute,
|
|
595
531
|
inferFullPath,
|
|
596
532
|
inferPath,
|
|
597
533
|
inferTo,
|
|
598
534
|
isRouteNodeValidForAugmentation,
|
|
599
|
-
|
|
535
|
+
isSegmentPathless,
|
|
600
536
|
mergeImportDeclarations,
|
|
601
537
|
multiSortBy,
|
|
602
538
|
removeExt,
|
|
603
539
|
removeGroups,
|
|
604
540
|
removeLastSegmentFromPath,
|
|
605
541
|
removeLayoutSegments,
|
|
542
|
+
removeLayoutSegmentsWithEscape,
|
|
606
543
|
removeLeadingSlash,
|
|
607
|
-
removeLeadingUnderscores,
|
|
608
544
|
removeTrailingSlash,
|
|
609
|
-
removeTrailingUnderscores,
|
|
610
545
|
removeUnderscores,
|
|
546
|
+
removeUnderscoresWithEscape,
|
|
611
547
|
replaceBackslash,
|
|
612
548
|
resetRegex,
|
|
613
549
|
routePathToVariable,
|
package/dist/esm/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/prefer-for-of */\nimport * as fsp from 'node:fs/promises'\nimport path from 'node:path'\nimport * as prettier from 'prettier'\nimport { rootPathId } from './filesystem/physical/rootPathId'\nimport type { Config } from './config'\nimport type { ImportDeclaration, RouteNode } from './types'\n\n/**\n * Prefix map for O(1) parent route lookups.\n * Maps each route path prefix to the route node that owns that prefix.\n * Enables finding longest matching parent without linear search.\n */\nexport class RoutePrefixMap {\n private prefixToRoute: Map<string, RouteNode> = new Map()\n private layoutRoutes: Array<RouteNode> = []\n private nonNestedRoutes: Array<RouteNode> = []\n\n constructor(routes: Array<RouteNode>) {\n for (const route of routes) {\n if (!route.routePath || route.routePath === `/${rootPathId}`) continue\n\n // Index by exact path for direct lookups\n this.prefixToRoute.set(route.routePath, route)\n\n // Track layout routes separately for non-nested route handling\n if (\n route._fsRouteType === 'pathless_layout' ||\n route._fsRouteType === 'layout' ||\n route._fsRouteType === '__root'\n ) {\n this.layoutRoutes.push(route)\n }\n\n // Track non-nested routes separately\n if (route._isExperimentalNonNestedRoute) {\n this.nonNestedRoutes.push(route)\n }\n }\n\n // Sort by path length descending for longest-match-first\n this.layoutRoutes.sort(\n (a, b) => (b.routePath?.length ?? 0) - (a.routePath?.length ?? 0),\n )\n this.nonNestedRoutes.sort(\n (a, b) => (b.routePath?.length ?? 0) - (a.routePath?.length ?? 0),\n )\n }\n\n /**\n * Find the longest matching parent route for a given path.\n * O(k) where k is the number of path segments, not O(n) routes.\n */\n findParent(routePath: string): RouteNode | null {\n if (!routePath || routePath === '/') return null\n\n // Walk up the path segments\n let searchPath = routePath\n while (searchPath.length > 0) {\n const lastSlash = searchPath.lastIndexOf('/')\n if (lastSlash <= 0) break\n\n searchPath = searchPath.substring(0, lastSlash)\n const parent = this.prefixToRoute.get(searchPath)\n if (parent && parent.routePath !== routePath) {\n return parent\n }\n }\n return null\n }\n\n /**\n * Find parent for non-nested routes (needs layout route matching).\n */\n findParentForNonNested(\n routePath: string,\n originalRoutePath: string | undefined,\n nonNestedSegments: Array<string>,\n ): RouteNode | null {\n // First check for other non-nested routes that are prefixes\n // Use pre-sorted array for longest-match-first\n for (const route of this.nonNestedRoutes) {\n if (\n route.routePath !== routePath &&\n originalRoutePath?.startsWith(`${route.originalRoutePath}/`)\n ) {\n return route\n }\n }\n\n // Then check layout routes\n for (const route of this.layoutRoutes) {\n if (route.routePath === '/') continue\n\n // Skip if this route's original path + underscore matches a non-nested segment\n if (\n nonNestedSegments.some((seg) => seg === `${route.originalRoutePath}_`)\n ) {\n continue\n }\n\n // Check if this layout route is a prefix of the path we're looking for\n if (\n routePath.startsWith(`${route.routePath}/`) &&\n route.routePath !== routePath\n ) {\n return route\n }\n }\n\n return null\n }\n\n /**\n * Check if a route exists at the given path.\n */\n has(routePath: string): boolean {\n return this.prefixToRoute.has(routePath)\n }\n\n /**\n * Get a route by exact path.\n */\n get(routePath: string): RouteNode | undefined {\n return this.prefixToRoute.get(routePath)\n }\n}\n\nexport function multiSortBy<T>(\n arr: Array<T>,\n accessors: Array<(item: T) => any> = [(d) => d],\n): Array<T> {\n const len = arr.length\n // Pre-compute all accessor values to avoid repeated function calls during sort\n const indexed: Array<{ item: T; index: number; keys: Array<any> }> =\n new Array(len)\n for (let i = 0; i < len; i++) {\n const item = arr[i]!\n const keys = new Array(accessors.length)\n for (let j = 0; j < accessors.length; j++) {\n keys[j] = accessors[j]!(item)\n }\n indexed[i] = { item, index: i, keys }\n }\n\n indexed.sort((a, b) => {\n for (let j = 0; j < accessors.length; j++) {\n const ao = a.keys[j]\n const bo = b.keys[j]\n\n if (typeof ao === 'undefined') {\n if (typeof bo === 'undefined') {\n continue\n }\n return 1\n }\n\n if (ao === bo) {\n continue\n }\n\n return ao > bo ? 1 : -1\n }\n\n return a.index - b.index\n })\n\n const result: Array<T> = new Array(len)\n for (let i = 0; i < len; i++) {\n result[i] = indexed[i]!.item\n }\n return result\n}\n\nexport function cleanPath(path: string) {\n // remove double slashes\n return path.replace(/\\/{2,}/g, '/')\n}\n\nexport function trimPathLeft(path: string) {\n return path === '/' ? path : path.replace(/^\\/{1,}/, '')\n}\n\nexport function removeLeadingSlash(path: string): string {\n return path.replace(/^\\//, '')\n}\n\nexport function removeTrailingSlash(s: string) {\n return s.replace(/\\/$/, '')\n}\n\nconst BRACKET_CONTENT_RE = /\\[(.*?)\\]/g\nconst SPLIT_REGEX = /(?<!\\[)\\.(?!\\])/g\n\nexport function determineInitialRoutePath(\n routePath: string,\n config?: Pick<Config, 'experimental' | 'routeToken' | 'indexToken'>,\n) {\n const DISALLOWED_ESCAPE_CHARS = new Set([\n '/',\n '\\\\',\n '?',\n '#',\n ':',\n '*',\n '<',\n '>',\n '|',\n '!',\n '$',\n '%',\n ])\n\n const originalRoutePath =\n cleanPath(\n `/${(cleanPath(routePath) || '').split(SPLIT_REGEX).join('/')}`,\n ) || ''\n\n // check if the route path is a valid non-nested path,\n // TODO with new major rename to reflect not experimental anymore\n const isExperimentalNonNestedRoute = isValidNonNestedRoute(\n originalRoutePath,\n config,\n )\n\n let cleanedRoutePath = routePath\n\n // we already identified the path as non-nested and can now remove the trailing underscores\n // we need to do this now before we encounter any escaped trailing underscores\n // this way we can be sure any remaining trailing underscores should remain\n // TODO with new major we can remove check and always remove leading underscores\n if (config?.experimental?.nonNestedRoutes) {\n // we should leave trailing underscores if the route path is the root path\n if (originalRoutePath !== `/${rootPathId}`) {\n // remove trailing underscores on various path segments\n cleanedRoutePath = removeTrailingUnderscores(\n originalRoutePath,\n config.routeToken,\n )\n }\n }\n\n const parts = cleanedRoutePath.split(SPLIT_REGEX)\n\n // Escape any characters that in square brackets\n // we keep the original path untouched\n const escapedParts = parts.map((part) => {\n // Check if any disallowed characters are used in brackets\n\n let match\n while ((match = BRACKET_CONTENT_RE.exec(part)) !== null) {\n const character = match[1]\n if (character === undefined) continue\n if (DISALLOWED_ESCAPE_CHARS.has(character)) {\n console.error(\n `Error: Disallowed character \"${character}\" found in square brackets in route path \"${routePath}\".\\nYou cannot use any of the following characters in square brackets: ${Array.from(\n DISALLOWED_ESCAPE_CHARS,\n ).join(', ')}\\nPlease remove and/or replace them.`,\n )\n process.exit(1)\n }\n }\n\n // Since this split segment is safe at this point, we can\n // remove the brackets and replace them with the content inside\n return part.replace(BRACKET_CONTENT_RE, '$1')\n })\n\n // If the syntax for prefix/suffix is different, from the path\n // matching internals of router-core, we'd perform those changes here\n // on the `escapedParts` array before it is joined back together in\n // `final`\n\n const final = cleanPath(`/${escapedParts.join('/')}`) || ''\n\n return {\n routePath: final,\n isExperimentalNonNestedRoute,\n originalRoutePath,\n }\n}\n\nconst backslashRegex = /\\\\/g\n\nexport function replaceBackslash(s: string) {\n return s.replace(backslashRegex, '/')\n}\n\nconst alphanumericRegex = /[a-zA-Z0-9_]/\nconst splatSlashRegex = /\\/\\$\\//g\nconst trailingSplatRegex = /\\$$/g\nconst bracketSplatRegex = /\\$\\{\\$\\}/g\nconst dollarSignRegex = /\\$/g\nconst splitPathRegex = /[/-]/g\nconst leadingDigitRegex = /^(\\d)/g\n\nconst toVariableSafeChar = (char: string): string => {\n if (alphanumericRegex.test(char)) {\n return char // Keep alphanumeric characters and underscores as is\n }\n\n // Replace special characters with meaningful text equivalents\n switch (char) {\n case '.':\n return 'Dot'\n case '-':\n return 'Dash'\n case '@':\n return 'At'\n case '(':\n return '' // Removed since route groups use parentheses\n case ')':\n return '' // Removed since route groups use parentheses\n case ' ':\n return '' // Remove spaces\n default:\n return `Char${char.charCodeAt(0)}` // For any other characters\n }\n}\n\nexport function routePathToVariable(routePath: string): string {\n const cleaned = removeUnderscores(routePath)\n if (!cleaned) return ''\n\n const parts = cleaned\n .replace(splatSlashRegex, '/splat/')\n .replace(trailingSplatRegex, 'splat')\n .replace(bracketSplatRegex, 'splat')\n .replace(dollarSignRegex, '')\n .split(splitPathRegex)\n\n let result = ''\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]!\n const segment = i > 0 ? capitalize(part) : part\n for (let j = 0; j < segment.length; j++) {\n result += toVariableSafeChar(segment[j]!)\n }\n }\n\n return result.replace(leadingDigitRegex, 'R$1')\n}\n\nconst underscoreStartEndRegex = /(^_|_$)/gi\nconst underscoreSlashRegex = /(\\/_|_\\/)/gi\n\nexport function removeUnderscores(s?: string) {\n return s\n ?.replace(underscoreStartEndRegex, '')\n .replace(underscoreSlashRegex, '/')\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nexport function removeLeadingUnderscores(s: string, routeToken: string) {\n if (!s) return s\n\n const hasLeadingUnderscore = routeToken[0] === '_'\n\n const routeTokenToExclude = hasLeadingUnderscore\n ? routeToken.slice(1)\n : routeToken\n\n const escapedRouteToken = escapeRegExp(routeTokenToExclude)\n\n const leadingUnderscoreRegex = hasLeadingUnderscore\n ? new RegExp(`(?<=^|\\\\/)_(?!${escapedRouteToken})`, 'g')\n : new RegExp(`(?<=^|\\\\/)_`, 'g')\n\n return s.replaceAll(leadingUnderscoreRegex, '')\n}\n\nexport function removeTrailingUnderscores(s: string, routeToken: string) {\n if (!s) return s\n\n const hasTrailingUnderscore = routeToken.slice(-1) === '_'\n\n const routeTokenToExclude = hasTrailingUnderscore\n ? routeToken.slice(0, -1)\n : routeToken\n\n const escapedRouteToken = escapeRegExp(routeTokenToExclude)\n\n const trailingUnderscoreRegex = hasTrailingUnderscore\n ? new RegExp(`(?<!${escapedRouteToken})_(?=\\\\/|$)`, 'g')\n : new RegExp(`_(?=\\\\/)|_$`, 'g')\n\n return s.replaceAll(trailingUnderscoreRegex, '')\n}\n\nexport function capitalize(s: string) {\n if (typeof s !== 'string') return ''\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\nexport function removeExt(d: string, keepExtension: boolean = false) {\n return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d\n}\n\n/**\n * This function writes to a file if the content is different.\n *\n * @param filepath The path to the file\n * @param content Original content\n * @param incomingContent New content\n * @param callbacks Callbacks to run before and after writing\n * @returns Whether the file was written\n */\nexport async function writeIfDifferent(\n filepath: string,\n content: string,\n incomingContent: string,\n callbacks?: { beforeWrite?: () => void; afterWrite?: () => void },\n): Promise<boolean> {\n if (content !== incomingContent) {\n callbacks?.beforeWrite?.()\n await fsp.writeFile(filepath, incomingContent)\n callbacks?.afterWrite?.()\n return true\n }\n return false\n}\n\n/**\n * This function formats the source code using the default formatter (Prettier).\n *\n * @param source The content to format\n * @param config The configuration object\n * @returns The formatted content\n */\nexport async function format(\n source: string,\n config: {\n quoteStyle: 'single' | 'double'\n semicolons: boolean\n },\n): Promise<string> {\n const prettierOptions: prettier.Config = {\n semi: config.semicolons,\n singleQuote: config.quoteStyle === 'single',\n parser: 'typescript',\n }\n return prettier.format(source, prettierOptions)\n}\n\n/**\n * This function resets the regex index to 0 so that it can be reused\n * without having to create a new regex object or worry about the last\n * state when using the global flag.\n *\n * @param regex The regex object to reset\n * @returns\n */\nexport function resetRegex(regex: RegExp) {\n regex.lastIndex = 0\n return\n}\n\n/**\n * This function checks if a file exists.\n *\n * @param file The path to the file\n * @returns Whether the file exists\n */\nexport async function checkFileExists(file: string) {\n try {\n await fsp.access(file, fsp.constants.F_OK)\n return true\n } catch {\n return false\n }\n}\n\nconst possiblyNestedRouteGroupPatternRegex = /\\([^/]+\\)\\/?/g\nexport function removeGroups(s: string) {\n return s.replace(possiblyNestedRouteGroupPatternRegex, '')\n}\n\n/**\n * Removes all segments from a given path that start with an underscore ('_').\n *\n * @param {string} routePath - The path from which to remove segments. Defaults to '/'.\n * @returns {string} The path with all underscore-prefixed segments removed.\n * @example\n * removeLayoutSegments('/workspace/_auth/foo') // '/workspace/foo'\n */\nexport function removeLayoutSegments(routePath: string = '/'): string {\n const segments = routePath.split('/')\n const newSegments = segments.filter((segment) => !segment.startsWith('_'))\n return newSegments.join('/')\n}\n\n/**\n * The `node.path` is used as the `id` in the route definition.\n * This function checks if the given node has a parent and if so, it determines the correct path for the given node.\n * @param node - The node to determine the path for.\n * @returns The correct path for the given node.\n */\nexport function determineNodePath(node: RouteNode) {\n return (node.path = node.parent\n ? node.routePath?.replace(node.parent.routePath ?? '', '') || '/'\n : node.routePath)\n}\n\n/**\n * Removes the last segment from a given path. Segments are considered to be separated by a '/'.\n *\n * @param {string} routePath - The path from which to remove the last segment. Defaults to '/'.\n * @returns {string} The path with the last segment removed.\n * @example\n * removeLastSegmentFromPath('/workspace/_auth/foo') // '/workspace/_auth'\n */\nexport function removeLastSegmentFromPath(routePath: string = '/'): string {\n const segments = routePath.split('/')\n segments.pop() // Remove the last segment\n return segments.join('/')\n}\n\nconst nonNestedSegmentRegex = /_(?=\\/|$)/g\nconst openBracketRegex = /\\[/g\nconst closeBracketRegex = /\\]/g\n\n/**\n * Extracts non-nested segments from a route path.\n * Used for determining parent routes in non-nested route scenarios.\n */\nexport function getNonNestedSegments(routePath: string): Array<string> {\n nonNestedSegmentRegex.lastIndex = 0\n const result: Array<string> = []\n for (const match of routePath.matchAll(nonNestedSegmentRegex)) {\n const beforeStr = routePath.substring(0, match.index)\n openBracketRegex.lastIndex = 0\n closeBracketRegex.lastIndex = 0\n const openBrackets = beforeStr.match(openBracketRegex)?.length ?? 0\n const closeBrackets = beforeStr.match(closeBracketRegex)?.length ?? 0\n if (openBrackets === closeBrackets) {\n result.push(routePath.substring(0, match.index + 1))\n }\n }\n return result.reverse()\n}\n\n/**\n * Find parent route using RoutePrefixMap for O(k) lookups instead of O(n).\n */\nexport function hasParentRoute(\n prefixMap: RoutePrefixMap,\n node: RouteNode,\n routePathToCheck: string | undefined,\n originalRoutePathToCheck: string | undefined,\n): RouteNode | null {\n if (!routePathToCheck || routePathToCheck === '/') {\n return null\n }\n\n if (node._isExperimentalNonNestedRoute && originalRoutePathToCheck) {\n const nonNestedSegments = getNonNestedSegments(originalRoutePathToCheck)\n return prefixMap.findParentForNonNested(\n routePathToCheck,\n originalRoutePathToCheck,\n nonNestedSegments,\n )\n }\n\n return prefixMap.findParent(routePathToCheck)\n}\n\n/**\n * Gets the final variable name for a route\n */\nexport const getResolvedRouteNodeVariableName = (\n routeNode: RouteNode,\n): string => {\n return routeNode.children?.length\n ? `${routeNode.variableName}RouteWithChildren`\n : `${routeNode.variableName}Route`\n}\n\n/**\n * Checks if a given RouteNode is valid for augmenting it with typing based on conditions.\n * Also asserts that the RouteNode is defined.\n *\n * @param routeNode - The RouteNode to check.\n * @returns A boolean indicating whether the RouteNode is defined.\n */\nexport function isRouteNodeValidForAugmentation(\n routeNode?: RouteNode,\n): routeNode is RouteNode {\n if (!routeNode || routeNode.isVirtual) {\n return false\n }\n return true\n}\n\n/**\n * Infers the path for use by TS\n */\nexport const inferPath = (routeNode: RouteNode): string => {\n return routeNode.cleanedPath === '/'\n ? routeNode.cleanedPath\n : (routeNode.cleanedPath?.replace(/\\/$/, '') ?? '')\n}\n\n/**\n * Infers the full path for use by TS\n */\nexport const inferFullPath = (\n routeNode: RouteNode,\n config?: Pick<Config, 'experimental' | 'routeToken'>,\n): string => {\n // with new nonNestedPaths feature we can be sure any remaining trailing underscores are escaped and should remain\n // TODO with new major we can remove check and only remove leading underscores\n const fullPath = removeGroups(\n (config?.experimental?.nonNestedRoutes\n ? removeLayoutSegments(routeNode.routePath)\n : removeUnderscores(removeLayoutSegments(routeNode.routePath))) ?? '',\n )\n\n return routeNode.cleanedPath === '/' ? fullPath : fullPath.replace(/\\/$/, '')\n}\n\n/**\n * Creates a map from fullPath to routeNode\n */\nexport const createRouteNodesByFullPath = (\n routeNodes: Array<RouteNode>,\n config?: Pick<Config, 'experimental' | 'routeToken'>,\n): Map<string, RouteNode> => {\n return new Map(\n routeNodes.map((routeNode) => [\n inferFullPath(routeNode, config),\n routeNode,\n ]),\n )\n}\n\n/**\n * Create a map from 'to' to a routeNode\n */\nexport const createRouteNodesByTo = (\n routeNodes: Array<RouteNode>,\n config?: Pick<Config, 'experimental' | 'routeToken'>,\n): Map<string, RouteNode> => {\n return new Map(\n dedupeBranchesAndIndexRoutes(routeNodes).map((routeNode) => [\n inferTo(routeNode, config),\n routeNode,\n ]),\n )\n}\n\n/**\n * Create a map from 'id' to a routeNode\n */\nexport const createRouteNodesById = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n return new Map(\n routeNodes.map((routeNode) => {\n const id = routeNode.routePath ?? ''\n return [id, routeNode]\n }),\n )\n}\n\n/**\n * Infers to path\n */\nexport const inferTo = (\n routeNode: RouteNode,\n config?: Pick<Config, 'experimental' | 'routeToken'>,\n): string => {\n const fullPath = inferFullPath(routeNode, config)\n\n if (fullPath === '/') return fullPath\n\n return fullPath.replace(/\\/$/, '')\n}\n\n/**\n * Dedupes branches and index routes\n */\nexport const dedupeBranchesAndIndexRoutes = (\n routes: Array<RouteNode>,\n): Array<RouteNode> => {\n return routes.filter((route) => {\n if (route.children?.find((child) => child.cleanedPath === '/')) return false\n return true\n })\n}\n\nfunction checkUnique<TElement>(routes: Array<TElement>, key: keyof TElement) {\n // Check no two routes have the same `key`\n // if they do, throw an error with the conflicting filePaths\n const keys = routes.map((d) => d[key])\n const uniqueKeys = new Set(keys)\n if (keys.length !== uniqueKeys.size) {\n const duplicateKeys = keys.filter((d, i) => keys.indexOf(d) !== i)\n const conflictingFiles = routes.filter((d) =>\n duplicateKeys.includes(d[key]),\n )\n return conflictingFiles\n }\n return undefined\n}\n\nexport function checkRouteFullPathUniqueness(\n _routes: Array<RouteNode>,\n config: Config,\n) {\n const routes = _routes.map((d) => {\n const inferredFullPath = inferFullPath(d, config)\n return { ...d, inferredFullPath }\n })\n\n const conflictingFiles = checkUnique(routes, 'inferredFullPath')\n\n if (conflictingFiles !== undefined) {\n const errorMessage = `Conflicting configuration paths were found for the following route${conflictingFiles.length > 1 ? 's' : ''}: ${conflictingFiles\n .map((p) => `\"${p.inferredFullPath}\"`)\n .join(', ')}.\nPlease ensure each Route has a unique full path.\nConflicting files: \\n ${conflictingFiles.map((d) => path.resolve(config.routesDirectory, d.filePath)).join('\\n ')}\\n`\n throw new Error(errorMessage)\n }\n}\n\nexport function buildRouteTreeConfig(\n nodes: Array<RouteNode>,\n disableTypes: boolean,\n depth = 1,\n): Array<string> {\n const children = nodes.map((node) => {\n if (node._fsRouteType === '__root') {\n return\n }\n\n if (node._fsRouteType === 'pathless_layout' && !node.children?.length) {\n return\n }\n\n const route = `${node.variableName}`\n\n if (node.children?.length) {\n const childConfigs = buildRouteTreeConfig(\n node.children,\n disableTypes,\n depth + 1,\n )\n\n const childrenDeclaration = disableTypes\n ? ''\n : `interface ${route}RouteChildren {\n ${node.children\n .map(\n (child) =>\n `${child.variableName}Route: typeof ${getResolvedRouteNodeVariableName(child)}`,\n )\n .join(',')}\n}`\n\n const children = `const ${route}RouteChildren${disableTypes ? '' : `: ${route}RouteChildren`} = {\n ${node.children\n .map(\n (child) =>\n `${child.variableName}Route: ${getResolvedRouteNodeVariableName(child)}`,\n )\n .join(',')}\n}`\n\n const routeWithChildren = `const ${route}RouteWithChildren = ${route}Route._addFileChildren(${route}RouteChildren)`\n\n return [\n childConfigs.join('\\n'),\n childrenDeclaration,\n children,\n routeWithChildren,\n ].join('\\n\\n')\n }\n\n return undefined\n })\n\n return children.filter((x) => x !== undefined)\n}\n\nexport function buildImportString(\n importDeclaration: ImportDeclaration,\n): string {\n const { source, specifiers, importKind } = importDeclaration\n return specifiers.length\n ? `import ${importKind === 'type' ? 'type ' : ''}{ ${specifiers.map((s) => (s.local ? `${s.imported} as ${s.local}` : s.imported)).join(', ')} } from '${source}'`\n : ''\n}\n\nexport function lowerCaseFirstChar(value: string) {\n if (!value[0]) {\n return value\n }\n\n return value[0].toLowerCase() + value.slice(1)\n}\n\nexport function mergeImportDeclarations(\n imports: Array<ImportDeclaration>,\n): Array<ImportDeclaration> {\n const merged = new Map<string, ImportDeclaration>()\n\n for (const imp of imports) {\n const key = `${imp.source}-${imp.importKind ?? ''}`\n let existing = merged.get(key)\n if (!existing) {\n existing = { ...imp, specifiers: [] }\n merged.set(key, existing)\n }\n\n const existingSpecs = existing.specifiers\n for (const specifier of imp.specifiers) {\n let found = false\n for (let i = 0; i < existingSpecs.length; i++) {\n const e = existingSpecs[i]!\n if (e.imported === specifier.imported && e.local === specifier.local) {\n found = true\n break\n }\n }\n if (!found) {\n existingSpecs.push(specifier)\n }\n }\n }\n\n return [...merged.values()]\n}\n\nexport const findParent = (node: RouteNode | undefined): string => {\n if (!node) {\n return `rootRouteImport`\n }\n if (node.parent) {\n return `${node.parent.variableName}Route`\n }\n return findParent(node.parent)\n}\n\nexport function buildFileRoutesByPathInterface(opts: {\n routeNodes: Array<RouteNode>\n module: string\n interfaceName: string\n config?: Pick<Config, 'experimental' | 'routeToken'>\n}): string {\n return `declare module '${opts.module}' {\n interface ${opts.interfaceName} {\n ${opts.routeNodes\n .map((routeNode) => {\n const filePathId = routeNode.routePath\n const preloaderRoute = `typeof ${routeNode.variableName}RouteImport`\n\n const parent = findParent(routeNode)\n\n return `'${filePathId}': {\n id: '${filePathId}'\n path: '${inferPath(routeNode)}'\n fullPath: '${inferFullPath(routeNode, opts.config)}'\n preLoaderRoute: ${preloaderRoute}\n parentRoute: typeof ${parent}\n }`\n })\n .join('\\n')}\n }\n}`\n}\n\nexport function getImportPath(\n node: RouteNode,\n config: Config,\n generatedRouteTreePath: string,\n): string {\n return replaceBackslash(\n removeExt(\n path.relative(\n path.dirname(generatedRouteTreePath),\n path.resolve(config.routesDirectory, node.filePath),\n ),\n config.addExtensions,\n ),\n )\n}\n\nexport function getImportForRouteNode(\n node: RouteNode,\n config: Config,\n generatedRouteTreePath: string,\n root: string,\n): ImportDeclaration {\n let source = ''\n if (config.importRoutesUsingAbsolutePaths) {\n source = replaceBackslash(\n removeExt(\n path.resolve(root, config.routesDirectory, node.filePath),\n config.addExtensions,\n ),\n )\n } else {\n source = `./${getImportPath(node, config, generatedRouteTreePath)}`\n }\n return {\n source,\n specifiers: [\n {\n imported: 'Route',\n local: `${node.variableName}RouteImport`,\n },\n ],\n } satisfies ImportDeclaration\n}\n\n/**\n * Used to validate if a route is a pathless layout route\n * @param normalizedRoutePath Normalized route path, i.e `/foo/_layout/route.tsx` and `/foo._layout.route.tsx` to `/foo/_layout/route`\n * @param config The `router-generator` configuration object\n * @returns Boolean indicating if the route is a pathless layout route\n */\nexport function isValidNonNestedRoute(\n normalizedRoutePath: string,\n config?: Pick<Config, 'experimental' | 'routeToken' | 'indexToken'>,\n): boolean {\n if (!config?.experimental?.nonNestedRoutes) {\n return false\n }\n\n const segments = normalizedRoutePath.split('/').filter(Boolean)\n\n if (segments.length === 0) {\n return false\n }\n\n const lastRouteSegment = segments[segments.length - 1]!\n\n // If segment === __root, then exit as false\n if (lastRouteSegment === rootPathId) {\n return false\n }\n\n if (\n lastRouteSegment !== config.indexToken &&\n lastRouteSegment !== config.routeToken &&\n lastRouteSegment.endsWith('_')\n ) {\n return true\n }\n\n for (const segment of segments.slice(0, -1).reverse()) {\n if (segment === config.routeToken) {\n return false\n }\n\n if (segment.endsWith('_')) {\n return true\n }\n }\n\n return false\n}\n"],"names":["path","children"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/prefer-for-of */\nimport * as fsp from 'node:fs/promises'\nimport path from 'node:path'\nimport * as prettier from 'prettier'\nimport { rootPathId } from './filesystem/physical/rootPathId'\nimport type { Config } from './config'\nimport type { ImportDeclaration, RouteNode } from './types'\n\n/**\n * Prefix map for O(1) parent route lookups.\n * Maps each route path prefix to the route node that owns that prefix.\n * Enables finding longest matching parent without linear search.\n */\nexport class RoutePrefixMap {\n private prefixToRoute: Map<string, RouteNode> = new Map()\n private layoutRoutes: Array<RouteNode> = []\n\n constructor(routes: Array<RouteNode>) {\n for (const route of routes) {\n if (!route.routePath || route.routePath === `/${rootPathId}`) continue\n\n // Index by exact path for direct lookups\n this.prefixToRoute.set(route.routePath, route)\n\n if (\n route._fsRouteType === 'pathless_layout' ||\n route._fsRouteType === 'layout' ||\n route._fsRouteType === '__root'\n ) {\n this.layoutRoutes.push(route)\n }\n }\n\n // Sort by path length descending for longest-match-first\n this.layoutRoutes.sort(\n (a, b) => (b.routePath?.length ?? 0) - (a.routePath?.length ?? 0),\n )\n }\n\n /**\n * Find the longest matching parent route for a given path.\n * O(k) where k is the number of path segments, not O(n) routes.\n */\n findParent(routePath: string): RouteNode | null {\n if (!routePath || routePath === '/') return null\n\n // Walk up the path segments\n let searchPath = routePath\n while (searchPath.length > 0) {\n const lastSlash = searchPath.lastIndexOf('/')\n if (lastSlash <= 0) break\n\n searchPath = searchPath.substring(0, lastSlash)\n const parent = this.prefixToRoute.get(searchPath)\n if (parent && parent.routePath !== routePath) {\n return parent\n }\n }\n return null\n }\n\n /**\n * Check if a route exists at the given path.\n */\n has(routePath: string): boolean {\n return this.prefixToRoute.has(routePath)\n }\n\n /**\n * Get a route by exact path.\n */\n get(routePath: string): RouteNode | undefined {\n return this.prefixToRoute.get(routePath)\n }\n}\n\nexport function multiSortBy<T>(\n arr: Array<T>,\n accessors: Array<(item: T) => any> = [(d) => d],\n): Array<T> {\n const len = arr.length\n // Pre-compute all accessor values to avoid repeated function calls during sort\n const indexed: Array<{ item: T; index: number; keys: Array<any> }> =\n new Array(len)\n for (let i = 0; i < len; i++) {\n const item = arr[i]!\n const keys = new Array(accessors.length)\n for (let j = 0; j < accessors.length; j++) {\n keys[j] = accessors[j]!(item)\n }\n indexed[i] = { item, index: i, keys }\n }\n\n indexed.sort((a, b) => {\n for (let j = 0; j < accessors.length; j++) {\n const ao = a.keys[j]\n const bo = b.keys[j]\n\n if (typeof ao === 'undefined') {\n if (typeof bo === 'undefined') {\n continue\n }\n return 1\n }\n\n if (ao === bo) {\n continue\n }\n\n return ao > bo ? 1 : -1\n }\n\n return a.index - b.index\n })\n\n const result: Array<T> = new Array(len)\n for (let i = 0; i < len; i++) {\n result[i] = indexed[i]!.item\n }\n return result\n}\n\nexport function cleanPath(path: string) {\n // remove double slashes\n return path.replace(/\\/{2,}/g, '/')\n}\n\nexport function trimPathLeft(path: string) {\n return path === '/' ? path : path.replace(/^\\/{1,}/, '')\n}\n\nexport function removeLeadingSlash(path: string): string {\n return path.replace(/^\\//, '')\n}\n\nexport function removeTrailingSlash(s: string) {\n return s.replace(/\\/$/, '')\n}\n\nconst BRACKET_CONTENT_RE = /\\[(.*?)\\]/g\nconst SPLIT_REGEX = /(?<!\\[)\\.(?!\\])/g\n\n/**\n * Characters that cannot be escaped in square brackets.\n * These are characters that would cause issues in URLs or file systems.\n */\nconst DISALLOWED_ESCAPE_CHARS = new Set([\n '/',\n '\\\\',\n '?',\n '#',\n ':',\n '*',\n '<',\n '>',\n '|',\n '!',\n '$',\n '%',\n])\n\nexport function determineInitialRoutePath(routePath: string) {\n const originalRoutePath =\n cleanPath(\n `/${(cleanPath(routePath) || '').split(SPLIT_REGEX).join('/')}`,\n ) || ''\n\n const parts = routePath.split(SPLIT_REGEX)\n\n // Escape any characters that in square brackets\n // we keep the original path untouched\n const escapedParts = parts.map((part) => {\n // Check if any disallowed characters are used in brackets\n\n let match\n while ((match = BRACKET_CONTENT_RE.exec(part)) !== null) {\n const character = match[1]\n if (character === undefined) continue\n if (DISALLOWED_ESCAPE_CHARS.has(character)) {\n console.error(\n `Error: Disallowed character \"${character}\" found in square brackets in route path \"${routePath}\".\\nYou cannot use any of the following characters in square brackets: ${Array.from(\n DISALLOWED_ESCAPE_CHARS,\n ).join(', ')}\\nPlease remove and/or replace them.`,\n )\n process.exit(1)\n }\n }\n\n // Since this split segment is safe at this point, we can\n // remove the brackets and replace them with the content inside\n return part.replace(BRACKET_CONTENT_RE, '$1')\n })\n\n // If the syntax for prefix/suffix is different, from the path\n // matching internals of router-core, we'd perform those changes here\n // on the `escapedParts` array before it is joined back together in\n // `final`\n\n const final = cleanPath(`/${escapedParts.join('/')}`) || ''\n\n return {\n routePath: final,\n originalRoutePath,\n }\n}\n\n/**\n * Checks if a segment is fully escaped (entirely wrapped in brackets with no nested brackets).\n * E.g., \"[index]\" -> true, \"[_layout]\" -> true, \"foo[.]bar\" -> false, \"index\" -> false\n */\nfunction isFullyEscapedSegment(originalSegment: string): boolean {\n return (\n originalSegment.startsWith('[') &&\n originalSegment.endsWith(']') &&\n !originalSegment.slice(1, -1).includes('[') &&\n !originalSegment.slice(1, -1).includes(']')\n )\n}\n\n/**\n * Checks if the leading underscore in a segment is escaped.\n * Returns true if:\n * - Segment starts with [_] pattern: \"[_]layout\" -> \"_layout\"\n * - Segment is fully escaped and content starts with _: \"[_1nd3x]\" -> \"_1nd3x\"\n */\nexport function hasEscapedLeadingUnderscore(originalSegment: string): boolean {\n // Pattern: [_]something or [_something]\n return (\n originalSegment.startsWith('[_]') ||\n (originalSegment.startsWith('[_') && isFullyEscapedSegment(originalSegment))\n )\n}\n\n/**\n * Checks if the trailing underscore in a segment is escaped.\n * Returns true if:\n * - Segment ends with [_] pattern: \"blog[_]\" -> \"blog_\"\n * - Segment is fully escaped and content ends with _: \"[_r0ut3_]\" -> \"_r0ut3_\"\n */\nexport function hasEscapedTrailingUnderscore(originalSegment: string): boolean {\n // Pattern: something[_] or [something_]\n return (\n originalSegment.endsWith('[_]') ||\n (originalSegment.endsWith('_]') && isFullyEscapedSegment(originalSegment))\n )\n}\n\nconst backslashRegex = /\\\\/g\n\nexport function replaceBackslash(s: string) {\n return s.replace(backslashRegex, '/')\n}\n\nconst alphanumericRegex = /[a-zA-Z0-9_]/\nconst splatSlashRegex = /\\/\\$\\//g\nconst trailingSplatRegex = /\\$$/g\nconst bracketSplatRegex = /\\$\\{\\$\\}/g\nconst dollarSignRegex = /\\$/g\nconst splitPathRegex = /[/-]/g\nconst leadingDigitRegex = /^(\\d)/g\n\nconst toVariableSafeChar = (char: string): string => {\n if (alphanumericRegex.test(char)) {\n return char // Keep alphanumeric characters and underscores as is\n }\n\n // Replace special characters with meaningful text equivalents\n switch (char) {\n case '.':\n return 'Dot'\n case '-':\n return 'Dash'\n case '@':\n return 'At'\n case '(':\n return '' // Removed since route groups use parentheses\n case ')':\n return '' // Removed since route groups use parentheses\n case ' ':\n return '' // Remove spaces\n default:\n return `Char${char.charCodeAt(0)}` // For any other characters\n }\n}\n\nexport function routePathToVariable(routePath: string): string {\n const cleaned = removeUnderscores(routePath)\n if (!cleaned) return ''\n\n const parts = cleaned\n .replace(splatSlashRegex, '/splat/')\n .replace(trailingSplatRegex, 'splat')\n .replace(bracketSplatRegex, 'splat')\n .replace(dollarSignRegex, '')\n .split(splitPathRegex)\n\n let result = ''\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]!\n const segment = i > 0 ? capitalize(part) : part\n for (let j = 0; j < segment.length; j++) {\n result += toVariableSafeChar(segment[j]!)\n }\n }\n\n return result.replace(leadingDigitRegex, 'R$1')\n}\n\nconst underscoreStartEndRegex = /(^_|_$)/gi\nconst underscoreSlashRegex = /(\\/_|_\\/)/gi\n\nexport function removeUnderscores(s?: string) {\n return s\n ?.replace(underscoreStartEndRegex, '')\n .replace(underscoreSlashRegex, '/')\n}\n\n/**\n * Removes underscores from a path, but preserves underscores that were escaped\n * in the original path (indicated by [_] syntax).\n *\n * @param routePath - The path with brackets removed\n * @param originalPath - The original path that may contain [_] escape sequences\n * @returns The path with non-escaped underscores removed\n */\nexport function removeUnderscoresWithEscape(\n routePath?: string,\n originalPath?: string,\n): string {\n if (!routePath) return ''\n if (!originalPath) return removeUnderscores(routePath) ?? ''\n\n const routeSegments = routePath.split('/')\n const originalSegments = originalPath.split('/')\n\n const newSegments = routeSegments.map((segment, i) => {\n const originalSegment = originalSegments[i] || ''\n\n // Check if leading underscore is escaped\n const leadingEscaped = hasEscapedLeadingUnderscore(originalSegment)\n // Check if trailing underscore is escaped\n const trailingEscaped = hasEscapedTrailingUnderscore(originalSegment)\n\n let result = segment\n\n // Remove leading underscore only if not escaped\n if (result.startsWith('_') && !leadingEscaped) {\n result = result.slice(1)\n }\n\n // Remove trailing underscore only if not escaped\n if (result.endsWith('_') && !trailingEscaped) {\n result = result.slice(0, -1)\n }\n\n return result\n })\n\n return newSegments.join('/')\n}\n\n/**\n * Removes layout segments (segments starting with underscore) from a path,\n * but preserves segments where the underscore was escaped.\n *\n * @param routePath - The path with brackets removed\n * @param originalPath - The original path that may contain [_] escape sequences\n * @returns The path with non-escaped layout segments removed\n */\nexport function removeLayoutSegmentsWithEscape(\n routePath: string = '/',\n originalPath?: string,\n): string {\n if (!originalPath) return removeLayoutSegments(routePath)\n\n const routeSegments = routePath.split('/')\n const originalSegments = originalPath.split('/')\n\n // Keep segments that are NOT pathless (i.e., don't start with unescaped underscore)\n const newSegments = routeSegments.filter((segment, i) => {\n const originalSegment = originalSegments[i] || ''\n return !isSegmentPathless(segment, originalSegment)\n })\n\n return newSegments.join('/')\n}\n\n/**\n * Checks if a segment should be treated as a pathless/layout segment.\n * A segment is pathless if it starts with underscore and the underscore is not escaped.\n *\n * @param segment - The segment from routePath (brackets removed)\n * @param originalSegment - The segment from originalRoutePath (may contain brackets)\n * @returns true if the segment is pathless (has non-escaped leading underscore)\n */\nexport function isSegmentPathless(\n segment: string,\n originalSegment: string,\n): boolean {\n if (!segment.startsWith('_')) return false\n return !hasEscapedLeadingUnderscore(originalSegment)\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nexport function removeLeadingUnderscores(s: string, routeToken: string) {\n if (!s) return s\n\n const hasLeadingUnderscore = routeToken[0] === '_'\n\n const routeTokenToExclude = hasLeadingUnderscore\n ? routeToken.slice(1)\n : routeToken\n\n const escapedRouteToken = escapeRegExp(routeTokenToExclude)\n\n const leadingUnderscoreRegex = hasLeadingUnderscore\n ? new RegExp(`(?<=^|\\\\/)_(?!${escapedRouteToken})`, 'g')\n : new RegExp(`(?<=^|\\\\/)_`, 'g')\n\n return s.replaceAll(leadingUnderscoreRegex, '')\n}\n\nexport function removeTrailingUnderscores(s: string, routeToken: string) {\n if (!s) return s\n\n const hasTrailingUnderscore = routeToken.slice(-1) === '_'\n\n const routeTokenToExclude = hasTrailingUnderscore\n ? routeToken.slice(0, -1)\n : routeToken\n\n const escapedRouteToken = escapeRegExp(routeTokenToExclude)\n\n const trailingUnderscoreRegex = hasTrailingUnderscore\n ? new RegExp(`(?<!${escapedRouteToken})_(?=\\\\/|$)`, 'g')\n : new RegExp(`_(?=\\\\/)|_$`, 'g')\n\n return s.replaceAll(trailingUnderscoreRegex, '')\n}\n\nexport function capitalize(s: string) {\n if (typeof s !== 'string') return ''\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\nexport function removeExt(d: string, keepExtension: boolean = false) {\n return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d\n}\n\n/**\n * This function writes to a file if the content is different.\n *\n * @param filepath The path to the file\n * @param content Original content\n * @param incomingContent New content\n * @param callbacks Callbacks to run before and after writing\n * @returns Whether the file was written\n */\nexport async function writeIfDifferent(\n filepath: string,\n content: string,\n incomingContent: string,\n callbacks?: { beforeWrite?: () => void; afterWrite?: () => void },\n): Promise<boolean> {\n if (content !== incomingContent) {\n callbacks?.beforeWrite?.()\n await fsp.writeFile(filepath, incomingContent)\n callbacks?.afterWrite?.()\n return true\n }\n return false\n}\n\n/**\n * This function formats the source code using the default formatter (Prettier).\n *\n * @param source The content to format\n * @param config The configuration object\n * @returns The formatted content\n */\nexport async function format(\n source: string,\n config: {\n quoteStyle: 'single' | 'double'\n semicolons: boolean\n },\n): Promise<string> {\n const prettierOptions: prettier.Config = {\n semi: config.semicolons,\n singleQuote: config.quoteStyle === 'single',\n parser: 'typescript',\n }\n return prettier.format(source, prettierOptions)\n}\n\n/**\n * This function resets the regex index to 0 so that it can be reused\n * without having to create a new regex object or worry about the last\n * state when using the global flag.\n *\n * @param regex The regex object to reset\n * @returns\n */\nexport function resetRegex(regex: RegExp) {\n regex.lastIndex = 0\n return\n}\n\n/**\n * This function checks if a file exists.\n *\n * @param file The path to the file\n * @returns Whether the file exists\n */\nexport async function checkFileExists(file: string) {\n try {\n await fsp.access(file, fsp.constants.F_OK)\n return true\n } catch {\n return false\n }\n}\n\nconst possiblyNestedRouteGroupPatternRegex = /\\([^/]+\\)\\/?/g\nexport function removeGroups(s: string) {\n return s.replace(possiblyNestedRouteGroupPatternRegex, '')\n}\n\n/**\n * Removes all segments from a given path that start with an underscore ('_').\n *\n * @param {string} routePath - The path from which to remove segments. Defaults to '/'.\n * @returns {string} The path with all underscore-prefixed segments removed.\n * @example\n * removeLayoutSegments('/workspace/_auth/foo') // '/workspace/foo'\n */\nexport function removeLayoutSegments(routePath: string = '/'): string {\n const segments = routePath.split('/')\n const newSegments = segments.filter((segment) => !segment.startsWith('_'))\n return newSegments.join('/')\n}\n\n/**\n * The `node.path` is used as the `id` in the route definition.\n * This function checks if the given node has a parent and if so, it determines the correct path for the given node.\n * @param node - The node to determine the path for.\n * @returns The correct path for the given node.\n */\nexport function determineNodePath(node: RouteNode) {\n return (node.path = node.parent\n ? node.routePath?.replace(node.parent.routePath ?? '', '') || '/'\n : node.routePath)\n}\n\n/**\n * Removes the last segment from a given path. Segments are considered to be separated by a '/'.\n *\n * @param {string} routePath - The path from which to remove the last segment. Defaults to '/'.\n * @returns {string} The path with the last segment removed.\n * @example\n * removeLastSegmentFromPath('/workspace/_auth/foo') // '/workspace/_auth'\n */\nexport function removeLastSegmentFromPath(routePath: string = '/'): string {\n const segments = routePath.split('/')\n segments.pop() // Remove the last segment\n return segments.join('/')\n}\n\n/**\n * Find parent route using RoutePrefixMap for O(k) lookups instead of O(n).\n */\nexport function hasParentRoute(\n prefixMap: RoutePrefixMap,\n node: RouteNode,\n routePathToCheck: string | undefined,\n): RouteNode | null {\n if (!routePathToCheck || routePathToCheck === '/') {\n return null\n }\n\n return prefixMap.findParent(routePathToCheck)\n}\n\n/**\n * Gets the final variable name for a route\n */\nexport const getResolvedRouteNodeVariableName = (\n routeNode: RouteNode,\n): string => {\n return routeNode.children?.length\n ? `${routeNode.variableName}RouteWithChildren`\n : `${routeNode.variableName}Route`\n}\n\n/**\n * Checks if a given RouteNode is valid for augmenting it with typing based on conditions.\n * Also asserts that the RouteNode is defined.\n *\n * @param routeNode - The RouteNode to check.\n * @returns A boolean indicating whether the RouteNode is defined.\n */\nexport function isRouteNodeValidForAugmentation(\n routeNode?: RouteNode,\n): routeNode is RouteNode {\n if (!routeNode || routeNode.isVirtual) {\n return false\n }\n return true\n}\n\n/**\n * Infers the path for use by TS\n */\nexport const inferPath = (routeNode: RouteNode): string => {\n return routeNode.cleanedPath === '/'\n ? routeNode.cleanedPath\n : (routeNode.cleanedPath?.replace(/\\/$/, '') ?? '')\n}\n\n/**\n * Infers the full path for use by TS\n */\nexport const inferFullPath = (routeNode: RouteNode): string => {\n const fullPath = removeGroups(\n removeUnderscoresWithEscape(\n removeLayoutSegmentsWithEscape(\n routeNode.routePath,\n routeNode.originalRoutePath,\n ),\n routeNode.originalRoutePath,\n ),\n )\n\n return routeNode.cleanedPath === '/' ? fullPath : fullPath.replace(/\\/$/, '')\n}\n\n/**\n * Creates a map from fullPath to routeNode\n */\nexport const createRouteNodesByFullPath = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n return new Map(\n routeNodes.map((routeNode) => [inferFullPath(routeNode), routeNode]),\n )\n}\n\n/**\n * Create a map from 'to' to a routeNode\n */\nexport const createRouteNodesByTo = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n return new Map(\n dedupeBranchesAndIndexRoutes(routeNodes).map((routeNode) => [\n inferTo(routeNode),\n routeNode,\n ]),\n )\n}\n\n/**\n * Create a map from 'id' to a routeNode\n */\nexport const createRouteNodesById = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n return new Map(\n routeNodes.map((routeNode) => {\n const id = routeNode.routePath ?? ''\n return [id, routeNode]\n }),\n )\n}\n\n/**\n * Infers to path\n */\nexport const inferTo = (routeNode: RouteNode): string => {\n const fullPath = inferFullPath(routeNode)\n\n if (fullPath === '/') return fullPath\n\n return fullPath.replace(/\\/$/, '')\n}\n\n/**\n * Dedupes branches and index routes\n */\nexport const dedupeBranchesAndIndexRoutes = (\n routes: Array<RouteNode>,\n): Array<RouteNode> => {\n return routes.filter((route) => {\n if (route.children?.find((child) => child.cleanedPath === '/')) return false\n return true\n })\n}\n\nfunction checkUnique<TElement>(routes: Array<TElement>, key: keyof TElement) {\n // Check no two routes have the same `key`\n // if they do, throw an error with the conflicting filePaths\n const keys = routes.map((d) => d[key])\n const uniqueKeys = new Set(keys)\n if (keys.length !== uniqueKeys.size) {\n const duplicateKeys = keys.filter((d, i) => keys.indexOf(d) !== i)\n const conflictingFiles = routes.filter((d) =>\n duplicateKeys.includes(d[key]),\n )\n return conflictingFiles\n }\n return undefined\n}\n\nexport function checkRouteFullPathUniqueness(\n _routes: Array<RouteNode>,\n config: Config,\n) {\n const routes = _routes.map((d) => {\n const inferredFullPath = inferFullPath(d)\n return { ...d, inferredFullPath }\n })\n\n const conflictingFiles = checkUnique(routes, 'inferredFullPath')\n\n if (conflictingFiles !== undefined) {\n const errorMessage = `Conflicting configuration paths were found for the following route${conflictingFiles.length > 1 ? 's' : ''}: ${conflictingFiles\n .map((p) => `\"${p.inferredFullPath}\"`)\n .join(', ')}.\nPlease ensure each Route has a unique full path.\nConflicting files: \\n ${conflictingFiles.map((d) => path.resolve(config.routesDirectory, d.filePath)).join('\\n ')}\\n`\n throw new Error(errorMessage)\n }\n}\n\nexport function buildRouteTreeConfig(\n nodes: Array<RouteNode>,\n disableTypes: boolean,\n depth = 1,\n): Array<string> {\n const children = nodes.map((node) => {\n if (node._fsRouteType === '__root') {\n return\n }\n\n if (node._fsRouteType === 'pathless_layout' && !node.children?.length) {\n return\n }\n\n const route = `${node.variableName}`\n\n if (node.children?.length) {\n const childConfigs = buildRouteTreeConfig(\n node.children,\n disableTypes,\n depth + 1,\n )\n\n const childrenDeclaration = disableTypes\n ? ''\n : `interface ${route}RouteChildren {\n ${node.children\n .map(\n (child) =>\n `${child.variableName}Route: typeof ${getResolvedRouteNodeVariableName(child)}`,\n )\n .join(',')}\n}`\n\n const children = `const ${route}RouteChildren${disableTypes ? '' : `: ${route}RouteChildren`} = {\n ${node.children\n .map(\n (child) =>\n `${child.variableName}Route: ${getResolvedRouteNodeVariableName(child)}`,\n )\n .join(',')}\n}`\n\n const routeWithChildren = `const ${route}RouteWithChildren = ${route}Route._addFileChildren(${route}RouteChildren)`\n\n return [\n childConfigs.join('\\n'),\n childrenDeclaration,\n children,\n routeWithChildren,\n ].join('\\n\\n')\n }\n\n return undefined\n })\n\n return children.filter((x) => x !== undefined)\n}\n\nexport function buildImportString(\n importDeclaration: ImportDeclaration,\n): string {\n const { source, specifiers, importKind } = importDeclaration\n return specifiers.length\n ? `import ${importKind === 'type' ? 'type ' : ''}{ ${specifiers.map((s) => (s.local ? `${s.imported} as ${s.local}` : s.imported)).join(', ')} } from '${source}'`\n : ''\n}\n\nexport function lowerCaseFirstChar(value: string) {\n if (!value[0]) {\n return value\n }\n\n return value[0].toLowerCase() + value.slice(1)\n}\n\nexport function mergeImportDeclarations(\n imports: Array<ImportDeclaration>,\n): Array<ImportDeclaration> {\n const merged = new Map<string, ImportDeclaration>()\n\n for (const imp of imports) {\n const key = `${imp.source}-${imp.importKind ?? ''}`\n let existing = merged.get(key)\n if (!existing) {\n existing = { ...imp, specifiers: [] }\n merged.set(key, existing)\n }\n\n const existingSpecs = existing.specifiers\n for (const specifier of imp.specifiers) {\n let found = false\n for (let i = 0; i < existingSpecs.length; i++) {\n const e = existingSpecs[i]!\n if (e.imported === specifier.imported && e.local === specifier.local) {\n found = true\n break\n }\n }\n if (!found) {\n existingSpecs.push(specifier)\n }\n }\n }\n\n return [...merged.values()]\n}\n\nexport const findParent = (node: RouteNode | undefined): string => {\n if (!node) {\n return `rootRouteImport`\n }\n if (node.parent) {\n return `${node.parent.variableName}Route`\n }\n return findParent(node.parent)\n}\n\nexport function buildFileRoutesByPathInterface(opts: {\n routeNodes: Array<RouteNode>\n module: string\n interfaceName: string\n config?: Pick<Config, 'routeToken'>\n}): string {\n return `declare module '${opts.module}' {\n interface ${opts.interfaceName} {\n ${opts.routeNodes\n .map((routeNode) => {\n const filePathId = routeNode.routePath\n const preloaderRoute = `typeof ${routeNode.variableName}RouteImport`\n\n const parent = findParent(routeNode)\n\n return `'${filePathId}': {\n id: '${filePathId}'\n path: '${inferPath(routeNode)}'\n fullPath: '${inferFullPath(routeNode)}'\n preLoaderRoute: ${preloaderRoute}\n parentRoute: typeof ${parent}\n }`\n })\n .join('\\n')}\n }\n}`\n}\n\nexport function getImportPath(\n node: RouteNode,\n config: Config,\n generatedRouteTreePath: string,\n): string {\n return replaceBackslash(\n removeExt(\n path.relative(\n path.dirname(generatedRouteTreePath),\n path.resolve(config.routesDirectory, node.filePath),\n ),\n config.addExtensions,\n ),\n )\n}\n\nexport function getImportForRouteNode(\n node: RouteNode,\n config: Config,\n generatedRouteTreePath: string,\n root: string,\n): ImportDeclaration {\n let source = ''\n if (config.importRoutesUsingAbsolutePaths) {\n source = replaceBackslash(\n removeExt(\n path.resolve(root, config.routesDirectory, node.filePath),\n config.addExtensions,\n ),\n )\n } else {\n source = `./${getImportPath(node, config, generatedRouteTreePath)}`\n }\n return {\n source,\n specifiers: [\n {\n imported: 'Route',\n local: `${node.variableName}RouteImport`,\n },\n ],\n } satisfies ImportDeclaration\n}\n"],"names":["path","children"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/router-generator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.142.0",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"tsx": "^4.19.2",
|
|
56
56
|
"zod": "^3.24.2",
|
|
57
57
|
"@tanstack/router-utils": "1.141.0",
|
|
58
|
-
"@tanstack/
|
|
59
|
-
"@tanstack/
|
|
58
|
+
"@tanstack/router-core": "1.141.8",
|
|
59
|
+
"@tanstack/virtual-file-routes": "1.141.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@tanstack/react-router": "1.141.8"
|
package/src/config.ts
CHANGED
|
@@ -54,8 +54,6 @@ export const configSchema = baseConfigSchema.extend({
|
|
|
54
54
|
.object({
|
|
55
55
|
// TODO: This has been made stable and is now "autoCodeSplitting". Remove in next major version.
|
|
56
56
|
enableCodeSplitting: z.boolean().optional(),
|
|
57
|
-
// TODO: This resolves issues with non-nested paths in file-based routing. To be made default in next major version.
|
|
58
|
-
nonNestedRoutes: z.boolean().optional(),
|
|
59
57
|
})
|
|
60
58
|
.optional(),
|
|
61
59
|
plugins: z.array(z.custom<GeneratorPlugin>()).optional(),
|