# core/factories/grammar.factory.ts

> 79 lines of code and 10 definitions.

Tree: GovLab Context
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/context#file-context-core-factories-grammar-factory-ts
Source text: https://banes-lab.com/source/context/core/factories/grammar.factory.ts.txt

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

## Definitions

- `assemble` (lexical_declaration, line 27)
- `buildIndexes` (lexical_declaration, line 18)
- `createPagGrammar` (lexical_declaration, line 58, exported)
- `template` (lexical_declaration, line 46)
- `audit` (lexical_declaration, line 59, exported)
- `checks` (lexical_declaration, line 60, exported)
- `data` (lexical_declaration, line 61, exported)
- `indexes` (lexical_declaration, line 62, exported)
- `PAG_FACE` (lexical_declaration, line 71, exported)
- `algo` (lexical_declaration, line 73, exported)

## Contained in

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

## Uses

- [configuration/strings/grammar.strings.ts](https://banes-lab.com/source/context/configuration/strings/grammar.strings.ts.md)
- [core/parsers/document.parser.ts](https://banes-lab.com/source/context/core/parsers/document.parser.ts.md)
- [core/resolvers/template.resolver.ts](https://banes-lab.com/source/context/core/resolvers/template.resolver.ts.md)
- [core/selectors/grammar.selector.ts](https://banes-lab.com/source/context/core/selectors/grammar.selector.ts.md)
- [core/validators/document.validator.ts](https://banes-lab.com/source/context/core/validators/document.validator.ts.md)
- [core/validators/grammar.validator.ts](https://banes-lab.com/source/context/core/validators/grammar.validator.ts.md)

## Linked from

- [configuration/strings](https://banes-lab.com/anatomy/context/folder-context-configuration-strings.md)
- [core/factories](https://banes-lab.com/anatomy/context/folder-context-core-factories.md)
- [core/parsers](https://banes-lab.com/anatomy/context/folder-context-core-parsers.md)
- [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 type { ContractResolver, GrammarIndexes, PagData, PagGrammar, PagGrammarOptions } from "#types/grammar.types";
import { categoriesOf, contextFor, hasRoleIn, keywordIdOf } from "#core/selectors/grammar.selector";
import { COLLECTIONS } from "#configuration/constants/ontology.constants";
import { CheckTable } from "#core/stores/check.store";
import { PAG_SUBJECT } from "#configuration/constants/grammar.constants";
import { ReadAudit } from "#core/observers/record.observer";
import { deepFreeze } from "#core/converters/base.converter";
import { defineOntologyFace } from "#core/registries/ontology.registry";
import { grammarIssuesOf } from "#core/validators/grammar.validator";
import { isAlgoGrammar } from "#core/guards/context.guard";
import { loadBundledData } from "#core/loaders/grammar.loader";
import { missingDependency } from "#configuration/strings/ontology.strings";
import { parse } from "#core/parsers/document.parser";
import { resolvePagTemplate } from "#core/resolvers/template.resolver";
import { unknownTemplateType } from "#configuration/strings/grammar.strings";
import { validate } from "#core/validators/document.validator";

const buildIndexes = function buildIndexes(data: PagData): GrammarIndexes {
    return {
        keywordById: new Map(data.keywords.map((record) => [keywordIdOf(record), record])),
        productionByLhs: new Map(data.productions.map((record) => [record.lhs, record])),
        templateByType: new Map(data.templates.map((record) => [record.type, record])),
        typeByName: new Map(data.documentTypes.map((record) => [record.type, record])),
    };
};

const assemble = function assemble(
    data: PagData,
    indexes: GrammarIndexes,
    resolver: ContractResolver,
): Omit<PagGrammar, "attributions" | "checkOf" | "unreadKeys"> {
    return {
        categories: () => categoriesOf(data),
        contextFor: (type) => contextFor(type, { data, indexes, resolver }),
        documentType: (type) => indexes.typeByName.get(type) ?? null,
        documentTypes: () => [...data.documentTypes],
        keyword: (id) => indexes.keywordById.get(id) ?? null,
        keywords: (category) =>
            typeof category === "string" && category.length > 0
                ? data.keywords.filter((record) => hasRoleIn(record, category))
                : [...data.keywords],
        parse: (text) => parse(text),
        production: (lhs) => indexes.productionByLhs.get(lhs) ?? null,
        productions: () => [...data.productions],
        resolvePagTemplate: (type, slots) => {
            const template = indexes.templateByType.get(type);
            return template
                ? resolvePagTemplate(template, slots)
                : { text: "", unresolved: [], violations: [unknownTemplateType(type)] };
        },
        template: (type) => indexes.templateByType.get(type) ?? null,
        templates: () => [...data.templates],
        validate: (text) => validate(text),
        validateOntology: () => grammarIssuesOf(data, indexes.typeByName),
    };
};

export const createPagGrammar = function createPagGrammar(options: PagGrammarOptions = {}): PagGrammar {
    const audit = new ReadAudit(COLLECTIONS.pag);
    const checks = new CheckTable();
    const data = deepFreeze(options.data ?? loadBundledData(audit, checks));
    const indexes = buildIndexes(data);
    return {
        ...assemble(data, indexes, options.resolver ?? {}),
        attributions: () => audit.attributions(),
        checkOf: (kind, id) => checks.checkOf(kind, id),
        unreadKeys: () => audit.unread(),
    };
};

export const PAG_FACE = defineOntologyFace<PagGrammar>({
    build: (_context, dependencies) => {
        const algo = dependencies[COLLECTIONS.algorithms];
        if (!isAlgoGrammar(algo)) {
            throw new Error(missingDependency(COLLECTIONS.pag, COLLECTIONS.algorithms));
        }
        return createPagGrammar({
            resolver: { contractsForType: () => algo.query({ domain: PAG_SUBJECT }).map((contract) => contract.id) },
        });
    },
    dependsOn: [COLLECTIONS.algorithms],
    name: COLLECTIONS.pag,
});
```
