rules/eslint/no-hardcoded-exclusions.eslint.rule.ts

rules/eslint/no-hardcoded-exclusions.eslint.rule.ts is a file in GovLab Extension Host. 130 lines of code and 21 definitions.

import type { LocalRule, RuleContext, RuleListener } from "../../types/rule.types.ts";
import {
    argumentAt,
    calleeName,
    isType,
    literalString,
    locOf,
    nameOf,
    nodeAt,
    nodesAt,
    recordAt,
    stringIn,
} from "../../shared/selectors/syntax.selector.ts";
import type { AstNode } from "../../types/syntax.types.ts";
import { absolutePath } from "@ssot/paths";
import { defineCheck } from "@govlab/context/check";
import { listener } from "../../shared/factories/listener.factory.ts";
import { normalizePath } from "../../shared/resolvers/anchor.resolver.ts";

const EXCLUSION_NAME_PARTS = ["skip", "ignore", "prune", "exclude", "runtime_root", "runtimeroot"];
const SSOT_CALLEES = new Set([
    "masterExcludeMarkers",
    "masterExclude",
    "withMasterExclude",
    "relativePath",
    "absolutePath",
]);
const INFRASTRUCTURE_HINTS = [
    "node_modules",
    "dist",
    "build",
    "coverage",
    "target",
    ".git",
    ".cache",
    ".vite",
    ".registry",
    ".vscode",
    ".next",
    ".tmp",
];
const MASTER_LIST_OWNER = normalizePath(absolutePath("govlabHost.config"));

const isExemptFile = function isExemptFile(filename: string): boolean {
    return normalizePath(filename) === MASTER_LIST_OWNER;
};

const namesAnExclusion = function namesAnExclusion(name: string): boolean {
    const lowered = name.toLowerCase();
    return EXCLUSION_NAME_PARTS.some((part) => lowered.includes(part));
};

const literalsIn = function literalsIn(element: AstNode): string[] {
    const literal = literalString(element);
    if (literal !== null) {
        return [literal];
    }
    if (element.type !== "TemplateLiteral") {
        return [];
    }
    return nodesAt(element, "quasis")
        .map((quasi) => stringIn(recordAt(quasi, "value"), "cooked"))
        .filter((cooked) => cooked.trim().length > 0);
};

const literalsOf = function literalsOf(node: AstNode | null): string[] {
    return nodesAt(node, "elements").flatMap(literalsIn);
};

const holdsSsotCall = function holdsSsotCall(node: AstNode | null): boolean {
    return nodesAt(node, "elements").some((element) => {
        const inner = element.type === "SpreadElement" ? nodeAt(element, "argument") : element;
        return isType(inner, "CallExpression") && SSOT_CALLEES.has(calleeName(inner));
    });
};

const WRAPPERS = new Set(["NewExpression", "CallExpression"]);

const arrayOf = function arrayOf(init: AstNode | null): AstNode | null {
    if (init === null) {
        return null;
    }
    if (init.type === "ArrayExpression") {
        return init;
    }
    return WRAPPERS.has(init.type) ? argumentAt(init, 0) : null;
};

export default {
    create(context: RuleContext): RuleListener {
        if (isExemptFile(context.filename)) {
            return {};
        }
        return listener({
            variableDeclarator(view) {
                const id = nodeAt(view, "id");
                const name = isType(id, "Identifier") ? nameOf(id) : "";
                if (name === "" || !namesAnExclusion(name)) {
                    return;
                }
                const array = arrayOf(nodeAt(view, "init"));
                if (array === null) {
                    return;
                }
                const first = literalsOf(array).find((value) =>
                    INFRASTRUCTURE_HINTS.some((hint) => value.includes(hint)),
                );
                if (first === undefined) {
                    return;
                }
                const payload = { name, value: first };
                if (holdsSsotCall(array)) {
                    context.report({ data: payload, loc: locOf(view), messageId: "partialExclusion" });
                } else {
                    context.report({ data: payload, loc: locOf(view), messageId: "hardcodedExclusion" });
                }
            },
        });
    },
    meta: {
        docs: {
            checks: defineCheck({
                detects: ["architecture:hardcoded-configuration"],
                enforces: ["architecture:single-source-of-truth"],
            }),
            description:
                "An exclusion set is declared once, in the quality config, and reached through the master-exclude surface. A list spelled in source drifts from that one silently, and every tool then walks a slightly different tree — which is how a directory ends up skipped by one check and scanned by another. A genuinely tool-specific exclusion is declared under the tool's key in the config and requested by name, so the addition is still data rather than code.",
            workspaceWide: true,
        },
        messages: {
            hardcodedExclusion:
                "`{{ name }}` spells its own exclusion set — `{{ value }}`. Take it from the master exclude surface, and declare any tool-specific addition under that tool's key in the quality config.",
            partialExclusion:
                "`{{ name }}` reads the master exclude surface and then appends `{{ value }}` in source. The appended entry is invisible to every other tool — declare it under this tool's key in the quality config instead.",
        },
        schema: [],
        type: "problem",
    },
} satisfies LocalRule;