# codemods/selectors/codemod.selector.ts

> 65 lines of code and 14 definitions.

Tree: Governance tree
Language: typescript
Layer: application
Canonical: https://banes-lab.com/anatomy/governance#file-governance-codemods-selectors-codemod-selector-ts
Source text: https://banes-lab.com/source/governance/codemods/selectors/codemod.selector.ts.txt

Listed in [codemods/selectors](https://banes-lab.com/api/source/governance/codemods/selectors.md), before [codemods/selectors/edit.selector.ts](https://banes-lab.com/source/governance/codemods/selectors/edit.selector.ts.md).

## Definitions

- `report` (lexical_declaration, line 19)
- `printMap` (lexical_declaration, line 32)
- `reportBlocked` (lexical_declaration, line 39)
- `locationOf` (lexical_declaration, line 28)
- `applyCodemod` (lexical_declaration, line 53, exported)
- `refuse` (lexical_declaration, line 23, exported)
- `MAP` (lexical_declaration, line 16)
- `FAILURE` (lexical_declaration, line 17)
- `sorted` (lexical_declaration, line 33)
- `line` (lexical_declaration, line 44)
- `convertible` (lexical_declaration, line 58, exported)
- `blocked` (lexical_declaration, line 59, exported)
- `applied` (lexical_declaration, line 60, exported)
- `programs` (lexical_declaration, line 61, exported)

## Uses

- [codemods/strings/codemod.strings.ts](https://banes-lab.com/source/governance/codemods/strings/codemod.strings.ts.md)

## Source

```typescript
import {
    CONVERTIBLE,
    DEFAULT_SCOPE_NOUN,
    appliedLine,
    blockedLine,
    gatedLine,
    handFixLine,
    leftAsWrittenLine,
    mapLine,
    noteLine,
    refusedLine,
} from "../strings/codemod.strings.ts";
import type { CodemodFinding, CodemodSpec } from "../../types/codemod.types.ts";
import { applyByFile } from "./edit.selector.ts";

const MAP = process.argv.includes("--map");
const FAILURE = 1;

const report = function report(line: string): void {
    process.stdout.write(`${line}\n`);
};

export const refuse = function refuse(reason: string): never {
    process.stderr.write(refusedLine(reason));
    process.exit(FAILURE);
};

const locationOf = function locationOf(finding: CodemodFinding): string {
    return `${finding.file}:${String(finding.line)}`;
};

const printMap = function printMap<F extends CodemodFinding>(spec: CodemodSpec<F>): void {
    const sorted = [...spec.findings].toSorted((a, b) => a.file.localeCompare(b.file) || a.line - b.line);
    for (const finding of sorted) {
        report(mapLine(locationOf(finding), spec.label(finding), finding.reason ?? CONVERTIBLE));
    }
};

const reportBlocked = function reportBlocked<F extends CodemodFinding>(
    spec: CodemodSpec<F>,
    blocked: readonly F[],
): void {
    for (const finding of blocked) {
        const line = blockedLine(locationOf(finding), spec.ruleId, spec.blockedMessage(finding));
        if (spec.gateOnBlocked) {
            process.stderr.write(`${gatedLine(line)}\n`);
        } else {
            report(noteLine(line));
        }
    }
};

export const applyCodemod = function applyCodemod<F extends CodemodFinding>(spec: CodemodSpec<F>): void {
    if (MAP) {
        printMap(spec);
        process.exit(0);
    }
    const convertible = spec.findings.filter((finding) => finding.reason === null);
    const blocked = spec.findings.filter((finding) => finding.reason !== null);
    const applied = applyByFile(spec.editsByFile(convertible));
    const programs = String(spec.programCount);
    report(appliedLine(spec.ruleId, applied, spec.appliedNoun, programs, spec.scopeNoun ?? DEFAULT_SCOPE_NOUN));
    if (blocked.length === 0) {
        return;
    }
    reportBlocked(spec, blocked);
    if (spec.gateOnBlocked) {
        process.stderr.write(`${handFixLine(spec.ruleId, blocked.length)}\n`);
        process.exit(FAILURE);
    }
    report(leftAsWrittenLine(spec.ruleId, blocked.length));
};
```
