# codemods/entrypoints/code-point.entrypoint.ts

> 46 lines of code and 11 definitions.

Tree: Governance tree
Language: typescript
Layer: runtime
Canonical: https://banes-lab.com/anatomy/governance#file-governance-codemods-entrypoints-code-point-entrypoint-ts
Source text: https://banes-lab.com/source/governance/codemods/entrypoints/code-point.entrypoint.ts.txt

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

## Definitions

- `scanProgram` (lexical_declaration, line 10)
- `collect` (lexical_declaration, line 25)
- `RULE_ID` (lexical_declaration, line 8)
- `program` (lexical_declaration, line 11)
- `checker` (lexical_declaration, line 12)
- `buildEdits` (lexical_declaration, line 16)
- `byFile` (lexical_declaration, line 17)
- `edit` (lexical_declaration, line 19)
- `seen` (lexical_declaration, line 26)
- `findings` (lexical_declaration, line 27)
- `key` (lexical_declaration, line 30)

## Uses

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

## Records this file checks

- [Correctness](https://banes-lab.com/records/architecture/correctness.md)

## Source

```typescript
import { CODEMOD_TSCONFIGS, programFor, repoSourceFiles } from "../selectors/program.selector.ts";
import { replacementText, scanSourceFile } from "../analyzers/code-point.analyzer.ts";
import type { CodePointFinding } from "../../types/analyzer.types.ts";
import type { Edit } from "../../types/codemod.types.ts";
import { applyCodemod } from "../selectors/codemod.selector.ts";
import { defineCheck } from "@govlab/context/check";

const RULE_ID = "prefer-code-point";

const scanProgram = function scanProgram(tsconfigPath: string): CodePointFinding[] {
    const program = programFor(tsconfigPath);
    const checker = program.getTypeChecker();
    return repoSourceFiles(program).flatMap((sourceFile) => scanSourceFile(checker, sourceFile));
};

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

const collect = function collect(): CodePointFinding[] {
    const seen = new Set<string>();
    const findings: CodePointFinding[] = [];
    for (const tsconfig of CODEMOD_TSCONFIGS) {
        for (const finding of scanProgram(tsconfig)) {
            const key = `${finding.file}:${String(finding.start)}`;
            if (!seen.has(key)) {
                seen.add(key);
                findings.push(finding);
            }
        }
    }
    return findings;
};

applyCodemod({
    appliedNoun: "charCodeAt call(s) rewritten to a null-coalesced codePointAt",
    blockedMessage: (finding) =>
        `'charCodeAt' returns a UTF-16 code unit, so it splits an astral character into surrogate halves; 'codePointAt' returns the whole code point but widens the result to 'number | undefined'. This call cannot be rewritten automatically (${finding.reason}).`,
    checks: defineCheck({ detects: [], enforces: ["architecture:correctness"] }),
    editsByFile: buildEdits,
    findings: collect(),
    gateOnBlocked: false,
    label: (finding) => finding.receiver,
    programCount: CODEMOD_TSCONFIGS.length,
    ruleId: RULE_ID,
});
```
