Files
gaokao-volunteer-system/apps/web/scripts/codegen-check.ts

67 lines
2.1 KiB
TypeScript
Raw Normal View History

/**
* 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);
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 导出`);
}
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');