tools/core/predicates/source.predicate.ts

tools/core/predicates/source.predicate.ts is a file in Coordination Surface. 112 lines of code and 31 definitions.

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

const QUOTES = new Set(['"', "'", "`"]);

const ESCAPE = "\\";

const DECLARATION_TAILS = [":", "(", ",", " }", "\n"];

const FILESYSTEM_IMPORT_TAIL = `"node:fs";`;

export const filesystemImports = function filesystemImports(source: string): string[] {
    return source
        .split("\n")
        .map((line) => line.trim())
        .filter((line) => line.startsWith("import ") && line.endsWith(FILESYSTEM_IMPORT_TAIL));
};

type Mode = "block" | "code" | "line" | "quote";

interface Scan {
    readonly mode: Mode;
    readonly quote: string;
    readonly escaped: boolean;
}

interface Step {
    readonly next: Scan;
    readonly width: number;
    readonly code: boolean;
}

const CODE: Scan = { escaped: false, mode: "code", quote: "" };

const OPENERS = new Map<string, Mode>([
    ["//", "line"],
    ["/*", "block"],
]);

const BLOCK_CLOSE = "*/";

const skipped = function skipped(next: Scan, width: number): Step {
    return { code: false, next, width };
};

const commentStep = function commentStep(scan: Scan, pair: string): Step | null {
    if (scan.mode === "line") {
        return skipped(pair.startsWith("\n") ? CODE : scan, 1);
    }
    if (scan.mode === "block") {
        return pair === BLOCK_CLOSE ? skipped(CODE, 2) : skipped(scan, 1);
    }
    return null;
};

const quoteStep = function quoteStep(scan: Scan, char: string): Step | null {
    if (scan.escaped) {
        return skipped({ ...scan, escaped: false }, 1);
    }
    if (char === ESCAPE) {
        return skipped({ ...scan, escaped: true }, 1);
    }
    if (scan.mode === "quote") {
        return skipped(char === scan.quote ? CODE : scan, 1);
    }
    return null;
};

const codeStep = function codeStep(char: string, pair: string): Step {
    const opener = OPENERS.get(pair);
    if (opener !== undefined) {
        return skipped({ escaped: false, mode: opener, quote: "" }, 2);
    }
    if (QUOTES.has(char)) {
        return skipped({ escaped: false, mode: "quote", quote: char }, 1);
    }
    return { code: true, next: CODE, width: 1 };
};

const stepOf = function stepOf(scan: Scan, source: string, index: number): Step {
    const char = source.charAt(index);
    const pair = source.slice(index, index + 2);
    return commentStep(scan, pair) ?? quoteStep(scan, char) ?? codeStep(char, pair);
};

const scanCode = function scanCode(source: string, at: (index: number, char: string) => boolean): boolean {
    let scan = CODE;
    let index = 0;

    while (index < source.length) {
        const step = stepOf(scan, source, index);
        if (step.code && at(index, source.charAt(index))) {
            return true;
        }
        scan = step.next;
        index += step.width;
    }

    return false;
};

const isIdentifierChar = function isIdentifierChar(char: string): boolean {
    return isWordCharacter(char) || char === "$";
};

const memberCallOpensHere = function memberCallOpensHere(source: string, index: number): boolean {
    let cursor = index - 1;
    while (cursor >= 0 && isIdentifierChar(source.charAt(cursor))) {
        cursor -= 1;
    }
    return cursor !== index - 1 && source.charAt(cursor) === ".";
};

const memberCallFollows = function memberCallFollows(source: string, index: number): boolean {
    let cursor = index + 1;
    while (cursor < source.length && isIdentifierChar(source.charAt(cursor))) {
        cursor += 1;
    }
    return cursor !== index + 1 && source.charAt(cursor) === "(";
};

export const containsInCode = function containsInCode(source: string, needle: string): boolean {
    return scanCode(source, (index) => source.startsWith(needle, index));
};

export const reachesRegexLiteral = function reachesRegexLiteral(source: string): boolean {
    return scanCode(source, (index, char) => {
        const next = source.charAt(index + 1);

        if (char === "(" && next === "/" && source.charAt(index + 2) !== "/") {
            return memberCallOpensHere(source, index);
        }

        return char === "/" && next === "." && memberCallFollows(source, index + 1);
    });
};

export const declaresProperty = function declaresProperty(source: string, name: string): boolean {
    return DECLARATION_TAILS.some((tail) => containsInCode(source, `${name}${tail}`));
};