@tanstack/router-generator
Advanced tools
Comparing version 1.52.0 to 1.54.0
import { z } from 'zod'; | ||
export declare const configSchema: z.ZodObject<{ | ||
virtualRouteConfig: z.ZodOptional<z.ZodType<import('@tanstack/virtual-file-routes').VirtualRootRoute, z.ZodTypeDef, import('@tanstack/virtual-file-routes').VirtualRootRoute>>; | ||
routeFilePrefix: z.ZodOptional<z.ZodString>; | ||
@@ -42,2 +43,3 @@ routeFileIgnorePrefix: z.ZodDefault<z.ZodOptional<z.ZodString>>; | ||
routeToken: string; | ||
virtualRouteConfig?: import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined; | ||
routeFilePrefix?: string | undefined; | ||
@@ -50,2 +52,3 @@ routeFileIgnorePattern?: string | undefined; | ||
}, { | ||
virtualRouteConfig?: import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined; | ||
routeFilePrefix?: string | undefined; | ||
@@ -52,0 +55,0 @@ routeFileIgnorePrefix?: string | undefined; |
import path from "node:path"; | ||
import { existsSync, readFileSync } from "node:fs"; | ||
import { z } from "zod"; | ||
import { virtualRootRouteSchema } from "./filesystem/virtual/config.js"; | ||
const configSchema = z.object({ | ||
virtualRouteConfig: virtualRootRouteSchema.optional(), | ||
routeFilePrefix: z.string().optional(), | ||
@@ -6,0 +8,0 @@ routeFileIgnorePrefix: z.string().optional().default("-"), |
@@ -0,29 +1,4 @@ | ||
import { RouteNode } from './types.js'; | ||
import { Config } from './config.js'; | ||
export declare const rootPathId = "__root"; | ||
export type RouteNode = { | ||
filePath: string; | ||
fullPath: string; | ||
variableName: string; | ||
routePath?: string; | ||
cleanedPath?: string; | ||
path?: string; | ||
isNonPath?: boolean; | ||
isNonLayout?: boolean; | ||
isLayout?: boolean; | ||
isVirtualParentRequired?: boolean; | ||
isVirtualParentRoute?: boolean; | ||
isRoute?: boolean; | ||
isAPIRoute?: boolean; | ||
isLoader?: boolean; | ||
isComponent?: boolean; | ||
isErrorComponent?: boolean; | ||
isPendingComponent?: boolean; | ||
isVirtual?: boolean; | ||
isLazy?: boolean; | ||
isRoot?: boolean; | ||
children?: Array<RouteNode>; | ||
parent?: RouteNode; | ||
}; | ||
export declare function generator(config: Config): Promise<void>; | ||
export declare function removeExt(d: string, keepExtension?: boolean): string; | ||
export declare function multiSortBy<T>(arr: Array<T>, accessors?: Array<(item: T) => any>): Array<T>; | ||
@@ -30,0 +5,0 @@ /** |
@@ -5,106 +5,9 @@ import path from "node:path"; | ||
import * as prettier from "prettier"; | ||
import { logging, trimPathLeft, cleanPath } from "./utils.js"; | ||
import { logging, replaceBackslash, removeExt, removeUnderscores, removeTrailingSlash, determineInitialRoutePath, trimPathLeft, routePathToVariable } from "./utils.js"; | ||
import { getRouteNodes as getRouteNodes$1 } from "./filesystem/physical/getRouteNodes.js"; | ||
import { getRouteNodes } from "./filesystem/virtual/getRouteNodes.js"; | ||
import { rootPathId } from "./filesystem/physical/rootPathId.js"; | ||
let latestTask = 0; | ||
const rootPathId = "__root"; | ||
const routeGroupPatternRegex = /\(.+\)/g; | ||
const possiblyNestedRouteGroupPatternRegex = /\([^/]+\)\/?/g; | ||
const disallowedRouteGroupConfiguration = /\(([^)]+)\).(ts|js|tsx|jsx)/; | ||
async function getRouteNodes(config) { | ||
const { routeFilePrefix, routeFileIgnorePrefix, routeFileIgnorePattern } = config; | ||
const logger = logging({ disabled: config.disableLogging }); | ||
const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? "", "g"); | ||
const routeNodes = []; | ||
async function recurse(dir) { | ||
const fullDir = path.resolve(config.routesDirectory, dir); | ||
let dirList = await fsp.readdir(fullDir, { withFileTypes: true }); | ||
dirList = dirList.filter((d) => { | ||
if (d.name.startsWith(".") || routeFileIgnorePrefix && d.name.startsWith(routeFileIgnorePrefix)) { | ||
return false; | ||
} | ||
if (routeFilePrefix) { | ||
return d.name.startsWith(routeFilePrefix); | ||
} | ||
if (routeFileIgnorePattern) { | ||
return !d.name.match(routeFileIgnoreRegExp); | ||
} | ||
return true; | ||
}); | ||
await Promise.all( | ||
dirList.map(async (dirent) => { | ||
const fullPath = path.join(fullDir, dirent.name); | ||
const relativePath = path.join(dir, dirent.name); | ||
if (dirent.isDirectory()) { | ||
await recurse(relativePath); | ||
} else if (fullPath.match(/\.(tsx|ts|jsx|js)$/)) { | ||
const filePath = replaceBackslash(path.join(dir, dirent.name)); | ||
const filePathNoExt = removeExt(filePath); | ||
let routePath = determineInitialRoutePath(filePathNoExt); | ||
if (routeFilePrefix) { | ||
routePath = routePath.replaceAll(routeFilePrefix, ""); | ||
} | ||
if (disallowedRouteGroupConfiguration.test(dirent.name)) { | ||
const errorMessage = `A route configuration for a route group was found at \`${filePath}\`. This is not supported. Did you mean to use a layout/pathless route instead?`; | ||
logger.error(`ERROR: ${errorMessage}`); | ||
throw new Error(errorMessage); | ||
} | ||
const variableName = routePathToVariable(routePath); | ||
const isLazy = routePath.endsWith("/lazy"); | ||
if (isLazy) { | ||
routePath = routePath.replace(/\/lazy$/, ""); | ||
} | ||
const isRoute = routePath.endsWith(`/${config.routeToken}`); | ||
const isComponent = routePath.endsWith("/component"); | ||
const isErrorComponent = routePath.endsWith("/errorComponent"); | ||
const isPendingComponent = routePath.endsWith("/pendingComponent"); | ||
const isLoader = routePath.endsWith("/loader"); | ||
const isAPIRoute = routePath.startsWith( | ||
`${removeTrailingSlash(config.apiBase)}/` | ||
); | ||
const segments = routePath.split("/"); | ||
const lastRouteSegment = segments[segments.length - 1]; | ||
const isLayout = lastRouteSegment !== config.indexToken && lastRouteSegment !== config.routeToken && (lastRouteSegment == null ? void 0 : lastRouteSegment.startsWith("_")) || false; | ||
[ | ||
[isComponent, "component"], | ||
[isErrorComponent, "errorComponent"], | ||
[isPendingComponent, "pendingComponent"], | ||
[isLoader, "loader"] | ||
].forEach(([isType, type]) => { | ||
if (isType) { | ||
logger.warn( | ||
`WARNING: The \`.${type}.tsx\` suffix used for the ${filePath} file is deprecated. Use the new \`.lazy.tsx\` suffix instead.` | ||
); | ||
} | ||
}); | ||
routePath = routePath.replace( | ||
new RegExp( | ||
`/(component|errorComponent|pendingComponent|loader|${config.routeToken}|lazy)$` | ||
), | ||
"" | ||
); | ||
if (routePath === config.indexToken) { | ||
routePath = "/"; | ||
} | ||
routePath = routePath.replace(new RegExp(`/${config.indexToken}$`), "/") || "/"; | ||
routeNodes.push({ | ||
filePath, | ||
fullPath, | ||
routePath, | ||
variableName, | ||
isRoute, | ||
isComponent, | ||
isErrorComponent, | ||
isPendingComponent, | ||
isLoader, | ||
isLazy, | ||
isLayout, | ||
isAPIRoute | ||
}); | ||
} | ||
}) | ||
); | ||
return routeNodes; | ||
} | ||
await recurse("./"); | ||
return routeNodes; | ||
} | ||
let isFirst = false; | ||
@@ -138,7 +41,12 @@ let skipMessage = false; | ||
}; | ||
const routePathIdPrefix = config.routeFilePrefix ?? ""; | ||
const beforeRouteNodes = await getRouteNodes(config); | ||
const rootRouteNode = beforeRouteNodes.find( | ||
(d) => d.routePath === `/${rootPathId}` | ||
); | ||
let getRouteNodesResult; | ||
if (config.virtualRouteConfig) { | ||
getRouteNodesResult = await getRouteNodes(config); | ||
} else { | ||
getRouteNodesResult = await getRouteNodes$1(config); | ||
} | ||
const { rootRouteNode, routeNodes: beforeRouteNodes } = getRouteNodesResult; | ||
if (rootRouteNode === void 0) { | ||
throw new Error(`rootRouteNode must not be undefined`); | ||
} | ||
const preRouteNodes = multiSortBy(beforeRouteNodes, [ | ||
@@ -208,6 +116,4 @@ (d) => d.routePath === "/" ? -1 : 1, | ||
const split = trimmedPath.split("/"); | ||
const first = split[0] ?? trimmedPath; | ||
const lastRouteSegment = split[split.length - 1] ?? trimmedPath; | ||
node.isNonPath = lastRouteSegment.startsWith("_") || routeGroupPatternRegex.test(lastRouteSegment); | ||
node.isNonLayout = first.endsWith("_"); | ||
node.cleanedPath = removeGroups( | ||
@@ -412,3 +318,13 @@ removeUnderscores(removeLayoutSegments(node.path)) ?? "" | ||
const virtualRouteNodes = sortedRouteNodes.filter((d) => d.isVirtual); | ||
const rootPathIdExtension = config.addExtensions && rootRouteNode ? path.extname(rootRouteNode.filePath) : ""; | ||
function getImportPath(node) { | ||
return replaceBackslash( | ||
removeExt( | ||
path.relative( | ||
path.dirname(config.generatedRouteTree), | ||
path.resolve(config.routesDirectory, node.filePath) | ||
), | ||
config.addExtensions | ||
) | ||
); | ||
} | ||
const routeImports = [ | ||
@@ -421,21 +337,5 @@ ...config.routeTreeFileHeader, | ||
[ | ||
`import { Route as rootRoute } from './${replaceBackslash( | ||
path.relative( | ||
path.dirname(config.generatedRouteTree), | ||
path.resolve( | ||
config.routesDirectory, | ||
`${routePathIdPrefix}${rootPathId}${rootPathIdExtension}` | ||
) | ||
) | ||
)}'`, | ||
`import { Route as rootRoute } from './${getImportPath(rootRouteNode)}'`, | ||
...sortedRouteNodes.filter((d) => !d.isVirtual).map((node) => { | ||
return `import { Route as ${node.variableName}Import } from './${replaceBackslash( | ||
removeExt( | ||
path.relative( | ||
path.dirname(config.generatedRouteTree), | ||
path.resolve(config.routesDirectory, node.filePath) | ||
), | ||
config.addExtensions | ||
) | ||
)}'`; | ||
return `import { Route as ${node.variableName}Import } from './${getImportPath(node)}'`; | ||
}) | ||
@@ -531,3 +431,3 @@ ].join("\n"), | ||
__root__: { | ||
filePath: rootRouteNode == null ? void 0 : rootRouteNode.filePath, | ||
filePath: rootRouteNode.filePath, | ||
children: routeTree.map( | ||
@@ -595,9 +495,2 @@ (d) => getFilePathIdAndRouteIdFromPath(d.routePath)[1] | ||
} | ||
function routePathToVariable(routePath) { | ||
var _a; | ||
return ((_a = removeUnderscores(routePath)) == null ? void 0 : _a.replace(/\/\$\//g, "/splat/").replace(/\$$/g, "splat").replace(/\$/g, "").split(/[/-]/g).map((d, i) => i > 0 ? capitalize(d) : d).join("").replace(/([^a-zA-Z0-9]|[.])/gm, "").replace(/^(\d)/g, "R$1")) ?? ""; | ||
} | ||
function removeExt(d, keepExtension = false) { | ||
return keepExtension ? d : d.substring(0, d.lastIndexOf(".")) || d; | ||
} | ||
function spaces(d) { | ||
@@ -625,27 +518,11 @@ return Array.from({ length: d }).map(() => " ").join(""); | ||
} | ||
function capitalize(s) { | ||
if (typeof s !== "string") return ""; | ||
return s.charAt(0).toUpperCase() + s.slice(1); | ||
} | ||
function removeUnderscores(s) { | ||
return s == null ? void 0 : s.replaceAll(/(^_|_$)/gi, "").replaceAll(/(\/_|_\/)/gi, "/"); | ||
} | ||
function removeTrailingUnderscores(s) { | ||
return s == null ? void 0 : s.replaceAll(/(_$)/gi, "").replaceAll(/(_\/)/gi, "/"); | ||
} | ||
function replaceBackslash(s) { | ||
return s.replaceAll(/\\/gi, "/"); | ||
} | ||
function removeGroups(s) { | ||
return s.replace(possiblyNestedRouteGroupPatternRegex, ""); | ||
} | ||
function removeTrailingSlash(s) { | ||
return s.replace(/\/$/, ""); | ||
} | ||
function determineInitialRoutePath(routePath) { | ||
return cleanPath(`/${routePath.split(".").join("/")}`) || ""; | ||
} | ||
function determineNodePath(node) { | ||
var _a; | ||
return node.path = node.parent ? ((_a = node.routePath) == null ? void 0 : _a.replace(node.parent.routePath, "")) || "/" : node.routePath; | ||
return node.path = node.parent ? ((_a = node.routePath) == null ? void 0 : _a.replace(node.parent.routePath ?? "", "")) || "/" : node.routePath; | ||
} | ||
@@ -741,7 +618,5 @@ function removeLastSegmentFromPath(routePath = "/") { | ||
multiSortBy, | ||
removeExt, | ||
removeLastSegmentFromPath, | ||
rootPathId, | ||
startAPIRouteSegmentsFromTSRFilePath | ||
}; | ||
//# sourceMappingURL=generator.js.map |
@@ -12,1 +12,9 @@ export declare function cleanPath(path: string): string; | ||
}; | ||
export declare function removeLeadingSlash(path: string): string; | ||
export declare function removeTrailingSlash(s: string): string; | ||
export declare function determineInitialRoutePath(routePath: string): string; | ||
export declare function replaceBackslash(s: string): string; | ||
export declare function routePathToVariable(routePath: string): string; | ||
export declare function removeUnderscores(s?: string): string | undefined; | ||
export declare function capitalize(s: string): string; | ||
export declare function removeExt(d: string, keepExtension?: boolean): string; |
@@ -26,7 +26,41 @@ function cleanPath(path) { | ||
} | ||
function removeLeadingSlash(path) { | ||
return path.replace(/^\//, ""); | ||
} | ||
function removeTrailingSlash(s) { | ||
return s.replace(/\/$/, ""); | ||
} | ||
function determineInitialRoutePath(routePath) { | ||
return cleanPath(`/${routePath.split(".").join("/")}`) || ""; | ||
} | ||
function replaceBackslash(s) { | ||
return s.replaceAll(/\\/gi, "/"); | ||
} | ||
function routePathToVariable(routePath) { | ||
var _a; | ||
return ((_a = removeUnderscores(routePath)) == null ? void 0 : _a.replace(/\/\$\//g, "/splat/").replace(/\$$/g, "splat").replace(/\$/g, "").split(/[/-]/g).map((d, i) => i > 0 ? capitalize(d) : d).join("").replace(/([^a-zA-Z0-9]|[.])/gm, "").replace(/^(\d)/g, "R$1")) ?? ""; | ||
} | ||
function removeUnderscores(s) { | ||
return s == null ? void 0 : s.replaceAll(/(^_|_$)/gi, "").replaceAll(/(\/_|_\/)/gi, "/"); | ||
} | ||
function capitalize(s) { | ||
if (typeof s !== "string") return ""; | ||
return s.charAt(0).toUpperCase() + s.slice(1); | ||
} | ||
function removeExt(d, keepExtension = false) { | ||
return keepExtension ? d : d.substring(0, d.lastIndexOf(".")) || d; | ||
} | ||
export { | ||
capitalize, | ||
cleanPath, | ||
determineInitialRoutePath, | ||
logging, | ||
removeExt, | ||
removeLeadingSlash, | ||
removeTrailingSlash, | ||
removeUnderscores, | ||
replaceBackslash, | ||
routePathToVariable, | ||
trimPathLeft | ||
}; | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "@tanstack/router-generator", | ||
"version": "1.52.0", | ||
"version": "1.54.0", | ||
"description": "Modern and scalable routing for React applications", | ||
@@ -53,5 +53,6 @@ "author": "Tanner Linsley", | ||
"prettier": "^3.3.3", | ||
"zod": "^3.23.8" | ||
"zod": "^3.23.8", | ||
"@tanstack/virtual-file-routes": "^1.52.5" | ||
}, | ||
"scripts": {} | ||
} |
import path from 'node:path' | ||
import { existsSync, readFileSync } from 'node:fs' | ||
import { z } from 'zod' | ||
import { virtualRootRouteSchema } from './filesystem/virtual/config' | ||
export const configSchema = z.object({ | ||
virtualRouteConfig: virtualRootRouteSchema.optional(), | ||
routeFilePrefix: z.string().optional(), | ||
@@ -7,0 +9,0 @@ routeFileIgnorePrefix: z.string().optional().default('-'), |
@@ -5,172 +5,22 @@ import path from 'node:path' | ||
import * as prettier from 'prettier' | ||
import { cleanPath, logging, trimPathLeft } from './utils' | ||
import { | ||
determineInitialRoutePath, | ||
logging, | ||
removeExt, | ||
removeTrailingSlash, | ||
removeUnderscores, | ||
replaceBackslash, | ||
routePathToVariable, | ||
trimPathLeft, | ||
} from './utils' | ||
import { getRouteNodes as physicalGetRouteNodes } from './filesystem/physical/getRouteNodes' | ||
import { getRouteNodes as virtualGetRouteNodes } from './filesystem/virtual/getRouteNodes' | ||
import { rootPathId } from './filesystem/physical/rootPathId' | ||
import type { GetRouteNodesResult, RouteNode } from './types' | ||
import type { Config } from './config' | ||
let latestTask = 0 | ||
export const rootPathId = '__root' | ||
const routeGroupPatternRegex = /\(.+\)/g | ||
const possiblyNestedRouteGroupPatternRegex = /\([^/]+\)\/?/g | ||
const disallowedRouteGroupConfiguration = /\(([^)]+)\).(ts|js|tsx|jsx)/ | ||
export type RouteNode = { | ||
filePath: string | ||
fullPath: string | ||
variableName: string | ||
routePath?: string | ||
cleanedPath?: string | ||
path?: string | ||
isNonPath?: boolean | ||
isNonLayout?: boolean | ||
isLayout?: boolean | ||
isVirtualParentRequired?: boolean | ||
isVirtualParentRoute?: boolean | ||
isRoute?: boolean | ||
isAPIRoute?: boolean | ||
isLoader?: boolean | ||
isComponent?: boolean | ||
isErrorComponent?: boolean | ||
isPendingComponent?: boolean | ||
isVirtual?: boolean | ||
isLazy?: boolean | ||
isRoot?: boolean | ||
children?: Array<RouteNode> | ||
parent?: RouteNode | ||
} | ||
async function getRouteNodes(config: Config) { | ||
const { routeFilePrefix, routeFileIgnorePrefix, routeFileIgnorePattern } = | ||
config | ||
const logger = logging({ disabled: config.disableLogging }) | ||
const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? '', 'g') | ||
const routeNodes: Array<RouteNode> = [] | ||
async function recurse(dir: string) { | ||
const fullDir = path.resolve(config.routesDirectory, dir) | ||
let dirList = await fsp.readdir(fullDir, { withFileTypes: true }) | ||
dirList = dirList.filter((d) => { | ||
if ( | ||
d.name.startsWith('.') || | ||
(routeFileIgnorePrefix && d.name.startsWith(routeFileIgnorePrefix)) | ||
) { | ||
return false | ||
} | ||
if (routeFilePrefix) { | ||
return d.name.startsWith(routeFilePrefix) | ||
} | ||
if (routeFileIgnorePattern) { | ||
return !d.name.match(routeFileIgnoreRegExp) | ||
} | ||
return true | ||
}) | ||
await Promise.all( | ||
dirList.map(async (dirent) => { | ||
const fullPath = path.join(fullDir, dirent.name) | ||
const relativePath = path.join(dir, dirent.name) | ||
if (dirent.isDirectory()) { | ||
await recurse(relativePath) | ||
} else if (fullPath.match(/\.(tsx|ts|jsx|js)$/)) { | ||
const filePath = replaceBackslash(path.join(dir, dirent.name)) | ||
const filePathNoExt = removeExt(filePath) | ||
let routePath = determineInitialRoutePath(filePathNoExt) | ||
if (routeFilePrefix) { | ||
routePath = routePath.replaceAll(routeFilePrefix, '') | ||
} | ||
if (disallowedRouteGroupConfiguration.test(dirent.name)) { | ||
const errorMessage = `A route configuration for a route group was found at \`${filePath}\`. This is not supported. Did you mean to use a layout/pathless route instead?` | ||
logger.error(`ERROR: ${errorMessage}`) | ||
throw new Error(errorMessage) | ||
} | ||
const variableName = routePathToVariable(routePath) | ||
// Remove the index from the route path and | ||
// if the route path is empty, use `/' | ||
const isLazy = routePath.endsWith('/lazy') | ||
if (isLazy) { | ||
routePath = routePath.replace(/\/lazy$/, '') | ||
} | ||
const isRoute = routePath.endsWith(`/${config.routeToken}`) | ||
const isComponent = routePath.endsWith('/component') | ||
const isErrorComponent = routePath.endsWith('/errorComponent') | ||
const isPendingComponent = routePath.endsWith('/pendingComponent') | ||
const isLoader = routePath.endsWith('/loader') | ||
const isAPIRoute = routePath.startsWith( | ||
`${removeTrailingSlash(config.apiBase)}/`, | ||
) | ||
const segments = routePath.split('/') | ||
const lastRouteSegment = segments[segments.length - 1] | ||
const isLayout = | ||
(lastRouteSegment !== config.indexToken && | ||
lastRouteSegment !== config.routeToken && | ||
lastRouteSegment?.startsWith('_')) || | ||
false | ||
;( | ||
[ | ||
[isComponent, 'component'], | ||
[isErrorComponent, 'errorComponent'], | ||
[isPendingComponent, 'pendingComponent'], | ||
[isLoader, 'loader'], | ||
] as const | ||
).forEach(([isType, type]) => { | ||
if (isType) { | ||
logger.warn( | ||
`WARNING: The \`.${type}.tsx\` suffix used for the ${filePath} file is deprecated. Use the new \`.lazy.tsx\` suffix instead.`, | ||
) | ||
} | ||
}) | ||
routePath = routePath.replace( | ||
new RegExp( | ||
`/(component|errorComponent|pendingComponent|loader|${config.routeToken}|lazy)$`, | ||
), | ||
'', | ||
) | ||
if (routePath === config.indexToken) { | ||
routePath = '/' | ||
} | ||
routePath = | ||
routePath.replace(new RegExp(`/${config.indexToken}$`), '/') || '/' | ||
routeNodes.push({ | ||
filePath, | ||
fullPath, | ||
routePath, | ||
variableName, | ||
isRoute, | ||
isComponent, | ||
isErrorComponent, | ||
isPendingComponent, | ||
isLoader, | ||
isLazy, | ||
isLayout, | ||
isAPIRoute, | ||
}) | ||
} | ||
}), | ||
) | ||
return routeNodes | ||
} | ||
await recurse('./') | ||
return routeNodes | ||
} | ||
let isFirst = false | ||
@@ -220,8 +70,14 @@ let skipMessage = false | ||
const routePathIdPrefix = config.routeFilePrefix ?? '' | ||
const beforeRouteNodes = await getRouteNodes(config) | ||
const rootRouteNode = beforeRouteNodes.find( | ||
(d) => d.routePath === `/${rootPathId}`, | ||
) | ||
let getRouteNodesResult: GetRouteNodesResult | ||
if (config.virtualRouteConfig) { | ||
getRouteNodesResult = await virtualGetRouteNodes(config) | ||
} else { | ||
getRouteNodesResult = await physicalGetRouteNodes(config) | ||
} | ||
const { rootRouteNode, routeNodes: beforeRouteNodes } = getRouteNodesResult | ||
if (rootRouteNode === undefined) { | ||
throw new Error(`rootRouteNode must not be undefined`) | ||
} | ||
const preRouteNodes = multiSortBy(beforeRouteNodes, [ | ||
@@ -312,3 +168,2 @@ (d) => (d.routePath === '/' ? -1 : 1), | ||
const split = trimmedPath.split('/') | ||
const first = split[0] ?? trimmedPath | ||
const lastRouteSegment = split[split.length - 1] ?? trimmedPath | ||
@@ -319,3 +174,2 @@ | ||
routeGroupPatternRegex.test(lastRouteSegment) | ||
node.isNonLayout = first.endsWith('_') | ||
@@ -578,7 +432,14 @@ node.cleanedPath = removeGroups( | ||
const virtualRouteNodes = sortedRouteNodes.filter((d) => d.isVirtual) | ||
const rootPathIdExtension = | ||
config.addExtensions && rootRouteNode | ||
? path.extname(rootRouteNode.filePath) | ||
: '' | ||
function getImportPath(node: RouteNode) { | ||
return replaceBackslash( | ||
removeExt( | ||
path.relative( | ||
path.dirname(config.generatedRouteTree), | ||
path.resolve(config.routesDirectory, node.filePath), | ||
), | ||
config.addExtensions, | ||
), | ||
) | ||
} | ||
const routeImports = [ | ||
@@ -592,11 +453,3 @@ ...config.routeTreeFileHeader, | ||
[ | ||
`import { Route as rootRoute } from './${replaceBackslash( | ||
path.relative( | ||
path.dirname(config.generatedRouteTree), | ||
path.resolve( | ||
config.routesDirectory, | ||
`${routePathIdPrefix}${rootPathId}${rootPathIdExtension}`, | ||
), | ||
), | ||
)}'`, | ||
`import { Route as rootRoute } from './${getImportPath(rootRouteNode)}'`, | ||
...sortedRouteNodes | ||
@@ -607,11 +460,3 @@ .filter((d) => !d.isVirtual) | ||
node.variableName | ||
}Import } from './${replaceBackslash( | ||
removeExt( | ||
path.relative( | ||
path.dirname(config.generatedRouteTree), | ||
path.resolve(config.routesDirectory, node.filePath), | ||
), | ||
config.addExtensions, | ||
), | ||
)}'` | ||
}Import } from './${getImportPath(node)}'` | ||
}), | ||
@@ -714,3 +559,3 @@ ].join('\n'), | ||
const [filePathId, routeId] = getFilePathIdAndRouteIdFromPath( | ||
routeNode.routePath!, | ||
routeNode.routePath, | ||
) | ||
@@ -746,5 +591,5 @@ | ||
__root__: { | ||
filePath: rootRouteNode?.filePath, | ||
filePath: rootRouteNode.filePath, | ||
children: routeTree.map( | ||
(d) => getFilePathIdAndRouteIdFromPath(d.routePath!)[1], | ||
(d) => getFilePathIdAndRouteIdFromPath(d.routePath)[1], | ||
), | ||
@@ -754,3 +599,3 @@ }, | ||
routeNodes.map((d) => { | ||
const [_, routeId] = getFilePathIdAndRouteIdFromPath(d.routePath!) | ||
const [_, routeId] = getFilePathIdAndRouteIdFromPath(d.routePath) | ||
@@ -766,3 +611,3 @@ return [ | ||
(childRoute) => | ||
getFilePathIdAndRouteIdFromPath(childRoute.routePath!)[1], | ||
getFilePathIdAndRouteIdFromPath(childRoute.routePath)[1], | ||
), | ||
@@ -834,20 +679,2 @@ }, | ||
function routePathToVariable(routePath: string): string { | ||
return ( | ||
removeUnderscores(routePath) | ||
?.replace(/\/\$\//g, '/splat/') | ||
.replace(/\$$/g, 'splat') | ||
.replace(/\$/g, '') | ||
.split(/[/-]/g) | ||
.map((d, i) => (i > 0 ? capitalize(d) : d)) | ||
.join('') | ||
.replace(/([^a-zA-Z0-9]|[.])/gm, '') | ||
.replace(/^(\d)/g, 'R$1') ?? '' | ||
) | ||
} | ||
export function removeExt(d: string, keepExtension: boolean = false) { | ||
return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d | ||
} | ||
function spaces(d: number): string { | ||
@@ -889,11 +716,2 @@ return Array.from({ length: d }) | ||
function capitalize(s: string) { | ||
if (typeof s !== 'string') return '' | ||
return s.charAt(0).toUpperCase() + s.slice(1) | ||
} | ||
function removeUnderscores(s?: string) { | ||
return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\/_|_\/)/gi, '/') | ||
} | ||
function removeTrailingUnderscores(s?: string) { | ||
@@ -903,6 +721,2 @@ return s?.replaceAll(/(_$)/gi, '').replaceAll(/(_\/)/gi, '/') | ||
function replaceBackslash(s: string) { | ||
return s.replaceAll(/\\/gi, '/') | ||
} | ||
function removeGroups(s: string) { | ||
@@ -912,10 +726,2 @@ return s.replace(possiblyNestedRouteGroupPatternRegex, '') | ||
function removeTrailingSlash(s: string) { | ||
return s.replace(/\/$/, '') | ||
} | ||
function determineInitialRoutePath(routePath: string) { | ||
return cleanPath(`/${routePath.split('.').join('/')}`) || '' | ||
} | ||
/** | ||
@@ -929,3 +735,3 @@ * The `node.path` is used as the `id` in the route definition. | ||
return (node.path = node.parent | ||
? node.routePath?.replace(node.parent.routePath!, '') || '/' | ||
? node.routePath?.replace(node.parent.routePath ?? '', '') || '/' | ||
: node.routePath) | ||
@@ -1014,3 +820,3 @@ } | ||
function getFilePathIdAndRouteIdFromPath(pathname: string) { | ||
function getFilePathIdAndRouteIdFromPath(pathname?: string) { | ||
const filePathId = removeTrailingUnderscores(pathname) | ||
@@ -1017,0 +823,0 @@ const id = removeGroups(filePathId ?? '') |
@@ -29,1 +29,44 @@ export function cleanPath(path: string) { | ||
} | ||
export function removeLeadingSlash(path: string): string { | ||
return path.replace(/^\//, '') | ||
} | ||
export function removeTrailingSlash(s: string) { | ||
return s.replace(/\/$/, '') | ||
} | ||
export function determineInitialRoutePath(routePath: string) { | ||
return cleanPath(`/${routePath.split('.').join('/')}`) || '' | ||
} | ||
export function replaceBackslash(s: string) { | ||
return s.replaceAll(/\\/gi, '/') | ||
} | ||
export function routePathToVariable(routePath: string): string { | ||
return ( | ||
removeUnderscores(routePath) | ||
?.replace(/\/\$\//g, '/splat/') | ||
.replace(/\$$/g, 'splat') | ||
.replace(/\$/g, '') | ||
.split(/[/-]/g) | ||
.map((d, i) => (i > 0 ? capitalize(d) : d)) | ||
.join('') | ||
.replace(/([^a-zA-Z0-9]|[.])/gm, '') | ||
.replace(/^(\d)/g, 'R$1') ?? '' | ||
) | ||
} | ||
export function removeUnderscores(s?: string) { | ||
return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\/_|_\/)/gi, '/') | ||
} | ||
export function capitalize(s: string) { | ||
if (typeof s !== 'string') return '' | ||
return s.charAt(0).toUpperCase() + s.slice(1) | ||
} | ||
export function removeExt(d: string, keepExtension: boolean = false) { | ||
return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
274044
61
3587
3
+ Added@tanstack/virtual-file-routes@1.64.0(transitive)