core/converters/reason.reference.converter.ts
core/converters/reason.reference.converter.ts is a file in Bane's Lab Build Scripts. 141 lines of code and 29 definitions.
import type { DerivationLoopView, ReasonNodeView } from "@banes-lab/web/types/loop.types.js";
import { REASON_FACE, REFERENCED_BY_RELATION, STAGE_FACE } from "@govlab/constants";
import type { ReferenceIndex, ReferenceRecord } from "@banes-lab/web/types/reference.types.js";
import { loopSummary, nodeSummary, substrateSummary } from "@banes-lab/web/strings/catalog.strings";
import { nameOf, recordOf, titleOf } from "#core/converters/reference.field.converter";
import type { EdgeRef } from "@banes-lab/web/types/link.types.js";
import type { ReasonView } from "@banes-lab/web/types/reason.types.js";
import { refOf } from "#core/resolvers/ontology.resolver";
const HYPHEN = "-";
const MODEL_KIND = "model";
const STAGES_RELATION = "stages";
const STAGE_KIND = "stage";
interface Anchored {
readonly anchor: string;
readonly id: string;
}
const kindOfAnchor = function kindOfAnchor(anchor: string, id: string): string {
return anchor.slice(0, anchor.length - id.length - HYPHEN.length);
};
const reasonCollections = function reasonCollections(reason: ReasonView): readonly (readonly Anchored[])[] {
return [
reason.axes,
reason.nodes,
reason.substrate.nodes,
reason.dimensions,
reason.invariants,
reason.layers,
reason.lenses,
reason.mathDomains,
reason.mathTypes,
reason.models,
reason.modes,
reason.patternTypes,
reason.representations,
reason.techniques,
reason.testSurfaces,
reason.universalAxes,
[reason.derivationLoop],
];
};
const inboundOf = function inboundOf(records: ReadonlyMap<string, ReferenceRecord>): ReadonlyMap<string, EdgeRef[]> {
const inbound = new Map<string, EdgeRef[]>();
for (const [ref, record] of records) {
const targets = record.relations.flatMap((relation) => relation.edges.map((edge) => edge.ref));
for (const target of targets) {
if (target !== null && records.has(target) && target !== ref) {
inbound.set(target, [...(inbound.get(target) ?? []), { label: record.name, ref }]);
}
}
}
return inbound;
};
const describedNode = function describedNode(record: ReferenceRecord, node: ReasonNodeView): ReferenceRecord {
return node.concept === null
? record
: {
...record,
summary: record.summary ?? nodeSummary(node.concept.label, node.axis.label, node.mathType.label),
};
};
const describedLoop = function describedLoop(record: ReferenceRecord, loop: DerivationLoopView): ReferenceRecord {
const stages = loop.stages.map((stage) => ({ label: titleOf(stage.id), ref: refOf(STAGE_FACE, stage.id) }));
return {
...record,
relations: [...record.relations, { edges: stages, relation: STAGES_RELATION }],
summary:
record.summary ??
loopSummary(
record.name,
stages.map((stage) => stage.label),
),
};
};
const describedRecords = function describedRecords(
reason: ReasonView,
built: ReadonlyMap<string, ReferenceRecord>,
): ReadonlyMap<string, ReferenceRecord> {
const nodes = new Map(reason.nodes.map((node) => [refOf(REASON_FACE, node.anchor), node]));
const loopRef = refOf(REASON_FACE, reason.derivationLoop.anchor);
return new Map(
[...built].map(([ref, record]) => {
const node = nodes.get(ref);
if (node !== undefined) {
return [ref, describedNode(record, node)];
}
return [ref, ref === loopRef ? describedLoop(record, reason.derivationLoop) : record];
}),
);
};
const describeSubstrate = function describeSubstrate(
reason: ReasonView,
records: ReadonlyMap<string, ReferenceRecord>,
inbound: ReadonlyMap<string, EdgeRef[]>,
): ReadonlyMap<string, string> {
return new Map(
reason.substrate.nodes.map((node) => {
const ref = refOf(REASON_FACE, node.anchor);
const models = (inbound.get(ref) ?? [])
.filter((edge) => edge.ref !== null && records.get(edge.ref)?.kind === MODEL_KIND)
.map((edge) => edge.label);
return [ref, substrateSummary(node.layer.label, node.mathType.label, models)];
}),
);
};
export const reasonReferencesOf = function reasonReferencesOf(reason: ReasonView): ReferenceIndex {
const built = new Map(
reasonCollections(reason)
.flat()
.map((view) => [
refOf(REASON_FACE, view.anchor),
recordOf(view, kindOfAnchor(view.anchor, view.id), nameOf(view, view.id)),
]),
);
const outbound = describedRecords(reason, built);
const inbound = inboundOf(outbound);
const substrate = describeSubstrate(reason, outbound, inbound);
const index: Record<string, ReferenceRecord> = {};
for (const [ref, record] of outbound) {
const referencedBy = inbound.get(ref) ?? [];
const summary = record.summary ?? substrate.get(ref) ?? null;
index[ref] =
referencedBy.length === 0
? { ...record, summary }
: {
...record,
relations: [...record.relations, { edges: referencedBy, relation: REFERENCED_BY_RELATION }],
summary,
};
}
return index;
};
export const stageReferencesOf = function stageReferencesOf(reason: ReasonView): ReferenceIndex {
const index: Record<string, ReferenceRecord> = {};
const questions = new Map(reason.axes.map((axis) => [refOf(REASON_FACE, axis.anchor), axis.question]));
for (const stage of reason.derivationLoop.stages) {
const ref = refOf(STAGE_FACE, stage.id);
const summary = stage.axis.ref === null ? null : (questions.get(stage.axis.ref) ?? null);
index[ref] = { ...recordOf(stage, STAGE_KIND, titleOf(stage.id)), summary };
}
return index;
};