43 lines
3.6 KiB
TypeScript
43 lines
3.6 KiB
TypeScript
import test from "node:test";
|
|||
|
|
import assert from "node:assert/strict";
|
||
|
|
import { editStructure, scaffoldResourceSource } from "../src/capability-language/structural-edits.js";
|
||
|
|
|
||
|
|
test("package scaffolding and function edits preserve surrounding source and use exact selectors", () => {
|
||
|
|
const source = `// 🧭 resource comment\n${scaffoldResourceSource("package", "Chess", "package:chess", "package:chess@1")}`;
|
||
|
|
const functionSource = 'function evaluate id "export:evaluate" : string -> string;';
|
||
|
|
const appended = editStructure(source, {operation: "append", parent: {kind: "packageResourceDecl", id: "package:chess"}, source: functionSource});
|
||
|
|
assert.ok(appended.startsWith("// 🧭 resource comment\n"));
|
||
|
|
assert.ok(appended.includes(functionSource));
|
||
|
|
const replaced = editStructure(appended, {operation: "replace", target: {kind: "packageFunctionExport", id: "export:evaluate"}, source: 'function evaluate id "export:evaluate" : unit -> string;'});
|
||
|
|
assert.ok(replaced.includes(": unit -> string;"));
|
||
|
|
assert.ok(!editStructure(replaced, {operation: "remove", target: {kind: "packageFunctionExport", id: "export:evaluate"}}).includes("evaluate"));
|
||
|
|
assert.throws(() => editStructure(source, {operation: "remove", target: {kind: "packageResourceDecl", id: "package:chess@1"}}), /exactly once/);
|
||
|
|
assert.throws(() => editStructure(source, {operation: "append", parent: {kind: "packageResourceDecl"}, source: "not valid QX"}), /Invalid structural/);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("dependency scaffolding validates exact sources and preserves unrelated lock comments", () => {
|
||
|
|
const source = `// 🧭 lock\nquixos-lock version 1 {\n quixos source { repository "https://example.test/quixos.git"; commit "${"a".repeat(40)}"; }\n // retained comment\n}\n`;
|
||
|
|
const dependency = {operation: "dependency" as const, kind: "package" as const, name: "Chess", source: {repository: "https://example.test/chess.git", commit: "b".repeat(40)}};
|
||
|
|
const appended = editStructure(source, dependency);
|
||
|
|
assert.ok(appended.includes("// retained comment"));
|
||
|
|
assert.ok(appended.startsWith("// 🧭 lock\n"));
|
||
|
|
assert.throws(() => editStructure(source, {...dependency, source: {...dependency.source, commit: "main"}}), /Invalid dependency/);
|
||
|
|
const changed = editStructure(appended, {...dependency, source: {...dependency.source, commit: "c".repeat(40)}});
|
||
|
|
assert.ok(!changed.includes("b".repeat(40)));
|
||
|
|
assert.ok(!editStructure(changed, {...dependency, source: null}).includes("package Chess"));
|
||
|
|
});
|
||
|
|
|
||
|
|
test("conformance enrollment, major edits, imports, and private attachment removal preserve valid structure", () => {
|
||
|
|
const source = `fragment { conform Game as Playable { private state Board id "slot:board" on Game : string policy optimistic-register; } }`;
|
||
|
|
const selector = {kind: "conformanceDecl", names: ["Game", "Playable"]};
|
||
|
|
const enrolled = editStructure(source, {operation: "conformance-id", target: selector, id: "conformance:playable"});
|
||
|
|
assert.ok(enrolled.includes('as Playable id "conformance:playable"'));
|
||
|
|
const major = editStructure(enrolled, {operation: "semantic-major", target: {kind: "conformanceDecl", id: "conformance:playable"}, major: 2});
|
||
|
|
assert.ok(major.includes("semantic-major 2"));
|
||
|
|
assert.throws(() => editStructure(major, {operation: "conformance-id", target: selector, id: "different"}), /Cannot change/);
|
||
|
|
const removed = editStructure(major, {operation: "remove", target: {kind: "stateDecl", id: "slot:board"}});
|
||
|
|
assert.ok(!removed.includes("private"));
|
||
|
|
const imported = editStructure(removed, {operation: "import", kind: "interface", name: "Playable"});
|
||
|
|
assert.equal(editStructure(imported, {operation: "import", kind: "interface", name: "Playable"}), imported);
|
||
|
|
});
|