@lark-apaas/devtool-kits 1.2.19 → 1.2.21
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/bin/generate-api-routes.cjs +189 -0
- package/dist/bin/generate-api-routes.cjs.map +1 -0
- package/dist/bin/generate-api-routes.d.cts +1 -0
- package/dist/bin/generate-api-routes.d.ts +1 -0
- package/dist/bin/generate-api-routes.js +43 -0
- package/dist/bin/generate-api-routes.js.map +1 -0
- package/dist/bin/generate-page-routes.cjs +227 -0
- package/dist/bin/generate-page-routes.cjs.map +1 -0
- package/dist/bin/generate-page-routes.d.cts +1 -0
- package/dist/bin/generate-page-routes.d.ts +1 -0
- package/dist/bin/generate-page-routes.js +43 -0
- package/dist/bin/generate-page-routes.js.map +1 -0
- package/dist/chunk-7QVYU63E.js +7 -0
- package/dist/chunk-7QVYU63E.js.map +1 -0
- package/dist/chunk-LSHFHCDF.js +350 -0
- package/dist/chunk-LSHFHCDF.js.map +1 -0
- package/dist/chunk-YPNLFWHQ.js +189 -0
- package/dist/chunk-YPNLFWHQ.js.map +1 -0
- package/dist/index.cjs +475 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -3
- package/dist/index.d.ts +41 -3
- package/dist/index.js +202 -276
- package/dist/index.js.map +1 -1
- package/package.json +9 -2
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-7QVYU63E.js";
|
|
4
|
+
|
|
5
|
+
// src/middlewares/openapi/services.ts
|
|
6
|
+
import { promises as fs2 } from "fs";
|
|
7
|
+
import * as fsSync from "fs";
|
|
8
|
+
import path2 from "path";
|
|
9
|
+
import ts from "typescript";
|
|
10
|
+
|
|
11
|
+
// src/middlewares/openapi/utils.ts
|
|
12
|
+
import path from "path";
|
|
13
|
+
import { promises as fs } from "fs";
|
|
14
|
+
async function findControllerFiles(dir) {
|
|
15
|
+
const files = [];
|
|
16
|
+
async function scan(currentDir) {
|
|
17
|
+
const entries = await fs.readdir(currentDir, {
|
|
18
|
+
withFileTypes: true
|
|
19
|
+
});
|
|
20
|
+
for (const entry of entries) {
|
|
21
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
22
|
+
if (entry.isDirectory()) {
|
|
23
|
+
await scan(fullPath);
|
|
24
|
+
} else if (entry.isFile() && entry.name.endsWith(".controller.ts")) {
|
|
25
|
+
files.push(fullPath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
__name(scan, "scan");
|
|
30
|
+
await scan(dir);
|
|
31
|
+
return files;
|
|
32
|
+
}
|
|
33
|
+
__name(findControllerFiles, "findControllerFiles");
|
|
34
|
+
async function buildSourceMap(controllerFiles, processFile) {
|
|
35
|
+
const sourceMap = /* @__PURE__ */ new Map();
|
|
36
|
+
const concurrency = 10;
|
|
37
|
+
const results = [];
|
|
38
|
+
for (let i = 0; i < controllerFiles.length; i += concurrency) {
|
|
39
|
+
const batch = controllerFiles.slice(i, i + concurrency);
|
|
40
|
+
const batchResults = await Promise.all(batch.map((filePath) => processFile(filePath)));
|
|
41
|
+
results.push(...batchResults);
|
|
42
|
+
}
|
|
43
|
+
for (const metadata of results) {
|
|
44
|
+
for (const [operationId, info] of metadata.entries()) {
|
|
45
|
+
sourceMap.set(operationId, info);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return sourceMap;
|
|
49
|
+
}
|
|
50
|
+
__name(buildSourceMap, "buildSourceMap");
|
|
51
|
+
function findSourceInfo(operationId, sourceMap) {
|
|
52
|
+
const directMatch = sourceMap.get(operationId);
|
|
53
|
+
if (directMatch) {
|
|
54
|
+
return directMatch;
|
|
55
|
+
}
|
|
56
|
+
for (const [key, value] of sourceMap.entries()) {
|
|
57
|
+
const [className, methodName] = key.split("_");
|
|
58
|
+
if (!className || !methodName) continue;
|
|
59
|
+
const camelCaseId = className.charAt(0).toLowerCase() + className.slice(1) + methodName.charAt(0).toUpperCase() + methodName.slice(1);
|
|
60
|
+
if (operationId === camelCaseId) {
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
if (operationId === methodName) {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
__name(findSourceInfo, "findSourceInfo");
|
|
70
|
+
function enhanceOpenApiPaths(openapi, sourceMap) {
|
|
71
|
+
let enhancedCount = 0;
|
|
72
|
+
if (!openapi.paths) {
|
|
73
|
+
return enhancedCount;
|
|
74
|
+
}
|
|
75
|
+
for (const pathItem of Object.values(openapi.paths)) {
|
|
76
|
+
if (!pathItem || typeof pathItem !== "object") continue;
|
|
77
|
+
for (const operation of Object.values(pathItem)) {
|
|
78
|
+
if (operation && typeof operation === "object" && "operationId" in operation) {
|
|
79
|
+
const sourceInfo = findSourceInfo(operation.operationId, sourceMap);
|
|
80
|
+
if (sourceInfo) {
|
|
81
|
+
operation["x-source"] = {
|
|
82
|
+
file: sourceInfo.file,
|
|
83
|
+
line: sourceInfo.line
|
|
84
|
+
};
|
|
85
|
+
enhancedCount++;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return enhancedCount;
|
|
91
|
+
}
|
|
92
|
+
__name(enhanceOpenApiPaths, "enhanceOpenApiPaths");
|
|
93
|
+
function transformOpenapiPaths(openapi, basePath) {
|
|
94
|
+
if (basePath === "/" || !openapi.paths) {
|
|
95
|
+
return openapi;
|
|
96
|
+
}
|
|
97
|
+
const newPaths = {};
|
|
98
|
+
Object.keys(openapi.paths).forEach((key) => {
|
|
99
|
+
const staticApiKey = key.startsWith(basePath) ? key.slice(basePath.length) : key;
|
|
100
|
+
newPaths[staticApiKey] = openapi.paths[key];
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
...openapi,
|
|
104
|
+
paths: newPaths,
|
|
105
|
+
basePath
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
__name(transformOpenapiPaths, "transformOpenapiPaths");
|
|
109
|
+
|
|
110
|
+
// src/middlewares/openapi/services.ts
|
|
111
|
+
async function enhanceOpenApiWithSourceInfo(options = {}) {
|
|
112
|
+
const startTime = Date.now();
|
|
113
|
+
const openapiPath = options.openapiPath || path2.resolve(__dirname, "../client/src/api/gen/openapi.json");
|
|
114
|
+
const serverDir = options.serverDir || path2.resolve(__dirname, "../server");
|
|
115
|
+
const writeFile = options.writeFile !== false;
|
|
116
|
+
let openapi;
|
|
117
|
+
if (options.openapiData) {
|
|
118
|
+
openapi = JSON.parse(JSON.stringify(options.openapiData));
|
|
119
|
+
} else {
|
|
120
|
+
const openapiContent = await fs2.readFile(openapiPath, "utf-8");
|
|
121
|
+
openapi = JSON.parse(openapiContent);
|
|
122
|
+
}
|
|
123
|
+
const controllerFiles = await findControllerFiles(serverDir);
|
|
124
|
+
const sourceMap = await buildSourceMap(controllerFiles, processControllerFile);
|
|
125
|
+
const enhanced = enhanceOpenApiPaths(openapi, sourceMap);
|
|
126
|
+
if (writeFile) {
|
|
127
|
+
await fs2.writeFile(openapiPath, JSON.stringify(openapi, null, 2) + "\n", "utf-8");
|
|
128
|
+
}
|
|
129
|
+
const duration = Date.now() - startTime;
|
|
130
|
+
return {
|
|
131
|
+
openapi,
|
|
132
|
+
stats: {
|
|
133
|
+
duration,
|
|
134
|
+
controllersFound: controllerFiles.length,
|
|
135
|
+
endpointsExtracted: sourceMap.size,
|
|
136
|
+
endpointsEnhanced: enhanced
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
__name(enhanceOpenApiWithSourceInfo, "enhanceOpenApiWithSourceInfo");
|
|
141
|
+
async function processControllerFile(filePath) {
|
|
142
|
+
const relativePath = path2.relative(process.cwd(), filePath);
|
|
143
|
+
const content = await fs2.readFile(filePath, "utf-8");
|
|
144
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
145
|
+
return extractControllerMetadata(sourceFile, relativePath);
|
|
146
|
+
}
|
|
147
|
+
__name(processControllerFile, "processControllerFile");
|
|
148
|
+
function extractControllerMetadata(sourceFile, filePath) {
|
|
149
|
+
const metadata = /* @__PURE__ */ new Map();
|
|
150
|
+
let controllerPath = "";
|
|
151
|
+
let className = "";
|
|
152
|
+
function getDecorators(node) {
|
|
153
|
+
if ("modifiers" in node && Array.isArray(node.modifiers)) {
|
|
154
|
+
return node.modifiers.filter((mod) => mod.kind === ts.SyntaxKind.Decorator);
|
|
155
|
+
}
|
|
156
|
+
if ("decorators" in node && Array.isArray(node.decorators)) {
|
|
157
|
+
return node.decorators;
|
|
158
|
+
}
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
__name(getDecorators, "getDecorators");
|
|
162
|
+
function visit(node) {
|
|
163
|
+
if (ts.isClassDeclaration(node)) {
|
|
164
|
+
const decorators = getDecorators(node);
|
|
165
|
+
if (node.name) {
|
|
166
|
+
className = node.name.getText(sourceFile);
|
|
167
|
+
}
|
|
168
|
+
for (const decorator of decorators) {
|
|
169
|
+
if (ts.isCallExpression(decorator.expression)) {
|
|
170
|
+
const expression = decorator.expression;
|
|
171
|
+
const decoratorName = expression.expression.getText(sourceFile);
|
|
172
|
+
if (decoratorName === "Controller") {
|
|
173
|
+
if (expression.arguments.length > 0) {
|
|
174
|
+
const arg = expression.arguments[0];
|
|
175
|
+
if (ts.isStringLiteral(arg)) {
|
|
176
|
+
controllerPath = arg.text;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (ts.isMethodDeclaration(node) && node.name) {
|
|
184
|
+
const methodName = node.name.getText(sourceFile);
|
|
185
|
+
let httpMethod = "";
|
|
186
|
+
let routePath = "";
|
|
187
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
188
|
+
const decorators = getDecorators(node);
|
|
189
|
+
for (const decorator of decorators) {
|
|
190
|
+
if (ts.isCallExpression(decorator.expression)) {
|
|
191
|
+
const decoratorName = decorator.expression.expression.getText(sourceFile);
|
|
192
|
+
if ([
|
|
193
|
+
"Get",
|
|
194
|
+
"Post",
|
|
195
|
+
"Put",
|
|
196
|
+
"Delete",
|
|
197
|
+
"Patch",
|
|
198
|
+
"Options",
|
|
199
|
+
"Head",
|
|
200
|
+
"All"
|
|
201
|
+
].includes(decoratorName)) {
|
|
202
|
+
httpMethod = decoratorName.toLowerCase();
|
|
203
|
+
if (decorator.expression.arguments.length > 0) {
|
|
204
|
+
const arg = decorator.expression.arguments[0];
|
|
205
|
+
if (ts.isStringLiteral(arg)) {
|
|
206
|
+
routePath = arg.text;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (httpMethod && methodName && className) {
|
|
213
|
+
const operationId = `${className}_${methodName}`;
|
|
214
|
+
metadata.set(operationId, {
|
|
215
|
+
file: filePath,
|
|
216
|
+
line: line + 1,
|
|
217
|
+
method: httpMethod,
|
|
218
|
+
controllerPath,
|
|
219
|
+
routePath
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
ts.forEachChild(node, visit);
|
|
224
|
+
}
|
|
225
|
+
__name(visit, "visit");
|
|
226
|
+
visit(sourceFile);
|
|
227
|
+
return metadata;
|
|
228
|
+
}
|
|
229
|
+
__name(extractControllerMetadata, "extractControllerMetadata");
|
|
230
|
+
var HTTP_DECORATOR_NAMES = [
|
|
231
|
+
"Get",
|
|
232
|
+
"Post",
|
|
233
|
+
"Put",
|
|
234
|
+
"Delete",
|
|
235
|
+
"Patch",
|
|
236
|
+
"Options",
|
|
237
|
+
"Head",
|
|
238
|
+
"All"
|
|
239
|
+
];
|
|
240
|
+
function findControllerFilesSync(dir) {
|
|
241
|
+
const files = [];
|
|
242
|
+
function scan(currentDir) {
|
|
243
|
+
let entries;
|
|
244
|
+
try {
|
|
245
|
+
entries = fsSync.readdirSync(currentDir, {
|
|
246
|
+
withFileTypes: true
|
|
247
|
+
});
|
|
248
|
+
} catch {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
for (const entry of entries) {
|
|
252
|
+
const fullPath = path2.join(currentDir, entry.name);
|
|
253
|
+
if (entry.isDirectory()) {
|
|
254
|
+
scan(fullPath);
|
|
255
|
+
} else if (entry.isFile() && entry.name.endsWith(".controller.ts")) {
|
|
256
|
+
files.push(fullPath);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
__name(scan, "scan");
|
|
261
|
+
scan(dir);
|
|
262
|
+
return files;
|
|
263
|
+
}
|
|
264
|
+
__name(findControllerFilesSync, "findControllerFilesSync");
|
|
265
|
+
function normalizeApiPath(controllerPath, routePath) {
|
|
266
|
+
const combined = routePath ? `${controllerPath}/${routePath}` : controllerPath;
|
|
267
|
+
let normalized = combined.replace(/\/+/g, "/");
|
|
268
|
+
if (!normalized.startsWith("/")) normalized = `/${normalized}`;
|
|
269
|
+
if (normalized.length > 1 && normalized.endsWith("/")) normalized = normalized.slice(0, -1);
|
|
270
|
+
return normalized;
|
|
271
|
+
}
|
|
272
|
+
__name(normalizeApiPath, "normalizeApiPath");
|
|
273
|
+
function parseControllerRoutes(filePath) {
|
|
274
|
+
let content;
|
|
275
|
+
try {
|
|
276
|
+
content = fsSync.readFileSync(filePath, "utf-8");
|
|
277
|
+
} catch {
|
|
278
|
+
return [];
|
|
279
|
+
}
|
|
280
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
281
|
+
const routes = [];
|
|
282
|
+
function getDecoratorsCompat(node) {
|
|
283
|
+
if ("modifiers" in node && Array.isArray(node.modifiers)) {
|
|
284
|
+
return node.modifiers.filter((mod) => mod.kind === ts.SyntaxKind.Decorator);
|
|
285
|
+
}
|
|
286
|
+
if ("decorators" in node && Array.isArray(node.decorators)) {
|
|
287
|
+
return node.decorators;
|
|
288
|
+
}
|
|
289
|
+
return [];
|
|
290
|
+
}
|
|
291
|
+
__name(getDecoratorsCompat, "getDecoratorsCompat");
|
|
292
|
+
function getStringArg(expr) {
|
|
293
|
+
if (expr.arguments.length > 0 && ts.isStringLiteral(expr.arguments[0])) {
|
|
294
|
+
return expr.arguments[0].text;
|
|
295
|
+
}
|
|
296
|
+
return "";
|
|
297
|
+
}
|
|
298
|
+
__name(getStringArg, "getStringArg");
|
|
299
|
+
function visit(node) {
|
|
300
|
+
if (ts.isClassDeclaration(node)) {
|
|
301
|
+
let controllerPath = "";
|
|
302
|
+
for (const dec of getDecoratorsCompat(node)) {
|
|
303
|
+
if (ts.isCallExpression(dec.expression)) {
|
|
304
|
+
const name = dec.expression.expression.getText(sourceFile);
|
|
305
|
+
if (name === "Controller") {
|
|
306
|
+
controllerPath = getStringArg(dec.expression);
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
for (const member of node.members) {
|
|
312
|
+
if (!ts.isMethodDeclaration(member)) continue;
|
|
313
|
+
for (const dec of getDecoratorsCompat(member)) {
|
|
314
|
+
if (!ts.isCallExpression(dec.expression)) continue;
|
|
315
|
+
const decoratorName = dec.expression.expression.getText(sourceFile);
|
|
316
|
+
if (!HTTP_DECORATOR_NAMES.includes(decoratorName)) continue;
|
|
317
|
+
const routePath = getStringArg(dec.expression);
|
|
318
|
+
const fullPath = normalizeApiPath(controllerPath, routePath);
|
|
319
|
+
const method = decoratorName === "All" ? "*" : decoratorName.toUpperCase();
|
|
320
|
+
routes.push({
|
|
321
|
+
method,
|
|
322
|
+
path: fullPath
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
ts.forEachChild(node, visit);
|
|
328
|
+
}
|
|
329
|
+
__name(visit, "visit");
|
|
330
|
+
visit(sourceFile);
|
|
331
|
+
return routes;
|
|
332
|
+
}
|
|
333
|
+
__name(parseControllerRoutes, "parseControllerRoutes");
|
|
334
|
+
function parseApiRoutes(serverDir) {
|
|
335
|
+
const resolvedDir = path2.resolve(serverDir);
|
|
336
|
+
const controllerFiles = findControllerFilesSync(resolvedDir);
|
|
337
|
+
const routes = [];
|
|
338
|
+
for (const filePath of controllerFiles) {
|
|
339
|
+
routes.push(...parseControllerRoutes(filePath));
|
|
340
|
+
}
|
|
341
|
+
return routes;
|
|
342
|
+
}
|
|
343
|
+
__name(parseApiRoutes, "parseApiRoutes");
|
|
344
|
+
|
|
345
|
+
export {
|
|
346
|
+
transformOpenapiPaths,
|
|
347
|
+
enhanceOpenApiWithSourceInfo,
|
|
348
|
+
parseApiRoutes
|
|
349
|
+
};
|
|
350
|
+
//# sourceMappingURL=chunk-LSHFHCDF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/middlewares/openapi/services.ts","../src/middlewares/openapi/utils.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport * as fsSync from 'node:fs';\nimport path from 'node:path';\nimport ts from 'typescript';\nimport type { SourceInfo, EnhanceOptions, EnhanceResult } from './types';\nimport { findControllerFiles, buildSourceMap, enhanceOpenApiPaths } from './utils';\n\n/**\n * Enhances OpenAPI JSON with source file location metadata\n * Can be called programmatically or run as a script\n */\nexport async function enhanceOpenApiWithSourceInfo(options: EnhanceOptions = {}): Promise<EnhanceResult> {\n const startTime = Date.now();\n\n const openapiPath = options.openapiPath || path.resolve(__dirname, '../client/src/api/gen/openapi.json');\n const serverDir = options.serverDir || path.resolve(__dirname, '../server');\n const writeFile = options.writeFile !== false;\n\n let openapi: any;\n if (options.openapiData) {\n // Use provided data (for in-memory enhancement)\n openapi = JSON.parse(JSON.stringify(options.openapiData)); // Deep clone\n } else {\n // Read from file\n const openapiContent = await fs.readFile(openapiPath, 'utf-8');\n openapi = JSON.parse(openapiContent);\n }\n\n const controllerFiles = await findControllerFiles(serverDir);\n const sourceMap = await buildSourceMap(controllerFiles, processControllerFile);\n const enhanced = enhanceOpenApiPaths(openapi, sourceMap);\n\n if (writeFile) {\n await fs.writeFile(openapiPath, JSON.stringify(openapi, null, 2) + '\\n', 'utf-8');\n }\n\n const duration = Date.now() - startTime;\n\n return {\n openapi,\n stats: {\n duration,\n controllersFound: controllerFiles.length,\n endpointsExtracted: sourceMap.size,\n endpointsEnhanced: enhanced,\n },\n };\n}\n\n/**\n * Process a single controller file\n */\nasync function processControllerFile(filePath: string): Promise<Map<string, SourceInfo>> {\n const relativePath = path.relative(process.cwd(), filePath);\n\n // Parse file\n const content = await fs.readFile(filePath, 'utf-8');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n return extractControllerMetadata(sourceFile, relativePath);\n}\n\n/**\n * Extract controller metadata from TypeScript source file\n */\nfunction extractControllerMetadata(sourceFile: ts.SourceFile, filePath: string): Map<string, SourceInfo> {\n const metadata = new Map<string, SourceInfo>();\n let controllerPath = '';\n let className = '';\n\n // Helper function to get decorators from both old and new TypeScript APIs\n function getDecorators(node: ts.Node): readonly ts.Decorator[] {\n // TypeScript 5.x: decorators are in modifiers array\n if ('modifiers' in node && Array.isArray(node.modifiers)) {\n return (node.modifiers as ts.ModifierLike[]).filter(\n (mod): mod is ts.Decorator => mod.kind === ts.SyntaxKind.Decorator,\n );\n }\n // TypeScript 4.x: decorators are in decorators array\n if ('decorators' in node && Array.isArray(node.decorators)) {\n return node.decorators as readonly ts.Decorator[];\n }\n return [];\n }\n\n function visit(node: ts.Node): void {\n // Extract @Controller decorator and its path\n if (ts.isClassDeclaration(node)) {\n const decorators = getDecorators(node);\n\n // Extract class name\n if (node.name) {\n className = node.name.getText(sourceFile);\n }\n\n for (const decorator of decorators) {\n if (ts.isCallExpression(decorator.expression)) {\n const expression = decorator.expression;\n const decoratorName = expression.expression.getText(sourceFile);\n\n if (decoratorName === 'Controller') {\n if (expression.arguments.length > 0) {\n const arg = expression.arguments[0];\n if (ts.isStringLiteral(arg)) {\n controllerPath = arg.text;\n }\n }\n }\n }\n }\n }\n\n // Extract methods with HTTP decorators\n if (ts.isMethodDeclaration(node) && node.name) {\n const methodName = node.name.getText(sourceFile);\n let httpMethod = '';\n let routePath = '';\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));\n\n const decorators = getDecorators(node);\n\n for (const decorator of decorators) {\n if (ts.isCallExpression(decorator.expression)) {\n const decoratorName = decorator.expression.expression.getText(sourceFile);\n if (['Get', 'Post', 'Put', 'Delete', 'Patch', 'Options', 'Head', 'All'].includes(decoratorName)) {\n httpMethod = decoratorName.toLowerCase();\n if (decorator.expression.arguments.length > 0) {\n const arg = decorator.expression.arguments[0];\n if (ts.isStringLiteral(arg)) {\n routePath = arg.text;\n }\n }\n }\n }\n }\n\n if (httpMethod && methodName && className) {\n const operationId = `${className}_${methodName}`;\n metadata.set(operationId, {\n file: filePath,\n line: line + 1,\n method: httpMethod,\n controllerPath,\n routePath,\n });\n }\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return metadata;\n}\n\n// --- API Route Parsing (synchronous, for build-time injection) ---\n\nconst HTTP_DECORATOR_NAMES = ['Get', 'Post', 'Put', 'Delete', 'Patch', 'Options', 'Head', 'All'];\n\nfunction findControllerFilesSync(dir: string): string[] {\n const files: string[] = [];\n function scan(currentDir: string): void {\n let entries: fsSync.Dirent[];\n try {\n entries = fsSync.readdirSync(currentDir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n if (entry.isDirectory()) {\n scan(fullPath);\n } else if (entry.isFile() && entry.name.endsWith('.controller.ts')) {\n files.push(fullPath);\n }\n }\n }\n scan(dir);\n return files;\n}\n\nfunction normalizeApiPath(controllerPath: string, routePath: string): string {\n const combined = routePath ? `${controllerPath}/${routePath}` : controllerPath;\n let normalized = combined.replace(/\\/+/g, '/');\n if (!normalized.startsWith('/')) normalized = `/${normalized}`;\n if (normalized.length > 1 && normalized.endsWith('/')) normalized = normalized.slice(0, -1);\n return normalized;\n}\n\nfunction parseControllerRoutes(filePath: string): Array<{ method: string; path: string }> {\n let content: string;\n try {\n content = fsSync.readFileSync(filePath, 'utf-8');\n } catch {\n return [];\n }\n\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n const routes: Array<{ method: string; path: string }> = [];\n\n function getDecoratorsCompat(node: ts.Node): readonly ts.Decorator[] {\n if ('modifiers' in node && Array.isArray(node.modifiers)) {\n return (node.modifiers as ts.ModifierLike[]).filter(\n (mod): mod is ts.Decorator => mod.kind === ts.SyntaxKind.Decorator,\n );\n }\n if ('decorators' in node && Array.isArray(node.decorators)) {\n return node.decorators as readonly ts.Decorator[];\n }\n return [];\n }\n\n function getStringArg(expr: ts.CallExpression): string {\n if (expr.arguments.length > 0 && ts.isStringLiteral(expr.arguments[0])) {\n return expr.arguments[0].text;\n }\n return '';\n }\n\n function visit(node: ts.Node): void {\n if (ts.isClassDeclaration(node)) {\n let controllerPath = '';\n for (const dec of getDecoratorsCompat(node)) {\n if (ts.isCallExpression(dec.expression)) {\n const name = dec.expression.expression.getText(sourceFile);\n if (name === 'Controller') {\n controllerPath = getStringArg(dec.expression);\n break;\n }\n }\n }\n\n for (const member of node.members) {\n if (!ts.isMethodDeclaration(member)) continue;\n for (const dec of getDecoratorsCompat(member)) {\n if (!ts.isCallExpression(dec.expression)) continue;\n const decoratorName = dec.expression.expression.getText(sourceFile);\n if (!HTTP_DECORATOR_NAMES.includes(decoratorName)) continue;\n\n const routePath = getStringArg(dec.expression);\n const fullPath = normalizeApiPath(controllerPath, routePath);\n const method = decoratorName === 'All' ? '*' : decoratorName.toUpperCase();\n routes.push({ method, path: fullPath });\n }\n }\n }\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return routes;\n}\n\n/**\n * Scan serverDir for NestJS controller files and extract all parameterized API routes.\n * Synchronous — safe to call at preset config time (before bundling).\n */\nexport function parseApiRoutes(serverDir: string): Array<{ method: string; path: string }> {\n const resolvedDir = path.resolve(serverDir);\n const controllerFiles = findControllerFilesSync(resolvedDir);\n const routes: Array<{ method: string; path: string }> = [];\n for (const filePath of controllerFiles) {\n routes.push(...parseControllerRoutes(filePath));\n }\n return routes;\n}\n","import path from 'node:path';\nimport { promises as fs } from 'node:fs';\nimport type { SourceInfo } from './types';\n\n/**\n * Find all controller files in a directory\n */\nexport async function findControllerFiles(dir: string): Promise<string[]> {\n const files: string[] = [];\n\n async function scan(currentDir: string): Promise<void> {\n const entries = await fs.readdir(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n\n if (entry.isDirectory()) {\n await scan(fullPath);\n } else if (entry.isFile() && entry.name.endsWith('.controller.ts')) {\n files.push(fullPath);\n }\n }\n }\n\n await scan(dir);\n return files;\n}\n\n/**\n * Build source map from controller files\n */\nexport async function buildSourceMap(\n controllerFiles: string[],\n processFile: (filePath: string) => Promise<Map<string, SourceInfo>>,\n): Promise<Map<string, SourceInfo>> {\n const sourceMap = new Map<string, SourceInfo>();\n\n // Process files in parallel with a concurrency limit\n const concurrency = 10;\n const results: Map<string, SourceInfo>[] = [];\n\n for (let i = 0; i < controllerFiles.length; i += concurrency) {\n const batch = controllerFiles.slice(i, i + concurrency);\n const batchResults = await Promise.all(batch.map((filePath) => processFile(filePath)));\n results.push(...batchResults);\n }\n\n // Merge results\n for (const metadata of results) {\n for (const [operationId, info] of metadata.entries()) {\n sourceMap.set(operationId, info);\n }\n }\n\n return sourceMap;\n}\n\n/**\n * Try to match operationId with different formats\n * Supports:\n * - Direct match: ClassName_methodName\n * - Camel case: classNameMethodName\n * - Method only: methodName\n */\nfunction findSourceInfo(operationId: string, sourceMap: Map<string, SourceInfo>): SourceInfo | undefined {\n // Try direct match first\n const directMatch = sourceMap.get(operationId);\n if (directMatch) {\n return directMatch;\n }\n\n // Try matching with different formats\n for (const [key, value] of sourceMap.entries()) {\n // key format: ClassName_methodName\n const [className, methodName] = key.split('_');\n if (!className || !methodName) continue;\n\n // Try camelCase format: classNameMethodName\n const camelCaseId = className.charAt(0).toLowerCase() + className.slice(1) + methodName.charAt(0).toUpperCase() + methodName.slice(1);\n if (operationId === camelCaseId) {\n return value;\n }\n\n // Try method name only\n if (operationId === methodName) {\n return value;\n }\n }\n\n return undefined;\n}\n\n/**\n * Enhance OpenAPI paths with source information\n */\nexport function enhanceOpenApiPaths(openapi: any, sourceMap: Map<string, SourceInfo>): number {\n let enhancedCount = 0;\n\n if (!openapi.paths) {\n return enhancedCount;\n }\n\n for (const pathItem of Object.values(openapi.paths)) {\n if (!pathItem || typeof pathItem !== 'object') continue;\n\n for (const operation of Object.values(pathItem)) {\n if (operation && typeof operation === 'object' && 'operationId' in operation) {\n const sourceInfo = findSourceInfo(operation.operationId as string, sourceMap);\n if (sourceInfo) {\n operation['x-source'] = {\n file: sourceInfo.file,\n line: sourceInfo.line,\n };\n enhancedCount++;\n }\n }\n }\n }\n\n return enhancedCount;\n}\n\n/**\n * Transform OpenAPI paths by removing basePath prefix\n */\nexport function transformOpenapiPaths(openapi: any, basePath: string): any {\n if (basePath === '/' || !openapi.paths) {\n return openapi;\n }\n\n const newPaths: any = {};\n Object.keys(openapi.paths).forEach((key) => {\n const staticApiKey = key.startsWith(basePath) ? key.slice(basePath.length) : key;\n newPaths[staticApiKey] = openapi.paths[key];\n });\n\n return {\n ...openapi,\n paths: newPaths,\n basePath,\n };\n}\n"],"mappings":"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","names":["promises","fs","fsSync","path","ts","path","promises","fs","findControllerFiles","dir","files","scan","currentDir","entries","fs","readdir","withFileTypes","entry","fullPath","path","join","name","isDirectory","isFile","endsWith","push","buildSourceMap","controllerFiles","processFile","sourceMap","Map","concurrency","results","i","length","batch","slice","batchResults","Promise","all","map","filePath","metadata","operationId","info","set","findSourceInfo","directMatch","get","key","value","className","methodName","split","camelCaseId","charAt","toLowerCase","toUpperCase","undefined","enhanceOpenApiPaths","openapi","enhancedCount","paths","pathItem","Object","values","operation","sourceInfo","file","line","transformOpenapiPaths","basePath","newPaths","keys","forEach","staticApiKey","startsWith","enhanceOpenApiWithSourceInfo","options","startTime","Date","now","openapiPath","path","resolve","__dirname","serverDir","writeFile","openapi","openapiData","JSON","parse","stringify","openapiContent","fs","readFile","controllerFiles","findControllerFiles","sourceMap","buildSourceMap","processControllerFile","enhanced","enhanceOpenApiPaths","duration","stats","controllersFound","length","endpointsExtracted","size","endpointsEnhanced","filePath","relativePath","relative","process","cwd","content","sourceFile","ts","createSourceFile","ScriptTarget","Latest","extractControllerMetadata","metadata","Map","controllerPath","className","getDecorators","node","Array","isArray","modifiers","filter","mod","kind","SyntaxKind","Decorator","decorators","visit","isClassDeclaration","name","getText","decorator","isCallExpression","expression","decoratorName","arguments","arg","isStringLiteral","text","isMethodDeclaration","methodName","httpMethod","routePath","line","getLineAndCharacterOfPosition","getStart","includes","toLowerCase","operationId","set","file","method","forEachChild","HTTP_DECORATOR_NAMES","findControllerFilesSync","dir","files","scan","currentDir","entries","readdirSync","withFileTypes","entry","fullPath","join","isDirectory","isFile","endsWith","push","normalizeApiPath","combined","normalized","replace","startsWith","slice","parseControllerRoutes","readFileSync","routes","getDecoratorsCompat","getStringArg","expr","dec","member","members","toUpperCase","parseApiRoutes","resolvedDir"]}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-7QVYU63E.js";
|
|
4
|
+
|
|
5
|
+
// src/route-parser.ts
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
import * as crypto from "crypto";
|
|
9
|
+
import { parse } from "@babel/parser";
|
|
10
|
+
import _traverse from "@babel/traverse";
|
|
11
|
+
import * as t from "@babel/types";
|
|
12
|
+
var traverse = typeof _traverse === "function" ? _traverse : _traverse.default;
|
|
13
|
+
function routeParserLog(level, message, ...args) {
|
|
14
|
+
const prefix = "[route-parser]";
|
|
15
|
+
const logMessage = `${prefix} ${message}`;
|
|
16
|
+
switch (level) {
|
|
17
|
+
case "warn":
|
|
18
|
+
console.warn(logMessage, ...args);
|
|
19
|
+
break;
|
|
20
|
+
case "error":
|
|
21
|
+
console.error(logMessage, ...args);
|
|
22
|
+
break;
|
|
23
|
+
case "info":
|
|
24
|
+
console.info(logMessage, ...args);
|
|
25
|
+
break;
|
|
26
|
+
default:
|
|
27
|
+
console.log(logMessage, ...args);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
__name(routeParserLog, "routeParserLog");
|
|
31
|
+
function calculateFileHash(filePath) {
|
|
32
|
+
try {
|
|
33
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
34
|
+
return crypto.createHash("md5").update(content).digest("hex");
|
|
35
|
+
} catch (error) {
|
|
36
|
+
routeParserLog("warn", "Failed to calculate file hash:", error.message);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
__name(calculateFileHash, "calculateFileHash");
|
|
41
|
+
function isRouteComponent(openingElement) {
|
|
42
|
+
return t.isJSXIdentifier(openingElement.name) && openingElement.name.name === "Route";
|
|
43
|
+
}
|
|
44
|
+
__name(isRouteComponent, "isRouteComponent");
|
|
45
|
+
function evaluateTemplateLiteral(templateLiteral) {
|
|
46
|
+
const quasis = templateLiteral.quasis;
|
|
47
|
+
const expressions = templateLiteral.expressions;
|
|
48
|
+
if (quasis.length === 1 && expressions.length === 0) {
|
|
49
|
+
return quasis[0].value.raw;
|
|
50
|
+
}
|
|
51
|
+
return quasis.map((q) => q.value.raw).join("");
|
|
52
|
+
}
|
|
53
|
+
__name(evaluateTemplateLiteral, "evaluateTemplateLiteral");
|
|
54
|
+
function extractPageRouteInfo(openingElement) {
|
|
55
|
+
const routeInfo = {};
|
|
56
|
+
openingElement.attributes.forEach((attr) => {
|
|
57
|
+
if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
|
|
58
|
+
const name = attr.name.name;
|
|
59
|
+
let value;
|
|
60
|
+
if (attr.value) {
|
|
61
|
+
if (t.isStringLiteral(attr.value)) {
|
|
62
|
+
value = attr.value.value;
|
|
63
|
+
} else if (t.isJSXExpressionContainer(attr.value)) {
|
|
64
|
+
const expression = attr.value.expression;
|
|
65
|
+
if (t.isStringLiteral(expression)) {
|
|
66
|
+
value = expression.value;
|
|
67
|
+
} else if (t.isTemplateLiteral(expression)) {
|
|
68
|
+
value = evaluateTemplateLiteral(expression);
|
|
69
|
+
} else {
|
|
70
|
+
value = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
value = true;
|
|
75
|
+
}
|
|
76
|
+
routeInfo[name] = value;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return routeInfo;
|
|
80
|
+
}
|
|
81
|
+
__name(extractPageRouteInfo, "extractPageRouteInfo");
|
|
82
|
+
function buildFullPath(routeStack, currentRoute) {
|
|
83
|
+
let fullPath = "";
|
|
84
|
+
for (let i = 0; i < routeStack.length; i++) {
|
|
85
|
+
if (routeStack[i].path) {
|
|
86
|
+
let parentPath = routeStack[i].path;
|
|
87
|
+
if (!parentPath.startsWith("/")) parentPath = `/${parentPath}`;
|
|
88
|
+
if (parentPath.endsWith("/") && parentPath !== "/") {
|
|
89
|
+
parentPath = parentPath.slice(0, -1);
|
|
90
|
+
}
|
|
91
|
+
fullPath += parentPath === "/" ? "" : parentPath;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (currentRoute.index) {
|
|
95
|
+
return fullPath || "/";
|
|
96
|
+
} else if (currentRoute.path) {
|
|
97
|
+
const routePath = currentRoute.path;
|
|
98
|
+
if (routePath === "*") {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
if (!routePath.startsWith("/")) {
|
|
102
|
+
fullPath = `${fullPath}/${routePath}`;
|
|
103
|
+
} else {
|
|
104
|
+
fullPath = routePath;
|
|
105
|
+
}
|
|
106
|
+
if (fullPath === "") fullPath = "/";
|
|
107
|
+
if (!fullPath.startsWith("/")) fullPath = `/${fullPath}`;
|
|
108
|
+
return fullPath;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
__name(buildFullPath, "buildFullPath");
|
|
113
|
+
function parseRoutesFromFile(appPath, basePath, options = {}) {
|
|
114
|
+
const { applyBasePath = true } = options;
|
|
115
|
+
const defaultPath = applyBasePath && basePath ? `${basePath}/` : "/";
|
|
116
|
+
try {
|
|
117
|
+
const appFilePath = path.resolve(process.cwd(), appPath);
|
|
118
|
+
if (!fs.existsSync(appFilePath)) {
|
|
119
|
+
throw new Error(`App file does not exist: ${appFilePath}`);
|
|
120
|
+
}
|
|
121
|
+
const sourceCode = fs.readFileSync(appFilePath, "utf-8");
|
|
122
|
+
const ast = parse(sourceCode, {
|
|
123
|
+
sourceType: "module",
|
|
124
|
+
plugins: [
|
|
125
|
+
"jsx",
|
|
126
|
+
"typescript",
|
|
127
|
+
"decorators-legacy",
|
|
128
|
+
"classProperties",
|
|
129
|
+
"objectRestSpread",
|
|
130
|
+
"functionBind",
|
|
131
|
+
"exportDefaultFrom",
|
|
132
|
+
"exportNamespaceFrom",
|
|
133
|
+
"dynamicImport",
|
|
134
|
+
"nullishCoalescingOperator",
|
|
135
|
+
"optionalChaining"
|
|
136
|
+
]
|
|
137
|
+
});
|
|
138
|
+
const routeSet = /* @__PURE__ */ new Set();
|
|
139
|
+
const routeStack = [];
|
|
140
|
+
traverse(ast, {
|
|
141
|
+
JSXElement: {
|
|
142
|
+
enter(nodePath) {
|
|
143
|
+
const { openingElement } = nodePath.node;
|
|
144
|
+
if (isRouteComponent(openingElement)) {
|
|
145
|
+
routeStack.push(extractPageRouteInfo(openingElement));
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
exit(nodePath) {
|
|
149
|
+
const { openingElement } = nodePath.node;
|
|
150
|
+
if (isRouteComponent(openingElement)) {
|
|
151
|
+
const currentRoute = routeStack.pop();
|
|
152
|
+
if (currentRoute && currentRoute.path === "*") return;
|
|
153
|
+
if (currentRoute && (currentRoute.path || currentRoute.index)) {
|
|
154
|
+
const fullPath = buildFullPath(routeStack, currentRoute);
|
|
155
|
+
if (fullPath) routeSet.add(fullPath);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
const routes = Array.from(routeSet).map((routePath) => ({
|
|
162
|
+
path: applyBasePath && basePath ? `${basePath}${routePath}` : routePath
|
|
163
|
+
}));
|
|
164
|
+
return routes.length > 0 ? routes : [
|
|
165
|
+
{
|
|
166
|
+
path: defaultPath
|
|
167
|
+
}
|
|
168
|
+
];
|
|
169
|
+
} catch (error) {
|
|
170
|
+
routeParserLog("warn", "Route parsing failed, using default routes:", error.message);
|
|
171
|
+
return [
|
|
172
|
+
{
|
|
173
|
+
path: defaultPath
|
|
174
|
+
}
|
|
175
|
+
];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
__name(parseRoutesFromFile, "parseRoutesFromFile");
|
|
179
|
+
|
|
180
|
+
export {
|
|
181
|
+
routeParserLog,
|
|
182
|
+
calculateFileHash,
|
|
183
|
+
isRouteComponent,
|
|
184
|
+
evaluateTemplateLiteral,
|
|
185
|
+
extractPageRouteInfo,
|
|
186
|
+
buildFullPath,
|
|
187
|
+
parseRoutesFromFile
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=chunk-YPNLFWHQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/route-parser.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport { parse } from '@babel/parser';\nimport _traverse from '@babel/traverse';\nimport * as t from '@babel/types';\n\n// Handle CJS default export interop in ESM context\nconst traverse = typeof _traverse === 'function' ? _traverse : (_traverse as any).default;\n\nexport interface PageRouteInfo {\n path?: string;\n index?: boolean;\n [key: string]: unknown;\n}\n\nexport interface ParseRoutesOptions {\n /** If true, prefix all routes with basePath. Default: true */\n applyBasePath?: boolean;\n}\n\nexport function routeParserLog(\n level: 'log' | 'warn' | 'error' | 'info',\n message: string,\n ...args: unknown[]\n): void {\n const prefix = '[route-parser]';\n const logMessage = `${prefix} ${message}`;\n switch (level) {\n case 'warn':\n console.warn(logMessage, ...args);\n break;\n case 'error':\n console.error(logMessage, ...args);\n break;\n case 'info':\n console.info(logMessage, ...args);\n break;\n default:\n console.log(logMessage, ...args);\n }\n}\n\nexport function calculateFileHash(filePath: string): string | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n return crypto.createHash('md5').update(content).digest('hex');\n } catch (error) {\n routeParserLog('warn', 'Failed to calculate file hash:', (error as Error).message);\n return null;\n }\n}\n\nexport function isRouteComponent(openingElement: t.JSXOpeningElement): boolean {\n return (\n t.isJSXIdentifier(openingElement.name) &&\n openingElement.name.name === 'Route'\n );\n}\n\nexport function evaluateTemplateLiteral(templateLiteral: t.TemplateLiteral): string {\n const quasis = templateLiteral.quasis;\n const expressions = templateLiteral.expressions;\n\n if (quasis.length === 1 && expressions.length === 0) {\n return quasis[0].value.raw;\n }\n\n return quasis.map((q) => q.value.raw).join('');\n}\n\nexport function extractPageRouteInfo(openingElement: t.JSXOpeningElement): PageRouteInfo {\n const routeInfo: PageRouteInfo = {};\n\n openingElement.attributes.forEach((attr) => {\n if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {\n const name = attr.name.name;\n let value: unknown;\n\n if (attr.value) {\n if (t.isStringLiteral(attr.value)) {\n value = attr.value.value;\n } else if (t.isJSXExpressionContainer(attr.value)) {\n const expression = attr.value.expression;\n if (t.isStringLiteral(expression)) {\n value = expression.value;\n } else if (t.isTemplateLiteral(expression)) {\n value = evaluateTemplateLiteral(expression);\n } else {\n value = true;\n }\n }\n } else {\n value = true;\n }\n\n routeInfo[name] = value;\n }\n });\n\n return routeInfo;\n}\n\nexport function buildFullPath(\n routeStack: PageRouteInfo[],\n currentRoute: PageRouteInfo\n): string | null {\n let fullPath = '';\n\n for (let i = 0; i < routeStack.length; i++) {\n if (routeStack[i].path) {\n let parentPath = routeStack[i].path!;\n if (!parentPath.startsWith('/')) parentPath = `/${parentPath}`;\n if (parentPath.endsWith('/') && parentPath !== '/') {\n parentPath = parentPath.slice(0, -1);\n }\n\n fullPath += parentPath === '/' ? '' : parentPath;\n }\n }\n\n if (currentRoute.index) {\n return fullPath || '/';\n } else if (currentRoute.path) {\n const routePath = currentRoute.path;\n\n if (routePath === '*') {\n return null;\n }\n\n if (!routePath.startsWith('/')) {\n fullPath = `${fullPath}/${routePath}`;\n } else {\n fullPath = routePath;\n }\n\n if (fullPath === '') fullPath = '/';\n if (!fullPath.startsWith('/')) fullPath = `/${fullPath}`;\n\n return fullPath;\n }\n\n return null;\n}\n\n/**\n * Parse routes from the app file at build time.\n * @param appPath - Path to app.tsx (relative to cwd or absolute)\n * @param basePath - Normalized base path prefix (e.g., '/my_plugin', or '' for no prefix)\n * @param options - Parse options\n * @returns Array of route definitions\n */\nexport function parseRoutesFromFile(\n appPath: string,\n basePath: string,\n options: ParseRoutesOptions = {}\n): Array<{ path: string }> {\n const { applyBasePath = true } = options;\n const defaultPath = applyBasePath && basePath ? `${basePath}/` : '/';\n\n try {\n const appFilePath = path.resolve(process.cwd(), appPath);\n\n if (!fs.existsSync(appFilePath)) {\n throw new Error(`App file does not exist: ${appFilePath}`);\n }\n\n const sourceCode = fs.readFileSync(appFilePath, 'utf-8');\n\n const ast = parse(sourceCode, {\n sourceType: 'module',\n plugins: [\n 'jsx',\n 'typescript',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n });\n\n const routeSet = new Set<string>();\n const routeStack: PageRouteInfo[] = [];\n\n traverse(ast, {\n JSXElement: {\n enter(nodePath: any) {\n const { openingElement } = nodePath.node;\n if (isRouteComponent(openingElement)) {\n routeStack.push(extractPageRouteInfo(openingElement));\n }\n },\n exit(nodePath: any) {\n const { openingElement } = nodePath.node;\n if (isRouteComponent(openingElement)) {\n const currentRoute = routeStack.pop();\n if (currentRoute && currentRoute.path === '*') return;\n if (currentRoute && (currentRoute.path || currentRoute.index)) {\n const fullPath = buildFullPath(routeStack, currentRoute);\n if (fullPath) routeSet.add(fullPath);\n }\n }\n },\n },\n });\n\n const routes = Array.from(routeSet).map((routePath) => ({\n path: applyBasePath && basePath ? `${basePath}${routePath}` : routePath,\n }));\n return routes.length > 0 ? routes : [{ path: defaultPath }];\n } catch (error) {\n routeParserLog('warn', 'Route parsing failed, using default routes:', (error as Error).message);\n return [{ path: defaultPath }];\n }\n}\n"],"mappings":"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","names":["fs","path","crypto","parse","_traverse","t","traverse","_traverse","default","routeParserLog","level","message","args","prefix","logMessage","console","warn","error","info","log","calculateFileHash","filePath","content","readFileSync","createHash","update","digest","isRouteComponent","openingElement","isJSXIdentifier","name","evaluateTemplateLiteral","templateLiteral","quasis","expressions","length","value","raw","map","q","join","extractPageRouteInfo","routeInfo","attributes","forEach","attr","isJSXAttribute","isStringLiteral","isJSXExpressionContainer","expression","isTemplateLiteral","buildFullPath","routeStack","currentRoute","fullPath","i","path","parentPath","startsWith","endsWith","slice","index","routePath","parseRoutesFromFile","appPath","basePath","options","applyBasePath","defaultPath","appFilePath","resolve","process","cwd","existsSync","Error","sourceCode","ast","parse","sourceType","plugins","routeSet","Set","JSXElement","enter","nodePath","node","push","exit","pop","add","routes","Array","from"]}
|