# tools/core/inspectors/entrypoint.inspector.ts

> 113 lines of code and 39 definitions.

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

Listed in [tools/core/inspectors](https://banes-lab.com/api/source/coordination/tools/core/inspectors.md), after [tools/core/inspectors/declaration.inspector.ts](https://banes-lab.com/source/coordination/tools/core/inspectors/declaration.inspector.ts.md) and before [tools/core/inspectors/fence.inspector.ts](https://banes-lab.com/source/coordination/tools/core/inspectors/fence.inspector.ts.md).

## Definitions

- `factsOf` (lexical_declaration, line 89)
- `carrierIn` (lexical_declaration, line 41)
- `branchingName` (lexical_declaration, line 55)
- `opened` (lexical_declaration, line 64)
- `closed` (lexical_declaration, line 76)
- `unpublishedBranchOperands` (lexical_declaration, line 113, exported)
- `scannedFacts` (lexical_declaration, line 99)
- `reportCarrier` (lexical_declaration, line 51)
- `DECLARE_CONST` (lexical_declaration, line 4)
- `BLOCK_CLOSE` (lexical_declaration, line 6)
- `BRANCH_MARKS` (lexical_declaration, line 8)
- `ScanState` (interface_declaration, line 10)
- `LineFacts` (interface_declaration, line 17)
- `Calls` (interface_declaration, line 24)
- `OUTSIDE` (lexical_declaration, line 30)
- `declaresCarrier` (lexical_declaration, line 32)
- `lead` (lexical_declaration, line 33)
- `next` (lexical_declaration, line 37)
- `at` (lexical_declaration, line 42)
- `inside` (lexical_declaration, line 46)
- `close` (lexical_declaration, line 47)
- `rest` (lexical_declaration, line 59)
- `stop` (lexical_declaration, line 60)
- `declared` (lexical_declaration, line 65)
- `opensReport` (lexical_declaration, line 66)
- `opensRun` (lexical_declaration, line 67)
- `delta` (lexical_declaration, line 77)
- `runDepth` (lexical_declaration, line 78)
- `reportDepth` (lexical_declaration, line 79)
- `closes` (lexical_declaration, line 80)
- `value` (lexical_declaration, line 90)
- `out` (lexical_declaration, line 100)
- `state` (lexical_declaration, line 101)
- `trimmed` (lexical_declaration, line 104)
- `lines` (lexical_declaration, line 118, exported)
- `facts` (lexical_declaration, line 119, exported)
- `branching` (lexical_declaration, line 121, exported)
- `published` (lexical_declaration, line 122, exported)
- `passed` (lexical_declaration, line 123, exported)

## Uses

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

## Used by

- [tools/rules/entrypoint.rule.ts](https://banes-lab.com/source/coordination/tools/rules/entrypoint.rule.ts.md)

## Source

```typescript
import { braceDelta, memberKey, memberValue } from "../analyzers/source.analyzer.ts";
import type { BranchOperand } from "../types/entrypoint.types.ts";

const DECLARE_CONST = "const ";

const BLOCK_CLOSE = "}";

const BRANCH_MARKS = ["?", "if (", "&&", "||"];

interface ScanState {
    readonly inRun: boolean;
    readonly inReport: boolean;
    readonly runDepth: number;
    readonly reportDepth: number;
}

interface LineFacts {
    readonly line: number;
    readonly branching: string | null;
    readonly passed: string | null;
    readonly published: readonly string[];
}

interface Calls {
    readonly carrier: string;
    readonly runCall: string;
    readonly reportCall: string;
}

const OUTSIDE: ScanState = { inReport: false, inRun: false, reportDepth: 0, runDepth: 0 };

const declaresCarrier = function declaresCarrier(trimmed: string, carrier: string): boolean {
    const lead = `${DECLARE_CONST}${carrier}`;
    if (!trimmed.startsWith(lead)) {
        return false;
    }
    const next = trimmed.charAt(lead.length);
    return next === " " || next === ":" || next === "=";
};

const carrierIn = function carrierIn(line: string, reportCall: string): string {
    const at = line.indexOf(`${reportCall}(`);
    if (at === -1) {
        return "";
    }
    const inside = line.slice(at + reportCall.length + 1);
    const close = inside.indexOf(")");
    return close === -1 ? "" : (inside.slice(0, close).split(",").at(-1) ?? "").trim();
};

const reportCarrier = function reportCarrier(lines: readonly string[], reportCall: string): string {
    return lines.map((line) => carrierIn(line, reportCall)).find((carrier) => carrier.length > 0) ?? "";
};

const branchingName = function branchingName(trimmed: string): string | null {
    if (!trimmed.startsWith(DECLARE_CONST) || !BRANCH_MARKS.some((mark) => trimmed.includes(mark))) {
        return null;
    }
    const rest = trimmed.slice(DECLARE_CONST.length);
    const stop = rest.indexOf(" ");
    return stop <= 0 ? null : rest.slice(0, stop);
};

const opened = function opened(state: ScanState, trimmed: string, calls: Calls): ScanState {
    const declared = calls.carrier.length > 0 && declaresCarrier(trimmed, calls.carrier);
    const opensReport = declared || trimmed.includes(`${calls.reportCall}(`);
    const opensRun = trimmed.includes(`${calls.runCall}(`);
    return {
        inReport: state.inReport || opensReport,
        inRun: state.inRun || opensRun,
        reportDepth: opensReport ? 0 : state.reportDepth,
        runDepth: opensRun ? 0 : state.runDepth,
    };
};

const closed = function closed(state: ScanState, trimmed: string): ScanState {
    const delta = braceDelta(trimmed);
    const runDepth = state.runDepth + (state.inRun ? delta : 0);
    const reportDepth = state.reportDepth + (state.inReport ? delta : 0);
    const closes = trimmed.startsWith(BLOCK_CLOSE);
    return {
        inReport: state.inReport && !(reportDepth <= 0 && closes),
        inRun: state.inRun && !(runDepth <= 0 && closes),
        reportDepth,
        runDepth,
    };
};

const factsOf = function factsOf(state: ScanState, trimmed: string, line: number): LineFacts {
    const value = memberValue(trimmed);
    return {
        branching: branchingName(trimmed),
        line,
        passed: state.inRun && value.length > 0 ? value : null,
        published: state.inReport ? [memberKey(trimmed), value].filter((word) => word.length > 0) : [],
    };
};

const scannedFacts = function scannedFacts(lines: readonly string[], calls: Calls): LineFacts[] {
    const out: LineFacts[] = [];
    let state = OUTSIDE;

    for (const [index, line] of lines.entries()) {
        const trimmed = line.trim();
        state = opened(state, trimmed, calls);
        out.push(factsOf(state, trimmed, index + 1));
        state = closed(state, trimmed);
    }

    return out;
};

export const unpublishedBranchOperands = function unpublishedBranchOperands(
    source: string,
    runCall: string,
    reportCall: string,
): BranchOperand[] {
    const lines = source.split("\n");
    const facts = scannedFacts(lines, { carrier: reportCarrier(lines, reportCall), reportCall, runCall });

    const branching = new Set(facts.flatMap((fact) => (fact.branching === null ? [] : [fact.branching])));
    const published = new Set(facts.flatMap((fact) => fact.published));
    const passed = new Map(
        facts
            .flatMap((fact): [string, number][] => (fact.passed === null ? [] : [[fact.passed, fact.line]]))
            .toReversed(),
    );

    return [...passed]
        .filter(([name]) => branching.has(name) && !published.has(name))
        .toSorted((left, right) => left[1] - right[1])
        .map(([name, line]) => ({ line, name }));
};
```
