core/quality/eslint/require-central-config.eslint.rule.ts

core/quality/eslint/require-central-config.eslint.rule.ts is a file in GovLab Quality. 90 lines of code and 17 definitions.

import { isDigit, isUpperAlpha } from "@govlab/constants";
import type { Rule } from "eslint";
import { packageRelOf } from "#core/resolvers/package.resolver";

const CONFIG_INIT_TYPES = new Set(["Literal"]);
const SELECTORS = ["ExportNamedDeclaration"];

const MESSAGE =
    "Scalar config constant '{{name}}' is declared inline in a concern module, not in a constants module. " +
    "Move exported UPPER_SNAKE scalar knobs (number/string literals) into a co-located `constants/` folder (or src/constants.ts) so a package's tunable surface lives in dedicated constants modules. [central_config]";

interface VarDeclarator {
    id: { type: string; name?: string | undefined };
    init?: { type: string } | null | undefined;
}

const isWorkspaceSrcFile = function isWorkspaceSrcFile(filename: string): boolean {
    const normalized = filename.replaceAll("\\", "/");
    if (!normalized.includes("/src/") || !normalized.endsWith(".ts") || normalized.endsWith(".d.ts")) {
        return false;
    }
    return packageRelOf(normalized) !== null;
};

const isCentralConstantsLocation = function isCentralConstantsLocation(filename: string): boolean {
    const normalized = filename.replaceAll("\\", "/");
    return (
        normalized.includes("/constants/") ||
        normalized.endsWith("/constants.ts") ||
        normalized.endsWith("-constants.ts") ||
        normalized.endsWith(".constants.ts")
    );
};

const isUpperSnake = function isUpperSnake(name: string): boolean {
    let hasUpper = false;
    for (const ch of name) {
        if (isUpperAlpha(ch)) {
            hasUpper = true;
            continue;
        }
        if (!isDigit(ch) && ch !== "_") {
            return false;
        }
    }
    return hasUpper;
};

const offendingConstName = function offendingConstName(declarator: VarDeclarator): string | null {
    if (declarator.id.type !== "Identifier" || typeof declarator.id.name !== "string") {
        return null;
    }
    const { name } = declarator.id;
    if (!isUpperSnake(name)) {
        return null;
    }
    const initType = declarator.init?.type;
    return typeof initType === "string" && CONFIG_INIT_TYPES.has(initType) ? name : null;
};

const onExport = function onExport(context: Rule.RuleContext, node: Rule.Node): void {
    if (node.type !== "ExportNamedDeclaration") {
        return;
    }
    const { declaration } = node;
    if (declaration?.type !== "VariableDeclaration" || declaration.kind !== "const") {
        return;
    }
    for (const declarator of declaration.declarations) {
        const name = offendingConstName(declarator);
        if (name !== null) {
            context.report({ data: { name }, messageId: "decentralizedConfig", node });
        }
    }
};

export default {
    create(context): Rule.RuleListener {
        if (!isWorkspaceSrcFile(context.filename) || isCentralConstantsLocation(context.filename)) {
            return {};
        }
        const listeners: Rule.RuleListener = {};
        for (const selector of SELECTORS) {
            listeners[selector] = (node: Rule.Node): void => {
                onExport(context, node);
            };
        }
        return listeners;
    },

    meta: {
        docs: {
            description:
                "Exported UPPER_SNAKE config constants (objects/arrays/literals) must live in the package's central constants location, not scattered across concern modules.",
        },
        messages: { decentralizedConfig: MESSAGE },
        schema: [],
        type: "problem",
    },
} satisfies Rule.RuleModule;