testLibrariesFromAnotherCodebase
a library is another codebase's release (or namespace, by hash), mounted read-only: code uses it like its own, its packages stay its own, it's removed only when nothing uses it, and it travels with history
import { codebase } from "#codebase/tcmts/cli/test/e2e/releases"; import assert from "node:assert/strict"; export const testLibrariesFromAnotherCodebase = () => { const alice = codebase("alice"); alice.save( `// tcm: namespace geo\nexport const manifest = { name: "geo" };\n/** A square's area. */\nexport const area = (side: number) => side * side;\nexport const double = (side: number) => 2 * area(side);\n`, "add", ); alice.tcm("release", "geo@1.0.0"); const me = codebase("me"); me.save(`// tcm: namespace app\nexport const greeting = "hi";\n`, "add"); // in the project's root namespace, by its newest release, everything it uses received and checked assert.match( me.tcm("lib", "add", alice.dir, "geo"), /added app\.lib\.geo: geo@1\.0\.0 from .*\(3 names; 3 definitions received/, ); assert.match(me.tcm("lib"), /app\.lib\.geo {2}geo@1\.0\.0 {2}from /); assert.match(me.tcm("history", "1"), /lib add app\.lib\.geo\n(.*\n)*\s+app\.lib\.libraries +\+/); // code uses it like its own me.save( `// tcm: namespace app\nimport { area, double } from "#codebase/app/lib/geo";\nexport const total = () => area(2) + double(3);\n`, "add", ); assert.equal(me.tcm("run", "app.total").trim(), "22"); // and its package is its own, not this codebase's assert.match(me.tcm("releases"), /no packages yet/); // read-only: its names, and the record saying what it is const patched = me.run("patch", "app.lib.geo.area", "--old", "side * side", "--new", "side ** 2"); assert.notEqual(patched.status, 0); assert.match( patched.out, /app\.lib\.geo\.area is in the library app\.lib\.geo \(geo@1\.0\.0\), which is read-only/, ); assert.match(me.run("mv", "app.lib.geo", "app.geo").out, /read-only/); assert.match(me.run("rm", "app.lib.libraries").out, /records the libraries mounted beside it/); // a copy of its own changes; the library keeps what it had me.tcm("alias", "app.lib.geo.area", "app.myArea"); me.tcm("patch", "app.myArea", "--old", "side * side", "--new", "side * side + 1"); assert.match( me.tcm("view", "app.lib.geo.double"), /import \{ area \} from "#codebase\/app\/lib\/geo"/, ); assert.match(me.tcm("lib"), /geo@1\.0\.0 {2}from [^\n]*$/m); assert.doesNotMatch(me.tcm("lib"), /aren't the namespace/); // by its namespace's hash, wherever it's asked for; removed again, as nothing uses what only it names const hash = /"namespace": "(\w+)"/.exec(me.tcm("view", "app.lib.libraries"))![1]!; // (a hash names no package to be called after: it says so, and is called what it's told) assert.match( me.run("lib", "add", alice.dir, `#${hash}`).out, /a library by hash has no package to be called after: say what to call it \(--as <name>\)/, ); assert.match( me.run("lib", "add", alice.dir).out, /which library\? tcm lib add .* <package>\[@<version>\]/, ); assert.match( me.tcm("lib", "add", alice.dir, `#${hash}`, "--as", "copy", "--at", "vendor.geo"), /added vendor\.geo: #\w{8} from /, ); assert.match( me.run("lib", "add", alice.dir, "geo", "--at", "vendor.geo").out, /vendor\.geo is in the library vendor\.geo/, ); assert.match(me.tcm("lib", "rm", "vendor.geo"), /removed vendor\.geo \(3 names\)/); assert.match(me.tcm("ls", "vendor"), /nothing under vendor/); // but not while code uses it assert.match(me.run("lib", "rm", "geo").out, /app\.lib\.geo is used by app\.total/); assert.match( me.run("lib", "add", alice.dir, "geo").out, /app\.lib\.geo is in the library app\.lib\.geo/, ); assert.match( me.run("lib", "add", alice.dir, "geo@9.9.9", "--at", "old.geo").out, /has no geo@9\.9\.9; it has 1\.0\.0/, ); // and formatting leaves it as it was released assert.match(me.tcm("fmt"), /no hashes changed/); // a codebase pulling this one has it too, as read-only there const other = codebase("other"); other.tcm("remote", "add", "origin", me.dir); other.tcm("pull"); assert.match(other.tcm("lib"), /app\.lib\.geo {2}geo@1\.0\.0/); assert.match(other.run("rm", "app.lib.geo.double", "--force").out, /read-only/); }