mirror of
https://github.com/hpd840321/starRiverProperty.git
synced 2026-06-09 16:30:29 +08:00
72d0785b50
Former-commit-id: 077d411ff67c34df692f271b177983ac96e99cd1
117 lines
4.3 KiB
JavaScript
117 lines
4.3 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* 路由表提取器
|
|
* 从格式化后的 JS 中提取 vue-router 的 routes 定义
|
|
*
|
|
* 用法: node extract-router.js <formatted-dir> <output.json>
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const parser = require('@babel/parser');
|
|
const traverse = require('@babel/traverse').default;
|
|
|
|
function extractRouter(inputDir, outputFile) {
|
|
const files = fs.readdirSync(inputDir).filter(f => f.endsWith('.formatted.js'));
|
|
const routes = [];
|
|
|
|
for (const file of files) {
|
|
const code = fs.readFileSync(path.join(inputDir, file), 'utf-8');
|
|
|
|
try {
|
|
const ast = parser.parse(code, {
|
|
sourceType: 'script',
|
|
plugins: ['jsx', 'typescript', 'classProperties', 'dynamicImport'],
|
|
errorRecovery: true,
|
|
});
|
|
|
|
traverse(ast, {
|
|
// Match routes: [...] arrays containing path/component objects
|
|
ArrayExpression(nodePath) {
|
|
const node = nodePath.node;
|
|
|
|
const hasRoutes = node.elements.some(el =>
|
|
el.type === 'ObjectExpression' &&
|
|
el.properties.some(prop => prop.key && prop.key.name === 'path')
|
|
);
|
|
|
|
if (hasRoutes) {
|
|
node.elements.forEach(el => {
|
|
if (el.type === 'ObjectExpression') {
|
|
const routeDef = {};
|
|
el.properties.forEach(prop => {
|
|
if (prop.key && prop.key.type === 'Identifier') {
|
|
if (prop.key.name === 'path' && prop.value.type === 'StringLiteral') {
|
|
routeDef.path = prop.value.value;
|
|
}
|
|
if (prop.key.name === 'name' && prop.value.type === 'StringLiteral') {
|
|
routeDef.name = prop.value.value;
|
|
}
|
|
if (prop.key.name === 'meta' && prop.value.type === 'ObjectExpression') {
|
|
routeDef.meta = {};
|
|
prop.value.properties.forEach(mp => {
|
|
if (mp.key && mp.key.type === 'Identifier') {
|
|
routeDef.meta[mp.key.name] = mp.value.type === 'StringLiteral' ? mp.value.value : true;
|
|
}
|
|
});
|
|
}
|
|
if (prop.key.name === 'component') {
|
|
routeDef.component = prop.value.type === 'ArrowFunctionExpression'
|
|
? 'lazyImport'
|
|
: (prop.value.type === 'Identifier' ? prop.value.name : 'inline');
|
|
}
|
|
}
|
|
});
|
|
|
|
if (routeDef.path && !routes.find(r => r.path === routeDef.path)) {
|
|
routes.push(routeDef);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
// Match path-like strings: /xxx/xxx
|
|
StringLiteral(nodePath) {
|
|
const value = nodePath.node.value;
|
|
if (typeof value === 'string' && /^\/[a-z][a-z0-9_/-]*$/i.test(value) && value.length > 2) {
|
|
const parent = nodePath.parent;
|
|
if (parent.type === 'ObjectProperty' && parent.key && parent.key.name === 'path') {
|
|
return; // Already handled above
|
|
}
|
|
if (!routes.find(r => r.path === value)) {
|
|
routes.push({ path: value, source: 'stringLiteral', file: file });
|
|
}
|
|
}
|
|
},
|
|
});
|
|
} catch (e) {
|
|
// Skip unparseable files
|
|
}
|
|
}
|
|
|
|
const result = routes.sort((a, b) => (a.path || '').localeCompare(b.path || ''));
|
|
|
|
fs.writeFileSync(outputFile, JSON.stringify(result, null, 2));
|
|
console.log(`提取完成: ${result.length} 条路由 → ${outputFile}`);
|
|
|
|
// Generate Markdown route table
|
|
const mdPath = outputFile.replace('.json', '.md');
|
|
let md = '# 路由表\n\n';
|
|
md += `| Path | Name | Component | Meta |\n`;
|
|
md += `|------|------|-----------|------|\n`;
|
|
result.forEach(r => {
|
|
md += `| \`${r.path || '-'}\` | ${r.name || '-'} | ${r.component || '-'} | ${r.meta ? JSON.stringify(r.meta) : '-'} |\n`;
|
|
});
|
|
fs.writeFileSync(mdPath, md);
|
|
console.log(`路由表 Markdown: ${mdPath}`);
|
|
}
|
|
|
|
const args = process.argv.slice(2);
|
|
if (args.length < 2) {
|
|
console.log('用法: node extract-router.js <formatted-dir> <output.json>');
|
|
process.exit(1);
|
|
}
|
|
|
|
extractRouter(args[0], args[1]);
|