core/factories/grammar.factory.ts
core/factories/grammar.factory.ts is a file in GovLab Context. 79 lines of code and 10 definitions.
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,
});