Files
initiative/scripts/check-gates.mjs
T
LukasandClaude Opus 5 5d99764e14 Make jscpd actually scan, and tighten its threshold to 3%
.jscpd.json set pattern to an array, but jscpd's --pattern takes a single
glob string. An array matches nothing, so the gate had reported success
without reading a file since 2793a66 introduced it — its 0.074ms
"detection time" and absent stats table were the tell. Bisecting the
config confirmed that key alone reduces the run to zero files.

The ignore entries were also bare names rather than globs, so once the
pattern worked it swept apps/web/dist and .pnpm-store — 948 files.

Excludes __tests__, matching what .jsinspectrc already does. Duplication
between test cases is usually deliberate: parallel arrange/act/assert
blocks read better than shared setup, and the factories under
apps/web/src/__tests__/factories cover the deduplication worth having.

Real duplication is 1.72% across 209 source files, so the threshold drops
from 5% to 3%. jscpd measures a ratio rather than blocking each new clone,
and a 5% budget left roughly 3x headroom before it would ever fire.

Gives jscpd explicit paths behind `pnpm jscpd`, so lefthook and the check
script share one invocation, as jsinspect already does.

Also guards the pattern key in check-gates.mjs, since an array there fails
silently rather than erroring.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 14:27:51 +02:00

84 lines
2.8 KiB
JavaScript

import { execFileSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { join } from "node:path";
const ROOT = new URL("..", import.meta.url).pathname.replace(/\/$/, "");
const RUN_LINE_RE = /^\s*run:\s*(.+?)\s*$/;
/** @param {string} path */
const read = (path) => readFileSync(join(ROOT, path), "utf-8");
/**
* Gates must invoke `pnpm oxlint` with no extra arguments: pnpm forwards them
* after `--`, where oxlint reads them as file paths and lints nothing.
* @param {Record<string, string>} scripts
*/
function findGatesWithOwnFlags(scripts) {
const commands = Object.entries(scripts)
.filter(([name]) => name !== "oxlint")
.flatMap(([name, body]) =>
body.split("&&").map((c) => [`scripts.${name}`, c.trim()]),
);
for (const line of read("lefthook.yml").split("\n")) {
const command = RUN_LINE_RE.exec(line)?.[1];
if (command) commands.push(["lefthook.yml", command]);
}
return commands
.filter(([, c]) => c.includes("oxlint") && c !== "pnpm oxlint")
.map(([source, c]) => `${source} runs "${c}" instead of "pnpm oxlint"`);
}
/**
* Runs the configured command with one rule forced to warn. A working gate
* exits non-zero; exiting 0 means it lints nothing, or does not fail on
* warnings.
* @param {string} oxlintScript
*/
function failsOnWarnings(oxlintScript) {
const args = [...oxlintScript.split(" ").slice(1), "-W", "no-console"];
try {
execFileSync(join(ROOT, "node_modules/.bin/oxlint"), args, {
cwd: ROOT,
stdio: "ignore",
});
return false;
} catch {
return true;
}
}
/**
* Reports ways a quality gate could pass without checking anything, which is
* indistinguishable from a clean run.
* @returns {string[]}
*/
export function checkGates() {
/** @type {Record<string, string>} */
const scripts = JSON.parse(read("package.json")).scripts;
const violations = findGatesWithOwnFlags(scripts);
// Vitest defaults to failing when no test file matches. Setting this puts
// the test gate back to exiting 0 if the include globs ever stop matching.
if (read("vitest.config.ts").includes("passWithNoTests")) {
violations.push("vitest.config.ts sets passWithNoTests");
}
// jscpd's pattern is a single glob string. An array matches no files, and
// the run then reports success having read nothing.
if (Array.isArray(JSON.parse(read(".jscpd.json")).pattern)) {
violations.push(".jscpd.json sets pattern to an array, not a glob string");
}
// The canary rule below is not type-aware, so the probe alone cannot
// detect type-aware rules being switched off.
if (!scripts.oxlint.includes("--type-aware")) {
violations.push("scripts.oxlint is missing --type-aware");
}
if (!failsOnWarnings(scripts.oxlint)) {
violations.push(
`scripts.oxlint exits 0 despite no-console violations: "${scripts.oxlint}"`,
);
}
return violations;
}