# rules/eslint/closure-standalone-script-imported.eslint.rule.ts

> 40 lines of code and 10 definitions.

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

Listed in [rules/eslint](https://banes-lab.com/api/source/governance/rules/eslint.md), after [rules/eslint/closure-show-flag-polarity.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/closure-show-flag-polarity.eslint.rule.ts.md) and before [rules/eslint/closure-tests-centralized.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/closure-tests-centralized.eslint.rule.ts.md).

## Definitions

- `create` (method_definition, line 16, exported)
- `LIST_JOINER` (lexical_declaration, line 8)
- `SHOWN_IMPORTERS` (lexical_declaration, line 9)
- `STANDALONE_ROOT` (lexical_declaration, line 11)
- `HOME` (lexical_declaration, line 12)
- `IMPORTERS` (lexical_declaration, line 13)
- `filename` (lexical_declaration, line 17, exported)
- `found` (lexical_declaration, line 18, exported)
- `program` (method_definition, line 23, exported)
- `importers` (lexical_declaration, line 24, 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 { applicationImporters } from "../../shared/analyzers/specifier.analyzer.ts";
import { defineCheck } from "@govlab/context/check";
import { listener } from "../../shared/factories/listener.factory.ts";
import { normalizePath } from "../../shared/resolvers/anchor.resolver.ts";

const LIST_JOINER = ", ";
const SHOWN_IMPORTERS = 3;

const STANDALONE_ROOT = `${normalizePath(absolutePath("project.scripts"))}/`;
const HOME = relativePath("app.build");
const IMPORTERS = applicationImporters();

export default {
    create(context: RuleContext): RuleListener {
        const filename = normalizePath(context.filename);
        const found = filename.startsWith(STANDALONE_ROOT) ? IMPORTERS.get(filename) : undefined;
        if (found === undefined) {
            return {};
        }
        return listener({
            program(_view, node) {
                const importers = [...new Set(found)].slice(0, SHOWN_IMPORTERS).join(LIST_JOINER);
                context.report({ data: { home: HOME, importers }, messageId: "importedScript", node });
            },
        });
    },
    meta: {
        docs: {
            checks: defineCheck({ detects: [], enforces: ["architecture:explicit-boundaries"] }),
            description:
                "A standalone script runs on its own and nothing imports it. Once a file under the application root imports one, the script has become a dependency of the application, and it belongs in the member that owns the application's build.",
            workspaceWide: true,
        },
        messages: {
            importedScript:
                "This script is imported by {{importers}}, so it is part of the application's build rather than a standalone script. Move it to {{home}}, the member that owns the scripts the application imports, and point its importers at that package.",
        },
        schema: [],
        type: "problem",
    },
} satisfies LocalRule;
```
