Files
gaokao-volunteer-system/apps/web/scripts/codegen-check.ts
Frontend Developer e554215335
Some checks failed
CI / pytest (Python 3.10) (push) Has been cancelled
CI / pytest (Python 3.11) (push) Has been cancelled
CI / pytest (Python 3.12) (push) Has been cancelled
finish sprint 1-3 frontend contract closure
2026-07-03 21:28:50 +08:00

89 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* V10 选项 B · OpenAPI Codegen 校验脚本
*
* G1 contract gate:
* - 生成文件必须存在
* - 不允许旧占位 stub 文件假通过
* - TypeScript 声明必须包含 OpenAPI paths
* - Zod client 输出必须包含可导出 contract/schema 内容
*
* 注意: 后端 OpenAPI 文档里可能合法出现“占位密钥”等业务说明,
* 不能把任意“占位”字样误判为生成文件仍是 stub。
*/
import { existsSync, readFileSync } from 'node:fs';
const TYPES_FILE = 'src/types/api-generated.d.ts';
const SCHEMAS_FILE = 'src/schemas/api-generated.ts';
function fail(message: string): never {
console.error(`${message}`);
process.exit(1);
}
function readRequired(path: string): string {
if (!existsSync(path)) {
fail(`Codegen 文件缺失: ${path}; 请运行 pnpm codegen`);
}
return readFileSync(path, 'utf-8');
}
function looksLikeStub(content: string): boolean {
const trimmed = content.trim();
const firstLines = trimmed.split(/\r?\n/).slice(0, 12).join('\n');
if (trimmed === 'export {};') return true;
if (/^\/\/\s*(占位类型|占位 schema|placeholder|stub)/i.test(firstLines)) return true;
if (trimmed.length < 500 && /占位|placeholder|stub|真实后端启动后|后端 OpenAPI 联通后/i.test(trimmed)) return true;
return false;
}
const typesContent = readRequired(TYPES_FILE);
const schemasContent = readRequired(SCHEMAS_FILE);
const REQUIRED_SPRINT3_PATHS = [
'/api/share-link',
'/api/share-link/latest',
'/api/share-link/{code}/revoke',
'/api/share-link/{code}/stats',
'/api/data-query/score-line',
'/api/data-query/rank-estimator',
'/api/data-query/majors',
'/api/data-query/schools',
'/api/review/start',
'/api/review/{review_id}/status',
'/api/review/action',
'/api/poster/generate',
'/api/llm/config',
'/api/llm/{provider}/enhance',
] as const;
if (looksLikeStub(typesContent)) {
fail(`${TYPES_FILE} 仍是占位/stub 输出`);
}
if (looksLikeStub(schemasContent)) {
fail(`${SCHEMAS_FILE} 仍是占位/stub 输出`);
}
if (!/export interface paths\b/.test(typesContent)) {
fail(`${TYPES_FILE} 未包含 openapi-typescript paths 接口`);
}
if (!/\/api\//.test(typesContent)) {
fail(`${TYPES_FILE} 未包含任何 /api/ 路径`);
}
if (!/export const|export default|makeApi|z\.object/.test(schemasContent)) {
fail(`${SCHEMAS_FILE} 未包含可用的 schema/client 导出`);
}
const missingSprint3Paths = REQUIRED_SPRINT3_PATHS.filter((path) => !typesContent.includes(`"${path}"`));
if (missingSprint3Paths.length > 0) {
fail(`${TYPES_FILE} missing Sprint 3 React JSON API paths: ${missingSprint3Paths.join(', ')}`);
}
if (/: any\b/.test(typesContent)) {
fail(`${TYPES_FILE} 包含 ': any'G1 0-any 闸门失败`);
}
console.log('✅ Codegen contract gate passed: generated OpenAPI types/schemas are non-stub');