# tools/core/runners/fixture.runner.ts

> 136 lines of code and 30 definitions.

Tree: Coordination tree
Language: typescript
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-runners-fixture-runner-ts
Source text: https://banes-lab.com/assets/sources/source.169ba03edbf324ebc999c24f8dd8c1bd21927be7ac2a4b037011b44cb52ea327.generated.txt

## Definitions

- `quoted` (lexical_declaration, line 88)
- `close` (lexical_declaration, line 51, exported)
- `accepts` (lexical_declaration, line 45, exported)
- `fixtureEntry` (lexical_declaration, line 104, exported)
- `runFixture` (lexical_declaration, line 122, exported)
- `parseSamples` (lexical_declaration, line 43, exported)
- `CLOSER` (lexical_declaration, line 12)
- `FIRES_LEAD` (lexical_declaration, line 14)
- `ACCEPTS_LEAD` (lexical_declaration, line 16)
- `PAIR_SEPARATOR` (lexical_declaration, line 18)
- `FixtureSample` (interface_declaration, line 20, exported)
- `ParsedSamples` (interface_declaration, line 25, exported)
- `FixtureRequest` (interface_declaration, line 30, exported)
- `FixtureOutcome` (interface_declaration, line 38, exported)
- `fires` (lexical_declaration, line 44, exported)
- `openPath` (lexical_declaration, line 47, exported)
- `openLines` (lexical_declaration, line 48, exported)
- `into` (lexical_declaration, line 49, exported)
- `sample` (lexical_declaration, line 55, exported)
- `out` (lexical_declaration, line 89)
- `{ fires }` (lexical_declaration, line 105, exported)
- `{ accepts }` (lexical_declaration, line 106, exported)
- `separator` (lexical_declaration, line 127, exported)
- `samples` (lexical_declaration, line 132, exported)
- `before` (lexical_declaration, line 137, exported)
- `lines` (lexical_declaration, line 142, exported)
- `at` (lexical_declaration, line 143, exported)
- `index` (lexical_declaration, line 144, exported)
- `[rule, kind]` (lexical_declaration, line 156, exported)
- `written` (lexical_declaration, line 157, exported)

## Uses

- [tools/core/strings/fixture.strings.ts](https://banes-lab.com/source/coordination/tools/core/strings/fixture.strings.ts.md)

## Used by

- [tools/core/analyzers/board.analyzer.ts](https://banes-lab.com/source/coordination/tools/core/analyzers/board.analyzer.ts.md)
- [tools/rules/governance.rule.ts](https://banes-lab.com/source/coordination/tools/rules/governance.rule.ts.md)

## Source

```typescript
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 = "/";

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

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

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

export 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")) {
        if (line.startsWith(FIRES_LEAD)) {
            close();
            into = "fires";
            openPath = line.slice(FIRES_LEAD.length).trim();
            openLines = [];
            continue;
        }
        if (line.startsWith(ACCEPTS_LEAD)) {
            close();
            into = "accepts";
            openPath = line.slice(ACCEPTS_LEAD.length).trim();
            openLines = [];
            continue;
        }
        if (into === "") {
            continue;
        }
        openLines.push(line);
    }

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

const quoted = function quoted(text: string): string {
    let out = "";
    for (const character of text) {
        if (character === "\\") {
            out += String.raw`\\`;
        } else if (character === '"') {
            out += String.raw`\"`;
        } else if (character === "\n") {
            out += String.raw`\n`;
        } else {
            out += character;
        }
    }
    return `"${out}"`;
};

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");
};

export const runFixture = function runFixture(request: FixtureRequest): FixtureOutcome {
    if (!existsSync(request.absolute)) {
        return { code: 2, message: fixtureModuleMissing(request.target) };
    }

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

    const samples = parseSamples(request.body);
    if (samples.fires === null || samples.accepts === null) {
        return { code: 2, message: halfMissing(samples.fires === null ? "fired" : "accepted") };
    }

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

    const lines = before.split("\n");
    let at = -1;
    for (let index = lines.length - 1; index >= 0; index -= 1) {
        if ((lines[index] ?? "").trim() !== CLOSER) {
            continue;
        }
        at = index;
        break;
    }

    if (at === -1) {
        return { code: 2, message: setMissing(request.target) };
    }

    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) };
};
```
