#!/usr/bin/env node import { mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; import { dirname, join, relative } from 'node:path'; function argument(name) { const index = process.argv.indexOf(name); return index >= 0 ? process.argv[index + 1] : ''; } const source = argument('--source'); const output = argument('--output'); if (!source || !output) throw new Error('用法:node scripts/generate-legacy-admin-inventory.mjs --source --output '); const files = []; function walk(directory) { for (const entry of readdirSync(directory, { withFileTypes: true })) { const path = join(directory, entry.name); if (entry.isDirectory()) walk(path); else if (entry.name.endsWith('.cs') && path.includes('Areas.Admin.Controllers')) files.push(path); } } walk(source); const returnTypes = 'Task<[^>]+>|IActionResult|ActionResult|JsonResult|ContentResult|ViewResult|string|void|object|DataTable|PartialViewResult'; const methodPattern = new RegExp(`public\\s+(?:async\\s+)?(?:${returnTypes})\\s+([A-Za-z0-9_]+)\\s*\\(`, 'g'); const rows = []; for (const file of files) { const code = readFileSync(file, 'utf8'); const controller = code.match(/public class ([A-Za-z0-9_]+)Controller/)?.[1]; if (!controller) continue; const actions = [...code.matchAll(methodPattern)].map((match) => match[1]).filter((name) => !['OnActionExecuting', 'OnActionExecutionAsync'].includes(name)); const sourcePath = relative(source, file); const moduleName = sourcePath.replace(/^ZoomLaCMS\.Areas\.Admin\.Controllers(?:\.|\/)?/, '').replace(/Controller\.cs$/, '').replaceAll('/', ' / ') || controller; rows.push({ controller, moduleName, actions, source: sourcePath }); } rows.sort((left, right) => left.controller.localeCompare(right.controller, 'en')); const totalActions = rows.reduce((sum, row) => sum + row.actions.length, 0); const lines = [ '# 旧 ASP.NET 管理后台控制器与动作清单', '', '> 本文件由 `scripts/generate-legacy-admin-inventory.mjs` 从 `ZoomLaCMS.dll` 的 ILSpy 反编译结果生成。发布包没有 `.sln`、`.csproj` 和原始 Razor 视图,因此这是后端动作基线,不等同于可恢复的页面像素基线。', '', `- 管理控制器:${rows.length}`, `- 可识别公开动作:${totalActions}`, '- 生成日期:2026-08-18', '', '| 模块 / 控制器 | 动作数 | 公开动作 |', '|---|---:|---|', ...rows.map((row) => `| ${row.moduleName} | ${row.actions.length} | ${row.actions.map((action) => `\`${action}\``).join('、')} |`), '', ]; mkdirSync(dirname(output), { recursive: true }); writeFileSync(output, lines.join('\n')); console.log(`Generated ${output}: ${rows.length} controllers, ${totalActions} actions.`);