Files
OmniRoute/scripts/check/complexityEslintReport.mjs
backryun d1d75fdbf4 ci(quality): cut PR gate wall time without dropping protection (#6716)
Collapse duplicate CI spend while keeping each gate's existence reason:

- quality.yml: TIA __RUN_ALL__ defers full unit to fast-unit 4-shard (#6781);
  path filters via classify-pr-changes; docs-gates split; draft skip
- ci.yml: wire docs/i18n/code path filters; ESLint JSON artifact for quality-gate;
  drop advisory typecheck:noimplicit; float actions/cache@v6
- TIA parity: memory/usage/combo/serial; **/*.test.mjs any depth; electron/bin
  no longer force unit __RUN_ALL__
- check:complexity-ratchets: one ESLint walk, ruleId-isolated baselines + cache
- check:api-docs-refs + lib/apiRoutes: shared API route inventory
- husky pre-push: intentionally light (gates live in pre-commit); CLAUDE.md +
  QUALITY_GATES.md docs synced
- collect-metrics / lint:json: path.resolve cache path; Windows-safe eslint bin
- env-doc allowlist for ESLINT_RESULTS_JSON / COMPLEXITY_ESLINT_REPORT
- release-green --full-ci expects check:api-docs-refs (not docs-symbols alone)

Tests: select-impacted, classify-pr-changes, api-routes lib, complexity-rule-count,
validate-release-green.

Reconciled after #6781 (fast-unit 2→4 shards) per maintainer request on #6716.

Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
2026-07-11 08:03:11 -03:00

105 lines
2.9 KiB
JavaScript

#!/usr/bin/env node
/**
* Shared ESLint runner for complexity + cognitive-complexity ratchets.
* One tree walk → JSON report; consumers count by ruleId (not errorCount).
*/
import { execFileSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const CONFIG_PATH = path.join(ROOT, "eslint.complexity-ratchets.config.mjs");
/** Positional dirs — must match config `files` scopes (see check-complexity tests). */
export const ESLINT_SCAN_DIRS = ["src", "open-sse", "electron", "bin"];
const ESLINT_BIN = path.join(
ROOT,
"node_modules",
".bin",
process.platform === "win32" ? "eslint.cmd" : "eslint"
);
/** Args after the eslint binary (tests lock scan dirs on this array). */
export const ESLINT_ARGS = [
"--no-config-lookup",
"--config",
CONFIG_PATH,
"--format",
"json",
"--cache",
"--cache-location",
".eslintcache-complexity",
...ESLINT_SCAN_DIRS,
];
const COMPLEXITY_RULES = new Set(["complexity", "max-lines-per-function"]);
/**
* @param {Array<{messages?: Array<{ruleId?: string}>}>} report
* @returns {number}
*/
export function countComplexityViolations(report) {
let count = 0;
for (const file of report) {
for (const msg of file.messages || []) {
if (COMPLEXITY_RULES.has(msg.ruleId)) count++;
}
}
return count;
}
/**
* @param {Array<{messages?: Array<{ruleId?: string}>}>} report
* @returns {number}
*/
export function countCognitiveViolations(report) {
let count = 0;
for (const file of report) {
for (const msg of file.messages || []) {
if (msg.ruleId === "sonarjs/cognitive-complexity") count++;
}
}
return count;
}
/**
* Run ESLint once (or reuse COMPLEXITY_ESLINT_REPORT / in-process cache).
* @returns {Array<object>}
*/
export function getComplexityEslintReport() {
const fromEnv = process.env.COMPLEXITY_ESLINT_REPORT;
if (fromEnv && fs.existsSync(fromEnv)) {
return JSON.parse(fs.readFileSync(fromEnv, "utf8"));
}
if (getComplexityEslintReport._cache) return getComplexityEslintReport._cache;
let stdout;
try {
// Prefer local bin (Windows-safe); shell only needed for .cmd shims.
stdout = execFileSync(ESLINT_BIN, ESLINT_ARGS, {
cwd: ROOT,
encoding: "utf8",
maxBuffer: 64 * 1024 * 1024,
shell: process.platform === "win32",
});
} catch (err) {
stdout = err.stdout ? String(err.stdout) : "";
if (!stdout.trim()) throw err;
}
const report = JSON.parse(stdout);
getComplexityEslintReport._cache = report;
const outDir = path.join(ROOT, ".artifacts");
try {
fs.mkdirSync(outDir, { recursive: true });
fs.writeFileSync(path.join(outDir, "complexity-eslint.json"), stdout);
} catch {
// best-effort cache for sibling steps / local inspection
}
return report;
}
getComplexityEslintReport._cache = null;