# codemods/entrypoints/sink.entrypoint.ts

> 80 lines of code and 29 definitions.

Tree: GovLab Extension Host
Language: typescript
Layer: runtime
Canonical: https://banes-lab.com/anatomy/governance#file-governance-codemods-entrypoints-sink-entrypoint-ts
Source text: https://banes-lab.com/source/governance/codemods/entrypoints/sink.entrypoint.ts.txt

Listed in [codemods/entrypoints](https://banes-lab.com/api/source/governance/codemods/entrypoints.md), after [codemods/entrypoints/location.entrypoint.ts](https://banes-lab.com/source/governance/codemods/entrypoints/location.entrypoint.ts.md) and before [codemods/entrypoints/specifier.entrypoint.ts](https://banes-lab.com/source/governance/codemods/entrypoints/specifier.entrypoint.ts.md).

## Definitions

- `isRecord` (lexical_declaration, line 17)
- `declaresWriter` (lexical_declaration, line 40)
- `collect` (lexical_declaration, line 53)
- `RULE_ID` (lexical_declaration, line 12)
- `RULE_KEY` (lexical_declaration, line 13)
- `WRITER_MODULE` (lexical_declaration, line 14)
- `MANIFEST` (lexical_declaration, line 15)
- `ownerModulesOf` (lexical_declaration, line 21)
- `entry` (lexical_declaration, line 22)
- `options` (lexical_declaration, line 23)
- `modules` (lexical_declaration, line 24)
- `nearestManifest` (lexical_declaration, line 28)
- `folder` (lexical_declaration, line 29)
- `candidate` (lexical_declaration, line 31)
- `manifest` (lexical_declaration, line 41)
- `parsed` (lexical_declaration, line 45)
- `dependencies` (lexical_declaration, line 46)
- `qualityConfig` (lexical_declaration, line 50)
- `writeScope` (lexical_declaration, line 51)
- `seen` (lexical_declaration, line 54)
- `program` (lexical_declaration, line 56)
- `checker` (lexical_declaration, line 57)
- `key` (lexical_declaration, line 60)
- `fresh` (lexical_declaration, line 61)
- `buildEdits` (lexical_declaration, line 67)
- `byFile` (lexical_declaration, line 68)
- `known` (lexical_declaration, line 70)
- `imports` (lexical_declaration, line 71)
- `edit` (lexical_declaration, line 72)

## Contained in

- [codemods/entrypoints](https://banes-lab.com/anatomy/governance/folder-governance-codemods-entrypoints.md)

## Uses

- [codemods/selectors/program.selector.ts](https://banes-lab.com/source/governance/codemods/selectors/program.selector.ts.md)

## Enforces

- [Idempotency](https://banes-lab.com/records/architecture/idempotency.md)
- [Determinism](https://banes-lab.com/records/architecture/determinism.md)

## Linked from

- [codemods/entrypoints](https://banes-lab.com/anatomy/governance/folder-governance-codemods-entrypoints.md)
- [codemods/selectors](https://banes-lab.com/anatomy/governance/folder-governance-codemods-selectors.md)

## Source

```typescript
import { CODEMOD_TSCONFIGS, programFor, repoSourceFiles } from "../selectors/program.selector.ts";
import type { WriteFinding, WriteScope } from "../../types/analyzer.types.ts";
import { dirname, join } from "node:path";
import { existsSync, readFileSync } from "node:fs";
import type { Edit } from "../../types/codemod.types.ts";
import { ROOT } from "@ssot/paths";
import { applyCodemod } from "../selectors/codemod.selector.ts";
import { defineCheck } from "@govlab/context/check";
import { loadGovlabConfig } from "@govlab/quality/config";
import { scanSourceFile } from "../analyzers/sink.analyzer.ts";

const RULE_ID = "no-raw-file-write";
const RULE_KEY = "govlab-write/no-raw-file-write";
const WRITER_MODULE = "@govlab/canonical-write";
const MANIFEST = "package.json";

const isRecord = function isRecord(value: unknown): value is Record<string, unknown> {
    return typeof value === "object" && value !== null;
};

const ownerModulesOf = function ownerModulesOf(rules: unknown): Set<string> {
    const entry = isRecord(rules) ? rules[RULE_KEY] : undefined;
    const options: unknown = Array.isArray(entry) ? entry.at(1) : undefined;
    const modules = isRecord(options) ? options["modules"] : undefined;
    return new Set(Array.isArray(modules) ? modules.filter((name): name is string => typeof name === "string") : []);
};

const nearestManifest = function nearestManifest(fileName: string): string | null {
    let folder = dirname(fileName);
    while (folder !== dirname(folder)) {
        const candidate = join(folder, MANIFEST);
        if (existsSync(candidate)) {
            return candidate;
        }
        folder = dirname(folder);
    }
    return null;
};

const declaresWriter = function declaresWriter(fileName: string): boolean {
    const manifest = nearestManifest(fileName);
    if (manifest === null) {
        return false;
    }
    const parsed: unknown = JSON.parse(readFileSync(manifest, "utf8"));
    const dependencies = isRecord(parsed) ? parsed["dependencies"] : undefined;
    return isRecord(dependencies) && WRITER_MODULE in dependencies;
};

const qualityConfig = await loadGovlabConfig(ROOT);
const writeScope: WriteScope = { declaresWriter, owners: ownerModulesOf(qualityConfig.eslint?.rules) };

const collect = function collect(): WriteFinding[] {
    const seen = new Set<string>();
    return CODEMOD_TSCONFIGS.flatMap((tsconfig) => {
        const program = programFor(tsconfig);
        const checker = program.getTypeChecker();
        return repoSourceFiles(program).flatMap((source) => scanSourceFile(checker, source, writeScope));
    }).filter((finding) => {
        const key = `${finding.file}:${String(finding.start)}`;
        const fresh = !seen.has(key);
        seen.add(key);
        return fresh;
    });
};

const buildEdits = function buildEdits(findings: readonly WriteFinding[]): Map<string, Edit[]> {
    const byFile = new Map<string, Edit[]>();
    for (const finding of findings) {
        const known = byFile.get(finding.fileName);
        const imports = known === undefined ? finding.importEdits : [];
        const edit: Edit = { end: finding.end, replacement: finding.replacement, start: finding.start };
        byFile.set(finding.fileName, [...(known ?? []), ...imports, edit]);
    }
    return byFile;
};

applyCodemod({
    appliedNoun: "raw file write(s) routed through the owner's verbatim writer",
    blockedMessage: (finding) =>
        `A raw file write outside the module that owns file writes skips what the owner guarantees. This write cannot be rewritten automatically (${finding.reason ?? ""}).`,
    checks: defineCheck({ detects: [], enforces: ["architecture:idempotency", "architecture:determinism"] }),
    editsByFile: buildEdits,
    findings: collect(),
    gateOnBlocked: false,
    label: (finding) => finding.replacement,
    programCount: CODEMOD_TSCONFIGS.length,
    ruleId: RULE_ID,
});
```
