# tools/core/validators/repair.validator.ts

> 69 lines of code and 17 definitions.

Tree: Coordination tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-validators-repair-validator-ts
Source text: https://banes-lab.com/source/coordination/tools/core/validators/repair.validator.ts.txt

Listed in [tools/core/validators](https://banes-lab.com/api/source/coordination/tools/core/validators.md), after [tools/core/validators/record.validator.ts](https://banes-lab.com/source/coordination/tools/core/validators/record.validator.ts.md) and before [tools/core/validators/rule.validator.ts](https://banes-lab.com/source/coordination/tools/core/validators/rule.validator.ts.md).

## Definitions

- `candidateOf` (lexical_declaration, line 38)
- `UnrepairableLocus` (interface_declaration, line 5)
- `UnrepairableCandidate` (interface_declaration, line 12)
- `RepairJudges` (interface_declaration, line 17)
- `textOf` (lexical_declaration, line 22)
- `reasonOf` (lexical_declaration, line 26)
- `remediation` (lexical_declaration, line 43)
- `target` (lexical_declaration, line 44)
- `locus` (lexical_declaration, line 49)
- `reason` (lexical_declaration, line 50)
- `rule` (lexical_declaration, line 51)
- `unrepairableLoci` (lexical_declaration, line 57, exported)
- `judges` (lexical_declaration, line 62, exported)
- `candidates` (lexical_declaration, line 63, exported)
- `held` (lexical_declaration, line 64, exported)
- `seen` (lexical_declaration, line 70, exported)
- `fresh` (lexical_declaration, line 73, exported)

## Uses

- [tools/core/predicates/schema.predicate.ts](https://banes-lab.com/source/coordination/tools/core/predicates/schema.predicate.ts.md)

## Source

```typescript
import { fieldOf } from "../readers/json.reader.ts";
import { isObject } from "../predicates/schema.predicate.ts";
import { reportsIn } from "../readers/report.reader.ts";

interface UnrepairableLocus {
    readonly report: string;
    readonly rule: string;
    readonly target: string;
    readonly reason: "frozenTarget" | "permanentSpan";
}

interface UnrepairableCandidate {
    readonly key: string;
    readonly locus: UnrepairableLocus;
}

interface RepairJudges {
    readonly frozen: (target: string) => boolean;
    readonly permanentSpan: (path: string, locus: string) => boolean;
}

const textOf = function textOf(value: unknown): string {
    return typeof value === "string" ? value : "";
};

const reasonOf = function reasonOf(
    target: string,
    reported: string,
    locus: string,
    judges: RepairJudges,
): UnrepairableLocus["reason"] | null {
    if (judges.frozen(target)) {
        return "frozenTarget";
    }
    return judges.permanentSpan(reported, locus) ? "permanentSpan" : null;
};

const candidateOf = function candidateOf(
    entry: string,
    finding: unknown,
    judges: RepairJudges,
): UnrepairableCandidate[] {
    const remediation = isObject(finding) ? finding["remediation"] : undefined;
    const target = isObject(remediation) ? remediation["target"] : undefined;
    if (!isObject(finding) || typeof target !== "string") {
        return [];
    }

    const locus = textOf(finding["locus"]);
    const reason = reasonOf(target, textOf(finding["path"]), locus, judges);
    const rule = textOf(finding["rule"]);
    return reason === null
        ? []
        : [{ key: `${entry}|${rule}|${target}|${locus}`, locus: { reason, report: entry, rule, target } }];
};

export const unrepairableLoci = function unrepairableLoci(
    repoRoot: string,
    frozen: (target: string) => boolean,
    permanentSpan: (path: string, locus: string) => boolean,
): UnrepairableLocus[] {
    const judges: RepairJudges = { frozen, permanentSpan };
    const candidates = reportsIn(repoRoot).flatMap((report) => {
        const held = fieldOf(report.value, "findings");
        return Array.isArray(held)
            ? held.flatMap((finding: unknown) => candidateOf(report.entry, finding, judges))
            : [];
    });

    const seen = new Set<string>();
    return candidates
        .filter((candidate) => {
            const fresh = !seen.has(candidate.key);
            seen.add(candidate.key);
            return fresh;
        })
        .map((candidate) => candidate.locus);
};
```
