# rules/eslint/closure-build-script-unimported.eslint.rule.ts

> 51 lines of code and 9 definitions.

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

Listed in [rules/eslint](https://banes-lab.com/api/source/governance/rules/eslint.md), after [rules/eslint/closure-barrel-must-be-glob.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/closure-barrel-must-be-glob.eslint.rule.ts.md) and before [rules/eslint/closure-discriminated-union-must-be-exhaustive.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/closure-discriminated-union-must-be-exhaustive.eslint.rule.ts.md).

## Definitions

- `create` (method_definition, line 30, exported)
- `SOURCE_EXTENSION` (lexical_declaration, line 11)
- `discoveredFiles` (lexical_declaration, line 13)
- `folder` (lexical_declaration, line 14)
- `BUILD_ROOT` (lexical_declaration, line 22)
- `HOME` (lexical_declaration, line 23)
- `REACHED` (lexical_declaration, line 24)
- `filename` (lexical_declaration, line 31, exported)
- `program` (method_definition, line 36, exported)

## Uses

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

## Records this file checks

- [Explicit Boundaries](https://banes-lab.com/records/architecture/explicit-boundaries.md)

## Source

```typescript
import type { LocalRule, RuleContext, RuleListener } from "../../types/rule.types.ts";
import { absolutePath, relativePath } from "@ssot/paths";
import { existsSync, readdirSync } from "node:fs";
import { gateTargets, reachedUnder, scriptTargets } from "../../shared/analyzers/specifier.analyzer.ts";
import { DISCOVERED_FOLDER_KEYS } from "../../shared/manifests/folder.manifest.ts";
import { defineCheck } from "@govlab/context/check";
import { join } from "node:path";
import { listener } from "../../shared/factories/listener.factory.ts";
import { normalizePath } from "../../shared/resolvers/anchor.resolver.ts";

const SOURCE_EXTENSION = ".ts";

const discoveredFiles = function discoveredFiles(key: string): string[] {
    const folder = absolutePath(key);
    return existsSync(folder)
        ? readdirSync(folder)
              .filter((name) => name.endsWith(SOURCE_EXTENSION))
              .map((name) => normalizePath(join(folder, name)))
        : [];
};

const BUILD_ROOT = `${normalizePath(absolutePath("app.build"))}/`;
const HOME = relativePath("project.scripts");
const REACHED = reachedUnder(
    BUILD_ROOT,
    new Set([...scriptTargets(), ...gateTargets(), ...DISCOVERED_FOLDER_KEYS.flatMap(discoveredFiles)]),
);

export default {
    create(context: RuleContext): RuleListener {
        const filename = normalizePath(context.filename);
        if (!filename.startsWith(BUILD_ROOT) || !filename.endsWith(SOURCE_EXTENSION) || REACHED.has(filename)) {
            return {};
        }
        return listener({
            program(_view, node) {
                context.report({ data: { home: HOME }, messageId: "unimportedScript", node });
            },
        });
    },
    meta: {
        docs: {
            checks: defineCheck({ detects: [], enforces: ["architecture:explicit-boundaries"] }),
            description:
                "The build member holds only the scripts the application reaches through its imports, that a package script or a gate step runs, or that a pipeline discovers in one of its declared discovery folders. A file there that none of these reaches is a standalone script, and it belongs with the standalone scripts.",
            workspaceWide: true,
        },
        messages: {
            unimportedScript:
                "No chain of imports from the application reaches this file, and neither a package script nor a gate step runs it, so it is a standalone script rather than part of the build. Move it to {{home}}, where standalone scripts live.",
        },
        schema: [],
        type: "problem",
    },
} satisfies LocalRule;
```
