tools/core/readers/invocation.reader.ts

tools/core/readers/invocation.reader.ts is a file in Coordination Surface. 84 lines of code and 25 definitions.

import { bodyFileMissing, bodyInline, fixedTarget, forgedBoundary, stdinEmpty } from "../strings/board.strings.ts";
import { existsSync, readFileSync } from "node:fs";
import type { Outcome } from "../types/invocation.types.ts";
import { forgedBoundaries } from "../predicates/marker.predicate.ts";
import { projectRoot } from "../../../config/surface.config.ts";
import { resolve } from "node:path";

const FLAG_LEAD = "--";

const STDIN_OPERAND = "-";

const TRAILING = new Set([" ", "\t", "\n", "\r"]);

export const finish: (message: string, code: number) => never = function finish(message, code) {
    process.stdout.write(message);
    process.exit(code);
};

export const argumentValue = function argumentValue(flag: string): string | null {
    const at = process.argv.indexOf(flag);
    const value = at === -1 ? undefined : process.argv[at + 1];
    return value === undefined || value.length === 0 || value.startsWith(FLAG_LEAD) ? null : value;
};

const operandsAfter = function operandsAfter(flag: string): string[] {
    const at = process.argv.indexOf(flag);
    if (at === -1) {
        return [];
    }

    const rest = process.argv.slice(at + 1);
    const end = rest.findIndex((token) => token.startsWith(FLAG_LEAD));
    return end === -1 ? rest : rest.slice(0, end);
};

export const joinedValue = function joinedValue(flag: string): string | null {
    const held = operandsAfter(flag);
    return held.length === 0 ? null : held.join(" ");
};

export const refuseFixedTarget = function refuseFixedTarget(form: string, surface: string): void {
    if (process.argv.includes("--file")) {
        finish(fixedTarget(form, surface), 2);
    }
};

const refuseForgedBoundary = function refuseForgedBoundary(body: string, flag: string): void {
    const forged = forgedBoundaries(body);
    if (forged.length === 0) {
        return;
    }

    const named = forged.map((entry) => `line ${String(entry.line)}: ${entry.text}`).join("; ");
    finish(forgedBoundary(flag, forged.length, named), 2);
};

const withoutTrailing = function withoutTrailing(raw: string): string {
    let end = raw.length;
    while (end > 0 && TRAILING.has(raw.charAt(end - 1))) {
        end -= 1;
    }
    return raw.slice(0, end);
};

const inlineOperand = function inlineOperand(inlineFlag: string, fileFlag: string): string | null {
    const inline = joinedValue(inlineFlag);
    if (inline === null) {
        return null;
    }

    if (inline !== STDIN_OPERAND) {
        finish(bodyInline(inlineFlag, fileFlag, STDIN_OPERAND, operandsAfter(inlineFlag).length), 2);
    }

    const piped = readFileSync(0, "utf8");
    if (piped.trim().length === 0) {
        process.stdout.write(stdinEmpty(inlineFlag, STDIN_OPERAND));
        return null;
    }
    refuseForgedBoundary(piped, `${inlineFlag} ${STDIN_OPERAND}`);
    return piped;
};

export const textOperand = function textOperand(inlineFlag: string, fileFlag: string): string | null {
    const path = argumentValue(fileFlag);
    if (path === null) {
        return inlineOperand(inlineFlag, fileFlag);
    }

    const from = resolve(projectRoot(), path);
    if (!existsSync(from)) {
        finish(bodyFileMissing(fileFlag, path), 2);
    }

    const body = withoutTrailing(readFileSync(from, "utf8"));
    refuseForgedBoundary(body, fileFlag);
    return body;
};

export const bodyOr = function bodyOr(refusal: string, act: (body: string) => Outcome): Outcome {
    const body = textOperand("--body", "--body-file");
    return body === null ? { code: 2, message: refusal } : act(body);
};