# core/normalizers/reason.normalizer.ts

> 185 lines of code and 27 definitions.

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

Listed in [core/normalizers](https://banes-lab.com/api/source/context/core/normalizers.md), after [core/normalizers/lexicon.normalizer.ts](https://banes-lab.com/source/context/core/normalizers/lexicon.normalizer.ts.md) and before [core/normalizers/reason.surface.normalizer.ts](https://banes-lab.com/source/context/core/normalizers/reason.surface.normalizer.ts.md).

## Definitions

- `normalizeRecursion` (lexical_declaration, line 97)
- `stringListMap` (lexical_declaration, line 196)
- `normalizeMaps` (lexical_declaration, line 201, exported)
- `refused` (lexical_declaration, line 31, exported)
- `normalizeSubstrate` (lexical_declaration, line 174, exported)
- `aliased` (lexical_declaration, line 41, exported)
- `checked` (lexical_declaration, line 45, exported)
- `normalizeNode` (lexical_declaration, line 74, exported)
- `normalizeLens` (lexical_declaration, line 130, exported)
- `normalizeTransition` (lexical_declaration, line 106)
- `normalizeMathType` (lexical_declaration, line 53, exported)
- `normalizeAxis` (lexical_declaration, line 63, exported)
- `normalizeSubstrateNode` (lexical_declaration, line 88)
- `normalizeDimension` (lexical_declaration, line 121, exported)
- `normalizeLayer` (lexical_declaration, line 49, exported)
- `normalizeEdge` (lexical_declaration, line 117, exported)
- `normalizeMode` (lexical_declaration, line 144, exported)
- `normalizeRepresentation` (lexical_declaration, line 148, exported)
- `normalizeMathDomain` (lexical_declaration, line 152, exported)
- `normalizePatternType` (lexical_declaration, line 156, exported)
- `normalizeUniversalAxis` (lexical_declaration, line 170, exported)
- `normalizeStage` (lexical_declaration, line 102)
- `normalizeModel` (lexical_declaration, line 160, exported)
- `normalizeDerivationLoop` (lexical_declaration, line 184, exported)
- `base` (lexical_declaration, line 161, exported)
- `raw` (lexical_declaration, line 197)
- `foundations` (lexical_declaration, line 202, exported)

## Contained in

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

## Uses

- [core/loaders/lexicon.loader.ts](https://banes-lab.com/source/context/core/loaders/lexicon.loader.ts.md)
- [core/normalizers/field.normalizer.ts](https://banes-lab.com/source/context/core/normalizers/field.normalizer.ts.md)
- [core/predicates/record.predicate.ts](https://banes-lab.com/source/context/core/predicates/record.predicate.ts.md)
- [core/selectors/reason.selector.ts](https://banes-lab.com/source/context/core/selectors/reason.selector.ts.md)
- [core/validators/field.validator.ts](https://banes-lab.com/source/context/core/validators/field.validator.ts.md)

## Used by

- [core/loaders/reason.loader.ts](https://banes-lab.com/source/context/core/loaders/reason.loader.ts.md)

## Linked from

- [core/loaders](https://banes-lab.com/anatomy/context/folder-context-core-loaders.md)
- [core/normalizers](https://banes-lab.com/anatomy/context/folder-context-core-normalizers.md)
- [core/predicates](https://banes-lab.com/anatomy/context/folder-context-core-predicates.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 {
    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"]),
    };
};
```
