172 lines
5.0 KiB
JavaScript
172 lines
5.0 KiB
JavaScript
|
|
#!/usr/bin/env node
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* NestJS vs Java 路由规范化对比脚本
|
|||
|
|
* 解决参数风格差异、空子路径、模块分组等问题
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const fs = require('fs');
|
|||
|
|
const path = require('path');
|
|||
|
|
const glob = require('glob');
|
|||
|
|
|
|||
|
|
// 路由规范化函数
|
|||
|
|
function normalizeRoute(route) {
|
|||
|
|
return route
|
|||
|
|
.replace(/:([^/]+)/g, '{$1}') // :param -> {param}
|
|||
|
|
.replace(/\/$/g, '') // 移除尾部斜杠
|
|||
|
|
.replace(/^\/$/, ''); // 处理根路径
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 提取NestJS路由信息
|
|||
|
|
function extractNestJSRoutes(controllerPath) {
|
|||
|
|
const content = fs.readFileSync(controllerPath, 'utf8');
|
|||
|
|
const routes = [];
|
|||
|
|
|
|||
|
|
// 提取类级Controller路径
|
|||
|
|
const controllerMatch = content.match(/@Controller\(["'`]([^"'`]+)["'`]\)/);
|
|||
|
|
const basePath = controllerMatch ? controllerMatch[1] : '';
|
|||
|
|
|
|||
|
|
// 提取方法级路由
|
|||
|
|
const methodMatches = content.matchAll(/@(Get|Post|Put|Delete|Patch)\((["'`]([^"'`]*)["'`])?\)[\s\S]*?(async\s+)?(\w+)\s*\(/g);
|
|||
|
|
|
|||
|
|
for (const match of methodMatches) {
|
|||
|
|
const method = match[1].toUpperCase();
|
|||
|
|
const subPath = match[3] || '';
|
|||
|
|
const fullPath = normalizeRoute(path.join(basePath, subPath));
|
|||
|
|
|
|||
|
|
routes.push({
|
|||
|
|
method,
|
|||
|
|
path: fullPath,
|
|||
|
|
basePath,
|
|||
|
|
subPath,
|
|||
|
|
file: path.basename(controllerPath)
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return routes;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 提取Java路由信息
|
|||
|
|
function extractJavaRoutes(controllerPath) {
|
|||
|
|
const content = fs.readFileSync(controllerPath, 'utf8');
|
|||
|
|
const routes = [];
|
|||
|
|
|
|||
|
|
// 提取类级RequestMapping路径
|
|||
|
|
const classMappingMatch = content.match(/@RequestMapping\(["'`]([^"'`]+)["'`]\)/);
|
|||
|
|
const basePath = classMappingMatch ? classMappingMatch[1] : '';
|
|||
|
|
|
|||
|
|
// 提取方法级路由
|
|||
|
|
const methodMatches = content.matchAll(/@(GetMapping|PostMapping|PutMapping|DeleteMapping|RequestMapping)\((["'`]([^"'`]*)["'`])?\)[\s\S]*?(\w+)\s*\(/g);
|
|||
|
|
|
|||
|
|
for (const match of methodMatches) {
|
|||
|
|
const annotation = match[1];
|
|||
|
|
const subPath = match[3] || '';
|
|||
|
|
|
|||
|
|
let method = 'GET';
|
|||
|
|
if (annotation === 'PostMapping') method = 'POST';
|
|||
|
|
else if (annotation === 'PutMapping') method = 'PUT';
|
|||
|
|
else if (annotation === 'DeleteMapping') method = 'DELETE';
|
|||
|
|
|
|||
|
|
const fullPath = normalizeRoute(path.join(basePath, subPath));
|
|||
|
|
|
|||
|
|
routes.push({
|
|||
|
|
method,
|
|||
|
|
path: fullPath,
|
|||
|
|
basePath,
|
|||
|
|
subPath,
|
|||
|
|
file: path.basename(controllerPath)
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return routes;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 主对比函数
|
|||
|
|
function compareRoutes(nestDir, javaDir) {
|
|||
|
|
const nestRoutes = [];
|
|||
|
|
const javaRoutes = [];
|
|||
|
|
|
|||
|
|
// 提取NestJS路由
|
|||
|
|
const nestFiles = glob.sync(`${nestDir}/**/*.controller.ts`);
|
|||
|
|
nestFiles.forEach(file => {
|
|||
|
|
const routes = extractNestJSRoutes(file);
|
|||
|
|
nestRoutes.push(...routes);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 提取Java路由
|
|||
|
|
const javaFiles = glob.sync(`${javaDir}/**/*Controller.java`);
|
|||
|
|
javaFiles.forEach(file => {
|
|||
|
|
const routes = extractJavaRoutes(file);
|
|||
|
|
javaRoutes.push(...routes);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 对比分析
|
|||
|
|
const comparison = {
|
|||
|
|
total: {
|
|||
|
|
nest: nestRoutes.length,
|
|||
|
|
java: javaRoutes.length
|
|||
|
|
},
|
|||
|
|
matches: [],
|
|||
|
|
missingInNest: [],
|
|||
|
|
missingInJava: [],
|
|||
|
|
inconsistencies: []
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 标准化路由键用于对比
|
|||
|
|
const getRouteKey = (route) => `${route.method}:${route.path}`;
|
|||
|
|
|
|||
|
|
const nestRouteMap = new Map(nestRoutes.map(r => [getRouteKey(r), r]));
|
|||
|
|
const javaRouteMap = new Map(javaRoutes.map(r => [getRouteKey(r), r]));
|
|||
|
|
|
|||
|
|
// 查找匹配项
|
|||
|
|
for (const [key, nestRoute] of nestRouteMap) {
|
|||
|
|
if (javaRouteMap.has(key)) {
|
|||
|
|
comparison.matches.push({
|
|||
|
|
route: key,
|
|||
|
|
nestFile: nestRoute.file,
|
|||
|
|
javaFile: javaRouteMap.get(key).file
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
comparison.missingInJava.push(nestRoute);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查找Java中缺失的项
|
|||
|
|
for (const [key, javaRoute] of javaRouteMap) {
|
|||
|
|
if (!nestRouteMap.has(key)) {
|
|||
|
|
comparison.missingInNest.push(javaRoute);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return comparison;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 执行对比
|
|||
|
|
console.log('🚀 NestJS vs Java 路由规范化对比开始...\n');
|
|||
|
|
|
|||
|
|
const nestDir = '/Users/wanwu/Documents/wanwujie/wwjcloud-nsetjs/wwjcloud-nest-v1/wwjcloud/libs/wwjcloud-core/src/controllers';
|
|||
|
|
const javaDir = '/Users/wanwu/Documents/wanwujie/wwjcloud-nsetjs/niucloud-java/niucloud-core/src/main/java/com/niu/core/controller';
|
|||
|
|
|
|||
|
|
const result = compareRoutes(nestDir, javaDir);
|
|||
|
|
|
|||
|
|
console.log('📊 对比结果:');
|
|||
|
|
console.log(`✅ 匹配路由: ${result.matches.length}`);
|
|||
|
|
console.log(`❌ NestJS缺失: ${result.missingInNest.length}`);
|
|||
|
|
console.log(`⚠️ Java缺失: ${result.missingInJava.length}`);
|
|||
|
|
console.log(`📈 覆盖率: ${((result.matches.length / result.total.java) * 100).toFixed(1)}%`);
|
|||
|
|
|
|||
|
|
if (result.missingInNest.length > 0) {
|
|||
|
|
console.log('\n🔍 NestJS缺失路由详情:');
|
|||
|
|
result.missingInNest.forEach(route => {
|
|||
|
|
console.log(` ${route.method} ${route.path} (${route.file})`);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (result.missingInJava.length > 0) {
|
|||
|
|
console.log('\n🔍 Java缺失路由详情:');
|
|||
|
|
result.missingInJava.forEach(route => {
|
|||
|
|
console.log(` ${route.method} ${route.path} (${route.file})`);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log('\n✅ 对比完成!');
|