editFiles

tcmts.cli.main.editFiles · #uzaklkmy · term · runs on the server

uses node:path

tcm edit of files kept as written: each into a file of its own, named as it is (or file). A Markdown file's first line says where it goes back; another's is saved with --into.

import type { Codebase } from "#codebase/tcmts/cli/codebase";
import { fileContent, fileName, formatOf } from "#codebase/tcmts/cli/files";
import { dim } from "#codebase/tcmts/cli/style";
import { scratchShown, shellWord, shownPath, UsageError } from "#codebase/tcmts/cli/ui";
import fs from "node:fs";
import path from "node:path";

export function editFiles(
  cb: Codebase,
  targets: string[],
  file: string | undefined,
  force: boolean,
) {
  if (file && targets.length > 1)
    throw new UsageError("--file names one file: edit files one at a time");
  for (const t of targets) {
    const h = cb.lookupOne(t);
    const rec = cb.store.getDef(h)!;
    if (rec.kind !== "file")
      throw new UsageError(`${t} is code, the others files: edit them apart`);
    const name = cb.store.pathsOf(h)[0] ?? t;
    const ns = name.slice(0, Math.max(0, name.lastIndexOf(".")));
    const format = formatOf(rec);
    // as it's named, here (or in a session's own directory)
    const out =
      file ??
      path.join(
        cb.sessionDir ?? process.cwd(),
        fileName(name.slice(name.lastIndexOf(".") + 1), rec),
      );
    const content = fileContent(cb, rec, ns);
    const body =
      format === "md"
        ? Buffer.concat([Buffer.from(`<!-- tcm: path ${name} -->\n`), content])
        : content;
    // the codebase's own config, where `tcm edit` writes: never over it, --force or not
    if (
      ["package.json", "tsconfig.json", ".mcp.json"].some(
        (f) => path.resolve(out) === path.join(cb.lay.root, f),
      )
    )
      throw new UsageError(
        `${path.basename(out)} here is the codebase's own: edit ${name} with --file <other>`,
      );
    if (fs.existsSync(out) && !force && !fs.readFileSync(out).equals(body))
      throw new UsageError(
        `${path.basename(out)} exists; pass --force to overwrite it, or --file <other>`,
      );
    fs.writeFileSync(out, body);
    // (where it went whole, as tcm_edit reads it; how to save it as it's named in a session)
    console.log(
      `wrote ${name} to ${shownPath(out)}${format === "md" ? "" : dim(` (saved with \`tcm update ${shellWord(scratchShown(out, cb.sessionDir))} --into ${ns}\`)`)}`,
    );
  }
}

uses

used by