core/normalizers/reason.normalizer.ts

core/normalizers/reason.normalizer.ts is a file in GovLab Context. 185 lines of code and 27 definitions.

import type {
    Axis,
    CycleRecursion,
    DerivationLoop,
    LoopStage,
    LoopTransition,
    MathType,
    ReasonEdge,
    ReasonLayer,
    ReasonNode,
    Substrate,
    SubstrateNode,
} from "#types/reason.node.types";
import type {
    Dimension,
    Lens,
    MathDomain,
    Mode,
    Model,
    PatternType,
    ReasonMaps,
    Representation,
    UniversalAxis,
} from "#types/reason.concept.types";
import { asString, asStringArray, optionalString, optionalStrings } from "#core/normalizers/field.normalizer";
import { REASON_SUBJECT } from "#configuration/constants/reason.constants";
import { isObject } from "#core/predicates/record.predicate";
import { refuseRecord } from "#core/validators/field.validator";
import { schemaOf } from "#core/selectors/reason.selector";

export const refused = function refused<T>(
    kind: string,
    normalize: (raw: Record<string, unknown>) => T,
): (raw: Record<string, unknown>) => T {
    return (raw) => {
        refuseRecord(REASON_SUBJECT, kind, schemaOf(kind), raw);
        return normalize(raw);
    };
};

export const aliased = function aliased<T extends { aliases?: string[] }>(
    kind: string,
    normalize: (raw: Record<string, unknown>) => T,
): (raw: Record<string, unknown>) => T {
    const checked = refused(kind, normalize);
    return (raw) => ({ ...checked(raw), ...optionalStrings(raw, "aliases") });
};

export const normalizeLayer = function normalizeLayer(raw: Record<string, unknown>): ReasonLayer {
    return { id: asString(raw["id"]), label: asString(raw["label"]), question: asString(raw["question"]) };
};

export const normalizeMathType = function normalizeMathType(raw: Record<string, unknown>): MathType {
    return {
        domains: asStringArray(raw["domains"]),
        id: asString(raw["id"]),
        predicateFamily: asString(raw["predicateFamily"]),
        question: asString(raw["question"]),
        yieldsShape: asString(raw["yieldsShape"]),
    };
};

export const normalizeAxis = function normalizeAxis(raw: Record<string, unknown>): Axis {
    return {
        id: asString(raw["id"]),
        layer: asString(raw["layer"]),
        mandatory: asString(raw["mandatory"]),
        primaryMathType: asString(raw["primaryMathType"]),
        question: asString(raw["question"]),
        selectable: raw["selectable"] === true,
    };
};

export const normalizeNode = function normalizeNode(raw: Record<string, unknown>): ReasonNode {
    return {
        axis: asString(raw["axis"]),
        id: asString(raw["id"]),
        mathType: asString(raw["mathType"]),
        name: asString(raw["name"]),
        ...optionalString(raw, "concept"),
        ...optionalString(raw, "question"),
        ...optionalString(raw, "answerShape"),
        ...optionalString(raw, "decisionTest"),
        ...optionalString(raw, "role"),
    };
};

const normalizeSubstrateNode = function normalizeSubstrateNode(raw: Record<string, unknown>): SubstrateNode {
    return {
        id: asString(raw["id"]),
        layer: asString(raw["layer"]),
        mathType: asString(raw["mathType"]),
        name: asString(raw["name"]),
    };
};

const normalizeRecursion = function normalizeRecursion(value: unknown): CycleRecursion {
    const raw = isObject(value) ? value : {};
    return { from: asString(raw["from"]), to: asString(raw["to"]) };
};

const normalizeStage = function normalizeStage(raw: Record<string, unknown>): LoopStage {
    return { axis: asString(raw["axis"]), id: asString(raw["id"]) };
};

const normalizeTransition = function normalizeTransition(raw: Record<string, unknown>): LoopTransition {
    return {
        from: asString(raw["from"]),
        kind: asString(raw["kind"]),
        to: asString(raw["to"]),
        ...optionalString(raw, "gate"),
        ...optionalString(raw, "onFail"),
        ...optionalString(raw, "onPass"),
    };
};

export const normalizeEdge = function normalizeEdge(raw: Record<string, unknown>): ReasonEdge {
    return { from: asString(raw["from"]), ...optionalString(raw, "to"), ...optionalString(raw, "label") };
};

export const normalizeDimension = function normalizeDimension(raw: Record<string, unknown>): Dimension {
    return {
        id: asString(raw["id"]),
        mathDomains: asStringArray(raw["mathDomains"]),
        mathNature: asString(raw["mathNature"]),
        question: asString(raw["question"]),
    };
};

export const normalizeLens = function normalizeLens(raw: Record<string, unknown>): Lens {
    return {
        id: asString(raw["id"]),
        mathDomains: asStringArray(raw["mathDomains"]),
        mathFields: asStringArray(raw["mathFields"]),
        nature: asString(raw["nature"]),
        question: asString(raw["question"]),
        universalAxis: asString(raw["universalAxis"]),
        ...optionalString(raw, "label"),
        ...optionalStrings(raw, "surfaces"),
        ...optionalStrings(raw, "detectedBy"),
    };
};

export const normalizeMode = function normalizeMode(raw: Record<string, unknown>): Mode {
    return { id: asString(raw["id"]), practice: asString(raw["practice"]), ...optionalString(raw, "question") };
};

export const normalizeRepresentation = function normalizeRepresentation(raw: Record<string, unknown>): Representation {
    return { expression: asString(raw["expression"]), id: asString(raw["id"]), ...optionalString(raw, "label") };
};

export const normalizeMathDomain = function normalizeMathDomain(raw: Record<string, unknown>): MathDomain {
    return { id: asString(raw["id"]), question: asString(raw["question"]), studies: asString(raw["studies"]) };
};

export const normalizePatternType = function normalizePatternType(raw: Record<string, unknown>): PatternType {
    return { id: asString(raw["id"]), viewpoint: asString(raw["viewpoint"]), ...optionalString(raw, "label") };
};

export const normalizeModel = function normalizeModel(raw: Record<string, unknown>): Model {
    const base: Model = {
        id: asString(raw["id"]),
        question: asString(raw["question"]),
        sequence: asStringArray(raw["sequence"]),
        stepKind: asString(raw["stepKind"]),
    };
    return isObject(raw["recursion"]) ? { ...base, recursion: normalizeRecursion(raw["recursion"]) } : base;
};

export const normalizeUniversalAxis = function normalizeUniversalAxis(raw: Record<string, unknown>): UniversalAxis {
    return { id: asString(raw["id"]), question: asString(raw["question"]), subsumes: asStringArray(raw["subsumes"]) };
};

export const normalizeSubstrate = function normalizeSubstrate(raw: Record<string, unknown>): Substrate {
    return {
        cycle: asStringArray(raw["cycle"]),
        nodes: (Array.isArray(raw["nodes"]) ? raw["nodes"] : [])
            .filter(isObject)
            .map(aliased("substrate-node", normalizeSubstrateNode)),
        recursion: normalizeRecursion(raw["recursion"]),
    };
};

export const normalizeDerivationLoop = function normalizeDerivationLoop(raw: Record<string, unknown>): DerivationLoop {
    return {
        id: asString(raw["id"]),
        stages: (Array.isArray(raw["stages"]) ? raw["stages"] : [])
            .filter(isObject)
            .map(refused("stage", normalizeStage)),
        transitions: (Array.isArray(raw["transitions"]) ? raw["transitions"] : [])
            .filter(isObject)
            .map(normalizeTransition),
    };
};

const stringListMap = function stringListMap(value: unknown): Record<string, string[]> {
    const raw = isObject(value) ? value : {};
    return Object.fromEntries(Object.keys(raw).map((key) => [key, asStringArray(raw[key])]));
};

export const normalizeMaps = function normalizeMaps(raw: Record<string, unknown>): ReasonMaps {
    const foundations = isObject(raw["foundations"]) ? raw["foundations"] : {};
    return {
        foundations: { layers: stringListMap(foundations["layers"]), sequence: asStringArray(foundations["sequence"]) },
        invariants: stringListMap(raw["invariants"]),
        patternOperations: asStringArray(raw["patternOperations"]),
    };
};