followImports

tcmts.cli.main.followImports · #7smasgef · term · runs on the server

uses node:fs

Imports follow the code in a scratch file, as in tcm patch: names it uses and doesn't import are imported (#slct55le, near its namespace: into, else its // tcm: namespace line), and imports nothing in it uses are taken out (pruneUnusedImports). How far depends on how: "save" does both, before it's saved; "check" imports, and says what saving would take out (an import not used yet may be for code still to be written); "say" changes nothing, saying what it would import (tcm watch: the file is open in an editor, being written). What it does, or would, is said; a file that isn't code is left alone.

import type { Codebase } from "#codebase/tcmts/cli/codebase";
import { importMissing, pruneUnusedImports } from "#codebase/tcmts/cli/main";
import { joinName } from "#codebase/tcmts/cli/mirror";
import { dim } from "#codebase/tcmts/cli/style";
import fs from "node:fs";

export function followImports(
  cb: Codebase,
  file: string,
  into: string | undefined,
  how: "save" | "check" | "say",
): void {
  if (!/\.[cm]?tsx?$/.test(file) || !fs.existsSync(file)) return;
  const text = fs.readFileSync(file, "utf8");
  const pruned = pruneUnusedImports(file, text);
  if (how === "save" && pruned.dropped.length) {
    fs.writeFileSync(file, pruned.text);
    console.log(dim(`  took out imports nothing uses: ${pruned.dropped.join(", ")}`));
  }
  const ns = into ?? /^\/\/ tcm: namespace (\S+)/m.exec(text)?.[1] ?? "";
  for (const line of importMissing(cb, file, joinName(ns, "_"), how !== "say"))
    console.log(
      dim(
        how === "say"
          ? `  not imported: ${line} (\`tcm check\` or saving imports it)`
          : `  ${line}`,
      ),
    );
  if (how !== "save" && pruned.dropped.length)
    console.log(
      dim(
        `  nothing uses ${pruned.dropped.join(", ")}: saving takes ${pruned.dropped.length > 1 ? "those imports" : "that import"} out`,
      ),
    );
}

uses

used by