# tools/core/analyzers/archive.analyzer.ts

> 59 lines of code and 21 definitions.

Tree: Coordination tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-analyzers-archive-analyzer-ts
Source text: https://banes-lab.com/source/coordination/tools/core/analyzers/archive.analyzer.ts.txt

Listed in [tools/core/analyzers](https://banes-lab.com/api/source/coordination/tools/core/analyzers.md), before [tools/core/analyzers/binding.analyzer.ts](https://banes-lab.com/source/coordination/tools/core/analyzers/binding.analyzer.ts.md).

## Definitions

- `filedNotice` (lexical_declaration, line 33, exported)
- `ENTRY_MARKER` (lexical_declaration, line 4, exported)
- `ENTRY_LEADS` (lexical_declaration, line 6, exported)
- `Promotion` (interface_declaration, line 8)
- `declaresLead` (lexical_declaration, line 13, exported)
- `filedHeadings` (lexical_declaration, line 17, exported)
- `out` (lexical_declaration, line 18, exported)
- `heading` (lexical_declaration, line 24, exported)
- `filed` (lexical_declaration, line 34, exported)
- `classes` (lexical_declaration, line 39, exported)
- `entryEnd` (lexical_declaration, line 43, exported)
- `next` (lexical_declaration, line 44, exported)
- `promoteLeads` (lexical_declaration, line 48, exported)
- `lines` (lexical_declaration, line 49, exported)
- `promoted` (lexical_declaration, line 50, exported)
- `held` (lexical_declaration, line 51, exported)
- `at` (lexical_declaration, line 54, exported)
- `clauseEnd` (lexical_declaration, line 65, exported)
- `end` (lexical_declaration, line 66, exported)
- `starts` (lexical_declaration, line 67, exported)
- `blank` (lexical_declaration, line 71, exported)

## Uses

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

## Used by

- [tools/core/runners/archive.runner.ts](https://banes-lab.com/source/coordination/tools/core/runners/archive.runner.ts.md)

## Source

```typescript
import { classesFiled } from "../strings/archive.strings.ts";
import { isClassHeading } from "../predicates/marker.predicate.ts";

export const ENTRY_MARKER = "### ";

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

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

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

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 filedNotice = function filedNotice(source: string): string {
    const filed = filedHeadings(source);
    if (filed.length === 0) {
        return "";
    }

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

export 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;
};

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