Files

72 lines
2.5 KiB
JavaScript
Executable File
Raw Permalink 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.
#!/usr/bin/env node
/**
* 校验代码内的契约版本常量与 contracts/VERSION 一致。
* 在构建前执行:不一致则退出码 1,阻止契约漂移。
*
* 用法:node scripts/check-contracts.mjs
*/
import { readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const here = dirname(fileURLToPath(import.meta.url));
const versionFile = join(here, '..', '..', 'contracts', 'VERSION');
const constantFile = join(here, '..', 'src', 'config', 'contract-versions.ts');
function parseVersionFile(content) {
const out = {};
for (const rawLine of content.split(/\r?\n/)) {
const line = rawLine.trim();
if (!line || line.startsWith('#')) continue;
const idx = line.indexOf(':');
if (idx <= 0) continue;
out[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
}
return out;
}
function parseConstants(content) {
const block = /CONTRACT_VERSIONS[^=]*=\s*Object\.freeze\(\{([\s\S]*?)\}\)/.exec(content);
if (!block) throw new Error('无法在 contract-versions.ts 中定位 CONTRACT_VERSIONS');
const out = {};
// 键可能是带引号的 'rest-api',也可能是不带引号的 database
for (const match of block[1].matchAll(/['"]?([\w-]+)['"]?\s*:\s*['"]([^'"]+)['"]/g)) {
out[match[1]] = match[2];
}
return out;
}
let fileVersions;
let codeVersions;
try {
fileVersions = parseVersionFile(readFileSync(versionFile, 'utf8'));
} catch (error) {
console.error(`✗ 无法读取 ${versionFile}:${error.message}`);
process.exit(1);
}
try {
codeVersions = parseConstants(readFileSync(constantFile, 'utf8'));
} catch (error) {
console.error(`✗ 无法解析 ${constantFile}:${error.message}`);
process.exit(1);
}
const keys = new Set([...Object.keys(fileVersions), ...Object.keys(codeVersions)]);
const problems = [];
for (const key of [...keys].sort()) {
const a = fileVersions[key];
const b = codeVersions[key];
if (a === undefined) problems.push(` ${key}: 仅存在于代码常量(${b})`);
else if (b === undefined) problems.push(` ${key}: 仅存在于 contracts/VERSION(${a})`);
else if (a !== b) problems.push(` ${key}: contracts/VERSION=${a} vs 代码常量=${b}`);
}
if (problems.length > 0) {
console.error('✗ 契约版本不一致:');
console.error(problems.join('\n'));
console.error('\n请同步 contracts/VERSION 与 web-server/src/config/contract-versions.ts');
process.exit(1);
}
console.log(`✓ 契约版本一致(${Object.keys(fileVersions).length} 项):${JSON.stringify(fileVersions)}`);