# domain/loaders/evidence.loader.ts

> 109 lines of code and 22 definitions.

Tree: Site tree
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/tree#file-domain-loaders-evidence-loader-ts
Source text: https://banes-lab.com/assets/sources/source.9cd19f4a3854ba2f70ad81a4922677ef59fd3dcfe27e1c38cf712e53154f4d5d.generated.txt

## Definitions

- `treeRef` (lexical_declaration, line 24)
- `relation` (lexical_declaration, line 60)
- `resolveDefinition` (lexical_declaration, line 28)
- `resolveFile` (lexical_declaration, line 39)
- `resolveWords` (lexical_declaration, line 46)
- `evidenceRelations` (lexical_declaration, line 64, exported)
- `withEvidence` (lexical_declaration, line 112, exported)
- `resolveNode` (lexical_declaration, line 53, exported)
- `subjectEdge` (lexical_declaration, line 82)
- `groundingRelations` (lexical_declaration, line 91, exported)
- `Resolved` (interface_declaration, line 18)
- `location` (lexical_declaration, line 29)
- `path` (lexical_declaration, line 47)
- `holds` (lexical_declaration, line 77)
- `resolved` (lexical_declaration, line 78, exported)
- `face` (lexical_declaration, line 86)
- `record` (lexical_declaration, line 87)
- `requested` (lexical_declaration, line 95, exported)
- `node` (lexical_declaration, line 101, exported)
- `subjects` (lexical_declaration, line 102, exported)
- `edges` (lexical_declaration, line 105, exported)
- `added` (lexical_declaration, line 119, exported)

## Uses

- [domain/converters/evidence.converter.ts](https://banes-lab.com/source/tree/domain/converters/evidence.converter.ts.md)
- [domain/converters/source.converter.ts](https://banes-lab.com/source/tree/domain/converters/source.converter.ts.md)

## Used by

- [domain/loaders/reference.loader.ts](https://banes-lab.com/source/tree/domain/loaders/reference.loader.ts.md)

## Source

```typescript
import { ANATOMY_FACE, CHAPTER_FACE } from "#configuration/constants/vocabulary.constants";
import { EVIDENCE_RELATION, GROUNDS_RELATION } from "#configuration/strings/folder.strings";
import type { Evidence, EvidenceNode, EvidenceSubject } from "#types/evidence.types";
import type { ReferenceContent, ReferenceRelation, ReferenceTarget } from "#types/reference.types";
import { chapterEdge, evidenceFor } from "#domain/converters/evidence.converter";
import { citedDefinition, resolveFolder, resolvePath } from "#core/loaders/definition.loader";
import { fileId, folderHref, folderId, nodeHref } from "#domain/converters/source.converter";
import { ANCHOR_PREFIX } from "#configuration/constants/document.constants";
import { EVIDENCE } from "#configuration/constants/evidence.source.constants";
import type { EdgeRef } from "#types/link.types";
import { FACE_SEPARATOR } from "@govlab/constants";
import type { NodeTarget } from "#types/folder.types";
import { PATH_SEPARATOR } from "#configuration/constants/anatomy.constants";
import { loadReferences } from "#assets/reference.generated";
import { resolveTarget } from "#domain/loaders/anatomy.loader";
import { targetOf } from "#core/converters/folder.converter";

interface Resolved {
    readonly edge: EdgeRef;
    readonly id: string;
    readonly line: number | null;
}

const treeRef = function treeRef(href: string): string {
    return CHAPTER_FACE + FACE_SEPARATOR + href;
};

const resolveDefinition = function resolveDefinition(name: string, file: string | null): Resolved | null {
    const location = citedDefinition(name, file);
    return location === null
        ? null
        : {
              edge: { label: name, ref: treeRef(nodeHref(location.file, location.line)) },
              id: fileId(location.file),
              line: location.line,
          };
};

const resolveFile = function resolveFile(name: string): Resolved | null {
    const path = resolvePath(name);
    return path === null
        ? null
        : { edge: { label: name, ref: treeRef(nodeHref(path, null)) }, id: fileId(path), line: null };
};

const resolveWords = function resolveWords(words: readonly string[]): Resolved | null {
    const path = resolveFolder(words.join(PATH_SEPARATOR));
    return path === null
        ? null
        : { edge: { label: path, ref: treeRef(folderHref(path)) }, id: folderId(path), line: null };
};

export const resolveNode = function resolveNode(node: EvidenceNode): Resolved | null {
    if (node.kind === "definition") {
        return resolveDefinition(node.name, node.file);
    }
    return node.kind === "file" ? resolveFile(node.name) : resolveWords(node.words);
};

const relation = function relation(name: string, edges: readonly EdgeRef[]): ReferenceRelation[] {
    return edges.length === 0 ? [] : [{ edges, relation: name }];
};

export const evidenceRelations = function evidenceRelations(
    target: ReferenceTarget,
    registry: readonly Evidence[] = EVIDENCE,
): ReferenceRelation[] {
    const edges = evidenceFor(target, registry).flatMap((entry) =>
        entry.nodes.flatMap((node) => {
            const resolved = resolveNode(node);
            return resolved === null ? [] : [resolved.edge];
        }),
    );
    return relation(EVIDENCE_RELATION, edges);
};

const holds = function holds(node: EvidenceNode, target: NodeTarget): boolean {
    const resolved = resolveNode(node);
    return resolved !== null && resolved.id === target.id && (resolved.line === null || resolved.line === target.line);
};

const subjectEdge = async function subjectEdge(subject: EvidenceSubject): Promise<EdgeRef | null> {
    if (subject.kind === "chapter") {
        return chapterEdge(subject);
    }
    const face = subject.ref.slice(0, subject.ref.indexOf(FACE_SEPARATOR));
    const record = (await loadReferences(face))?.[subject.ref];
    return record === undefined ? null : { label: record.name, ref: subject.ref };
};

export const groundingRelations = async function groundingRelations(
    target: ReferenceTarget,
    registry: readonly Evidence[] = EVIDENCE,
): Promise<ReferenceRelation[]> {
    const requested = targetOf(
        ANCHOR_PREFIX + target.ref.slice(target.ref.indexOf(FACE_SEPARATOR) + FACE_SEPARATOR.length),
    );
    if (requested === null) {
        return [];
    }
    const node = resolveTarget(requested);
    const subjects = registry
        .filter((entry) => entry.nodes.some((candidate) => holds(candidate, node)))
        .map((entry) => entry.subject);
    const edges = await Promise.all(subjects.map(subjectEdge));
    return relation(
        GROUNDS_RELATION,
        edges.filter((edge): edge is EdgeRef => edge !== null),
    );
};

export const withEvidence = async function withEvidence(
    target: ReferenceTarget,
    content: ReferenceContent,
): Promise<ReferenceContent> {
    if (content.kind === "chapter") {
        return { chapter: { ...content.chapter, relations: evidenceRelations(target) }, kind: "chapter" };
    }
    const added = target.face === ANATOMY_FACE ? await groundingRelations(target) : evidenceRelations(target);
    return { kind: "record", record: { ...content.record, relations: [...content.record.relations, ...added] } };
};
```
