Files
wwjcloud/scripts/scan-guards.js

97 lines
2.8 KiB
JavaScript
Raw Normal View History

#!/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);
}
}