tools/core/validators/entrypoint.validator.ts

tools/core/validators/entrypoint.validator.ts is a file in Coordination Surface. 94 lines of code and 33 definitions.

import type { Mutation, RequestedOperation } from "../types/entrypoint.types.ts";
import { codeMask, matchesAt, spacesFrom, wordFrom } from "../analyzers/source.analyzer.ts";

const FLAG_LEAD = "--";

const READ = "readFileSync";

const WRITE = "writeFileSync";

const COMPARISONS = ["!==", "===", "!=", "=="];

interface Event {
    readonly kind: "read" | "write";
    readonly target: string;
    readonly index: number;
    readonly line: number;
}

export const unsuppliedOperands = function unsuppliedOperands(requested: readonly RequestedOperation[]): string[] {
    return requested.filter((entry) => entry.requested && !entry.supplied).map((entry) => entry.refusal);
};

export const writesNothing = function writesNothing(
    argv: readonly string[],
    flag: string,
    selfRehearsing: readonly string[],
): boolean {
    return argv.includes(flag) && !selfRehearsing.some((form) => argv.includes(form));
};

const flagOf = function flagOf(token: string): string {
    const equals = token.indexOf("=");
    return equals === -1 ? token : token.slice(0, equals);
};

export const unknownArguments = function unknownArguments(argv: readonly string[], known: readonly string[]): string[] {
    const flags = argv
        .filter((token) => token.startsWith(FLAG_LEAD) && token.length > FLAG_LEAD.length)
        .map(flagOf)
        .filter((flag) => !known.includes(flag));
    return [...new Set(flags)];
};

export const unshareableOperations = function unshareableOperations(
    requested: readonly string[],
    exclusive: readonly string[],
): string[] {
    const held = requested.filter((flag) => exclusive.includes(flag));
    return held.length > 0 && requested.length > 1 ? held : [];
};

const argumentAt = function argumentAt(source: string, after: number): string | null {
    const open = spacesFrom(source, after);
    if (source.charAt(open) !== "(") {
        return null;
    }
    const argument = wordFrom(source, spacesFrom(source, open + 1));
    return argument.length === 0 ? null : argument;
};

const eventAt = function eventAt(source: string, index: number, line: number): Event | null {
    const read = matchesAt(source, index, READ);
    if (!read && !matchesAt(source, index, WRITE)) {
        return null;
    }
    const target = argumentAt(source, index + (read ? READ : WRITE).length);
    return target === null ? null : { index, kind: read ? "read" : "write", line, target };
};

const events = function events(source: string): Event[] {
    const mask = codeMask(source);
    const out: Event[] = [];
    let line = 1;

    for (let index = 0; index < source.length; index += 1) {
        const event = mask[index] === true ? eventAt(source, index, line) : null;
        if (event !== null) {
            out.push(event);
        }
        line += source.charAt(index) === "\n" ? 1 : 0;
    }

    return out;
};

const comparedBetween = function comparedBetween(source: string, from: number, to: number): boolean {
    return COMPARISONS.some((operator) => {
        const at = source.indexOf(operator, from);
        return at !== -1 && at + operator.length <= to;
    });
};

const witnessedWrite = function witnessedWrite(source: string, priors: readonly Event[], write: Event): boolean {
    const last = priors.at(-1);
    return priors.length >= 2 && last !== undefined && comparedBetween(source, last.index, write.index);
};

export const unwitnessedWrites = function unwitnessedWrites(source: string): Mutation[] {
    const ordered = events(source);

    return ordered
        .filter((event) => event.kind === "write")
        .flatMap((write) => {
            const priors = ordered.filter(
                (candidate) =>
                    candidate.kind === "read" && candidate.target === write.target && candidate.index < write.index,
            );
            const witnessed = witnessedWrite(source, priors, write);
            return priors.length === 0 || witnessed
                ? []
                : [{ line: write.line, reads: priors.length, target: write.target, witnessed }];
        });
};