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

> 84 lines of code and 22 definitions.

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

## Definitions

- `unmarkedReaders` (lexical_declaration, line 93, exported)
- `markedReaders` (lexical_declaration, line 19, exported)
- `withReader` (lexical_declaration, line 37)
- `runMark` (lexical_declaration, line 59, exported)
- `MarkRequest` (interface_declaration, line 7, exported)
- `MarkOutcome` (interface_declaration, line 14, exported)
- `rest` (lexical_declaration, line 25, exported)
- `value` (lexical_declaration, line 26, exported)
- `joined` (lexical_declaration, line 43)
- `at` (lexical_declaration, line 44, exported)
- `tail` (lexical_declaration, line 50)
- `width` (lexical_declaration, line 51)
- `source` (lexical_declaration, line 60, exported)
- `span` (lexical_declaration, line 61, exported)
- `lines` (lexical_declaration, line 71, exported)
- `marker` (lexical_declaration, line 72, exported)
- `healRequested` (lexical_declaration, line 84, exported)
- `authorOf` (lexical_declaration, line 88, exported)
- `cut` (lexical_declaration, line 89, exported)
- `readers` (lexical_declaration, line 99, exported)
- `named` (lexical_declaration, line 100, exported)
- `carriesLedger` (lexical_declaration, line 105, exported)

## Uses

- [tools/core/strings/mark.strings.ts](https://banes-lab.com/source/coordination/tools/core/strings/mark.strings.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 { AT_FIELD, READ_FIELD, TO_FIELD } from "../formatters/board.formatter.ts";

import { alreadyMarked, itemNotFound, marked, notAddressed } from "../strings/mark.strings.ts";
import { readFileSync, writeFileSync } from "node:fs";
import { itemSpans } from "../resolvers/sweep.resolver.ts";

export interface MarkRequest {
    readonly target: string;
    readonly absolute: string;
    readonly item: string;
    readonly agent: string;
}

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

export const markedReaders = function markedReaders(marker: string): string[] {
    const at = marker.indexOf(READ_FIELD);
    if (at === -1) {
        return [];
    }

    const rest = marker.slice(at + READ_FIELD.length);
    let value = "";
    for (const character of rest) {
        if (character === " ") {
            break;
        }
        value += character;
    }

    return value.length === 0 ? [] : value.split(",");
};

const withReader = function withReader(marker: string, agent: string): string {
    const readers = markedReaders(marker);
    if (readers.includes(agent)) {
        return marker;
    }

    const joined = [...readers, agent].join(",");
    const at = marker.indexOf(READ_FIELD);

    if (at === -1) {
        return `${marker} ${READ_FIELD}${joined}`;
    }

    const tail = marker.slice(at + READ_FIELD.length);
    let width = 0;
    while (width < tail.length && tail.charAt(width) !== " ") {
        width += 1;
    }

    return `${marker.slice(0, at)}${READ_FIELD}${joined}${tail.slice(width)}`;
};

export const runMark = function runMark(request: MarkRequest): MarkOutcome {
    const source = readFileSync(request.absolute, "utf8");
    const span = itemSpans(source).find((entry) => entry.key === request.item);

    if (span === undefined) {
        return { code: 2, message: itemNotFound(request.item, request.target) };
    }

    if (span.to.length > 0 && !span.to.includes(request.agent)) {
        return { code: 2, message: notAddressed(request.item, request.agent) };
    }

    const lines = source.split("\n");
    const marker = lines[span.from] ?? "";

    if (markedReaders(marker).includes(request.agent)) {
        return { code: 0, message: alreadyMarked(request.agent, request.item) };
    }

    lines[span.from] = withReader(marker, request.agent);
    writeFileSync(request.absolute, lines.join("\n"), "utf8");

    return { code: 0, message: marked(request.agent, request.item) };
};

export const healRequested = function healRequested(argv: readonly string[], flag: string): boolean {
    return !argv.includes(flag);
};

export const authorOf = function authorOf(item: string): string {
    const cut = item.indexOf("-");
    return cut <= 0 ? item : item.slice(0, cut);
};

export const unmarkedReaders = function unmarkedReaders(
    marker: string,
    addressed: readonly string[],
    active: readonly string[],
    author = "",
): string[] {
    const readers = markedReaders(marker);
    const named = addressed.length === 0 ? active : addressed;

    return named.filter((letter) => letter !== author && active.includes(letter) && !readers.includes(letter));
};

export const carriesLedger = function carriesLedger(marker: string): boolean {
    return marker.includes(READ_FIELD) || marker.includes(TO_FIELD) || marker.includes(AT_FIELD);
};
```
