# tools/core/formatters/text.formatter.ts

> 55 lines of code and 19 definitions.

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

## Definitions

- `safeKey` (lexical_declaration, line 11, exported)
- `capped` (lexical_declaration, line 54)
- `isAlphanumeric` (lexical_declaration, line 7)
- `diffLines` (lexical_declaration, line 58, exported)
- `CONTEXT_CAP` (lexical_declaration, line 3)
- `KEY_FILLER` (lexical_declaration, line 5)
- `appendSection` (lexical_declaration, line 19, exported)
- `terminated` (lexical_declaration, line 20, exported)
- `counted` (lexical_declaration, line 24)
- `Surplus` (interface_declaration, line 32)
- `surplus` (lexical_declaration, line 37)
- `remaining` (lexical_declaration, line 42)
- `out` (lexical_declaration, line 43, exported)
- `spare` (lexical_declaration, line 45)
- `was` (lexical_declaration, line 59, exported)
- `now` (lexical_declaration, line 60, exported)
- `heldBefore` (lexical_declaration, line 61, exported)
- `added` (lexical_declaration, line 63, exported)
- `removed` (lexical_declaration, line 64, exported)

## Uses

- [tools/core/predicates/token.predicate.ts](https://banes-lab.com/source/coordination/tools/core/predicates/token.predicate.ts.md)

## Used by

- [tools/core/registries/claim.registry.ts](https://banes-lab.com/source/coordination/tools/core/registries/claim.registry.ts.md)
- [tools/core/registries/snapshot.registry.ts](https://banes-lab.com/source/coordination/tools/core/registries/snapshot.registry.ts.md)

## Source

```typescript
import { isWordCharacter } from "../predicates/token.predicate.ts";

const CONTEXT_CAP = 400;

const KEY_FILLER = "-";

const isAlphanumeric = function isAlphanumeric(char: string): boolean {
    return char !== "_" && isWordCharacter(char);
};

export const safeKey = function safeKey(text: string): string {
    let out = "";
    for (const char of text) {
        out += isAlphanumeric(char) ? char : KEY_FILLER;
    }
    return out;
};

export const appendSection = function appendSection(before: string, heading: string, body: string): string {
    const terminated = before.endsWith("\n") ? before : `${before}\n`;
    return `${terminated}\n${heading}\n\n${body}\n`;
};

const counted = function counted(lines: readonly string[]): Map<string, number> {
    const out = new Map<string, number>();
    for (const line of lines) {
        out.set(line, (out.get(line) ?? 0) + 1);
    }
    return out;
};

interface Surplus {
    readonly lines: readonly string[];
    readonly remaining: ReadonlyMap<string, number>;
}

const surplus = function surplus(
    lines: readonly string[],
    own: ReadonlyMap<string, number>,
    other: ReadonlyMap<string, number>,
): Surplus {
    const remaining = new Map(own);
    const out: string[] = [];
    for (const line of lines) {
        const spare = remaining.get(line) ?? 0;
        if (line.trim().length > 0 && (other.get(line) ?? 0) < spare) {
            remaining.set(line, spare - 1);
            out.push(line);
        }
    }
    return { lines: out, remaining };
};

const capped = function capped(mark: string): (line: string) => string {
    return (line: string): string => `${mark} ${line.trim().slice(0, CONTEXT_CAP)}`;
};

export const diffLines = function diffLines(before: string, after: string): string[] {
    const was = before.split("\n");
    const now = after.split("\n");
    const heldBefore = counted(was);

    const added = surplus(now, counted(now), heldBefore);
    const removed = surplus(was, heldBefore, added.remaining);

    return [...removed.lines.map(capped("-")), ...added.lines.map(capped("+"))];
};
```
