Files
jackwener--opencli/scripts/check-silent-column-drop.mjs
wehub-resource-sync 9b395f5cc3
Build Chrome Extension / build (push) Waiting to run
Trigger Website Rebuild (Docs Updated) / dispatch (push) Waiting to run
E2E Headed Chrome / e2e-headed (macos-15) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (ubuntu-latest) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (windows-latest) (push) Has been cancelled
CI / build (macos-latest) (push) Has been cancelled
CI / build (ubuntu-latest) (push) Has been cancelled
CI / build (windows-latest) (push) Has been cancelled
CI / unit-test (push) Has been cancelled
CI / bun-test (push) Has been cancelled
CI / adapter-test (push) Has been cancelled
CI / smoke-test (macos-latest) (push) Has been cancelled
CI / smoke-test (ubuntu-latest) (push) Has been cancelled
Security Audit / audit (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:48 +08:00

106 lines
3.9 KiB
JavaScript

#!/usr/bin/env node
/**
* check-silent-column-drop.mjs — CI gate for newly introduced table-output loss.
*
* This gate intentionally uses a baseline. The repo currently has known
* silent-column-drop findings, and blocking every existing violation would make
* the first CI adoption PR too large. The invariant enforced here is:
*
* no new silent-column-drop signatures beyond scripts/silent-column-drop-baseline.json
*
* When a follow-up sweep fixes existing violations, run:
*
* node scripts/check-silent-column-drop.mjs --update-baseline
*/
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const PROJECT_ROOT = resolve(__dirname, '..');
const DIST_AUDIT = resolve(PROJECT_ROOT, 'dist', 'src', 'convention-audit.js');
const BASELINE_PATH = resolve(__dirname, 'silent-column-drop-baseline.json');
const UPDATE = process.argv.includes('--update-baseline');
if (!existsSync(DIST_AUDIT)) {
console.error('dist/src/convention-audit.js not found. Run npm run build before this check.');
process.exit(1);
}
const { runConventionAudit } = await import(pathToFileURL(DIST_AUDIT).href);
const report = runConventionAudit({ projectRoot: PROJECT_ROOT });
const category = report.categories.find((item) => item.rule === 'silent-column-drop');
const current = sortRecords((category?.violations ?? []).map(toBaselineRecord));
if (UPDATE) {
writeFileSync(BASELINE_PATH, `${JSON.stringify(current, null, 2)}\n`);
console.log(`Updated ${relative(BASELINE_PATH)} with ${current.length} silent-column-drop baseline entr${current.length === 1 ? 'y' : 'ies'}.`);
process.exit(0);
}
if (!existsSync(BASELINE_PATH)) {
console.error(`${relative(BASELINE_PATH)} not found. Run node scripts/check-silent-column-drop.mjs --update-baseline.`);
process.exit(1);
}
const baseline = sortRecords(JSON.parse(readFileSync(BASELINE_PATH, 'utf-8')));
const baselineSignatures = new Set(baseline.map(signature));
const currentSignatures = new Set(current.map(signature));
const added = current.filter((record) => !baselineSignatures.has(signature(record)));
const resolved = baseline.filter((record) => !currentSignatures.has(signature(record)));
console.log(`Silent-column-drop gate: current=${current.length}, baseline=${baseline.length}, new=${added.length}, resolved=${resolved.length}`);
if (resolved.length > 0) {
console.log('');
console.log('Resolved baseline entries detected. Consider shrinking the baseline:');
for (const record of resolved) {
console.log(` - ${record.command} ${record.file} missing=[${record.missing.join(', ')}]`);
}
}
if (added.length === 0) {
console.log('OK - no new silent-column-drop violations.');
process.exit(0);
}
console.log('');
console.log('New silent-column-drop violations:');
for (const record of added) {
console.log(` - ${record.command} ${record.file} missing=[${record.missing.join(', ')}]`);
}
console.log('');
console.log('Fix the adapter columns, or if this is an intentional baseline adoption, run:');
console.log(' node scripts/check-silent-column-drop.mjs --update-baseline');
process.exit(1);
function toBaselineRecord(violation) {
const missing = Array.isArray(violation.details?.missing)
? violation.details.missing.map(String).sort()
: [];
return {
command: String(violation.command ?? ''),
file: String(violation.file ?? ''),
missing,
};
}
function signature(record) {
return `${record.command}\0${record.file}\0${record.missing.join('\0')}`;
}
function sortRecords(records) {
return records
.map((record) => ({
command: String(record.command),
file: String(record.file),
missing: Array.isArray(record.missing) ? record.missing.map(String).sort() : [],
}))
.sort((a, b) => signature(a).localeCompare(signature(b)));
}
function relative(file) {
return file.replace(`${PROJECT_ROOT}/`, '');
}