tools/core/entrypoints/segment.entrypoint.ts

tools/core/entrypoints/segment.entrypoint.ts is a file in Coordination Surface. 155 lines of code and 36 definitions.

import type { Document, Edit, Finding, Hit, RenameMap, Report, SegmentPattern } from "../types/segment.types.ts";
import {
    applyEdits,
    editsFromFieldPrefixes,
    editsFromFieldValues,
    editsFromInlinePrefixes,
    editsFromInlines,
} from "../transformers/segment.transformer.ts";
import { projectRoot, surfacePrefix } from "../../../config/surface.config.ts";
import { readSource, toPosix, walk } from "../iterators/file.iterator.ts";
import { rehearsalLine, segmentCounts, segmentSummary } from "../strings/segment.strings.ts";
import { toEditRecords, toHitRecords, verdictOf, writeReport } from "../reporters/segment.reporter.ts";
import { NO_FIX_FLAG } from "../constants/path.constants.ts";
import { REFERENCE_FIELDS } from "../matchers/reference.matcher.ts";
import { isStringMap } from "../predicates/schema.predicate.ts";
import { loadTaxonomy } from "../resolvers/taxonomy.resolver.ts";
import { matchAll } from "../matchers/segment.matcher.ts";
import { readDocument } from "../readers/document.reader.ts";
import { readJson } from "../readers/json.reader.ts";
import { resolve } from "node:path";
import { writeFileSync } from "node:fs";

const REPO_ROOT = projectRoot();

export const RESTATES: readonly string[] = [
    "mutation_preview_first",
    "healing_is_default_in_every_entrypoint",
    "pattern_references_verified_after_rename",
];

const PATTERNS: SegmentPattern[] = [
    { id: "record-cross-reference", predicates: [{ keyEquals: "see", kind: "field" }] },
    { id: "record-source-pointer", predicates: [{ keyEquals: "source", kind: "field", valueStartsWith: "local:" }] },
    { id: "import-directive", predicates: [{ inlineKind: "import-path" }] },
    {
        id: "record-header",
        predicates: [
            { depthEquals: 3, kind: "heading" },
            { keyEquals: "type", kind: "field" },
        ],
    },
];

interface Args {
    readonly scan: string | null;
    readonly renameMap: string | null;
    readonly apply: boolean;
    readonly patternId: string | null;
}

interface Scanned {
    readonly hits: readonly Hit[];
    readonly edits: readonly Edit[];
    readonly extension: string;
}

const valueAfter = function valueAfter(argv: readonly string[], flag: string): string | null {
    const at = argv.lastIndexOf(flag);
    return at === -1 ? null : (argv[at + 1] ?? null);
};

const parseArgs = function parseArgs(argv: readonly string[]): Args {
    return {
        apply: !argv.includes(NO_FIX_FLAG),
        patternId: valueAfter(argv, "--pattern"),
        renameMap: valueAfter(argv, "--rename"),
        scan: valueAfter(argv, "--scan"),
    };
};

const renameEdits = function renameEdits(document: Document, map: RenameMap): Edit[] {
    return [
        ...editsFromInlines(document, map, ["link-target", "inline-code", "import-path"]),
        ...REFERENCE_FIELDS.flatMap((key) => editsFromFieldValues(document, key, map)),
        ...editsFromFieldPrefixes(document, REFERENCE_FIELDS, map),
        ...editsFromInlinePrefixes(document, map, ["link-target", "inline-code"]),
    ];
};

const scanFile = function scanFile(file: string, patterns: readonly SegmentPattern[], map: RenameMap | null): Scanned {
    const relPath = toPosix(REPO_ROOT, file);
    const dot = relPath.lastIndexOf(".");
    const document = readDocument(relPath, readSource(file));
    return {
        edits: map === null ? [] : renameEdits(document, map),
        extension: dot === -1 ? "(none)" : relPath.slice(dot),
        hits: matchAll(document, patterns),
    };
};

const applyByPath = function applyByPath(edits: readonly Edit[]): Edit[] {
    const byPath = Map.groupBy(edits, (edit) => edit.path);
    return [...byPath].flatMap(([relPath, fileEdits]) => {
        const absolute = resolve(REPO_ROOT, relPath);
        const result = applyEdits(readSource(absolute), fileEdits);
        if (result.rejected.length === 0) {
            writeFileSync(absolute, result.text, "utf8");
        }
        return [...result.rejected];
    });
};

const overlapFinding = function overlapFinding(bad: Edit): Finding {
    return {
        actual: bad.reason,
        expected: null,
        healed: false,
        line: 0,
        locus: `bytes ${bad.start}..${bad.end}`,
        path: bad.path,
        remediation: {
            action: "split",
            decide: "two rename-map entries resolve to overlapping spans in this file — narrow one key so the spans are disjoint, then re-run",
            deterministic: false,
            from: bad.reason,
            target: bad.path,
            to: null,
        },
        rule: "segment/editOverlap",
        stack: [
            { check: "applyEdits", resolved: "right-to-left" },
            { check: "boundary", resolved: `edit end ${bad.end} crossed a prior edit start` },
        ],
    };
};

const renameMapOf = function renameMapOf(mapPath: string | null): RenameMap | null {
    return mapPath === null
        ? null
        : readJson(readSource(resolve(REPO_ROOT, mapPath)), isStringMap, mapPath, "RenameMap");
};

const extensionCounts = function extensionCounts(scanned: readonly Scanned[]): Record<string, number> {
    const counts: Record<string, number> = {};
    for (const { extension } of scanned) {
        counts[extension] = (counts[extension] ?? 0) + 1;
    }
    return counts;
};

const main = function main(): void {
    const args = parseArgs(process.argv.slice(2));
    const root = resolve(REPO_ROOT, args.scan ?? surfacePrefix());
    const files = walk({ extensions: [".md", ".ts"], ignored: loadTaxonomy().ignored, root });
    const patterns = args.patternId === null ? PATTERNS : PATTERNS.filter((pattern) => pattern.id === args.patternId);
    const map = renameMapOf(args.renameMap);

    const scanned = files.map((file) => scanFile(file, patterns, map));
    const hits = scanned.flatMap((scan) => scan.hits);
    const edits = scanned.flatMap((scan) => scan.edits);
    const rehearsal = map !== null && !args.apply;
    const rejected = map !== null && args.apply ? applyByPath(edits) : [];
    const findings = rejected.map(overlapFinding);

    const report: Report = {
        coverage: { filesByExtension: extensionCounts(scanned), roots: [toPosix(REPO_ROOT, root) || "."] },
        edits: toEditRecords(edits),
        findings,
        hits: toHitRecords(hits),
        rejected: toEditRecords(rejected),
        scanned: files.length,
        tool: "segment",
        verdict: verdictOf(findings, rejected),
    };

    const target = writeReport(REPO_ROOT, "segment", report);
    const counts = segmentCounts(report.scanned, report.hits.length, report.edits.length, report.rejected.length);
    const rehearsed = rehearsal ? rehearsalLine(NO_FIX_FLAG) : "";

    process.stdout.write(segmentSummary(report.verdict.toUpperCase(), counts, toPosix(REPO_ROOT, target), rehearsed));

    process.exit(report.verdict === "pass" ? 0 : 1);
};

main();