@tanstack/router-cli 0.0.1-beta.151 → 0.0.1-beta.153
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/build/cjs/config.js +9 -1
- package/build/cjs/config.js.map +1 -1
- package/build/cjs/generator.js +161 -154
- package/build/cjs/generator.js.map +1 -1
- package/build/cjs/watch.js +12 -12
- package/build/cjs/watch.js.map +1 -1
- package/package.json +5 -2
- package/src/config.ts +12 -7
- package/src/generator.ts +209 -230
- package/src/watch.ts +16 -13
package/build/cjs/config.js
CHANGED
|
@@ -14,15 +14,23 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
14
14
|
|
|
15
15
|
var path = require('path');
|
|
16
16
|
var fs = require('fs-extra');
|
|
17
|
+
var zod = require('zod');
|
|
17
18
|
|
|
18
19
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
19
20
|
|
|
20
21
|
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
21
22
|
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
22
23
|
|
|
24
|
+
const configSchema = zod.z.object({
|
|
25
|
+
routeFilePrefix: zod.z.string().optional(),
|
|
26
|
+
routeFileIgnorePrefix: zod.z.string().optional(),
|
|
27
|
+
routesDirectory: zod.z.string(),
|
|
28
|
+
generatedRouteTree: zod.z.string()
|
|
29
|
+
});
|
|
23
30
|
const configFilePathJson = path__default["default"].resolve(process.cwd(), 'tsr.config.json');
|
|
24
31
|
async function getConfig() {
|
|
25
|
-
|
|
32
|
+
const config = await fs__default["default"].readJson(configFilePathJson);
|
|
33
|
+
return configSchema.parse(config);
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
exports.getConfig = getConfig;
|
package/build/cjs/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sources":["../../src/config.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\n\
|
|
1
|
+
{"version":3,"file":"config.js","sources":["../../src/config.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\nimport { z } from 'zod'\n\nconst configSchema = z.object({\n routeFilePrefix: z.string().optional(),\n routeFileIgnorePrefix: z.string().optional(),\n routesDirectory: z.string(),\n generatedRouteTree: z.string(),\n})\n\nexport type Config = z.infer<typeof configSchema>\n\nconst configFilePathJson = path.resolve(process.cwd(), 'tsr.config.json')\n\nexport async function getConfig() {\n const config = (await fs.readJson(configFilePathJson)) as unknown as Config\n\n return configSchema.parse(config)\n}\n"],"names":["configSchema","z","object","routeFilePrefix","string","optional","routeFileIgnorePrefix","routesDirectory","generatedRouteTree","configFilePathJson","path","resolve","process","cwd","getConfig","config","fs","readJson","parse"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAIA,MAAMA,YAAY,GAAGC,KAAC,CAACC,MAAM,CAAC;EAC5BC,eAAe,EAAEF,KAAC,CAACG,MAAM,EAAE,CAACC,QAAQ,EAAE;EACtCC,qBAAqB,EAAEL,KAAC,CAACG,MAAM,EAAE,CAACC,QAAQ,EAAE;AAC5CE,EAAAA,eAAe,EAAEN,KAAC,CAACG,MAAM,EAAE;AAC3BI,EAAAA,kBAAkB,EAAEP,KAAC,CAACG,MAAM,EAAC;AAC/B,CAAC,CAAC,CAAA;AAIF,MAAMK,kBAAkB,GAAGC,wBAAI,CAACC,OAAO,CAACC,OAAO,CAACC,GAAG,EAAE,EAAE,iBAAiB,CAAC,CAAA;AAElE,eAAeC,SAASA,GAAG;EAChC,MAAMC,MAAM,GAAI,MAAMC,sBAAE,CAACC,QAAQ,CAACR,kBAAkB,CAAuB,CAAA;AAE3E,EAAA,OAAOT,YAAY,CAACkB,KAAK,CAACH,MAAM,CAAC,CAAA;AACnC;;;;"}
|
package/build/cjs/generator.js
CHANGED
|
@@ -14,44 +14,98 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
14
14
|
|
|
15
15
|
var path = require('path');
|
|
16
16
|
var fs = require('fs-extra');
|
|
17
|
-
var
|
|
17
|
+
var prettier = require('prettier');
|
|
18
|
+
var routerCore = require('@tanstack/router-core');
|
|
18
19
|
|
|
19
20
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
20
21
|
|
|
22
|
+
function _interopNamespace(e) {
|
|
23
|
+
if (e && e.__esModule) return e;
|
|
24
|
+
var n = Object.create(null);
|
|
25
|
+
if (e) {
|
|
26
|
+
Object.keys(e).forEach(function (k) {
|
|
27
|
+
if (k !== 'default') {
|
|
28
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
29
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
get: function () { return e[k]; }
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
n["default"] = e;
|
|
37
|
+
return Object.freeze(n);
|
|
38
|
+
}
|
|
39
|
+
|
|
21
40
|
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
22
41
|
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
23
|
-
var
|
|
42
|
+
var prettier__namespace = /*#__PURE__*/_interopNamespace(prettier);
|
|
24
43
|
|
|
25
44
|
let latestTask = 0;
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
async function
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
45
|
+
const rootPathId = '__root';
|
|
46
|
+
const fileRouteRegex = /new\s+FileRoute\(([^)]*)\)/g;
|
|
47
|
+
async function getRouteNodes(config) {
|
|
48
|
+
const {
|
|
49
|
+
routeFilePrefix,
|
|
50
|
+
routeFileIgnorePrefix
|
|
51
|
+
} = config;
|
|
52
|
+
let routeNodes = [];
|
|
53
|
+
async function recurse(dir) {
|
|
54
|
+
const fullDir = path__default["default"].resolve(config.routesDirectory, dir);
|
|
55
|
+
let dirList = await fs__default["default"].readdir(fullDir);
|
|
56
|
+
dirList = dirList.filter(d => {
|
|
57
|
+
if (d.startsWith('.') || d.startsWith(routeFileIgnorePrefix)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
if (routeFilePrefix) {
|
|
61
|
+
return d.startsWith(routeFilePrefix);
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
await Promise.all(dirList.map(async fileName => {
|
|
66
|
+
const fullPath = path__default["default"].join(fullDir, fileName);
|
|
67
|
+
const relativePath = path__default["default"].join(dir, fileName);
|
|
68
|
+
const stat = await fs__default["default"].stat(fullPath);
|
|
69
|
+
if (stat.isDirectory()) {
|
|
70
|
+
await recurse(relativePath);
|
|
71
|
+
} else {
|
|
72
|
+
const filePath = path__default["default"].join(dir, fileName);
|
|
73
|
+
const filePathNoExt = removeExt(filePath);
|
|
74
|
+
let routePath = routerCore.cleanPath(`/${filePathNoExt.split('.').join('/')}`);
|
|
75
|
+
const variableName = fileToVariable(routePath);
|
|
76
|
+
|
|
77
|
+
// Remove the index from the route path and
|
|
78
|
+
// if the route path is empty, use `/'
|
|
79
|
+
if (routePath.endsWith('/index')) {
|
|
80
|
+
routePath = routePath.replace(/\/index$/, '/');
|
|
81
|
+
} else if (routePath === 'index') {
|
|
82
|
+
routePath = '/';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// console.log(filePath)
|
|
33
86
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
87
|
+
routeNodes.push({
|
|
88
|
+
filePath,
|
|
89
|
+
fullPath,
|
|
90
|
+
routePath,
|
|
91
|
+
variableName
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}));
|
|
95
|
+
return routeNodes;
|
|
40
96
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
fullPath,
|
|
44
|
-
routePath,
|
|
45
|
-
variableName: fileToVariable(removeExt(filename))
|
|
46
|
-
};
|
|
97
|
+
await recurse('./');
|
|
98
|
+
return routeNodes;
|
|
47
99
|
}
|
|
100
|
+
let first = false;
|
|
101
|
+
let skipMessage = false;
|
|
48
102
|
async function generator(config) {
|
|
49
103
|
console.log();
|
|
50
|
-
|
|
51
|
-
if (!nodeCache) {
|
|
52
|
-
first = true;
|
|
104
|
+
if (!first) {
|
|
53
105
|
console.log('🔄 Generating routes...');
|
|
54
|
-
|
|
106
|
+
first = true;
|
|
107
|
+
} else if (skipMessage) {
|
|
108
|
+
skipMessage = false;
|
|
55
109
|
} else {
|
|
56
110
|
console.log('♻️ Regenerating routes...');
|
|
57
111
|
}
|
|
@@ -59,167 +113,116 @@ async function generator(config) {
|
|
|
59
113
|
latestTask = taskId;
|
|
60
114
|
const checkLatest = () => {
|
|
61
115
|
if (latestTask !== taskId) {
|
|
62
|
-
|
|
116
|
+
skipMessage = true;
|
|
63
117
|
return false;
|
|
64
118
|
}
|
|
65
119
|
return true;
|
|
66
120
|
};
|
|
67
121
|
const start = Date.now();
|
|
68
|
-
let
|
|
69
|
-
|
|
70
|
-
const fileQueue = [];
|
|
71
|
-
const queueWriteFile = (filename, content) => {
|
|
72
|
-
fileQueue.push([filename, content]);
|
|
73
|
-
};
|
|
74
|
-
let dirList;
|
|
75
|
-
try {
|
|
76
|
-
dirList = await fs__default["default"].readdir(config.routesDirectory);
|
|
77
|
-
} catch (err) {
|
|
78
|
-
console.log();
|
|
79
|
-
console.error('TSR: Error reading the config.routesDirectory. Does it exist?');
|
|
80
|
-
console.log();
|
|
81
|
-
throw err;
|
|
82
|
-
}
|
|
83
|
-
let routeNodes = await Promise.all(dirList.map(async filename => {
|
|
84
|
-
return createRouteNode(config, filename);
|
|
85
|
-
}));
|
|
86
|
-
routeNodes = multiSortBy(routeNodes, [d => d.routePath === '/' ? -1 : 1, d => d.routePath?.split('/').length, d => d.routePath?.endsWith('/') ? -1 : 1, d => d.routePath]).filter(d => d.routePath !== '_root');
|
|
122
|
+
let routeNodes = await getRouteNodes(config);
|
|
123
|
+
routeNodes = multiSortBy(routeNodes, [d => d.routePath === '/' ? -1 : 1, d => d.routePath?.split('/').length, d => d.routePath?.endsWith('/') ? -1 : 1, d => d.routePath]).filter(d => d.routePath !== `/${rootPathId}`);
|
|
87
124
|
const routeTree = [];
|
|
88
125
|
|
|
89
126
|
// Loop over the flat list of routeNodes and
|
|
90
127
|
// build up a tree based on the routeNodes' routePath
|
|
91
128
|
routeNodes.forEach(node => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (!parent.children) {
|
|
98
|
-
parent.children = [];
|
|
99
|
-
}
|
|
100
|
-
findParent(parent.children, node, parent);
|
|
101
|
-
} else {
|
|
102
|
-
node.path = node.routePath?.replace(parentNode?.routePath ?? '', '');
|
|
103
|
-
node.parent = parentNode;
|
|
104
|
-
existing.push(node);
|
|
129
|
+
routeNodes.forEach(existingNode => {
|
|
130
|
+
if (node.routePath?.startsWith(`${existingNode?.routePath ?? ''}/`)
|
|
131
|
+
// node.routePath.length > existingNode.routePath!.length
|
|
132
|
+
) {
|
|
133
|
+
node.parent = existingNode;
|
|
105
134
|
}
|
|
106
|
-
};
|
|
107
|
-
|
|
135
|
+
});
|
|
136
|
+
node.path = node.parent ? node.routePath?.replace(node.parent.routePath, '') || '/' : node.routePath;
|
|
137
|
+
const trimmedPath = routerCore.trimPathLeft(node.path ?? '');
|
|
138
|
+
const split = trimmedPath?.split('/') ?? [];
|
|
139
|
+
let first = split[0] ?? trimmedPath ?? '';
|
|
140
|
+
node.isNonPath = first.startsWith('_');
|
|
141
|
+
node.isNonLayout = first.endsWith('_');
|
|
142
|
+
node.cleanedPath = removeUnderscores(node.path) ?? '';
|
|
143
|
+
if (node.parent) {
|
|
144
|
+
node.parent.children = node.parent.children ?? [];
|
|
145
|
+
node.parent.children.push(node);
|
|
146
|
+
} else {
|
|
147
|
+
routeTree.push(node);
|
|
148
|
+
}
|
|
108
149
|
});
|
|
109
150
|
async function buildRouteConfig(nodes, depth = 1) {
|
|
110
|
-
const children = nodes.map(async
|
|
111
|
-
let node = nodeCache.find(d => d.fullPath === n.fullPath);
|
|
112
|
-
if (node) {
|
|
113
|
-
node.new = false;
|
|
114
|
-
} else {
|
|
115
|
-
node = n;
|
|
116
|
-
nodeCache.push(node);
|
|
117
|
-
if (!first) {
|
|
118
|
-
node.new = true;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
node.version = latestTask;
|
|
151
|
+
const children = nodes.map(async node => {
|
|
122
152
|
const routeCode = await fs__default["default"].readFile(node.fullPath, 'utf-8');
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (code) {
|
|
134
|
-
await fs__default["default"].writeFile(node.fullPath, code);
|
|
135
|
-
}
|
|
136
|
-
} catch (err) {
|
|
137
|
-
node.hash = '';
|
|
138
|
-
throw err;
|
|
139
|
-
}
|
|
153
|
+
|
|
154
|
+
// Ensure the boilerplate for the route exists
|
|
155
|
+
if (node.isRoot) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Ensure that new FileRoute(anything?) is replace with FileRoute(${node.routePath})
|
|
160
|
+
const replaced = routeCode.replace(fileRouteRegex, `new FileRoute('${node.routePath}')`);
|
|
161
|
+
if (replaced !== routeCode) {
|
|
162
|
+
await fs__default["default"].writeFile(node.fullPath, replaced);
|
|
140
163
|
}
|
|
141
164
|
const route = `${node.variableName}Route`;
|
|
142
|
-
routeConfigImports.push(`import { route as ${route} } from './${removeExt(path__default["default"].relative(path__default["default"].dirname(config.generatedRouteTree), path__default["default"].resolve(config.routesDirectory, node.filename)))}'`);
|
|
143
165
|
if (node.children?.length) {
|
|
144
166
|
const childConfigs = await buildRouteConfig(node.children, depth + 1);
|
|
145
|
-
return `${route}.addChildren([
|
|
167
|
+
return `${route}.addChildren([${spaces(depth * 4)}${childConfigs}])`;
|
|
146
168
|
}
|
|
147
169
|
return route;
|
|
148
170
|
});
|
|
149
|
-
return (await Promise.all(children)).filter(Boolean).join(
|
|
171
|
+
return (await Promise.all(children)).filter(Boolean).join(`,`);
|
|
150
172
|
}
|
|
151
173
|
const routeConfigChildrenText = await buildRouteConfig(routeTree);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
174
|
+
const routeImports = [`import { route as rootRoute } from './${path__default["default"].relative(path__default["default"].dirname(config.generatedRouteTree), path__default["default"].resolve(config.routesDirectory, rootPathId))}'`, ...multiSortBy(routeNodes, [d => d.routePath?.includes(`/${rootPathId}`) ? -1 : 1, d => d.routePath?.split('/').length, d => d.routePath?.endsWith("index'") ? -1 : 1, d => d]).map(node => {
|
|
175
|
+
return `import { route as ${node.variableName}Route } from './${removeExt(path__default["default"].relative(path__default["default"].dirname(config.generatedRouteTree), path__default["default"].resolve(config.routesDirectory, node.filePath)))}'`;
|
|
176
|
+
})].join('\n');
|
|
177
|
+
const routeTypes = `declare module '@tanstack/react-router' {
|
|
155
178
|
interface FileRoutesByPath {
|
|
156
179
|
${routeNodes.map(routeNode => {
|
|
157
180
|
return `'${routeNode.routePath}': {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}).join('\n
|
|
181
|
+
parentRoute: typeof ${routeNode.parent?.variableName ?? 'root'}Route
|
|
182
|
+
}`;
|
|
183
|
+
}).join('\n')}
|
|
161
184
|
}
|
|
162
|
-
}
|
|
185
|
+
}`;
|
|
186
|
+
const routeOptions = routeNodes.map(routeNode => {
|
|
163
187
|
return `Object.assign(${routeNode.variableName ?? 'root'}Route.options, {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
nodeCache = nodeCache.filter(d => {
|
|
186
|
-
if (d.version !== latestTask) {
|
|
187
|
-
removedNodes.push(d);
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
return true;
|
|
188
|
+
${[routeNode.isNonPath ? `id: '${routeNode.cleanedPath}'` : `path: '${routeNode.cleanedPath}'`, `getParentRoute: () => ${routeNode.parent?.variableName ?? 'root'}Route`, routeNode.layoutLimit ? `layoutLimit: '${routeNode.layoutLimit}'` : ''
|
|
189
|
+
// `\n// ${JSON.stringify(
|
|
190
|
+
// {
|
|
191
|
+
// ...routeNode,
|
|
192
|
+
// parent: undefined,
|
|
193
|
+
// children: undefined,
|
|
194
|
+
// fullPath: undefined,
|
|
195
|
+
// variableName: undefined,
|
|
196
|
+
// },
|
|
197
|
+
// null,
|
|
198
|
+
// 2,
|
|
199
|
+
// )
|
|
200
|
+
// .split('\n')
|
|
201
|
+
// .join('\n// ')}`,
|
|
202
|
+
].filter(Boolean).join(',')}
|
|
203
|
+
})`;
|
|
204
|
+
}).join('\n\n');
|
|
205
|
+
const routeConfig = `export const routeTree = rootRoute.addChildren([${routeConfigChildrenText}])`;
|
|
206
|
+
const routeConfigFileContent = await prettier__namespace.format([routeImports, routeTypes, routeOptions, routeConfig].join('\n\n'), {
|
|
207
|
+
semi: false,
|
|
208
|
+
parser: 'typescript'
|
|
191
209
|
});
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (newNodes.length || updatedNodes.length || removedNodes.length) {
|
|
196
|
-
if (newNodes.length) {
|
|
197
|
-
console.log(`🥳 Added ${newNodes.length} new routes`);
|
|
198
|
-
}
|
|
199
|
-
if (updatedNodes.length) {
|
|
200
|
-
console.log(`✅ Updated ${updatedNodes.length} routes`);
|
|
201
|
-
}
|
|
202
|
-
if (removedNodes.length) {
|
|
203
|
-
console.log(`🗑 Removed ${removedNodes.length} unused routes`);
|
|
210
|
+
const routeTreeContent = await fs__default["default"].readFile(path__default["default"].resolve(config.generatedRouteTree), 'utf-8').catch(err => {
|
|
211
|
+
if (err.code === 'ENOENT') {
|
|
212
|
+
return undefined;
|
|
204
213
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Ensure that new FileRoute(anything?) is replace with FileRoute(${node.routePath})
|
|
215
|
-
const replaced = code.replace(/new\s+FileRoute\(([^)]*)\)/g, `new FileRoute('${node.routePath}')`);
|
|
216
|
-
if (replaced !== code) {
|
|
217
|
-
return replaced;
|
|
214
|
+
throw err;
|
|
215
|
+
});
|
|
216
|
+
if (!checkLatest()) return;
|
|
217
|
+
if (routeTreeContent !== routeConfigFileContent) {
|
|
218
|
+
await fs__default["default"].ensureDir(path__default["default"].dirname(path__default["default"].resolve(config.generatedRouteTree)));
|
|
219
|
+
if (!checkLatest()) return;
|
|
220
|
+
await fs__default["default"].writeFile(path__default["default"].resolve(config.generatedRouteTree), routeConfigFileContent);
|
|
218
221
|
}
|
|
219
|
-
|
|
222
|
+
console.log(`🌲 Processed ${routeNodes.length} routes in ${Date.now() - start}ms`);
|
|
220
223
|
}
|
|
221
224
|
function fileToVariable(d) {
|
|
222
|
-
return d
|
|
225
|
+
return removeUnderscores(d)?.replace(/\$/g, '')?.split(/[/-]/g).map((d, i) => i > 0 ? capitalize(d) : d).join('').replace(/([^a-zA-Z0-9]|[\.])/gm, '') ?? '';
|
|
223
226
|
}
|
|
224
227
|
function removeExt(d) {
|
|
225
228
|
return d.substring(0, d.lastIndexOf('.')) || d;
|
|
@@ -252,9 +255,13 @@ function capitalize(s) {
|
|
|
252
255
|
if (typeof s !== 'string') return '';
|
|
253
256
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
254
257
|
}
|
|
258
|
+
function removeUnderscores(s) {
|
|
259
|
+
return s?.replace(/(^_|_$)/, '').replace(/(\/_|_\/)/, '/');
|
|
260
|
+
}
|
|
255
261
|
|
|
262
|
+
exports.fileRouteRegex = fileRouteRegex;
|
|
256
263
|
exports.generator = generator;
|
|
257
264
|
exports.multiSortBy = multiSortBy;
|
|
258
265
|
exports.removeExt = removeExt;
|
|
259
|
-
exports.
|
|
266
|
+
exports.rootPathId = rootPathId;
|
|
260
267
|
//# sourceMappingURL=generator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sources":["../../src/generator.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\nimport crypto from 'crypto'\nimport { Config } from './config'\n\nlet latestTask = 0\nexport const rootRouteName = 'root'\n\nexport type RouteNode = {\n filename: string\n fullPath: string\n variableName: string\n routePath?: string\n path?: string\n id?: string\n hash?: string\n version?: number\n changed?: boolean\n new?: boolean\n isRoot?: boolean\n children?: RouteNode[]\n parent?: RouteNode\n}\n\nlet nodeCache: RouteNode[] = undefined!\n\nasync function createRouteNode(\n config: Config,\n fileName: string,\n): Promise<RouteNode> {\n const filename = path.basename(fileName)\n const fullPath = path.resolve(config.routesDirectory, filename)\n const fileNameNoExt = removeExt(filename)\n let routePath = fileNameNoExt.split('.').join('/')\n\n // Remove the index from the route path and\n // if the route path is empty, use `/'\n if (routePath.endsWith('/index')) {\n routePath = routePath.replace(/\\/index$/, '/')\n } else if (routePath === 'index') {\n routePath = '/'\n }\n\n return {\n filename,\n fullPath,\n routePath,\n variableName: fileToVariable(removeExt(filename)),\n }\n}\n\nexport async function generator(config: Config) {\n console.log()\n\n let first = false\n\n if (!nodeCache) {\n first = true\n console.log('🔄 Generating routes...')\n nodeCache = []\n } else {\n console.log('♻️ Regenerating routes...')\n }\n\n const taskId = latestTask + 1\n latestTask = taskId\n\n const checkLatest = () => {\n if (latestTask !== taskId) {\n console.log(`- Skipping since file changes were made while generating.`)\n return false\n }\n\n return true\n }\n\n const start = Date.now()\n let routeConfigImports: string[] = []\n\n let nodesChanged = false\n const fileQueue: [string, string][] = []\n const queueWriteFile = (filename: string, content: string) => {\n fileQueue.push([filename, content])\n }\n\n let dirList\n\n try {\n dirList = await fs.readdir(config.routesDirectory)\n } catch (err) {\n console.log()\n console.error(\n 'TSR: Error reading the config.routesDirectory. Does it exist?',\n )\n console.log()\n throw err\n }\n\n let routeNodes = await Promise.all(\n dirList.map(async (filename): Promise<RouteNode> => {\n return createRouteNode(config, filename)\n }),\n )\n\n routeNodes = multiSortBy(routeNodes, [\n (d) => (d.routePath === '/' ? -1 : 1),\n (d) => d.routePath?.split('/').length,\n (d) => (d.routePath?.endsWith('/') ? -1 : 1),\n (d) => d.routePath,\n ]).filter((d) => d.routePath !== '_root')\n\n const routeTree: RouteNode[] = []\n\n // Loop over the flat list of routeNodes and\n // build up a tree based on the routeNodes' routePath\n routeNodes.forEach((node) => {\n const findParent = (\n existing: RouteNode[],\n node: RouteNode,\n parentNode?: RouteNode,\n ) => {\n const parent = existing.find((d) => {\n return node.routePath?.startsWith(d.path!)\n })\n\n if (parent) {\n if (!parent.children) {\n parent.children = []\n }\n\n findParent(parent.children, node, parent)\n } else {\n node.path = node.routePath?.replace(parentNode?.routePath ?? '', '')\n node.parent = parentNode\n existing.push(node)\n }\n }\n\n findParent(routeTree, node)\n })\n\n async function buildRouteConfig(\n nodes: RouteNode[],\n depth = 1,\n ): Promise<string> {\n const children = nodes.map(async (n) => {\n let node = nodeCache.find((d) => d.fullPath === n.fullPath)!\n\n if (node) {\n node.new = false\n } else {\n node = n\n nodeCache.push(node)\n if (!first) {\n node.new = true\n }\n }\n\n node.version = latestTask\n\n const routeCode = await fs.readFile(node.fullPath, 'utf-8')\n const hashSum = crypto.createHash('sha256')\n hashSum.update(routeCode)\n const hash = hashSum.digest('hex')\n\n node.changed = node.hash !== hash\n if (node.changed) {\n nodesChanged = true\n node.hash = hash\n\n try {\n // Ensure the boilerplate for the route exists\n const code = await ensureBoilerplate(node, routeCode)\n\n if (code) {\n await fs.writeFile(node.fullPath, code)\n }\n } catch (err) {\n node.hash = ''\n throw err\n }\n }\n\n const route = `${node.variableName}Route`\n\n routeConfigImports.push(\n `import { route as ${route} } from './${removeExt(\n path.relative(\n path.dirname(config.generatedRouteTree),\n path.resolve(config.routesDirectory, node.filename),\n ),\n )}'`,\n )\n\n if (node.children?.length) {\n const childConfigs = await buildRouteConfig(node.children, depth + 1)\n return `${route}.addChildren([\\n${spaces(\n depth * 4,\n )}${childConfigs}\\n${spaces(depth * 2)}])`\n }\n\n return route\n })\n\n return (await Promise.all(children))\n .filter(Boolean)\n .join(`,\\n${spaces(depth * 2)}`)\n }\n\n const routeConfigChildrenText = await buildRouteConfig(routeTree)\n\n routeConfigImports = multiSortBy(routeConfigImports, [\n (d) => (d.includes(rootRouteName) ? -1 : 1),\n (d) => d.split('/').length,\n (d) => (d.endsWith(\"index'\") ? -1 : 1),\n (d) => d,\n ])\n\n const routeConfig = `export const routeTree = rootRoute.addChildren([\\n ${routeConfigChildrenText}\\n])`\n\n const routeConfigFileContent = [\n `import { route as rootRoute } from './${path.relative(\n path.dirname(config.generatedRouteTree),\n path.resolve(config.routesDirectory, '_root'),\n )}'`,\n routeConfigImports.join('\\n'),\n `declare module '@tanstack/react-router' {\n interface FileRoutesByPath {\n ${routeNodes\n .map((routeNode) => {\n return `'${routeNode.routePath}': {\n parentRoute: typeof ${routeNode.parent?.variableName ?? 'root'}Route\n }`\n })\n .join('\\n ')} \n }\n}`,\n routeNodes\n .map((routeNode) => {\n return `Object.assign(${\n routeNode.variableName ?? 'root'\n }Route.options, {\n path: '${routeNode.path}',\n getParentRoute: () => ${`${routeNode.parent?.variableName ?? 'root'}Route,\n})`}`\n })\n .join('\\n'),\n routeConfig,\n ].join('\\n\\n')\n\n if (nodesChanged) {\n queueWriteFile(\n path.resolve(config.generatedRouteTree),\n routeConfigFileContent,\n )\n }\n\n if (!checkLatest()) return\n\n await Promise.all(\n fileQueue.map(async ([filename, content]) => {\n await fs.ensureDir(path.dirname(filename))\n const exists = await fs.pathExists(filename)\n let current = ''\n if (exists) {\n current = await fs.readFile(filename, 'utf-8')\n }\n if (current !== content) {\n await fs.writeFile(filename, content)\n }\n }),\n )\n\n if (!checkLatest()) return\n\n const removedNodes: RouteNode[] = []\n\n nodeCache = nodeCache.filter((d) => {\n if (d.version !== latestTask) {\n removedNodes.push(d)\n return false\n }\n return true\n })\n\n const newNodes = nodeCache.filter((d) => d.new)\n const updatedNodes = nodeCache.filter((d) => !d.new && d.changed)\n\n console.log(\n `🌲 Processed ${nodeCache.length} routes in ${Date.now() - start}ms`,\n )\n\n if (newNodes.length || updatedNodes.length || removedNodes.length) {\n if (newNodes.length) {\n console.log(`🥳 Added ${newNodes.length} new routes`)\n }\n\n if (updatedNodes.length) {\n console.log(`✅ Updated ${updatedNodes.length} routes`)\n }\n\n if (removedNodes.length) {\n console.log(`🗑 Removed ${removedNodes.length} unused routes`)\n }\n } else {\n console.log(`🎉 No changes were found. Carry on!`)\n }\n}\n\nasync function ensureBoilerplate(node: RouteNode, code: string) {\n if (node.isRoot) {\n return\n }\n\n // Ensure that new FileRoute(anything?) is replace with FileRoute(${node.routePath})\n const replaced = code.replace(\n /new\\s+FileRoute\\(([^)]*)\\)/g,\n `new FileRoute('${node.routePath}')`,\n )\n\n if (replaced !== code) {\n return replaced\n }\n\n return\n}\n\nfunction fileToVariable(d: string) {\n return d\n .split('/')\n .map((d, i) => (i > 0 ? capitalize(d) : d))\n .join('')\n .replace(/([^a-zA-Z0-9]|[\\.])/gm, '')\n}\n\nexport function removeExt(d: string) {\n return d.substring(0, d.lastIndexOf('.')) || d\n}\n\nfunction spaces(d: number): string {\n return Array.from({ length: d })\n .map(() => ' ')\n .join('')\n}\n\nexport function multiSortBy<T>(\n arr: T[],\n accessors: ((item: T) => any)[] = [(d) => d],\n): T[] {\n return arr\n .map((d, i) => [d, i] as const)\n .sort(([a, ai], [b, bi]) => {\n for (const accessor of accessors) {\n const ao = accessor(a)\n const bo = accessor(b)\n\n if (typeof ao === 'undefined') {\n if (typeof bo === 'undefined') {\n continue\n }\n return 1\n }\n\n if (ao === bo) {\n continue\n }\n\n return ao > bo ? 1 : -1\n }\n\n return ai - bi\n })\n .map(([d]) => d)\n}\n\nfunction capitalize(s: string) {\n if (typeof s !== 'string') return ''\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n"],"names":["latestTask","rootRouteName","nodeCache","undefined","createRouteNode","config","fileName","filename","path","basename","fullPath","resolve","routesDirectory","fileNameNoExt","removeExt","routePath","split","join","endsWith","replace","variableName","fileToVariable","generator","console","log","first","taskId","checkLatest","start","Date","now","routeConfigImports","nodesChanged","fileQueue","queueWriteFile","content","push","dirList","fs","readdir","err","error","routeNodes","Promise","all","map","multiSortBy","d","length","filter","routeTree","forEach","node","findParent","existing","parentNode","parent","find","startsWith","children","buildRouteConfig","nodes","depth","n","new","version","routeCode","readFile","hashSum","crypto","createHash","update","hash","digest","changed","code","ensureBoilerplate","writeFile","route","relative","dirname","generatedRouteTree","childConfigs","spaces","Boolean","routeConfigChildrenText","includes","routeConfig","routeConfigFileContent","routeNode","ensureDir","exists","pathExists","current","removedNodes","newNodes","updatedNodes","isRoot","replaced","i","capitalize","substring","lastIndexOf","Array","from","arr","accessors","sort","a","ai","b","bi","accessor","ao","bo","s","charAt","toUpperCase","slice"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generator.js","sources":["../../src/generator.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\nimport * as prettier from 'prettier'\nimport { Config } from './config'\nimport { cleanPath, trimPathLeft } from '@tanstack/router-core'\n\nlet latestTask = 0\nexport const rootPathId = '__root'\nexport const fileRouteRegex = /new\\s+FileRoute\\(([^)]*)\\)/g\n\nexport type RouteNode = {\n filePath: string\n fullPath: string\n variableName: string\n routePath?: string\n cleanedPath?: string\n path?: string\n isNonPath?: boolean\n isNonLayout?: boolean\n isRoot?: boolean\n children?: RouteNode[]\n parent?: RouteNode\n layoutLimit?: string\n}\n\nasync function getRouteNodes(config: Config) {\n const { routeFilePrefix, routeFileIgnorePrefix } = config\n\n let routeNodes: RouteNode[] = []\n\n async function recurse(dir: string) {\n const fullDir = path.resolve(config.routesDirectory, dir)\n let dirList = await fs.readdir(fullDir)\n\n dirList = dirList.filter((d) => {\n if (d.startsWith('.') || d.startsWith(routeFileIgnorePrefix)) {\n return false\n }\n\n if (routeFilePrefix) {\n return d.startsWith(routeFilePrefix)\n }\n\n return true\n })\n\n await Promise.all(\n dirList.map(async (fileName) => {\n const fullPath = path.join(fullDir, fileName)\n const relativePath = path.join(dir, fileName)\n const stat = await fs.stat(fullPath)\n\n if (stat.isDirectory()) {\n await recurse(relativePath)\n } else {\n const filePath = path.join(dir, fileName)\n const filePathNoExt = removeExt(filePath)\n let routePath = cleanPath(`/${filePathNoExt.split('.').join('/')}`)\n const variableName = fileToVariable(routePath)\n\n // Remove the index from the route path and\n // if the route path is empty, use `/'\n if (routePath.endsWith('/index')) {\n routePath = routePath.replace(/\\/index$/, '/')\n } else if (routePath === 'index') {\n routePath = '/'\n }\n\n // console.log(filePath)\n\n routeNodes.push({\n filePath,\n fullPath,\n routePath,\n variableName,\n })\n }\n }),\n )\n\n return routeNodes\n }\n\n await recurse('./')\n\n return routeNodes\n}\n\nlet first = false\nlet skipMessage = false\n\nexport async function generator(config: Config) {\n console.log()\n\n if (!first) {\n console.log('🔄 Generating routes...')\n first = true\n } else if (skipMessage) {\n skipMessage = false\n } else {\n console.log('♻️ Regenerating routes...')\n }\n\n const taskId = latestTask + 1\n latestTask = taskId\n\n const checkLatest = () => {\n if (latestTask !== taskId) {\n skipMessage = true\n return false\n }\n\n return true\n }\n\n const start = Date.now()\n\n let routeNodes = await getRouteNodes(config)\n\n routeNodes = multiSortBy(routeNodes, [\n (d) => (d.routePath === '/' ? -1 : 1),\n (d) => d.routePath?.split('/').length,\n (d) => (d.routePath?.endsWith('/') ? -1 : 1),\n (d) => d.routePath,\n ]).filter((d) => d.routePath !== `/${rootPathId}`)\n\n const routeTree: RouteNode[] = []\n\n // Loop over the flat list of routeNodes and\n // build up a tree based on the routeNodes' routePath\n routeNodes.forEach((node) => {\n routeNodes.forEach((existingNode) => {\n if (\n node.routePath?.startsWith(`${existingNode?.routePath ?? ''}/`)\n // node.routePath.length > existingNode.routePath!.length\n ) {\n node.parent = existingNode\n }\n })\n\n node.path = node.parent\n ? node.routePath?.replace(node.parent.routePath!, '') || '/'\n : node.routePath\n\n const trimmedPath = trimPathLeft(node.path ?? '')\n\n const split = trimmedPath?.split('/') ?? []\n let first = split[0] ?? trimmedPath ?? ''\n\n node.isNonPath = first.startsWith('_')\n node.isNonLayout = first.endsWith('_')\n\n node.cleanedPath = removeUnderscores(node.path) ?? ''\n\n if (node.parent) {\n node.parent.children = node.parent.children ?? []\n node.parent.children.push(node)\n } else {\n routeTree.push(node)\n }\n })\n\n async function buildRouteConfig(\n nodes: RouteNode[],\n depth = 1,\n ): Promise<string> {\n const children = nodes.map(async (node) => {\n const routeCode = await fs.readFile(node.fullPath, 'utf-8')\n\n // Ensure the boilerplate for the route exists\n if (node.isRoot) {\n return\n }\n\n // Ensure that new FileRoute(anything?) is replace with FileRoute(${node.routePath})\n const replaced = routeCode.replace(\n fileRouteRegex,\n `new FileRoute('${node.routePath}')`,\n )\n\n if (replaced !== routeCode) {\n await fs.writeFile(node.fullPath, replaced)\n }\n\n const route = `${node.variableName}Route`\n\n if (node.children?.length) {\n const childConfigs = await buildRouteConfig(node.children, depth + 1)\n return `${route}.addChildren([${spaces(depth * 4)}${childConfigs}])`\n }\n\n return route\n })\n\n return (await Promise.all(children)).filter(Boolean).join(`,`)\n }\n\n const routeConfigChildrenText = await buildRouteConfig(routeTree)\n\n const routeImports = [\n `import { route as rootRoute } from './${path.relative(\n path.dirname(config.generatedRouteTree),\n path.resolve(config.routesDirectory, rootPathId),\n )}'`,\n ...multiSortBy(routeNodes, [\n (d) => (d.routePath?.includes(`/${rootPathId}`) ? -1 : 1),\n (d) => d.routePath?.split('/').length,\n (d) => (d.routePath?.endsWith(\"index'\") ? -1 : 1),\n (d) => d,\n ]).map((node) => {\n return `import { route as ${node.variableName}Route } from './${removeExt(\n path.relative(\n path.dirname(config.generatedRouteTree),\n path.resolve(config.routesDirectory, node.filePath),\n ),\n )}'`\n }),\n ].join('\\n')\n\n const routeTypes = `declare module '@tanstack/react-router' {\n interface FileRoutesByPath {\n ${routeNodes\n .map((routeNode) => {\n return `'${routeNode.routePath}': {\n parentRoute: typeof ${routeNode.parent?.variableName ?? 'root'}Route\n }`\n })\n .join('\\n')} \n }\n}`\n\n const routeOptions = routeNodes\n .map((routeNode) => {\n return `Object.assign(${routeNode.variableName ?? 'root'}Route.options, {\n ${[\n routeNode.isNonPath\n ? `id: '${routeNode.cleanedPath}'`\n : `path: '${routeNode.cleanedPath}'`,\n `getParentRoute: () => ${\n routeNode.parent?.variableName ?? 'root'\n }Route`,\n routeNode.layoutLimit\n ? `layoutLimit: '${routeNode.layoutLimit}'`\n : '',\n // `\\n// ${JSON.stringify(\n // {\n // ...routeNode,\n // parent: undefined,\n // children: undefined,\n // fullPath: undefined,\n // variableName: undefined,\n // },\n // null,\n // 2,\n // )\n // .split('\\n')\n // .join('\\n// ')}`,\n ]\n .filter(Boolean)\n .join(',')}\n })`\n })\n .join('\\n\\n')\n\n const routeConfig = `export const routeTree = rootRoute.addChildren([${routeConfigChildrenText}])`\n\n const routeConfigFileContent = await prettier.format(\n [routeImports, routeTypes, routeOptions, routeConfig].join('\\n\\n'),\n {\n semi: false,\n parser: 'typescript',\n },\n )\n\n const routeTreeContent = await fs\n .readFile(path.resolve(config.generatedRouteTree), 'utf-8')\n .catch((err: any) => {\n if (err.code === 'ENOENT') {\n return undefined\n }\n throw err\n })\n\n if (!checkLatest()) return\n\n if (routeTreeContent !== routeConfigFileContent) {\n await fs.ensureDir(path.dirname(path.resolve(config.generatedRouteTree)))\n if (!checkLatest()) return\n await fs.writeFile(\n path.resolve(config.generatedRouteTree),\n routeConfigFileContent,\n )\n }\n\n console.log(\n `🌲 Processed ${routeNodes.length} routes in ${Date.now() - start}ms`,\n )\n}\n\nfunction fileToVariable(d: string): string {\n return (\n removeUnderscores(d)\n ?.replace(/\\$/g, '')\n ?.split(/[/-]/g)\n .map((d, i) => (i > 0 ? capitalize(d) : d))\n .join('')\n .replace(/([^a-zA-Z0-9]|[\\.])/gm, '') ?? ''\n )\n}\n\nexport function removeExt(d: string) {\n return d.substring(0, d.lastIndexOf('.')) || d\n}\n\nfunction spaces(d: number): string {\n return Array.from({ length: d })\n .map(() => ' ')\n .join('')\n}\n\nexport function multiSortBy<T>(\n arr: T[],\n accessors: ((item: T) => any)[] = [(d) => d],\n): T[] {\n return arr\n .map((d, i) => [d, i] as const)\n .sort(([a, ai], [b, bi]) => {\n for (const accessor of accessors) {\n const ao = accessor(a)\n const bo = accessor(b)\n\n if (typeof ao === 'undefined') {\n if (typeof bo === 'undefined') {\n continue\n }\n return 1\n }\n\n if (ao === bo) {\n continue\n }\n\n return ao > bo ? 1 : -1\n }\n\n return ai - bi\n })\n .map(([d]) => d)\n}\n\nfunction capitalize(s: string) {\n if (typeof s !== 'string') return ''\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\nfunction removeUnderscores(s?: string) {\n return s?.replace(/(^_|_$)/, '').replace(/(\\/_|_\\/)/, '/')\n}\n"],"names":["latestTask","rootPathId","fileRouteRegex","getRouteNodes","config","routeFilePrefix","routeFileIgnorePrefix","routeNodes","recurse","dir","fullDir","path","resolve","routesDirectory","dirList","fs","readdir","filter","d","startsWith","Promise","all","map","fileName","fullPath","join","relativePath","stat","isDirectory","filePath","filePathNoExt","removeExt","routePath","cleanPath","split","variableName","fileToVariable","endsWith","replace","push","first","skipMessage","generator","console","log","taskId","checkLatest","start","Date","now","multiSortBy","length","routeTree","forEach","node","existingNode","parent","trimmedPath","trimPathLeft","isNonPath","isNonLayout","cleanedPath","removeUnderscores","children","buildRouteConfig","nodes","depth","routeCode","readFile","isRoot","replaced","writeFile","route","childConfigs","spaces","Boolean","routeConfigChildrenText","routeImports","relative","dirname","generatedRouteTree","includes","routeTypes","routeNode","routeOptions","layoutLimit","routeConfig","routeConfigFileContent","prettier","format","semi","parser","routeTreeContent","catch","err","code","undefined","ensureDir","i","capitalize","substring","lastIndexOf","Array","from","arr","accessors","sort","a","ai","b","bi","accessor","ao","bo","s","charAt","toUpperCase","slice"],"mappings":"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"}
|
package/build/cjs/watch.js
CHANGED
|
@@ -24,19 +24,13 @@ var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
|
24
24
|
|
|
25
25
|
async function watch() {
|
|
26
26
|
const configWatcher = chokidar__default["default"].watch(path__default["default"].resolve(process.cwd(), 'tsr.config.js'));
|
|
27
|
-
let watcher = new chokidar__default["default"].FSWatcher();
|
|
27
|
+
let watcher = new chokidar__default["default"].FSWatcher({});
|
|
28
28
|
const generatorWatcher = async () => {
|
|
29
29
|
const config$1 = await config.getConfig();
|
|
30
30
|
watcher.close();
|
|
31
31
|
console.log(`TSR: Watching routes (${config$1.routesDirectory})...`);
|
|
32
32
|
watcher = chokidar__default["default"].watch(config$1.routesDirectory);
|
|
33
33
|
watcher.on('ready', async () => {
|
|
34
|
-
try {
|
|
35
|
-
await generator.generator(config$1);
|
|
36
|
-
} catch (err) {
|
|
37
|
-
console.error(err);
|
|
38
|
-
console.log();
|
|
39
|
-
}
|
|
40
34
|
const handle = async () => {
|
|
41
35
|
try {
|
|
42
36
|
await generator.generator(config$1);
|
|
@@ -45,11 +39,17 @@ async function watch() {
|
|
|
45
39
|
console.log();
|
|
46
40
|
}
|
|
47
41
|
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
await handle();
|
|
43
|
+
let timeout;
|
|
44
|
+
const deduped = file => {
|
|
45
|
+
if (timeout) {
|
|
46
|
+
clearTimeout(timeout);
|
|
47
|
+
}
|
|
48
|
+
timeout = setTimeout(handle, 10);
|
|
49
|
+
};
|
|
50
|
+
watcher.on('change', deduped);
|
|
51
|
+
watcher.on('add', deduped);
|
|
52
|
+
watcher.on('unlink', deduped);
|
|
53
53
|
});
|
|
54
54
|
};
|
|
55
55
|
configWatcher.on('ready', generatorWatcher);
|
package/build/cjs/watch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.js","sources":["../../src/watch.ts"],"sourcesContent":["import chokidar from 'chokidar'\nimport path from 'path'\nimport { getConfig } from './config'\nimport { generator } from './generator'\n\nexport async function watch() {\n const configWatcher = chokidar.watch(\n path.resolve(process.cwd(), 'tsr.config.js'),\n )\n\n let watcher = new chokidar.FSWatcher()\n\n const generatorWatcher = async () => {\n const config = await getConfig()\n\n watcher.close()\n\n console.log(`TSR: Watching routes (${config.routesDirectory})...`)\n watcher = chokidar.watch(config.routesDirectory)\n\n watcher.on('ready', async () => {\n try {\n
|
|
1
|
+
{"version":3,"file":"watch.js","sources":["../../src/watch.ts"],"sourcesContent":["import chokidar from 'chokidar'\nimport path from 'path'\nimport { getConfig } from './config'\nimport { generator } from './generator'\n\nexport async function watch() {\n const configWatcher = chokidar.watch(\n path.resolve(process.cwd(), 'tsr.config.js'),\n )\n\n let watcher = new chokidar.FSWatcher({})\n\n const generatorWatcher = async () => {\n const config = await getConfig()\n\n watcher.close()\n\n console.log(`TSR: Watching routes (${config.routesDirectory})...`)\n watcher = chokidar.watch(config.routesDirectory)\n\n watcher.on('ready', async () => {\n const handle = async () => {\n try {\n await generator(config)\n } catch (err) {\n console.error(err)\n console.log()\n }\n }\n\n await handle()\n\n let timeout: ReturnType<typeof setTimeout>\n\n const deduped = (file: string) => {\n if (timeout) {\n clearTimeout(timeout)\n }\n\n timeout = setTimeout(handle, 10)\n }\n\n watcher.on('change', deduped)\n watcher.on('add', deduped)\n watcher.on('unlink', deduped)\n })\n }\n\n configWatcher.on('ready', generatorWatcher)\n configWatcher.on('change', generatorWatcher)\n}\n"],"names":["watch","configWatcher","chokidar","path","resolve","process","cwd","watcher","FSWatcher","generatorWatcher","config","getConfig","close","console","log","routesDirectory","on","handle","generator","err","error","timeout","deduped","file","clearTimeout","setTimeout"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAKO,eAAeA,KAAKA,GAAG;AAC5B,EAAA,MAAMC,aAAa,GAAGC,4BAAQ,CAACF,KAAK,CAClCG,wBAAI,CAACC,OAAO,CAACC,OAAO,CAACC,GAAG,EAAE,EAAE,eAAe,CAC7C,CAAC,CAAA;EAED,IAAIC,OAAO,GAAG,IAAIL,4BAAQ,CAACM,SAAS,CAAC,EAAE,CAAC,CAAA;AAExC,EAAA,MAAMC,gBAAgB,GAAG,YAAY;AACnC,IAAA,MAAMC,QAAM,GAAG,MAAMC,gBAAS,EAAE,CAAA;IAEhCJ,OAAO,CAACK,KAAK,EAAE,CAAA;IAEfC,OAAO,CAACC,GAAG,CAAE,CAAA,sBAAA,EAAwBJ,QAAM,CAACK,eAAgB,MAAK,CAAC,CAAA;IAClER,OAAO,GAAGL,4BAAQ,CAACF,KAAK,CAACU,QAAM,CAACK,eAAe,CAAC,CAAA;AAEhDR,IAAAA,OAAO,CAACS,EAAE,CAAC,OAAO,EAAE,YAAY;AAC9B,MAAA,MAAMC,MAAM,GAAG,YAAY;QACzB,IAAI;UACF,MAAMC,mBAAS,CAACR,QAAM,CAAC,CAAA;SACxB,CAAC,OAAOS,GAAG,EAAE;AACZN,UAAAA,OAAO,CAACO,KAAK,CAACD,GAAG,CAAC,CAAA;UAClBN,OAAO,CAACC,GAAG,EAAE,CAAA;AACf,SAAA;OACD,CAAA;MAED,MAAMG,MAAM,EAAE,CAAA;AAEd,MAAA,IAAII,OAAsC,CAAA;MAE1C,MAAMC,OAAO,GAAIC,IAAY,IAAK;AAChC,QAAA,IAAIF,OAAO,EAAE;UACXG,YAAY,CAACH,OAAO,CAAC,CAAA;AACvB,SAAA;AAEAA,QAAAA,OAAO,GAAGI,UAAU,CAACR,MAAM,EAAE,EAAE,CAAC,CAAA;OACjC,CAAA;AAEDV,MAAAA,OAAO,CAACS,EAAE,CAAC,QAAQ,EAAEM,OAAO,CAAC,CAAA;AAC7Bf,MAAAA,OAAO,CAACS,EAAE,CAAC,KAAK,EAAEM,OAAO,CAAC,CAAA;AAC1Bf,MAAAA,OAAO,CAACS,EAAE,CAAC,QAAQ,EAAEM,OAAO,CAAC,CAAA;AAC/B,KAAC,CAAC,CAAA;GACH,CAAA;AAEDrB,EAAAA,aAAa,CAACe,EAAE,CAAC,OAAO,EAAEP,gBAAgB,CAAC,CAAA;AAC3CR,EAAAA,aAAa,CAACe,EAAE,CAAC,QAAQ,EAAEP,gBAAgB,CAAC,CAAA;AAC9C;;;;"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/router-cli",
|
|
3
3
|
"author": "Tanner Linsley",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.153",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://tanstack.com/router",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"@babel/preset-env": "^7.20.2",
|
|
47
47
|
"@babel/template": "^7.18.10",
|
|
48
48
|
"@babel/types": "^7.20.2",
|
|
49
|
+
"@tanstack/router-core": "0.0.1-beta.150",
|
|
49
50
|
"@types/fs-extra": "^9.0.13",
|
|
50
51
|
"@types/klaw": "^3.0.3",
|
|
51
52
|
"@types/through2": "^2.0.38",
|
|
@@ -55,8 +56,10 @@
|
|
|
55
56
|
"fs-extra": "^10.1.0",
|
|
56
57
|
"klaw": "^4.0.1",
|
|
57
58
|
"nodemon": "^2.0.20",
|
|
59
|
+
"prettier": "^3.0.2",
|
|
58
60
|
"through2": "^4.0.2",
|
|
59
|
-
"yargs": "^17.6.2"
|
|
61
|
+
"yargs": "^17.6.2",
|
|
62
|
+
"zod": "^3.19.1"
|
|
60
63
|
},
|
|
61
64
|
"scripts": {
|
|
62
65
|
"build": "rollup --config rollup.config.js"
|
package/src/config.ts
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import fs from 'fs-extra'
|
|
3
|
+
import { z } from 'zod'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
routesDirectory: string
|
|
8
|
-
generatedRouteTree: string
|
|
9
|
-
}
|
|
5
|
+
const configSchema = z.object({
|
|
6
|
+
routeFilePrefix: z.string().optional(),
|
|
7
|
+
routeFileIgnorePrefix: z.string().optional(),
|
|
8
|
+
routesDirectory: z.string(),
|
|
9
|
+
generatedRouteTree: z.string(),
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
export type Config = z.infer<typeof configSchema>
|
|
10
13
|
|
|
11
14
|
const configFilePathJson = path.resolve(process.cwd(), 'tsr.config.json')
|
|
12
15
|
|
|
13
16
|
export async function getConfig() {
|
|
14
|
-
|
|
17
|
+
const config = (await fs.readJson(configFilePathJson)) as unknown as Config
|
|
18
|
+
|
|
19
|
+
return configSchema.parse(config)
|
|
15
20
|
}
|
package/src/generator.ts
CHANGED
|
@@ -1,63 +1,102 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import fs from 'fs-extra'
|
|
3
|
-
import
|
|
3
|
+
import * as prettier from 'prettier'
|
|
4
4
|
import { Config } from './config'
|
|
5
|
+
import { cleanPath, trimPathLeft } from '@tanstack/router-core'
|
|
5
6
|
|
|
6
7
|
let latestTask = 0
|
|
7
|
-
export const
|
|
8
|
+
export const rootPathId = '__root'
|
|
9
|
+
export const fileRouteRegex = /new\s+FileRoute\(([^)]*)\)/g
|
|
8
10
|
|
|
9
11
|
export type RouteNode = {
|
|
10
|
-
|
|
12
|
+
filePath: string
|
|
11
13
|
fullPath: string
|
|
12
14
|
variableName: string
|
|
13
15
|
routePath?: string
|
|
16
|
+
cleanedPath?: string
|
|
14
17
|
path?: string
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
version?: number
|
|
18
|
-
changed?: boolean
|
|
19
|
-
new?: boolean
|
|
18
|
+
isNonPath?: boolean
|
|
19
|
+
isNonLayout?: boolean
|
|
20
20
|
isRoot?: boolean
|
|
21
21
|
children?: RouteNode[]
|
|
22
22
|
parent?: RouteNode
|
|
23
|
+
layoutLimit?: string
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
26
|
+
async function getRouteNodes(config: Config) {
|
|
27
|
+
const { routeFilePrefix, routeFileIgnorePrefix } = config
|
|
28
|
+
|
|
29
|
+
let routeNodes: RouteNode[] = []
|
|
30
|
+
|
|
31
|
+
async function recurse(dir: string) {
|
|
32
|
+
const fullDir = path.resolve(config.routesDirectory, dir)
|
|
33
|
+
let dirList = await fs.readdir(fullDir)
|
|
34
|
+
|
|
35
|
+
dirList = dirList.filter((d) => {
|
|
36
|
+
if (d.startsWith('.') || d.startsWith(routeFileIgnorePrefix)) {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (routeFilePrefix) {
|
|
41
|
+
return d.startsWith(routeFilePrefix)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return true
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
await Promise.all(
|
|
48
|
+
dirList.map(async (fileName) => {
|
|
49
|
+
const fullPath = path.join(fullDir, fileName)
|
|
50
|
+
const relativePath = path.join(dir, fileName)
|
|
51
|
+
const stat = await fs.stat(fullPath)
|
|
52
|
+
|
|
53
|
+
if (stat.isDirectory()) {
|
|
54
|
+
await recurse(relativePath)
|
|
55
|
+
} else {
|
|
56
|
+
const filePath = path.join(dir, fileName)
|
|
57
|
+
const filePathNoExt = removeExt(filePath)
|
|
58
|
+
let routePath = cleanPath(`/${filePathNoExt.split('.').join('/')}`)
|
|
59
|
+
const variableName = fileToVariable(routePath)
|
|
60
|
+
|
|
61
|
+
// Remove the index from the route path and
|
|
62
|
+
// if the route path is empty, use `/'
|
|
63
|
+
if (routePath.endsWith('/index')) {
|
|
64
|
+
routePath = routePath.replace(/\/index$/, '/')
|
|
65
|
+
} else if (routePath === 'index') {
|
|
66
|
+
routePath = '/'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// console.log(filePath)
|
|
43
70
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
71
|
+
routeNodes.push({
|
|
72
|
+
filePath,
|
|
73
|
+
fullPath,
|
|
74
|
+
routePath,
|
|
75
|
+
variableName,
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
}),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return routeNodes
|
|
49
82
|
}
|
|
83
|
+
|
|
84
|
+
await recurse('./')
|
|
85
|
+
|
|
86
|
+
return routeNodes
|
|
50
87
|
}
|
|
51
88
|
|
|
89
|
+
let first = false
|
|
90
|
+
let skipMessage = false
|
|
91
|
+
|
|
52
92
|
export async function generator(config: Config) {
|
|
53
93
|
console.log()
|
|
54
94
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (!nodeCache) {
|
|
58
|
-
first = true
|
|
95
|
+
if (!first) {
|
|
59
96
|
console.log('🔄 Generating routes...')
|
|
60
|
-
|
|
97
|
+
first = true
|
|
98
|
+
} else if (skipMessage) {
|
|
99
|
+
skipMessage = false
|
|
61
100
|
} else {
|
|
62
101
|
console.log('♻️ Regenerating routes...')
|
|
63
102
|
}
|
|
@@ -67,7 +106,7 @@ export async function generator(config: Config) {
|
|
|
67
106
|
|
|
68
107
|
const checkLatest = () => {
|
|
69
108
|
if (latestTask !== taskId) {
|
|
70
|
-
|
|
109
|
+
skipMessage = true
|
|
71
110
|
return false
|
|
72
111
|
}
|
|
73
112
|
|
|
@@ -75,262 +114,198 @@ export async function generator(config: Config) {
|
|
|
75
114
|
}
|
|
76
115
|
|
|
77
116
|
const start = Date.now()
|
|
78
|
-
let routeConfigImports: string[] = []
|
|
79
117
|
|
|
80
|
-
let
|
|
81
|
-
const fileQueue: [string, string][] = []
|
|
82
|
-
const queueWriteFile = (filename: string, content: string) => {
|
|
83
|
-
fileQueue.push([filename, content])
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
let dirList
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
dirList = await fs.readdir(config.routesDirectory)
|
|
90
|
-
} catch (err) {
|
|
91
|
-
console.log()
|
|
92
|
-
console.error(
|
|
93
|
-
'TSR: Error reading the config.routesDirectory. Does it exist?',
|
|
94
|
-
)
|
|
95
|
-
console.log()
|
|
96
|
-
throw err
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
let routeNodes = await Promise.all(
|
|
100
|
-
dirList.map(async (filename): Promise<RouteNode> => {
|
|
101
|
-
return createRouteNode(config, filename)
|
|
102
|
-
}),
|
|
103
|
-
)
|
|
118
|
+
let routeNodes = await getRouteNodes(config)
|
|
104
119
|
|
|
105
120
|
routeNodes = multiSortBy(routeNodes, [
|
|
106
121
|
(d) => (d.routePath === '/' ? -1 : 1),
|
|
107
122
|
(d) => d.routePath?.split('/').length,
|
|
108
123
|
(d) => (d.routePath?.endsWith('/') ? -1 : 1),
|
|
109
124
|
(d) => d.routePath,
|
|
110
|
-
]).filter((d) => d.routePath !==
|
|
125
|
+
]).filter((d) => d.routePath !== `/${rootPathId}`)
|
|
111
126
|
|
|
112
127
|
const routeTree: RouteNode[] = []
|
|
113
128
|
|
|
114
129
|
// Loop over the flat list of routeNodes and
|
|
115
130
|
// build up a tree based on the routeNodes' routePath
|
|
116
131
|
routeNodes.forEach((node) => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
132
|
+
routeNodes.forEach((existingNode) => {
|
|
133
|
+
if (
|
|
134
|
+
node.routePath?.startsWith(`${existingNode?.routePath ?? ''}/`)
|
|
135
|
+
// node.routePath.length > existingNode.routePath!.length
|
|
136
|
+
) {
|
|
137
|
+
node.parent = existingNode
|
|
138
|
+
}
|
|
139
|
+
})
|
|
125
140
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
141
|
+
node.path = node.parent
|
|
142
|
+
? node.routePath?.replace(node.parent.routePath!, '') || '/'
|
|
143
|
+
: node.routePath
|
|
130
144
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
existing.push(node)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
145
|
+
const trimmedPath = trimPathLeft(node.path ?? '')
|
|
146
|
+
|
|
147
|
+
const split = trimmedPath?.split('/') ?? []
|
|
148
|
+
let first = split[0] ?? trimmedPath ?? ''
|
|
138
149
|
|
|
139
|
-
|
|
150
|
+
node.isNonPath = first.startsWith('_')
|
|
151
|
+
node.isNonLayout = first.endsWith('_')
|
|
152
|
+
|
|
153
|
+
node.cleanedPath = removeUnderscores(node.path) ?? ''
|
|
154
|
+
|
|
155
|
+
if (node.parent) {
|
|
156
|
+
node.parent.children = node.parent.children ?? []
|
|
157
|
+
node.parent.children.push(node)
|
|
158
|
+
} else {
|
|
159
|
+
routeTree.push(node)
|
|
160
|
+
}
|
|
140
161
|
})
|
|
141
162
|
|
|
142
163
|
async function buildRouteConfig(
|
|
143
164
|
nodes: RouteNode[],
|
|
144
165
|
depth = 1,
|
|
145
166
|
): Promise<string> {
|
|
146
|
-
const children = nodes.map(async (
|
|
147
|
-
let node = nodeCache.find((d) => d.fullPath === n.fullPath)!
|
|
148
|
-
|
|
149
|
-
if (node) {
|
|
150
|
-
node.new = false
|
|
151
|
-
} else {
|
|
152
|
-
node = n
|
|
153
|
-
nodeCache.push(node)
|
|
154
|
-
if (!first) {
|
|
155
|
-
node.new = true
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
node.version = latestTask
|
|
160
|
-
|
|
167
|
+
const children = nodes.map(async (node) => {
|
|
161
168
|
const routeCode = await fs.readFile(node.fullPath, 'utf-8')
|
|
162
|
-
const hashSum = crypto.createHash('sha256')
|
|
163
|
-
hashSum.update(routeCode)
|
|
164
|
-
const hash = hashSum.digest('hex')
|
|
165
169
|
|
|
166
|
-
|
|
167
|
-
if (node.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
// Ensure the boilerplate for the route exists
|
|
171
|
+
if (node.isRoot) {
|
|
172
|
+
return
|
|
173
|
+
}
|
|
170
174
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
175
|
+
// Ensure that new FileRoute(anything?) is replace with FileRoute(${node.routePath})
|
|
176
|
+
const replaced = routeCode.replace(
|
|
177
|
+
fileRouteRegex,
|
|
178
|
+
`new FileRoute('${node.routePath}')`,
|
|
179
|
+
)
|
|
174
180
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
} catch (err) {
|
|
179
|
-
node.hash = ''
|
|
180
|
-
throw err
|
|
181
|
-
}
|
|
181
|
+
if (replaced !== routeCode) {
|
|
182
|
+
await fs.writeFile(node.fullPath, replaced)
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
const route = `${node.variableName}Route`
|
|
185
186
|
|
|
186
|
-
routeConfigImports.push(
|
|
187
|
-
`import { route as ${route} } from './${removeExt(
|
|
188
|
-
path.relative(
|
|
189
|
-
path.dirname(config.generatedRouteTree),
|
|
190
|
-
path.resolve(config.routesDirectory, node.filename),
|
|
191
|
-
),
|
|
192
|
-
)}'`,
|
|
193
|
-
)
|
|
194
|
-
|
|
195
187
|
if (node.children?.length) {
|
|
196
188
|
const childConfigs = await buildRouteConfig(node.children, depth + 1)
|
|
197
|
-
return `${route}.addChildren([
|
|
198
|
-
depth * 4,
|
|
199
|
-
)}${childConfigs}\n${spaces(depth * 2)}])`
|
|
189
|
+
return `${route}.addChildren([${spaces(depth * 4)}${childConfigs}])`
|
|
200
190
|
}
|
|
201
191
|
|
|
202
192
|
return route
|
|
203
193
|
})
|
|
204
194
|
|
|
205
|
-
return (await Promise.all(children))
|
|
206
|
-
.filter(Boolean)
|
|
207
|
-
.join(`,\n${spaces(depth * 2)}`)
|
|
195
|
+
return (await Promise.all(children)).filter(Boolean).join(`,`)
|
|
208
196
|
}
|
|
209
197
|
|
|
210
198
|
const routeConfigChildrenText = await buildRouteConfig(routeTree)
|
|
211
199
|
|
|
212
|
-
|
|
213
|
-
(d) => (d.includes(rootRouteName) ? -1 : 1),
|
|
214
|
-
(d) => d.split('/').length,
|
|
215
|
-
(d) => (d.endsWith("index'") ? -1 : 1),
|
|
216
|
-
(d) => d,
|
|
217
|
-
])
|
|
218
|
-
|
|
219
|
-
const routeConfig = `export const routeTree = rootRoute.addChildren([\n ${routeConfigChildrenText}\n])`
|
|
220
|
-
|
|
221
|
-
const routeConfigFileContent = [
|
|
200
|
+
const routeImports = [
|
|
222
201
|
`import { route as rootRoute } from './${path.relative(
|
|
223
202
|
path.dirname(config.generatedRouteTree),
|
|
224
|
-
path.resolve(config.routesDirectory,
|
|
203
|
+
path.resolve(config.routesDirectory, rootPathId),
|
|
225
204
|
)}'`,
|
|
226
|
-
|
|
227
|
-
|
|
205
|
+
...multiSortBy(routeNodes, [
|
|
206
|
+
(d) => (d.routePath?.includes(`/${rootPathId}`) ? -1 : 1),
|
|
207
|
+
(d) => d.routePath?.split('/').length,
|
|
208
|
+
(d) => (d.routePath?.endsWith("index'") ? -1 : 1),
|
|
209
|
+
(d) => d,
|
|
210
|
+
]).map((node) => {
|
|
211
|
+
return `import { route as ${node.variableName}Route } from './${removeExt(
|
|
212
|
+
path.relative(
|
|
213
|
+
path.dirname(config.generatedRouteTree),
|
|
214
|
+
path.resolve(config.routesDirectory, node.filePath),
|
|
215
|
+
),
|
|
216
|
+
)}'`
|
|
217
|
+
}),
|
|
218
|
+
].join('\n')
|
|
219
|
+
|
|
220
|
+
const routeTypes = `declare module '@tanstack/react-router' {
|
|
228
221
|
interface FileRoutesByPath {
|
|
229
222
|
${routeNodes
|
|
230
223
|
.map((routeNode) => {
|
|
231
224
|
return `'${routeNode.routePath}': {
|
|
232
|
-
|
|
233
|
-
|
|
225
|
+
parentRoute: typeof ${routeNode.parent?.variableName ?? 'root'}Route
|
|
226
|
+
}`
|
|
234
227
|
})
|
|
235
|
-
.join('\n
|
|
228
|
+
.join('\n')}
|
|
236
229
|
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
230
|
+
}`
|
|
231
|
+
|
|
232
|
+
const routeOptions = routeNodes
|
|
233
|
+
.map((routeNode) => {
|
|
234
|
+
return `Object.assign(${routeNode.variableName ?? 'root'}Route.options, {
|
|
235
|
+
${[
|
|
236
|
+
routeNode.isNonPath
|
|
237
|
+
? `id: '${routeNode.cleanedPath}'`
|
|
238
|
+
: `path: '${routeNode.cleanedPath}'`,
|
|
239
|
+
`getParentRoute: () => ${
|
|
240
|
+
routeNode.parent?.variableName ?? 'root'
|
|
241
|
+
}Route`,
|
|
242
|
+
routeNode.layoutLimit
|
|
243
|
+
? `layoutLimit: '${routeNode.layoutLimit}'`
|
|
244
|
+
: '',
|
|
245
|
+
// `\n// ${JSON.stringify(
|
|
246
|
+
// {
|
|
247
|
+
// ...routeNode,
|
|
248
|
+
// parent: undefined,
|
|
249
|
+
// children: undefined,
|
|
250
|
+
// fullPath: undefined,
|
|
251
|
+
// variableName: undefined,
|
|
252
|
+
// },
|
|
253
|
+
// null,
|
|
254
|
+
// 2,
|
|
255
|
+
// )
|
|
256
|
+
// .split('\n')
|
|
257
|
+
// .join('\n// ')}`,
|
|
258
|
+
]
|
|
259
|
+
.filter(Boolean)
|
|
260
|
+
.join(',')}
|
|
261
|
+
})`
|
|
262
|
+
})
|
|
263
|
+
.join('\n\n')
|
|
250
264
|
|
|
251
|
-
|
|
252
|
-
queueWriteFile(
|
|
253
|
-
path.resolve(config.generatedRouteTree),
|
|
254
|
-
routeConfigFileContent,
|
|
255
|
-
)
|
|
256
|
-
}
|
|
265
|
+
const routeConfig = `export const routeTree = rootRoute.addChildren([${routeConfigChildrenText}])`
|
|
257
266
|
|
|
258
|
-
|
|
267
|
+
const routeConfigFileContent = await prettier.format(
|
|
268
|
+
[routeImports, routeTypes, routeOptions, routeConfig].join('\n\n'),
|
|
269
|
+
{
|
|
270
|
+
semi: false,
|
|
271
|
+
parser: 'typescript',
|
|
272
|
+
},
|
|
273
|
+
)
|
|
259
274
|
|
|
260
|
-
await
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (exists) {
|
|
266
|
-
current = await fs.readFile(filename, 'utf-8')
|
|
275
|
+
const routeTreeContent = await fs
|
|
276
|
+
.readFile(path.resolve(config.generatedRouteTree), 'utf-8')
|
|
277
|
+
.catch((err: any) => {
|
|
278
|
+
if (err.code === 'ENOENT') {
|
|
279
|
+
return undefined
|
|
267
280
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
}),
|
|
272
|
-
)
|
|
281
|
+
throw err
|
|
282
|
+
})
|
|
273
283
|
|
|
274
284
|
if (!checkLatest()) return
|
|
275
285
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
const newNodes = nodeCache.filter((d) => d.new)
|
|
287
|
-
const updatedNodes = nodeCache.filter((d) => !d.new && d.changed)
|
|
286
|
+
if (routeTreeContent !== routeConfigFileContent) {
|
|
287
|
+
await fs.ensureDir(path.dirname(path.resolve(config.generatedRouteTree)))
|
|
288
|
+
if (!checkLatest()) return
|
|
289
|
+
await fs.writeFile(
|
|
290
|
+
path.resolve(config.generatedRouteTree),
|
|
291
|
+
routeConfigFileContent,
|
|
292
|
+
)
|
|
293
|
+
}
|
|
288
294
|
|
|
289
295
|
console.log(
|
|
290
|
-
`🌲 Processed ${
|
|
296
|
+
`🌲 Processed ${routeNodes.length} routes in ${Date.now() - start}ms`,
|
|
291
297
|
)
|
|
292
|
-
|
|
293
|
-
if (newNodes.length || updatedNodes.length || removedNodes.length) {
|
|
294
|
-
if (newNodes.length) {
|
|
295
|
-
console.log(`🥳 Added ${newNodes.length} new routes`)
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (updatedNodes.length) {
|
|
299
|
-
console.log(`✅ Updated ${updatedNodes.length} routes`)
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
if (removedNodes.length) {
|
|
303
|
-
console.log(`🗑 Removed ${removedNodes.length} unused routes`)
|
|
304
|
-
}
|
|
305
|
-
} else {
|
|
306
|
-
console.log(`🎉 No changes were found. Carry on!`)
|
|
307
|
-
}
|
|
308
298
|
}
|
|
309
299
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
`new FileRoute('${node.routePath}')`,
|
|
300
|
+
function fileToVariable(d: string): string {
|
|
301
|
+
return (
|
|
302
|
+
removeUnderscores(d)
|
|
303
|
+
?.replace(/\$/g, '')
|
|
304
|
+
?.split(/[/-]/g)
|
|
305
|
+
.map((d, i) => (i > 0 ? capitalize(d) : d))
|
|
306
|
+
.join('')
|
|
307
|
+
.replace(/([^a-zA-Z0-9]|[\.])/gm, '') ?? ''
|
|
319
308
|
)
|
|
320
|
-
|
|
321
|
-
if (replaced !== code) {
|
|
322
|
-
return replaced
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
function fileToVariable(d: string) {
|
|
329
|
-
return d
|
|
330
|
-
.split('/')
|
|
331
|
-
.map((d, i) => (i > 0 ? capitalize(d) : d))
|
|
332
|
-
.join('')
|
|
333
|
-
.replace(/([^a-zA-Z0-9]|[\.])/gm, '')
|
|
334
309
|
}
|
|
335
310
|
|
|
336
311
|
export function removeExt(d: string) {
|
|
@@ -377,3 +352,7 @@ function capitalize(s: string) {
|
|
|
377
352
|
if (typeof s !== 'string') return ''
|
|
378
353
|
return s.charAt(0).toUpperCase() + s.slice(1)
|
|
379
354
|
}
|
|
355
|
+
|
|
356
|
+
function removeUnderscores(s?: string) {
|
|
357
|
+
return s?.replace(/(^_|_$)/, '').replace(/(\/_|_\/)/, '/')
|
|
358
|
+
}
|
package/src/watch.ts
CHANGED
|
@@ -8,7 +8,7 @@ export async function watch() {
|
|
|
8
8
|
path.resolve(process.cwd(), 'tsr.config.js'),
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
-
let watcher = new chokidar.FSWatcher()
|
|
11
|
+
let watcher = new chokidar.FSWatcher({})
|
|
12
12
|
|
|
13
13
|
const generatorWatcher = async () => {
|
|
14
14
|
const config = await getConfig()
|
|
@@ -19,13 +19,6 @@ export async function watch() {
|
|
|
19
19
|
watcher = chokidar.watch(config.routesDirectory)
|
|
20
20
|
|
|
21
21
|
watcher.on('ready', async () => {
|
|
22
|
-
try {
|
|
23
|
-
await generator(config)
|
|
24
|
-
} catch (err) {
|
|
25
|
-
console.error(err)
|
|
26
|
-
console.log()
|
|
27
|
-
}
|
|
28
|
-
|
|
29
22
|
const handle = async () => {
|
|
30
23
|
try {
|
|
31
24
|
await generator(config)
|
|
@@ -35,11 +28,21 @@ export async function watch() {
|
|
|
35
28
|
}
|
|
36
29
|
}
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
await handle()
|
|
32
|
+
|
|
33
|
+
let timeout: ReturnType<typeof setTimeout>
|
|
34
|
+
|
|
35
|
+
const deduped = (file: string) => {
|
|
36
|
+
if (timeout) {
|
|
37
|
+
clearTimeout(timeout)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
timeout = setTimeout(handle, 10)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
watcher.on('change', deduped)
|
|
44
|
+
watcher.on('add', deduped)
|
|
45
|
+
watcher.on('unlink', deduped)
|
|
43
46
|
})
|
|
44
47
|
}
|
|
45
48
|
|