@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/cjs/utils.d.cts
CHANGED
|
@@ -8,17 +8,12 @@ import { ImportDeclaration, RouteNode } from './types.cjs';
|
|
|
8
8
|
export declare class RoutePrefixMap {
|
|
9
9
|
private prefixToRoute;
|
|
10
10
|
private layoutRoutes;
|
|
11
|
-
private nonNestedRoutes;
|
|
12
11
|
constructor(routes: Array<RouteNode>);
|
|
13
12
|
/**
|
|
14
13
|
* Find the longest matching parent route for a given path.
|
|
15
14
|
* O(k) where k is the number of path segments, not O(n) routes.
|
|
16
15
|
*/
|
|
17
16
|
findParent(routePath: string): RouteNode | null;
|
|
18
|
-
/**
|
|
19
|
-
* Find parent for non-nested routes (needs layout route matching).
|
|
20
|
-
*/
|
|
21
|
-
findParentForNonNested(routePath: string, originalRoutePath: string | undefined, nonNestedSegments: Array<string>): RouteNode | null;
|
|
22
17
|
/**
|
|
23
18
|
* Check if a route exists at the given path.
|
|
24
19
|
*/
|
|
@@ -33,14 +28,54 @@ export declare function cleanPath(path: string): string;
|
|
|
33
28
|
export declare function trimPathLeft(path: string): string;
|
|
34
29
|
export declare function removeLeadingSlash(path: string): string;
|
|
35
30
|
export declare function removeTrailingSlash(s: string): string;
|
|
36
|
-
export declare function determineInitialRoutePath(routePath: string
|
|
31
|
+
export declare function determineInitialRoutePath(routePath: string): {
|
|
37
32
|
routePath: string;
|
|
38
|
-
isExperimentalNonNestedRoute: boolean;
|
|
39
33
|
originalRoutePath: string;
|
|
40
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Checks if the leading underscore in a segment is escaped.
|
|
37
|
+
* Returns true if:
|
|
38
|
+
* - Segment starts with [_] pattern: "[_]layout" -> "_layout"
|
|
39
|
+
* - Segment is fully escaped and content starts with _: "[_1nd3x]" -> "_1nd3x"
|
|
40
|
+
*/
|
|
41
|
+
export declare function hasEscapedLeadingUnderscore(originalSegment: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Checks if the trailing underscore in a segment is escaped.
|
|
44
|
+
* Returns true if:
|
|
45
|
+
* - Segment ends with [_] pattern: "blog[_]" -> "blog_"
|
|
46
|
+
* - Segment is fully escaped and content ends with _: "[_r0ut3_]" -> "_r0ut3_"
|
|
47
|
+
*/
|
|
48
|
+
export declare function hasEscapedTrailingUnderscore(originalSegment: string): boolean;
|
|
41
49
|
export declare function replaceBackslash(s: string): string;
|
|
42
50
|
export declare function routePathToVariable(routePath: string): string;
|
|
43
51
|
export declare function removeUnderscores(s?: string): string | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Removes underscores from a path, but preserves underscores that were escaped
|
|
54
|
+
* in the original path (indicated by [_] syntax).
|
|
55
|
+
*
|
|
56
|
+
* @param routePath - The path with brackets removed
|
|
57
|
+
* @param originalPath - The original path that may contain [_] escape sequences
|
|
58
|
+
* @returns The path with non-escaped underscores removed
|
|
59
|
+
*/
|
|
60
|
+
export declare function removeUnderscoresWithEscape(routePath?: string, originalPath?: string): string;
|
|
61
|
+
/**
|
|
62
|
+
* Removes layout segments (segments starting with underscore) from a path,
|
|
63
|
+
* but preserves segments where the underscore was escaped.
|
|
64
|
+
*
|
|
65
|
+
* @param routePath - The path with brackets removed
|
|
66
|
+
* @param originalPath - The original path that may contain [_] escape sequences
|
|
67
|
+
* @returns The path with non-escaped layout segments removed
|
|
68
|
+
*/
|
|
69
|
+
export declare function removeLayoutSegmentsWithEscape(routePath?: string, originalPath?: string): string;
|
|
70
|
+
/**
|
|
71
|
+
* Checks if a segment should be treated as a pathless/layout segment.
|
|
72
|
+
* A segment is pathless if it starts with underscore and the underscore is not escaped.
|
|
73
|
+
*
|
|
74
|
+
* @param segment - The segment from routePath (brackets removed)
|
|
75
|
+
* @param originalSegment - The segment from originalRoutePath (may contain brackets)
|
|
76
|
+
* @returns true if the segment is pathless (has non-escaped leading underscore)
|
|
77
|
+
*/
|
|
78
|
+
export declare function isSegmentPathless(segment: string, originalSegment: string): boolean;
|
|
44
79
|
export declare function removeLeadingUnderscores(s: string, routeToken: string): string;
|
|
45
80
|
export declare function removeTrailingUnderscores(s: string, routeToken: string): string;
|
|
46
81
|
export declare function capitalize(s: string): string;
|
|
@@ -111,15 +146,10 @@ export declare function determineNodePath(node: RouteNode): string | undefined;
|
|
|
111
146
|
* removeLastSegmentFromPath('/workspace/_auth/foo') // '/workspace/_auth'
|
|
112
147
|
*/
|
|
113
148
|
export declare function removeLastSegmentFromPath(routePath?: string): string;
|
|
114
|
-
/**
|
|
115
|
-
* Extracts non-nested segments from a route path.
|
|
116
|
-
* Used for determining parent routes in non-nested route scenarios.
|
|
117
|
-
*/
|
|
118
|
-
export declare function getNonNestedSegments(routePath: string): Array<string>;
|
|
119
149
|
/**
|
|
120
150
|
* Find parent route using RoutePrefixMap for O(k) lookups instead of O(n).
|
|
121
151
|
*/
|
|
122
|
-
export declare function hasParentRoute(prefixMap: RoutePrefixMap, node: RouteNode, routePathToCheck: string | undefined
|
|
152
|
+
export declare function hasParentRoute(prefixMap: RoutePrefixMap, node: RouteNode, routePathToCheck: string | undefined): RouteNode | null;
|
|
123
153
|
/**
|
|
124
154
|
* Gets the final variable name for a route
|
|
125
155
|
*/
|
|
@@ -139,15 +169,15 @@ export declare const inferPath: (routeNode: RouteNode) => string;
|
|
|
139
169
|
/**
|
|
140
170
|
* Infers the full path for use by TS
|
|
141
171
|
*/
|
|
142
|
-
export declare const inferFullPath: (routeNode: RouteNode
|
|
172
|
+
export declare const inferFullPath: (routeNode: RouteNode) => string;
|
|
143
173
|
/**
|
|
144
174
|
* Creates a map from fullPath to routeNode
|
|
145
175
|
*/
|
|
146
|
-
export declare const createRouteNodesByFullPath: (routeNodes: Array<RouteNode
|
|
176
|
+
export declare const createRouteNodesByFullPath: (routeNodes: Array<RouteNode>) => Map<string, RouteNode>;
|
|
147
177
|
/**
|
|
148
178
|
* Create a map from 'to' to a routeNode
|
|
149
179
|
*/
|
|
150
|
-
export declare const createRouteNodesByTo: (routeNodes: Array<RouteNode
|
|
180
|
+
export declare const createRouteNodesByTo: (routeNodes: Array<RouteNode>) => Map<string, RouteNode>;
|
|
151
181
|
/**
|
|
152
182
|
* Create a map from 'id' to a routeNode
|
|
153
183
|
*/
|
|
@@ -155,7 +185,7 @@ export declare const createRouteNodesById: (routeNodes: Array<RouteNode>) => Map
|
|
|
155
185
|
/**
|
|
156
186
|
* Infers to path
|
|
157
187
|
*/
|
|
158
|
-
export declare const inferTo: (routeNode: RouteNode
|
|
188
|
+
export declare const inferTo: (routeNode: RouteNode) => string;
|
|
159
189
|
/**
|
|
160
190
|
* Dedupes branches and index routes
|
|
161
191
|
*/
|
|
@@ -170,14 +200,7 @@ export declare function buildFileRoutesByPathInterface(opts: {
|
|
|
170
200
|
routeNodes: Array<RouteNode>;
|
|
171
201
|
module: string;
|
|
172
202
|
interfaceName: string;
|
|
173
|
-
config?: Pick<Config, '
|
|
203
|
+
config?: Pick<Config, 'routeToken'>;
|
|
174
204
|
}): string;
|
|
175
205
|
export declare function getImportPath(node: RouteNode, config: Config, generatedRouteTreePath: string): string;
|
|
176
206
|
export declare function getImportForRouteNode(node: RouteNode, config: Config, generatedRouteTreePath: string, root: string): ImportDeclaration;
|
|
177
|
-
/**
|
|
178
|
-
* Used to validate if a route is a pathless layout route
|
|
179
|
-
* @param normalizedRoutePath Normalized route path, i.e `/foo/_layout/route.tsx` and `/foo._layout.route.tsx` to `/foo/_layout/route`
|
|
180
|
-
* @param config The `router-generator` configuration object
|
|
181
|
-
* @returns Boolean indicating if the route is a pathless layout route
|
|
182
|
-
*/
|
|
183
|
-
export declare function isValidNonNestedRoute(normalizedRoutePath: string, config?: Pick<Config, 'experimental' | 'routeToken' | 'indexToken'>): boolean;
|
package/dist/esm/config.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare const baseConfigSchema: z.ZodObject<{
|
|
|
15
15
|
routeToken: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
16
16
|
pathParamsAllowedCharacters: z.ZodOptional<z.ZodArray<z.ZodEnum<[";", ":", "@", "&", "=", "+", "$", ","]>, "many">>;
|
|
17
17
|
}, "strip", z.ZodTypeAny, {
|
|
18
|
-
target: "
|
|
18
|
+
target: "vue" | "react" | "solid";
|
|
19
19
|
routeFileIgnorePrefix: string;
|
|
20
20
|
routesDirectory: string;
|
|
21
21
|
quoteStyle: "single" | "double";
|
|
@@ -27,9 +27,9 @@ export declare const baseConfigSchema: z.ZodObject<{
|
|
|
27
27
|
virtualRouteConfig?: string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
|
|
28
28
|
routeFilePrefix?: string | undefined;
|
|
29
29
|
routeFileIgnorePattern?: string | undefined;
|
|
30
|
-
pathParamsAllowedCharacters?: ("
|
|
30
|
+
pathParamsAllowedCharacters?: (":" | "$" | ";" | "@" | "&" | "=" | "+" | ",")[] | undefined;
|
|
31
31
|
}, {
|
|
32
|
-
target?: "
|
|
32
|
+
target?: "vue" | "react" | "solid" | undefined;
|
|
33
33
|
virtualRouteConfig?: string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
|
|
34
34
|
routeFilePrefix?: string | undefined;
|
|
35
35
|
routeFileIgnorePrefix?: string | undefined;
|
|
@@ -41,7 +41,7 @@ export declare const baseConfigSchema: z.ZodObject<{
|
|
|
41
41
|
routeTreeFileHeader?: string[] | undefined;
|
|
42
42
|
indexToken?: string | undefined;
|
|
43
43
|
routeToken?: string | undefined;
|
|
44
|
-
pathParamsAllowedCharacters?: ("
|
|
44
|
+
pathParamsAllowedCharacters?: (":" | "$" | ";" | "@" | "&" | "=" | "+" | ",")[] | undefined;
|
|
45
45
|
}>;
|
|
46
46
|
export type BaseConfig = z.infer<typeof baseConfigSchema>;
|
|
47
47
|
export declare const configSchema: z.ZodObject<{
|
|
@@ -78,19 +78,16 @@ export declare const configSchema: z.ZodObject<{
|
|
|
78
78
|
}>>;
|
|
79
79
|
experimental: z.ZodOptional<z.ZodObject<{
|
|
80
80
|
enableCodeSplitting: z.ZodOptional<z.ZodBoolean>;
|
|
81
|
-
nonNestedRoutes: z.ZodOptional<z.ZodBoolean>;
|
|
82
81
|
}, "strip", z.ZodTypeAny, {
|
|
83
82
|
enableCodeSplitting?: boolean | undefined;
|
|
84
|
-
nonNestedRoutes?: boolean | undefined;
|
|
85
83
|
}, {
|
|
86
84
|
enableCodeSplitting?: boolean | undefined;
|
|
87
|
-
nonNestedRoutes?: boolean | undefined;
|
|
88
85
|
}>>;
|
|
89
86
|
plugins: z.ZodOptional<z.ZodArray<z.ZodType<GeneratorPlugin, z.ZodTypeDef, GeneratorPlugin>, "many">>;
|
|
90
87
|
tmpDir: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
91
88
|
importRoutesUsingAbsolutePaths: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
92
89
|
}, "strip", z.ZodTypeAny, {
|
|
93
|
-
target: "
|
|
90
|
+
target: "vue" | "react" | "solid";
|
|
94
91
|
routeFileIgnorePrefix: string;
|
|
95
92
|
routesDirectory: string;
|
|
96
93
|
quoteStyle: "single" | "double";
|
|
@@ -105,10 +102,11 @@ export declare const configSchema: z.ZodObject<{
|
|
|
105
102
|
enableRouteTreeFormatting: boolean;
|
|
106
103
|
tmpDir: string;
|
|
107
104
|
importRoutesUsingAbsolutePaths: boolean;
|
|
105
|
+
plugins?: GeneratorPlugin[] | undefined;
|
|
108
106
|
virtualRouteConfig?: string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
|
|
109
107
|
routeFilePrefix?: string | undefined;
|
|
110
108
|
routeFileIgnorePattern?: string | undefined;
|
|
111
|
-
pathParamsAllowedCharacters?: ("
|
|
109
|
+
pathParamsAllowedCharacters?: (":" | "$" | ";" | "@" | "&" | "=" | "+" | ",")[] | undefined;
|
|
112
110
|
verboseFileRoutes?: boolean | undefined;
|
|
113
111
|
routeTreeFileFooter?: string[] | ((...args: unknown[]) => string[]) | undefined;
|
|
114
112
|
autoCodeSplitting?: boolean | undefined;
|
|
@@ -118,11 +116,10 @@ export declare const configSchema: z.ZodObject<{
|
|
|
118
116
|
} | undefined;
|
|
119
117
|
experimental?: {
|
|
120
118
|
enableCodeSplitting?: boolean | undefined;
|
|
121
|
-
nonNestedRoutes?: boolean | undefined;
|
|
122
119
|
} | undefined;
|
|
123
|
-
plugins?: GeneratorPlugin[] | undefined;
|
|
124
120
|
}, {
|
|
125
|
-
|
|
121
|
+
plugins?: GeneratorPlugin[] | undefined;
|
|
122
|
+
target?: "vue" | "react" | "solid" | undefined;
|
|
126
123
|
virtualRouteConfig?: string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
|
|
127
124
|
routeFilePrefix?: string | undefined;
|
|
128
125
|
routeFileIgnorePrefix?: string | undefined;
|
|
@@ -134,7 +131,7 @@ export declare const configSchema: z.ZodObject<{
|
|
|
134
131
|
routeTreeFileHeader?: string[] | undefined;
|
|
135
132
|
indexToken?: string | undefined;
|
|
136
133
|
routeToken?: string | undefined;
|
|
137
|
-
pathParamsAllowedCharacters?: ("
|
|
134
|
+
pathParamsAllowedCharacters?: (":" | "$" | ";" | "@" | "&" | "=" | "+" | ",")[] | undefined;
|
|
138
135
|
generatedRouteTree?: string | undefined;
|
|
139
136
|
disableTypes?: boolean | undefined;
|
|
140
137
|
verboseFileRoutes?: boolean | undefined;
|
|
@@ -148,9 +145,7 @@ export declare const configSchema: z.ZodObject<{
|
|
|
148
145
|
} | undefined;
|
|
149
146
|
experimental?: {
|
|
150
147
|
enableCodeSplitting?: boolean | undefined;
|
|
151
|
-
nonNestedRoutes?: boolean | undefined;
|
|
152
148
|
} | undefined;
|
|
153
|
-
plugins?: GeneratorPlugin[] | undefined;
|
|
154
149
|
tmpDir?: string | undefined;
|
|
155
150
|
importRoutesUsingAbsolutePaths?: boolean | undefined;
|
|
156
151
|
}>;
|
package/dist/esm/config.js
CHANGED
|
@@ -38,9 +38,7 @@ const configSchema = baseConfigSchema.extend({
|
|
|
38
38
|
}).optional(),
|
|
39
39
|
experimental: z.object({
|
|
40
40
|
// TODO: This has been made stable and is now "autoCodeSplitting". Remove in next major version.
|
|
41
|
-
enableCodeSplitting: z.boolean().optional()
|
|
42
|
-
// TODO: This resolves issues with non-nested paths in file-based routing. To be made default in next major version.
|
|
43
|
-
nonNestedRoutes: z.boolean().optional()
|
|
41
|
+
enableCodeSplitting: z.boolean().optional()
|
|
44
42
|
}).optional(),
|
|
45
43
|
plugins: z.array(z.custom()).optional(),
|
|
46
44
|
tmpDir: z.string().optional().default(""),
|
package/dist/esm/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sources":["../../src/config.ts"],"sourcesContent":["import path from 'node:path'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { z } from 'zod'\nimport { virtualRootRouteSchema } from './filesystem/virtual/config'\nimport type { GeneratorPlugin } from './plugin/types'\n\nexport const baseConfigSchema = z.object({\n target: z.enum(['react', 'solid', 'vue']).optional().default('react'),\n virtualRouteConfig: virtualRootRouteSchema.or(z.string()).optional(),\n routeFilePrefix: z.string().optional(),\n routeFileIgnorePrefix: z.string().optional().default('-'),\n routeFileIgnorePattern: z.string().optional(),\n routesDirectory: z.string().optional().default('./src/routes'),\n quoteStyle: z.enum(['single', 'double']).optional().default('single'),\n semicolons: z.boolean().optional().default(false),\n disableLogging: z.boolean().optional().default(false),\n routeTreeFileHeader: z\n .array(z.string())\n .optional()\n .default([\n '/* eslint-disable */',\n '// @ts-nocheck',\n '// noinspection JSUnusedGlobalSymbols',\n ]),\n indexToken: z.string().optional().default('index'),\n routeToken: z.string().optional().default('route'),\n pathParamsAllowedCharacters: z\n .array(z.enum([';', ':', '@', '&', '=', '+', '$', ',']))\n .optional(),\n})\n\nexport type BaseConfig = z.infer<typeof baseConfigSchema>\n\nexport const configSchema = baseConfigSchema.extend({\n generatedRouteTree: z.string().optional().default('./src/routeTree.gen.ts'),\n disableTypes: z.boolean().optional().default(false),\n verboseFileRoutes: z.boolean().optional(),\n addExtensions: z.boolean().optional().default(false),\n enableRouteTreeFormatting: z.boolean().optional().default(true),\n routeTreeFileFooter: z\n .union([\n z.array(z.string()).optional().default([]),\n z.function().returns(z.array(z.string())),\n ])\n .optional(),\n autoCodeSplitting: z.boolean().optional(),\n customScaffolding: z\n .object({\n routeTemplate: z.string().optional(),\n lazyRouteTemplate: z.string().optional(),\n })\n .optional(),\n experimental: z\n .object({\n // TODO: This has been made stable and is now \"autoCodeSplitting\". Remove in next major version.\n enableCodeSplitting: z.boolean().optional(),\n
|
|
1
|
+
{"version":3,"file":"config.js","sources":["../../src/config.ts"],"sourcesContent":["import path from 'node:path'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { z } from 'zod'\nimport { virtualRootRouteSchema } from './filesystem/virtual/config'\nimport type { GeneratorPlugin } from './plugin/types'\n\nexport const baseConfigSchema = z.object({\n target: z.enum(['react', 'solid', 'vue']).optional().default('react'),\n virtualRouteConfig: virtualRootRouteSchema.or(z.string()).optional(),\n routeFilePrefix: z.string().optional(),\n routeFileIgnorePrefix: z.string().optional().default('-'),\n routeFileIgnorePattern: z.string().optional(),\n routesDirectory: z.string().optional().default('./src/routes'),\n quoteStyle: z.enum(['single', 'double']).optional().default('single'),\n semicolons: z.boolean().optional().default(false),\n disableLogging: z.boolean().optional().default(false),\n routeTreeFileHeader: z\n .array(z.string())\n .optional()\n .default([\n '/* eslint-disable */',\n '// @ts-nocheck',\n '// noinspection JSUnusedGlobalSymbols',\n ]),\n indexToken: z.string().optional().default('index'),\n routeToken: z.string().optional().default('route'),\n pathParamsAllowedCharacters: z\n .array(z.enum([';', ':', '@', '&', '=', '+', '$', ',']))\n .optional(),\n})\n\nexport type BaseConfig = z.infer<typeof baseConfigSchema>\n\nexport const configSchema = baseConfigSchema.extend({\n generatedRouteTree: z.string().optional().default('./src/routeTree.gen.ts'),\n disableTypes: z.boolean().optional().default(false),\n verboseFileRoutes: z.boolean().optional(),\n addExtensions: z.boolean().optional().default(false),\n enableRouteTreeFormatting: z.boolean().optional().default(true),\n routeTreeFileFooter: z\n .union([\n z.array(z.string()).optional().default([]),\n z.function().returns(z.array(z.string())),\n ])\n .optional(),\n autoCodeSplitting: z.boolean().optional(),\n customScaffolding: z\n .object({\n routeTemplate: z.string().optional(),\n lazyRouteTemplate: z.string().optional(),\n })\n .optional(),\n experimental: z\n .object({\n // TODO: This has been made stable and is now \"autoCodeSplitting\". Remove in next major version.\n enableCodeSplitting: z.boolean().optional(),\n })\n .optional(),\n plugins: z.array(z.custom<GeneratorPlugin>()).optional(),\n tmpDir: z.string().optional().default(''),\n importRoutesUsingAbsolutePaths: z.boolean().optional().default(false),\n})\n\nexport type Config = z.infer<typeof configSchema>\n\ntype ResolveParams = {\n configDirectory: string\n}\n\nexport function resolveConfigPath({ configDirectory }: ResolveParams) {\n return path.resolve(configDirectory, 'tsr.config.json')\n}\n\nexport function getConfig(\n inlineConfig: Partial<Config> = {},\n configDirectory?: string,\n): Config {\n if (configDirectory === undefined) {\n configDirectory = process.cwd()\n }\n const configFilePathJson = resolveConfigPath({ configDirectory })\n const exists = existsSync(configFilePathJson)\n\n let config: Config\n\n if (exists) {\n config = configSchema.parse({\n ...JSON.parse(readFileSync(configFilePathJson, 'utf-8')),\n ...inlineConfig,\n })\n } else {\n config = configSchema.parse(inlineConfig)\n }\n\n // If typescript is disabled, make sure the generated route tree is a .js file\n if (config.disableTypes) {\n config.generatedRouteTree = config.generatedRouteTree.replace(\n /\\.(ts|tsx)$/,\n '.js',\n )\n }\n\n // if a configDirectory is used, paths should be relative to that directory\n if (configDirectory) {\n // if absolute configDirectory is provided, use it as the root\n if (path.isAbsolute(configDirectory)) {\n config.routesDirectory = path.resolve(\n configDirectory,\n config.routesDirectory,\n )\n config.generatedRouteTree = path.resolve(\n configDirectory,\n config.generatedRouteTree,\n )\n } else {\n config.routesDirectory = path.resolve(\n process.cwd(),\n configDirectory,\n config.routesDirectory,\n )\n config.generatedRouteTree = path.resolve(\n process.cwd(),\n configDirectory,\n config.generatedRouteTree,\n )\n }\n }\n\n const resolveTmpDir = (dir: string | Array<string>) => {\n if (Array.isArray(dir)) {\n dir = path.join(...dir)\n }\n if (!path.isAbsolute(dir)) {\n dir = path.resolve(process.cwd(), dir)\n }\n return dir\n }\n\n if (config.tmpDir) {\n config.tmpDir = resolveTmpDir(config.tmpDir)\n } else if (process.env.TSR_TMP_DIR) {\n config.tmpDir = resolveTmpDir(process.env.TSR_TMP_DIR)\n } else {\n config.tmpDir = resolveTmpDir(['.tanstack', 'tmp'])\n }\n\n validateConfig(config)\n return config\n}\n\nfunction validateConfig(config: Config) {\n if (typeof config.experimental?.enableCodeSplitting !== 'undefined') {\n const message = `\n------\n⚠️ ⚠️ ⚠️\nERROR: The \"experimental.enableCodeSplitting\" flag has been made stable and is now \"autoCodeSplitting\". Please update your configuration file to use \"autoCodeSplitting\" instead of \"experimental.enableCodeSplitting\".\n------\n`\n console.error(message)\n throw new Error(message)\n }\n\n if (config.indexToken === config.routeToken) {\n throw new Error(\n `The \"indexToken\" and \"routeToken\" options must be different.`,\n )\n }\n\n if (\n config.routeFileIgnorePrefix &&\n config.routeFileIgnorePrefix.trim() === '_'\n ) {\n throw new Error(\n `The \"routeFileIgnorePrefix\" cannot be an underscore (\"_\"). This is a reserved character used to denote a pathless route. Please use a different prefix.`,\n )\n }\n\n return config\n}\n"],"names":[],"mappings":";;;;AAMO,MAAM,mBAAmB,EAAE,OAAO;AAAA,EACvC,QAAQ,EAAE,KAAK,CAAC,SAAS,SAAS,KAAK,CAAC,EAAE,WAAW,QAAQ,OAAO;AAAA,EACpE,oBAAoB,uBAAuB,GAAG,EAAE,OAAA,CAAQ,EAAE,SAAA;AAAA,EAC1D,iBAAiB,EAAE,OAAA,EAAS,SAAA;AAAA,EAC5B,uBAAuB,EAAE,OAAA,EAAS,SAAA,EAAW,QAAQ,GAAG;AAAA,EACxD,wBAAwB,EAAE,OAAA,EAAS,SAAA;AAAA,EACnC,iBAAiB,EAAE,OAAA,EAAS,SAAA,EAAW,QAAQ,cAAc;AAAA,EAC7D,YAAY,EAAE,KAAK,CAAC,UAAU,QAAQ,CAAC,EAAE,SAAA,EAAW,QAAQ,QAAQ;AAAA,EACpE,YAAY,EAAE,QAAA,EAAU,SAAA,EAAW,QAAQ,KAAK;AAAA,EAChD,gBAAgB,EAAE,QAAA,EAAU,SAAA,EAAW,QAAQ,KAAK;AAAA,EACpD,qBAAqB,EAClB,MAAM,EAAE,QAAQ,EAChB,SAAA,EACA,QAAQ;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AAAA,EACH,YAAY,EAAE,OAAA,EAAS,SAAA,EAAW,QAAQ,OAAO;AAAA,EACjD,YAAY,EAAE,OAAA,EAAS,SAAA,EAAW,QAAQ,OAAO;AAAA,EACjD,6BAA6B,EAC1B,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG,CAAC,CAAC,EACtD,SAAA;AACL,CAAC;AAIM,MAAM,eAAe,iBAAiB,OAAO;AAAA,EAClD,oBAAoB,EAAE,OAAA,EAAS,SAAA,EAAW,QAAQ,wBAAwB;AAAA,EAC1E,cAAc,EAAE,QAAA,EAAU,SAAA,EAAW,QAAQ,KAAK;AAAA,EAClD,mBAAmB,EAAE,QAAA,EAAU,SAAA;AAAA,EAC/B,eAAe,EAAE,QAAA,EAAU,SAAA,EAAW,QAAQ,KAAK;AAAA,EACnD,2BAA2B,EAAE,QAAA,EAAU,SAAA,EAAW,QAAQ,IAAI;AAAA,EAC9D,qBAAqB,EAClB,MAAM;AAAA,IACL,EAAE,MAAM,EAAE,OAAA,CAAQ,EAAE,SAAA,EAAW,QAAQ,EAAE;AAAA,IACzC,EAAE,WAAW,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;AAAA,EAAA,CACzC,EACA,SAAA;AAAA,EACH,mBAAmB,EAAE,QAAA,EAAU,SAAA;AAAA,EAC/B,mBAAmB,EAChB,OAAO;AAAA,IACN,eAAe,EAAE,OAAA,EAAS,SAAA;AAAA,IAC1B,mBAAmB,EAAE,OAAA,EAAS,SAAA;AAAA,EAAS,CACxC,EACA,SAAA;AAAA,EACH,cAAc,EACX,OAAO;AAAA;AAAA,IAEN,qBAAqB,EAAE,QAAA,EAAU,SAAA;AAAA,EAAS,CAC3C,EACA,SAAA;AAAA,EACH,SAAS,EAAE,MAAM,EAAE,OAAA,CAAyB,EAAE,SAAA;AAAA,EAC9C,QAAQ,EAAE,OAAA,EAAS,SAAA,EAAW,QAAQ,EAAE;AAAA,EACxC,gCAAgC,EAAE,QAAA,EAAU,SAAA,EAAW,QAAQ,KAAK;AACtE,CAAC;AAQM,SAAS,kBAAkB,EAAE,mBAAkC;AACpE,SAAO,KAAK,QAAQ,iBAAiB,iBAAiB;AACxD;AAEO,SAAS,UACd,eAAgC,CAAA,GAChC,iBACQ;AACR,MAAI,oBAAoB,QAAW;AACjC,sBAAkB,QAAQ,IAAA;AAAA,EAC5B;AACA,QAAM,qBAAqB,kBAAkB,EAAE,iBAAiB;AAChE,QAAM,SAAS,WAAW,kBAAkB;AAE5C,MAAI;AAEJ,MAAI,QAAQ;AACV,aAAS,aAAa,MAAM;AAAA,MAC1B,GAAG,KAAK,MAAM,aAAa,oBAAoB,OAAO,CAAC;AAAA,MACvD,GAAG;AAAA,IAAA,CACJ;AAAA,EACH,OAAO;AACL,aAAS,aAAa,MAAM,YAAY;AAAA,EAC1C;AAGA,MAAI,OAAO,cAAc;AACvB,WAAO,qBAAqB,OAAO,mBAAmB;AAAA,MACpD;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AAGA,MAAI,iBAAiB;AAEnB,QAAI,KAAK,WAAW,eAAe,GAAG;AACpC,aAAO,kBAAkB,KAAK;AAAA,QAC5B;AAAA,QACA,OAAO;AAAA,MAAA;AAET,aAAO,qBAAqB,KAAK;AAAA,QAC/B;AAAA,QACA,OAAO;AAAA,MAAA;AAAA,IAEX,OAAO;AACL,aAAO,kBAAkB,KAAK;AAAA,QAC5B,QAAQ,IAAA;AAAA,QACR;AAAA,QACA,OAAO;AAAA,MAAA;AAET,aAAO,qBAAqB,KAAK;AAAA,QAC/B,QAAQ,IAAA;AAAA,QACR;AAAA,QACA,OAAO;AAAA,MAAA;AAAA,IAEX;AAAA,EACF;AAEA,QAAM,gBAAgB,CAAC,QAAgC;AACrD,QAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,YAAM,KAAK,KAAK,GAAG,GAAG;AAAA,IACxB;AACA,QAAI,CAAC,KAAK,WAAW,GAAG,GAAG;AACzB,YAAM,KAAK,QAAQ,QAAQ,IAAA,GAAO,GAAG;AAAA,IACvC;AACA,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,QAAQ;AACjB,WAAO,SAAS,cAAc,OAAO,MAAM;AAAA,EAC7C,WAAW,QAAQ,IAAI,aAAa;AAClC,WAAO,SAAS,cAAc,QAAQ,IAAI,WAAW;AAAA,EACvD,OAAO;AACL,WAAO,SAAS,cAAc,CAAC,aAAa,KAAK,CAAC;AAAA,EACpD;AAEA,iBAAe,MAAM;AACrB,SAAO;AACT;AAEA,SAAS,eAAe,QAAgB;AACtC,MAAI,OAAO,OAAO,cAAc,wBAAwB,aAAa;AACnE,UAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAMhB,YAAQ,MAAM,OAAO;AACrB,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,MAAI,OAAO,eAAe,OAAO,YAAY;AAC3C,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AAEA,MACE,OAAO,yBACP,OAAO,sBAAsB,KAAA,MAAW,KACxC;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AAEA,SAAO;AACT;"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { FsRouteType, GetRouteNodesResult } from '../../types.js';
|
|
2
2
|
import { Config } from '../../config.js';
|
|
3
3
|
export declare function isVirtualConfigFile(fileName: string): boolean;
|
|
4
|
-
export declare function getRouteNodes(config: Pick<Config, 'routesDirectory' | 'routeFilePrefix' | 'routeFileIgnorePrefix' | 'routeFileIgnorePattern' | 'disableLogging' | 'routeToken' | 'indexToken'
|
|
4
|
+
export declare function getRouteNodes(config: Pick<Config, 'routesDirectory' | 'routeFilePrefix' | 'routeFileIgnorePrefix' | 'routeFileIgnorePattern' | 'disableLogging' | 'routeToken' | 'indexToken'>, root: string): Promise<GetRouteNodesResult>;
|
|
5
5
|
/**
|
|
6
6
|
* Determines the metadata for a given route path based on the provided configuration.
|
|
7
7
|
*
|
|
8
|
-
* @param routePath - The determined initial routePath.
|
|
8
|
+
* @param routePath - The determined initial routePath (with brackets removed).
|
|
9
|
+
* @param originalRoutePath - The original route path (may contain brackets for escaped content).
|
|
9
10
|
* @param config - The user configuration object.
|
|
10
11
|
* @returns An object containing the type of the route and the variable name derived from the route path.
|
|
11
12
|
*/
|
|
12
|
-
export declare function getRouteMeta(routePath: string, config: Pick<Config, 'routeToken' | 'indexToken'>): {
|
|
13
|
+
export declare function getRouteMeta(routePath: string, originalRoutePath: string, config: Pick<Config, 'routeToken' | 'indexToken'>): {
|
|
13
14
|
fsRouteType: Extract<FsRouteType, 'static' | 'layout' | 'api' | 'lazy' | 'loader' | 'component' | 'pendingComponent' | 'errorComponent' | 'notFoundComponent'>;
|
|
14
15
|
variableName: string;
|
|
15
16
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import * as fsp from "node:fs/promises";
|
|
3
|
-
import { replaceBackslash, routePathToVariable, removeExt, determineInitialRoutePath } from "../../utils.js";
|
|
3
|
+
import { replaceBackslash, routePathToVariable, removeExt, determineInitialRoutePath, hasEscapedLeadingUnderscore } from "../../utils.js";
|
|
4
4
|
import { getRouteNodes as getRouteNodes$1 } from "../virtual/getRouteNodes.js";
|
|
5
5
|
import { loadConfigFile } from "../virtual/loadConfigFile.js";
|
|
6
6
|
import { logging } from "../../logger.js";
|
|
@@ -84,9 +84,8 @@ async function getRouteNodes(config, root) {
|
|
|
84
84
|
const filePathNoExt = removeExt(filePath);
|
|
85
85
|
const {
|
|
86
86
|
routePath: initialRoutePath,
|
|
87
|
-
originalRoutePath: initialOriginalRoutePath
|
|
88
|
-
|
|
89
|
-
} = determineInitialRoutePath(filePathNoExt, config);
|
|
87
|
+
originalRoutePath: initialOriginalRoutePath
|
|
88
|
+
} = determineInitialRoutePath(filePathNoExt);
|
|
90
89
|
let routePath = initialRoutePath;
|
|
91
90
|
let originalRoutePath = initialOriginalRoutePath;
|
|
92
91
|
if (routeFilePrefix) {
|
|
@@ -101,14 +100,19 @@ async function getRouteNodes(config, root) {
|
|
|
101
100
|
logger.error(`ERROR: ${errorMessage}`);
|
|
102
101
|
throw new Error(errorMessage);
|
|
103
102
|
}
|
|
104
|
-
const meta = getRouteMeta(routePath, config);
|
|
103
|
+
const meta = getRouteMeta(routePath, originalRoutePath, config);
|
|
105
104
|
const variableName = meta.variableName;
|
|
106
105
|
let routeType = meta.fsRouteType;
|
|
107
106
|
if (routeType === "lazy") {
|
|
108
107
|
routePath = routePath.replace(/\/lazy$/, "");
|
|
109
108
|
originalRoutePath = originalRoutePath.replace(/\/lazy$/, "");
|
|
110
109
|
}
|
|
111
|
-
if (isValidPathlessLayoutRoute(
|
|
110
|
+
if (isValidPathlessLayoutRoute(
|
|
111
|
+
routePath,
|
|
112
|
+
originalRoutePath,
|
|
113
|
+
routeType,
|
|
114
|
+
config
|
|
115
|
+
)) {
|
|
112
116
|
routeType = "pathless_layout";
|
|
113
117
|
}
|
|
114
118
|
const isVueFile = filePath.endsWith(".vue");
|
|
@@ -127,36 +131,50 @@ async function getRouteNodes(config, root) {
|
|
|
127
131
|
}
|
|
128
132
|
});
|
|
129
133
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
""
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
|
|
134
|
+
const originalSegments = originalRoutePath.split("/").filter(Boolean);
|
|
135
|
+
const lastOriginalSegmentForSuffix = originalSegments[originalSegments.length - 1] || "";
|
|
136
|
+
const specialSuffixes = [
|
|
137
|
+
"component",
|
|
138
|
+
"errorComponent",
|
|
139
|
+
"notFoundComponent",
|
|
140
|
+
"pendingComponent",
|
|
141
|
+
"loader",
|
|
142
|
+
config.routeToken,
|
|
143
|
+
"lazy"
|
|
144
|
+
];
|
|
145
|
+
const suffixToStrip = specialSuffixes.find((suffix) => {
|
|
146
|
+
const endsWithSuffix = routePath.endsWith(`/${suffix}`);
|
|
147
|
+
const isEscaped = lastOriginalSegmentForSuffix === `[${suffix}]`;
|
|
148
|
+
return endsWithSuffix && !isEscaped;
|
|
149
|
+
});
|
|
150
|
+
if (suffixToStrip) {
|
|
151
|
+
routePath = routePath.replace(new RegExp(`/${suffixToStrip}$`), "");
|
|
152
|
+
originalRoutePath = originalRoutePath.replace(
|
|
153
|
+
new RegExp(`/${suffixToStrip}$`),
|
|
154
|
+
""
|
|
155
|
+
);
|
|
144
156
|
}
|
|
145
|
-
|
|
146
|
-
|
|
157
|
+
const lastOriginalSegment = originalRoutePath.split("/").filter(Boolean).pop() || "";
|
|
158
|
+
const isIndexEscaped = lastOriginalSegment === `[${config.indexToken}]`;
|
|
159
|
+
if (!isIndexEscaped) {
|
|
160
|
+
if (routePath === config.indexToken) {
|
|
161
|
+
routePath = "/";
|
|
162
|
+
}
|
|
163
|
+
if (originalRoutePath === config.indexToken) {
|
|
164
|
+
originalRoutePath = "/";
|
|
165
|
+
}
|
|
166
|
+
routePath = routePath.replace(new RegExp(`/${config.indexToken}$`), "/") || "/";
|
|
167
|
+
originalRoutePath = originalRoutePath.replace(
|
|
168
|
+
new RegExp(`/${config.indexToken}$`),
|
|
169
|
+
"/"
|
|
170
|
+
) || "/";
|
|
147
171
|
}
|
|
148
|
-
routePath = routePath.replace(new RegExp(`/${config.indexToken}$`), "/") || "/";
|
|
149
|
-
originalRoutePath = originalRoutePath.replace(
|
|
150
|
-
new RegExp(`/${config.indexToken}$`),
|
|
151
|
-
"/"
|
|
152
|
-
) || "/";
|
|
153
172
|
routeNodes.push({
|
|
154
173
|
filePath,
|
|
155
174
|
fullPath,
|
|
156
175
|
routePath,
|
|
157
176
|
variableName,
|
|
158
177
|
_fsRouteType: routeType,
|
|
159
|
-
_isExperimentalNonNestedRoute: isExperimentalNonNestedRoute,
|
|
160
178
|
originalRoutePath
|
|
161
179
|
});
|
|
162
180
|
}
|
|
@@ -185,42 +203,56 @@ async function getRouteNodes(config, root) {
|
|
|
185
203
|
physicalDirectories: allPhysicalDirectories
|
|
186
204
|
};
|
|
187
205
|
}
|
|
188
|
-
function getRouteMeta(routePath, config) {
|
|
206
|
+
function getRouteMeta(routePath, originalRoutePath, config) {
|
|
189
207
|
let fsRouteType = "static";
|
|
190
|
-
|
|
208
|
+
const originalSegments = originalRoutePath.split("/").filter(Boolean);
|
|
209
|
+
const lastOriginalSegment = originalSegments[originalSegments.length - 1] || "";
|
|
210
|
+
const isSuffixEscaped = (suffix) => {
|
|
211
|
+
return lastOriginalSegment === `[${suffix}]`;
|
|
212
|
+
};
|
|
213
|
+
if (routePath.endsWith(`/${config.routeToken}`) && !isSuffixEscaped(config.routeToken)) {
|
|
191
214
|
fsRouteType = "layout";
|
|
192
|
-
} else if (routePath.endsWith("/lazy")) {
|
|
215
|
+
} else if (routePath.endsWith("/lazy") && !isSuffixEscaped("lazy")) {
|
|
193
216
|
fsRouteType = "lazy";
|
|
194
|
-
} else if (routePath.endsWith("/loader")) {
|
|
217
|
+
} else if (routePath.endsWith("/loader") && !isSuffixEscaped("loader")) {
|
|
195
218
|
fsRouteType = "loader";
|
|
196
|
-
} else if (routePath.endsWith("/component")) {
|
|
219
|
+
} else if (routePath.endsWith("/component") && !isSuffixEscaped("component")) {
|
|
197
220
|
fsRouteType = "component";
|
|
198
|
-
} else if (routePath.endsWith("/pendingComponent")) {
|
|
221
|
+
} else if (routePath.endsWith("/pendingComponent") && !isSuffixEscaped("pendingComponent")) {
|
|
199
222
|
fsRouteType = "pendingComponent";
|
|
200
|
-
} else if (routePath.endsWith("/errorComponent")) {
|
|
223
|
+
} else if (routePath.endsWith("/errorComponent") && !isSuffixEscaped("errorComponent")) {
|
|
201
224
|
fsRouteType = "errorComponent";
|
|
202
|
-
} else if (routePath.endsWith("/notFoundComponent")) {
|
|
225
|
+
} else if (routePath.endsWith("/notFoundComponent") && !isSuffixEscaped("notFoundComponent")) {
|
|
203
226
|
fsRouteType = "notFoundComponent";
|
|
204
227
|
}
|
|
205
228
|
const variableName = routePathToVariable(routePath);
|
|
206
229
|
return { fsRouteType, variableName };
|
|
207
230
|
}
|
|
208
|
-
function isValidPathlessLayoutRoute(normalizedRoutePath, routeType, config) {
|
|
231
|
+
function isValidPathlessLayoutRoute(normalizedRoutePath, originalRoutePath, routeType, config) {
|
|
209
232
|
if (routeType === "lazy") {
|
|
210
233
|
return false;
|
|
211
234
|
}
|
|
212
235
|
const segments = normalizedRoutePath.split("/").filter(Boolean);
|
|
236
|
+
const originalSegments = originalRoutePath.split("/").filter(Boolean);
|
|
213
237
|
if (segments.length === 0) {
|
|
214
238
|
return false;
|
|
215
239
|
}
|
|
216
240
|
const lastRouteSegment = segments[segments.length - 1];
|
|
241
|
+
const lastOriginalSegment = originalSegments[originalSegments.length - 1] || "";
|
|
217
242
|
const secondToLastRouteSegment = segments[segments.length - 2];
|
|
243
|
+
const secondToLastOriginalSegment = originalSegments[originalSegments.length - 2];
|
|
218
244
|
if (lastRouteSegment === rootPathId) {
|
|
219
245
|
return false;
|
|
220
246
|
}
|
|
221
|
-
if (lastRouteSegment === config.routeToken && typeof secondToLastRouteSegment === "string") {
|
|
247
|
+
if (lastRouteSegment === config.routeToken && typeof secondToLastRouteSegment === "string" && typeof secondToLastOriginalSegment === "string") {
|
|
248
|
+
if (hasEscapedLeadingUnderscore(secondToLastOriginalSegment)) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
222
251
|
return secondToLastRouteSegment.startsWith("_");
|
|
223
252
|
}
|
|
253
|
+
if (hasEscapedLeadingUnderscore(lastOriginalSegment)) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
224
256
|
return lastRouteSegment !== config.indexToken && lastRouteSegment !== config.routeToken && lastRouteSegment.startsWith("_");
|
|
225
257
|
}
|
|
226
258
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getRouteNodes.js","sources":["../../../../src/filesystem/physical/getRouteNodes.ts"],"sourcesContent":["import path from 'node:path'\nimport * as fsp from 'node:fs/promises'\nimport {\n determineInitialRoutePath,\n removeExt,\n replaceBackslash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesVirtual } from '../virtual/getRouteNodes'\nimport { loadConfigFile } from '../virtual/loadConfigFile'\nimport { logging } from '../../logger'\nimport { rootPathId } from './rootPathId'\nimport type {\n VirtualRootRoute,\n VirtualRouteSubtreeConfig,\n} from '@tanstack/virtual-file-routes'\nimport type { FsRouteType, GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\n\nconst disallowedRouteGroupConfiguration = /\\(([^)]+)\\).(ts|js|tsx|jsx|vue)/\n\nconst virtualConfigFileRegExp = /__virtual\\.[mc]?[jt]s$/\nexport function isVirtualConfigFile(fileName: string): boolean {\n return virtualConfigFileRegExp.test(fileName)\n}\n\nexport async function getRouteNodes(\n config: Pick<\n Config,\n | 'routesDirectory'\n | 'routeFilePrefix'\n | 'routeFileIgnorePrefix'\n | 'routeFileIgnorePattern'\n | 'disableLogging'\n | 'routeToken'\n | 'indexToken'\n | 'experimental'\n >,\n root: string,\n): Promise<GetRouteNodesResult> {\n const { routeFilePrefix, routeFileIgnorePrefix, routeFileIgnorePattern } =\n config\n\n const logger = logging({ disabled: config.disableLogging })\n const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? '', 'g')\n\n const routeNodes: Array<RouteNode> = []\n const allPhysicalDirectories: Array<string> = []\n\n async function recurse(dir: string) {\n const fullDir = path.resolve(config.routesDirectory, dir)\n let dirList = await fsp.readdir(fullDir, { withFileTypes: true })\n\n dirList = dirList.filter((d) => {\n if (\n d.name.startsWith('.') ||\n (routeFileIgnorePrefix && d.name.startsWith(routeFileIgnorePrefix))\n ) {\n return false\n }\n\n if (routeFilePrefix) {\n if (routeFileIgnorePattern) {\n return (\n d.name.startsWith(routeFilePrefix) &&\n !d.name.match(routeFileIgnoreRegExp)\n )\n }\n\n return d.name.startsWith(routeFilePrefix)\n }\n\n if (routeFileIgnorePattern) {\n return !d.name.match(routeFileIgnoreRegExp)\n }\n\n return true\n })\n\n const virtualConfigFile = dirList.find((dirent) => {\n return dirent.isFile() && isVirtualConfigFile(dirent.name)\n })\n\n if (virtualConfigFile !== undefined) {\n const virtualRouteConfigExport = await loadConfigFile(\n path.resolve(fullDir, virtualConfigFile.name),\n )\n let virtualRouteSubtreeConfig: VirtualRouteSubtreeConfig\n if (typeof virtualRouteConfigExport.default === 'function') {\n virtualRouteSubtreeConfig = await virtualRouteConfigExport.default()\n } else {\n virtualRouteSubtreeConfig = virtualRouteConfigExport.default\n }\n const dummyRoot: VirtualRootRoute = {\n type: 'root',\n file: '',\n children: virtualRouteSubtreeConfig,\n }\n const { routeNodes: virtualRouteNodes, physicalDirectories } =\n await getRouteNodesVirtual(\n {\n ...config,\n routesDirectory: fullDir,\n virtualRouteConfig: dummyRoot,\n },\n root,\n )\n allPhysicalDirectories.push(...physicalDirectories)\n virtualRouteNodes.forEach((node) => {\n const filePath = replaceBackslash(path.join(dir, node.filePath))\n const routePath = `/${dir}${node.routePath}`\n\n node.variableName = routePathToVariable(\n `${dir}/${removeExt(node.filePath)}`,\n )\n node.routePath = routePath\n node.filePath = filePath\n })\n\n routeNodes.push(...virtualRouteNodes)\n\n return\n }\n\n await Promise.all(\n dirList.map(async (dirent) => {\n const fullPath = replaceBackslash(path.join(fullDir, dirent.name))\n const relativePath = path.posix.join(dir, dirent.name)\n\n if (dirent.isDirectory()) {\n await recurse(relativePath)\n } else if (fullPath.match(/\\.(tsx|ts|jsx|js|vue)$/)) {\n const filePath = replaceBackslash(path.join(dir, dirent.name))\n const filePathNoExt = removeExt(filePath)\n const {\n routePath: initialRoutePath,\n originalRoutePath: initialOriginalRoutePath,\n isExperimentalNonNestedRoute,\n } = determineInitialRoutePath(filePathNoExt, config)\n\n let routePath = initialRoutePath\n let originalRoutePath = initialOriginalRoutePath\n\n if (routeFilePrefix) {\n routePath = routePath.replaceAll(routeFilePrefix, '')\n originalRoutePath = originalRoutePath.replaceAll(\n routeFilePrefix,\n '',\n )\n }\n\n if (disallowedRouteGroupConfiguration.test(dirent.name)) {\n 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?`\n logger.error(`ERROR: ${errorMessage}`)\n throw new Error(errorMessage)\n }\n\n const meta = getRouteMeta(routePath, config)\n const variableName = meta.variableName\n let routeType: FsRouteType = meta.fsRouteType\n\n if (routeType === 'lazy') {\n routePath = routePath.replace(/\\/lazy$/, '')\n originalRoutePath = originalRoutePath.replace(/\\/lazy$/, '')\n }\n\n // this check needs to happen after the lazy route has been cleaned up\n // since the routePath is used to determine if a route is pathless\n if (isValidPathlessLayoutRoute(routePath, routeType, config)) {\n routeType = 'pathless_layout'\n }\n\n // Only show deprecation warning for .tsx/.ts files, not .vue files\n // Vue files using .component.vue is the Vue-native way\n const isVueFile = filePath.endsWith('.vue')\n if (!isVueFile) {\n ;(\n [\n ['component', 'component'],\n ['errorComponent', 'errorComponent'],\n ['notFoundComponent', 'notFoundComponent'],\n ['pendingComponent', 'pendingComponent'],\n ['loader', 'loader'],\n ] satisfies Array<[FsRouteType, string]>\n ).forEach(([matcher, type]) => {\n if (routeType === matcher) {\n logger.warn(\n `WARNING: The \\`.${type}.tsx\\` suffix used for the ${filePath} file is deprecated. Use the new \\`.lazy.tsx\\` suffix instead.`,\n )\n }\n })\n }\n\n routePath = routePath.replace(\n new RegExp(\n `/(component|errorComponent|notFoundComponent|pendingComponent|loader|${config.routeToken}|lazy)$`,\n ),\n '',\n )\n\n originalRoutePath = originalRoutePath.replace(\n new RegExp(\n `/(component|errorComponent|notFoundComponent|pendingComponent|loader|${config.routeToken}|lazy)$`,\n ),\n '',\n )\n\n if (routePath === config.indexToken) {\n routePath = '/'\n }\n\n if (originalRoutePath === config.indexToken) {\n originalRoutePath = '/'\n }\n\n routePath =\n routePath.replace(new RegExp(`/${config.indexToken}$`), '/') || '/'\n\n originalRoutePath =\n originalRoutePath.replace(\n new RegExp(`/${config.indexToken}$`),\n '/',\n ) || '/'\n\n routeNodes.push({\n filePath,\n fullPath,\n routePath,\n variableName,\n _fsRouteType: routeType,\n _isExperimentalNonNestedRoute: isExperimentalNonNestedRoute,\n originalRoutePath,\n })\n }\n }),\n )\n\n return routeNodes\n }\n\n await recurse('./')\n\n // Find the root route node - prefer the actual route file over component/loader files\n const rootRouteNode =\n routeNodes.find(\n (d) =>\n d.routePath === `/${rootPathId}` &&\n ![\n 'component',\n 'errorComponent',\n 'notFoundComponent',\n 'pendingComponent',\n 'loader',\n 'lazy',\n ].includes(d._fsRouteType),\n ) ?? routeNodes.find((d) => d.routePath === `/${rootPathId}`)\n if (rootRouteNode) {\n rootRouteNode._fsRouteType = '__root'\n rootRouteNode.variableName = 'root'\n }\n\n return {\n rootRouteNode,\n routeNodes,\n physicalDirectories: allPhysicalDirectories,\n }\n}\n\n/**\n * Determines the metadata for a given route path based on the provided configuration.\n *\n * @param routePath - The determined initial routePath.\n * @param config - The user configuration object.\n * @returns An object containing the type of the route and the variable name derived from the route path.\n */\nexport function getRouteMeta(\n routePath: string,\n config: Pick<Config, 'routeToken' | 'indexToken'>,\n): {\n // `__root` is can be more easily determined by filtering down to routePath === /${rootPathId}\n // `pathless` is needs to determined after `lazy` has been cleaned up from the routePath\n fsRouteType: Extract<\n FsRouteType,\n | 'static'\n | 'layout'\n | 'api'\n | 'lazy'\n | 'loader'\n | 'component'\n | 'pendingComponent'\n | 'errorComponent'\n | 'notFoundComponent'\n >\n variableName: string\n} {\n let fsRouteType: FsRouteType = 'static'\n\n if (routePath.endsWith(`/${config.routeToken}`)) {\n // layout routes, i.e `/foo/route.tsx` or `/foo/_layout/route.tsx`\n fsRouteType = 'layout'\n } else if (routePath.endsWith('/lazy')) {\n // lazy routes, i.e. `/foo.lazy.tsx`\n fsRouteType = 'lazy'\n } else if (routePath.endsWith('/loader')) {\n // loader routes, i.e. `/foo.loader.tsx`\n fsRouteType = 'loader'\n } else if (routePath.endsWith('/component')) {\n // component routes, i.e. `/foo.component.tsx`\n fsRouteType = 'component'\n } else if (routePath.endsWith('/pendingComponent')) {\n // pending component routes, i.e. `/foo.pendingComponent.tsx`\n fsRouteType = 'pendingComponent'\n } else if (routePath.endsWith('/errorComponent')) {\n // error component routes, i.e. `/foo.errorComponent.tsx`\n fsRouteType = 'errorComponent'\n } else if (routePath.endsWith('/notFoundComponent')) {\n // not found component routes, i.e. `/foo.notFoundComponent.tsx`\n fsRouteType = 'notFoundComponent'\n }\n\n const variableName = routePathToVariable(routePath)\n\n return { fsRouteType, variableName }\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 */\nfunction isValidPathlessLayoutRoute(\n normalizedRoutePath: string,\n routeType: FsRouteType,\n config: Pick<Config, 'routeToken' | 'indexToken'>,\n): boolean {\n if (routeType === 'lazy') {\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 const secondToLastRouteSegment = segments[segments.length - 2]\n\n // If segment === __root, then exit as false\n if (lastRouteSegment === rootPathId) {\n return false\n }\n\n // If segment === config.routeToken and secondToLastSegment is a string that starts with _, then exit as true\n // Since the route is actually a configuration route for a layout/pathless route\n // i.e. /foo/_layout/route.tsx === /foo/_layout.tsx\n if (\n lastRouteSegment === config.routeToken &&\n typeof secondToLastRouteSegment === 'string'\n ) {\n return secondToLastRouteSegment.startsWith('_')\n }\n\n // Segment starts with _\n return (\n lastRouteSegment !== config.indexToken &&\n lastRouteSegment !== config.routeToken &&\n lastRouteSegment.startsWith('_')\n )\n}\n"],"names":["getRouteNodesVirtual"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"getRouteNodes.js","sources":["../../../../src/filesystem/physical/getRouteNodes.ts"],"sourcesContent":["import path from 'node:path'\nimport * as fsp from 'node:fs/promises'\nimport {\n determineInitialRoutePath,\n hasEscapedLeadingUnderscore,\n removeExt,\n replaceBackslash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesVirtual } from '../virtual/getRouteNodes'\nimport { loadConfigFile } from '../virtual/loadConfigFile'\nimport { logging } from '../../logger'\nimport { rootPathId } from './rootPathId'\nimport type {\n VirtualRootRoute,\n VirtualRouteSubtreeConfig,\n} from '@tanstack/virtual-file-routes'\nimport type { FsRouteType, GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\n\nconst disallowedRouteGroupConfiguration = /\\(([^)]+)\\).(ts|js|tsx|jsx|vue)/\n\nconst virtualConfigFileRegExp = /__virtual\\.[mc]?[jt]s$/\nexport function isVirtualConfigFile(fileName: string): boolean {\n return virtualConfigFileRegExp.test(fileName)\n}\n\nexport async function getRouteNodes(\n config: Pick<\n Config,\n | 'routesDirectory'\n | 'routeFilePrefix'\n | 'routeFileIgnorePrefix'\n | 'routeFileIgnorePattern'\n | 'disableLogging'\n | 'routeToken'\n | 'indexToken'\n >,\n root: string,\n): Promise<GetRouteNodesResult> {\n const { routeFilePrefix, routeFileIgnorePrefix, routeFileIgnorePattern } =\n config\n\n const logger = logging({ disabled: config.disableLogging })\n const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? '', 'g')\n\n const routeNodes: Array<RouteNode> = []\n const allPhysicalDirectories: Array<string> = []\n\n async function recurse(dir: string) {\n const fullDir = path.resolve(config.routesDirectory, dir)\n let dirList = await fsp.readdir(fullDir, { withFileTypes: true })\n\n dirList = dirList.filter((d) => {\n if (\n d.name.startsWith('.') ||\n (routeFileIgnorePrefix && d.name.startsWith(routeFileIgnorePrefix))\n ) {\n return false\n }\n\n if (routeFilePrefix) {\n if (routeFileIgnorePattern) {\n return (\n d.name.startsWith(routeFilePrefix) &&\n !d.name.match(routeFileIgnoreRegExp)\n )\n }\n\n return d.name.startsWith(routeFilePrefix)\n }\n\n if (routeFileIgnorePattern) {\n return !d.name.match(routeFileIgnoreRegExp)\n }\n\n return true\n })\n\n const virtualConfigFile = dirList.find((dirent) => {\n return dirent.isFile() && isVirtualConfigFile(dirent.name)\n })\n\n if (virtualConfigFile !== undefined) {\n const virtualRouteConfigExport = await loadConfigFile(\n path.resolve(fullDir, virtualConfigFile.name),\n )\n let virtualRouteSubtreeConfig: VirtualRouteSubtreeConfig\n if (typeof virtualRouteConfigExport.default === 'function') {\n virtualRouteSubtreeConfig = await virtualRouteConfigExport.default()\n } else {\n virtualRouteSubtreeConfig = virtualRouteConfigExport.default\n }\n const dummyRoot: VirtualRootRoute = {\n type: 'root',\n file: '',\n children: virtualRouteSubtreeConfig,\n }\n const { routeNodes: virtualRouteNodes, physicalDirectories } =\n await getRouteNodesVirtual(\n {\n ...config,\n routesDirectory: fullDir,\n virtualRouteConfig: dummyRoot,\n },\n root,\n )\n allPhysicalDirectories.push(...physicalDirectories)\n virtualRouteNodes.forEach((node) => {\n const filePath = replaceBackslash(path.join(dir, node.filePath))\n const routePath = `/${dir}${node.routePath}`\n\n node.variableName = routePathToVariable(\n `${dir}/${removeExt(node.filePath)}`,\n )\n node.routePath = routePath\n node.filePath = filePath\n })\n\n routeNodes.push(...virtualRouteNodes)\n\n return\n }\n\n await Promise.all(\n dirList.map(async (dirent) => {\n const fullPath = replaceBackslash(path.join(fullDir, dirent.name))\n const relativePath = path.posix.join(dir, dirent.name)\n\n if (dirent.isDirectory()) {\n await recurse(relativePath)\n } else if (fullPath.match(/\\.(tsx|ts|jsx|js|vue)$/)) {\n const filePath = replaceBackslash(path.join(dir, dirent.name))\n const filePathNoExt = removeExt(filePath)\n const {\n routePath: initialRoutePath,\n originalRoutePath: initialOriginalRoutePath,\n } = determineInitialRoutePath(filePathNoExt)\n\n let routePath = initialRoutePath\n let originalRoutePath = initialOriginalRoutePath\n\n if (routeFilePrefix) {\n routePath = routePath.replaceAll(routeFilePrefix, '')\n originalRoutePath = originalRoutePath.replaceAll(\n routeFilePrefix,\n '',\n )\n }\n\n if (disallowedRouteGroupConfiguration.test(dirent.name)) {\n 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?`\n logger.error(`ERROR: ${errorMessage}`)\n throw new Error(errorMessage)\n }\n\n const meta = getRouteMeta(routePath, originalRoutePath, config)\n const variableName = meta.variableName\n let routeType: FsRouteType = meta.fsRouteType\n\n if (routeType === 'lazy') {\n routePath = routePath.replace(/\\/lazy$/, '')\n originalRoutePath = originalRoutePath.replace(/\\/lazy$/, '')\n }\n\n // this check needs to happen after the lazy route has been cleaned up\n // since the routePath is used to determine if a route is pathless\n if (\n isValidPathlessLayoutRoute(\n routePath,\n originalRoutePath,\n routeType,\n config,\n )\n ) {\n routeType = 'pathless_layout'\n }\n\n // Only show deprecation warning for .tsx/.ts files, not .vue files\n // Vue files using .component.vue is the Vue-native way\n const isVueFile = filePath.endsWith('.vue')\n if (!isVueFile) {\n ;(\n [\n ['component', 'component'],\n ['errorComponent', 'errorComponent'],\n ['notFoundComponent', 'notFoundComponent'],\n ['pendingComponent', 'pendingComponent'],\n ['loader', 'loader'],\n ] satisfies Array<[FsRouteType, string]>\n ).forEach(([matcher, type]) => {\n if (routeType === matcher) {\n logger.warn(\n `WARNING: The \\`.${type}.tsx\\` suffix used for the ${filePath} file is deprecated. Use the new \\`.lazy.tsx\\` suffix instead.`,\n )\n }\n })\n }\n\n // Get the last segment of originalRoutePath to check for escaping\n const originalSegments = originalRoutePath.split('/').filter(Boolean)\n const lastOriginalSegmentForSuffix =\n originalSegments[originalSegments.length - 1] || ''\n\n // List of special suffixes that can be escaped\n const specialSuffixes = [\n 'component',\n 'errorComponent',\n 'notFoundComponent',\n 'pendingComponent',\n 'loader',\n config.routeToken,\n 'lazy',\n ]\n\n // Only strip the suffix if it wasn't escaped (not wrapped in brackets)\n const suffixToStrip = specialSuffixes.find((suffix) => {\n const endsWithSuffix = routePath.endsWith(`/${suffix}`)\n const isEscaped = lastOriginalSegmentForSuffix === `[${suffix}]`\n return endsWithSuffix && !isEscaped\n })\n\n if (suffixToStrip) {\n routePath = routePath.replace(new RegExp(`/${suffixToStrip}$`), '')\n originalRoutePath = originalRoutePath.replace(\n new RegExp(`/${suffixToStrip}$`),\n '',\n )\n }\n\n // Check if the index token should be treated specially or as a literal path\n // If it's escaped (wrapped in brackets in originalRoutePath), it should be literal\n const lastOriginalSegment =\n originalRoutePath.split('/').filter(Boolean).pop() || ''\n const isIndexEscaped =\n lastOriginalSegment === `[${config.indexToken}]`\n\n if (!isIndexEscaped) {\n if (routePath === config.indexToken) {\n routePath = '/'\n }\n\n if (originalRoutePath === config.indexToken) {\n originalRoutePath = '/'\n }\n\n routePath =\n routePath.replace(new RegExp(`/${config.indexToken}$`), '/') ||\n '/'\n\n originalRoutePath =\n originalRoutePath.replace(\n new RegExp(`/${config.indexToken}$`),\n '/',\n ) || '/'\n }\n\n routeNodes.push({\n filePath,\n fullPath,\n routePath,\n variableName,\n _fsRouteType: routeType,\n originalRoutePath,\n })\n }\n }),\n )\n\n return routeNodes\n }\n\n await recurse('./')\n\n // Find the root route node - prefer the actual route file over component/loader files\n const rootRouteNode =\n routeNodes.find(\n (d) =>\n d.routePath === `/${rootPathId}` &&\n ![\n 'component',\n 'errorComponent',\n 'notFoundComponent',\n 'pendingComponent',\n 'loader',\n 'lazy',\n ].includes(d._fsRouteType),\n ) ?? routeNodes.find((d) => d.routePath === `/${rootPathId}`)\n if (rootRouteNode) {\n rootRouteNode._fsRouteType = '__root'\n rootRouteNode.variableName = 'root'\n }\n\n return {\n rootRouteNode,\n routeNodes,\n physicalDirectories: allPhysicalDirectories,\n }\n}\n\n/**\n * Determines the metadata for a given route path based on the provided configuration.\n *\n * @param routePath - The determined initial routePath (with brackets removed).\n * @param originalRoutePath - The original route path (may contain brackets for escaped content).\n * @param config - The user configuration object.\n * @returns An object containing the type of the route and the variable name derived from the route path.\n */\nexport function getRouteMeta(\n routePath: string,\n originalRoutePath: string,\n config: Pick<Config, 'routeToken' | 'indexToken'>,\n): {\n // `__root` is can be more easily determined by filtering down to routePath === /${rootPathId}\n // `pathless` is needs to determined after `lazy` has been cleaned up from the routePath\n fsRouteType: Extract<\n FsRouteType,\n | 'static'\n | 'layout'\n | 'api'\n | 'lazy'\n | 'loader'\n | 'component'\n | 'pendingComponent'\n | 'errorComponent'\n | 'notFoundComponent'\n >\n variableName: string\n} {\n let fsRouteType: FsRouteType = 'static'\n\n // Get the last segment from the original path to check for escaping\n const originalSegments = originalRoutePath.split('/').filter(Boolean)\n const lastOriginalSegment =\n originalSegments[originalSegments.length - 1] || ''\n\n // Helper to check if a specific suffix is escaped\n const isSuffixEscaped = (suffix: string): boolean => {\n return lastOriginalSegment === `[${suffix}]`\n }\n\n if (\n routePath.endsWith(`/${config.routeToken}`) &&\n !isSuffixEscaped(config.routeToken)\n ) {\n // layout routes, i.e `/foo/route.tsx` or `/foo/_layout/route.tsx`\n fsRouteType = 'layout'\n } else if (routePath.endsWith('/lazy') && !isSuffixEscaped('lazy')) {\n // lazy routes, i.e. `/foo.lazy.tsx`\n fsRouteType = 'lazy'\n } else if (routePath.endsWith('/loader') && !isSuffixEscaped('loader')) {\n // loader routes, i.e. `/foo.loader.tsx`\n fsRouteType = 'loader'\n } else if (\n routePath.endsWith('/component') &&\n !isSuffixEscaped('component')\n ) {\n // component routes, i.e. `/foo.component.tsx`\n fsRouteType = 'component'\n } else if (\n routePath.endsWith('/pendingComponent') &&\n !isSuffixEscaped('pendingComponent')\n ) {\n // pending component routes, i.e. `/foo.pendingComponent.tsx`\n fsRouteType = 'pendingComponent'\n } else if (\n routePath.endsWith('/errorComponent') &&\n !isSuffixEscaped('errorComponent')\n ) {\n // error component routes, i.e. `/foo.errorComponent.tsx`\n fsRouteType = 'errorComponent'\n } else if (\n routePath.endsWith('/notFoundComponent') &&\n !isSuffixEscaped('notFoundComponent')\n ) {\n // not found component routes, i.e. `/foo.notFoundComponent.tsx`\n fsRouteType = 'notFoundComponent'\n }\n\n const variableName = routePathToVariable(routePath)\n\n return { fsRouteType, variableName }\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 originalRoutePath Original route path with brackets for escaped content\n * @param routeType The route type determined from file extension\n * @param config The `router-generator` configuration object\n * @returns Boolean indicating if the route is a pathless layout route\n */\nfunction isValidPathlessLayoutRoute(\n normalizedRoutePath: string,\n originalRoutePath: string,\n routeType: FsRouteType,\n config: Pick<Config, 'routeToken' | 'indexToken'>,\n): boolean {\n if (routeType === 'lazy') {\n return false\n }\n\n const segments = normalizedRoutePath.split('/').filter(Boolean)\n const originalSegments = originalRoutePath.split('/').filter(Boolean)\n\n if (segments.length === 0) {\n return false\n }\n\n const lastRouteSegment = segments[segments.length - 1]!\n const lastOriginalSegment =\n originalSegments[originalSegments.length - 1] || ''\n const secondToLastRouteSegment = segments[segments.length - 2]\n const secondToLastOriginalSegment =\n originalSegments[originalSegments.length - 2]\n\n // If segment === __root, then exit as false\n if (lastRouteSegment === rootPathId) {\n return false\n }\n\n // If segment === config.routeToken and secondToLastSegment is a string that starts with _, then exit as true\n // Since the route is actually a configuration route for a layout/pathless route\n // i.e. /foo/_layout/route.tsx === /foo/_layout.tsx\n // But if the underscore is escaped, it's not a pathless layout\n if (\n lastRouteSegment === config.routeToken &&\n typeof secondToLastRouteSegment === 'string' &&\n typeof secondToLastOriginalSegment === 'string'\n ) {\n // Check if the underscore is escaped\n if (hasEscapedLeadingUnderscore(secondToLastOriginalSegment)) {\n return false\n }\n return secondToLastRouteSegment.startsWith('_')\n }\n\n // Segment starts with _ but check if it's escaped\n // If the original segment has [_] at the start, the underscore is escaped and it's not a pathless layout\n if (hasEscapedLeadingUnderscore(lastOriginalSegment)) {\n return false\n }\n\n return (\n lastRouteSegment !== config.indexToken &&\n lastRouteSegment !== config.routeToken &&\n lastRouteSegment.startsWith('_')\n )\n}\n"],"names":["getRouteNodesVirtual"],"mappings":"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"}
|