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

> 60 lines of code and 10 definitions.

Tree: Governance tree
Language: typescript
Canonical: https://banes-lab.com/anatomy/governance#file-governance-rules-eslint-file-length-eslint-rule-ts
Source text: https://banes-lab.com/source/governance/rules/eslint/file-length.eslint.rule.ts.txt

Listed in [rules/eslint](https://banes-lab.com/api/source/governance/rules/eslint.md), after [rules/eslint/factory-owned-value.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/factory-owned-value.eslint.rule.ts.md) and before [rules/eslint/no-comments.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/no-comments.eslint.rule.ts.md).

## Definitions

- `isExempt` (lexical_declaration, line 10)
- `create` (method_definition, line 31, exported)
- `EXEMPT_SUFFIXES` (lexical_declaration, line 8)
- `norm` (lexical_declaration, line 11)
- `countLines` (lexical_declaration, line 20)
- `{ filename }` (lexical_declaration, line 32, exported)
- `program` (method_definition, line 37, exported)
- `count` (lexical_declaration, line 38, exported)
- `basename` (lexical_declaration, line 42, exported)
- `payload` (lexical_declaration, line 43, exported)

## Uses

- [shared/factories/listener.factory.ts](https://banes-lab.com/source/governance/shared/factories/listener.factory.ts.md)

## Records this file checks

- [Single Responsibility Principle](https://banes-lab.com/records/architecture/single-responsibility.md)
- [God Object](https://banes-lab.com/records/architecture/god-object.md)

## Source

```typescript
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 { 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 {
    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.",
        },
        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;
```
