core/adapters/tool.oxlint.adapter.ts
core/adapters/tool.oxlint.adapter.ts is a file in GovLab Quality. 118 lines of code and 23 definitions.
import type { AdvisoryContext, RunnerContext, ScanSpec, ToolCall } from "#types/tool.types";
import { NO_STDERR_DETAIL, installHint, toolErrorMessage } from "#configuration/strings/tool.strings";
import { fixCycle, passTool, residualOf } from "#core/adapters/tool.adapter";
import { isRecord, stringArrayField, stringArrayFieldOr } from "#core/selectors/record.selector";
import { notInstalled, toolFailure } from "#core/factories/finding.factory";
import { FINDING_STATUSES } from "#configuration/constants/tool.constants";
import type { OxlintBlockExclusion } from "#types/config.types";
import type { RunResult } from "#types/finding.types";
import { createRequire } from "node:module";
import { defineTool } from "#core/registries/tool.registry";
import { failedWhenEmpty } from "#core/classifiers/invocation.classifier";
import { filterBlockExcluded } from "#core/selectors/block.selector";
import { gatingAdvisory } from "#core/factories/tool.factory";
import { isModuleMissing } from "#core/predicates/failure.predicate";
import { loadGovlabConfig } from "#core/loaders/config.loader";
import { parseOxlintOutput } from "#core/parsers/tool.oxlint.parser";
import path from "node:path";
import process from "node:process";
import { sectionOf } from "#core/selectors/config.selector";
import { tailLines } from "#core/selectors/failure.selector";
import { withMasterExclude } from "#core/selectors/exclusions.selector";
import { writeToolJson } from "#core/persistence/tool.persistence";
const SECTION = "oxlint";
const RULE_OFF = "off";
const DEFAULT_ENV = { builtin: true };
const CONFIG_FILE = "oxlintrc.json";
const FIX_CONFIG_FILE = "oxlintrc.fix.json";
const moduleRequire = createRequire(import.meta.url);
interface Invocation {
bin: string;
configFile: string;
fixConfigFile: string;
ignore: string[];
}
const recordOr = function recordOr(value: unknown, fallback: Record<string, unknown>): Record<string, unknown> {
return isRecord(value) ? value : fallback;
};
export const govlabOxlintConfig = async (consumerRoot: string = process.cwd()): Promise<Record<string, unknown>> => {
const config = await loadGovlabConfig(consumerRoot);
const section = sectionOf(config, SECTION);
return {
categories: recordOr(section["categories"], {}),
env: recordOr(section["env"], DEFAULT_ENV),
globals: recordOr(section["globals"], {}),
ignorePatterns: withMasterExclude(config, stringArrayField(section, "ignorePatterns")),
plugins: stringArrayFieldOr(section, "plugins", []),
rules: recordOr(section["rules"], {}),
};
};
export const govlabOxlintFixConfig = async (consumerRoot: string = process.cwd()): Promise<Record<string, unknown>> => {
const config = await loadGovlabConfig(consumerRoot);
const section = sectionOf(config, SECTION);
const silenced = Object.fromEntries(stringArrayField(section, "reportOnly").map((rule) => [rule, RULE_OFF]));
return { ...(await govlabOxlintConfig(consumerRoot)), rules: { ...recordOr(section["rules"], {}), ...silenced } };
};
const resolveOxlintBin = function resolveOxlintBin(): string | null {
try {
return path.resolve(path.dirname(moduleRequire.resolve(SECTION)), "..", "bin", SECTION);
} catch (error) {
if (isModuleMissing(error)) {
return null;
}
throw error;
}
};
const oxlintCall = function oxlintCall(invocation: Invocation, context: RunnerContext, withFix: boolean): ToolCall {
const args = [
invocation.bin,
"--type-aware",
"--disable-nested-config",
"-c",
withFix ? invocation.fixConfigFile : invocation.configFile,
"-f",
"json",
...invocation.ignore.flatMap((pattern) => ["--ignore-pattern", pattern]),
...(withFix ? ["--fix"] : []),
...context.paths,
];
return { args, bin: process.execPath, cwd: context.root };
};
const oxlintSpec = function oxlintSpec(
advisory: AdvisoryContext,
exclusions: readonly OxlintBlockExclusion[],
): ScanSpec {
return {
failed: failedWhenEmpty(FINDING_STATUSES),
failure: (exit) =>
toolFailure(advisory, toolErrorMessage(SECTION, exit.status, tailLines(exit.stderr, NO_STDERR_DETAIL))),
parse: (result) =>
filterBlockExcluded(parseOxlintOutput(result.stdout, advisory.ecosystem), exclusions, advisory.root),
};
};
export const runOxlint = async function runOxlint(context: RunnerContext): Promise<RunResult> {
const advisory = gatingAdvisory(context, SECTION, installHint(SECTION));
const bin = resolveOxlintBin();
if (bin === null) {
return notInstalled(advisory);
}
const config = await govlabOxlintConfig(context.root);
const invocation: Invocation = {
bin,
configFile: await writeToolJson(context.root, CONFIG_FILE, config),
fixConfigFile: await writeToolJson(context.root, FIX_CONFIG_FILE, await govlabOxlintFixConfig(context.root)),
ignore: stringArrayField(config, "ignorePatterns"),
};
const spec = oxlintSpec(advisory, (await loadGovlabConfig(context.root)).oxlint?.blockExclusions ?? []);
return fixCycle(
passTool(advisory, oxlintCall(invocation, context, false), spec),
(findings) => context.fix && findings.length > 0,
(reported) => {
const fixed = passTool(advisory, oxlintCall(invocation, context, true), spec);
return fixed.terminal
? fixed.result
: residualOf(reported, passTool(advisory, oxlintCall(invocation, context, false), spec));
},
);
};
defineTool({ ecosystems: ["typescript"], run: runOxlint, tool: SECTION });