@tanstack/router-generator 1.167.20 → 1.167.22-pre.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/filesystem/virtual/getRouteNodes.cjs +3 -3
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs.map +1 -1
- package/dist/cjs/utils.cjs +14 -3
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +8 -0
- package/dist/esm/filesystem/virtual/getRouteNodes.js +4 -4
- package/dist/esm/filesystem/virtual/getRouteNodes.js.map +1 -1
- package/dist/esm/utils.d.ts +8 -0
- package/dist/esm/utils.js +14 -4
- package/dist/esm/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/filesystem/virtual/getRouteNodes.ts +10 -4
- package/src/utils.ts +20 -6
|
@@ -68,7 +68,7 @@ async function getRouteNodesRecursive(tsrConfig, root, fullDir, nodes, tokenRege
|
|
|
68
68
|
return {
|
|
69
69
|
children: (await Promise.all(nodes.map(async (node) => {
|
|
70
70
|
if (node.type === "physical") {
|
|
71
|
-
const { routePath: routePathPrefix, originalRoutePath: originalRoutePathPrefix } = node.pathPrefix ? require_utils.
|
|
71
|
+
const { routePath: routePathPrefix, originalRoutePath: originalRoutePathPrefix } = node.pathPrefix ? require_utils.determineInitialRoutePathFromExplicitPath(require_utils.removeLeadingSlash(node.pathPrefix)) : {
|
|
72
72
|
routePath: "",
|
|
73
73
|
originalRoutePath: ""
|
|
74
74
|
};
|
|
@@ -118,7 +118,7 @@ async function getRouteNodesRecursive(tsrConfig, root, fullDir, nodes, tokenRege
|
|
|
118
118
|
case "route": {
|
|
119
119
|
const lastSegment = node.path;
|
|
120
120
|
let routeNode;
|
|
121
|
-
const { routePath: escapedSegment, originalRoutePath: originalSegment } = require_utils.
|
|
121
|
+
const { routePath: escapedSegment, originalRoutePath: originalSegment } = require_utils.determineInitialRoutePathFromExplicitPath(require_utils.removeLeadingSlash(lastSegment));
|
|
122
122
|
const routePath = `${parentRoutePath}${escapedSegment}`;
|
|
123
123
|
const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`;
|
|
124
124
|
const routePathSegmentMetadata = require_utils.createLiteralRoutePathSegmentMetadata(routePath, parent, true);
|
|
@@ -162,7 +162,7 @@ async function getRouteNodesRecursive(tsrConfig, root, fullDir, nodes, tokenRege
|
|
|
162
162
|
node.id = ensureLeadingUnderScore(fileNameWithoutExt);
|
|
163
163
|
}
|
|
164
164
|
const lastSegment = node.id;
|
|
165
|
-
const { routePath: escapedSegment, originalRoutePath: originalSegment } = require_utils.
|
|
165
|
+
const { routePath: escapedSegment, originalRoutePath: originalSegment } = require_utils.determineInitialRoutePathFromExplicitPath(require_utils.removeLeadingSlash(lastSegment));
|
|
166
166
|
const routePath = `${parentRoutePath}${escapedSegment}`;
|
|
167
167
|
const routeNode = {
|
|
168
168
|
fullPath,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getRouteNodes.cjs","names":[],"sources":["../../../../src/filesystem/virtual/getRouteNodes.ts"],"sourcesContent":["import path, { join, resolve } from 'node:path'\nimport {\n cleanPath,\n createLiteralRoutePathSegmentMetadata,\n createRoutePathSegmentMetadata,\n determineInitialRoutePath,\n joinRoutePathSegmentMetadata,\n removeExt,\n removeLeadingSlash,\n removeTrailingSlash,\n replaceBackslash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'\nimport { rootPathId } from '../physical/rootPathId'\nimport { virtualRootRouteSchema } from './config'\nimport { loadConfigFile } from './loadConfigFile'\nimport type {\n VirtualRootRoute,\n VirtualRouteNode,\n} from '@tanstack/virtual-file-routes'\nimport type { GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\nimport type { TokenRegexBundle } from '../physical/getRouteNodes'\n\nfunction ensureLeadingUnderScore(id: string) {\n if (id.startsWith('_')) {\n return id\n }\n return `_${id}`\n}\n\nfunction flattenTree(node: RouteNode): Array<RouteNode> {\n const result = [node]\n\n if (node.children) {\n for (const child of node.children) {\n result.push(...flattenTree(child))\n }\n }\n delete node.children\n\n return result\n}\n\nexport async function getRouteNodes(\n tsrConfig: Pick<\n Config,\n | 'routesDirectory'\n | 'virtualRouteConfig'\n | 'routeFileIgnorePrefix'\n | 'disableLogging'\n | 'indexToken'\n | 'routeToken'\n >,\n root: string,\n tokenRegexes: TokenRegexBundle,\n): Promise<GetRouteNodesResult> {\n const fullDir = resolve(tsrConfig.routesDirectory)\n if (tsrConfig.virtualRouteConfig === undefined) {\n throw new Error(`virtualRouteConfig is undefined`)\n }\n let virtualRouteConfig: VirtualRootRoute\n if (typeof tsrConfig.virtualRouteConfig === 'string') {\n virtualRouteConfig = await getVirtualRouteConfigFromFileExport(\n tsrConfig,\n root,\n )\n } else {\n virtualRouteConfig = tsrConfig.virtualRouteConfig\n }\n const { children, physicalDirectories } = await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n virtualRouteConfig.children,\n tokenRegexes,\n )\n const allNodes = flattenTree({\n children,\n filePath: virtualRouteConfig.file,\n fullPath: replaceBackslash(join(fullDir, virtualRouteConfig.file)),\n variableName: 'root',\n routePath: `/${rootPathId}`,\n _fsRouteType: '__root',\n })\n\n const rootRouteNode = allNodes[0]\n const routeNodes = allNodes.slice(1)\n\n return { rootRouteNode, routeNodes, physicalDirectories }\n}\n\n/**\n * Get the virtual route config from a file export\n *\n * @example\n * ```ts\n * // routes.ts\n * import { rootRoute } from '@tanstack/virtual-file-routes'\n *\n * export const routes = rootRoute({ ... })\n * // or\n * export default rootRoute({ ... })\n * ```\n *\n */\nasync function getVirtualRouteConfigFromFileExport(\n tsrConfig: Pick<Config, 'virtualRouteConfig'>,\n root: string,\n): Promise<VirtualRootRoute> {\n if (\n tsrConfig.virtualRouteConfig === undefined ||\n typeof tsrConfig.virtualRouteConfig !== 'string' ||\n tsrConfig.virtualRouteConfig === ''\n ) {\n throw new Error(`virtualRouteConfig is undefined or empty`)\n }\n const exports = await loadConfigFile(join(root, tsrConfig.virtualRouteConfig))\n\n if (!('routes' in exports) && !('default' in exports)) {\n throw new Error(\n `routes not found in ${tsrConfig.virtualRouteConfig}. The routes export must be named like 'export const routes = ...' or done using 'export default ...'`,\n )\n }\n\n const virtualRouteConfig =\n 'routes' in exports ? exports.routes : exports.default\n\n return virtualRootRouteSchema.parse(virtualRouteConfig)\n}\n\nexport async function getRouteNodesRecursive(\n tsrConfig: Pick<\n Config,\n | 'routesDirectory'\n | 'routeFileIgnorePrefix'\n | 'disableLogging'\n | 'indexToken'\n | 'routeToken'\n >,\n root: string,\n fullDir: string,\n nodes: Array<VirtualRouteNode> | undefined,\n tokenRegexes: TokenRegexBundle,\n parent?: RouteNode,\n): Promise<{ children: Array<RouteNode>; physicalDirectories: Array<string> }> {\n if (nodes === undefined) {\n return { children: [], physicalDirectories: [] }\n }\n const allPhysicalDirectories: Array<string> = []\n const children = await Promise.all(\n nodes.map(async (node) => {\n if (node.type === 'physical') {\n const {\n routePath: routePathPrefix,\n originalRoutePath: originalRoutePathPrefix,\n } = node.pathPrefix\n ? determineInitialRoutePath(removeLeadingSlash(node.pathPrefix))\n : { routePath: '', originalRoutePath: '' }\n const { routeNodes, physicalDirectories } = await getRouteNodesPhysical(\n {\n ...tsrConfig,\n routesDirectory: resolve(fullDir, node.directory),\n },\n root,\n tokenRegexes,\n )\n allPhysicalDirectories.push(\n resolve(fullDir, node.directory),\n ...physicalDirectories,\n )\n routeNodes.forEach((subtreeNode) => {\n const pathPrefix = cleanPath(\n `${parent?.routePath ?? ''}${routePathPrefix}`,\n )\n const originalPathPrefix = cleanPath(\n `${parent?.originalRoutePath ?? parent?.routePath ?? ''}${originalRoutePathPrefix}`,\n )\n const literalPathPrefixSegments =\n createLiteralRoutePathSegmentMetadata(pathPrefix, parent, true)\n const routePath = cleanPath(`${pathPrefix}${subtreeNode.routePath}`)\n subtreeNode.variableName = routePathToVariable(\n `${routePathPrefix}/${removeExt(subtreeNode.filePath)}`,\n )\n subtreeNode._routePathSegmentMetadata = joinRoutePathSegmentMetadata(\n routePath,\n pathPrefix,\n literalPathPrefixSegments,\n subtreeNode._routePathSegmentMetadata,\n )\n subtreeNode.routePath = routePath\n // Keep originalRoutePath aligned with routePath for escape detection\n if (subtreeNode.originalRoutePath) {\n subtreeNode.originalRoutePath = cleanPath(\n `${originalPathPrefix}${subtreeNode.originalRoutePath}`,\n )\n }\n subtreeNode.filePath = `${node.directory}/${subtreeNode.filePath}`\n })\n return routeNodes\n }\n\n function getFile(file: string) {\n const filePath = file\n const variableName = routePathToVariable(removeExt(filePath))\n const fullPath = replaceBackslash(join(fullDir, filePath))\n return { filePath, variableName, fullPath }\n }\n const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')\n const parentOriginalRoutePath = removeTrailingSlash(\n parent?.originalRoutePath ?? parent?.routePath ?? '/',\n )\n const virtualParentRoutePath = parent?.routePath ?? `/${rootPathId}`\n\n switch (node.type) {\n case 'index': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n const routePath = `${parentRoutePath}/`\n const originalRoutePath = `${parentOriginalRoutePath}/`\n return {\n filePath,\n fullPath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: parent?._routePathSegmentMetadata\n ? [...parent._routePathSegmentMetadata]\n : undefined,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n } satisfies RouteNode\n }\n\n case 'route': {\n const lastSegment = node.path\n let routeNode: RouteNode\n\n // Process the segment to handle escape sequences like [_]\n const {\n routePath: escapedSegment,\n originalRoutePath: originalSegment,\n } = determineInitialRoutePath(removeLeadingSlash(lastSegment))\n const routePath = `${parentRoutePath}${escapedSegment}`\n const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`\n const routePathSegmentMetadata =\n createLiteralRoutePathSegmentMetadata(routePath, parent, true)\n\n if (node.file) {\n const { filePath, variableName, fullPath } = getFile(node.file)\n routeNode = {\n filePath,\n fullPath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n } else {\n routeNode = {\n filePath: '',\n fullPath: '',\n variableName: routePathToVariable(routePath),\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n isVirtual: true,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n }\n\n if (node.children !== undefined) {\n const { children, physicalDirectories } =\n await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n node.children,\n tokenRegexes,\n routeNode,\n )\n routeNode.children = children\n allPhysicalDirectories.push(...physicalDirectories)\n\n // If the route has children, it should be a layout\n routeNode._fsRouteType = 'layout'\n }\n return routeNode\n }\n case 'layout': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n\n if (node.id !== undefined) {\n node.id = ensureLeadingUnderScore(node.id)\n } else {\n const baseName = path.basename(filePath)\n const fileNameWithoutExt = path.parse(baseName).name\n node.id = ensureLeadingUnderScore(fileNameWithoutExt)\n }\n const lastSegment = node.id\n // Process the segment to handle escape sequences like [_]\n const {\n routePath: escapedSegment,\n originalRoutePath: originalSegment,\n } = determineInitialRoutePath(removeLeadingSlash(lastSegment))\n const routePath = `${parentRoutePath}${escapedSegment}`\n // Store the original path with brackets for escape detection\n const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`\n const routePathSegmentMetadata = joinRoutePathSegmentMetadata(\n routePath,\n parentRoutePath,\n parent?._routePathSegmentMetadata,\n createRoutePathSegmentMetadata(escapedSegment, originalSegment),\n )\n\n const routeNode: RouteNode = {\n fullPath,\n filePath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n _fsRouteType: 'pathless_layout',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n\n if (node.children !== undefined) {\n const { children, physicalDirectories } =\n await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n node.children,\n tokenRegexes,\n routeNode,\n )\n routeNode.children = children\n allPhysicalDirectories.push(...physicalDirectories)\n }\n return routeNode\n }\n }\n }),\n )\n return {\n children: children.flat(),\n physicalDirectories: allPhysicalDirectories,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"getRouteNodes.cjs","names":[],"sources":["../../../../src/filesystem/virtual/getRouteNodes.ts"],"sourcesContent":["import path, { join, resolve } from 'node:path'\nimport {\n cleanPath,\n createLiteralRoutePathSegmentMetadata,\n createRoutePathSegmentMetadata,\n determineInitialRoutePathFromExplicitPath,\n joinRoutePathSegmentMetadata,\n removeExt,\n removeLeadingSlash,\n removeTrailingSlash,\n replaceBackslash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'\nimport { rootPathId } from '../physical/rootPathId'\nimport { virtualRootRouteSchema } from './config'\nimport { loadConfigFile } from './loadConfigFile'\nimport type {\n VirtualRootRoute,\n VirtualRouteNode,\n} from '@tanstack/virtual-file-routes'\nimport type { GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\nimport type { TokenRegexBundle } from '../physical/getRouteNodes'\n\nfunction ensureLeadingUnderScore(id: string) {\n if (id.startsWith('_')) {\n return id\n }\n return `_${id}`\n}\n\nfunction flattenTree(node: RouteNode): Array<RouteNode> {\n const result = [node]\n\n if (node.children) {\n for (const child of node.children) {\n result.push(...flattenTree(child))\n }\n }\n delete node.children\n\n return result\n}\n\nexport async function getRouteNodes(\n tsrConfig: Pick<\n Config,\n | 'routesDirectory'\n | 'virtualRouteConfig'\n | 'routeFileIgnorePrefix'\n | 'disableLogging'\n | 'indexToken'\n | 'routeToken'\n >,\n root: string,\n tokenRegexes: TokenRegexBundle,\n): Promise<GetRouteNodesResult> {\n const fullDir = resolve(tsrConfig.routesDirectory)\n if (tsrConfig.virtualRouteConfig === undefined) {\n throw new Error(`virtualRouteConfig is undefined`)\n }\n let virtualRouteConfig: VirtualRootRoute\n if (typeof tsrConfig.virtualRouteConfig === 'string') {\n virtualRouteConfig = await getVirtualRouteConfigFromFileExport(\n tsrConfig,\n root,\n )\n } else {\n virtualRouteConfig = tsrConfig.virtualRouteConfig\n }\n const { children, physicalDirectories } = await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n virtualRouteConfig.children,\n tokenRegexes,\n )\n const allNodes = flattenTree({\n children,\n filePath: virtualRouteConfig.file,\n fullPath: replaceBackslash(join(fullDir, virtualRouteConfig.file)),\n variableName: 'root',\n routePath: `/${rootPathId}`,\n _fsRouteType: '__root',\n })\n\n const rootRouteNode = allNodes[0]\n const routeNodes = allNodes.slice(1)\n\n return { rootRouteNode, routeNodes, physicalDirectories }\n}\n\n/**\n * Get the virtual route config from a file export\n *\n * @example\n * ```ts\n * // routes.ts\n * import { rootRoute } from '@tanstack/virtual-file-routes'\n *\n * export const routes = rootRoute({ ... })\n * // or\n * export default rootRoute({ ... })\n * ```\n *\n */\nasync function getVirtualRouteConfigFromFileExport(\n tsrConfig: Pick<Config, 'virtualRouteConfig'>,\n root: string,\n): Promise<VirtualRootRoute> {\n if (\n tsrConfig.virtualRouteConfig === undefined ||\n typeof tsrConfig.virtualRouteConfig !== 'string' ||\n tsrConfig.virtualRouteConfig === ''\n ) {\n throw new Error(`virtualRouteConfig is undefined or empty`)\n }\n const exports = await loadConfigFile(join(root, tsrConfig.virtualRouteConfig))\n\n if (!('routes' in exports) && !('default' in exports)) {\n throw new Error(\n `routes not found in ${tsrConfig.virtualRouteConfig}. The routes export must be named like 'export const routes = ...' or done using 'export default ...'`,\n )\n }\n\n const virtualRouteConfig =\n 'routes' in exports ? exports.routes : exports.default\n\n return virtualRootRouteSchema.parse(virtualRouteConfig)\n}\n\nexport async function getRouteNodesRecursive(\n tsrConfig: Pick<\n Config,\n | 'routesDirectory'\n | 'routeFileIgnorePrefix'\n | 'disableLogging'\n | 'indexToken'\n | 'routeToken'\n >,\n root: string,\n fullDir: string,\n nodes: Array<VirtualRouteNode> | undefined,\n tokenRegexes: TokenRegexBundle,\n parent?: RouteNode,\n): Promise<{ children: Array<RouteNode>; physicalDirectories: Array<string> }> {\n if (nodes === undefined) {\n return { children: [], physicalDirectories: [] }\n }\n const allPhysicalDirectories: Array<string> = []\n const children = await Promise.all(\n nodes.map(async (node) => {\n if (node.type === 'physical') {\n const {\n routePath: routePathPrefix,\n originalRoutePath: originalRoutePathPrefix,\n } = node.pathPrefix\n ? determineInitialRoutePathFromExplicitPath(\n removeLeadingSlash(node.pathPrefix),\n )\n : { routePath: '', originalRoutePath: '' }\n const { routeNodes, physicalDirectories } = await getRouteNodesPhysical(\n {\n ...tsrConfig,\n routesDirectory: resolve(fullDir, node.directory),\n },\n root,\n tokenRegexes,\n )\n allPhysicalDirectories.push(\n resolve(fullDir, node.directory),\n ...physicalDirectories,\n )\n routeNodes.forEach((subtreeNode) => {\n const pathPrefix = cleanPath(\n `${parent?.routePath ?? ''}${routePathPrefix}`,\n )\n const originalPathPrefix = cleanPath(\n `${parent?.originalRoutePath ?? parent?.routePath ?? ''}${originalRoutePathPrefix}`,\n )\n const literalPathPrefixSegments =\n createLiteralRoutePathSegmentMetadata(pathPrefix, parent, true)\n const routePath = cleanPath(`${pathPrefix}${subtreeNode.routePath}`)\n subtreeNode.variableName = routePathToVariable(\n `${routePathPrefix}/${removeExt(subtreeNode.filePath)}`,\n )\n subtreeNode._routePathSegmentMetadata = joinRoutePathSegmentMetadata(\n routePath,\n pathPrefix,\n literalPathPrefixSegments,\n subtreeNode._routePathSegmentMetadata,\n )\n subtreeNode.routePath = routePath\n // Keep originalRoutePath aligned with routePath for escape detection\n if (subtreeNode.originalRoutePath) {\n subtreeNode.originalRoutePath = cleanPath(\n `${originalPathPrefix}${subtreeNode.originalRoutePath}`,\n )\n }\n subtreeNode.filePath = `${node.directory}/${subtreeNode.filePath}`\n })\n return routeNodes\n }\n\n function getFile(file: string) {\n const filePath = file\n const variableName = routePathToVariable(removeExt(filePath))\n const fullPath = replaceBackslash(join(fullDir, filePath))\n return { filePath, variableName, fullPath }\n }\n const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')\n const parentOriginalRoutePath = removeTrailingSlash(\n parent?.originalRoutePath ?? parent?.routePath ?? '/',\n )\n const virtualParentRoutePath = parent?.routePath ?? `/${rootPathId}`\n\n switch (node.type) {\n case 'index': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n const routePath = `${parentRoutePath}/`\n const originalRoutePath = `${parentOriginalRoutePath}/`\n return {\n filePath,\n fullPath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: parent?._routePathSegmentMetadata\n ? [...parent._routePathSegmentMetadata]\n : undefined,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n } satisfies RouteNode\n }\n\n case 'route': {\n const lastSegment = node.path\n let routeNode: RouteNode\n\n // Process the segment to handle escape sequences like [_]\n const {\n routePath: escapedSegment,\n originalRoutePath: originalSegment,\n } = determineInitialRoutePathFromExplicitPath(\n removeLeadingSlash(lastSegment),\n )\n const routePath = `${parentRoutePath}${escapedSegment}`\n const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`\n const routePathSegmentMetadata =\n createLiteralRoutePathSegmentMetadata(routePath, parent, true)\n\n if (node.file) {\n const { filePath, variableName, fullPath } = getFile(node.file)\n routeNode = {\n filePath,\n fullPath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n } else {\n routeNode = {\n filePath: '',\n fullPath: '',\n variableName: routePathToVariable(routePath),\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n isVirtual: true,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n }\n\n if (node.children !== undefined) {\n const { children, physicalDirectories } =\n await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n node.children,\n tokenRegexes,\n routeNode,\n )\n routeNode.children = children\n allPhysicalDirectories.push(...physicalDirectories)\n\n // If the route has children, it should be a layout\n routeNode._fsRouteType = 'layout'\n }\n return routeNode\n }\n case 'layout': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n\n if (node.id !== undefined) {\n node.id = ensureLeadingUnderScore(node.id)\n } else {\n const baseName = path.basename(filePath)\n const fileNameWithoutExt = path.parse(baseName).name\n node.id = ensureLeadingUnderScore(fileNameWithoutExt)\n }\n const lastSegment = node.id\n // Process the segment to handle escape sequences like [_]\n const {\n routePath: escapedSegment,\n originalRoutePath: originalSegment,\n } = determineInitialRoutePathFromExplicitPath(\n removeLeadingSlash(lastSegment),\n )\n const routePath = `${parentRoutePath}${escapedSegment}`\n // Store the original path with brackets for escape detection\n const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`\n const routePathSegmentMetadata = joinRoutePathSegmentMetadata(\n routePath,\n parentRoutePath,\n parent?._routePathSegmentMetadata,\n createRoutePathSegmentMetadata(escapedSegment, originalSegment),\n )\n\n const routeNode: RouteNode = {\n fullPath,\n filePath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n _fsRouteType: 'pathless_layout',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n\n if (node.children !== undefined) {\n const { children, physicalDirectories } =\n await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n node.children,\n tokenRegexes,\n routeNode,\n )\n routeNode.children = children\n allPhysicalDirectories.push(...physicalDirectories)\n }\n return routeNode\n }\n }\n }),\n )\n return {\n children: children.flat(),\n physicalDirectories: allPhysicalDirectories,\n }\n}\n"],"mappings":"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"}
|
package/dist/cjs/utils.cjs
CHANGED
|
@@ -129,10 +129,10 @@ var DISALLOWED_ESCAPE_CHARS = new Set([
|
|
|
129
129
|
"$",
|
|
130
130
|
"%"
|
|
131
131
|
]);
|
|
132
|
-
function
|
|
133
|
-
const originalRoutePath = cleanPath(`/${
|
|
132
|
+
function determineInitialRoutePathFromParts(routePath, parts) {
|
|
133
|
+
const originalRoutePath = cleanPath(`/${cleanPath(parts.join("/")) || ""}`) || "";
|
|
134
134
|
return {
|
|
135
|
-
routePath: cleanPath(`/${
|
|
135
|
+
routePath: cleanPath(`/${parts.map((part) => {
|
|
136
136
|
let match;
|
|
137
137
|
while ((match = BRACKET_CONTENT_RE.exec(part)) !== null) {
|
|
138
138
|
const character = match[1];
|
|
@@ -147,6 +147,16 @@ function determineInitialRoutePath(routePath) {
|
|
|
147
147
|
originalRoutePath
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
|
+
function determineInitialRoutePath(routePath) {
|
|
151
|
+
return determineInitialRoutePathFromParts(routePath, routePath.split(SPLIT_REGEX));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Resolves bracket escapes in an explicit route path or ID without applying
|
|
155
|
+
* the dot-delimited flat-file route convention.
|
|
156
|
+
*/
|
|
157
|
+
function determineInitialRoutePathFromExplicitPath(routePath) {
|
|
158
|
+
return determineInitialRoutePathFromParts(routePath, [routePath]);
|
|
159
|
+
}
|
|
150
160
|
/**
|
|
151
161
|
* Checks if a segment is fully escaped (entirely wrapped in brackets with no nested brackets).
|
|
152
162
|
* E.g., "[index]" -> true, "[_layout]" -> true, "foo[.]bar" -> false, "index" -> false
|
|
@@ -725,6 +735,7 @@ exports.createRouteNodesByTo = createRouteNodesByTo;
|
|
|
725
735
|
exports.createRoutePathSegmentMetadata = createRoutePathSegmentMetadata;
|
|
726
736
|
exports.createTokenRegex = createTokenRegex;
|
|
727
737
|
exports.determineInitialRoutePath = determineInitialRoutePath;
|
|
738
|
+
exports.determineInitialRoutePathFromExplicitPath = determineInitialRoutePathFromExplicitPath;
|
|
728
739
|
exports.determineNodePath = determineNodePath;
|
|
729
740
|
exports.escapeRegExp = escapeRegExp;
|
|
730
741
|
exports.findParent = findParent;
|
package/dist/cjs/utils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.cjs","names":[],"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, TokenMatcher } from './config'\nimport type {\n ImportDeclaration,\n RouteNode,\n RoutePathSegmentMetadata,\n} 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\n constructor(routes: Array<RouteNode>) {\n for (const route of routes) {\n if (!route.routePath || route.routePath === `/${rootPathId}`) continue\n\n // Skip route pieces (lazy, loader, component, etc.) - they are merged with main routes\n // and should not be valid parent candidates\n if (\n route._fsRouteType === 'lazy' ||\n route._fsRouteType === 'loader' ||\n route._fsRouteType === 'component' ||\n route._fsRouteType === 'pendingComponent' ||\n route._fsRouteType === 'errorComponent' ||\n route._fsRouteType === 'notFoundComponent'\n ) {\n continue\n }\n\n // Index by exact path for direct lookups\n this.prefixToRoute.set(route.routePath, route)\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\n/**\n * Sorts route nodes by root, path depth, index status, and finally `routePath`.\n * The `routePath` comparison keeps the output consistent when the earlier\n * values are the same.\n */\nexport function sortRouteNodes(\n routeNodes: Array<RouteNode>,\n indexTokenSegmentRegex: RegExp,\n): Array<RouteNode> {\n return multiSortBy(routeNodes, [\n (d) => (d.routePath?.includes(`/${rootPathId}`) ? -1 : 1),\n (d) =>\n d.routePath === undefined\n ? undefined\n : countSlashSeparatedParts(d.routePath),\n (d) => {\n const segments = d.routePath?.split('/').filter(Boolean) ?? []\n const last = segments[segments.length - 1] ?? ''\n return indexTokenSegmentRegex.test(last) ? -1 : 1\n },\n (d) => d.routePath,\n ])\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\nexport function countRoutePathSegments(routePath?: string): number {\n const path = routePath ?? ''\n let count = 0\n let inSegment = false\n\n for (let i = 0; i < path.length; i++) {\n if (path[i] === '/') {\n inSegment = false\n continue\n }\n\n if (!inSegment) {\n count++\n inSegment = true\n }\n }\n\n return count\n}\n\nexport function countSlashSeparatedParts(path: string): number {\n let count = 1\n\n for (let i = 0; i < path.length; i++) {\n if (path[i] === '/') count++\n }\n\n return count\n}\n\nexport function hasRoutePathSegmentMetadata(\n metadata: RoutePathSegmentMetadata | undefined,\n): metadata is RoutePathSegmentMetadata {\n return !!(\n metadata?.literalLeadingUnderscore || metadata?.literalTrailingUnderscore\n )\n}\n\nfunction mergeRoutePathSegmentMetadata(\n current: RoutePathSegmentMetadata | undefined,\n incoming: RoutePathSegmentMetadata | undefined,\n): RoutePathSegmentMetadata | undefined {\n const hasCurrent = hasRoutePathSegmentMetadata(current)\n const hasIncoming = hasRoutePathSegmentMetadata(incoming)\n\n if (!hasCurrent) return hasIncoming ? incoming : undefined\n if (!hasIncoming) return current\n\n return {\n literalLeadingUnderscore:\n current.literalLeadingUnderscore || incoming.literalLeadingUnderscore,\n literalTrailingUnderscore:\n current.literalTrailingUnderscore || incoming.literalTrailingUnderscore,\n }\n}\n\nexport function createRoutePathSegmentMetadata(\n routePath: string = '/',\n originalPath?: string,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n if (!originalPath) return undefined\n\n const routeSegments = routePath.split('/')\n const originalSegments = originalPath.split('/')\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n routeSegments.length,\n )\n let hasMetadata = false\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]!\n const originalSegment = originalSegments[i] || ''\n const literalLeadingUnderscore =\n segment.startsWith('_') && hasEscapedLeadingUnderscore(originalSegment)\n const literalTrailingUnderscore =\n segment.endsWith('_') && hasEscapedTrailingUnderscore(originalSegment)\n\n if (!literalLeadingUnderscore && !literalTrailingUnderscore) continue\n\n hasMetadata = true\n metadata[i] = {\n literalLeadingUnderscore: literalLeadingUnderscore || undefined,\n literalTrailingUnderscore: literalTrailingUnderscore || undefined,\n }\n }\n\n return hasMetadata ? metadata : undefined\n}\n\nexport function createLiteralRoutePathSegmentMetadata(\n routePath: string,\n parent?: RouteNode,\n literalNewSegments = false,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n const routeSegments = routePath.split('/')\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n routeSegments.length,\n )\n const parentDepth = countRoutePathSegments(parent?.routePath)\n let hasMetadata = false\n let depth = 0\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]\n metadata[i] = parent?._routePathSegmentMetadata?.[i]\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[i])\n\n if (!segment) continue\n\n if (literalNewSegments && depth >= parentDepth) {\n const literalLeadingUnderscore = segment.startsWith('_')\n const literalTrailingUnderscore = segment.endsWith('_')\n\n if (literalLeadingUnderscore || literalTrailingUnderscore) {\n metadata[i] = mergeRoutePathSegmentMetadata(metadata[i], {\n literalLeadingUnderscore: literalLeadingUnderscore || undefined,\n literalTrailingUnderscore: literalTrailingUnderscore || undefined,\n })\n hasMetadata = true\n }\n }\n\n depth++\n }\n\n return hasMetadata ? metadata : undefined\n}\n\nexport function joinRoutePathSegmentMetadata(\n routePath: string,\n prefixPath: string,\n prefixMetadata: Array<RoutePathSegmentMetadata | undefined> | undefined,\n childMetadata: Array<RoutePathSegmentMetadata | undefined> | undefined,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n countSlashSeparatedParts(routePath),\n )\n let hasMetadata = false\n\n if (prefixMetadata) {\n for (let i = 0; i < prefixMetadata.length && i < metadata.length; i++) {\n metadata[i] = prefixMetadata[i]\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[i])\n }\n }\n\n const offset = countRoutePathSegments(prefixPath)\n if (childMetadata) {\n for (let i = 1; i < childMetadata.length; i++) {\n const targetIndex = offset + i\n if (targetIndex >= metadata.length) break\n\n metadata[targetIndex] = mergeRoutePathSegmentMetadata(\n metadata[targetIndex],\n childMetadata[i],\n )\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[targetIndex])\n }\n }\n\n return hasMetadata ? metadata : undefined\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 removeUnderscoresFromSegment(\n segment: string,\n metadata?: RoutePathSegmentMetadata,\n): string {\n let result = segment\n\n if (result.startsWith('_') && !metadata?.literalLeadingUnderscore) {\n result = result.slice(1)\n }\n\n if (result.endsWith('_') && !metadata?.literalTrailingUnderscore) {\n result = result.slice(0, -1)\n }\n\n return result\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 metadata = createRoutePathSegmentMetadata(routePath, originalPath)\n const newSegments = new Array<string>(routeSegments.length)\n\n for (let i = 0; i < routeSegments.length; i++) {\n newSegments[i] = removeUnderscoresFromSegment(\n routeSegments[i]!,\n metadata?.[i],\n )\n }\n\n return newSegments.join('/')\n}\n\nexport function removeLayoutSegmentsAndUnderscoresWithEscape(\n routePath: string = '/',\n originalPath?: string,\n routePathSegmentMetadata?: Array<RoutePathSegmentMetadata | undefined>,\n): string {\n if (!originalPath) {\n return removeUnderscores(removeLayoutSegments(routePath)) ?? ''\n }\n\n const metadata =\n routePathSegmentMetadata ??\n createRoutePathSegmentMetadata(routePath, originalPath)\n\n const routeSegments = routePath.split('/')\n const originalSegments = originalPath.split('/')\n const newSegments: Array<string> = []\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]!\n const originalSegment = originalSegments[i] || ''\n const segmentMetadata = metadata?.[i]\n\n if (\n !segmentMetadata?.literalLeadingUnderscore &&\n isSegmentPathless(segment, originalSegment)\n ) {\n continue\n }\n\n newSegments.push(removeUnderscoresFromSegment(segment, segmentMetadata))\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\nexport function escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction sanitizeTokenFlags(flags?: string): string | undefined {\n if (!flags) return flags\n\n // Prevent stateful behavior with RegExp.prototype.test/exec\n // g = global, y = sticky\n return flags.replace(/[gy]/g, '')\n}\n\nexport function createTokenRegex(\n token: TokenMatcher,\n opts: {\n type: 'segment' | 'filename'\n },\n): RegExp {\n // Defensive check: if token is undefined/null, throw a clear error\n // (runtime safety for config loading edge cases)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (token === undefined || token === null) {\n throw new Error(\n `createTokenRegex: token is ${token}. This usually means the config was not properly parsed with defaults.`,\n )\n }\n\n try {\n if (typeof token === 'string') {\n return opts.type === 'segment'\n ? new RegExp(`^${escapeRegExp(token)}$`)\n : new RegExp(`[./]${escapeRegExp(token)}[.]`)\n }\n\n if (token instanceof RegExp) {\n const flags = sanitizeTokenFlags(token.flags)\n return opts.type === 'segment'\n ? new RegExp(`^(?:${token.source})$`, flags)\n : new RegExp(`[./](?:${token.source})[.]`, flags)\n }\n\n // Handle JSON regex object form: { regex: string, flags?: string }\n if (typeof token === 'object' && 'regex' in token) {\n const flags = sanitizeTokenFlags(token.flags)\n return opts.type === 'segment'\n ? new RegExp(`^(?:${token.regex})$`, flags)\n : new RegExp(`[./](?:${token.regex})[.]`, flags)\n }\n\n throw new Error(\n `createTokenRegex: invalid token type. Expected string, RegExp, or { regex, flags } object, got: ${typeof token}`,\n )\n } catch (e) {\n if (e instanceof SyntaxError) {\n const pattern =\n typeof token === 'string'\n ? token\n : token instanceof RegExp\n ? token.source\n : token.regex\n throw new Error(\n `Invalid regex pattern in token config: \"${pattern}\". ${e.message}`,\n )\n }\n throw e\n }\n}\n\nfunction isBracketWrappedSegment(segment: string): boolean {\n return segment.startsWith('[') && segment.endsWith(']')\n}\n\nexport function unwrapBracketWrappedSegment(segment: string): string {\n return isBracketWrappedSegment(segment) ? segment.slice(1, -1) : segment\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, addExtensions: boolean | string = false) {\n if (typeof addExtensions === 'string') {\n const dotIndex = d.lastIndexOf('.')\n if (dotIndex === -1) return d\n return d.substring(0, dotIndex) + addExtensions\n }\n return addExtensions ? 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 * Infers the path for use by TS\n */\nconst inferPath = (routeNode: RouteNode): string => {\n if (routeNode.cleanedPath === '/') {\n return routeNode.cleanedPath ?? ''\n }\n return 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 removeLayoutSegmentsAndUnderscoresWithEscape(\n routeNode.routePath,\n routeNode.originalRoutePath,\n routeNode._routePathSegmentMetadata,\n ),\n )\n\n if (fullPath === '') {\n return '/'\n }\n\n // Preserve trailing slash for index routes (routePath ends with '/')\n // This ensures types match runtime behavior\n const isIndexRoute = routeNode.routePath?.endsWith('/')\n if (isIndexRoute) {\n return fullPath\n }\n\n return fullPath.replace(/\\/$/, '')\n}\n\nconst shouldPreferIndexRoute = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n return existing.cleanedPath === '/' && current.cleanedPath !== '/'\n}\n\nconst isIndexRouteNode = (routeNode: RouteNode): boolean => {\n return routeNode.routePath?.endsWith('/') ?? false\n}\n\nconst isPathlessRouteNode = (routeNode: RouteNode): boolean => {\n return routeNode._fsRouteType === 'pathless_layout'\n}\n\nconst shouldReplaceRouteNodeForTo = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n const currentIsIndex = isIndexRouteNode(current)\n const existingIsIndex = isIndexRouteNode(existing)\n if (currentIsIndex !== existingIsIndex) {\n return currentIsIndex\n }\n\n const currentIsPathless = isPathlessRouteNode(current)\n const existingIsPathless = isPathlessRouteNode(existing)\n if (currentIsPathless !== existingIsPathless) {\n return !currentIsPathless\n }\n\n return true\n}\n\nconst shouldReplaceRouteNodeForFullPath = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n const currentIsPathless = isPathlessRouteNode(current)\n const existingIsPathless = isPathlessRouteNode(existing)\n if (currentIsPathless !== existingIsPathless) {\n return !currentIsPathless\n }\n\n return true\n}\n\n/**\n * Creates a map from fullPath to routeNode\n */\nexport const createRouteNodesByFullPath = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n const map = new Map<string, RouteNode>()\n\n for (const routeNode of routeNodes) {\n const fullPath = inferFullPath(routeNode)\n\n if (fullPath === '/' && map.has('/')) {\n const existing = map.get('/')!\n if (shouldPreferIndexRoute(routeNode, existing)) {\n continue\n }\n }\n\n const existing = map.get(fullPath)\n if (existing && !shouldReplaceRouteNodeForFullPath(routeNode, existing)) {\n continue\n }\n\n map.set(fullPath, routeNode)\n }\n\n return map\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 const map = new Map<string, RouteNode>()\n\n for (const routeNode of dedupeBranchesAndIndexRoutes(routeNodes)) {\n const to = inferTo(routeNode)\n\n const existing = map.get(to)\n if (existing && !shouldReplaceRouteNodeForTo(routeNode, existing)) {\n continue\n }\n\n map.set(to, routeNode)\n }\n\n return map\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 */\nconst 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 */\nconst 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 emptyPathRoutes = _routes.filter((d) => d.routePath === '')\n if (emptyPathRoutes.length) {\n const errorMessage = `Invalid route path \"\" was found. Root routes must be defined via __root.tsx (createRootRoute), not createFileRoute('') or a route file that resolves to an empty path.\nConflicting files: \\n ${emptyPathRoutes\n .map((d) => path.resolve(config.routesDirectory, d.filePath))\n .join('\\n ')}\\n`\n throw new Error(errorMessage)\n }\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 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\nfunction 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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.cjs","names":[],"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, TokenMatcher } from './config'\nimport type {\n ImportDeclaration,\n RouteNode,\n RoutePathSegmentMetadata,\n} 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\n constructor(routes: Array<RouteNode>) {\n for (const route of routes) {\n if (!route.routePath || route.routePath === `/${rootPathId}`) continue\n\n // Skip route pieces (lazy, loader, component, etc.) - they are merged with main routes\n // and should not be valid parent candidates\n if (\n route._fsRouteType === 'lazy' ||\n route._fsRouteType === 'loader' ||\n route._fsRouteType === 'component' ||\n route._fsRouteType === 'pendingComponent' ||\n route._fsRouteType === 'errorComponent' ||\n route._fsRouteType === 'notFoundComponent'\n ) {\n continue\n }\n\n // Index by exact path for direct lookups\n this.prefixToRoute.set(route.routePath, route)\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\n/**\n * Sorts route nodes by root, path depth, index status, and finally `routePath`.\n * The `routePath` comparison keeps the output consistent when the earlier\n * values are the same.\n */\nexport function sortRouteNodes(\n routeNodes: Array<RouteNode>,\n indexTokenSegmentRegex: RegExp,\n): Array<RouteNode> {\n return multiSortBy(routeNodes, [\n (d) => (d.routePath?.includes(`/${rootPathId}`) ? -1 : 1),\n (d) =>\n d.routePath === undefined\n ? undefined\n : countSlashSeparatedParts(d.routePath),\n (d) => {\n const segments = d.routePath?.split('/').filter(Boolean) ?? []\n const last = segments[segments.length - 1] ?? ''\n return indexTokenSegmentRegex.test(last) ? -1 : 1\n },\n (d) => d.routePath,\n ])\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\nfunction determineInitialRoutePathFromParts(\n routePath: string,\n parts: Array<string>,\n) {\n const originalRoutePath =\n cleanPath(`/${cleanPath(parts.join('/')) || ''}`) || ''\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\nexport function determineInitialRoutePath(routePath: string) {\n return determineInitialRoutePathFromParts(\n routePath,\n routePath.split(SPLIT_REGEX),\n )\n}\n\n/**\n * Resolves bracket escapes in an explicit route path or ID without applying\n * the dot-delimited flat-file route convention.\n */\nexport function determineInitialRoutePathFromExplicitPath(routePath: string) {\n return determineInitialRoutePathFromParts(routePath, [routePath])\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\nexport function countRoutePathSegments(routePath?: string): number {\n const path = routePath ?? ''\n let count = 0\n let inSegment = false\n\n for (let i = 0; i < path.length; i++) {\n if (path[i] === '/') {\n inSegment = false\n continue\n }\n\n if (!inSegment) {\n count++\n inSegment = true\n }\n }\n\n return count\n}\n\nexport function countSlashSeparatedParts(path: string): number {\n let count = 1\n\n for (let i = 0; i < path.length; i++) {\n if (path[i] === '/') count++\n }\n\n return count\n}\n\nexport function hasRoutePathSegmentMetadata(\n metadata: RoutePathSegmentMetadata | undefined,\n): metadata is RoutePathSegmentMetadata {\n return !!(\n metadata?.literalLeadingUnderscore || metadata?.literalTrailingUnderscore\n )\n}\n\nfunction mergeRoutePathSegmentMetadata(\n current: RoutePathSegmentMetadata | undefined,\n incoming: RoutePathSegmentMetadata | undefined,\n): RoutePathSegmentMetadata | undefined {\n const hasCurrent = hasRoutePathSegmentMetadata(current)\n const hasIncoming = hasRoutePathSegmentMetadata(incoming)\n\n if (!hasCurrent) return hasIncoming ? incoming : undefined\n if (!hasIncoming) return current\n\n return {\n literalLeadingUnderscore:\n current.literalLeadingUnderscore || incoming.literalLeadingUnderscore,\n literalTrailingUnderscore:\n current.literalTrailingUnderscore || incoming.literalTrailingUnderscore,\n }\n}\n\nexport function createRoutePathSegmentMetadata(\n routePath: string = '/',\n originalPath?: string,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n if (!originalPath) return undefined\n\n const routeSegments = routePath.split('/')\n const originalSegments = originalPath.split('/')\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n routeSegments.length,\n )\n let hasMetadata = false\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]!\n const originalSegment = originalSegments[i] || ''\n const literalLeadingUnderscore =\n segment.startsWith('_') && hasEscapedLeadingUnderscore(originalSegment)\n const literalTrailingUnderscore =\n segment.endsWith('_') && hasEscapedTrailingUnderscore(originalSegment)\n\n if (!literalLeadingUnderscore && !literalTrailingUnderscore) continue\n\n hasMetadata = true\n metadata[i] = {\n literalLeadingUnderscore: literalLeadingUnderscore || undefined,\n literalTrailingUnderscore: literalTrailingUnderscore || undefined,\n }\n }\n\n return hasMetadata ? metadata : undefined\n}\n\nexport function createLiteralRoutePathSegmentMetadata(\n routePath: string,\n parent?: RouteNode,\n literalNewSegments = false,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n const routeSegments = routePath.split('/')\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n routeSegments.length,\n )\n const parentDepth = countRoutePathSegments(parent?.routePath)\n let hasMetadata = false\n let depth = 0\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]\n metadata[i] = parent?._routePathSegmentMetadata?.[i]\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[i])\n\n if (!segment) continue\n\n if (literalNewSegments && depth >= parentDepth) {\n const literalLeadingUnderscore = segment.startsWith('_')\n const literalTrailingUnderscore = segment.endsWith('_')\n\n if (literalLeadingUnderscore || literalTrailingUnderscore) {\n metadata[i] = mergeRoutePathSegmentMetadata(metadata[i], {\n literalLeadingUnderscore: literalLeadingUnderscore || undefined,\n literalTrailingUnderscore: literalTrailingUnderscore || undefined,\n })\n hasMetadata = true\n }\n }\n\n depth++\n }\n\n return hasMetadata ? metadata : undefined\n}\n\nexport function joinRoutePathSegmentMetadata(\n routePath: string,\n prefixPath: string,\n prefixMetadata: Array<RoutePathSegmentMetadata | undefined> | undefined,\n childMetadata: Array<RoutePathSegmentMetadata | undefined> | undefined,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n countSlashSeparatedParts(routePath),\n )\n let hasMetadata = false\n\n if (prefixMetadata) {\n for (let i = 0; i < prefixMetadata.length && i < metadata.length; i++) {\n metadata[i] = prefixMetadata[i]\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[i])\n }\n }\n\n const offset = countRoutePathSegments(prefixPath)\n if (childMetadata) {\n for (let i = 1; i < childMetadata.length; i++) {\n const targetIndex = offset + i\n if (targetIndex >= metadata.length) break\n\n metadata[targetIndex] = mergeRoutePathSegmentMetadata(\n metadata[targetIndex],\n childMetadata[i],\n )\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[targetIndex])\n }\n }\n\n return hasMetadata ? metadata : undefined\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 removeUnderscoresFromSegment(\n segment: string,\n metadata?: RoutePathSegmentMetadata,\n): string {\n let result = segment\n\n if (result.startsWith('_') && !metadata?.literalLeadingUnderscore) {\n result = result.slice(1)\n }\n\n if (result.endsWith('_') && !metadata?.literalTrailingUnderscore) {\n result = result.slice(0, -1)\n }\n\n return result\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 metadata = createRoutePathSegmentMetadata(routePath, originalPath)\n const newSegments = new Array<string>(routeSegments.length)\n\n for (let i = 0; i < routeSegments.length; i++) {\n newSegments[i] = removeUnderscoresFromSegment(\n routeSegments[i]!,\n metadata?.[i],\n )\n }\n\n return newSegments.join('/')\n}\n\nexport function removeLayoutSegmentsAndUnderscoresWithEscape(\n routePath: string = '/',\n originalPath?: string,\n routePathSegmentMetadata?: Array<RoutePathSegmentMetadata | undefined>,\n): string {\n if (!originalPath) {\n return removeUnderscores(removeLayoutSegments(routePath)) ?? ''\n }\n\n const metadata =\n routePathSegmentMetadata ??\n createRoutePathSegmentMetadata(routePath, originalPath)\n\n const routeSegments = routePath.split('/')\n const originalSegments = originalPath.split('/')\n const newSegments: Array<string> = []\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]!\n const originalSegment = originalSegments[i] || ''\n const segmentMetadata = metadata?.[i]\n\n if (\n !segmentMetadata?.literalLeadingUnderscore &&\n isSegmentPathless(segment, originalSegment)\n ) {\n continue\n }\n\n newSegments.push(removeUnderscoresFromSegment(segment, segmentMetadata))\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\nexport function escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction sanitizeTokenFlags(flags?: string): string | undefined {\n if (!flags) return flags\n\n // Prevent stateful behavior with RegExp.prototype.test/exec\n // g = global, y = sticky\n return flags.replace(/[gy]/g, '')\n}\n\nexport function createTokenRegex(\n token: TokenMatcher,\n opts: {\n type: 'segment' | 'filename'\n },\n): RegExp {\n // Defensive check: if token is undefined/null, throw a clear error\n // (runtime safety for config loading edge cases)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (token === undefined || token === null) {\n throw new Error(\n `createTokenRegex: token is ${token}. This usually means the config was not properly parsed with defaults.`,\n )\n }\n\n try {\n if (typeof token === 'string') {\n return opts.type === 'segment'\n ? new RegExp(`^${escapeRegExp(token)}$`)\n : new RegExp(`[./]${escapeRegExp(token)}[.]`)\n }\n\n if (token instanceof RegExp) {\n const flags = sanitizeTokenFlags(token.flags)\n return opts.type === 'segment'\n ? new RegExp(`^(?:${token.source})$`, flags)\n : new RegExp(`[./](?:${token.source})[.]`, flags)\n }\n\n // Handle JSON regex object form: { regex: string, flags?: string }\n if (typeof token === 'object' && 'regex' in token) {\n const flags = sanitizeTokenFlags(token.flags)\n return opts.type === 'segment'\n ? new RegExp(`^(?:${token.regex})$`, flags)\n : new RegExp(`[./](?:${token.regex})[.]`, flags)\n }\n\n throw new Error(\n `createTokenRegex: invalid token type. Expected string, RegExp, or { regex, flags } object, got: ${typeof token}`,\n )\n } catch (e) {\n if (e instanceof SyntaxError) {\n const pattern =\n typeof token === 'string'\n ? token\n : token instanceof RegExp\n ? token.source\n : token.regex\n throw new Error(\n `Invalid regex pattern in token config: \"${pattern}\". ${e.message}`,\n )\n }\n throw e\n }\n}\n\nfunction isBracketWrappedSegment(segment: string): boolean {\n return segment.startsWith('[') && segment.endsWith(']')\n}\n\nexport function unwrapBracketWrappedSegment(segment: string): string {\n return isBracketWrappedSegment(segment) ? segment.slice(1, -1) : segment\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, addExtensions: boolean | string = false) {\n if (typeof addExtensions === 'string') {\n const dotIndex = d.lastIndexOf('.')\n if (dotIndex === -1) return d\n return d.substring(0, dotIndex) + addExtensions\n }\n return addExtensions ? 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 * Infers the path for use by TS\n */\nconst inferPath = (routeNode: RouteNode): string => {\n if (routeNode.cleanedPath === '/') {\n return routeNode.cleanedPath ?? ''\n }\n return 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 removeLayoutSegmentsAndUnderscoresWithEscape(\n routeNode.routePath,\n routeNode.originalRoutePath,\n routeNode._routePathSegmentMetadata,\n ),\n )\n\n if (fullPath === '') {\n return '/'\n }\n\n // Preserve trailing slash for index routes (routePath ends with '/')\n // This ensures types match runtime behavior\n const isIndexRoute = routeNode.routePath?.endsWith('/')\n if (isIndexRoute) {\n return fullPath\n }\n\n return fullPath.replace(/\\/$/, '')\n}\n\nconst shouldPreferIndexRoute = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n return existing.cleanedPath === '/' && current.cleanedPath !== '/'\n}\n\nconst isIndexRouteNode = (routeNode: RouteNode): boolean => {\n return routeNode.routePath?.endsWith('/') ?? false\n}\n\nconst isPathlessRouteNode = (routeNode: RouteNode): boolean => {\n return routeNode._fsRouteType === 'pathless_layout'\n}\n\nconst shouldReplaceRouteNodeForTo = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n const currentIsIndex = isIndexRouteNode(current)\n const existingIsIndex = isIndexRouteNode(existing)\n if (currentIsIndex !== existingIsIndex) {\n return currentIsIndex\n }\n\n const currentIsPathless = isPathlessRouteNode(current)\n const existingIsPathless = isPathlessRouteNode(existing)\n if (currentIsPathless !== existingIsPathless) {\n return !currentIsPathless\n }\n\n return true\n}\n\nconst shouldReplaceRouteNodeForFullPath = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n const currentIsPathless = isPathlessRouteNode(current)\n const existingIsPathless = isPathlessRouteNode(existing)\n if (currentIsPathless !== existingIsPathless) {\n return !currentIsPathless\n }\n\n return true\n}\n\n/**\n * Creates a map from fullPath to routeNode\n */\nexport const createRouteNodesByFullPath = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n const map = new Map<string, RouteNode>()\n\n for (const routeNode of routeNodes) {\n const fullPath = inferFullPath(routeNode)\n\n if (fullPath === '/' && map.has('/')) {\n const existing = map.get('/')!\n if (shouldPreferIndexRoute(routeNode, existing)) {\n continue\n }\n }\n\n const existing = map.get(fullPath)\n if (existing && !shouldReplaceRouteNodeForFullPath(routeNode, existing)) {\n continue\n }\n\n map.set(fullPath, routeNode)\n }\n\n return map\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 const map = new Map<string, RouteNode>()\n\n for (const routeNode of dedupeBranchesAndIndexRoutes(routeNodes)) {\n const to = inferTo(routeNode)\n\n const existing = map.get(to)\n if (existing && !shouldReplaceRouteNodeForTo(routeNode, existing)) {\n continue\n }\n\n map.set(to, routeNode)\n }\n\n return map\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 */\nconst 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 */\nconst 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 emptyPathRoutes = _routes.filter((d) => d.routePath === '')\n if (emptyPathRoutes.length) {\n const errorMessage = `Invalid route path \"\" was found. Root routes must be defined via __root.tsx (createRootRoute), not createFileRoute('') or a route file that resolves to an empty path.\nConflicting files: \\n ${emptyPathRoutes\n .map((d) => path.resolve(config.routesDirectory, d.filePath))\n .join('\\n ')}\\n`\n throw new Error(errorMessage)\n }\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 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\nfunction 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"],"mappings":"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"}
|
package/dist/cjs/utils.d.cts
CHANGED
|
@@ -37,6 +37,14 @@ export declare function determineInitialRoutePath(routePath: string): {
|
|
|
37
37
|
routePath: string;
|
|
38
38
|
originalRoutePath: string;
|
|
39
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* Resolves bracket escapes in an explicit route path or ID without applying
|
|
42
|
+
* the dot-delimited flat-file route convention.
|
|
43
|
+
*/
|
|
44
|
+
export declare function determineInitialRoutePathFromExplicitPath(routePath: string): {
|
|
45
|
+
routePath: string;
|
|
46
|
+
originalRoutePath: string;
|
|
47
|
+
};
|
|
40
48
|
/**
|
|
41
49
|
* Checks if the leading underscore in a segment is escaped.
|
|
42
50
|
* Returns true if:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { virtualRootRouteSchema } from "./config.js";
|
|
2
2
|
import { rootPathId } from "../physical/rootPathId.js";
|
|
3
|
-
import { cleanPath, createLiteralRoutePathSegmentMetadata, createRoutePathSegmentMetadata,
|
|
3
|
+
import { cleanPath, createLiteralRoutePathSegmentMetadata, createRoutePathSegmentMetadata, determineInitialRoutePathFromExplicitPath, joinRoutePathSegmentMetadata, removeExt, removeLeadingSlash, removeTrailingSlash, replaceBackslash, routePathToVariable } from "../../utils.js";
|
|
4
4
|
import { loadConfigFile } from "./loadConfigFile.js";
|
|
5
5
|
import { getRouteNodes as getRouteNodes$1 } from "../physical/getRouteNodes.js";
|
|
6
6
|
import path, { join, resolve } from "node:path";
|
|
@@ -66,7 +66,7 @@ async function getRouteNodesRecursive(tsrConfig, root, fullDir, nodes, tokenRege
|
|
|
66
66
|
return {
|
|
67
67
|
children: (await Promise.all(nodes.map(async (node) => {
|
|
68
68
|
if (node.type === "physical") {
|
|
69
|
-
const { routePath: routePathPrefix, originalRoutePath: originalRoutePathPrefix } = node.pathPrefix ?
|
|
69
|
+
const { routePath: routePathPrefix, originalRoutePath: originalRoutePathPrefix } = node.pathPrefix ? determineInitialRoutePathFromExplicitPath(removeLeadingSlash(node.pathPrefix)) : {
|
|
70
70
|
routePath: "",
|
|
71
71
|
originalRoutePath: ""
|
|
72
72
|
};
|
|
@@ -116,7 +116,7 @@ async function getRouteNodesRecursive(tsrConfig, root, fullDir, nodes, tokenRege
|
|
|
116
116
|
case "route": {
|
|
117
117
|
const lastSegment = node.path;
|
|
118
118
|
let routeNode;
|
|
119
|
-
const { routePath: escapedSegment, originalRoutePath: originalSegment } =
|
|
119
|
+
const { routePath: escapedSegment, originalRoutePath: originalSegment } = determineInitialRoutePathFromExplicitPath(removeLeadingSlash(lastSegment));
|
|
120
120
|
const routePath = `${parentRoutePath}${escapedSegment}`;
|
|
121
121
|
const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`;
|
|
122
122
|
const routePathSegmentMetadata = createLiteralRoutePathSegmentMetadata(routePath, parent, true);
|
|
@@ -160,7 +160,7 @@ async function getRouteNodesRecursive(tsrConfig, root, fullDir, nodes, tokenRege
|
|
|
160
160
|
node.id = ensureLeadingUnderScore(fileNameWithoutExt);
|
|
161
161
|
}
|
|
162
162
|
const lastSegment = node.id;
|
|
163
|
-
const { routePath: escapedSegment, originalRoutePath: originalSegment } =
|
|
163
|
+
const { routePath: escapedSegment, originalRoutePath: originalSegment } = determineInitialRoutePathFromExplicitPath(removeLeadingSlash(lastSegment));
|
|
164
164
|
const routePath = `${parentRoutePath}${escapedSegment}`;
|
|
165
165
|
const routeNode = {
|
|
166
166
|
fullPath,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getRouteNodes.js","names":[],"sources":["../../../../src/filesystem/virtual/getRouteNodes.ts"],"sourcesContent":["import path, { join, resolve } from 'node:path'\nimport {\n cleanPath,\n createLiteralRoutePathSegmentMetadata,\n createRoutePathSegmentMetadata,\n determineInitialRoutePath,\n joinRoutePathSegmentMetadata,\n removeExt,\n removeLeadingSlash,\n removeTrailingSlash,\n replaceBackslash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'\nimport { rootPathId } from '../physical/rootPathId'\nimport { virtualRootRouteSchema } from './config'\nimport { loadConfigFile } from './loadConfigFile'\nimport type {\n VirtualRootRoute,\n VirtualRouteNode,\n} from '@tanstack/virtual-file-routes'\nimport type { GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\nimport type { TokenRegexBundle } from '../physical/getRouteNodes'\n\nfunction ensureLeadingUnderScore(id: string) {\n if (id.startsWith('_')) {\n return id\n }\n return `_${id}`\n}\n\nfunction flattenTree(node: RouteNode): Array<RouteNode> {\n const result = [node]\n\n if (node.children) {\n for (const child of node.children) {\n result.push(...flattenTree(child))\n }\n }\n delete node.children\n\n return result\n}\n\nexport async function getRouteNodes(\n tsrConfig: Pick<\n Config,\n | 'routesDirectory'\n | 'virtualRouteConfig'\n | 'routeFileIgnorePrefix'\n | 'disableLogging'\n | 'indexToken'\n | 'routeToken'\n >,\n root: string,\n tokenRegexes: TokenRegexBundle,\n): Promise<GetRouteNodesResult> {\n const fullDir = resolve(tsrConfig.routesDirectory)\n if (tsrConfig.virtualRouteConfig === undefined) {\n throw new Error(`virtualRouteConfig is undefined`)\n }\n let virtualRouteConfig: VirtualRootRoute\n if (typeof tsrConfig.virtualRouteConfig === 'string') {\n virtualRouteConfig = await getVirtualRouteConfigFromFileExport(\n tsrConfig,\n root,\n )\n } else {\n virtualRouteConfig = tsrConfig.virtualRouteConfig\n }\n const { children, physicalDirectories } = await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n virtualRouteConfig.children,\n tokenRegexes,\n )\n const allNodes = flattenTree({\n children,\n filePath: virtualRouteConfig.file,\n fullPath: replaceBackslash(join(fullDir, virtualRouteConfig.file)),\n variableName: 'root',\n routePath: `/${rootPathId}`,\n _fsRouteType: '__root',\n })\n\n const rootRouteNode = allNodes[0]\n const routeNodes = allNodes.slice(1)\n\n return { rootRouteNode, routeNodes, physicalDirectories }\n}\n\n/**\n * Get the virtual route config from a file export\n *\n * @example\n * ```ts\n * // routes.ts\n * import { rootRoute } from '@tanstack/virtual-file-routes'\n *\n * export const routes = rootRoute({ ... })\n * // or\n * export default rootRoute({ ... })\n * ```\n *\n */\nasync function getVirtualRouteConfigFromFileExport(\n tsrConfig: Pick<Config, 'virtualRouteConfig'>,\n root: string,\n): Promise<VirtualRootRoute> {\n if (\n tsrConfig.virtualRouteConfig === undefined ||\n typeof tsrConfig.virtualRouteConfig !== 'string' ||\n tsrConfig.virtualRouteConfig === ''\n ) {\n throw new Error(`virtualRouteConfig is undefined or empty`)\n }\n const exports = await loadConfigFile(join(root, tsrConfig.virtualRouteConfig))\n\n if (!('routes' in exports) && !('default' in exports)) {\n throw new Error(\n `routes not found in ${tsrConfig.virtualRouteConfig}. The routes export must be named like 'export const routes = ...' or done using 'export default ...'`,\n )\n }\n\n const virtualRouteConfig =\n 'routes' in exports ? exports.routes : exports.default\n\n return virtualRootRouteSchema.parse(virtualRouteConfig)\n}\n\nexport async function getRouteNodesRecursive(\n tsrConfig: Pick<\n Config,\n | 'routesDirectory'\n | 'routeFileIgnorePrefix'\n | 'disableLogging'\n | 'indexToken'\n | 'routeToken'\n >,\n root: string,\n fullDir: string,\n nodes: Array<VirtualRouteNode> | undefined,\n tokenRegexes: TokenRegexBundle,\n parent?: RouteNode,\n): Promise<{ children: Array<RouteNode>; physicalDirectories: Array<string> }> {\n if (nodes === undefined) {\n return { children: [], physicalDirectories: [] }\n }\n const allPhysicalDirectories: Array<string> = []\n const children = await Promise.all(\n nodes.map(async (node) => {\n if (node.type === 'physical') {\n const {\n routePath: routePathPrefix,\n originalRoutePath: originalRoutePathPrefix,\n } = node.pathPrefix\n ? determineInitialRoutePath(removeLeadingSlash(node.pathPrefix))\n : { routePath: '', originalRoutePath: '' }\n const { routeNodes, physicalDirectories } = await getRouteNodesPhysical(\n {\n ...tsrConfig,\n routesDirectory: resolve(fullDir, node.directory),\n },\n root,\n tokenRegexes,\n )\n allPhysicalDirectories.push(\n resolve(fullDir, node.directory),\n ...physicalDirectories,\n )\n routeNodes.forEach((subtreeNode) => {\n const pathPrefix = cleanPath(\n `${parent?.routePath ?? ''}${routePathPrefix}`,\n )\n const originalPathPrefix = cleanPath(\n `${parent?.originalRoutePath ?? parent?.routePath ?? ''}${originalRoutePathPrefix}`,\n )\n const literalPathPrefixSegments =\n createLiteralRoutePathSegmentMetadata(pathPrefix, parent, true)\n const routePath = cleanPath(`${pathPrefix}${subtreeNode.routePath}`)\n subtreeNode.variableName = routePathToVariable(\n `${routePathPrefix}/${removeExt(subtreeNode.filePath)}`,\n )\n subtreeNode._routePathSegmentMetadata = joinRoutePathSegmentMetadata(\n routePath,\n pathPrefix,\n literalPathPrefixSegments,\n subtreeNode._routePathSegmentMetadata,\n )\n subtreeNode.routePath = routePath\n // Keep originalRoutePath aligned with routePath for escape detection\n if (subtreeNode.originalRoutePath) {\n subtreeNode.originalRoutePath = cleanPath(\n `${originalPathPrefix}${subtreeNode.originalRoutePath}`,\n )\n }\n subtreeNode.filePath = `${node.directory}/${subtreeNode.filePath}`\n })\n return routeNodes\n }\n\n function getFile(file: string) {\n const filePath = file\n const variableName = routePathToVariable(removeExt(filePath))\n const fullPath = replaceBackslash(join(fullDir, filePath))\n return { filePath, variableName, fullPath }\n }\n const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')\n const parentOriginalRoutePath = removeTrailingSlash(\n parent?.originalRoutePath ?? parent?.routePath ?? '/',\n )\n const virtualParentRoutePath = parent?.routePath ?? `/${rootPathId}`\n\n switch (node.type) {\n case 'index': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n const routePath = `${parentRoutePath}/`\n const originalRoutePath = `${parentOriginalRoutePath}/`\n return {\n filePath,\n fullPath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: parent?._routePathSegmentMetadata\n ? [...parent._routePathSegmentMetadata]\n : undefined,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n } satisfies RouteNode\n }\n\n case 'route': {\n const lastSegment = node.path\n let routeNode: RouteNode\n\n // Process the segment to handle escape sequences like [_]\n const {\n routePath: escapedSegment,\n originalRoutePath: originalSegment,\n } = determineInitialRoutePath(removeLeadingSlash(lastSegment))\n const routePath = `${parentRoutePath}${escapedSegment}`\n const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`\n const routePathSegmentMetadata =\n createLiteralRoutePathSegmentMetadata(routePath, parent, true)\n\n if (node.file) {\n const { filePath, variableName, fullPath } = getFile(node.file)\n routeNode = {\n filePath,\n fullPath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n } else {\n routeNode = {\n filePath: '',\n fullPath: '',\n variableName: routePathToVariable(routePath),\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n isVirtual: true,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n }\n\n if (node.children !== undefined) {\n const { children, physicalDirectories } =\n await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n node.children,\n tokenRegexes,\n routeNode,\n )\n routeNode.children = children\n allPhysicalDirectories.push(...physicalDirectories)\n\n // If the route has children, it should be a layout\n routeNode._fsRouteType = 'layout'\n }\n return routeNode\n }\n case 'layout': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n\n if (node.id !== undefined) {\n node.id = ensureLeadingUnderScore(node.id)\n } else {\n const baseName = path.basename(filePath)\n const fileNameWithoutExt = path.parse(baseName).name\n node.id = ensureLeadingUnderScore(fileNameWithoutExt)\n }\n const lastSegment = node.id\n // Process the segment to handle escape sequences like [_]\n const {\n routePath: escapedSegment,\n originalRoutePath: originalSegment,\n } = determineInitialRoutePath(removeLeadingSlash(lastSegment))\n const routePath = `${parentRoutePath}${escapedSegment}`\n // Store the original path with brackets for escape detection\n const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`\n const routePathSegmentMetadata = joinRoutePathSegmentMetadata(\n routePath,\n parentRoutePath,\n parent?._routePathSegmentMetadata,\n createRoutePathSegmentMetadata(escapedSegment, originalSegment),\n )\n\n const routeNode: RouteNode = {\n fullPath,\n filePath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n _fsRouteType: 'pathless_layout',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n\n if (node.children !== undefined) {\n const { children, physicalDirectories } =\n await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n node.children,\n tokenRegexes,\n routeNode,\n )\n routeNode.children = children\n allPhysicalDirectories.push(...physicalDirectories)\n }\n return routeNode\n }\n }\n }),\n )\n return {\n children: children.flat(),\n physicalDirectories: allPhysicalDirectories,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"getRouteNodes.js","names":[],"sources":["../../../../src/filesystem/virtual/getRouteNodes.ts"],"sourcesContent":["import path, { join, resolve } from 'node:path'\nimport {\n cleanPath,\n createLiteralRoutePathSegmentMetadata,\n createRoutePathSegmentMetadata,\n determineInitialRoutePathFromExplicitPath,\n joinRoutePathSegmentMetadata,\n removeExt,\n removeLeadingSlash,\n removeTrailingSlash,\n replaceBackslash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'\nimport { rootPathId } from '../physical/rootPathId'\nimport { virtualRootRouteSchema } from './config'\nimport { loadConfigFile } from './loadConfigFile'\nimport type {\n VirtualRootRoute,\n VirtualRouteNode,\n} from '@tanstack/virtual-file-routes'\nimport type { GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\nimport type { TokenRegexBundle } from '../physical/getRouteNodes'\n\nfunction ensureLeadingUnderScore(id: string) {\n if (id.startsWith('_')) {\n return id\n }\n return `_${id}`\n}\n\nfunction flattenTree(node: RouteNode): Array<RouteNode> {\n const result = [node]\n\n if (node.children) {\n for (const child of node.children) {\n result.push(...flattenTree(child))\n }\n }\n delete node.children\n\n return result\n}\n\nexport async function getRouteNodes(\n tsrConfig: Pick<\n Config,\n | 'routesDirectory'\n | 'virtualRouteConfig'\n | 'routeFileIgnorePrefix'\n | 'disableLogging'\n | 'indexToken'\n | 'routeToken'\n >,\n root: string,\n tokenRegexes: TokenRegexBundle,\n): Promise<GetRouteNodesResult> {\n const fullDir = resolve(tsrConfig.routesDirectory)\n if (tsrConfig.virtualRouteConfig === undefined) {\n throw new Error(`virtualRouteConfig is undefined`)\n }\n let virtualRouteConfig: VirtualRootRoute\n if (typeof tsrConfig.virtualRouteConfig === 'string') {\n virtualRouteConfig = await getVirtualRouteConfigFromFileExport(\n tsrConfig,\n root,\n )\n } else {\n virtualRouteConfig = tsrConfig.virtualRouteConfig\n }\n const { children, physicalDirectories } = await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n virtualRouteConfig.children,\n tokenRegexes,\n )\n const allNodes = flattenTree({\n children,\n filePath: virtualRouteConfig.file,\n fullPath: replaceBackslash(join(fullDir, virtualRouteConfig.file)),\n variableName: 'root',\n routePath: `/${rootPathId}`,\n _fsRouteType: '__root',\n })\n\n const rootRouteNode = allNodes[0]\n const routeNodes = allNodes.slice(1)\n\n return { rootRouteNode, routeNodes, physicalDirectories }\n}\n\n/**\n * Get the virtual route config from a file export\n *\n * @example\n * ```ts\n * // routes.ts\n * import { rootRoute } from '@tanstack/virtual-file-routes'\n *\n * export const routes = rootRoute({ ... })\n * // or\n * export default rootRoute({ ... })\n * ```\n *\n */\nasync function getVirtualRouteConfigFromFileExport(\n tsrConfig: Pick<Config, 'virtualRouteConfig'>,\n root: string,\n): Promise<VirtualRootRoute> {\n if (\n tsrConfig.virtualRouteConfig === undefined ||\n typeof tsrConfig.virtualRouteConfig !== 'string' ||\n tsrConfig.virtualRouteConfig === ''\n ) {\n throw new Error(`virtualRouteConfig is undefined or empty`)\n }\n const exports = await loadConfigFile(join(root, tsrConfig.virtualRouteConfig))\n\n if (!('routes' in exports) && !('default' in exports)) {\n throw new Error(\n `routes not found in ${tsrConfig.virtualRouteConfig}. The routes export must be named like 'export const routes = ...' or done using 'export default ...'`,\n )\n }\n\n const virtualRouteConfig =\n 'routes' in exports ? exports.routes : exports.default\n\n return virtualRootRouteSchema.parse(virtualRouteConfig)\n}\n\nexport async function getRouteNodesRecursive(\n tsrConfig: Pick<\n Config,\n | 'routesDirectory'\n | 'routeFileIgnorePrefix'\n | 'disableLogging'\n | 'indexToken'\n | 'routeToken'\n >,\n root: string,\n fullDir: string,\n nodes: Array<VirtualRouteNode> | undefined,\n tokenRegexes: TokenRegexBundle,\n parent?: RouteNode,\n): Promise<{ children: Array<RouteNode>; physicalDirectories: Array<string> }> {\n if (nodes === undefined) {\n return { children: [], physicalDirectories: [] }\n }\n const allPhysicalDirectories: Array<string> = []\n const children = await Promise.all(\n nodes.map(async (node) => {\n if (node.type === 'physical') {\n const {\n routePath: routePathPrefix,\n originalRoutePath: originalRoutePathPrefix,\n } = node.pathPrefix\n ? determineInitialRoutePathFromExplicitPath(\n removeLeadingSlash(node.pathPrefix),\n )\n : { routePath: '', originalRoutePath: '' }\n const { routeNodes, physicalDirectories } = await getRouteNodesPhysical(\n {\n ...tsrConfig,\n routesDirectory: resolve(fullDir, node.directory),\n },\n root,\n tokenRegexes,\n )\n allPhysicalDirectories.push(\n resolve(fullDir, node.directory),\n ...physicalDirectories,\n )\n routeNodes.forEach((subtreeNode) => {\n const pathPrefix = cleanPath(\n `${parent?.routePath ?? ''}${routePathPrefix}`,\n )\n const originalPathPrefix = cleanPath(\n `${parent?.originalRoutePath ?? parent?.routePath ?? ''}${originalRoutePathPrefix}`,\n )\n const literalPathPrefixSegments =\n createLiteralRoutePathSegmentMetadata(pathPrefix, parent, true)\n const routePath = cleanPath(`${pathPrefix}${subtreeNode.routePath}`)\n subtreeNode.variableName = routePathToVariable(\n `${routePathPrefix}/${removeExt(subtreeNode.filePath)}`,\n )\n subtreeNode._routePathSegmentMetadata = joinRoutePathSegmentMetadata(\n routePath,\n pathPrefix,\n literalPathPrefixSegments,\n subtreeNode._routePathSegmentMetadata,\n )\n subtreeNode.routePath = routePath\n // Keep originalRoutePath aligned with routePath for escape detection\n if (subtreeNode.originalRoutePath) {\n subtreeNode.originalRoutePath = cleanPath(\n `${originalPathPrefix}${subtreeNode.originalRoutePath}`,\n )\n }\n subtreeNode.filePath = `${node.directory}/${subtreeNode.filePath}`\n })\n return routeNodes\n }\n\n function getFile(file: string) {\n const filePath = file\n const variableName = routePathToVariable(removeExt(filePath))\n const fullPath = replaceBackslash(join(fullDir, filePath))\n return { filePath, variableName, fullPath }\n }\n const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')\n const parentOriginalRoutePath = removeTrailingSlash(\n parent?.originalRoutePath ?? parent?.routePath ?? '/',\n )\n const virtualParentRoutePath = parent?.routePath ?? `/${rootPathId}`\n\n switch (node.type) {\n case 'index': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n const routePath = `${parentRoutePath}/`\n const originalRoutePath = `${parentOriginalRoutePath}/`\n return {\n filePath,\n fullPath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: parent?._routePathSegmentMetadata\n ? [...parent._routePathSegmentMetadata]\n : undefined,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n } satisfies RouteNode\n }\n\n case 'route': {\n const lastSegment = node.path\n let routeNode: RouteNode\n\n // Process the segment to handle escape sequences like [_]\n const {\n routePath: escapedSegment,\n originalRoutePath: originalSegment,\n } = determineInitialRoutePathFromExplicitPath(\n removeLeadingSlash(lastSegment),\n )\n const routePath = `${parentRoutePath}${escapedSegment}`\n const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`\n const routePathSegmentMetadata =\n createLiteralRoutePathSegmentMetadata(routePath, parent, true)\n\n if (node.file) {\n const { filePath, variableName, fullPath } = getFile(node.file)\n routeNode = {\n filePath,\n fullPath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n } else {\n routeNode = {\n filePath: '',\n fullPath: '',\n variableName: routePathToVariable(routePath),\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n isVirtual: true,\n _fsRouteType: 'static',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n }\n\n if (node.children !== undefined) {\n const { children, physicalDirectories } =\n await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n node.children,\n tokenRegexes,\n routeNode,\n )\n routeNode.children = children\n allPhysicalDirectories.push(...physicalDirectories)\n\n // If the route has children, it should be a layout\n routeNode._fsRouteType = 'layout'\n }\n return routeNode\n }\n case 'layout': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n\n if (node.id !== undefined) {\n node.id = ensureLeadingUnderScore(node.id)\n } else {\n const baseName = path.basename(filePath)\n const fileNameWithoutExt = path.parse(baseName).name\n node.id = ensureLeadingUnderScore(fileNameWithoutExt)\n }\n const lastSegment = node.id\n // Process the segment to handle escape sequences like [_]\n const {\n routePath: escapedSegment,\n originalRoutePath: originalSegment,\n } = determineInitialRoutePathFromExplicitPath(\n removeLeadingSlash(lastSegment),\n )\n const routePath = `${parentRoutePath}${escapedSegment}`\n // Store the original path with brackets for escape detection\n const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`\n const routePathSegmentMetadata = joinRoutePathSegmentMetadata(\n routePath,\n parentRoutePath,\n parent?._routePathSegmentMetadata,\n createRoutePathSegmentMetadata(escapedSegment, originalSegment),\n )\n\n const routeNode: RouteNode = {\n fullPath,\n filePath,\n variableName,\n routePath,\n originalRoutePath,\n _routePathSegmentMetadata: routePathSegmentMetadata,\n _fsRouteType: 'pathless_layout',\n _virtualParentRoutePath: virtualParentRoutePath,\n }\n\n if (node.children !== undefined) {\n const { children, physicalDirectories } =\n await getRouteNodesRecursive(\n tsrConfig,\n root,\n fullDir,\n node.children,\n tokenRegexes,\n routeNode,\n )\n routeNode.children = children\n allPhysicalDirectories.push(...physicalDirectories)\n }\n return routeNode\n }\n }\n }),\n )\n return {\n children: children.flat(),\n physicalDirectories: allPhysicalDirectories,\n }\n}\n"],"mappings":"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"}
|
package/dist/esm/utils.d.ts
CHANGED
|
@@ -37,6 +37,14 @@ export declare function determineInitialRoutePath(routePath: string): {
|
|
|
37
37
|
routePath: string;
|
|
38
38
|
originalRoutePath: string;
|
|
39
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* Resolves bracket escapes in an explicit route path or ID without applying
|
|
42
|
+
* the dot-delimited flat-file route convention.
|
|
43
|
+
*/
|
|
44
|
+
export declare function determineInitialRoutePathFromExplicitPath(routePath: string): {
|
|
45
|
+
routePath: string;
|
|
46
|
+
originalRoutePath: string;
|
|
47
|
+
};
|
|
40
48
|
/**
|
|
41
49
|
* Checks if the leading underscore in a segment is escaped.
|
|
42
50
|
* Returns true if:
|
package/dist/esm/utils.js
CHANGED
|
@@ -125,10 +125,10 @@ var DISALLOWED_ESCAPE_CHARS = new Set([
|
|
|
125
125
|
"$",
|
|
126
126
|
"%"
|
|
127
127
|
]);
|
|
128
|
-
function
|
|
129
|
-
const originalRoutePath = cleanPath(`/${
|
|
128
|
+
function determineInitialRoutePathFromParts(routePath, parts) {
|
|
129
|
+
const originalRoutePath = cleanPath(`/${cleanPath(parts.join("/")) || ""}`) || "";
|
|
130
130
|
return {
|
|
131
|
-
routePath: cleanPath(`/${
|
|
131
|
+
routePath: cleanPath(`/${parts.map((part) => {
|
|
132
132
|
let match;
|
|
133
133
|
while ((match = BRACKET_CONTENT_RE.exec(part)) !== null) {
|
|
134
134
|
const character = match[1];
|
|
@@ -143,6 +143,16 @@ function determineInitialRoutePath(routePath) {
|
|
|
143
143
|
originalRoutePath
|
|
144
144
|
};
|
|
145
145
|
}
|
|
146
|
+
function determineInitialRoutePath(routePath) {
|
|
147
|
+
return determineInitialRoutePathFromParts(routePath, routePath.split(SPLIT_REGEX));
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Resolves bracket escapes in an explicit route path or ID without applying
|
|
151
|
+
* the dot-delimited flat-file route convention.
|
|
152
|
+
*/
|
|
153
|
+
function determineInitialRoutePathFromExplicitPath(routePath) {
|
|
154
|
+
return determineInitialRoutePathFromParts(routePath, [routePath]);
|
|
155
|
+
}
|
|
146
156
|
/**
|
|
147
157
|
* Checks if a segment is fully escaped (entirely wrapped in brackets with no nested brackets).
|
|
148
158
|
* E.g., "[index]" -> true, "[_layout]" -> true, "foo[.]bar" -> false, "index" -> false
|
|
@@ -704,6 +714,6 @@ function getImportForRouteNode(node, config, generatedRouteTreePath, root) {
|
|
|
704
714
|
};
|
|
705
715
|
}
|
|
706
716
|
//#endregion
|
|
707
|
-
export { RoutePrefixMap, buildFileRoutesByPathInterface, buildImportString, buildRouteTreeConfig, capitalize, checkFileExists, checkRouteFullPathUniqueness, cleanPath, countRoutePathSegments, countSlashSeparatedParts, createLiteralRoutePathSegmentMetadata, createRouteNodesByFullPath, createRouteNodesById, createRouteNodesByTo, createRoutePathSegmentMetadata, createTokenRegex, determineInitialRoutePath, determineNodePath, escapeRegExp, findParent, format, getImportForRouteNode, getResolvedRouteNodeVariableName, hasEscapedLeadingUnderscore, hasParentRoute, inferFullPath, isSegmentPathless, joinRoutePathSegmentMetadata, mergeImportDeclarations, multiSortBy, removeExt, removeGroups, removeLastSegmentFromPath, removeLayoutSegmentsAndUnderscoresWithEscape, removeLeadingSlash, removeTrailingSlash, removeUnderscores, replaceBackslash, resetRegex, routePathToVariable, sortRouteNodes, trimPathLeft, unwrapBracketWrappedSegment, writeIfDifferent };
|
|
717
|
+
export { RoutePrefixMap, buildFileRoutesByPathInterface, buildImportString, buildRouteTreeConfig, capitalize, checkFileExists, checkRouteFullPathUniqueness, cleanPath, countRoutePathSegments, countSlashSeparatedParts, createLiteralRoutePathSegmentMetadata, createRouteNodesByFullPath, createRouteNodesById, createRouteNodesByTo, createRoutePathSegmentMetadata, createTokenRegex, determineInitialRoutePath, determineInitialRoutePathFromExplicitPath, determineNodePath, escapeRegExp, findParent, format, getImportForRouteNode, getResolvedRouteNodeVariableName, hasEscapedLeadingUnderscore, hasParentRoute, inferFullPath, isSegmentPathless, joinRoutePathSegmentMetadata, mergeImportDeclarations, multiSortBy, removeExt, removeGroups, removeLastSegmentFromPath, removeLayoutSegmentsAndUnderscoresWithEscape, removeLeadingSlash, removeTrailingSlash, removeUnderscores, replaceBackslash, resetRegex, routePathToVariable, sortRouteNodes, trimPathLeft, unwrapBracketWrappedSegment, writeIfDifferent };
|
|
708
718
|
|
|
709
719
|
//# sourceMappingURL=utils.js.map
|
package/dist/esm/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"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, TokenMatcher } from './config'\nimport type {\n ImportDeclaration,\n RouteNode,\n RoutePathSegmentMetadata,\n} 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\n constructor(routes: Array<RouteNode>) {\n for (const route of routes) {\n if (!route.routePath || route.routePath === `/${rootPathId}`) continue\n\n // Skip route pieces (lazy, loader, component, etc.) - they are merged with main routes\n // and should not be valid parent candidates\n if (\n route._fsRouteType === 'lazy' ||\n route._fsRouteType === 'loader' ||\n route._fsRouteType === 'component' ||\n route._fsRouteType === 'pendingComponent' ||\n route._fsRouteType === 'errorComponent' ||\n route._fsRouteType === 'notFoundComponent'\n ) {\n continue\n }\n\n // Index by exact path for direct lookups\n this.prefixToRoute.set(route.routePath, route)\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\n/**\n * Sorts route nodes by root, path depth, index status, and finally `routePath`.\n * The `routePath` comparison keeps the output consistent when the earlier\n * values are the same.\n */\nexport function sortRouteNodes(\n routeNodes: Array<RouteNode>,\n indexTokenSegmentRegex: RegExp,\n): Array<RouteNode> {\n return multiSortBy(routeNodes, [\n (d) => (d.routePath?.includes(`/${rootPathId}`) ? -1 : 1),\n (d) =>\n d.routePath === undefined\n ? undefined\n : countSlashSeparatedParts(d.routePath),\n (d) => {\n const segments = d.routePath?.split('/').filter(Boolean) ?? []\n const last = segments[segments.length - 1] ?? ''\n return indexTokenSegmentRegex.test(last) ? -1 : 1\n },\n (d) => d.routePath,\n ])\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\nexport function countRoutePathSegments(routePath?: string): number {\n const path = routePath ?? ''\n let count = 0\n let inSegment = false\n\n for (let i = 0; i < path.length; i++) {\n if (path[i] === '/') {\n inSegment = false\n continue\n }\n\n if (!inSegment) {\n count++\n inSegment = true\n }\n }\n\n return count\n}\n\nexport function countSlashSeparatedParts(path: string): number {\n let count = 1\n\n for (let i = 0; i < path.length; i++) {\n if (path[i] === '/') count++\n }\n\n return count\n}\n\nexport function hasRoutePathSegmentMetadata(\n metadata: RoutePathSegmentMetadata | undefined,\n): metadata is RoutePathSegmentMetadata {\n return !!(\n metadata?.literalLeadingUnderscore || metadata?.literalTrailingUnderscore\n )\n}\n\nfunction mergeRoutePathSegmentMetadata(\n current: RoutePathSegmentMetadata | undefined,\n incoming: RoutePathSegmentMetadata | undefined,\n): RoutePathSegmentMetadata | undefined {\n const hasCurrent = hasRoutePathSegmentMetadata(current)\n const hasIncoming = hasRoutePathSegmentMetadata(incoming)\n\n if (!hasCurrent) return hasIncoming ? incoming : undefined\n if (!hasIncoming) return current\n\n return {\n literalLeadingUnderscore:\n current.literalLeadingUnderscore || incoming.literalLeadingUnderscore,\n literalTrailingUnderscore:\n current.literalTrailingUnderscore || incoming.literalTrailingUnderscore,\n }\n}\n\nexport function createRoutePathSegmentMetadata(\n routePath: string = '/',\n originalPath?: string,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n if (!originalPath) return undefined\n\n const routeSegments = routePath.split('/')\n const originalSegments = originalPath.split('/')\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n routeSegments.length,\n )\n let hasMetadata = false\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]!\n const originalSegment = originalSegments[i] || ''\n const literalLeadingUnderscore =\n segment.startsWith('_') && hasEscapedLeadingUnderscore(originalSegment)\n const literalTrailingUnderscore =\n segment.endsWith('_') && hasEscapedTrailingUnderscore(originalSegment)\n\n if (!literalLeadingUnderscore && !literalTrailingUnderscore) continue\n\n hasMetadata = true\n metadata[i] = {\n literalLeadingUnderscore: literalLeadingUnderscore || undefined,\n literalTrailingUnderscore: literalTrailingUnderscore || undefined,\n }\n }\n\n return hasMetadata ? metadata : undefined\n}\n\nexport function createLiteralRoutePathSegmentMetadata(\n routePath: string,\n parent?: RouteNode,\n literalNewSegments = false,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n const routeSegments = routePath.split('/')\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n routeSegments.length,\n )\n const parentDepth = countRoutePathSegments(parent?.routePath)\n let hasMetadata = false\n let depth = 0\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]\n metadata[i] = parent?._routePathSegmentMetadata?.[i]\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[i])\n\n if (!segment) continue\n\n if (literalNewSegments && depth >= parentDepth) {\n const literalLeadingUnderscore = segment.startsWith('_')\n const literalTrailingUnderscore = segment.endsWith('_')\n\n if (literalLeadingUnderscore || literalTrailingUnderscore) {\n metadata[i] = mergeRoutePathSegmentMetadata(metadata[i], {\n literalLeadingUnderscore: literalLeadingUnderscore || undefined,\n literalTrailingUnderscore: literalTrailingUnderscore || undefined,\n })\n hasMetadata = true\n }\n }\n\n depth++\n }\n\n return hasMetadata ? metadata : undefined\n}\n\nexport function joinRoutePathSegmentMetadata(\n routePath: string,\n prefixPath: string,\n prefixMetadata: Array<RoutePathSegmentMetadata | undefined> | undefined,\n childMetadata: Array<RoutePathSegmentMetadata | undefined> | undefined,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n countSlashSeparatedParts(routePath),\n )\n let hasMetadata = false\n\n if (prefixMetadata) {\n for (let i = 0; i < prefixMetadata.length && i < metadata.length; i++) {\n metadata[i] = prefixMetadata[i]\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[i])\n }\n }\n\n const offset = countRoutePathSegments(prefixPath)\n if (childMetadata) {\n for (let i = 1; i < childMetadata.length; i++) {\n const targetIndex = offset + i\n if (targetIndex >= metadata.length) break\n\n metadata[targetIndex] = mergeRoutePathSegmentMetadata(\n metadata[targetIndex],\n childMetadata[i],\n )\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[targetIndex])\n }\n }\n\n return hasMetadata ? metadata : undefined\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 removeUnderscoresFromSegment(\n segment: string,\n metadata?: RoutePathSegmentMetadata,\n): string {\n let result = segment\n\n if (result.startsWith('_') && !metadata?.literalLeadingUnderscore) {\n result = result.slice(1)\n }\n\n if (result.endsWith('_') && !metadata?.literalTrailingUnderscore) {\n result = result.slice(0, -1)\n }\n\n return result\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 metadata = createRoutePathSegmentMetadata(routePath, originalPath)\n const newSegments = new Array<string>(routeSegments.length)\n\n for (let i = 0; i < routeSegments.length; i++) {\n newSegments[i] = removeUnderscoresFromSegment(\n routeSegments[i]!,\n metadata?.[i],\n )\n }\n\n return newSegments.join('/')\n}\n\nexport function removeLayoutSegmentsAndUnderscoresWithEscape(\n routePath: string = '/',\n originalPath?: string,\n routePathSegmentMetadata?: Array<RoutePathSegmentMetadata | undefined>,\n): string {\n if (!originalPath) {\n return removeUnderscores(removeLayoutSegments(routePath)) ?? ''\n }\n\n const metadata =\n routePathSegmentMetadata ??\n createRoutePathSegmentMetadata(routePath, originalPath)\n\n const routeSegments = routePath.split('/')\n const originalSegments = originalPath.split('/')\n const newSegments: Array<string> = []\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]!\n const originalSegment = originalSegments[i] || ''\n const segmentMetadata = metadata?.[i]\n\n if (\n !segmentMetadata?.literalLeadingUnderscore &&\n isSegmentPathless(segment, originalSegment)\n ) {\n continue\n }\n\n newSegments.push(removeUnderscoresFromSegment(segment, segmentMetadata))\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\nexport function escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction sanitizeTokenFlags(flags?: string): string | undefined {\n if (!flags) return flags\n\n // Prevent stateful behavior with RegExp.prototype.test/exec\n // g = global, y = sticky\n return flags.replace(/[gy]/g, '')\n}\n\nexport function createTokenRegex(\n token: TokenMatcher,\n opts: {\n type: 'segment' | 'filename'\n },\n): RegExp {\n // Defensive check: if token is undefined/null, throw a clear error\n // (runtime safety for config loading edge cases)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (token === undefined || token === null) {\n throw new Error(\n `createTokenRegex: token is ${token}. This usually means the config was not properly parsed with defaults.`,\n )\n }\n\n try {\n if (typeof token === 'string') {\n return opts.type === 'segment'\n ? new RegExp(`^${escapeRegExp(token)}$`)\n : new RegExp(`[./]${escapeRegExp(token)}[.]`)\n }\n\n if (token instanceof RegExp) {\n const flags = sanitizeTokenFlags(token.flags)\n return opts.type === 'segment'\n ? new RegExp(`^(?:${token.source})$`, flags)\n : new RegExp(`[./](?:${token.source})[.]`, flags)\n }\n\n // Handle JSON regex object form: { regex: string, flags?: string }\n if (typeof token === 'object' && 'regex' in token) {\n const flags = sanitizeTokenFlags(token.flags)\n return opts.type === 'segment'\n ? new RegExp(`^(?:${token.regex})$`, flags)\n : new RegExp(`[./](?:${token.regex})[.]`, flags)\n }\n\n throw new Error(\n `createTokenRegex: invalid token type. Expected string, RegExp, or { regex, flags } object, got: ${typeof token}`,\n )\n } catch (e) {\n if (e instanceof SyntaxError) {\n const pattern =\n typeof token === 'string'\n ? token\n : token instanceof RegExp\n ? token.source\n : token.regex\n throw new Error(\n `Invalid regex pattern in token config: \"${pattern}\". ${e.message}`,\n )\n }\n throw e\n }\n}\n\nfunction isBracketWrappedSegment(segment: string): boolean {\n return segment.startsWith('[') && segment.endsWith(']')\n}\n\nexport function unwrapBracketWrappedSegment(segment: string): string {\n return isBracketWrappedSegment(segment) ? segment.slice(1, -1) : segment\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, addExtensions: boolean | string = false) {\n if (typeof addExtensions === 'string') {\n const dotIndex = d.lastIndexOf('.')\n if (dotIndex === -1) return d\n return d.substring(0, dotIndex) + addExtensions\n }\n return addExtensions ? 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 * Infers the path for use by TS\n */\nconst inferPath = (routeNode: RouteNode): string => {\n if (routeNode.cleanedPath === '/') {\n return routeNode.cleanedPath ?? ''\n }\n return 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 removeLayoutSegmentsAndUnderscoresWithEscape(\n routeNode.routePath,\n routeNode.originalRoutePath,\n routeNode._routePathSegmentMetadata,\n ),\n )\n\n if (fullPath === '') {\n return '/'\n }\n\n // Preserve trailing slash for index routes (routePath ends with '/')\n // This ensures types match runtime behavior\n const isIndexRoute = routeNode.routePath?.endsWith('/')\n if (isIndexRoute) {\n return fullPath\n }\n\n return fullPath.replace(/\\/$/, '')\n}\n\nconst shouldPreferIndexRoute = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n return existing.cleanedPath === '/' && current.cleanedPath !== '/'\n}\n\nconst isIndexRouteNode = (routeNode: RouteNode): boolean => {\n return routeNode.routePath?.endsWith('/') ?? false\n}\n\nconst isPathlessRouteNode = (routeNode: RouteNode): boolean => {\n return routeNode._fsRouteType === 'pathless_layout'\n}\n\nconst shouldReplaceRouteNodeForTo = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n const currentIsIndex = isIndexRouteNode(current)\n const existingIsIndex = isIndexRouteNode(existing)\n if (currentIsIndex !== existingIsIndex) {\n return currentIsIndex\n }\n\n const currentIsPathless = isPathlessRouteNode(current)\n const existingIsPathless = isPathlessRouteNode(existing)\n if (currentIsPathless !== existingIsPathless) {\n return !currentIsPathless\n }\n\n return true\n}\n\nconst shouldReplaceRouteNodeForFullPath = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n const currentIsPathless = isPathlessRouteNode(current)\n const existingIsPathless = isPathlessRouteNode(existing)\n if (currentIsPathless !== existingIsPathless) {\n return !currentIsPathless\n }\n\n return true\n}\n\n/**\n * Creates a map from fullPath to routeNode\n */\nexport const createRouteNodesByFullPath = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n const map = new Map<string, RouteNode>()\n\n for (const routeNode of routeNodes) {\n const fullPath = inferFullPath(routeNode)\n\n if (fullPath === '/' && map.has('/')) {\n const existing = map.get('/')!\n if (shouldPreferIndexRoute(routeNode, existing)) {\n continue\n }\n }\n\n const existing = map.get(fullPath)\n if (existing && !shouldReplaceRouteNodeForFullPath(routeNode, existing)) {\n continue\n }\n\n map.set(fullPath, routeNode)\n }\n\n return map\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 const map = new Map<string, RouteNode>()\n\n for (const routeNode of dedupeBranchesAndIndexRoutes(routeNodes)) {\n const to = inferTo(routeNode)\n\n const existing = map.get(to)\n if (existing && !shouldReplaceRouteNodeForTo(routeNode, existing)) {\n continue\n }\n\n map.set(to, routeNode)\n }\n\n return map\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 */\nconst 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 */\nconst 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 emptyPathRoutes = _routes.filter((d) => d.routePath === '')\n if (emptyPathRoutes.length) {\n const errorMessage = `Invalid route path \"\" was found. Root routes must be defined via __root.tsx (createRootRoute), not createFileRoute('') or a route file that resolves to an empty path.\nConflicting files: \\n ${emptyPathRoutes\n .map((d) => path.resolve(config.routesDirectory, d.filePath))\n .join('\\n ')}\\n`\n throw new Error(errorMessage)\n }\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 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\nfunction 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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"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, TokenMatcher } from './config'\nimport type {\n ImportDeclaration,\n RouteNode,\n RoutePathSegmentMetadata,\n} 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\n constructor(routes: Array<RouteNode>) {\n for (const route of routes) {\n if (!route.routePath || route.routePath === `/${rootPathId}`) continue\n\n // Skip route pieces (lazy, loader, component, etc.) - they are merged with main routes\n // and should not be valid parent candidates\n if (\n route._fsRouteType === 'lazy' ||\n route._fsRouteType === 'loader' ||\n route._fsRouteType === 'component' ||\n route._fsRouteType === 'pendingComponent' ||\n route._fsRouteType === 'errorComponent' ||\n route._fsRouteType === 'notFoundComponent'\n ) {\n continue\n }\n\n // Index by exact path for direct lookups\n this.prefixToRoute.set(route.routePath, route)\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\n/**\n * Sorts route nodes by root, path depth, index status, and finally `routePath`.\n * The `routePath` comparison keeps the output consistent when the earlier\n * values are the same.\n */\nexport function sortRouteNodes(\n routeNodes: Array<RouteNode>,\n indexTokenSegmentRegex: RegExp,\n): Array<RouteNode> {\n return multiSortBy(routeNodes, [\n (d) => (d.routePath?.includes(`/${rootPathId}`) ? -1 : 1),\n (d) =>\n d.routePath === undefined\n ? undefined\n : countSlashSeparatedParts(d.routePath),\n (d) => {\n const segments = d.routePath?.split('/').filter(Boolean) ?? []\n const last = segments[segments.length - 1] ?? ''\n return indexTokenSegmentRegex.test(last) ? -1 : 1\n },\n (d) => d.routePath,\n ])\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\nfunction determineInitialRoutePathFromParts(\n routePath: string,\n parts: Array<string>,\n) {\n const originalRoutePath =\n cleanPath(`/${cleanPath(parts.join('/')) || ''}`) || ''\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\nexport function determineInitialRoutePath(routePath: string) {\n return determineInitialRoutePathFromParts(\n routePath,\n routePath.split(SPLIT_REGEX),\n )\n}\n\n/**\n * Resolves bracket escapes in an explicit route path or ID without applying\n * the dot-delimited flat-file route convention.\n */\nexport function determineInitialRoutePathFromExplicitPath(routePath: string) {\n return determineInitialRoutePathFromParts(routePath, [routePath])\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\nexport function countRoutePathSegments(routePath?: string): number {\n const path = routePath ?? ''\n let count = 0\n let inSegment = false\n\n for (let i = 0; i < path.length; i++) {\n if (path[i] === '/') {\n inSegment = false\n continue\n }\n\n if (!inSegment) {\n count++\n inSegment = true\n }\n }\n\n return count\n}\n\nexport function countSlashSeparatedParts(path: string): number {\n let count = 1\n\n for (let i = 0; i < path.length; i++) {\n if (path[i] === '/') count++\n }\n\n return count\n}\n\nexport function hasRoutePathSegmentMetadata(\n metadata: RoutePathSegmentMetadata | undefined,\n): metadata is RoutePathSegmentMetadata {\n return !!(\n metadata?.literalLeadingUnderscore || metadata?.literalTrailingUnderscore\n )\n}\n\nfunction mergeRoutePathSegmentMetadata(\n current: RoutePathSegmentMetadata | undefined,\n incoming: RoutePathSegmentMetadata | undefined,\n): RoutePathSegmentMetadata | undefined {\n const hasCurrent = hasRoutePathSegmentMetadata(current)\n const hasIncoming = hasRoutePathSegmentMetadata(incoming)\n\n if (!hasCurrent) return hasIncoming ? incoming : undefined\n if (!hasIncoming) return current\n\n return {\n literalLeadingUnderscore:\n current.literalLeadingUnderscore || incoming.literalLeadingUnderscore,\n literalTrailingUnderscore:\n current.literalTrailingUnderscore || incoming.literalTrailingUnderscore,\n }\n}\n\nexport function createRoutePathSegmentMetadata(\n routePath: string = '/',\n originalPath?: string,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n if (!originalPath) return undefined\n\n const routeSegments = routePath.split('/')\n const originalSegments = originalPath.split('/')\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n routeSegments.length,\n )\n let hasMetadata = false\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]!\n const originalSegment = originalSegments[i] || ''\n const literalLeadingUnderscore =\n segment.startsWith('_') && hasEscapedLeadingUnderscore(originalSegment)\n const literalTrailingUnderscore =\n segment.endsWith('_') && hasEscapedTrailingUnderscore(originalSegment)\n\n if (!literalLeadingUnderscore && !literalTrailingUnderscore) continue\n\n hasMetadata = true\n metadata[i] = {\n literalLeadingUnderscore: literalLeadingUnderscore || undefined,\n literalTrailingUnderscore: literalTrailingUnderscore || undefined,\n }\n }\n\n return hasMetadata ? metadata : undefined\n}\n\nexport function createLiteralRoutePathSegmentMetadata(\n routePath: string,\n parent?: RouteNode,\n literalNewSegments = false,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n const routeSegments = routePath.split('/')\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n routeSegments.length,\n )\n const parentDepth = countRoutePathSegments(parent?.routePath)\n let hasMetadata = false\n let depth = 0\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]\n metadata[i] = parent?._routePathSegmentMetadata?.[i]\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[i])\n\n if (!segment) continue\n\n if (literalNewSegments && depth >= parentDepth) {\n const literalLeadingUnderscore = segment.startsWith('_')\n const literalTrailingUnderscore = segment.endsWith('_')\n\n if (literalLeadingUnderscore || literalTrailingUnderscore) {\n metadata[i] = mergeRoutePathSegmentMetadata(metadata[i], {\n literalLeadingUnderscore: literalLeadingUnderscore || undefined,\n literalTrailingUnderscore: literalTrailingUnderscore || undefined,\n })\n hasMetadata = true\n }\n }\n\n depth++\n }\n\n return hasMetadata ? metadata : undefined\n}\n\nexport function joinRoutePathSegmentMetadata(\n routePath: string,\n prefixPath: string,\n prefixMetadata: Array<RoutePathSegmentMetadata | undefined> | undefined,\n childMetadata: Array<RoutePathSegmentMetadata | undefined> | undefined,\n): Array<RoutePathSegmentMetadata | undefined> | undefined {\n const metadata = new Array<RoutePathSegmentMetadata | undefined>(\n countSlashSeparatedParts(routePath),\n )\n let hasMetadata = false\n\n if (prefixMetadata) {\n for (let i = 0; i < prefixMetadata.length && i < metadata.length; i++) {\n metadata[i] = prefixMetadata[i]\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[i])\n }\n }\n\n const offset = countRoutePathSegments(prefixPath)\n if (childMetadata) {\n for (let i = 1; i < childMetadata.length; i++) {\n const targetIndex = offset + i\n if (targetIndex >= metadata.length) break\n\n metadata[targetIndex] = mergeRoutePathSegmentMetadata(\n metadata[targetIndex],\n childMetadata[i],\n )\n hasMetadata ||= hasRoutePathSegmentMetadata(metadata[targetIndex])\n }\n }\n\n return hasMetadata ? metadata : undefined\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 removeUnderscoresFromSegment(\n segment: string,\n metadata?: RoutePathSegmentMetadata,\n): string {\n let result = segment\n\n if (result.startsWith('_') && !metadata?.literalLeadingUnderscore) {\n result = result.slice(1)\n }\n\n if (result.endsWith('_') && !metadata?.literalTrailingUnderscore) {\n result = result.slice(0, -1)\n }\n\n return result\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 metadata = createRoutePathSegmentMetadata(routePath, originalPath)\n const newSegments = new Array<string>(routeSegments.length)\n\n for (let i = 0; i < routeSegments.length; i++) {\n newSegments[i] = removeUnderscoresFromSegment(\n routeSegments[i]!,\n metadata?.[i],\n )\n }\n\n return newSegments.join('/')\n}\n\nexport function removeLayoutSegmentsAndUnderscoresWithEscape(\n routePath: string = '/',\n originalPath?: string,\n routePathSegmentMetadata?: Array<RoutePathSegmentMetadata | undefined>,\n): string {\n if (!originalPath) {\n return removeUnderscores(removeLayoutSegments(routePath)) ?? ''\n }\n\n const metadata =\n routePathSegmentMetadata ??\n createRoutePathSegmentMetadata(routePath, originalPath)\n\n const routeSegments = routePath.split('/')\n const originalSegments = originalPath.split('/')\n const newSegments: Array<string> = []\n\n for (let i = 0; i < routeSegments.length; i++) {\n const segment = routeSegments[i]!\n const originalSegment = originalSegments[i] || ''\n const segmentMetadata = metadata?.[i]\n\n if (\n !segmentMetadata?.literalLeadingUnderscore &&\n isSegmentPathless(segment, originalSegment)\n ) {\n continue\n }\n\n newSegments.push(removeUnderscoresFromSegment(segment, segmentMetadata))\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\nexport function escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction sanitizeTokenFlags(flags?: string): string | undefined {\n if (!flags) return flags\n\n // Prevent stateful behavior with RegExp.prototype.test/exec\n // g = global, y = sticky\n return flags.replace(/[gy]/g, '')\n}\n\nexport function createTokenRegex(\n token: TokenMatcher,\n opts: {\n type: 'segment' | 'filename'\n },\n): RegExp {\n // Defensive check: if token is undefined/null, throw a clear error\n // (runtime safety for config loading edge cases)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (token === undefined || token === null) {\n throw new Error(\n `createTokenRegex: token is ${token}. This usually means the config was not properly parsed with defaults.`,\n )\n }\n\n try {\n if (typeof token === 'string') {\n return opts.type === 'segment'\n ? new RegExp(`^${escapeRegExp(token)}$`)\n : new RegExp(`[./]${escapeRegExp(token)}[.]`)\n }\n\n if (token instanceof RegExp) {\n const flags = sanitizeTokenFlags(token.flags)\n return opts.type === 'segment'\n ? new RegExp(`^(?:${token.source})$`, flags)\n : new RegExp(`[./](?:${token.source})[.]`, flags)\n }\n\n // Handle JSON regex object form: { regex: string, flags?: string }\n if (typeof token === 'object' && 'regex' in token) {\n const flags = sanitizeTokenFlags(token.flags)\n return opts.type === 'segment'\n ? new RegExp(`^(?:${token.regex})$`, flags)\n : new RegExp(`[./](?:${token.regex})[.]`, flags)\n }\n\n throw new Error(\n `createTokenRegex: invalid token type. Expected string, RegExp, or { regex, flags } object, got: ${typeof token}`,\n )\n } catch (e) {\n if (e instanceof SyntaxError) {\n const pattern =\n typeof token === 'string'\n ? token\n : token instanceof RegExp\n ? token.source\n : token.regex\n throw new Error(\n `Invalid regex pattern in token config: \"${pattern}\". ${e.message}`,\n )\n }\n throw e\n }\n}\n\nfunction isBracketWrappedSegment(segment: string): boolean {\n return segment.startsWith('[') && segment.endsWith(']')\n}\n\nexport function unwrapBracketWrappedSegment(segment: string): string {\n return isBracketWrappedSegment(segment) ? segment.slice(1, -1) : segment\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, addExtensions: boolean | string = false) {\n if (typeof addExtensions === 'string') {\n const dotIndex = d.lastIndexOf('.')\n if (dotIndex === -1) return d\n return d.substring(0, dotIndex) + addExtensions\n }\n return addExtensions ? 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 * Infers the path for use by TS\n */\nconst inferPath = (routeNode: RouteNode): string => {\n if (routeNode.cleanedPath === '/') {\n return routeNode.cleanedPath ?? ''\n }\n return 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 removeLayoutSegmentsAndUnderscoresWithEscape(\n routeNode.routePath,\n routeNode.originalRoutePath,\n routeNode._routePathSegmentMetadata,\n ),\n )\n\n if (fullPath === '') {\n return '/'\n }\n\n // Preserve trailing slash for index routes (routePath ends with '/')\n // This ensures types match runtime behavior\n const isIndexRoute = routeNode.routePath?.endsWith('/')\n if (isIndexRoute) {\n return fullPath\n }\n\n return fullPath.replace(/\\/$/, '')\n}\n\nconst shouldPreferIndexRoute = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n return existing.cleanedPath === '/' && current.cleanedPath !== '/'\n}\n\nconst isIndexRouteNode = (routeNode: RouteNode): boolean => {\n return routeNode.routePath?.endsWith('/') ?? false\n}\n\nconst isPathlessRouteNode = (routeNode: RouteNode): boolean => {\n return routeNode._fsRouteType === 'pathless_layout'\n}\n\nconst shouldReplaceRouteNodeForTo = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n const currentIsIndex = isIndexRouteNode(current)\n const existingIsIndex = isIndexRouteNode(existing)\n if (currentIsIndex !== existingIsIndex) {\n return currentIsIndex\n }\n\n const currentIsPathless = isPathlessRouteNode(current)\n const existingIsPathless = isPathlessRouteNode(existing)\n if (currentIsPathless !== existingIsPathless) {\n return !currentIsPathless\n }\n\n return true\n}\n\nconst shouldReplaceRouteNodeForFullPath = (\n current: RouteNode,\n existing: RouteNode,\n): boolean => {\n const currentIsPathless = isPathlessRouteNode(current)\n const existingIsPathless = isPathlessRouteNode(existing)\n if (currentIsPathless !== existingIsPathless) {\n return !currentIsPathless\n }\n\n return true\n}\n\n/**\n * Creates a map from fullPath to routeNode\n */\nexport const createRouteNodesByFullPath = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n const map = new Map<string, RouteNode>()\n\n for (const routeNode of routeNodes) {\n const fullPath = inferFullPath(routeNode)\n\n if (fullPath === '/' && map.has('/')) {\n const existing = map.get('/')!\n if (shouldPreferIndexRoute(routeNode, existing)) {\n continue\n }\n }\n\n const existing = map.get(fullPath)\n if (existing && !shouldReplaceRouteNodeForFullPath(routeNode, existing)) {\n continue\n }\n\n map.set(fullPath, routeNode)\n }\n\n return map\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 const map = new Map<string, RouteNode>()\n\n for (const routeNode of dedupeBranchesAndIndexRoutes(routeNodes)) {\n const to = inferTo(routeNode)\n\n const existing = map.get(to)\n if (existing && !shouldReplaceRouteNodeForTo(routeNode, existing)) {\n continue\n }\n\n map.set(to, routeNode)\n }\n\n return map\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 */\nconst 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 */\nconst 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 emptyPathRoutes = _routes.filter((d) => d.routePath === '')\n if (emptyPathRoutes.length) {\n const errorMessage = `Invalid route path \"\" was found. Root routes must be defined via __root.tsx (createRootRoute), not createFileRoute('') or a route file that resolves to an empty path.\nConflicting files: \\n ${emptyPathRoutes\n .map((d) => path.resolve(config.routesDirectory, d.filePath))\n .join('\\n ')}\\n`\n throw new Error(errorMessage)\n }\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 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\nfunction 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"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/router-generator",
|
|
3
|
-
"version": "1.167.
|
|
3
|
+
"version": "1.167.22-pre.0",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,26 +54,26 @@
|
|
|
54
54
|
"magic-string": "^0.30.21",
|
|
55
55
|
"prettier": "^3.5.0",
|
|
56
56
|
"zod": "^4.4.3",
|
|
57
|
-
"@tanstack/router-core": "1.171.
|
|
57
|
+
"@tanstack/router-core": "1.171.16-pre.0",
|
|
58
58
|
"@tanstack/router-utils": "1.162.2",
|
|
59
59
|
"@tanstack/virtual-file-routes": "1.162.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@types/node": ">=20",
|
|
63
63
|
"vite": "*",
|
|
64
|
-
"@tanstack/react-router": "1.170.
|
|
64
|
+
"@tanstack/react-router": "1.170.19-pre.0"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"clean": "rimraf ./dist && rimraf ./coverage",
|
|
68
68
|
"clean:snapshots": "rimraf **/*snapshot* --glob",
|
|
69
69
|
"test:eslint": "eslint ./src",
|
|
70
70
|
"test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"",
|
|
71
|
-
"test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js -p tsconfig.legacy.json",
|
|
72
71
|
"test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js -p tsconfig.legacy.json",
|
|
73
72
|
"test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js -p tsconfig.legacy.json",
|
|
74
73
|
"test:types:ts58": "node ../../node_modules/typescript58/lib/tsc.js -p tsconfig.legacy.json",
|
|
75
74
|
"test:types:ts59": "node ../../node_modules/typescript59/lib/tsc.js -p tsconfig.legacy.json",
|
|
76
|
-
"test:types:ts60": "
|
|
75
|
+
"test:types:ts60": "tsc6 -p tsconfig.legacy.json",
|
|
76
|
+
"test:types:ts70": "tsc -p tsconfig.legacy.json",
|
|
77
77
|
"test:unit": "vitest --typecheck false && vitest run --typecheck.only",
|
|
78
78
|
"test:unit:dev": "pnpm run test:unit --watch --hideSkippedTests",
|
|
79
79
|
"test:build": "publint --strict && attw --ignore-rules no-resolution --pack .",
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
cleanPath,
|
|
4
4
|
createLiteralRoutePathSegmentMetadata,
|
|
5
5
|
createRoutePathSegmentMetadata,
|
|
6
|
-
|
|
6
|
+
determineInitialRoutePathFromExplicitPath,
|
|
7
7
|
joinRoutePathSegmentMetadata,
|
|
8
8
|
removeExt,
|
|
9
9
|
removeLeadingSlash,
|
|
@@ -156,7 +156,9 @@ export async function getRouteNodesRecursive(
|
|
|
156
156
|
routePath: routePathPrefix,
|
|
157
157
|
originalRoutePath: originalRoutePathPrefix,
|
|
158
158
|
} = node.pathPrefix
|
|
159
|
-
?
|
|
159
|
+
? determineInitialRoutePathFromExplicitPath(
|
|
160
|
+
removeLeadingSlash(node.pathPrefix),
|
|
161
|
+
)
|
|
160
162
|
: { routePath: '', originalRoutePath: '' }
|
|
161
163
|
const { routeNodes, physicalDirectories } = await getRouteNodesPhysical(
|
|
162
164
|
{
|
|
@@ -240,7 +242,9 @@ export async function getRouteNodesRecursive(
|
|
|
240
242
|
const {
|
|
241
243
|
routePath: escapedSegment,
|
|
242
244
|
originalRoutePath: originalSegment,
|
|
243
|
-
} =
|
|
245
|
+
} = determineInitialRoutePathFromExplicitPath(
|
|
246
|
+
removeLeadingSlash(lastSegment),
|
|
247
|
+
)
|
|
244
248
|
const routePath = `${parentRoutePath}${escapedSegment}`
|
|
245
249
|
const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`
|
|
246
250
|
const routePathSegmentMetadata =
|
|
@@ -305,7 +309,9 @@ export async function getRouteNodesRecursive(
|
|
|
305
309
|
const {
|
|
306
310
|
routePath: escapedSegment,
|
|
307
311
|
originalRoutePath: originalSegment,
|
|
308
|
-
} =
|
|
312
|
+
} = determineInitialRoutePathFromExplicitPath(
|
|
313
|
+
removeLeadingSlash(lastSegment),
|
|
314
|
+
)
|
|
309
315
|
const routePath = `${parentRoutePath}${escapedSegment}`
|
|
310
316
|
// Store the original path with brackets for escape detection
|
|
311
317
|
const originalRoutePath = `${parentOriginalRoutePath}${originalSegment}`
|
package/src/utils.ts
CHANGED
|
@@ -186,13 +186,12 @@ const DISALLOWED_ESCAPE_CHARS = new Set([
|
|
|
186
186
|
'%',
|
|
187
187
|
])
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
function determineInitialRoutePathFromParts(
|
|
190
|
+
routePath: string,
|
|
191
|
+
parts: Array<string>,
|
|
192
|
+
) {
|
|
190
193
|
const originalRoutePath =
|
|
191
|
-
cleanPath(
|
|
192
|
-
`/${(cleanPath(routePath) || '').split(SPLIT_REGEX).join('/')}`,
|
|
193
|
-
) || ''
|
|
194
|
-
|
|
195
|
-
const parts = routePath.split(SPLIT_REGEX)
|
|
194
|
+
cleanPath(`/${cleanPath(parts.join('/')) || ''}`) || ''
|
|
196
195
|
|
|
197
196
|
// Escape any characters that in square brackets
|
|
198
197
|
// we keep the original path untouched
|
|
@@ -231,6 +230,21 @@ export function determineInitialRoutePath(routePath: string) {
|
|
|
231
230
|
}
|
|
232
231
|
}
|
|
233
232
|
|
|
233
|
+
export function determineInitialRoutePath(routePath: string) {
|
|
234
|
+
return determineInitialRoutePathFromParts(
|
|
235
|
+
routePath,
|
|
236
|
+
routePath.split(SPLIT_REGEX),
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Resolves bracket escapes in an explicit route path or ID without applying
|
|
242
|
+
* the dot-delimited flat-file route convention.
|
|
243
|
+
*/
|
|
244
|
+
export function determineInitialRoutePathFromExplicitPath(routePath: string) {
|
|
245
|
+
return determineInitialRoutePathFromParts(routePath, [routePath])
|
|
246
|
+
}
|
|
247
|
+
|
|
234
248
|
/**
|
|
235
249
|
* Checks if a segment is fully escaped (entirely wrapped in brackets with no nested brackets).
|
|
236
250
|
* E.g., "[index]" -> true, "[_layout]" -> true, "foo[.]bar" -> false, "index" -> false
|