formatStored

tcmts.cli.fmt.formatStored · #vddki7fm · term · runs on the server

uses node:path

Reformat stored definitions: each component is rendered as it's stored (identifiers as written), formatted, analyzed again, and its new text kept only where the hash is the same. Returns what changed.

import type { Codebase } from "#codebase/tcmts/cli/codebase";
import { formatText } from "#codebase/tcmts/cli/fmt";
import { saltOf } from "#codebase/tcmts/core/analyze";
import { moduleFile, render } from "#codebase/tcmts/loader";
import fs from "node:fs";
import path from "node:path";

export function formatStored(
  cb: Codebase,
  hashes: string[],
): { formatted: string[]; unchanged: number; skipped: string[] } {
  const src = cb.source();
  const comps = new Set(
    hashes.map((h) => src.get(h)?.componentHash).filter((c): c is string => !!c),
  );
  const out = { formatted: [] as string[], unchanged: 0, skipped: [] as string[] };
  for (const c of comps) {
    const members = src.members(c);
    if (members.every((m) => m.kind === "type" && !m.sourceText)) continue;
    const rendered = render(members, src, cb.lay, { style: "internal", preserveText: true });
    const file = path.join(cb.lay.cacheDir, `_fmt_${moduleFile(c, src)}`);
    const formatted = formatText(cb, rendered.text, file);
    if (formatted === undefined || formatted === rendered.text) {
      out.unchanged += members.length;
      continue;
    }
    fs.writeFileSync(file, formatted);
    try {
      const byName = new Map([...rendered.memberNames].map(([h, n]) => [n, src.get(h)!]));
      const a = cb.analyzeProject(
        [file],
        (_f, name) => {
          const r = byName.get(name);
          return r && saltOf(r.ir);
        },
        [7016],
        cb.recheckOptions(members[0]?.checked),
      );
      for (const m of members) {
        const d = a.defs.find((x) => x.nameHint === rendered.memberNames.get(m.hash));
        if (!d || d.hash !== m.hash) {
          out.skipped.push(m.hash);
          continue;
        }
        if (d.sourceText === m.sourceText) {
          out.unchanged++;
          continue;
        }
        // (on this branch, a change in its history like any)
        cb.store.setText({ ...d, doc: m.doc, docRefs: m.docRefs }, "fmt");
        out.formatted.push(m.hash);
      }
    } finally {
      fs.rmSync(file, { force: true });
    }
  }
  return out;
}

uses

used by