@tanstack/router-generator 1.20.0 → 1.20.3-alpha.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 +93 -13
- package/dist/cjs/config.cjs.map +1 -1
- package/dist/cjs/config.d.cts +126 -9
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs +191 -0
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs.map +1 -0
- package/dist/cjs/filesystem/physical/getRouteNodes.d.cts +14 -0
- package/dist/cjs/filesystem/physical/rootPathId.cjs +5 -0
- package/dist/cjs/filesystem/physical/rootPathId.cjs.map +1 -0
- package/dist/cjs/filesystem/physical/rootPathId.d.cts +1 -0
- package/dist/cjs/filesystem/virtual/config.cjs +37 -0
- package/dist/cjs/filesystem/virtual/config.cjs.map +1 -0
- package/dist/cjs/filesystem/virtual/config.d.cts +3 -0
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs +186 -0
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs.map +1 -0
- package/dist/cjs/filesystem/virtual/getRouteNodes.d.cts +5 -0
- package/dist/cjs/filesystem/virtual/loadConfigFile.cjs +11 -0
- package/dist/cjs/filesystem/virtual/loadConfigFile.cjs.map +1 -0
- package/dist/cjs/filesystem/virtual/loadConfigFile.d.cts +1 -0
- package/dist/cjs/generator.cjs +516 -328
- package/dist/cjs/generator.cjs.map +1 -1
- package/dist/cjs/generator.d.cts +1 -37
- package/dist/cjs/index.cjs +24 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +7 -1
- package/dist/cjs/template.cjs +110 -0
- package/dist/cjs/template.cjs.map +1 -0
- package/dist/cjs/template.d.cts +33 -0
- package/dist/cjs/types.d.cts +20 -0
- package/dist/cjs/utils.cjs +177 -10
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +47 -5
- package/dist/esm/config.d.ts +126 -9
- package/dist/esm/config.js +88 -8
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/filesystem/physical/getRouteNodes.d.ts +14 -0
- package/dist/esm/filesystem/physical/getRouteNodes.js +174 -0
- package/dist/esm/filesystem/physical/getRouteNodes.js.map +1 -0
- package/dist/esm/filesystem/physical/rootPathId.d.ts +1 -0
- package/dist/esm/filesystem/physical/rootPathId.js +5 -0
- package/dist/esm/filesystem/physical/rootPathId.js.map +1 -0
- package/dist/esm/filesystem/virtual/config.d.ts +3 -0
- package/dist/esm/filesystem/virtual/config.js +37 -0
- package/dist/esm/filesystem/virtual/config.js.map +1 -0
- package/dist/esm/filesystem/virtual/getRouteNodes.d.ts +5 -0
- package/dist/esm/filesystem/virtual/getRouteNodes.js +186 -0
- package/dist/esm/filesystem/virtual/getRouteNodes.js.map +1 -0
- package/dist/esm/filesystem/virtual/loadConfigFile.d.ts +1 -0
- package/dist/esm/filesystem/virtual/loadConfigFile.js +11 -0
- package/dist/esm/filesystem/virtual/loadConfigFile.js.map +1 -0
- package/dist/esm/generator.d.ts +1 -37
- package/dist/esm/generator.js +509 -320
- package/dist/esm/generator.js.map +1 -1
- package/dist/esm/index.d.ts +7 -1
- package/dist/esm/index.js +26 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/template.d.ts +33 -0
- package/dist/esm/template.js +110 -0
- package/dist/esm/template.js.map +1 -0
- package/dist/esm/types.d.ts +20 -0
- package/dist/esm/utils.d.ts +47 -5
- package/dist/esm/utils.js +160 -11
- package/dist/esm/utils.js.map +1 -1
- package/package.json +27 -22
- package/src/config.ts +112 -8
- package/src/filesystem/physical/getRouteNodes.ts +295 -0
- package/src/filesystem/physical/rootPathId.ts +1 -0
- package/src/filesystem/virtual/config.ts +45 -0
- package/src/filesystem/virtual/getRouteNodes.ts +260 -0
- package/src/filesystem/virtual/loadConfigFile.ts +8 -0
- package/src/generator.ts +712 -395
- package/src/index.ts +33 -1
- package/src/template.ts +156 -0
- package/src/types.ts +31 -0
- package/src/utils.ts +237 -10
package/dist/esm/generator.js
CHANGED
|
@@ -1,106 +1,24 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import * as fs from "fs";
|
|
3
|
-
import * as fsp from "fs/promises";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as fsp from "node:fs/promises";
|
|
4
|
+
import { logging, multiSortBy, replaceBackslash, removeExt, writeIfDifferent, format, resetRegex, trimPathLeft, removeUnderscores, routePathToVariable } from "./utils.js";
|
|
5
|
+
import { getRouteNodes as getRouteNodes$1 } from "./filesystem/physical/getRouteNodes.js";
|
|
6
|
+
import { getRouteNodes } from "./filesystem/virtual/getRouteNodes.js";
|
|
7
|
+
import { rootPathId } from "./filesystem/physical/rootPathId.js";
|
|
8
|
+
import { getTargetTemplate, fillTemplate } from "./template.js";
|
|
9
|
+
const rootRouteId = "__root__";
|
|
6
10
|
let latestTask = 0;
|
|
7
|
-
const rootPathId = "__root";
|
|
8
11
|
const routeGroupPatternRegex = /\(.+\)/g;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const logger = logging({ disabled: config.disableLogging });
|
|
12
|
-
const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? "", "g");
|
|
13
|
-
let routeNodes = [];
|
|
14
|
-
async function recurse(dir) {
|
|
15
|
-
const fullDir = path.resolve(config.routesDirectory, dir);
|
|
16
|
-
let dirList = await fsp.readdir(fullDir, { withFileTypes: true });
|
|
17
|
-
dirList = dirList.filter((d) => {
|
|
18
|
-
if (d.name.startsWith(".") || routeFileIgnorePrefix && d.name.startsWith(routeFileIgnorePrefix)) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
if (routeFilePrefix) {
|
|
22
|
-
return d.name.startsWith(routeFilePrefix);
|
|
23
|
-
}
|
|
24
|
-
if (routeFileIgnorePattern) {
|
|
25
|
-
return !d.name.match(routeFileIgnoreRegExp);
|
|
26
|
-
}
|
|
27
|
-
return true;
|
|
28
|
-
});
|
|
29
|
-
await Promise.all(
|
|
30
|
-
dirList.map(async (dirent) => {
|
|
31
|
-
var _a;
|
|
32
|
-
const fullPath = path.join(fullDir, dirent.name);
|
|
33
|
-
const relativePath = path.join(dir, dirent.name);
|
|
34
|
-
if (dirent.isDirectory()) {
|
|
35
|
-
await recurse(relativePath);
|
|
36
|
-
} else if (fullPath.match(/\.(tsx|ts|jsx|js)$/)) {
|
|
37
|
-
const filePath = replaceBackslash(path.join(dir, dirent.name));
|
|
38
|
-
const filePathNoExt = removeExt(filePath);
|
|
39
|
-
let routePath = cleanPath(`/${filePathNoExt.split(".").join("/")}`) || "";
|
|
40
|
-
if (routeFilePrefix) {
|
|
41
|
-
routePath = routePath.replaceAll(routeFilePrefix, "");
|
|
42
|
-
}
|
|
43
|
-
const variableName = routePathToVariable(routePath);
|
|
44
|
-
let isLazy = routePath == null ? void 0 : routePath.endsWith("/lazy");
|
|
45
|
-
if (isLazy) {
|
|
46
|
-
routePath = routePath == null ? void 0 : routePath.replace(/\/lazy$/, "");
|
|
47
|
-
}
|
|
48
|
-
let isRoute = routePath == null ? void 0 : routePath.endsWith("/route");
|
|
49
|
-
let isComponent = routePath == null ? void 0 : routePath.endsWith("/component");
|
|
50
|
-
let isErrorComponent = routePath == null ? void 0 : routePath.endsWith("/errorComponent");
|
|
51
|
-
let isPendingComponent = routePath == null ? void 0 : routePath.endsWith("/pendingComponent");
|
|
52
|
-
let isLoader = routePath == null ? void 0 : routePath.endsWith("/loader");
|
|
53
|
-
const segments = (routePath ?? "").split("/");
|
|
54
|
-
let isLayout = ((_a = segments[segments.length - 1]) == null ? void 0 : _a.startsWith("_")) || false;
|
|
55
|
-
[
|
|
56
|
-
[isComponent, "component"],
|
|
57
|
-
[isErrorComponent, "errorComponent"],
|
|
58
|
-
[isPendingComponent, "pendingComponent"],
|
|
59
|
-
[isLoader, "loader"]
|
|
60
|
-
].forEach(([isType, type]) => {
|
|
61
|
-
if (isType) {
|
|
62
|
-
logger.warn(
|
|
63
|
-
`WARNING: The \`.${type}.tsx\` suffix used for the ${filePath} file is deprecated. Use the new \`.lazy.tsx\` suffix instead.`
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
routePath = routePath == null ? void 0 : routePath.replace(
|
|
68
|
-
/\/(component|errorComponent|pendingComponent|loader|route|lazy)$/,
|
|
69
|
-
""
|
|
70
|
-
);
|
|
71
|
-
if (routePath === "index") {
|
|
72
|
-
routePath = "/";
|
|
73
|
-
}
|
|
74
|
-
routePath = routePath.replace(/\/index$/, "/") || "/";
|
|
75
|
-
routeNodes.push({
|
|
76
|
-
filePath,
|
|
77
|
-
fullPath,
|
|
78
|
-
routePath,
|
|
79
|
-
variableName,
|
|
80
|
-
isRoute,
|
|
81
|
-
isComponent,
|
|
82
|
-
isErrorComponent,
|
|
83
|
-
isPendingComponent,
|
|
84
|
-
isLoader,
|
|
85
|
-
isLazy,
|
|
86
|
-
isLayout
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
})
|
|
90
|
-
);
|
|
91
|
-
return routeNodes;
|
|
92
|
-
}
|
|
93
|
-
await recurse("./");
|
|
94
|
-
return routeNodes;
|
|
95
|
-
}
|
|
96
|
-
let first = false;
|
|
12
|
+
const possiblyNestedRouteGroupPatternRegex = /\([^/]+\)\/?/g;
|
|
13
|
+
let isFirst = false;
|
|
97
14
|
let skipMessage = false;
|
|
98
|
-
async function generator(config) {
|
|
15
|
+
async function generator(config, root) {
|
|
16
|
+
const ROUTE_TEMPLATE = getTargetTemplate(config.target);
|
|
99
17
|
const logger = logging({ disabled: config.disableLogging });
|
|
100
18
|
logger.log("");
|
|
101
|
-
if (!
|
|
19
|
+
if (!isFirst) {
|
|
102
20
|
logger.log("♻️ Generating routes...");
|
|
103
|
-
|
|
21
|
+
isFirst = true;
|
|
104
22
|
} else if (skipMessage) {
|
|
105
23
|
skipMessage = false;
|
|
106
24
|
} else {
|
|
@@ -116,31 +34,34 @@ async function generator(config) {
|
|
|
116
34
|
return true;
|
|
117
35
|
};
|
|
118
36
|
const start = Date.now();
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
37
|
+
const TYPES_DISABLED = config.disableTypes;
|
|
38
|
+
let getRouteNodesResult;
|
|
39
|
+
if (config.virtualRouteConfig) {
|
|
40
|
+
getRouteNodesResult = await getRouteNodes(config, root);
|
|
41
|
+
} else {
|
|
42
|
+
getRouteNodesResult = await getRouteNodes$1(config, root);
|
|
43
|
+
}
|
|
44
|
+
const { rootRouteNode, routeNodes: beforeRouteNodes } = getRouteNodesResult;
|
|
45
|
+
if (rootRouteNode === void 0) {
|
|
46
|
+
let errorMessage = `rootRouteNode must not be undefined. Make sure you've added your root route into the route-tree.`;
|
|
47
|
+
if (!config.virtualRouteConfig) {
|
|
48
|
+
errorMessage += `
|
|
49
|
+
Make sure that you add a "${rootPathId}.${config.disableTypes ? "js" : "tsx"}" file to your routes directory.
|
|
50
|
+
Add the file in: "${config.routesDirectory}/${rootPathId}.${config.disableTypes ? "js" : "tsx"}"`;
|
|
51
|
+
}
|
|
52
|
+
throw new Error(errorMessage);
|
|
53
|
+
}
|
|
124
54
|
const preRouteNodes = multiSortBy(beforeRouteNodes, [
|
|
125
55
|
(d) => d.routePath === "/" ? -1 : 1,
|
|
126
56
|
(d) => {
|
|
127
57
|
var _a;
|
|
128
58
|
return (_a = d.routePath) == null ? void 0 : _a.split("/").length;
|
|
129
59
|
},
|
|
130
|
-
(d) => {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
(d) => {
|
|
135
|
-
var _a;
|
|
136
|
-
return ((_a = d.filePath) == null ? void 0 : _a.match(
|
|
137
|
-
/[./](component|errorComponent|pendingComponent|loader|lazy)[.]/
|
|
138
|
-
)) ? 1 : -1;
|
|
139
|
-
},
|
|
140
|
-
(d) => {
|
|
141
|
-
var _a;
|
|
142
|
-
return ((_a = d.filePath) == null ? void 0 : _a.match(/[./]route[.]/)) ? -1 : 1;
|
|
143
|
-
},
|
|
60
|
+
(d) => d.filePath.match(new RegExp(`[./]${config.indexToken}[.]`)) ? 1 : -1,
|
|
61
|
+
(d) => d.filePath.match(
|
|
62
|
+
/[./](component|errorComponent|pendingComponent|loader|lazy)[.]/
|
|
63
|
+
) ? 1 : -1,
|
|
64
|
+
(d) => d.filePath.match(new RegExp(`[./]${config.routeToken}[.]`)) ? -1 : 1,
|
|
144
65
|
(d) => {
|
|
145
66
|
var _a;
|
|
146
67
|
return ((_a = d.routePath) == null ? void 0 : _a.endsWith("/")) ? -1 : 1;
|
|
@@ -149,9 +70,37 @@ async function generator(config) {
|
|
|
149
70
|
]).filter((d) => ![`/${rootPathId}`].includes(d.routePath || ""));
|
|
150
71
|
const routeTree = [];
|
|
151
72
|
const routePiecesByPath = {};
|
|
152
|
-
|
|
73
|
+
const routeNodes = [];
|
|
74
|
+
const handleRootNode = async (node) => {
|
|
75
|
+
if (!node) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const routeCode = fs.readFileSync(node.fullPath, "utf-8");
|
|
79
|
+
if (!routeCode) {
|
|
80
|
+
const _rootTemplate = ROUTE_TEMPLATE.rootRoute;
|
|
81
|
+
const replaced = await fillTemplate(config, _rootTemplate.template(), {
|
|
82
|
+
tsrImports: _rootTemplate.imports.tsrImports(),
|
|
83
|
+
tsrPath: rootPathId,
|
|
84
|
+
tsrExportStart: _rootTemplate.imports.tsrExportStart(),
|
|
85
|
+
tsrExportEnd: _rootTemplate.imports.tsrExportEnd()
|
|
86
|
+
});
|
|
87
|
+
await writeIfDifferent(
|
|
88
|
+
node.fullPath,
|
|
89
|
+
"",
|
|
90
|
+
// Empty string because the file doesn't exist yet
|
|
91
|
+
replaced,
|
|
92
|
+
{
|
|
93
|
+
beforeWrite: () => {
|
|
94
|
+
logger.log(`🟡 Creating ${node.fullPath}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
await handleRootNode(rootRouteNode);
|
|
153
101
|
const handleNode = async (node) => {
|
|
154
|
-
var _a, _b;
|
|
102
|
+
var _a, _b, _c, _d, _e;
|
|
103
|
+
resetRegex(routeGroupPatternRegex);
|
|
155
104
|
let parentRoute = hasParentRoute(routeNodes, node, node.routePath);
|
|
156
105
|
if ((parentRoute == null ? void 0 : parentRoute.isVirtualParentRoute) && ((_a = parentRoute.children) == null ? void 0 : _a.length)) {
|
|
157
106
|
const possibleParentRoute = hasParentRoute(
|
|
@@ -163,76 +112,155 @@ async function generator(config) {
|
|
|
163
112
|
parentRoute = possibleParentRoute;
|
|
164
113
|
}
|
|
165
114
|
}
|
|
166
|
-
if (parentRoute)
|
|
167
|
-
node.parent = parentRoute;
|
|
115
|
+
if (parentRoute) node.parent = parentRoute;
|
|
168
116
|
node.path = determineNodePath(node);
|
|
169
117
|
const trimmedPath = trimPathLeft(node.path ?? "");
|
|
170
|
-
const split =
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
node.isNonPath = lastRouteSegment.startsWith("_");
|
|
174
|
-
node.isNonLayout = first2.endsWith("_");
|
|
118
|
+
const split = trimmedPath.split("/");
|
|
119
|
+
const lastRouteSegment = split[split.length - 1] ?? trimmedPath;
|
|
120
|
+
node.isNonPath = lastRouteSegment.startsWith("_") || routeGroupPatternRegex.test(lastRouteSegment);
|
|
175
121
|
node.cleanedPath = removeGroups(
|
|
176
122
|
removeUnderscores(removeLayoutSegments(node.path)) ?? ""
|
|
177
123
|
);
|
|
178
|
-
if (!node.isVirtualParentRoute) {
|
|
124
|
+
if (!node.isVirtualParentRoute && !node.isVirtual) {
|
|
179
125
|
const routeCode = fs.readFileSync(node.fullPath, "utf-8");
|
|
180
|
-
const escapedRoutePath =
|
|
181
|
-
((_b = node.routePath) == null ? void 0 : _b.replaceAll("$", "$$")) ?? ""
|
|
182
|
-
);
|
|
126
|
+
const escapedRoutePath = ((_b = node.routePath) == null ? void 0 : _b.replaceAll("$", "$$")) ?? "";
|
|
183
127
|
let replaced = routeCode;
|
|
128
|
+
const tRouteTemplate = ROUTE_TEMPLATE.route;
|
|
129
|
+
const tLazyRouteTemplate = ROUTE_TEMPLATE.lazyRoute;
|
|
184
130
|
if (!routeCode) {
|
|
185
|
-
if (node.
|
|
186
|
-
replaced =
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
].
|
|
131
|
+
if (node._fsRouteType === "lazy") {
|
|
132
|
+
replaced = await fillTemplate(
|
|
133
|
+
config,
|
|
134
|
+
(((_c = config.customScaffolding) == null ? void 0 : _c.lazyRouteTemplate) || ((_d = config.customScaffolding) == null ? void 0 : _d.routeTemplate)) ?? tLazyRouteTemplate.template(),
|
|
135
|
+
{
|
|
136
|
+
tsrImports: tLazyRouteTemplate.imports.tsrImports(),
|
|
137
|
+
tsrPath: escapedRoutePath.replaceAll(/\{(.+)\}/gm, "$1"),
|
|
138
|
+
tsrExportStart: tLazyRouteTemplate.imports.tsrExportStart(escapedRoutePath),
|
|
139
|
+
tsrExportEnd: tLazyRouteTemplate.imports.tsrExportEnd()
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
} else if (
|
|
143
|
+
// Creating a new normal route file
|
|
144
|
+
["layout", "static"].some(
|
|
145
|
+
(d) => d === node._fsRouteType
|
|
146
|
+
) || [
|
|
147
|
+
"component",
|
|
148
|
+
"pendingComponent",
|
|
149
|
+
"errorComponent",
|
|
150
|
+
"loader"
|
|
151
|
+
].every((d) => d !== node._fsRouteType)
|
|
152
|
+
) {
|
|
153
|
+
replaced = await fillTemplate(
|
|
154
|
+
config,
|
|
155
|
+
((_e = config.customScaffolding) == null ? void 0 : _e.routeTemplate) ?? tRouteTemplate.template(),
|
|
156
|
+
{
|
|
157
|
+
tsrImports: tRouteTemplate.imports.tsrImports(),
|
|
158
|
+
tsrPath: escapedRoutePath.replaceAll(/\{(.+)\}/gm, "$1"),
|
|
159
|
+
tsrExportStart: tRouteTemplate.imports.tsrExportStart(escapedRoutePath),
|
|
160
|
+
tsrExportEnd: tRouteTemplate.imports.tsrExportEnd()
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
} else if (config.verboseFileRoutes === false) {
|
|
165
|
+
if (!routeCode.split("\n").some((line) => line.trim().startsWith("export const Route"))) {
|
|
166
|
+
return;
|
|
199
167
|
}
|
|
168
|
+
replaced = routeCode.replace(
|
|
169
|
+
/(FileRoute\(\s*['"])([^\s]*)(['"],?\s*\))/g,
|
|
170
|
+
(_, p1, __, p3) => `${p1}${escapedRoutePath}${p3}`
|
|
171
|
+
).replace(
|
|
172
|
+
new RegExp(
|
|
173
|
+
`(import\\s*\\{)(.*)(create(Lazy)?FileRoute)(.*)(\\}\\s*from\\s*['"]@tanstack\\/${ROUTE_TEMPLATE.subPkg}['"])`,
|
|
174
|
+
"gs"
|
|
175
|
+
),
|
|
176
|
+
(_, p1, p2, ___, ____, p5, p6) => {
|
|
177
|
+
const beforeCreateFileRoute = () => {
|
|
178
|
+
if (!p2) return "";
|
|
179
|
+
let trimmed = p2.trim();
|
|
180
|
+
if (trimmed.endsWith(",")) {
|
|
181
|
+
trimmed = trimmed.slice(0, -1);
|
|
182
|
+
}
|
|
183
|
+
return trimmed;
|
|
184
|
+
};
|
|
185
|
+
const afterCreateFileRoute = () => {
|
|
186
|
+
if (!p5) return "";
|
|
187
|
+
let trimmed = p5.trim();
|
|
188
|
+
if (trimmed.startsWith(",")) {
|
|
189
|
+
trimmed = trimmed.slice(1);
|
|
190
|
+
}
|
|
191
|
+
return trimmed;
|
|
192
|
+
};
|
|
193
|
+
const newImport = () => {
|
|
194
|
+
const before = beforeCreateFileRoute();
|
|
195
|
+
const after = afterCreateFileRoute();
|
|
196
|
+
if (!before) return after;
|
|
197
|
+
if (!after) return before;
|
|
198
|
+
return `${before},${after}`;
|
|
199
|
+
};
|
|
200
|
+
const middle = newImport();
|
|
201
|
+
if (middle === "") return "";
|
|
202
|
+
return `${p1} ${newImport()} ${p6}`;
|
|
203
|
+
}
|
|
204
|
+
).replace(
|
|
205
|
+
/create(Lazy)?FileRoute(\(\s*['"])([^\s]*)(['"],?\s*\))/g,
|
|
206
|
+
(_, __, p2, ___, p4) => `${node._fsRouteType === "lazy" ? "createLazyFileRoute" : "createFileRoute"}`
|
|
207
|
+
);
|
|
200
208
|
} else {
|
|
201
209
|
replaced = routeCode.replace(
|
|
202
210
|
/(FileRoute\(\s*['"])([^\s]*)(['"],?\s*\))/g,
|
|
203
|
-
(
|
|
211
|
+
(_, p1, __, p3) => `${p1}${escapedRoutePath}${p3}`
|
|
212
|
+
).replace(
|
|
213
|
+
/((FileRoute)(\s*)(\({))/g,
|
|
214
|
+
(_, __, p2, p3, p4) => `${p2}('${escapedRoutePath}')${p3}${p4}`
|
|
204
215
|
).replace(
|
|
205
|
-
|
|
206
|
-
|
|
216
|
+
new RegExp(
|
|
217
|
+
`(import\\s*\\{.*)(create(Lazy)?FileRoute)(.*\\}\\s*from\\s*['"]@tanstack\\/${ROUTE_TEMPLATE.subPkg}['"])`,
|
|
218
|
+
"gs"
|
|
219
|
+
),
|
|
220
|
+
(_, p1, __, ___, p4) => `${p1}${node._fsRouteType === "lazy" ? "createLazyFileRoute" : "createFileRoute"}${p4}`
|
|
207
221
|
).replace(
|
|
208
|
-
/(
|
|
209
|
-
(
|
|
222
|
+
/create(Lazy)?FileRoute(\(\s*['"])([^\s]*)(['"],?\s*\))/g,
|
|
223
|
+
(_, __, p2, ___, p4) => `${node._fsRouteType === "lazy" ? "createLazyFileRoute" : "createFileRoute"}${p2}${escapedRoutePath}${p4}`
|
|
210
224
|
);
|
|
225
|
+
const regex = new RegExp(
|
|
226
|
+
`(import\\s*\\{.*)(create(Lazy)?FileRoute)(.*\\}\\s*from\\s*['"]@tanstack\\/${ROUTE_TEMPLATE.subPkg}['"])`,
|
|
227
|
+
"gm"
|
|
228
|
+
);
|
|
229
|
+
if (!replaced.match(regex)) {
|
|
230
|
+
replaced = [
|
|
231
|
+
`import { ${node._fsRouteType === "lazy" ? "createLazyFileRoute" : "createFileRoute"} } from '@tanstack/${ROUTE_TEMPLATE.subPkg}'`,
|
|
232
|
+
...replaced.split("\n")
|
|
233
|
+
].join("\n");
|
|
234
|
+
}
|
|
211
235
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
236
|
+
await writeIfDifferent(node.fullPath, routeCode, replaced, {
|
|
237
|
+
beforeWrite: () => {
|
|
238
|
+
logger.log(`🟡 Updating ${node.fullPath}`);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
216
241
|
}
|
|
217
|
-
if (!node.isVirtual &&
|
|
242
|
+
if (!node.isVirtual && [
|
|
243
|
+
"lazy",
|
|
244
|
+
"loader",
|
|
245
|
+
"component",
|
|
246
|
+
"pendingComponent",
|
|
247
|
+
"errorComponent"
|
|
248
|
+
].some((d) => d === node._fsRouteType)) {
|
|
218
249
|
routePiecesByPath[node.routePath] = routePiecesByPath[node.routePath] || {};
|
|
219
|
-
routePiecesByPath[node.routePath][node.
|
|
250
|
+
routePiecesByPath[node.routePath][node._fsRouteType === "lazy" ? "lazy" : node._fsRouteType === "loader" ? "loader" : node._fsRouteType === "errorComponent" ? "errorComponent" : node._fsRouteType === "pendingComponent" ? "pendingComponent" : "component"] = node;
|
|
220
251
|
const anchorRoute = routeNodes.find((d) => d.routePath === node.routePath);
|
|
221
252
|
if (!anchorRoute) {
|
|
222
253
|
await handleNode({
|
|
223
254
|
...node,
|
|
224
255
|
isVirtual: true,
|
|
225
|
-
|
|
226
|
-
isLoader: false,
|
|
227
|
-
isComponent: false,
|
|
228
|
-
isErrorComponent: false,
|
|
229
|
-
isPendingComponent: false
|
|
256
|
+
_fsRouteType: "static"
|
|
230
257
|
});
|
|
231
258
|
}
|
|
232
259
|
return;
|
|
233
260
|
}
|
|
234
261
|
const cleanedPathIsEmpty = (node.cleanedPath || "").length === 0;
|
|
235
|
-
|
|
262
|
+
const nonPathRoute = node._fsRouteType === "pathless_layout" && node.isNonPath;
|
|
263
|
+
node.isVirtualParentRequired = node._fsRouteType === "pathless_layout" || nonPathRoute ? !cleanedPathIsEmpty : false;
|
|
236
264
|
if (!node.isVirtual && node.isVirtualParentRequired) {
|
|
237
265
|
const parentRoutePath = removeLastSegmentFromPath(node.routePath) || "/";
|
|
238
266
|
const parentVariableName = routePathToVariable(parentRoutePath);
|
|
@@ -248,14 +276,15 @@ async function generator(config) {
|
|
|
248
276
|
routePath: parentRoutePath,
|
|
249
277
|
variableName: parentVariableName,
|
|
250
278
|
isVirtual: true,
|
|
251
|
-
|
|
279
|
+
_fsRouteType: "layout",
|
|
280
|
+
// layout since this route will wrap other routes
|
|
252
281
|
isVirtualParentRoute: true,
|
|
253
282
|
isVirtualParentRequired: false
|
|
254
283
|
};
|
|
255
284
|
parentNode.children = parentNode.children ?? [];
|
|
256
285
|
parentNode.children.push(node);
|
|
257
286
|
node.parent = parentNode;
|
|
258
|
-
if (node.
|
|
287
|
+
if (node._fsRouteType === "pathless_layout") {
|
|
259
288
|
node.path = determineNodePath(node);
|
|
260
289
|
}
|
|
261
290
|
await handleNode(parentNode);
|
|
@@ -278,25 +307,43 @@ async function generator(config) {
|
|
|
278
307
|
for (const node of preRouteNodes) {
|
|
279
308
|
await handleNode(node);
|
|
280
309
|
}
|
|
281
|
-
|
|
310
|
+
checkRouteFullPathUniqueness(
|
|
311
|
+
preRouteNodes.filter(
|
|
312
|
+
(d) => d.children === void 0 && "lazy" !== d._fsRouteType
|
|
313
|
+
),
|
|
314
|
+
config
|
|
315
|
+
);
|
|
316
|
+
function buildRouteTreeConfig(nodes, depth = 1) {
|
|
282
317
|
const children = nodes.map((node) => {
|
|
283
318
|
var _a, _b;
|
|
284
|
-
if (node.
|
|
319
|
+
if (node._fsRouteType === "__root") {
|
|
285
320
|
return;
|
|
286
321
|
}
|
|
287
|
-
if (node.
|
|
322
|
+
if (node._fsRouteType === "pathless_layout" && !((_a = node.children) == null ? void 0 : _a.length)) {
|
|
288
323
|
return;
|
|
289
324
|
}
|
|
290
325
|
const route = `${node.variableName}Route`;
|
|
291
326
|
if ((_b = node.children) == null ? void 0 : _b.length) {
|
|
292
|
-
const childConfigs =
|
|
293
|
-
|
|
327
|
+
const childConfigs = buildRouteTreeConfig(node.children, depth + 1);
|
|
328
|
+
const childrenDeclaration = TYPES_DISABLED ? "" : `interface ${route}Children {
|
|
329
|
+
${node.children.map((child) => `${child.variableName}Route: typeof ${getResolvedRouteNodeVariableName(child)}`).join(",")}
|
|
330
|
+
}`;
|
|
331
|
+
const children2 = `const ${route}Children${TYPES_DISABLED ? "" : `: ${route}Children`} = {
|
|
332
|
+
${node.children.map((child) => `${child.variableName}Route: ${getResolvedRouteNodeVariableName(child)}`).join(",")}
|
|
333
|
+
}`;
|
|
334
|
+
const routeWithChildren = `const ${route}WithChildren = ${route}._addFileChildren(${route}Children)`;
|
|
335
|
+
return [
|
|
336
|
+
childConfigs,
|
|
337
|
+
childrenDeclaration,
|
|
338
|
+
children2,
|
|
339
|
+
routeWithChildren
|
|
340
|
+
].join("\n\n");
|
|
294
341
|
}
|
|
295
|
-
return
|
|
342
|
+
return void 0;
|
|
296
343
|
});
|
|
297
|
-
return children.filter(Boolean).join(
|
|
344
|
+
return children.filter(Boolean).join("\n\n");
|
|
298
345
|
}
|
|
299
|
-
const routeConfigChildrenText =
|
|
346
|
+
const routeConfigChildrenText = buildRouteTreeConfig(routeTree);
|
|
300
347
|
const sortedRouteNodes = multiSortBy(routeNodes, [
|
|
301
348
|
(d) => {
|
|
302
349
|
var _a;
|
|
@@ -308,10 +355,25 @@ async function generator(config) {
|
|
|
308
355
|
},
|
|
309
356
|
(d) => {
|
|
310
357
|
var _a;
|
|
311
|
-
return ((_a = d.routePath) == null ? void 0 : _a.endsWith(
|
|
358
|
+
return ((_a = d.routePath) == null ? void 0 : _a.endsWith(config.indexToken)) ? -1 : 1;
|
|
312
359
|
},
|
|
313
360
|
(d) => d
|
|
314
361
|
]);
|
|
362
|
+
const typeImports = Object.entries({
|
|
363
|
+
// Used for augmentation of regular routes
|
|
364
|
+
CreateFileRoute: config.verboseFileRoutes === false && sortedRouteNodes.some(
|
|
365
|
+
(d) => isRouteNodeValidForAugmentation(d) && d._fsRouteType !== "lazy"
|
|
366
|
+
),
|
|
367
|
+
// Used for augmentation of lazy (`.lazy`) routes
|
|
368
|
+
CreateLazyFileRoute: config.verboseFileRoutes === false && sortedRouteNodes.some(
|
|
369
|
+
(node) => {
|
|
370
|
+
var _a;
|
|
371
|
+
return ((_a = routePiecesByPath[node.routePath]) == null ? void 0 : _a.lazy) && isRouteNodeValidForAugmentation(node);
|
|
372
|
+
}
|
|
373
|
+
),
|
|
374
|
+
// Used in the process of augmenting the routes
|
|
375
|
+
FileRoutesByPath: config.verboseFileRoutes === false && sortedRouteNodes.some((d) => isRouteNodeValidForAugmentation(d))
|
|
376
|
+
}).filter((d) => d[1]).map((d) => d[0]).sort((a, b) => a.localeCompare(b));
|
|
315
377
|
const imports = Object.entries({
|
|
316
378
|
createFileRoute: sortedRouteNodes.some((d) => d.isVirtual),
|
|
317
379
|
lazyFn: sortedRouteNodes.some(
|
|
@@ -328,43 +390,36 @@ async function generator(config) {
|
|
|
328
390
|
)
|
|
329
391
|
}).filter((d) => d[1]).map((d) => d[0]);
|
|
330
392
|
const virtualRouteNodes = sortedRouteNodes.filter((d) => d.isVirtual);
|
|
331
|
-
|
|
393
|
+
function getImportPath(node) {
|
|
394
|
+
return replaceBackslash(
|
|
395
|
+
removeExt(
|
|
396
|
+
path.relative(
|
|
397
|
+
path.dirname(config.generatedRouteTree),
|
|
398
|
+
path.resolve(config.routesDirectory, node.filePath)
|
|
399
|
+
),
|
|
400
|
+
config.addExtensions
|
|
401
|
+
)
|
|
402
|
+
);
|
|
403
|
+
}
|
|
332
404
|
const routeImports = [
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
` : ""
|
|
405
|
+
...config.routeTreeFileHeader,
|
|
406
|
+
`// This file was automatically generated by TanStack Router.
|
|
407
|
+
// You should NOT make any changes in this file as it will be overwritten.
|
|
408
|
+
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.`,
|
|
409
|
+
[
|
|
410
|
+
imports.length ? `import { ${imports.join(", ")} } from '${ROUTE_TEMPLATE.fullPkg}'` : "",
|
|
411
|
+
!TYPES_DISABLED && typeImports.length ? `import type { ${typeImports.join(", ")} } from '${ROUTE_TEMPLATE.fullPkg}'` : ""
|
|
412
|
+
].filter(Boolean).join("\n"),
|
|
340
413
|
"// Import Routes",
|
|
341
414
|
[
|
|
342
|
-
`import { Route as rootRoute } from './${
|
|
343
|
-
path.relative(
|
|
344
|
-
path.dirname(config.generatedRouteTree),
|
|
345
|
-
path.resolve(
|
|
346
|
-
config.routesDirectory,
|
|
347
|
-
`${routePathIdPrefix}${rootPathId}${rootPathIdExtension}`
|
|
348
|
-
)
|
|
349
|
-
)
|
|
350
|
-
)}'`,
|
|
415
|
+
`import { Route as rootRoute } from './${getImportPath(rootRouteNode)}'`,
|
|
351
416
|
...sortedRouteNodes.filter((d) => !d.isVirtual).map((node) => {
|
|
352
|
-
return `import { Route as ${node.variableName}
|
|
353
|
-
removeExt(
|
|
354
|
-
path.relative(
|
|
355
|
-
path.dirname(config.generatedRouteTree),
|
|
356
|
-
path.resolve(config.routesDirectory, node.filePath)
|
|
357
|
-
),
|
|
358
|
-
config.addExtensions
|
|
359
|
-
)
|
|
360
|
-
)}'`;
|
|
417
|
+
return `import { Route as ${node.variableName}RouteImport } from './${getImportPath(node)}'`;
|
|
361
418
|
})
|
|
362
419
|
].join("\n"),
|
|
363
420
|
virtualRouteNodes.length ? "// Create Virtual Routes" : "",
|
|
364
421
|
virtualRouteNodes.map((node) => {
|
|
365
|
-
return `const ${node.variableName}
|
|
366
|
-
node.routePath
|
|
367
|
-
)}')()`;
|
|
422
|
+
return `const ${node.variableName}RouteImport = createFileRoute('${node.routePath}')()`;
|
|
368
423
|
}).join("\n"),
|
|
369
424
|
"// Create/Update Routes",
|
|
370
425
|
sortedRouteNodes.map((node) => {
|
|
@@ -375,155 +430,221 @@ async function generator(config) {
|
|
|
375
430
|
const pendingComponentNode = (_d = routePiecesByPath[node.routePath]) == null ? void 0 : _d.pendingComponent;
|
|
376
431
|
const lazyComponentNode = (_e = routePiecesByPath[node.routePath]) == null ? void 0 : _e.lazy;
|
|
377
432
|
return [
|
|
378
|
-
|
|
433
|
+
[
|
|
434
|
+
`const ${node.variableName}Route = ${node.variableName}RouteImport.update({
|
|
379
435
|
${[
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
path.relative(
|
|
387
|
-
path.dirname(config.generatedRouteTree),
|
|
388
|
-
path.resolve(config.routesDirectory, loaderNode.filePath)
|
|
389
|
-
),
|
|
390
|
-
config.addExtensions
|
|
391
|
-
)
|
|
392
|
-
)}'), 'loader') })` : "",
|
|
393
|
-
componentNode || errorComponentNode || pendingComponentNode ? `.update({
|
|
394
|
-
${[
|
|
395
|
-
["component", componentNode],
|
|
396
|
-
["errorComponent", errorComponentNode],
|
|
397
|
-
["pendingComponent", pendingComponentNode]
|
|
398
|
-
].filter((d) => d[1]).map((d) => {
|
|
399
|
-
return `${d[0]}: lazyRouteComponent(() => import('./${replaceBackslash(
|
|
436
|
+
`id: '${node.path}'`,
|
|
437
|
+
!node.isNonPath ? `path: '${node.cleanedPath}'` : void 0,
|
|
438
|
+
`getParentRoute: () => ${((_f = node.parent) == null ? void 0 : _f.variableName) ?? "root"}Route`
|
|
439
|
+
].filter(Boolean).join(",")}
|
|
440
|
+
}${TYPES_DISABLED ? "" : "as any"})`,
|
|
441
|
+
loaderNode ? `.updateLoader({ loader: lazyFn(() => import('./${replaceBackslash(
|
|
400
442
|
removeExt(
|
|
401
443
|
path.relative(
|
|
402
444
|
path.dirname(config.generatedRouteTree),
|
|
403
|
-
path.resolve(config.routesDirectory,
|
|
445
|
+
path.resolve(config.routesDirectory, loaderNode.filePath)
|
|
404
446
|
),
|
|
405
447
|
config.addExtensions
|
|
406
448
|
)
|
|
407
|
-
)}'), '
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
449
|
+
)}'), 'loader') })` : "",
|
|
450
|
+
componentNode || errorComponentNode || pendingComponentNode ? `.update({
|
|
451
|
+
${[
|
|
452
|
+
["component", componentNode],
|
|
453
|
+
["errorComponent", errorComponentNode],
|
|
454
|
+
["pendingComponent", pendingComponentNode]
|
|
455
|
+
].filter((d) => d[1]).map((d) => {
|
|
456
|
+
return `${d[0]}: lazyRouteComponent(() => import('./${replaceBackslash(
|
|
457
|
+
removeExt(
|
|
458
|
+
path.relative(
|
|
459
|
+
path.dirname(config.generatedRouteTree),
|
|
460
|
+
path.resolve(config.routesDirectory, d[1].filePath)
|
|
461
|
+
),
|
|
462
|
+
config.addExtensions
|
|
417
463
|
)
|
|
418
|
-
),
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
464
|
+
)}'), '${d[0]}')`;
|
|
465
|
+
}).join("\n,")}
|
|
466
|
+
})` : "",
|
|
467
|
+
lazyComponentNode ? `.lazy(() => import('./${replaceBackslash(
|
|
468
|
+
removeExt(
|
|
469
|
+
path.relative(
|
|
470
|
+
path.dirname(config.generatedRouteTree),
|
|
471
|
+
path.resolve(
|
|
472
|
+
config.routesDirectory,
|
|
473
|
+
lazyComponentNode.filePath
|
|
474
|
+
)
|
|
475
|
+
),
|
|
476
|
+
config.addExtensions
|
|
477
|
+
)
|
|
478
|
+
)}').then((d) => d.Route))` : ""
|
|
479
|
+
].join("")
|
|
480
|
+
].join("\n\n");
|
|
423
481
|
}).join("\n\n"),
|
|
424
|
-
...
|
|
482
|
+
...TYPES_DISABLED ? [] : [
|
|
425
483
|
"// Populate the FileRoutesByPath interface",
|
|
426
|
-
`declare module '
|
|
484
|
+
`declare module '${ROUTE_TEMPLATE.fullPkg}' {
|
|
427
485
|
interface FileRoutesByPath {
|
|
428
486
|
${routeNodes.map((routeNode) => {
|
|
429
|
-
var _a, _b
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
487
|
+
var _a, _b;
|
|
488
|
+
const filePathId = routeNode.routePath;
|
|
489
|
+
return `'${filePathId}': {
|
|
490
|
+
id: '${filePathId}'
|
|
491
|
+
path: '${inferPath(routeNode)}'
|
|
492
|
+
fullPath: '${inferFullPath(routeNode)}'
|
|
493
|
+
preLoaderRoute: typeof ${routeNode.variableName}RouteImport
|
|
494
|
+
parentRoute: typeof ${routeNode.isVirtualParentRequired ? `${(_a = routeNode.parent) == null ? void 0 : _a.variableName}Route` : ((_b = routeNode.parent) == null ? void 0 : _b.variableName) ? `${routeNode.parent.variableName}RouteImport` : "rootRoute"}
|
|
433
495
|
}`;
|
|
434
496
|
}).join("\n")}
|
|
435
497
|
}
|
|
436
498
|
}`
|
|
437
499
|
],
|
|
500
|
+
...TYPES_DISABLED ? [] : config.verboseFileRoutes !== false ? [] : [
|
|
501
|
+
`// Add type-safety to the createFileRoute function across the route tree`,
|
|
502
|
+
routeNodes.map((routeNode) => {
|
|
503
|
+
var _a;
|
|
504
|
+
function getModuleDeclaration(routeNode2) {
|
|
505
|
+
if (!isRouteNodeValidForAugmentation(routeNode2)) {
|
|
506
|
+
return "";
|
|
507
|
+
}
|
|
508
|
+
return `declare module './${getImportPath(routeNode2)}' {
|
|
509
|
+
const ${routeNode2._fsRouteType === "lazy" ? "createLazyFileRoute" : "createFileRoute"}: ${routeNode2._fsRouteType === "lazy" ? `CreateLazyFileRoute<FileRoutesByPath['${routeNode2.routePath}']['preLoaderRoute']>}` : `CreateFileRoute<
|
|
510
|
+
'${routeNode2.routePath}',
|
|
511
|
+
FileRoutesByPath['${routeNode2.routePath}']['parentRoute'],
|
|
512
|
+
FileRoutesByPath['${routeNode2.routePath}']['id'],
|
|
513
|
+
FileRoutesByPath['${routeNode2.routePath}']['path'],
|
|
514
|
+
FileRoutesByPath['${routeNode2.routePath}']['fullPath']
|
|
515
|
+
>
|
|
516
|
+
}`}`;
|
|
517
|
+
}
|
|
518
|
+
return getModuleDeclaration(routeNode) + getModuleDeclaration(
|
|
519
|
+
(_a = routePiecesByPath[routeNode.routePath]) == null ? void 0 : _a.lazy
|
|
520
|
+
);
|
|
521
|
+
}).join("\n")
|
|
522
|
+
],
|
|
438
523
|
"// Create and export the route tree",
|
|
439
|
-
|
|
440
|
-
|
|
524
|
+
routeConfigChildrenText,
|
|
525
|
+
...TYPES_DISABLED ? [] : [
|
|
526
|
+
`export interface FileRoutesByFullPath {
|
|
527
|
+
${[...createRouteNodesByFullPath(routeNodes).entries()].map(
|
|
528
|
+
([fullPath, routeNode]) => {
|
|
529
|
+
return `'${fullPath}': typeof ${getResolvedRouteNodeVariableName(routeNode)}`;
|
|
530
|
+
}
|
|
531
|
+
)}
|
|
532
|
+
}`,
|
|
533
|
+
`export interface FileRoutesByTo {
|
|
534
|
+
${[...createRouteNodesByTo(routeNodes).entries()].map(([to, routeNode]) => {
|
|
535
|
+
return `'${to}': typeof ${getResolvedRouteNodeVariableName(routeNode)}`;
|
|
536
|
+
})}
|
|
537
|
+
}`,
|
|
538
|
+
`export interface FileRoutesById {
|
|
539
|
+
'${rootRouteId}': typeof rootRoute,
|
|
540
|
+
${[...createRouteNodesById(routeNodes).entries()].map(([id, routeNode]) => {
|
|
541
|
+
return `'${id}': typeof ${getResolvedRouteNodeVariableName(routeNode)}`;
|
|
542
|
+
})}
|
|
543
|
+
}`,
|
|
544
|
+
`export interface FileRouteTypes {
|
|
545
|
+
fileRoutesByFullPath: FileRoutesByFullPath
|
|
546
|
+
fullPaths: ${routeNodes.length > 0 ? [...createRouteNodesByFullPath(routeNodes).keys()].map((fullPath) => `'${fullPath}'`).join("|") : "never"}
|
|
547
|
+
fileRoutesByTo: FileRoutesByTo
|
|
548
|
+
to: ${routeNodes.length > 0 ? [...createRouteNodesByTo(routeNodes).keys()].map((to) => `'${to}'`).join("|") : "never"}
|
|
549
|
+
id: ${[`'${rootRouteId}'`, ...[...createRouteNodesById(routeNodes).keys()].map((id) => `'${id}'`)].join("|")}
|
|
550
|
+
fileRoutesById: FileRoutesById
|
|
551
|
+
}`,
|
|
552
|
+
`export interface RootRouteChildren {
|
|
553
|
+
${routeTree.map((child) => `${child.variableName}Route: typeof ${getResolvedRouteNodeVariableName(child)}`).join(",")}
|
|
554
|
+
}`
|
|
555
|
+
],
|
|
556
|
+
`const rootRouteChildren${TYPES_DISABLED ? "" : ": RootRouteChildren"} = {
|
|
557
|
+
${routeTree.map((child) => `${child.variableName}Route: ${getResolvedRouteNodeVariableName(child)}`).join(",")}
|
|
558
|
+
}`,
|
|
559
|
+
`export const routeTree = rootRoute._addFileChildren(rootRouteChildren)${TYPES_DISABLED ? "" : "._addFileTypes<FileRouteTypes>()"}`,
|
|
560
|
+
...config.routeTreeFileFooter
|
|
441
561
|
].filter(Boolean).join("\n\n");
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
562
|
+
const createRouteManifest = () => {
|
|
563
|
+
const routesManifest = {
|
|
564
|
+
[rootRouteId]: {
|
|
565
|
+
filePath: rootRouteNode.filePath,
|
|
566
|
+
children: routeTree.map((d) => d.routePath)
|
|
567
|
+
},
|
|
568
|
+
...Object.fromEntries(
|
|
569
|
+
routeNodes.map((d) => {
|
|
570
|
+
var _a, _b;
|
|
571
|
+
const filePathId = d.routePath;
|
|
572
|
+
return [
|
|
573
|
+
filePathId,
|
|
574
|
+
{
|
|
575
|
+
filePath: d.filePath,
|
|
576
|
+
parent: ((_a = d.parent) == null ? void 0 : _a.routePath) ? d.parent.routePath : void 0,
|
|
577
|
+
children: (_b = d.children) == null ? void 0 : _b.map((childRoute) => childRoute.routePath)
|
|
578
|
+
}
|
|
579
|
+
];
|
|
580
|
+
})
|
|
581
|
+
)
|
|
582
|
+
};
|
|
583
|
+
return JSON.stringify(
|
|
584
|
+
{
|
|
585
|
+
routes: routesManifest
|
|
586
|
+
},
|
|
587
|
+
null,
|
|
588
|
+
2
|
|
589
|
+
);
|
|
590
|
+
};
|
|
591
|
+
const includeManifest = ["react", "solid"];
|
|
592
|
+
const routeConfigFileContent = config.disableManifestGeneration || !includeManifest.includes(config.target) ? routeImports : [
|
|
593
|
+
routeImports,
|
|
594
|
+
"\n",
|
|
595
|
+
"/* ROUTE_MANIFEST_START",
|
|
596
|
+
createRouteManifest(),
|
|
597
|
+
"ROUTE_MANIFEST_END */"
|
|
598
|
+
].join("\n");
|
|
599
|
+
if (!checkLatest()) return;
|
|
600
|
+
const existingRouteTreeContent = await fsp.readFile(path.resolve(config.generatedRouteTree), "utf-8").catch((err) => {
|
|
448
601
|
if (err.code === "ENOENT") {
|
|
449
|
-
return
|
|
602
|
+
return "";
|
|
450
603
|
}
|
|
451
604
|
throw err;
|
|
452
605
|
});
|
|
453
|
-
if (!checkLatest())
|
|
606
|
+
if (!checkLatest()) return;
|
|
607
|
+
await fsp.mkdir(path.dirname(path.resolve(config.generatedRouteTree)), {
|
|
608
|
+
recursive: true
|
|
609
|
+
});
|
|
610
|
+
if (!checkLatest()) return;
|
|
611
|
+
const routeTreeWriteResult = await writeIfDifferent(
|
|
612
|
+
path.resolve(config.generatedRouteTree),
|
|
613
|
+
config.enableRouteTreeFormatting ? await format(existingRouteTreeContent, config) : existingRouteTreeContent,
|
|
614
|
+
config.enableRouteTreeFormatting ? await format(routeConfigFileContent, config) : routeConfigFileContent,
|
|
615
|
+
{
|
|
616
|
+
beforeWrite: () => {
|
|
617
|
+
logger.log(`🟡 Updating ${config.generatedRouteTree}`);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
);
|
|
621
|
+
if (routeTreeWriteResult && !checkLatest()) {
|
|
454
622
|
return;
|
|
455
|
-
if (routeTreeContent !== routeConfigFileContent) {
|
|
456
|
-
await fsp.mkdir(path.dirname(path.resolve(config.generatedRouteTree)), {
|
|
457
|
-
recursive: true
|
|
458
|
-
});
|
|
459
|
-
if (!checkLatest())
|
|
460
|
-
return;
|
|
461
|
-
await fsp.writeFile(
|
|
462
|
-
path.resolve(config.generatedRouteTree),
|
|
463
|
-
routeConfigFileContent
|
|
464
|
-
);
|
|
465
623
|
}
|
|
466
624
|
logger.log(
|
|
467
625
|
`✅ Processed ${routeNodes.length === 1 ? "route" : "routes"} in ${Date.now() - start}ms`
|
|
468
626
|
);
|
|
469
627
|
}
|
|
470
|
-
function routePathToVariable(d) {
|
|
471
|
-
var _a, _b, _c, _d;
|
|
472
|
-
return ((_d = (_c = (_b = (_a = removeUnderscores(d)) == null ? void 0 : _a.replace(/\/\$\//g, "/splat/")) == null ? void 0 : _b.replace(/\$$/g, "splat")) == null ? void 0 : _c.replace(/\$/g, "")) == null ? void 0 : _d.split(/[/-]/g).map((d2, i) => i > 0 ? capitalize(d2) : d2).join("").replace(/([^a-zA-Z0-9]|[\.])/gm, "").replace(/^(\d)/g, "R$1")) ?? "";
|
|
473
|
-
}
|
|
474
|
-
function removeExt(d, keepExtension = false) {
|
|
475
|
-
return keepExtension ? d : d.substring(0, d.lastIndexOf(".")) || d;
|
|
476
|
-
}
|
|
477
|
-
function spaces(d) {
|
|
478
|
-
return Array.from({ length: d }).map(() => " ").join("");
|
|
479
|
-
}
|
|
480
|
-
function multiSortBy(arr, accessors = [(d) => d]) {
|
|
481
|
-
return arr.map((d, i) => [d, i]).sort(([a, ai], [b, bi]) => {
|
|
482
|
-
for (const accessor of accessors) {
|
|
483
|
-
const ao = accessor(a);
|
|
484
|
-
const bo = accessor(b);
|
|
485
|
-
if (typeof ao === "undefined") {
|
|
486
|
-
if (typeof bo === "undefined") {
|
|
487
|
-
continue;
|
|
488
|
-
}
|
|
489
|
-
return 1;
|
|
490
|
-
}
|
|
491
|
-
if (ao === bo) {
|
|
492
|
-
continue;
|
|
493
|
-
}
|
|
494
|
-
return ao > bo ? 1 : -1;
|
|
495
|
-
}
|
|
496
|
-
return ai - bi;
|
|
497
|
-
}).map(([d]) => d);
|
|
498
|
-
}
|
|
499
|
-
function capitalize(s) {
|
|
500
|
-
if (typeof s !== "string")
|
|
501
|
-
return "";
|
|
502
|
-
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
503
|
-
}
|
|
504
|
-
function removeUnderscores(s) {
|
|
505
|
-
return s == null ? void 0 : s.replaceAll(/(^_|_$)/gi, "").replaceAll(/(\/_|_\/)/gi, "/");
|
|
506
|
-
}
|
|
507
|
-
function removeTrailingUnderscores(s) {
|
|
508
|
-
return s == null ? void 0 : s.replaceAll(/(_$)/gi, "").replaceAll(/(_\/)/gi, "/");
|
|
509
|
-
}
|
|
510
|
-
function replaceBackslash(s) {
|
|
511
|
-
return s.replaceAll(/\\/gi, "/");
|
|
512
|
-
}
|
|
513
628
|
function removeGroups(s) {
|
|
514
|
-
return s.
|
|
629
|
+
return s.replace(possiblyNestedRouteGroupPatternRegex, "");
|
|
630
|
+
}
|
|
631
|
+
function isRouteNodeValidForAugmentation(routeNode) {
|
|
632
|
+
if (!routeNode || routeNode.isVirtual) {
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
return true;
|
|
515
636
|
}
|
|
516
637
|
function determineNodePath(node) {
|
|
517
638
|
var _a;
|
|
518
|
-
return node.path = node.parent ? ((_a = node.routePath) == null ? void 0 : _a.replace(node.parent.routePath, "")) || "/" : node.routePath;
|
|
639
|
+
return node.path = node.parent ? ((_a = node.routePath) == null ? void 0 : _a.replace(node.parent.routePath ?? "", "")) || "/" : node.routePath;
|
|
519
640
|
}
|
|
520
|
-
function removeLastSegmentFromPath(
|
|
521
|
-
const segments =
|
|
641
|
+
function removeLastSegmentFromPath(routePath = "/") {
|
|
642
|
+
const segments = routePath.split("/");
|
|
522
643
|
segments.pop();
|
|
523
644
|
return segments.join("/");
|
|
524
645
|
}
|
|
525
|
-
function removeLayoutSegments(
|
|
526
|
-
const segments =
|
|
646
|
+
function removeLayoutSegments(routePath = "/") {
|
|
647
|
+
const segments = routePath.split("/");
|
|
527
648
|
const newSegments = segments.filter((segment) => !segment.startsWith("_"));
|
|
528
649
|
return newSegments.join("/");
|
|
529
650
|
}
|
|
@@ -536,8 +657,7 @@ function hasParentRoute(routes, node, routePathToCheck) {
|
|
|
536
657
|
(d) => d.variableName
|
|
537
658
|
]).filter((d) => d.routePath !== `/${rootPathId}`);
|
|
538
659
|
for (const route of sortedNodes) {
|
|
539
|
-
if (route.routePath === "/")
|
|
540
|
-
continue;
|
|
660
|
+
if (route.routePath === "/") continue;
|
|
541
661
|
if (routePathToCheck.startsWith(`${route.routePath}/`) && route.routePath !== routePathToCheck) {
|
|
542
662
|
return route;
|
|
543
663
|
}
|
|
@@ -547,12 +667,81 @@ function hasParentRoute(routes, node, routePathToCheck) {
|
|
|
547
667
|
const parentRoutePath = segments.join("/");
|
|
548
668
|
return hasParentRoute(routes, node, parentRoutePath);
|
|
549
669
|
}
|
|
670
|
+
const getResolvedRouteNodeVariableName = (routeNode) => {
|
|
671
|
+
var _a;
|
|
672
|
+
return ((_a = routeNode.children) == null ? void 0 : _a.length) ? `${routeNode.variableName}RouteWithChildren` : `${routeNode.variableName}Route`;
|
|
673
|
+
};
|
|
674
|
+
const createRouteNodesByFullPath = (routeNodes) => {
|
|
675
|
+
return new Map(
|
|
676
|
+
routeNodes.map((routeNode) => [inferFullPath(routeNode), routeNode])
|
|
677
|
+
);
|
|
678
|
+
};
|
|
679
|
+
const createRouteNodesByTo = (routeNodes) => {
|
|
680
|
+
return new Map(
|
|
681
|
+
dedupeBranchesAndIndexRoutes(routeNodes).map((routeNode) => [
|
|
682
|
+
inferTo(routeNode),
|
|
683
|
+
routeNode
|
|
684
|
+
])
|
|
685
|
+
);
|
|
686
|
+
};
|
|
687
|
+
const createRouteNodesById = (routeNodes) => {
|
|
688
|
+
return new Map(
|
|
689
|
+
routeNodes.map((routeNode) => {
|
|
690
|
+
const id = routeNode.routePath ?? "";
|
|
691
|
+
return [id, routeNode];
|
|
692
|
+
})
|
|
693
|
+
);
|
|
694
|
+
};
|
|
695
|
+
const inferFullPath = (routeNode) => {
|
|
696
|
+
const fullPath = removeGroups(
|
|
697
|
+
removeUnderscores(removeLayoutSegments(routeNode.routePath)) ?? ""
|
|
698
|
+
);
|
|
699
|
+
return routeNode.cleanedPath === "/" ? fullPath : fullPath.replace(/\/$/, "");
|
|
700
|
+
};
|
|
701
|
+
const inferPath = (routeNode) => {
|
|
702
|
+
var _a;
|
|
703
|
+
return routeNode.cleanedPath === "/" ? routeNode.cleanedPath : ((_a = routeNode.cleanedPath) == null ? void 0 : _a.replace(/\/$/, "")) ?? "";
|
|
704
|
+
};
|
|
705
|
+
const inferTo = (routeNode) => {
|
|
706
|
+
const fullPath = inferFullPath(routeNode);
|
|
707
|
+
if (fullPath === "/") return fullPath;
|
|
708
|
+
return fullPath.replace(/\/$/, "");
|
|
709
|
+
};
|
|
710
|
+
const dedupeBranchesAndIndexRoutes = (routes) => {
|
|
711
|
+
return routes.filter((route) => {
|
|
712
|
+
var _a;
|
|
713
|
+
if ((_a = route.children) == null ? void 0 : _a.find((child) => child.cleanedPath === "/")) return false;
|
|
714
|
+
return true;
|
|
715
|
+
});
|
|
716
|
+
};
|
|
717
|
+
function checkUnique(routes, key) {
|
|
718
|
+
const keys = routes.map((d) => d[key]);
|
|
719
|
+
const uniqueKeys = new Set(keys);
|
|
720
|
+
if (keys.length !== uniqueKeys.size) {
|
|
721
|
+
const duplicateKeys = keys.filter((d, i) => keys.indexOf(d) !== i);
|
|
722
|
+
const conflictingFiles = routes.filter(
|
|
723
|
+
(d) => duplicateKeys.includes(d[key])
|
|
724
|
+
);
|
|
725
|
+
return conflictingFiles;
|
|
726
|
+
}
|
|
727
|
+
return void 0;
|
|
728
|
+
}
|
|
729
|
+
function checkRouteFullPathUniqueness(_routes, config) {
|
|
730
|
+
const routes = _routes.map((d) => {
|
|
731
|
+
const inferredFullPath = inferFullPath(d);
|
|
732
|
+
return { ...d, inferredFullPath };
|
|
733
|
+
});
|
|
734
|
+
const conflictingFiles = checkUnique(routes, "inferredFullPath");
|
|
735
|
+
if (conflictingFiles !== void 0) {
|
|
736
|
+
const errorMessage = `Conflicting configuration paths were found for the following route${conflictingFiles.length > 1 ? "s" : ""}: ${conflictingFiles.map((p) => `"${p.inferredFullPath}"`).join(", ")}.
|
|
737
|
+
Please ensure each Route has a unique full path.
|
|
738
|
+
Conflicting files:
|
|
739
|
+
${conflictingFiles.map((d) => path.resolve(config.routesDirectory, d.filePath)).join("\n ")}
|
|
740
|
+
`;
|
|
741
|
+
throw new Error(errorMessage);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
550
744
|
export {
|
|
551
|
-
generator
|
|
552
|
-
hasParentRoute,
|
|
553
|
-
multiSortBy,
|
|
554
|
-
removeExt,
|
|
555
|
-
removeLastSegmentFromPath,
|
|
556
|
-
rootPathId
|
|
745
|
+
generator
|
|
557
746
|
};
|
|
558
747
|
//# sourceMappingURL=generator.js.map
|