# core/converters/check.converter.ts

> 95 lines of code and 23 definitions.

Tree: Bane's Lab Build Scripts
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/build-scripts#file-build-scripts-core-converters-check-converter-ts
Source text: https://banes-lab.com/source/build-scripts/core/converters/check.converter.ts.txt

Listed in [core/converters](https://banes-lab.com/api/source/build-scripts/core/converters.md), after [core/converters/catalog.grammar.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/catalog.grammar.converter.ts.md) and before [core/converters/company.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/company.converter.ts.md).

## Definitions

- `answerOf` (lexical_declaration, line 24)
- `within` (lexical_declaration, line 58)
- `resolutionOf` (lexical_declaration, line 77, exported)
- `entryOf` (lexical_declaration, line 57)
- `recordRefOf` (lexical_declaration, line 15, exported)
- `anchorOf` (lexical_declaration, line 16, exported)
- `coverageOf` (lexical_declaration, line 63)
- `answersOf` (lexical_declaration, line 28)
- `ANCHORED` (lexical_declaration, line 10)
- `untypedResolvers` (lexical_declaration, line 39)
- `isTyped` (lexical_declaration, line 47)
- `at` (lexical_declaration, line 48, exported)
- `CheckRefs` (interface_declaration, line 52)
- `records` (lexical_declaration, line 78, exported)
- `collections` (lexical_declaration, line 79, exported)
- `untyped` (lexical_declaration, line 80, exported)
- `refs` (lexical_declaration, line 81, exported)
- `answers` (lexical_declaration, line 88, exported)
- `slots` (lexical_declaration, line 89, exported)
- `byRecord` (lexical_declaration, line 90, exported)
- `view` (lexical_declaration, line 92, exported)
- `key` (lexical_declaration, line 93, exported)
- `slot` (lexical_declaration, line 94, exported)

## Contained in

- [core/converters](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-converters.md)

## Used by

- [core/converters/ontology.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/ontology.converter.ts.md)

## Linked from

- [core/converters](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-converters.md)

## Source

```typescript
import { ALGO_FACE, ARCH_FACE, FACE_SEPARATOR, LEX_FACE, PAG_FACE, REASON_FACE } from "@govlab/constants";
import type { CheckFacet, CheckedRecord, GovlabContext } from "@govlab/context";
import type { RecordCheckEntryView, ResolutionView } from "@banes-lab/web/types/ontology.types.js";
import { pagAnchor, reasonAnchor, refOf } from "#core/resolvers/ontology.resolver";
import type { CheckView } from "@banes-lab/web/types/reference.types.js";
import type { CoverageView } from "@banes-lab/web/types/coverage.types.js";
import type { EdgeRef } from "@banes-lab/web/types/link.types.js";
import type { Resolver } from "#types/ontology.types";

const ANCHORED: ReadonlyMap<string, (kind: string, id: string) => string> = new Map([
    [REASON_FACE, reasonAnchor],
    [PAG_FACE, pagAnchor],
]);

export const recordRefOf = function recordRefOf(collection: string, id: string): string {
    const anchorOf = ANCHORED.get(collection);
    if (anchorOf === undefined) {
        return refOf(collection, id);
    }
    const at = id.indexOf(FACE_SEPARATOR);
    return refOf(collection, anchorOf(id.slice(0, at), id.slice(at + FACE_SEPARATOR.length)));
};

const answerOf = function answerOf(answer: string | undefined): string | null {
    return answer === undefined || answer.trim().length === 0 ? null : answer;
};

const answersOf = function answersOf(facet: CheckFacet | null): CheckView {
    return {
        authority: answerOf(facet?.authority),
        evidence: answerOf(facet?.evidence),
        freshness: answerOf(facet?.freshness),
        observation: answerOf(facet?.observation),
        population: answerOf(facet?.population),
        refusal: answerOf(facet?.refusal),
    };
};

const untypedResolvers = function untypedResolvers(resolve: Resolver): ReadonlyMap<string, (raw: string) => EdgeRef> {
    return new Map([
        [ARCH_FACE, resolve.arch],
        [LEX_FACE, (raw: string): EdgeRef => resolve.target(refOf(LEX_FACE, raw))],
        [ALGO_FACE, resolve.algo],
    ]);
};

const isTyped = function isTyped(raw: string, collections: ReadonlySet<string>): boolean {
    const at = raw.indexOf(FACE_SEPARATOR);
    return at > 0 && collections.has(raw.slice(0, at));
};

interface CheckRefs {
    readonly by: (raw: string) => EdgeRef;
    readonly within: (collection: string, raw: string) => EdgeRef;
}

const entryOf = function entryOf(record: CheckedRecord, answers: number, refs: CheckRefs): RecordCheckEntryView {
    const within = (values: readonly string[]): readonly EdgeRef[] =>
        values.map((raw) => refs.within(record.collection, raw));
    return { answers, by: record.by.map(refs.by), dependsOn: within(record.dependsOn), shape: within(record.shape) };
};

const coverageOf = function coverageOf(context: GovlabContext): readonly CoverageView[] {
    return context
        .checkGaps()
        .collections.map((collection) => ({
            collection: collection.collection,
            questions: collection.questions.map((question) => ({
                answered: question.answered,
                declaredAbsent: question.declaredAbsent,
                question: question.question,
            })),
            records: collection.records,
        }));
};

export const resolutionOf = function resolutionOf(context: GovlabContext, resolve: Resolver): ResolutionView {
    const records = context.checkedRecords();
    const collections = new Set(records.map((record) => record.collection));
    const untyped = untypedResolvers(resolve);
    const refs: CheckRefs = {
        by: (raw) => (isTyped(raw, collections) ? resolve.target(raw) : { label: raw, ref: null }),
        within: (collection, raw) =>
            isTyped(raw, collections)
                ? resolve.target(raw)
                : (untyped.get(collection)?.(raw) ?? { label: raw, ref: null }),
    };
    const answers: CheckView[] = [];
    const slots = new Map<string, number>();
    const byRecord: Record<string, RecordCheckEntryView> = {};
    for (const record of records) {
        const view = answersOf(record.facet);
        const key = JSON.stringify(view);
        const slot = slots.get(key) ?? answers.push(view) - 1;
        slots.set(key, slot);
        byRecord[recordRefOf(record.collection, record.id)] = entryOf(record, slot, refs);
    }
    return {
        answers,
        byRecord,
        coverage: coverageOf(context),
        defects: context.validateResolution().total,
        records: records.length,
    };
};
```
