轻松聘
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

/**
* 后端接口预留审计:找出「函数体里没有留下任何后端调用痕迹」的接口函数。
*
* 背景:本项目当前是 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;
}