@tanstack/router-generator 1.139.14 → 1.140.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/config.cjs +1 -1
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/config.d.cts +6 -6
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs +32 -17
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs.map +1 -1
- package/dist/cjs/filesystem/physical/getRouteNodes.d.cts +1 -1
- package/dist/cjs/generator.cjs +141 -42
- package/dist/cjs/generator.cjs.map +1 -1
- package/dist/cjs/template.cjs +47 -0
- package/dist/cjs/template.cjs.map +1 -1
- package/dist/cjs/types.d.cts +2 -1
- package/dist/esm/config.d.ts +6 -6
- package/dist/esm/config.js +1 -1
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/filesystem/physical/getRouteNodes.d.ts +1 -1
- package/dist/esm/filesystem/physical/getRouteNodes.js +32 -17
- package/dist/esm/filesystem/physical/getRouteNodes.js.map +1 -1
- package/dist/esm/generator.js +141 -42
- package/dist/esm/generator.js.map +1 -1
- package/dist/esm/template.js +47 -0
- package/dist/esm/template.js.map +1 -1
- package/dist/esm/types.d.ts +2 -1
- package/package.json +6 -6
- package/src/config.ts +1 -1
- package/src/filesystem/physical/getRouteNodes.ts +42 -19
- package/src/generator.ts +208 -54
- package/src/template.ts +65 -0
- package/src/types.ts +2 -0
|
@@ -10,6 +10,6 @@ export declare function getRouteNodes(config: Pick<Config, 'routesDirectory' | '
|
|
|
10
10
|
* @returns An object containing the type of the route and the variable name derived from the route path.
|
|
11
11
|
*/
|
|
12
12
|
export declare function getRouteMeta(routePath: string, config: Pick<Config, 'routeToken' | 'indexToken'>): {
|
|
13
|
-
fsRouteType: Extract<FsRouteType, 'static' | 'layout' | 'api' | 'lazy' | 'loader' | 'component' | 'pendingComponent' | 'errorComponent'>;
|
|
13
|
+
fsRouteType: Extract<FsRouteType, 'static' | 'layout' | 'api' | 'lazy' | 'loader' | 'component' | 'pendingComponent' | 'errorComponent' | 'notFoundComponent'>;
|
|
14
14
|
variableName: string;
|
|
15
15
|
};
|
|
@@ -5,7 +5,7 @@ import { getRouteNodes as getRouteNodes$1 } from "../virtual/getRouteNodes.js";
|
|
|
5
5
|
import { loadConfigFile } from "../virtual/loadConfigFile.js";
|
|
6
6
|
import { logging } from "../../logger.js";
|
|
7
7
|
import { rootPathId } from "./rootPathId.js";
|
|
8
|
-
const disallowedRouteGroupConfiguration = /\(([^)]+)\).(ts|js|tsx|jsx)/;
|
|
8
|
+
const disallowedRouteGroupConfiguration = /\(([^)]+)\).(ts|js|tsx|jsx|vue)/;
|
|
9
9
|
const virtualConfigFileRegExp = /__virtual\.[mc]?[jt]s$/;
|
|
10
10
|
function isVirtualConfigFile(fileName) {
|
|
11
11
|
return virtualConfigFileRegExp.test(fileName);
|
|
@@ -79,7 +79,7 @@ async function getRouteNodes(config, root) {
|
|
|
79
79
|
const relativePath = path.posix.join(dir, dirent.name);
|
|
80
80
|
if (dirent.isDirectory()) {
|
|
81
81
|
await recurse(relativePath);
|
|
82
|
-
} else if (fullPath.match(/\.(tsx|ts|jsx|js)$/)) {
|
|
82
|
+
} else if (fullPath.match(/\.(tsx|ts|jsx|js|vue)$/)) {
|
|
83
83
|
const filePath = replaceBackslash(path.join(dir, dirent.name));
|
|
84
84
|
const filePathNoExt = removeExt(filePath);
|
|
85
85
|
const {
|
|
@@ -111,27 +111,31 @@ async function getRouteNodes(config, root) {
|
|
|
111
111
|
if (isValidPathlessLayoutRoute(routePath, routeType, config)) {
|
|
112
112
|
routeType = "pathless_layout";
|
|
113
113
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
[
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
|
|
114
|
+
const isVueFile = filePath.endsWith(".vue");
|
|
115
|
+
if (!isVueFile) {
|
|
116
|
+
[
|
|
117
|
+
["component", "component"],
|
|
118
|
+
["errorComponent", "errorComponent"],
|
|
119
|
+
["notFoundComponent", "notFoundComponent"],
|
|
120
|
+
["pendingComponent", "pendingComponent"],
|
|
121
|
+
["loader", "loader"]
|
|
122
|
+
].forEach(([matcher, type]) => {
|
|
123
|
+
if (routeType === matcher) {
|
|
124
|
+
logger.warn(
|
|
125
|
+
`WARNING: The \`.${type}.tsx\` suffix used for the ${filePath} file is deprecated. Use the new \`.lazy.tsx\` suffix instead.`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
126
130
|
routePath = routePath.replace(
|
|
127
131
|
new RegExp(
|
|
128
|
-
`/(component|errorComponent|pendingComponent|loader|${config.routeToken}|lazy)$`
|
|
132
|
+
`/(component|errorComponent|notFoundComponent|pendingComponent|loader|${config.routeToken}|lazy)$`
|
|
129
133
|
),
|
|
130
134
|
""
|
|
131
135
|
);
|
|
132
136
|
originalRoutePath = originalRoutePath.replace(
|
|
133
137
|
new RegExp(
|
|
134
|
-
`/(component|errorComponent|pendingComponent|loader|${config.routeToken}|lazy)$`
|
|
138
|
+
`/(component|errorComponent|notFoundComponent|pendingComponent|loader|${config.routeToken}|lazy)$`
|
|
135
139
|
),
|
|
136
140
|
""
|
|
137
141
|
);
|
|
@@ -161,7 +165,16 @@ async function getRouteNodes(config, root) {
|
|
|
161
165
|
return routeNodes;
|
|
162
166
|
}
|
|
163
167
|
await recurse("./");
|
|
164
|
-
const rootRouteNode = routeNodes.find(
|
|
168
|
+
const rootRouteNode = routeNodes.find(
|
|
169
|
+
(d) => d.routePath === `/${rootPathId}` && ![
|
|
170
|
+
"component",
|
|
171
|
+
"errorComponent",
|
|
172
|
+
"notFoundComponent",
|
|
173
|
+
"pendingComponent",
|
|
174
|
+
"loader",
|
|
175
|
+
"lazy"
|
|
176
|
+
].includes(d._fsRouteType)
|
|
177
|
+
) ?? routeNodes.find((d) => d.routePath === `/${rootPathId}`);
|
|
165
178
|
if (rootRouteNode) {
|
|
166
179
|
rootRouteNode._fsRouteType = "__root";
|
|
167
180
|
rootRouteNode.variableName = "root";
|
|
@@ -186,6 +199,8 @@ function getRouteMeta(routePath, config) {
|
|
|
186
199
|
fsRouteType = "pendingComponent";
|
|
187
200
|
} else if (routePath.endsWith("/errorComponent")) {
|
|
188
201
|
fsRouteType = "errorComponent";
|
|
202
|
+
} else if (routePath.endsWith("/notFoundComponent")) {
|
|
203
|
+
fsRouteType = "notFoundComponent";
|
|
189
204
|
}
|
|
190
205
|
const variableName = routePathToVariable(routePath);
|
|
191
206
|
return { fsRouteType, variableName };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getRouteNodes.js","sources":["../../../../src/filesystem/physical/getRouteNodes.ts"],"sourcesContent":["import path from 'node:path'\nimport * as fsp from 'node:fs/promises'\nimport {\n determineInitialRoutePath,\n removeExt,\n replaceBackslash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesVirtual } from '../virtual/getRouteNodes'\nimport { loadConfigFile } from '../virtual/loadConfigFile'\nimport { logging } from '../../logger'\nimport { rootPathId } from './rootPathId'\nimport type {\n VirtualRootRoute,\n VirtualRouteSubtreeConfig,\n} from '@tanstack/virtual-file-routes'\nimport type { FsRouteType, GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\n\nconst disallowedRouteGroupConfiguration = /\\(([^)]+)\\).(ts|js|tsx|jsx)/\n\nconst virtualConfigFileRegExp = /__virtual\\.[mc]?[jt]s$/\nexport function isVirtualConfigFile(fileName: string): boolean {\n return virtualConfigFileRegExp.test(fileName)\n}\n\nexport async function getRouteNodes(\n config: Pick<\n Config,\n | 'routesDirectory'\n | 'routeFilePrefix'\n | 'routeFileIgnorePrefix'\n | 'routeFileIgnorePattern'\n | 'disableLogging'\n | 'routeToken'\n | 'indexToken'\n | 'experimental'\n >,\n root: string,\n): Promise<GetRouteNodesResult> {\n const { routeFilePrefix, routeFileIgnorePrefix, routeFileIgnorePattern } =\n config\n\n const logger = logging({ disabled: config.disableLogging })\n const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? '', 'g')\n\n const routeNodes: Array<RouteNode> = []\n const allPhysicalDirectories: Array<string> = []\n\n async function recurse(dir: string) {\n const fullDir = path.resolve(config.routesDirectory, dir)\n let dirList = await fsp.readdir(fullDir, { withFileTypes: true })\n\n dirList = dirList.filter((d) => {\n if (\n d.name.startsWith('.') ||\n (routeFileIgnorePrefix && d.name.startsWith(routeFileIgnorePrefix))\n ) {\n return false\n }\n\n if (routeFilePrefix) {\n if (routeFileIgnorePattern) {\n return (\n d.name.startsWith(routeFilePrefix) &&\n !d.name.match(routeFileIgnoreRegExp)\n )\n }\n\n return d.name.startsWith(routeFilePrefix)\n }\n\n if (routeFileIgnorePattern) {\n return !d.name.match(routeFileIgnoreRegExp)\n }\n\n return true\n })\n\n const virtualConfigFile = dirList.find((dirent) => {\n return dirent.isFile() && isVirtualConfigFile(dirent.name)\n })\n\n if (virtualConfigFile !== undefined) {\n const virtualRouteConfigExport = await loadConfigFile(\n path.resolve(fullDir, virtualConfigFile.name),\n )\n let virtualRouteSubtreeConfig: VirtualRouteSubtreeConfig\n if (typeof virtualRouteConfigExport.default === 'function') {\n virtualRouteSubtreeConfig = await virtualRouteConfigExport.default()\n } else {\n virtualRouteSubtreeConfig = virtualRouteConfigExport.default\n }\n const dummyRoot: VirtualRootRoute = {\n type: 'root',\n file: '',\n children: virtualRouteSubtreeConfig,\n }\n const { routeNodes: virtualRouteNodes, physicalDirectories } =\n await getRouteNodesVirtual(\n {\n ...config,\n routesDirectory: fullDir,\n virtualRouteConfig: dummyRoot,\n },\n root,\n )\n allPhysicalDirectories.push(...physicalDirectories)\n virtualRouteNodes.forEach((node) => {\n const filePath = replaceBackslash(path.join(dir, node.filePath))\n const routePath = `/${dir}${node.routePath}`\n\n node.variableName = routePathToVariable(\n `${dir}/${removeExt(node.filePath)}`,\n )\n node.routePath = routePath\n node.filePath = filePath\n })\n\n routeNodes.push(...virtualRouteNodes)\n\n return\n }\n\n await Promise.all(\n dirList.map(async (dirent) => {\n const fullPath = replaceBackslash(path.join(fullDir, dirent.name))\n const relativePath = path.posix.join(dir, dirent.name)\n\n if (dirent.isDirectory()) {\n await recurse(relativePath)\n } else if (fullPath.match(/\\.(tsx|ts|jsx|js)$/)) {\n const filePath = replaceBackslash(path.join(dir, dirent.name))\n const filePathNoExt = removeExt(filePath)\n const {\n routePath: initialRoutePath,\n originalRoutePath: initialOriginalRoutePath,\n isExperimentalNonNestedRoute,\n } = determineInitialRoutePath(filePathNoExt, config)\n\n let routePath = initialRoutePath\n let originalRoutePath = initialOriginalRoutePath\n\n if (routeFilePrefix) {\n routePath = routePath.replaceAll(routeFilePrefix, '')\n originalRoutePath = originalRoutePath.replaceAll(\n routeFilePrefix,\n '',\n )\n }\n\n if (disallowedRouteGroupConfiguration.test(dirent.name)) {\n const errorMessage = `A route configuration for a route group was found at \\`${filePath}\\`. This is not supported. Did you mean to use a layout/pathless route instead?`\n logger.error(`ERROR: ${errorMessage}`)\n throw new Error(errorMessage)\n }\n\n const meta = getRouteMeta(routePath, config)\n const variableName = meta.variableName\n let routeType: FsRouteType = meta.fsRouteType\n\n if (routeType === 'lazy') {\n routePath = routePath.replace(/\\/lazy$/, '')\n originalRoutePath = originalRoutePath.replace(/\\/lazy$/, '')\n }\n\n // this check needs to happen after the lazy route has been cleaned up\n // since the routePath is used to determine if a route is pathless\n if (isValidPathlessLayoutRoute(routePath, routeType, config)) {\n routeType = 'pathless_layout'\n }\n\n ;(\n [\n ['component', 'component'],\n ['errorComponent', 'errorComponent'],\n ['pendingComponent', 'pendingComponent'],\n ['loader', 'loader'],\n ] satisfies Array<[FsRouteType, string]>\n ).forEach(([matcher, type]) => {\n if (routeType === matcher) {\n logger.warn(\n `WARNING: The \\`.${type}.tsx\\` suffix used for the ${filePath} file is deprecated. Use the new \\`.lazy.tsx\\` suffix instead.`,\n )\n }\n })\n\n routePath = routePath.replace(\n new RegExp(\n `/(component|errorComponent|pendingComponent|loader|${config.routeToken}|lazy)$`,\n ),\n '',\n )\n\n originalRoutePath = originalRoutePath.replace(\n new RegExp(\n `/(component|errorComponent|pendingComponent|loader|${config.routeToken}|lazy)$`,\n ),\n '',\n )\n\n if (routePath === config.indexToken) {\n routePath = '/'\n }\n\n if (originalRoutePath === config.indexToken) {\n originalRoutePath = '/'\n }\n\n routePath =\n routePath.replace(new RegExp(`/${config.indexToken}$`), '/') || '/'\n\n originalRoutePath =\n originalRoutePath.replace(\n new RegExp(`/${config.indexToken}$`),\n '/',\n ) || '/'\n\n routeNodes.push({\n filePath,\n fullPath,\n routePath,\n variableName,\n _fsRouteType: routeType,\n _isExperimentalNonNestedRoute: isExperimentalNonNestedRoute,\n originalRoutePath,\n })\n }\n }),\n )\n\n return routeNodes\n }\n\n await recurse('./')\n\n const rootRouteNode = routeNodes.find((d) => d.routePath === `/${rootPathId}`)\n if (rootRouteNode) {\n rootRouteNode._fsRouteType = '__root'\n rootRouteNode.variableName = 'root'\n }\n\n return {\n rootRouteNode,\n routeNodes,\n physicalDirectories: allPhysicalDirectories,\n }\n}\n\n/**\n * Determines the metadata for a given route path based on the provided configuration.\n *\n * @param routePath - The determined initial routePath.\n * @param config - The user configuration object.\n * @returns An object containing the type of the route and the variable name derived from the route path.\n */\nexport function getRouteMeta(\n routePath: string,\n config: Pick<Config, 'routeToken' | 'indexToken'>,\n): {\n // `__root` is can be more easily determined by filtering down to routePath === /${rootPathId}\n // `pathless` is needs to determined after `lazy` has been cleaned up from the routePath\n fsRouteType: Extract<\n FsRouteType,\n | 'static'\n | 'layout'\n | 'api'\n | 'lazy'\n | 'loader'\n | 'component'\n | 'pendingComponent'\n | 'errorComponent'\n >\n variableName: string\n} {\n let fsRouteType: FsRouteType = 'static'\n\n if (routePath.endsWith(`/${config.routeToken}`)) {\n // layout routes, i.e `/foo/route.tsx` or `/foo/_layout/route.tsx`\n fsRouteType = 'layout'\n } else if (routePath.endsWith('/lazy')) {\n // lazy routes, i.e. `/foo.lazy.tsx`\n fsRouteType = 'lazy'\n } else if (routePath.endsWith('/loader')) {\n // loader routes, i.e. `/foo.loader.tsx`\n fsRouteType = 'loader'\n } else if (routePath.endsWith('/component')) {\n // component routes, i.e. `/foo.component.tsx`\n fsRouteType = 'component'\n } else if (routePath.endsWith('/pendingComponent')) {\n // pending component routes, i.e. `/foo.pendingComponent.tsx`\n fsRouteType = 'pendingComponent'\n } else if (routePath.endsWith('/errorComponent')) {\n // error component routes, i.e. `/foo.errorComponent.tsx`\n fsRouteType = 'errorComponent'\n }\n\n const variableName = routePathToVariable(routePath)\n\n return { fsRouteType, variableName }\n}\n\n/**\n * Used to validate if a route is a pathless layout route\n * @param normalizedRoutePath Normalized route path, i.e `/foo/_layout/route.tsx` and `/foo._layout.route.tsx` to `/foo/_layout/route`\n * @param config The `router-generator` configuration object\n * @returns Boolean indicating if the route is a pathless layout route\n */\nfunction isValidPathlessLayoutRoute(\n normalizedRoutePath: string,\n routeType: FsRouteType,\n config: Pick<Config, 'routeToken' | 'indexToken'>,\n): boolean {\n if (routeType === 'lazy') {\n return false\n }\n\n const segments = normalizedRoutePath.split('/').filter(Boolean)\n\n if (segments.length === 0) {\n return false\n }\n\n const lastRouteSegment = segments[segments.length - 1]!\n const secondToLastRouteSegment = segments[segments.length - 2]\n\n // If segment === __root, then exit as false\n if (lastRouteSegment === rootPathId) {\n return false\n }\n\n // If segment === config.routeToken and secondToLastSegment is a string that starts with _, then exit as true\n // Since the route is actually a configuration route for a layout/pathless route\n // i.e. /foo/_layout/route.tsx === /foo/_layout.tsx\n if (\n lastRouteSegment === config.routeToken &&\n typeof secondToLastRouteSegment === 'string'\n ) {\n return secondToLastRouteSegment.startsWith('_')\n }\n\n // Segment starts with _\n return (\n lastRouteSegment !== config.indexToken &&\n lastRouteSegment !== config.routeToken &&\n lastRouteSegment.startsWith('_')\n )\n}\n"],"names":["getRouteNodesVirtual"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"getRouteNodes.js","sources":["../../../../src/filesystem/physical/getRouteNodes.ts"],"sourcesContent":["import path from 'node:path'\nimport * as fsp from 'node:fs/promises'\nimport {\n determineInitialRoutePath,\n removeExt,\n replaceBackslash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesVirtual } from '../virtual/getRouteNodes'\nimport { loadConfigFile } from '../virtual/loadConfigFile'\nimport { logging } from '../../logger'\nimport { rootPathId } from './rootPathId'\nimport type {\n VirtualRootRoute,\n VirtualRouteSubtreeConfig,\n} from '@tanstack/virtual-file-routes'\nimport type { FsRouteType, GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\n\nconst disallowedRouteGroupConfiguration = /\\(([^)]+)\\).(ts|js|tsx|jsx|vue)/\n\nconst virtualConfigFileRegExp = /__virtual\\.[mc]?[jt]s$/\nexport function isVirtualConfigFile(fileName: string): boolean {\n return virtualConfigFileRegExp.test(fileName)\n}\n\nexport async function getRouteNodes(\n config: Pick<\n Config,\n | 'routesDirectory'\n | 'routeFilePrefix'\n | 'routeFileIgnorePrefix'\n | 'routeFileIgnorePattern'\n | 'disableLogging'\n | 'routeToken'\n | 'indexToken'\n | 'experimental'\n >,\n root: string,\n): Promise<GetRouteNodesResult> {\n const { routeFilePrefix, routeFileIgnorePrefix, routeFileIgnorePattern } =\n config\n\n const logger = logging({ disabled: config.disableLogging })\n const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? '', 'g')\n\n const routeNodes: Array<RouteNode> = []\n const allPhysicalDirectories: Array<string> = []\n\n async function recurse(dir: string) {\n const fullDir = path.resolve(config.routesDirectory, dir)\n let dirList = await fsp.readdir(fullDir, { withFileTypes: true })\n\n dirList = dirList.filter((d) => {\n if (\n d.name.startsWith('.') ||\n (routeFileIgnorePrefix && d.name.startsWith(routeFileIgnorePrefix))\n ) {\n return false\n }\n\n if (routeFilePrefix) {\n if (routeFileIgnorePattern) {\n return (\n d.name.startsWith(routeFilePrefix) &&\n !d.name.match(routeFileIgnoreRegExp)\n )\n }\n\n return d.name.startsWith(routeFilePrefix)\n }\n\n if (routeFileIgnorePattern) {\n return !d.name.match(routeFileIgnoreRegExp)\n }\n\n return true\n })\n\n const virtualConfigFile = dirList.find((dirent) => {\n return dirent.isFile() && isVirtualConfigFile(dirent.name)\n })\n\n if (virtualConfigFile !== undefined) {\n const virtualRouteConfigExport = await loadConfigFile(\n path.resolve(fullDir, virtualConfigFile.name),\n )\n let virtualRouteSubtreeConfig: VirtualRouteSubtreeConfig\n if (typeof virtualRouteConfigExport.default === 'function') {\n virtualRouteSubtreeConfig = await virtualRouteConfigExport.default()\n } else {\n virtualRouteSubtreeConfig = virtualRouteConfigExport.default\n }\n const dummyRoot: VirtualRootRoute = {\n type: 'root',\n file: '',\n children: virtualRouteSubtreeConfig,\n }\n const { routeNodes: virtualRouteNodes, physicalDirectories } =\n await getRouteNodesVirtual(\n {\n ...config,\n routesDirectory: fullDir,\n virtualRouteConfig: dummyRoot,\n },\n root,\n )\n allPhysicalDirectories.push(...physicalDirectories)\n virtualRouteNodes.forEach((node) => {\n const filePath = replaceBackslash(path.join(dir, node.filePath))\n const routePath = `/${dir}${node.routePath}`\n\n node.variableName = routePathToVariable(\n `${dir}/${removeExt(node.filePath)}`,\n )\n node.routePath = routePath\n node.filePath = filePath\n })\n\n routeNodes.push(...virtualRouteNodes)\n\n return\n }\n\n await Promise.all(\n dirList.map(async (dirent) => {\n const fullPath = replaceBackslash(path.join(fullDir, dirent.name))\n const relativePath = path.posix.join(dir, dirent.name)\n\n if (dirent.isDirectory()) {\n await recurse(relativePath)\n } else if (fullPath.match(/\\.(tsx|ts|jsx|js|vue)$/)) {\n const filePath = replaceBackslash(path.join(dir, dirent.name))\n const filePathNoExt = removeExt(filePath)\n const {\n routePath: initialRoutePath,\n originalRoutePath: initialOriginalRoutePath,\n isExperimentalNonNestedRoute,\n } = determineInitialRoutePath(filePathNoExt, config)\n\n let routePath = initialRoutePath\n let originalRoutePath = initialOriginalRoutePath\n\n if (routeFilePrefix) {\n routePath = routePath.replaceAll(routeFilePrefix, '')\n originalRoutePath = originalRoutePath.replaceAll(\n routeFilePrefix,\n '',\n )\n }\n\n if (disallowedRouteGroupConfiguration.test(dirent.name)) {\n const errorMessage = `A route configuration for a route group was found at \\`${filePath}\\`. This is not supported. Did you mean to use a layout/pathless route instead?`\n logger.error(`ERROR: ${errorMessage}`)\n throw new Error(errorMessage)\n }\n\n const meta = getRouteMeta(routePath, config)\n const variableName = meta.variableName\n let routeType: FsRouteType = meta.fsRouteType\n\n if (routeType === 'lazy') {\n routePath = routePath.replace(/\\/lazy$/, '')\n originalRoutePath = originalRoutePath.replace(/\\/lazy$/, '')\n }\n\n // this check needs to happen after the lazy route has been cleaned up\n // since the routePath is used to determine if a route is pathless\n if (isValidPathlessLayoutRoute(routePath, routeType, config)) {\n routeType = 'pathless_layout'\n }\n\n // Only show deprecation warning for .tsx/.ts files, not .vue files\n // Vue files using .component.vue is the Vue-native way\n const isVueFile = filePath.endsWith('.vue')\n if (!isVueFile) {\n ;(\n [\n ['component', 'component'],\n ['errorComponent', 'errorComponent'],\n ['notFoundComponent', 'notFoundComponent'],\n ['pendingComponent', 'pendingComponent'],\n ['loader', 'loader'],\n ] satisfies Array<[FsRouteType, string]>\n ).forEach(([matcher, type]) => {\n if (routeType === matcher) {\n logger.warn(\n `WARNING: The \\`.${type}.tsx\\` suffix used for the ${filePath} file is deprecated. Use the new \\`.lazy.tsx\\` suffix instead.`,\n )\n }\n })\n }\n\n routePath = routePath.replace(\n new RegExp(\n `/(component|errorComponent|notFoundComponent|pendingComponent|loader|${config.routeToken}|lazy)$`,\n ),\n '',\n )\n\n originalRoutePath = originalRoutePath.replace(\n new RegExp(\n `/(component|errorComponent|notFoundComponent|pendingComponent|loader|${config.routeToken}|lazy)$`,\n ),\n '',\n )\n\n if (routePath === config.indexToken) {\n routePath = '/'\n }\n\n if (originalRoutePath === config.indexToken) {\n originalRoutePath = '/'\n }\n\n routePath =\n routePath.replace(new RegExp(`/${config.indexToken}$`), '/') || '/'\n\n originalRoutePath =\n originalRoutePath.replace(\n new RegExp(`/${config.indexToken}$`),\n '/',\n ) || '/'\n\n routeNodes.push({\n filePath,\n fullPath,\n routePath,\n variableName,\n _fsRouteType: routeType,\n _isExperimentalNonNestedRoute: isExperimentalNonNestedRoute,\n originalRoutePath,\n })\n }\n }),\n )\n\n return routeNodes\n }\n\n await recurse('./')\n\n // Find the root route node - prefer the actual route file over component/loader files\n const rootRouteNode =\n routeNodes.find(\n (d) =>\n d.routePath === `/${rootPathId}` &&\n ![\n 'component',\n 'errorComponent',\n 'notFoundComponent',\n 'pendingComponent',\n 'loader',\n 'lazy',\n ].includes(d._fsRouteType),\n ) ?? routeNodes.find((d) => d.routePath === `/${rootPathId}`)\n if (rootRouteNode) {\n rootRouteNode._fsRouteType = '__root'\n rootRouteNode.variableName = 'root'\n }\n\n return {\n rootRouteNode,\n routeNodes,\n physicalDirectories: allPhysicalDirectories,\n }\n}\n\n/**\n * Determines the metadata for a given route path based on the provided configuration.\n *\n * @param routePath - The determined initial routePath.\n * @param config - The user configuration object.\n * @returns An object containing the type of the route and the variable name derived from the route path.\n */\nexport function getRouteMeta(\n routePath: string,\n config: Pick<Config, 'routeToken' | 'indexToken'>,\n): {\n // `__root` is can be more easily determined by filtering down to routePath === /${rootPathId}\n // `pathless` is needs to determined after `lazy` has been cleaned up from the routePath\n fsRouteType: Extract<\n FsRouteType,\n | 'static'\n | 'layout'\n | 'api'\n | 'lazy'\n | 'loader'\n | 'component'\n | 'pendingComponent'\n | 'errorComponent'\n | 'notFoundComponent'\n >\n variableName: string\n} {\n let fsRouteType: FsRouteType = 'static'\n\n if (routePath.endsWith(`/${config.routeToken}`)) {\n // layout routes, i.e `/foo/route.tsx` or `/foo/_layout/route.tsx`\n fsRouteType = 'layout'\n } else if (routePath.endsWith('/lazy')) {\n // lazy routes, i.e. `/foo.lazy.tsx`\n fsRouteType = 'lazy'\n } else if (routePath.endsWith('/loader')) {\n // loader routes, i.e. `/foo.loader.tsx`\n fsRouteType = 'loader'\n } else if (routePath.endsWith('/component')) {\n // component routes, i.e. `/foo.component.tsx`\n fsRouteType = 'component'\n } else if (routePath.endsWith('/pendingComponent')) {\n // pending component routes, i.e. `/foo.pendingComponent.tsx`\n fsRouteType = 'pendingComponent'\n } else if (routePath.endsWith('/errorComponent')) {\n // error component routes, i.e. `/foo.errorComponent.tsx`\n fsRouteType = 'errorComponent'\n } else if (routePath.endsWith('/notFoundComponent')) {\n // not found component routes, i.e. `/foo.notFoundComponent.tsx`\n fsRouteType = 'notFoundComponent'\n }\n\n const variableName = routePathToVariable(routePath)\n\n return { fsRouteType, variableName }\n}\n\n/**\n * Used to validate if a route is a pathless layout route\n * @param normalizedRoutePath Normalized route path, i.e `/foo/_layout/route.tsx` and `/foo._layout.route.tsx` to `/foo/_layout/route`\n * @param config The `router-generator` configuration object\n * @returns Boolean indicating if the route is a pathless layout route\n */\nfunction isValidPathlessLayoutRoute(\n normalizedRoutePath: string,\n routeType: FsRouteType,\n config: Pick<Config, 'routeToken' | 'indexToken'>,\n): boolean {\n if (routeType === 'lazy') {\n return false\n }\n\n const segments = normalizedRoutePath.split('/').filter(Boolean)\n\n if (segments.length === 0) {\n return false\n }\n\n const lastRouteSegment = segments[segments.length - 1]!\n const secondToLastRouteSegment = segments[segments.length - 2]\n\n // If segment === __root, then exit as false\n if (lastRouteSegment === rootPathId) {\n return false\n }\n\n // If segment === config.routeToken and secondToLastSegment is a string that starts with _, then exit as true\n // Since the route is actually a configuration route for a layout/pathless route\n // i.e. /foo/_layout/route.tsx === /foo/_layout.tsx\n if (\n lastRouteSegment === config.routeToken &&\n typeof secondToLastRouteSegment === 'string'\n ) {\n return secondToLastRouteSegment.startsWith('_')\n }\n\n // Segment starts with _\n return (\n lastRouteSegment !== config.indexToken &&\n lastRouteSegment !== config.routeToken &&\n lastRouteSegment.startsWith('_')\n )\n}\n"],"names":["getRouteNodesVirtual"],"mappings":"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"}
|
package/dist/esm/generator.js
CHANGED
|
@@ -177,12 +177,24 @@ Add the file in: "${this.config.routesDirectory}/${rootPathId}.${this.config.dis
|
|
|
177
177
|
(d) => d.routePath?.split("/").length,
|
|
178
178
|
(d) => d.filePath.match(new RegExp(`[./]${this.config.indexToken}[.]`)) ? 1 : -1,
|
|
179
179
|
(d) => d.filePath.match(
|
|
180
|
-
/[./](component|errorComponent|pendingComponent|loader|lazy)[.]/
|
|
180
|
+
/[./](component|errorComponent|notFoundComponent|pendingComponent|loader|lazy)[.]/
|
|
181
181
|
) ? 1 : -1,
|
|
182
182
|
(d) => d.filePath.match(new RegExp(`[./]${this.config.routeToken}[.]`)) ? -1 : 1,
|
|
183
183
|
(d) => d.routePath?.endsWith("/") ? -1 : 1,
|
|
184
184
|
(d) => d.routePath
|
|
185
|
-
]).filter((d) =>
|
|
185
|
+
]).filter((d) => {
|
|
186
|
+
if (d.routePath === `/${rootPathId}`) {
|
|
187
|
+
return [
|
|
188
|
+
"component",
|
|
189
|
+
"errorComponent",
|
|
190
|
+
"notFoundComponent",
|
|
191
|
+
"pendingComponent",
|
|
192
|
+
"loader",
|
|
193
|
+
"lazy"
|
|
194
|
+
].includes(d._fsRouteType);
|
|
195
|
+
}
|
|
196
|
+
return true;
|
|
197
|
+
});
|
|
186
198
|
const routeFileAllResult = await Promise.allSettled(
|
|
187
199
|
preRouteNodes.filter((n) => !n.isVirtualParentRoute && !n.isVirtual).map((n) => this.processRouteNodeFile(n))
|
|
188
200
|
);
|
|
@@ -334,6 +346,25 @@ Add the file in: "${this.config.routesDirectory}/${rootPathId}.${this.config.dis
|
|
|
334
346
|
source: this.targetTemplate.fullPkg
|
|
335
347
|
});
|
|
336
348
|
}
|
|
349
|
+
const hasComponentPieces = sortedRouteNodes.some(
|
|
350
|
+
(node) => acc.routePiecesByPath[node.routePath]?.component || acc.routePiecesByPath[node.routePath]?.errorComponent || acc.routePiecesByPath[node.routePath]?.notFoundComponent || acc.routePiecesByPath[node.routePath]?.pendingComponent
|
|
351
|
+
);
|
|
352
|
+
const hasLoaderPieces = sortedRouteNodes.some(
|
|
353
|
+
(node) => acc.routePiecesByPath[node.routePath]?.loader
|
|
354
|
+
);
|
|
355
|
+
if (hasComponentPieces || hasLoaderPieces) {
|
|
356
|
+
const runtimeImport = {
|
|
357
|
+
specifiers: [],
|
|
358
|
+
source: this.targetTemplate.fullPkg
|
|
359
|
+
};
|
|
360
|
+
if (hasComponentPieces) {
|
|
361
|
+
runtimeImport.specifiers.push({ imported: "lazyRouteComponent" });
|
|
362
|
+
}
|
|
363
|
+
if (hasLoaderPieces) {
|
|
364
|
+
runtimeImport.specifiers.push({ imported: "lazyFn" });
|
|
365
|
+
}
|
|
366
|
+
imports.push(runtimeImport);
|
|
367
|
+
}
|
|
337
368
|
if (config.verboseFileRoutes === false) {
|
|
338
369
|
const typeImport = {
|
|
339
370
|
specifiers: [],
|
|
@@ -363,6 +394,7 @@ Add the file in: "${this.config.routesDirectory}/${rootPathId}.${this.config.dis
|
|
|
363
394
|
const loaderNode = acc.routePiecesByPath[node.routePath]?.loader;
|
|
364
395
|
const componentNode = acc.routePiecesByPath[node.routePath]?.component;
|
|
365
396
|
const errorComponentNode = acc.routePiecesByPath[node.routePath]?.errorComponent;
|
|
397
|
+
const notFoundComponentNode = acc.routePiecesByPath[node.routePath]?.notFoundComponent;
|
|
366
398
|
const pendingComponentNode = acc.routePiecesByPath[node.routePath]?.pendingComponent;
|
|
367
399
|
const lazyComponentNode = acc.routePiecesByPath[node.routePath]?.lazy;
|
|
368
400
|
return [
|
|
@@ -383,38 +415,97 @@ Add the file in: "${this.config.routesDirectory}/${rootPathId}.${this.config.dis
|
|
|
383
415
|
config.addExtensions
|
|
384
416
|
)
|
|
385
417
|
)}'), 'loader') })` : "",
|
|
386
|
-
componentNode || errorComponentNode || pendingComponentNode ? `.update({
|
|
418
|
+
componentNode || errorComponentNode || notFoundComponentNode || pendingComponentNode ? `.update({
|
|
387
419
|
${[
|
|
388
420
|
["component", componentNode],
|
|
389
421
|
["errorComponent", errorComponentNode],
|
|
422
|
+
["notFoundComponent", notFoundComponentNode],
|
|
390
423
|
["pendingComponent", pendingComponentNode]
|
|
391
424
|
].filter((d) => d[1]).map((d) => {
|
|
392
|
-
|
|
393
|
-
|
|
425
|
+
const isVueFile = d[1].filePath.endsWith(".vue");
|
|
426
|
+
const exportName = isVueFile ? "default" : d[0];
|
|
427
|
+
const importPath = replaceBackslash(
|
|
428
|
+
isVueFile ? path.relative(
|
|
429
|
+
path.dirname(config.generatedRouteTree),
|
|
430
|
+
path.resolve(
|
|
431
|
+
config.routesDirectory,
|
|
432
|
+
d[1].filePath
|
|
433
|
+
)
|
|
434
|
+
) : removeExt(
|
|
394
435
|
path.relative(
|
|
395
436
|
path.dirname(config.generatedRouteTree),
|
|
396
|
-
path.resolve(
|
|
437
|
+
path.resolve(
|
|
438
|
+
config.routesDirectory,
|
|
439
|
+
d[1].filePath
|
|
440
|
+
)
|
|
397
441
|
),
|
|
398
442
|
config.addExtensions
|
|
399
443
|
)
|
|
400
|
-
)
|
|
444
|
+
);
|
|
445
|
+
return `${d[0]}: lazyRouteComponent(() => import('./${importPath}'), '${exportName}')`;
|
|
401
446
|
}).join("\n,")}
|
|
402
447
|
})` : "",
|
|
403
|
-
lazyComponentNode ?
|
|
404
|
-
|
|
405
|
-
|
|
448
|
+
lazyComponentNode ? (() => {
|
|
449
|
+
const isVueFile = lazyComponentNode.filePath.endsWith(".vue");
|
|
450
|
+
const exportAccessor = isVueFile ? "d.default" : "d.Route";
|
|
451
|
+
const importPath = replaceBackslash(
|
|
452
|
+
isVueFile ? path.relative(
|
|
406
453
|
path.dirname(config.generatedRouteTree),
|
|
407
454
|
path.resolve(
|
|
408
455
|
config.routesDirectory,
|
|
409
456
|
lazyComponentNode.filePath
|
|
410
457
|
)
|
|
411
|
-
)
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
458
|
+
) : removeExt(
|
|
459
|
+
path.relative(
|
|
460
|
+
path.dirname(config.generatedRouteTree),
|
|
461
|
+
path.resolve(
|
|
462
|
+
config.routesDirectory,
|
|
463
|
+
lazyComponentNode.filePath
|
|
464
|
+
)
|
|
465
|
+
),
|
|
466
|
+
config.addExtensions
|
|
467
|
+
)
|
|
468
|
+
);
|
|
469
|
+
return `.lazy(() => import('./${importPath}').then((d) => ${exportAccessor}))`;
|
|
470
|
+
})() : ""
|
|
415
471
|
].join("")
|
|
416
472
|
].join("\n\n");
|
|
417
473
|
});
|
|
474
|
+
const rootRoutePath = `/${rootPathId}`;
|
|
475
|
+
const rootComponentNode = acc.routePiecesByPath[rootRoutePath]?.component;
|
|
476
|
+
const rootErrorComponentNode = acc.routePiecesByPath[rootRoutePath]?.errorComponent;
|
|
477
|
+
const rootNotFoundComponentNode = acc.routePiecesByPath[rootRoutePath]?.notFoundComponent;
|
|
478
|
+
const rootPendingComponentNode = acc.routePiecesByPath[rootRoutePath]?.pendingComponent;
|
|
479
|
+
let rootRouteUpdate = "";
|
|
480
|
+
if (rootComponentNode || rootErrorComponentNode || rootNotFoundComponentNode || rootPendingComponentNode) {
|
|
481
|
+
rootRouteUpdate = `const rootRouteWithChildren = rootRouteImport${rootComponentNode || rootErrorComponentNode || rootNotFoundComponentNode || rootPendingComponentNode ? `.update({
|
|
482
|
+
${[
|
|
483
|
+
["component", rootComponentNode],
|
|
484
|
+
["errorComponent", rootErrorComponentNode],
|
|
485
|
+
["notFoundComponent", rootNotFoundComponentNode],
|
|
486
|
+
["pendingComponent", rootPendingComponentNode]
|
|
487
|
+
].filter((d) => d[1]).map((d) => {
|
|
488
|
+
const isVueFile = d[1].filePath.endsWith(".vue");
|
|
489
|
+
const exportName = isVueFile ? "default" : d[0];
|
|
490
|
+
const importPath = replaceBackslash(
|
|
491
|
+
isVueFile ? path.relative(
|
|
492
|
+
path.dirname(config.generatedRouteTree),
|
|
493
|
+
path.resolve(config.routesDirectory, d[1].filePath)
|
|
494
|
+
) : removeExt(
|
|
495
|
+
path.relative(
|
|
496
|
+
path.dirname(config.generatedRouteTree),
|
|
497
|
+
path.resolve(
|
|
498
|
+
config.routesDirectory,
|
|
499
|
+
d[1].filePath
|
|
500
|
+
)
|
|
501
|
+
),
|
|
502
|
+
config.addExtensions
|
|
503
|
+
)
|
|
504
|
+
);
|
|
505
|
+
return `${d[0]}: lazyRouteComponent(() => import('./${importPath}'), '${exportName}')`;
|
|
506
|
+
}).join("\n,")}
|
|
507
|
+
})` : ""}._addFileChildren(rootRouteChildren)${config.disableTypes ? "" : `._addFileTypes<FileRouteTypes>()`}`;
|
|
508
|
+
}
|
|
418
509
|
let fileRoutesByPathInterface = "";
|
|
419
510
|
let fileRoutesByFullPath = "";
|
|
420
511
|
if (!config.disableTypes) {
|
|
@@ -460,7 +551,10 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved
|
|
|
460
551
|
(child) => `${child.variableName}Route: ${getResolvedRouteNodeVariableName(child)}`
|
|
461
552
|
).join(",")}
|
|
462
553
|
}`,
|
|
463
|
-
|
|
554
|
+
rootRouteUpdate ? rootRouteUpdate.replace(
|
|
555
|
+
"const rootRouteWithChildren = ",
|
|
556
|
+
"export const routeTree = "
|
|
557
|
+
) : `export const routeTree = rootRouteImport._addFileChildren(rootRouteChildren)${config.disableTypes ? "" : `._addFileTypes<FileRouteTypes>()`}`
|
|
464
558
|
].join("\n");
|
|
465
559
|
checkRouteFullPathUniqueness(
|
|
466
560
|
sortedRouteNodes.filter(
|
|
@@ -582,6 +676,7 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved
|
|
|
582
676
|
"component",
|
|
583
677
|
"pendingComponent",
|
|
584
678
|
"errorComponent",
|
|
679
|
+
"notFoundComponent",
|
|
585
680
|
"loader"
|
|
586
681
|
].every((d) => d !== node._fsRouteType)
|
|
587
682
|
) {
|
|
@@ -600,30 +695,33 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved
|
|
|
600
695
|
return null;
|
|
601
696
|
}
|
|
602
697
|
}
|
|
603
|
-
const
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
698
|
+
const isVueFile = node.filePath.endsWith(".vue");
|
|
699
|
+
if (!isVueFile) {
|
|
700
|
+
const transformResult = await transform({
|
|
701
|
+
source: updatedCacheEntry.fileContent,
|
|
702
|
+
ctx: {
|
|
703
|
+
target: this.config.target,
|
|
704
|
+
routeId: escapedRoutePath,
|
|
705
|
+
lazy: node._fsRouteType === "lazy",
|
|
706
|
+
verboseFileRoutes: !(this.config.verboseFileRoutes === false)
|
|
707
|
+
},
|
|
708
|
+
node
|
|
709
|
+
});
|
|
710
|
+
if (transformResult.result === "no-route-export") {
|
|
711
|
+
this.logger.warn(
|
|
712
|
+
`Route file "${node.fullPath}" does not contain any route piece. This is likely a mistake.`
|
|
713
|
+
);
|
|
714
|
+
return null;
|
|
715
|
+
}
|
|
716
|
+
if (transformResult.result === "error") {
|
|
717
|
+
throw new Error(
|
|
718
|
+
`Error transforming route file ${node.fullPath}: ${transformResult.error}`
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
if (transformResult.result === "modified") {
|
|
722
|
+
updatedCacheEntry.fileContent = transformResult.output;
|
|
723
|
+
shouldWriteRouteFile = true;
|
|
724
|
+
}
|
|
627
725
|
}
|
|
628
726
|
for (const plugin of this.plugins) {
|
|
629
727
|
plugin.afterTransform?.({ node, prevNode: previousCacheEntry?.node });
|
|
@@ -837,14 +935,15 @@ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${getResolved
|
|
|
837
935
|
"loader",
|
|
838
936
|
"component",
|
|
839
937
|
"pendingComponent",
|
|
840
|
-
"errorComponent"
|
|
938
|
+
"errorComponent",
|
|
939
|
+
"notFoundComponent"
|
|
841
940
|
].some((d) => d === node._fsRouteType)) {
|
|
842
941
|
acc.routePiecesByPath[node.routePath] = acc.routePiecesByPath[node.routePath] || {};
|
|
843
|
-
acc.routePiecesByPath[node.routePath][node._fsRouteType === "lazy" ? "lazy" : node._fsRouteType === "loader" ? "loader" : node._fsRouteType === "errorComponent" ? "errorComponent" : node._fsRouteType === "pendingComponent" ? "pendingComponent" : "component"] = node;
|
|
942
|
+
acc.routePiecesByPath[node.routePath][node._fsRouteType === "lazy" ? "lazy" : node._fsRouteType === "loader" ? "loader" : node._fsRouteType === "errorComponent" ? "errorComponent" : node._fsRouteType === "notFoundComponent" ? "notFoundComponent" : node._fsRouteType === "pendingComponent" ? "pendingComponent" : "component"] = node;
|
|
844
943
|
const anchorRoute = acc.routeNodes.find(
|
|
845
944
|
(d) => d.routePath === node.routePath
|
|
846
945
|
);
|
|
847
|
-
if (!anchorRoute) {
|
|
946
|
+
if (!anchorRoute && node.routePath !== `/${rootPathId}`) {
|
|
848
947
|
this.handleNode(
|
|
849
948
|
{
|
|
850
949
|
...node,
|