# core/validators/grammar.reference.validator.ts

> 59 lines of code and 9 definitions.

Tree: GovLab Context
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/context#file-context-core-validators-grammar-reference-validator-ts
Source text: https://banes-lab.com/source/context/core/validators/grammar.reference.validator.ts.txt

Listed in [core/validators](https://banes-lab.com/api/source/context/core/validators.md), after [core/validators/field.validator.ts](https://banes-lab.com/source/context/core/validators/field.validator.ts.md) and before [core/validators/grammar.validator.ts](https://banes-lab.com/source/context/core/validators/grammar.validator.ts.md).

## Definitions

- `unresolvedRef` (lexical_declaration, line 53)
- `unresolvedPagGroundsOf` (lexical_declaration, line 24, exported)
- `doctypeModelAxisOf` (lexical_declaration, line 57, exported)
- `groundedConstructs` (lexical_declaration, line 10)
- `ungroundedPagConstructsOf` (lexical_declaration, line 35, exported)
- `byName` (lexical_declaration, line 6)
- `kindMembers` (lexical_declaration, line 27, exported)
- `models` (lexical_declaration, line 58, exported)
- `axes` (lexical_declaration, line 59, exported)

## Contained in

- [core/validators](https://banes-lab.com/anatomy/context/folder-context-core-validators.md)

## Uses

- [core/resolvers/reference.resolver.ts](https://banes-lab.com/source/context/core/resolvers/reference.resolver.ts.md)
- [core/selectors/grammar.selector.ts](https://banes-lab.com/source/context/core/selectors/grammar.selector.ts.md)

## Used by

- [core/validators/ontology.validator.ts](https://banes-lab.com/source/context/core/validators/ontology.validator.ts.md)

## Linked from

- [core/resolvers](https://banes-lab.com/anatomy/context/folder-context-core-resolvers.md)
- [core/selectors](https://banes-lab.com/anatomy/context/folder-context-core-selectors.md)
- [core/validators](https://banes-lab.com/anatomy/context/folder-context-core-validators.md)

## Source

```typescript
import { PAG_GROUNDING_EXEMPT, PAG_PRODUCTION_EXEMPT } from "#configuration/constants/reference.constants";
import type { PagGroundingFaces } from "#types/reference.types";
import { kindRefResolves } from "#core/resolvers/reference.resolver";
import { roleIdOf } from "#core/selectors/grammar.selector";

const byName = function byName(a: string, b: string): number {
    return a.localeCompare(b);
};

const groundedConstructs = function groundedConstructs(
    faces: PagGroundingFaces,
): { id: string; grounds: readonly string[] | undefined }[] {
    return [
        ...faces.pag
            .keywords()
            .flatMap((keyword) =>
                keyword.roles.map((role) => ({ grounds: role.grounds, id: roleIdOf(keyword, role) })),
            ),
        ...faces.pag.productions().map((production) => ({ grounds: production.grounds, id: production.lhs })),
        ...faces.pag.documentTypes().map((doctype) => ({ grounds: doctype.grounds, id: doctype.type })),
    ];
};

export const unresolvedPagGroundsOf = function unresolvedPagGroundsOf(
    faces: PagGroundingFaces,
): { from: string; target: string }[] {
    const kindMembers = faces.reason.kindMembers();
    return groundedConstructs(faces).flatMap((construct) =>
        (construct.grounds ?? [])
            .filter((target) => !kindRefResolves(kindMembers, target))
            .map((target) => ({ from: construct.id, target })),
    );
};

export const ungroundedPagConstructsOf = function ungroundedPagConstructsOf(faces: PagGroundingFaces): string[] {
    return [
        ...faces.pag
            .keywords()
            .flatMap((keyword) =>
                keyword.roles
                    .filter((role) => !PAG_GROUNDING_EXEMPT.has(role.category) && (role.grounds ?? []).length === 0)
                    .map((role) => roleIdOf(keyword, role)),
            ),
        ...faces.pag
            .productions()
            .filter(
                (production) => !PAG_PRODUCTION_EXEMPT.has(production.lhs) && (production.grounds ?? []).length === 0,
            )
            .map((production) => production.lhs),
    ].toSorted(byName);
};

const unresolvedRef = function unresolvedRef(value: string | undefined, set: Set<string>): boolean {
    return typeof value !== "string" || value === "" || !set.has(value);
};

export const doctypeModelAxisOf = function doctypeModelAxisOf(faces: PagGroundingFaces): string[] {
    const models = new Set(faces.reason.models().map((model) => model.id));
    const axes = new Set(faces.reason.axes().map((axis) => axis.id));
    return faces.pag
        .documentTypes()
        .filter((doctype) => unresolvedRef(doctype.model, models) || unresolvedRef(doctype.axis, axes))
        .map((doctype) => doctype.type)
        .toSorted(byName);
};
```
