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

> 208 lines of code and 45 definitions.

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

## Definitions

- `filedNotice` (lexical_declaration, line 100, exported)
- `filedHeadings` (lexical_declaration, line 66, exported)
- `namesAClass` (lexical_declaration, line 82, exported)
- `runEntry` (lexical_declaration, line 110, exported)
- `runExtend` (lexical_declaration, line 214, exported)
- `runRepair` (lexical_declaration, line 165, exported)
- `classHeadings` (lexical_declaration, line 96, exported)
- `runClosure` (lexical_declaration, line 248, exported)
- `ClosureRequest` (interface_declaration, line 27, exported)
- `ClosureOutcome` (interface_declaration, line 36, exported)
- `JUDGEMENT_KIND` (lexical_declaration, line 43, exported)
- `ENTRY_MARKER` (lexical_declaration, line 45)
- `ENTRY_LEADS` (lexical_declaration, line 47)
- `declaresLead` (lexical_declaration, line 49)
- `EntryRequest` (interface_declaration, line 53, exported)
- `EntryOutcome` (interface_declaration, line 59, exported)
- `HEADING_WORD` (lexical_declaration, line 64)
- `heading` (lexical_declaration, line 73, exported)
- `filed` (lexical_declaration, line 101, exported)
- `classes` (lexical_declaration, line 106, exported)
- `missing` (lexical_declaration, line 121, exported)
- `entryEnd` (lexical_declaration, line 138)
- `next` (lexical_declaration, line 139)
- `Promotion` (interface_declaration, line 143)
- `promoteLeads` (lexical_declaration, line 148)
- `held` (lexical_declaration, line 151)
- `promotions` (lexical_declaration, line 179, exported)
- `promoted` (lexical_declaration, line 180, exported)
- `out` (lexical_declaration, line 181, exported)
- `ExtendRequest` (interface_declaration, line 197, exported)
- `clauseEnd` (lexical_declaration, line 204)
- `end` (lexical_declaration, line 205, exported)
- `starts` (lexical_declaration, line 206)
- `blank` (lexical_declaration, line 210)
- `before` (lexical_declaration, line 223, exported)
- `lines` (lexical_declaration, line 224, exported)
- `opens` (lexical_declaration, line 225, exported)
- `at` (lexical_declaration, line 231, exported)
- `written` (lexical_declaration, line 236, exported)
- `witness` (lexical_declaration, line 238, exported)
- `carried` (lexical_declaration, line 249, exported)
- `source` (lexical_declaration, line 250, exported)
- `index` (lexical_declaration, line 251, exported)
- `text` (lexical_declaration, line 252, exported)
- `kind` (lexical_declaration, line 253, exported)

## Uses

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

## Used by

- [tools/core/entrypoints/board.entrypoint.ts](https://banes-lab.com/source/coordination/tools/core/entrypoints/board.entrypoint.ts.md)

## Source

```typescript
import { authorOf, closureText } from "../generators/board.generator.ts";

import {
    classesFiled,
    clauseExtended,
    clauseMissing,
    entryAdded,
    entryExists,
    entryNotFound,
    extendContended,
    extendMissingHistory,
    extendNotFound,
    historyContended,
    historyMissing,
    leadUndeclared,
    leadsInPlace,
    leadsMissing,
    leadsRepaired,
    repairContended,
    repairMissingHistory,
} from "../strings/archive.strings.ts";
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { appendSection } from "../formatters/text.formatter.ts";
import { closureRefusal } from "../validators/archive.validator.ts";
import { itemKindOf } from "../formatters/board.formatter.ts";

export interface ClosureRequest {
    readonly absolute: string;
    readonly archive: string;
    readonly index: string;
    readonly closes: string;
    readonly agent: string | null;
    readonly ref: string | null;
}

export interface ClosureOutcome {
    readonly refusal: string | null;
    readonly author: string;
    readonly label: string;
    readonly acknowledged: boolean;
}

export const JUDGEMENT_KIND = "judgement";

const ENTRY_MARKER = "### ";

const ENTRY_LEADS = ["POPULATION:", "BOUNDARY:"];

const declaresLead = function declaresLead(body: string, lead: string): boolean {
    return body.split("\n").some((line) => line.startsWith(lead));
};

export interface EntryRequest {
    readonly archive: string;
    readonly heading: string;
    readonly body: string;
}

export interface EntryOutcome {
    readonly message: string;
    readonly code: number;
}

const HEADING_WORD = new Set("abcdefghijklmnopqrstuvwxyz0123456789-");

export const filedHeadings = function filedHeadings(source: string): string[] {
    const out: string[] = [];

    for (const line of source.split("\n")) {
        if (!line.startsWith(ENTRY_MARKER)) {
            continue;
        }
        const heading = line.slice(ENTRY_MARKER.length).trim();
        if (heading.length > 0) {
            out.push(heading);
        }
    }

    return out;
};

export const namesAClass = function namesAClass(heading: string): boolean {
    if (heading.length === 0) {
        return false;
    }

    for (const character of heading) {
        if (!HEADING_WORD.has(character)) {
            return false;
        }
    }

    return true;
};

export const classHeadings = function classHeadings(source: string): string[] {
    return filedHeadings(source).filter((heading) => namesAClass(heading));
};

export const filedNotice = function filedNotice(source: string): string {
    const filed = filedHeadings(source);
    if (filed.length === 0) {
        return "";
    }

    const classes = filed.filter((heading) => namesAClass(heading));
    return classesFiled(classes, filed.length - classes.length);
};

export const runEntry = function runEntry(request: EntryRequest): EntryOutcome {
    if (!existsSync(request.archive)) {
        return { code: 2, message: historyMissing(request.archive) };
    }

    const before = readFileSync(request.archive, "utf8");

    if (before.includes(`${ENTRY_MARKER}${request.heading}`)) {
        return { code: 2, message: `${entryExists(request.heading, request.archive)}${filedNotice(before)}` };
    }

    const missing = ENTRY_LEADS.filter((lead) => !declaresLead(request.body, lead));
    if (missing.length > 0) {
        return { code: 2, message: leadsMissing(missing) };
    }

    const written = appendSection(before, `${ENTRY_MARKER}${request.heading}`, request.body);

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

    writeFileSync(request.archive, written, "utf8");

    return { code: 0, message: `${entryAdded(request.heading, request.archive)}${filedNotice(before)}` };
};

const entryEnd = function entryEnd(lines: readonly string[], opens: number): number {
    const next = lines.findIndex((line, index) => index > opens && line.startsWith(ENTRY_MARKER));
    return next === -1 ? lines.length : next;
};

interface Promotion {
    readonly lines: string[];
    readonly promoted: string[];
}

const promoteLeads = function promoteLeads(line: string): Promotion {
    const lines: string[] = [];
    const promoted: string[] = [];
    let held = line;

    for (const lead of ENTRY_LEADS) {
        const at = held.indexOf(lead);
        if (at > 0) {
            lines.push(held.slice(0, at).trimEnd());
            held = held.slice(at);
            promoted.push(lead);
        }
    }

    return { lines: [...lines, held], promoted };
};

export const runRepair = function runRepair(request: { archive: string; heading: string }): EntryOutcome {
    if (!existsSync(request.archive)) {
        return { code: 2, message: repairMissingHistory(request.archive) };
    }

    const before = readFileSync(request.archive, "utf8");
    const lines = before.split("\n");
    const opens = lines.findIndex((line) => line.startsWith(`${ENTRY_MARKER}${request.heading}`));

    if (opens === -1) {
        return { code: 2, message: `${entryNotFound(request.heading, request.archive)}${filedNotice(before)}` };
    }

    const end = entryEnd(lines, opens);
    const promotions = lines.slice(opens + 1, end).map(promoteLeads);
    const promoted = promotions.flatMap((promotion) => promotion.promoted);
    const out = [...lines.slice(0, opens + 1), ...promotions.flatMap((promotion) => promotion.lines), ...lines.slice(end)];

    if (promoted.length === 0) {
        return { code: 0, message: leadsInPlace(request.heading) };
    }

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

    writeFileSync(request.archive, out.join("\n"), "utf8");

    return { code: 0, message: leadsRepaired(promoted, request.heading) };
};

export interface ExtendRequest {
    readonly archive: string;
    readonly heading: string;
    readonly lead: string;
    readonly body: string;
}

const clauseEnd = function clauseEnd(lines: readonly string[], opens: number, lead: string): number {
    const end = entryEnd(lines, opens);
    const starts = lines.findIndex((line, index) => index > opens && index < end && line.startsWith(lead));
    if (starts === -1) {
        return -1;
    }
    const blank = lines.findIndex((line, index) => index > starts && index < end && line.trim().length === 0);
    return (blank === -1 ? end : blank) - 1;
};

export const runExtend = function runExtend(request: ExtendRequest): EntryOutcome {
    if (!existsSync(request.archive)) {
        return { code: 2, message: extendMissingHistory(request.archive) };
    }

    if (!ENTRY_LEADS.includes(request.lead)) {
        return { code: 2, message: leadUndeclared(request.lead, ENTRY_LEADS) };
    }

    const before = readFileSync(request.archive, "utf8");
    const lines = before.split("\n");
    const opens = lines.findIndex((line) => line.startsWith(`${ENTRY_MARKER}${request.heading}`));

    if (opens === -1) {
        return { code: 2, message: `${extendNotFound(request.heading, request.archive)}${filedNotice(before)}` };
    }

    const at = clauseEnd(lines, opens, request.lead);
    if (at === -1) {
        return { code: 2, message: clauseMissing(request.heading, request.lead) };
    }

    const written = [...lines.slice(0, at + 1), request.body, ...lines.slice(at + 1)].join("\n");

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

    writeFileSync(request.archive, written, "utf8");

    return { code: 0, message: clauseExtended(request.lead, request.heading, request.archive) };
};

export const runClosure = function runClosure(request: ClosureRequest): ClosureOutcome {
    const carried = existsSync(request.archive) ? readFileSync(request.archive, "utf8") : "";
    const source = readFileSync(request.absolute, "utf8");
    const index = existsSync(request.index) ? readFileSync(request.index, "utf8") : "";
    const text = closureText(request.closes, request.ref ?? "", source, request.agent ?? "", index);
    const kind = itemKindOf(source, request.closes);

    return {
        acknowledged: kind === JUDGEMENT_KIND,
        author: authorOf(request.closes),
        label: `handled by ${request.agent ?? ""}`,
        refusal: closureRefusal(request.closes, request.ref, request.agent, text, carried, kind),
    };
};
```
