const fs = require('fs'); const specPath = process.argv[2] || '.swagger-default.json'; const spec = JSON.parse(fs.readFileSync(specPath, 'utf8')); const tagToFile = { sysuser: 'src/api/match/account.js', sysrole: 'src/api/match/role.js', sysorganization: 'src/api/match/sysorganization.js', event: 'src/api/match/event.js', eventrecord: 'src/api/match/eventRecord.js', project: 'src/api/match/project.js', order: 'src/api/match/order.js', merchant: 'src/api/match/merchant.js', coupon: 'src/api/match/coupon.js', certificate: 'src/api/match/certificate.js', certificatetemplate: 'src/api/match/certificate-detail.js', appuser: 'src/api/match/appuser.js', team: 'src/api/match/unituser.js', }; function existingEndpoints(file) { const txt = fs.readFileSync(file, 'utf8'); const re = /http\.(get|post|put|delete|patch)\(\s*(['"`])([^'"`]+)\2/g; const out = new Set(); let m; while ((m = re.exec(txt))) out.add(`${m[1].toUpperCase()} ${m[3]}`); return out; } const basePrefix = '/api'; const expectedByFile = new Map(); for (const [p, methods] of Object.entries(spec.paths || {})) { for (const [m, op] of Object.entries(methods || {})) { if (!op || !Array.isArray(op.tags) || !op.tags[0]) continue; const tag = op.tags[0]; const file = tagToFile[tag]; if (!file) continue; const url = p.startsWith(basePrefix) ? p.slice(basePrefix.length) : p; if (!expectedByFile.has(file)) expectedByFile.set(file, []); expectedByFile.get(file).push({ method: m.toUpperCase(), url, opId: op.operationId }); } } for (const file of [...expectedByFile.keys()].sort()) { const ops = expectedByFile.get(file); const exist = existingEndpoints(file); const missing = ops.filter((o) => !exist.has(`${o.method} ${o.url}`)); console.log(`\n=== ${file} ===`); console.log(`swagger ops: ${ops.length} | existing endpoints: ${exist.size} | missing exact: ${missing.length}`); for (const o of missing) console.log(`${o.method} ${o.url} (${o.opId})`); }