tools/core/runners/fixture.runner.ts

tools/core/runners/fixture.runner.ts is a file in Coordination Surface. 131 lines of code and 34 definitions.

import { existsSync, readFileSync, writeFileSync } from "node:fs";

import {
    fixtureAdded,
    fixtureContended,
    fixtureModuleMissing,
    halfMissing,
    notAPair,
    setMissing,
} from "../strings/fixture.strings.ts";

const CLOSER = "];";

const FIRES_LEAD = "FIRES ";

const ACCEPTS_LEAD = "ACCEPTS ";

const PAIR_SEPARATOR = "/";

const SAMPLE_LEADS: readonly (readonly ["accepts" | "fires", string])[] = [
    ["fires", FIRES_LEAD],
    ["accepts", ACCEPTS_LEAD],
];

const ESCAPES: ReadonlyMap<string, string> = new Map([
    ["\\", String.raw`\\`],
    ['"', String.raw`\"`],
    ["\n", String.raw`\n`],
]);

interface FixtureSample {
    readonly path: string;
    readonly text: string;
}

interface ParsedSamples {
    readonly fires: FixtureSample | null;
    readonly accepts: FixtureSample | null;
}

interface FixtureRequest {
    readonly target: string;
    readonly absolute: string;
    readonly pair: string;
    readonly body: string;
    readonly witness: string;
}

interface FixtureOutcome {
    readonly code: number;
    readonly message: string;
}

export const parseSamples = function parseSamples(body: string): ParsedSamples {
    let fires: FixtureSample | null = null;
    let accepts: FixtureSample | null = null;

    let openPath = "";
    let openLines: string[] = [];
    let into: "" | "accepts" | "fires" = "";

    const close = (): void => {
        if (into === "" || openPath.length === 0) {
            return;
        }
        const sample = { path: openPath, text: `${openLines.join("\n")}\n` };
        if (into === "fires") {
            fires = sample;
        } else {
            accepts = sample;
        }
    };

    for (const line of body.split("\n")) {
        const lead = SAMPLE_LEADS.find(([, prefix]) => line.startsWith(prefix));
        if (lead === undefined) {
            if (into !== "") {
                openLines.push(line);
            }
        } else {
            close();
            [into] = lead;
            openPath = line.slice(lead[1].length).trim();
            openLines = [];
        }
    }

    close();
    return { accepts, fires };
};

const quoted = function quoted(text: string): string {
    let escaped = "";
    for (const character of text) {
        escaped += ESCAPES.get(character) ?? character;
    }
    return `"${escaped}"`;
};

export const fixtureEntry = function fixtureEntry(rule: string, kind: string, samples: ParsedSamples): string {
    const { fires } = samples;
    const { accepts } = samples;

    return [
        "    {",
        `        rule: ${quoted(rule)},`,
        `        kind: ${quoted(kind)},`,
        "        fires: [",
        `            { path: ${quoted(fires?.path ?? "")}, text: ${quoted(fires?.text ?? "")} },`,
        "        ],",
        "        passes: [",
        `            { path: ${quoted(accepts?.path ?? "")}, text: ${quoted(accepts?.text ?? "")} },`,
        "        ],",
        "    },",
    ].join("\n");
};

const pairRefusal = function pairRefusal(request: FixtureRequest, samples: ParsedSamples): string | null {
    if (!existsSync(request.absolute)) {
        return fixtureModuleMissing(request.target);
    }

    const separator = request.pair.indexOf(PAIR_SEPARATOR);
    if (separator <= 0 || separator === request.pair.length - 1) {
        return notAPair(request.pair);
    }

    if (samples.fires === null || samples.accepts === null) {
        return halfMissing(samples.fires === null ? "fired" : "accepted");
    }

    return null;
};

export const runFixture = function runFixture(request: FixtureRequest): FixtureOutcome {
    const samples = parseSamples(request.body);
    const refusal = pairRefusal(request, samples);
    if (refusal !== null) {
        return { code: 2, message: refusal };
    }

    const before = readFileSync(request.absolute, "utf8");
    if (before !== request.witness) {
        return { code: 2, message: fixtureContended(request.target) };
    }

    const lines = before.split("\n");
    const at = lines.findLastIndex((line) => line.trim() === CLOSER);
    if (at === -1) {
        return { code: 2, message: setMissing(request.target) };
    }

    const separator = request.pair.indexOf(PAIR_SEPARATOR);
    const [rule, kind] = [request.pair.slice(0, separator), request.pair.slice(separator + 1)];
    const written = [...lines.slice(0, at), fixtureEntry(rule, kind, samples), ...lines.slice(at)].join("\n");
    writeFileSync(request.absolute, written, "utf8");

    return { code: 0, message: fixtureAdded(request.pair, request.target) };
};