resolveBuild

tcmts.cli.builds.resolveBuild · #rfwdm2rd · term · runs on the server

uses node:path

The tcm.js a build's name means: known-good, previous, a kept build's id (the history entry it was made from: a prefix will do, # or not), or a path (a tcm.js, or a build's directory).

import { buildBin, keptBuilds } from "#codebase/tcmts/cli/builds";
import { UsageError } from "#codebase/tcmts/cli/ui";
import fs from "node:fs";
import path from "node:path";

export function resolveBuild(spec: string, root: string | undefined, cwd = process.cwd()): string {
  const builds = root ? keptBuilds(root) : [];
  const id = spec.replace(/^#/, "");
  const named = builds.filter(
    (b) =>
      b.name === spec ||
      (spec === "known-good-previous" && b.name === "previous") ||
      (/^[a-z2-7]{4,}$/.test(id) && b.head?.startsWith(id)),
  );
  const distinct = [...new Map(named.map((b) => [b.bin, b])).values()];
  if (distinct.length === 1) return distinct[0]!.bin;
  if (distinct.length > 1)
    throw new UsageError(
      `${spec} is ${distinct.map((b) => b.name).join(" and ")}: give more of the hash`,
    );
  const given = path.resolve(cwd, spec);
  if (fs.existsSync(given)) {
    if (fs.statSync(given).isFile()) return given;
    const bin = buildBin(given);
    if (bin) return bin;
    throw new UsageError(`${spec} isn't a tcm build: it has no node_modules/tcm-ts/bin/tcm.js`);
  }
  throw new UsageError(
    root
      ? `no build ${spec}: ${builds.length ? `kept are ${builds.map((b) => b.name).join(", ")}` : "none are kept"} (\`tcm builds\` lists them; \`tcm builds make <entry>\` makes one from a history entry)`
      : `no build ${spec}, and no builds are kept here: TCM_BUILDS names the directory they're in (tcm's repository's dist/), or give a tcm.js`,
  );
}

uses

used by