You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
47 lines
2.2 KiB
47 lines
2.2 KiB
/**
|
|
* 后端接口预留审计:找出「函数体里没有留下任何后端调用痕迹」的接口函数。
|
|
*
|
|
* 背景:本项目当前是 mock 阶段,数据要能展示,但每个函数都要把真实请求写好、注释起来,
|
|
* 后端就绪时**放开注释**即可接入(见 `src/api/api.ts` 顶部的「后端接口预留」约定)。
|
|
* 判断标准是「函数体里出现过 fetch(」—— 注释着的也算,因此不依赖注释的写法。
|
|
*
|
|
* 豁免:确实没有后端接口、本就以本地存储为唯一真相源的函数,在函数体内任意位置写
|
|
* `backend-stub-ok` 注释即可跳过(约定见 api.ts 顶部)。
|
|
*
|
|
* 用法:node scripts/check-backend-stubs.mjs # 列出全部
|
|
* node scripts/check-backend-stubs.mjs --error # 有命中则 exit 1(可用于 CI)
|
|
*/
|
|
import { readFileSync } from 'node:fs';
|
|
|
|
const FILE = 'src/api/api.ts';
|
|
/** 有意不接后端的函数在函数体内标这个,避免与「忘了留接口」混在一起 */
|
|
const EXEMPT_MARKER = 'backend-stub-ok';
|
|
|
|
const lines = readFileSync(FILE, 'utf8').split('\n');
|
|
|
|
/** 顶层 `export async function` 的起始行;同步函数不涉及请求,不参与审计 */
|
|
const starts = [];
|
|
lines.forEach((line, index) => {
|
|
const match = line.match(/^export async function (\w+)/);
|
|
if (match) starts.push({ name: match[1], index });
|
|
});
|
|
starts.push({ name: null, index: lines.length });
|
|
|
|
const findings = [];
|
|
for (let i = 0; i < starts.length - 1; i += 1) {
|
|
const { name, index } = starts[i];
|
|
const body = lines.slice(index, starts[i + 1].index).join('\n');
|
|
if (body.includes('fetch(') || body.includes(EXEMPT_MARKER)) continue;
|
|
findings.push({ name, line: index + 1 });
|
|
}
|
|
|
|
if (findings.length === 0) {
|
|
console.log(`✅ ${starts.length - 1} 个接口函数均已预留后端调用(注释版)`);
|
|
} else {
|
|
console.log(`=== 未预留后端调用的接口函数 (${findings.length}) ===`);
|
|
for (const f of findings) {
|
|
console.log(`${FILE}:${f.line} ${f.name}`);
|
|
}
|
|
console.log('请补上注释版真实请求,或在不接后端的函数里标注 backend-stub-ok');
|
|
if (process.argv.includes('--error')) process.exitCode = 1;
|
|
}
|
|
|