2026-09-05 12:33:52 -07:00
import assert from "node:assert/strict" ;
import { mkdtemp , mkdir , rm , writeFile } from "node:fs/promises" ;
import os from "node:os" ;
import path from "node:path" ;
import test from "node:test" ;
2026-09-15 15:23:24 -07:00
import { compileCapabilityResourceRepository , compileWorkspaceRepository } from "../src/capability-language/index.js" ;
2026-09-05 12:33:52 -07:00
const quixosCommit = "1" . repeat ( 40 );
const namedCommit = "2" . repeat ( 40 );
const packageCommit = "3" . repeat ( 40 );
const lock = ( resources = "" ) => `quixos-lock version 1 {
quixos source {
repository "https://example.test/quixos.git";
commit " ${ quixosCommit } ";
}
${ resources }
}
` ;
test ( "workspace assembly resolves resource-owned dependencies recursively" , async ( context ) => {
const directory = await mkdtemp ( path . join ( os . tmpdir (), "quixos-assembly-" ));
context . after (() => rm ( directory , { recursive : true , force : true }));
const root = path . join ( directory , "root" );
const named = path . join ( directory , "named" );
const runtime = path . join ( directory , "runtime" );
await Promise . all ([ mkdir ( root ), mkdir ( named ), mkdir ( runtime )]);
2026-09-15 15:23:24 -07:00
await writeFile (
path . join ( root , "quixos.lock" ),
lock ( `package Runtime source {
2026-09-05 12:33:52 -07:00
repository "https://example.test/package-runtime.git";
commit " ${ packageCommit } ";
2026-09-15 15:23:24 -07:00
}` ),
);
await writeFile (
path . join ( root , "workspace.qx" ),
`workspace Test id "workspace:test" revision "workspace:test@1" commit " ${ "4" . repeat ( 40 ) } " {
2026-09-05 12:33:52 -07:00
atom Subject id "atom:subject";
import package Runtime;
}
2026-09-15 15:23:24 -07:00
` ,
);
2026-09-05 12:33:52 -07:00
await writeFile ( path . join ( named , "quixos.lock" ), lock ());
2026-09-15 15:23:24 -07:00
await writeFile (
path . join ( named , "interface.qx" ),
`interface Named id "interface:named" revision "interface:named@1" {
2026-09-05 12:33:52 -07:00
value name id "member:named:name" : string {
get id "operation:named:name:get";
}
}
2026-09-15 15:23:24 -07:00
` ,
);
await writeFile (
path . join ( runtime , "quixos.lock" ),
lock ( `interface Named source {
2026-09-05 12:33:52 -07:00
repository "https://example.test/interface-named.git";
commit " ${ namedCommit } ";
2026-09-15 15:23:24 -07:00
}` ),
);
await writeFile (
path . join ( runtime , "package.qx" ),
`import interface Named;
2026-09-05 12:33:52 -07:00
package Runtime id "package:runtime" revision "package:runtime@1" {
function describe id "export:runtime:describe" : interface-ref<Named> -> string;
}
2026-09-15 15:23:24 -07:00
` ,
);
2026-09-05 12:33:52 -07:00
const directories = new Map ([
[ `interface \ 0https://example.test/interface-named.git \ 0 ${ namedCommit } ` , named ],
[ `package \ 0https://example.test/package-runtime.git \ 0 ${ packageCommit } ` , runtime ],
]);
const result = await compileWorkspaceRepository ({
rootDirectory : root ,
resolveResource : async ( source , kind ) => {
const resolved = directories . get ( ` ${ kind } \ 0 ${ source . repository } \ 0 ${ source . commit } ` );
if ( ! resolved ) throw new Error ( `Unexpected source ${ source . repository } ` );
return { directory : resolved };
},
});
assert . equal ( result . resources . length , 2 );
assert . deepEqual (
result . workspace . interfaceImports . map (( entry ) => entry . revisionId ),
[ "interface:named@1" ],
);
assert . deepEqual (
result . workspace . packageImports . map (( entry ) => entry . revisionId ),
[ "package:runtime@1" ],
);
assert . equal ( result . directResources . size , 1 );
const resource = await compileCapabilityResourceRepository ({
rootDirectory : runtime ,
kind : "package" ,
source : {
resolver : "git" ,
repository : "https://example.test/package-runtime.git" ,
commit : packageCommit ,
},
resolveResource : async ( source , kind ) => {
const resolved = directories . get ( ` ${ kind } \ 0 ${ source . repository } \ 0 ${ source . commit } ` );
if ( ! resolved ) throw new Error ( `Unexpected source ${ source . repository } ` );
return { directory : resolved };
},
});
assert . equal ( resource . resource . kind , "package" );
assert . equal ( resource . resources . length , 2 );
assert . equal ( resource . directResources . size , 1 );
});
test ( "resource repositories cannot own workspace Quixos selection policy" , async ( context ) => {
const directory = await mkdtemp ( path . join ( os . tmpdir (), "quixos-resource-policy-" ));
context . after (() => rm ( directory , { recursive : true , force : true }));
2026-09-15 15:23:24 -07:00
await writeFile (
path . join ( directory , "quixos.lock" ),
`quixos-lock version 1 {
2026-09-05 12:33:52 -07:00
quixos source {
repository "https://example.test/quixos.git";
policy track-development;
ref "dev/alice/main";
commit " ${ quixosCommit } ";
}
2026-09-15 15:23:24 -07:00
}` ,
);
await writeFile (
path . join ( directory , "package.qx" ),
`package Runtime id "package:runtime" revision "package:runtime@1" { } \ n` ,
);
2026-09-05 12:33:52 -07:00
await assert . rejects (
compileCapabilityResourceRepository ({
rootDirectory : directory ,
kind : "package" ,
source : {
resolver : "git" ,
repository : "https://example.test/package-runtime.git" ,
commit : packageCommit ,
},
resolveResource : async () => ({ directory }),
}),
/resource locks may only declare their exact authored-against commit/ ,
);
});
test ( "resource manifests cannot hide lock dependencies" , async ( context ) => {
const directory = await mkdtemp ( path . join ( os . tmpdir (), "quixos-assembly-mismatch-" ));
context . after (() => rm ( directory , { recursive : true , force : true }));
const root = path . join ( directory , "root" );
const runtime = path . join ( directory , "runtime" );
await Promise . all ([ mkdir ( root ), mkdir ( runtime )]);
2026-09-15 15:23:24 -07:00
await writeFile (
path . join ( root , "quixos.lock" ),
lock ( `package Runtime source {
2026-09-05 12:33:52 -07:00
repository "https://example.test/package-runtime.git";
commit " ${ packageCommit } ";
2026-09-15 15:23:24 -07:00
}` ),
);
await writeFile (
path . join ( root , "workspace.qx" ),
`workspace Test id "workspace:test" revision "workspace:test@1" commit " ${ "4" . repeat ( 40 ) } " {
2026-09-05 12:33:52 -07:00
atom Subject id "atom:subject";
import package Runtime;
}
2026-09-15 15:23:24 -07:00
` ,
);
2026-09-05 12:33:52 -07:00
await writeFile ( path . join ( runtime , "quixos.lock" ), lock ());
2026-09-15 15:23:24 -07:00
await writeFile (
path . join ( runtime , "package.qx" ),
`import interface Hidden;
2026-09-05 12:33:52 -07:00
package Runtime id "package:runtime" revision "package:runtime@1" { }
2026-09-15 15:23:24 -07:00
` ,
);
2026-09-05 12:33:52 -07:00
await assert . rejects (
compileWorkspaceRepository ({
rootDirectory : root ,
resolveResource : async () => ({ directory : runtime }),
}),
/No resolved interface is available for lock binding Hidden/ ,
);
});
test ( "workspace assembly must satisfy nominal external interfaces" , async ( context ) => {
const directory = await mkdtemp ( path . join ( os . tmpdir (), "quixos-assembly-external-" ));
context . after (() => rm ( directory , { recursive : true , force : true }));
const root = path . join ( directory , "root" );
const runtime = path . join ( directory , "runtime" );
await Promise . all ([ mkdir ( root ), mkdir ( runtime )]);
2026-09-15 15:23:24 -07:00
await writeFile (
path . join ( root , "quixos.lock" ),
lock ( `package Runtime source {
2026-09-05 12:33:52 -07:00
repository "https://example.test/package-runtime.git";
commit " ${ packageCommit } ";
2026-09-15 15:23:24 -07:00
}` ),
);
await writeFile (
path . join ( root , "workspace.qx" ),
`workspace Test id "workspace:test" revision "workspace:test@1" commit " ${ "4" . repeat ( 40 ) } " {
2026-09-05 12:33:52 -07:00
atom Subject id "atom:subject";
import package Runtime;
}
2026-09-15 15:23:24 -07:00
` ,
);
2026-09-05 12:33:52 -07:00
await writeFile ( path . join ( runtime , "quixos.lock" ), lock ());
2026-09-15 15:23:24 -07:00
await writeFile (
path . join ( runtime , "package.qx" ),
`external interface Named revision "interface:named@1";
2026-09-05 12:33:52 -07:00
package Runtime id "package:runtime" revision "package:runtime@1" { }
2026-09-15 15:23:24 -07:00
` ,
);
2026-09-05 12:33:52 -07:00
await assert . rejects (
compileWorkspaceRepository ({
rootDirectory : root ,
resolveResource : async () => ({ directory : runtime }),
}),
/requires external interface Named \(interface:named@1\)/ ,
);
});
2026-09-22 15:41:27 -07:00
test ( "resource-owned fragment imports compile through the locked package closure" , async ( context ) => {
const directory = await mkdtemp ( path . join ( os . tmpdir (), "quixos-fragment-assembly-" ));
context . after (() => rm ( directory , { recursive : true , force : true }));
const dirs = Object . fromEntries ([ "item" , "rows" , "screen" ]. map (( name ) => [ name , path . join ( directory , name )]));
await Promise . all ( Object . values ( dirs ). map (( dir ) => mkdir ( dir )));
const dependency = ( kind : string , name : string ) =>
` ${ kind } ${ name } source {repository "https://example.test/ ${ name . toLowerCase () } .git"; commit " ${ namedCommit } ";}` ;
await writeFile ( path . join ( dirs . item ! , "quixos.lock" ), lock ());
await writeFile (
path . join ( dirs . item ! , "interface.qx" ),
`interface Item id "item" revision "item@1" {queryable value title id "title" : string {get id "title:get" execution snapshot targets [browser,server];}}` ,
);
await writeFile ( path . join ( dirs . rows ! , "quixos.lock" ), lock ( dependency ( "interface" , "Item" )));
await writeFile (
path . join ( dirs . rows ! , "package.qx" ),
`import interface Item; package Rows id "rows" revision "rows@1" {query fragment Row id "row" root Item document "row.graphql" fragment "Row";}` ,
);
await writeFile ( path . join ( dirs . rows ! , "row.graphql" ), "fragment Row on Item {_camino {ref} title}" );
await writeFile (
path . join ( dirs . screen ! , "quixos.lock" ),
lock ( dependency ( "interface" , "Item" ) + dependency ( "package" , "Rows" )),
);
await writeFile (
path . join ( dirs . screen ! , "package.qx" ),
`import interface Item; import package Rows; package Screen id "screen" revision "screen@1" {
query Inputs id "inputs" root Item document "screen.graphql" operation "Screen" {replica; fragments Rows.Row;}
query View id "view" root Item document "screen.graphql" operation "Screen" {local from Inputs; fragments Rows.Row;}
}` ,
);
await writeFile ( path . join ( dirs . screen ! , "screen.graphql" ), "query Screen {root {...Row}}" );
const result = await compileCapabilityResourceRepository ({
rootDirectory : dirs.screen ! ,
kind : "package" ,
source : { resolver : "git" , repository : "https://example.test/screen.git" , commit : packageCommit },
resolveResource : async ( source ) => {
const name = new URL ( source . repository ). pathname . slice ( 1 , - 4 );
assert . ok ( dirs [ name ], name );
return { directory : dirs [ name ] ! };
},
});
assert . equal ( result . resource . kind , "package" );
if ( result . resource . kind !== "package" ) throw Error ( "expected package" );
const view = result . resource . revision . checkedQueries ! . find (( q ) => q . declaration . id === "view" ) ! ;
assert . equal ( view . selection [ 0 ] ! . selection [ 0 ] ! . fragmentSpread ? . package , "rows@1" );
assert . equal ( result . resources . length , 3 );
});