# core/validators/evidence.validator.ts

> 48 lines of code and 12 definitions.

Tree: Build tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/build#file-build-core-validators-evidence-validator-ts
Source text: https://banes-lab.com/assets/sources/source.a1025f9108b8b5eaf239dd40f754e6efb1e8500828d4b8efea13067b63577f6d.generated.txt

## Definitions

- `nodeOf` (lexical_declaration, line 6)
- `teachingNodes` (lexical_declaration, line 15)
- `chapterNodes` (lexical_declaration, line 23)
- `NODE_MARK` (lexical_declaration, line 4)
- `finding` (lexical_declaration, line 10)
- `cut` (lexical_declaration, line 11)
- `groundingOf` (lexical_declaration, line 31, exported)
- `teaching` (lexical_declaration, line 36, exported)
- `declared` (lexical_declaration, line 37, exported)
- `grounded` (lexical_declaration, line 40, exported)
- `absent` (lexical_declaration, line 41, exported)
- `findings` (lexical_declaration, line 42, exported)

## Source

```typescript
import type { ContentGraph, DeclaredAbsence, Evidence, GraphFinding, GroundingReport } from "#types/coverage.types";
import { GROUNDING_CONTRADICTED, GROUNDING_UNDECLARED } from "#configuration/strings/coverage.strings";

const NODE_MARK = "#";

const nodeOf = function nodeOf(page: string, section: string): string {
    return page + NODE_MARK + section;
};

const finding = function finding(node: string, message: string): GraphFinding {
    const cut = node.indexOf(NODE_MARK);
    return { message, page: node.slice(0, cut), section: node.slice(cut + NODE_MARK.length) };
};

const teachingNodes = function teachingNodes(graphs: readonly ContentGraph[]): readonly string[] {
    return graphs.flatMap((graph) =>
        Object.entries(graph.sections).flatMap(([section, held]) =>
            held.teaches.length > 0 ? [nodeOf(graph.page, section)] : [],
        ),
    );
};

const chapterNodes = function chapterNodes(evidence: readonly Evidence[]): ReadonlySet<string> {
    return new Set(
        evidence.flatMap((entry) =>
            entry.subject.kind === "chapter" ? [nodeOf(entry.subject.page, entry.subject.section)] : [],
        ),
    );
};

export const groundingOf = function groundingOf(
    graphs: readonly ContentGraph[],
    evidence: readonly Evidence[],
    absences: readonly DeclaredAbsence[],
): GroundingReport {
    const teaching = teachingNodes(graphs);
    const declared = new Set(
        graphs.flatMap((graph) => Object.keys(graph.sections).map((key) => nodeOf(graph.page, key))),
    );
    const grounded = chapterNodes(evidence);
    const absent = new Set(absences.map((entry) => nodeOf(entry.subject.page, entry.subject.section)));
    const findings = [
        ...[...grounded].filter((node) => absent.has(node)).map((node) => finding(node, GROUNDING_CONTRADICTED)),
        ...[...grounded, ...absent]
            .filter((node) => !declared.has(node))
            .map((node) => finding(node, GROUNDING_UNDECLARED)),
    ];
    return {
        absent: teaching.filter((node) => absent.has(node)),
        findings,
        grounded: teaching.filter((node) => grounded.has(node)),
        unassessed: teaching.filter((node) => !grounded.has(node) && !absent.has(node)),
    };
};
```
