- 重构sys模块架构,严格按admin/api/core分层 - 对齐所有sys实体与数据库表结构 - 实现完整的adminapi控制器,匹配PHP/Java契约 - 修复依赖注入问题,确保服务正确注册 - 添加自动迁移工具和契约验证 - 完善多租户支持和审计功能 - 统一命名规范,与PHP业务逻辑保持一致
97 lines
2.8 KiB
JavaScript
97 lines
2.8 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const repoRoot = path.resolve(__dirname, '..');
|
|
const srcRoot = path.join(repoRoot, 'wwjcloud', 'src');
|
|
|
|
function isTypescriptFile(filePath) {
|
|
return filePath.endsWith('.ts') && !filePath.endsWith('.d.ts') && !filePath.endsWith('.spec.ts');
|
|
}
|
|
|
|
function walk(dir, collected = []) {
|
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
for (const entry of entries) {
|
|
const fullPath = path.join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
walk(fullPath, collected);
|
|
} else if (entry.isFile() && isTypescriptFile(fullPath)) {
|
|
collected.push(fullPath);
|
|
}
|
|
}
|
|
return collected;
|
|
}
|
|
|
|
function isAdminApiControllerFile(filePath) {
|
|
return filePath.includes(path.join('controllers', 'adminapi') + path.sep);
|
|
}
|
|
|
|
function extractControllerInfo(fileContent) {
|
|
const controllerMatch = fileContent.match(/@Controller\(([^)]*)\)/);
|
|
const basePathLiteral = controllerMatch ? controllerMatch[1] : '';
|
|
let basePath = '';
|
|
if (basePathLiteral) {
|
|
const strMatch = basePathLiteral.match(/['"`]([^'"`]*)['"`]/);
|
|
basePath = strMatch ? strMatch[1] : '';
|
|
}
|
|
|
|
const classDeclIdx = fileContent.indexOf('export class');
|
|
const header = classDeclIdx > -1 ? fileContent.slice(0, classDeclIdx) : fileContent;
|
|
const guardsSection = header;
|
|
const hasUseGuards = /@UseGuards\(([^)]*)\)/.test(guardsSection);
|
|
let guards = [];
|
|
if (hasUseGuards) {
|
|
const m = guardsSection.match(/@UseGuards\(([^)]*)\)/);
|
|
if (m) {
|
|
guards = m[1].split(',').map(s => s.trim());
|
|
}
|
|
}
|
|
const hasJwt = guards.some(g => /JwtAuthGuard/.test(g));
|
|
const hasRoles = guards.some(g => /RolesGuard/.test(g));
|
|
|
|
return { basePath, hasJwt, hasRoles };
|
|
}
|
|
|
|
function main() {
|
|
if (!fs.existsSync(srcRoot)) {
|
|
console.error(`src root not found: ${srcRoot}`);
|
|
process.exit(1);
|
|
}
|
|
const allTsFiles = walk(srcRoot);
|
|
const adminControllers = allTsFiles.filter(isAdminApiControllerFile);
|
|
|
|
const problems = [];
|
|
for (const filePath of adminControllers) {
|
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
if (!/@Controller\(/.test(content)) continue;
|
|
const info = extractControllerInfo(content);
|
|
const rel = path.relative(repoRoot, filePath);
|
|
|
|
const missing = [];
|
|
if (!info.hasJwt) missing.push('JwtAuthGuard');
|
|
if (!info.hasRoles) missing.push('RolesGuard');
|
|
if (missing.length > 0) {
|
|
problems.push({ file: rel, basePath: info.basePath || '', missing });
|
|
}
|
|
}
|
|
|
|
if (problems.length === 0) {
|
|
console.log('OK: All adminapi controllers have class-level JwtAuthGuard and RolesGuard.');
|
|
return;
|
|
}
|
|
|
|
console.log('file,basePath,missingGuards');
|
|
for (const p of problems) {
|
|
console.log(`${p.file},${p.basePath},${p.missing.join('|')}`);
|
|
}
|
|
}
|
|
|
|
if (require.main === module) {
|
|
try {
|
|
main();
|
|
} catch (err) {
|
|
console.error('scan-guards failed:', err);
|
|
process.exit(1);
|
|
}
|
|
}
|