# core/validators/vocabulary.validator.ts

> 34 lines of code and 7 definitions.

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

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

## Definitions

- `crossValidateFaces` (lexical_declaration, line 21, exported)
- `misspelledForcesOf` (lexical_declaration, line 10)
- `byName` (lexical_declaration, line 6)
- `tokens` (lexical_declaration, line 11)
- `canonical` (lexical_declaration, line 16)
- `archIds` (lexical_declaration, line 22, exported)
- `forces` (lexical_declaration, line 23, exported)

## Contained in

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

## Uses

- [core/classifiers/vocabulary.classifier.ts](https://banes-lab.com/source/context/core/classifiers/vocabulary.classifier.ts.md)

## Used by

- [core/factories/context.factory.ts](https://banes-lab.com/source/context/core/factories/context.factory.ts.md)

## Linked from

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

## Source

```typescript
import type { CrossFaceIssues, MisspelledForce } from "#types/validation.types";
import type { Faces } from "#types/context.types";
import { canonicalForceOf } from "#core/normalizers/vocabulary.normalizer";
import { classifyForce } from "#core/classifiers/vocabulary.classifier";

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

const misspelledForcesOf = function misspelledForcesOf(faces: Faces): MisspelledForce[] {
    const tokens = [
        ...faces.algo.all().flatMap((contract) => contract.force.map((token) => ({ record: contract.id, token }))),
        ...faces.arch.all().flatMap((principle) => principle.scope.map((token) => ({ record: principle.id, token }))),
    ];
    return tokens.flatMap(({ record, token }) => {
        const canonical = canonicalForceOf(token);
        return canonical === null ? [] : [{ canonical, record, token }];
    });
};

export const crossValidateFaces = function crossValidateFaces(faces: Faces): CrossFaceIssues {
    const archIds = new Set(faces.arch.ids());
    const forces = new Set(faces.algo.all().flatMap((contract) => contract.force));
    return {
        danglingPrincipleRefs: [...faces.algo.all(), ...faces.reason.techniques()]
            .filter(
                (record) =>
                    typeof record.principleRef === "string" &&
                    record.principleRef.length > 0 &&
                    !archIds.has(record.principleRef),
            )
            .map((record) => record.id)
            .toSorted(byName),
        misspelledForces: misspelledForcesOf(faces),
        unknownForces: [...forces].filter((force) => classifyForce(force) === "unknown").toSorted(byName),
    };
};
```
