import assert from "node:assert/strict"; import test from "node:test"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { compileWorkspaceRepository, compileCapabilityResourceRepository } from "../src/capability-language/index.js"; import { bindingSchema } from "../src/bindings/index.js"; import { parseQuixosLockDocument } from "../src/resource-lock/index.js"; import { editStructure } from "../src/capability-language/structural-edits.js"; const commit = "a".repeat(40); const entry = (kind: string, name: string) => `${kind} ${name} source {repository "https://example.test/${name}.git"; commit "${commit}";}`; const lock = (entries = "") => `quixos-lock version 1 {quixos source {repository "https://example.test/quixos.git"; commit "${commit}";} ${entries}}`; test("build dependency closures are retained without installing their capability descendants", async (t) => { const directory = await fs.mkdtemp(path.join(os.tmpdir(), "qx-build-deps-")); t.after(() => fs.rm(directory, { recursive: true, force: true })); const write = async (name: string, files: Record) => { await fs.mkdir(path.join(directory, name)); for (const [file, text] of Object.entries(files)) await fs.writeFile(path.join(directory, name, file), text); }; await write("root", { "quixos.lock": lock(entry("build", "Library")), "workspace.qx": `workspace Empty id "empty" revision "empty@1" commit "${commit}" {}`, }); await write("Library", { "quixos.lock": lock(entry("package", "Hidden")), "types.ts": "export type Label = string;", }); await write("Hidden", { "quixos.lock": lock(entry("interface", "Data")), "package.qx": 'import interface Data; package Hidden id "hidden" revision "hidden@1" {}', }); await write("Data", { "quixos.lock": lock(), "interface.qx": 'interface Data id "data" revision "data@1" {}' }); const resolveResource = async (source: { repository: string }) => ({ directory: path.join(directory, new URL(source.repository).pathname.slice(1, -4)), }); const compiled = await compileWorkspaceRepository({ rootDirectory: path.join(directory, "root"), resolveResource }); assert.equal(compiled.resources.length, 3); assert.deepEqual(compiled.capabilityResources, []); assert.deepEqual(compiled.workspace.packageImports, []); assert.deepEqual(compiled.workspace.interfaceImports, []); assert.deepEqual(bindingSchema(compiled).packages, []); const library = await compileCapabilityResourceRepository({ rootDirectory: path.join(directory, "Library"), kind: "build", source: { resolver: "git", repository: "https://example.test/Library.git", commit }, resolveResource, }); assert.deepEqual(library.resource, { kind: "build" }); assert.deepEqual(bindingSchema(library).interfaces, []); await fs.writeFile(path.join(directory, "Library/quixos.lock"), lock(entry("build", "Library"))); await assert.rejects( compileWorkspaceRepository({ rootDirectory: path.join(directory, "root"), resolveResource }), /dependency cycle/, ); }); test("build pins retain their kind through parsing and structural updates", () => { const initial = lock(entry("build", "Library")); const parsed = parseQuixosLockDocument(initial); assert.ok(parsed.ok); assert.equal(parsed.document.resources[0]!.kind, "build"); const edited = editStructure(initial, { operation: "dependency", kind: "build", name: "Library", source: { repository: "https://example.test/Library.git", commit: "b".repeat(40) }, }); const changed = parseQuixosLockDocument(edited); assert.ok(changed.ok); assert.equal(changed.document.resources[0]!.kind, "build"); assert.equal(changed.document.resources[0]!.source.commit, "b".repeat(40)); });