rules/eslint/file-length.eslint.rule.ts

rules/eslint/file-length.eslint.rule.ts is a file in GovLab Extension Host. 64 lines of code and 10 definitions.

import type { LocalRule, RuleContext, RuleListener } from "../../types/rule.types.ts";
import { FILE_LENGTH } from "../../shared/generated/thresholds.generated.ts";
import { concernSuffix } from "../../shared/manifests/taxonomy.manifest.ts";
import { defineCheck } from "@govlab/context/check";
import { isStandaloneScript } from "../../shared/predicates/location.predicate.ts";
import { listener } from "../../shared/factories/listener.factory.ts";
import { normalizePath } from "../../shared/resolvers/anchor.resolver.ts";

const EXEMPT_SUFFIXES = [".test.ts", ".spec.ts", ".d.ts", ".generated.ts", ".json", concernSuffix("strings")];

const isExempt = function isExempt(filename: string): boolean {
    if (isStandaloneScript(filename)) {
        return true;
    }
    const norm = normalizePath(filename);
    for (const suffix of EXEMPT_SUFFIXES) {
        if (norm.endsWith(suffix)) {
            return true;
        }
    }
    return false;
};

const countLines = function countLines(text: string): number {
    let count = 0;
    for (const line of text.split("\n")) {
        if (line.trim().length > 0) {
            count += 1;
        }
    }
    return count;
};

export default {
    create(context: RuleContext): RuleListener {
        const { filename } = context;
        if (isExempt(filename)) {
            return {};
        }
        return listener({
            program(_view, node) {
                const count = countLines(context.sourceCode.getText());
                if (count <= FILE_LENGTH) {
                    return;
                }
                const basename = normalizePath(filename).split("/").pop() ?? filename;
                const payload = { count: String(count), file: basename, max: String(FILE_LENGTH) };
                context.report({ data: payload, messageId: "tooLong", node });
            },
        });
    },
    meta: {
        docs: {
            checks: defineCheck({
                detects: ["architecture:god-object"],
                enforces: ["architecture:single-responsibility"],
            }),
            description:
                "Every file stays within the one line budget the quality config declares, counted in non-blank lines. The budget is derived from the config into the generated thresholds module before any rule loads, so the number has one home and this rule restates nothing. A strings module is exempt: it is a catalog of copy, and its length is decided by the content it carries rather than by a concern that could be split. A standalone server script is exempt because it ships as one file and can import nothing.",
        },
        messages: {
            tooLong:
                "`{{ file }}` is {{ count }} non-blank lines, over the {{ max }}-line budget the quality config declares. Split it by concern.",
        },
        schema: [],
        type: "problem",
    },
} satisfies LocalRule;