core/analyzers/field.analyzer.ts

core/analyzers/field.analyzer.ts is a file in GovLab Patterns. 43 lines of code and 14 definitions.

import { analysisNode, findingNode } from "#core/factories/node.factory";
import type { FieldOutput } from "#types/record.types";
import type { RepresentationRuntime } from "#types/representation.types";
import { runtimeFor } from "#core/selectors/representation.selector";

interface BoundRuntime {
    representation: string;
    runtime: RepresentationRuntime;
}

const bind = function bind(field: string, representations: readonly string[]): BoundRuntime[] {
    return representations.flatMap((representation) => {
        const factory = runtimeFor(representation);
        return factory ? [{ representation, runtime: factory(field) }] : [];
    });
};

export class FieldAnalyzer {
    private readonly field: string;
    private readonly runtimes: readonly BoundRuntime[];

    public constructor(field: string, representations: readonly string[]) {
        this.field = field;
        this.runtimes = bind(field, representations);
    }

    public update(chunk: readonly unknown[]): void {
        for (const { runtime } of this.runtimes) {
            runtime.update(chunk);
        }
    }

    public produce(): FieldOutput {
        const fragments = this.runtimes.map((bound) => this.emit(bound));
        return {
            findings: fragments.flatMap((fragment) => fragment.findings),
            nodes: fragments.flatMap((fragment) => fragment.nodes),
        };
    }

    private emit(bound: BoundRuntime): FieldOutput {
        const produced = bound.runtime.findings();
        if (produced.length === 0) {
            return { findings: [], nodes: [] };
        }
        const analysis = analysisNode(this.field, bound.representation);
        const findingNodes = produced.map((finding) => findingNode(analysis.id, finding.name, finding.coordinate));
        return { findings: produced, nodes: [analysis, ...findingNodes] };
    }
}