tools/core/analyzers/binding.analyzer.ts

tools/core/analyzers/binding.analyzer.ts is a file in Coordination Surface. 52 lines of code and 15 definitions.

import type { Resolution, SlotUse } from "../types/binding.types.ts";
import { RESOLUTION_STATES } from "../constants/binding.constants.ts";

const SLOT_OPEN = "{";
const SLOT_CLOSE = "}";
const SLOT_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.";

const isSlotName = function isSlotName(name: string): boolean {
    if (name.length === 0) {
        return false;
    }
    for (const character of name) {
        if (!SLOT_CHARACTERS.includes(character)) {
            return false;
        }
    }
    return true;
};

const slotNamesOf = function slotNamesOf(line: string): string[] {
    return line
        .split(SLOT_OPEN)
        .slice(1)
        .flatMap((segment) => {
            const close = segment.indexOf(SLOT_CLOSE);
            const name = close === -1 ? "" : segment.slice(0, close);
            return isSlotName(name) ? [SLOT_OPEN + name + SLOT_CLOSE] : [];
        });
};

const earliestState = function earliestState(line: string): Resolution | undefined {
    const found = RESOLUTION_STATES.map((state) => ({ at: line.indexOf(state), state })).filter(({ at }) => at !== -1);
    return found.toSorted((left, right) => left.at - right.at)[0]?.state;
};

export const slotsIn = function slotsIn(source: string): SlotUse[] {
    return source.split("\n").flatMap((line, index) => slotNamesOf(line).map((name) => ({ line: index + 1, name })));
};

export const slotStates = function slotStates(source: string): Map<string, Resolution> {
    const out = new Map<string, Resolution>();
    for (const line of source.split("\n")) {
        const state = earliestState(line);
        if (state === undefined) {
            continue;
        }
        for (const use of slotsIn(line)) {
            if (!out.has(use.name)) {
                out.set(use.name, state);
            }
        }
    }
    return out;
};

const WILDCARD_SLOT = ".*}";

export const enumeratesVocabulary = function enumeratesVocabulary(line: string): boolean {
    return line.includes(WILDCARD_SLOT);
};