testPackagesDependThroughReleases

tcmts.cli.test.e2e.releases.testPackagesDependThroughReleases · #er7jnguc · term

packages depend on each other through their releases

import { codebase } from "#codebase/tcmts/cli/test/e2e/releases";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";

export const testPackagesDependThroughReleases = () => {
  const a = codebase("two");
  a.save(`// tcm: namespace geo\nexport const manifest = { name: "geo" };\nexport interface Point { x: number; y: number }\nexport const distance = (a: Point, b: Point): number => Math.hypot(a.x - b.x, a.y - b.y);\n`, "add");
  a.save(`// tcm: namespace atlas\nimport { distance, type Point } from "#codebase/geo";\nexport const manifest = { name: "atlas", bin: { atlas: "main" } };\nexport const length = (ps: Point[]): number => ps.slice(1).reduce((n, p, i) => n + distance(ps[i]!, p), 0);\nexport const main = (): number => (console.log(length([{ x: 0, y: 0 }, { x: 3, y: 4 }])), 0);\n`, "add");
  assert.match(a.run("release").out, /which package\? atlas, geo/);
  assert.match(a.run("pack", "atlas").out, /this uses geo\.Point, geo\.distance from geo, which geo hasn't released yet: release geo first/);
  a.tcm("release", "geo");
  a.tcm("release", "atlas");

  // atlas imports what it uses of geo from geo's release, rather than carrying a copy
  assert.match(a.tcm("pack", "atlas@0.1.0"), /packed atlas@0\.1\.0 into \.tcm\/pack\/atlas: 2 module\(s\), depends on geo/);
  const dir = path.join(a.dir, ".tcm", "pack", "atlas");
  assert.deepEqual(JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf8")).dependencies, { geo: "^0.1.0" });
  const modules = fs.readdirSync(path.join(dir, "modules")).map((f) => fs.readFileSync(path.join(dir, "modules", f), "utf8")).join("\n");
  assert.match(modules, /import \{ distance as distance \} from "geo";/);
  assert.match(modules, /import type \{ Point as Point \} from "geo";/);
  assert.doesNotMatch(modules, /Math\.hypot/, "geo's code isn't copied in");

  // a change to geo is geo's: atlas's code didn't change, only what it uses
  a.save(`// tcm: namespace geo\nimport type { Point } from "#codebase/geo";\nexport const distance = (a: Point, b: Point, digits?: number): number => Number(Math.hypot(a.x - b.x, a.y - b.y).toFixed(digits ?? 10));\n`);
  assert.match(a.tcm("release", "check", "geo"), /geo's next release: 0\.1\.1 .*: additions/);
  assert.match(a.tcm("release", "check", "atlas"), /atlas's next release: 0\.1\.1 .*: no API changes[\s\S]*follow those changes \(atlas\.length/);
  assert.match(a.run("pack", "atlas").out, /geo@0\.1\.0 doesn't export as it is here: release geo first/);
  a.tcm("release", "geo");
  a.tcm("pack", "atlas");
  assert.deepEqual(JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf8")).dependencies, { geo: "^0.1.1" });
  assert.match(a.tcm("releases"), /^atlas {2}atlas\n {2}0\.1\.0 [\s\S]*geo {2}geo\n {2}0\.1\.1 [\s\S]* {2}0\.1\.0 /m);
}

uses