Build composable Camino packages with explicit type and source dependencies

This commit is contained in:
Timothy J. Aveni
2026-09-22 14:42:54 -07:00
parent 7173751f37
commit 82a4542746
30 changed files with 736 additions and 420 deletions
+2
View File
@@ -20,6 +20,7 @@ importEntry
resourceKind resourceKind
: INTERFACE : INTERFACE
| PACKAGE | PACKAGE
| BUILD
; ;
sourceBlock sourceBlock
@@ -58,6 +59,7 @@ QUIXOS: 'quixos';
SOURCE: 'source'; SOURCE: 'source';
INTERFACE: 'interface'; INTERFACE: 'interface';
PACKAGE: 'package'; PACKAGE: 'package';
BUILD: 'build';
REPOSITORY: 'repository'; REPOSITORY: 'repository';
COMMIT: 'commit'; COMMIT: 'commit';
POLICY: 'policy'; POLICY: 'policy';
+67 -2
View File
@@ -34,7 +34,8 @@ let
''; '';
lock = builtins.fromJSON (builtins.readFile lockFile); lock = builtins.fromJSON (builtins.readFile lockFile);
children = map ( children = map (
entry: load (ancestors ++ [ (sourceKey source) ]) (entry.source // { inherit (entry) kind; }) entry:
load (ancestors ++ [ (sourceKey source) ]) (entry.source // { inherit (entry) kind binding; })
) lock.resources; ) lock.resources;
in in
source // { inherit directory children lock; }; source // { inherit directory children lock; };
@@ -50,6 +51,12 @@ let
); );
runtimePackages = runtime.packages.${system}; runtimePackages = runtime.packages.${system};
flatten = node: [ node ] ++ pkgs.lib.concatMap flatten node.children; flatten = node: [ node ] ++ pkgs.lib.concatMap flatten node.children;
capabilityFlatten =
node:
if node.kind == "build" then
[ ]
else
[ node ] ++ pkgs.lib.concatMap capabilityFlatten node.children;
nodes = builtins.attrValues ( nodes = builtins.attrValues (
builtins.listToAttrs ( builtins.listToAttrs (
map (node: { map (node: {
@@ -94,6 +101,51 @@ let
} }
''; '';
contract = compile root; contract = compile root;
buildDependencies =
node:
builtins.listToAttrs (
map (dependency: {
name = dependency.binding;
value = {
src = dependency.directory;
source = { inherit (dependency) repository commit; };
flake = builtins.getFlake "git+${dependency.repository}?rev=${dependency.commit}&ref=refs/tags/quixos-reachability/${dependency.commit}";
};
}) (builtins.filter (dependency: dependency.kind == "build") node.children)
);
reactContracts =
node:
let
interfaces = builtins.attrValues (
builtins.listToAttrs (
map (dependency: {
name = sourceKey dependency;
value = dependency;
}) (builtins.filter (dependency: dependency.kind == "interface") (capabilityFlatten node))
)
);
in
pkgs.lib.concatMap (
dependency:
if !builtins.pathExists (dependency.directory + "/flake.nix") then
[ ]
else
let
source = builtins.getFlake "git+${dependency.repository}?rev=${dependency.commit}&ref=refs/tags/quixos-reachability/${dependency.commit}";
build = source.quixosInterfaces.${system}.reactTypes or null;
in
if build == null then
[ ]
else
[
(build {
interface = "${compile dependency}/candidate.json";
generator = protocol;
typescript = runtimePackages.camino-replica-core.dependencies;
dependencies = buildDependencies dependency;
})
]
) interfaces;
checkPackage = checkPackage =
node: node:
let let
@@ -126,11 +178,13 @@ let
sharedRuntime = runtimePackages.camino-shared-runtime; sharedRuntime = runtimePackages.camino-shared-runtime;
typescript = runtimePackages.camino-replica-core.dependencies; typescript = runtimePackages.camino-replica-core.dependencies;
packageRevisionId = candidate.revision.revisionId; packageRevisionId = candidate.revision.revisionId;
dependencies = buildDependencies node;
} }
// pkgs.lib.optionalAttrs (componentEntries != [ ]) { // pkgs.lib.optionalAttrs (componentEntries != [ ]) {
react = { react = {
sdk = runtimePackages.camino-react; sdk = runtimePackages.camino-react;
runtime = runtimePackages.camino-react-runtime; runtime = runtimePackages.camino-react-runtime;
contracts = reactContracts node;
}; };
} }
else else
@@ -157,7 +211,18 @@ let
if contractOnly then if contractOnly then
[ ] [ ]
else else
map checkPackage (builtins.filter (node: node.kind == "package") nodes); map checkPackage (
builtins.filter (node: node.kind == "package") (
builtins.attrValues (
builtins.listToAttrs (
map (node: {
name = sourceKey node;
value = node;
}) (capabilityFlatten root)
)
)
)
);
manifest = pkgs.writeText "qx-candidate-checks.json" (builtins.toJSON checks); manifest = pkgs.writeText "qx-candidate-checks.json" (builtins.toJSON checks);
bindingOptions = pkgs.writeText "qx-typescript-options.json" ( bindingOptions = pkgs.writeText "qx-typescript-options.json" (
builtins.toJSON ( builtins.toJSON (
+10 -5
View File
@@ -17,24 +17,29 @@ export type BindingSchema = {
interfaceTemplates?: InterfaceRevision[]; interfaceTemplates?: InterfaceRevision[];
packages: PackageRevision[]; packages: PackageRevision[];
}; };
export const bindingSchema = (compiled: Pick<CompiledCapabilityResourceRepository, "resources">): BindingSchema => ({ export const bindingSchema = (
compiled: Pick<CompiledCapabilityResourceRepository, "resources"> &
Partial<Pick<CompiledCapabilityResourceRepository, "capabilityResources">>,
): BindingSchema => ({
format: "quixos-bindings", format: "quixos-bindings",
version: 1, version: 1,
interfaceTemplates: compiled.resources.flatMap((node) => interfaceTemplates: (compiled.capabilityResources ?? compiled.resources).flatMap((node) =>
node.resource.kind === "interface" && node.resource.revision.template ? [node.resource.revision] : [], node.resource.kind === "interface" && node.resource.revision.template ? [node.resource.revision] : [],
), ),
interfaces: [ interfaces: [
...new Map( ...new Map(
compiled.resources (compiled.capabilityResources ?? compiled.resources)
.flatMap((node) => [ .flatMap((node) => [
...(node.resource.kind === "interface" ? [node.resource.revision] : []), ...(node.resource.kind === "interface" ? [node.resource.revision] : []),
...(node.resource.specializations ?? []), ...(node.resource.kind === "build" ? [] : (node.resource.specializations ?? [])),
]) ])
.filter((entry) => !entry.template) .filter((entry) => !entry.template)
.map((entry) => [entry.revisionId, entry]), .map((entry) => [entry.revisionId, entry]),
).values(), ).values(),
], ],
packages: compiled.resources.flatMap((node) => (node.resource.kind === "package" ? [node.resource.revision] : [])), packages: (compiled.capabilityResources ?? compiled.resources).flatMap((node) =>
node.resource.kind === "package" ? [node.resource.revision] : [],
),
}); });
export const specializeBindingSchema = ( export const specializeBindingSchema = (
+53 -14
View File
@@ -47,7 +47,7 @@ export type ResolvedCapabilityResource = {
source: GitSource; source: GitSource;
directory: string; directory: string;
lock: QuixosRepositoryLock; lock: QuixosRepositoryLock;
resource: CapabilityResource; resource: CapabilityResource | { kind: "build" };
dependencies: ReadonlyMap<string, ResolvedCapabilityResource>; dependencies: ReadonlyMap<string, ResolvedCapabilityResource>;
}; };
@@ -56,13 +56,15 @@ export type CompiledWorkspaceRepository = {
plan: CompiledWorkspaceRevision; plan: CompiledWorkspaceRevision;
lock: QuixosRepositoryLock; lock: QuixosRepositoryLock;
resources: ResolvedCapabilityResource[]; resources: ResolvedCapabilityResource[];
capabilityResources: ResolvedCapabilityResource[];
directResources: ReadonlyMap<string, ResolvedCapabilityResource>; directResources: ReadonlyMap<string, ResolvedCapabilityResource>;
}; };
export type CompiledCapabilityResourceRepository = { export type CompiledCapabilityResourceRepository = {
resource: CapabilityResource; resource: CapabilityResource | { kind: "build" };
lock: QuixosRepositoryLock; lock: QuixosRepositoryLock;
resources: ResolvedCapabilityResource[]; resources: ResolvedCapabilityResource[];
capabilityResources: ResolvedCapabilityResource[];
directResources: ReadonlyMap<string, ResolvedCapabilityResource>; directResources: ReadonlyMap<string, ResolvedCapabilityResource>;
}; };
@@ -79,7 +81,10 @@ const assertImportsMatchLock = (
resources: readonly LockedResource[], resources: readonly LockedResource[],
) => { ) => {
const authored = [...imports].map(importsKey).sort(); const authored = [...imports].map(importsKey).sort();
const locked = [...resources].map(importsKey).sort(); const locked = resources
.filter((entry) => entry.kind !== "build")
.map(importsKey)
.sort();
if (authored.length !== locked.length || authored.some((entry, index) => entry !== locked[index])) { if (authored.length !== locked.length || authored.some((entry, index) => entry !== locked[index])) {
throw new Error( throw new Error(
`${label} imports do not match quixos.lock:\n` + `${label} imports do not match quixos.lock:\n` +
@@ -137,13 +142,19 @@ const diagnosticsMessage = (
}) })
.join("\n")}`; .join("\n")}`;
const revisionFor = (node: ResolvedCapabilityResource) => node.resource.revision; const revisionFor = (node: ResolvedCapabilityResource) => {
if (node.resource.kind === "build") throw Error("Build sources have no capability revision");
return node.resource.revision;
};
const resourceClosure = (roots: readonly ResolvedCapabilityResource[]): ResolvedCapabilityResource[] => { const resourceClosure = (
roots: readonly ResolvedCapabilityResource[],
capabilityOnly = false,
): ResolvedCapabilityResource[] => {
const result: ResolvedCapabilityResource[] = []; const result: ResolvedCapabilityResource[] = [];
const seen = new Set<string>(); const seen = new Set<string>();
const visit = (node: ResolvedCapabilityResource) => { const visit = (node: ResolvedCapabilityResource) => {
if (seen.has(node.key)) return; if (seen.has(node.key) || (capabilityOnly && node.kind === "build")) return;
seen.add(node.key); seen.add(node.key);
for (const dependency of node.dependencies.values()) visit(dependency); for (const dependency of node.dependencies.values()) visit(dependency);
result.push(node); result.push(node);
@@ -155,7 +166,12 @@ const resourceClosure = (roots: readonly ResolvedCapabilityResource[]): Resolved
const environmentFor = ( const environmentFor = (
direct: readonly [LockedResource, ResolvedCapabilityResource][], direct: readonly [LockedResource, ResolvedCapabilityResource][],
closure: readonly ResolvedCapabilityResource[], closure: readonly ResolvedCapabilityResource[],
): CapabilityImportEnvironment => ({ ): CapabilityImportEnvironment => {
closure = resourceClosure(
direct.map(([, node]) => node),
true,
);
return {
interfaces: new Map( interfaces: new Map(
direct.flatMap(([locked, node]) => direct.flatMap(([locked, node]) =>
node.resource.kind === "interface" ? [[locked.binding, node.resource.revision] as const] : [], node.resource.kind === "interface" ? [[locked.binding, node.resource.revision] as const] : [],
@@ -169,14 +185,17 @@ const environmentFor = (
interfaceClosure: exactRevisions( interfaceClosure: exactRevisions(
closure.flatMap((node) => [ closure.flatMap((node) => [
...(node.resource.kind === "interface" ? [node.resource.revision] : []), ...(node.resource.kind === "interface" ? [node.resource.revision] : []),
...(node.resource.specializations ?? []), ...(node.resource.kind === "build" ? [] : (node.resource.specializations ?? [])),
]), ]),
), ),
packageClosure: exactRevisions( packageClosure: exactRevisions(
closure.flatMap((node) => (node.resource.kind === "package" ? [node.resource.revision] : [])), closure.flatMap((node) => (node.resource.kind === "package" ? [node.resource.revision] : [])),
), ),
externalAtoms: exactAtoms(closure.flatMap((node) => node.resource.externalAtoms)), externalAtoms: exactAtoms(
}); closure.flatMap((node) => (node.resource.kind === "build" ? [] : node.resource.externalAtoms)),
),
};
};
const createResourceGraphResolver = (quixosCommit: string, resolveResource: CapabilityRepositoryResolver) => { const createResourceGraphResolver = (quixosCommit: string, resolveResource: CapabilityRepositoryResolver) => {
const resolved = new Map<string, Promise<ResolvedCapabilityResource>>(); const resolved = new Map<string, Promise<ResolvedCapabilityResource>>();
@@ -218,6 +237,19 @@ const createResourceGraphResolver = (quixosCommit: string, resolveResource: Capa
for (const dependency of lockResult.lock.resources) { for (const dependency of lockResult.lock.resources) {
directPairs.push([dependency, await visit(dependency)]); directPairs.push([dependency, await visit(dependency)]);
} }
if (locked.kind === "build") {
return {
key,
kind: locked.kind,
source: locked.source,
directory: snapshot.directory,
lock: lockResult.lock,
resource: { kind: "build" as const },
dependencies: new Map(
directPairs.map(([dependency, node]) => [bindingKey(dependency.kind, dependency.binding), node]),
),
};
}
const dependencyClosure = resourceClosure(directPairs.map(([, node]) => node)); const dependencyClosure = resourceClosure(directPairs.map(([, node]) => node));
const environment = environmentFor(directPairs, dependencyClosure); const environment = environmentFor(directPairs, dependencyClosure);
const manifestName = locked.kind === "interface" ? "interface.qx" : "package.qx"; const manifestName = locked.kind === "interface" ? "interface.qx" : "package.qx";
@@ -332,6 +364,7 @@ export const compileCapabilityResourceRepository = async (options: {
resource: root.resource, resource: root.resource,
lock: root.lock, lock: root.lock,
resources: await resolver.nodes(), resources: await resolver.nodes(),
capabilityResources: resourceClosure([root], true),
directResources: root.dependencies, directResources: root.dependencies,
}; };
}; };
@@ -376,11 +409,13 @@ export const compileWorkspaceRepository = async (options: {
); );
} }
assertImportsMatchLock(workspacePath, compiled.imports, rootLock.resources); assertImportsMatchLock(workspacePath, compiled.imports, rootLock.resources);
const availableInterfaceIds = new Set( const availableInterfaceIds = new Set((environment.interfaceClosure ?? []).map((iface) => iface.revisionId));
nodes.flatMap((node) => (node.resource.kind === "interface" ? [node.resource.revision.revisionId] : [])),
);
const availableAtomIds = new Set(compiled.workspace.atoms.map((atom) => atom.id)); const availableAtomIds = new Set(compiled.workspace.atoms.map((atom) => atom.id));
for (const node of nodes) { for (const node of resourceClosure(
directPairs.map(([, node]) => node),
true,
)) {
if (node.resource.kind === "build") continue;
for (const requirement of node.resource.externalInterfaces) { for (const requirement of node.resource.externalInterfaces) {
if (!availableInterfaceIds.has(requirement.revisionId)) { if (!availableInterfaceIds.has(requirement.revisionId)) {
throw new Error( throw new Error(
@@ -430,6 +465,10 @@ export const compileWorkspaceRepository = async (options: {
plan: checked.plan, plan: checked.plan,
lock: rootLock, lock: rootLock,
resources: nodes, resources: nodes,
capabilityResources: resourceClosure(
directPairs.map(([, node]) => node),
true,
),
directResources: new Map(directPairs.map(([locked, node]) => [bindingKey(locked.kind, locked.binding), node])), directResources: new Map(directPairs.map(([locked, node]) => [bindingKey(locked.kind, locked.binding), node])),
}; };
}; };
+2 -2
View File
@@ -3,7 +3,7 @@ import path from "node:path";
import { loadQuixosLock, type GitSource } from "../resource-lock/index.js"; import { loadQuixosLock, type GitSource } from "../resource-lock/index.js";
export type AuthoringResource = { export type AuthoringResource = {
kind: "workspace" | "interface" | "package"; kind: "workspace" | "interface" | "package" | "build";
directory: string; directory: string;
resourceId?: string; resourceId?: string;
source?: GitSource; source?: GitSource;
@@ -31,7 +31,7 @@ export async function authoringContext(start: string) {
if (typeof entry.directory === "string" && path.isAbsolute(entry.directory)) if (typeof entry.directory === "string" && path.isAbsolute(entry.directory))
entry.directory = path.relative(workbench, entry.directory); entry.directory = path.relative(workbench, entry.directory);
if ( if (
!["interface", "package"].includes(entry.kind) || !["interface", "package", "build"].includes(entry.kind) ||
!entry.source || !entry.source ||
!/^resources\/[A-Za-z0-9][A-Za-z0-9._-]*$/.test(entry.directory) !/^resources\/[A-Za-z0-9][A-Za-z0-9._-]*$/.test(entry.directory)
) { ) {
+1 -1
View File
@@ -69,7 +69,7 @@ export async function inspectAuthoringRepository(root: string, historyLimit = 10
declarations: syntax declarations: syntax
? [...walkSyntax(syntax.root)] ? [...walkSyntax(syntax.root)]
.filter((node) => .filter((node) =>
/^(?:interface|package|atom|state|edge|method|function|event|conformance|component|presentation)\w*Decl$/.test( /^(?:(?:interface|package|atom|state|edge|method|function|event|conformance|presentation)\w*Decl|module(?:Member|Export))$/.test(
node.kind, node.kind,
), ),
) )
+2 -1
View File
@@ -209,7 +209,7 @@ export const checkWorkspaceCandidate = async (options: {
: []; : [];
const evolution = planEvolution(baseline, compiled.workspace, { reviews }); const evolution = planEvolution(baseline, compiled.workspace, { reviews });
blockers.push(...evolution.blockers); blockers.push(...evolution.blockers);
for (const resource of compiled.resources.filter((entry) => entry.kind === "package")) { for (const resource of compiled.capabilityResources.filter((entry) => entry.kind === "package")) {
// Per-package recursive schema, identical to host activation, not unrelated // Per-package recursive schema, identical to host activation, not unrelated
// workspace declarations that would unnecessarily invalidate build caches. // workspace declarations that would unnecessarily invalidate build caches.
const candidate = await compileCapabilityResourceRepository({ const candidate = await compileCapabilityResourceRepository({
@@ -218,6 +218,7 @@ export const checkWorkspaceCandidate = async (options: {
source: resource.source, source: resource.source,
resolveResource, resolveResource,
}); });
if (candidate.resource.kind !== "package") throw Error("Expected checked package contract");
const schema = path.join(temporary, "bindings.json"); const schema = path.join(temporary, "bindings.json");
await fs.writeFile( await fs.writeFile(
schema, schema,
+1 -1
View File
@@ -107,7 +107,7 @@ export async function buildCheckedPackage(source: string, schema: string, packag
* nested fetches. Keep build noise in a named log, with a bounded failure tail. */ * nested fetches. Keep build noise in a named log, with a bounded failure tail. */
export async function buildImmutableCandidate( export async function buildImmutableCandidate(
source: { repository: string; commit: string }, source: { repository: string; commit: string },
kind: "workspace" | "interface" | "package", kind: "workspace" | "interface" | "package" | "build",
logFile: string, logFile: string,
contractOnly = false, contractOnly = false,
): Promise<string> { ): Promise<string> {
@@ -56,7 +56,7 @@ export async function executionScaffold(
flake-utils.lib.eachDefaultSystem (system: let flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs { inherit system; }; pkgs = import nixpkgs { inherit system; };
in { in {
quixosPackages.checkedArtifacts = { plan, generator, core, sharedRuntime, typescript, packageRevisionId, react ? null }: quixosPackages.checkedArtifacts = { plan, generator, core, sharedRuntime, typescript, packageRevisionId, react ? null, ... }:
(import (helpers + "/artifacts.nix")) { (import (helpers + "/artifacts.nix")) {
inherit pkgs plan core sharedRuntime typescript packageRevisionId; inherit pkgs plan core sharedRuntime typescript packageRevisionId;
protocol = generator; protocol = generator;
+1 -1
View File
@@ -38,7 +38,7 @@ export const createGitCapabilityResolver = async (options: {
}>; }>;
}; };
for (const entry of document.resources ?? []) { for (const entry of document.resources ?? []) {
if (entry.kind !== "interface" && entry.kind !== "package") { if (entry.kind !== "interface" && entry.kind !== "package" && entry.kind !== "build") {
throw new Error(`Snapshot map has unsupported resource kind ${entry.kind}`); throw new Error(`Snapshot map has unsupported resource kind ${entry.kind}`);
} }
const key = sourceKey(entry.kind, entry.repository, entry.commit); const key = sourceKey(entry.kind, entry.repository, entry.commit);
+9 -5
View File
@@ -19,7 +19,7 @@ import { planEvolution, type WorkspaceRevision, type EvolutionReview } from "../
import { withFileLock } from "./file-lock.js"; import { withFileLock } from "./file-lock.js";
const execFile = promisify(callback); const execFile = promisify(callback);
type Source = { repository: string; commit: string }; type Source = { repository: string; commit: string };
export type UpgradeNode = { kind: "workspace" | "package" | "interface"; directory: string; source: Source }; export type UpgradeNode = { kind: "workspace" | "package" | "interface" | "build"; directory: string; source: Source };
export type UpgradeSpec = { export type UpgradeSpec = {
nodes: UpgradeNode[]; nodes: UpgradeNode[];
quixos?: Source; quixos?: Source;
@@ -105,7 +105,7 @@ export const discoverUpgradeSpec = async (workbench: string): Promise<UpgradeSpe
commit: await command(root, "jj", ["--ignore-working-copy", "log", "--no-graph", "-r", "@", "-T", "commit_id"]), commit: await command(root, "jj", ["--ignore-working-copy", "log", "--no-graph", "-r", "@", "-T", "commit_id"]),
}, },
}, },
...graph.resources.map((entry: { kind: "interface" | "package"; directory: string; source: Source }) => ({ ...graph.resources.map((entry: { kind: "interface" | "package" | "build"; directory: string; source: Source }) => ({
kind: entry.kind, kind: entry.kind,
source: entry.source, source: entry.source,
directory: path.relative(workbench, path.resolve(workbench, entry.directory)), directory: path.relative(workbench, path.resolve(workbench, entry.directory)),
@@ -139,7 +139,7 @@ export const planPinUpgrades = async (workbenchPath: string, spec: UpgradeSpec):
const keys = new Map<string, string>(); const keys = new Map<string, string>();
for (const node of spec.nodes) { for (const node of spec.nodes) {
validSource(node.source); validSource(node.source);
if (!["workspace", "package", "interface"].includes(node.kind) || keys.has(sourceKey(node))) if (!["workspace", "package", "interface", "build"].includes(node.kind) || keys.has(sourceKey(node)))
throw new Error("Duplicate/invalid upgrade resource identity"); throw new Error("Duplicate/invalid upgrade resource identity");
keys.set(sourceKey(node), node.directory); keys.set(sourceKey(node), node.directory);
} }
@@ -423,14 +423,14 @@ export const applyPinUpgrades = async (
const directory = await location(plan.workbench, node.directory); const directory = await location(plan.workbench, node.directory);
const standalone = await compileCapabilityResourceRepository({ const standalone = await compileCapabilityResourceRepository({
rootDirectory: directory, rootDirectory: directory,
kind: node.kind as "package" | "interface", kind: node.kind as "package" | "interface" | "build",
source, source,
resolveResource, resolveResource,
}); });
for (const dependency of standalone.resources) resources.set(dependency.key, dependency); for (const dependency of standalone.resources) resources.set(dependency.key, dependency);
resources.set(key, { resources.set(key, {
key, key,
kind: node.kind as "package" | "interface", kind: node.kind as "package" | "interface" | "build",
source, source,
directory, directory,
lock: standalone.lock, lock: standalone.lock,
@@ -450,11 +450,15 @@ export const applyPinUpgrades = async (
kind: node.kind, kind: node.kind,
source: node.source, source: node.source,
directory: node.directory, directory: node.directory,
...(node.resource.kind === "build"
? {}
: {
resourceId: resourceId:
node.resource.kind === "interface" node.resource.kind === "interface"
? node.resource.revision.interfaceId ? node.resource.revision.interfaceId
: node.resource.revision.packageId, : node.resource.revision.packageId,
revisionId: node.resource.revision.revisionId, revisionId: node.resource.revision.revisionId,
}),
dependencies: [...node.dependencies.entries()].map(([binding, dependency]) => ({ dependencies: [...node.dependencies.entries()].map(([binding, dependency]) => ({
binding, binding,
resourceKey: dependency.key, resourceKey: dependency.key,
+12 -2
View File
@@ -6,7 +6,7 @@ import { bindingSchema } from "../bindings/index.js";
import { compileCapabilityResourceRepository, type ResolvedCapabilityResource } from "./assembly.js"; import { compileCapabilityResourceRepository, type ResolvedCapabilityResource } from "./assembly.js";
import { createGitCapabilityResolver } from "./git-resolver.js"; import { createGitCapabilityResolver } from "./git-resolver.js";
const usage = `usage: quixos-resource-compile --root DIRECTORY --kind interface|package const usage = `usage: quixos-resource-compile --root DIRECTORY --kind interface|package|build
--repository URL --commit GIT_REV --checkout-root DIRECTORY --repository URL --commit GIT_REV --checkout-root DIRECTORY
[--snapshot-map PATH] [--snapshot-only true] [--graph-out PATH] [--schema-out PATH] [--snapshot-map PATH] [--snapshot-only true] [--graph-out PATH] [--schema-out PATH]
@@ -41,7 +41,13 @@ const parseArgs = (args: string[]) => {
const repository = values.get("--repository"); const repository = values.get("--repository");
const commit = values.get("--commit")?.toLowerCase(); const commit = values.get("--commit")?.toLowerCase();
const checkoutRoot = values.get("--checkout-root"); const checkoutRoot = values.get("--checkout-root");
if (!rootDirectory || !repository || !commit || !checkoutRoot || (kind !== "interface" && kind !== "package")) { if (
!rootDirectory ||
!repository ||
!commit ||
!checkoutRoot ||
(kind !== "interface" && kind !== "package" && kind !== "build")
) {
throw new Error(usage); throw new Error(usage);
} }
if (!/^([0-9a-f]{40}|[0-9a-f]{64})$/.test(commit)) { if (!/^([0-9a-f]{40}|[0-9a-f]{64})$/.test(commit)) {
@@ -67,9 +73,13 @@ const graphEntry = (node: ResolvedCapabilityResource) => ({
kind: node.kind, kind: node.kind,
source: node.source, source: node.source,
directory: node.directory, directory: node.directory,
...(node.resource.kind === "build"
? {}
: {
resourceId: resourceId:
node.resource.kind === "interface" ? node.resource.revision.interfaceId : node.resource.revision.packageId, node.resource.kind === "interface" ? node.resource.revision.interfaceId : node.resource.revision.packageId,
revisionId: node.resource.revision.revisionId, revisionId: node.resource.revision.revisionId,
}),
dependencies: [...node.dependencies.entries()].map(([binding, dependency]) => ({ dependencies: [...node.dependencies.entries()].map(([binding, dependency]) => ({
binding, binding,
resourceKey: dependency.key, resourceKey: dependency.key,
+4 -2
View File
@@ -15,7 +15,7 @@ export type StructuralEdit =
| { operation: "quixos-pin"; source: { repository: string; commit: string } } | { operation: "quixos-pin"; source: { repository: string; commit: string } }
| { | {
operation: "dependency"; operation: "dependency";
kind: "interface" | "package"; kind: "interface" | "package" | "build";
name: string; name: string;
source: { repository: string; commit: string } | null; source: { repository: string; commit: string } | null;
}; };
@@ -29,6 +29,8 @@ const selectable = new Set([
"packageResourceDecl", "packageResourceDecl",
"atomDecl", "atomDecl",
"valueMember", "valueMember",
"moduleMember",
"moduleExport",
"relationshipMember", "relationshipMember",
"operationMember", "operationMember",
"packageOperationExport", "packageOperationExport",
@@ -155,7 +157,7 @@ export const editStructure = (source: string, edit: StructuralEdit): string => {
if (edit.operation === "dependency") { if (edit.operation === "dependency") {
const parsed = parseQuixosLockDocument(source); const parsed = parseQuixosLockDocument(source);
if (!parsed.ok) throw new Error("Cannot scaffold an invalid lockfile"); if (!parsed.ok) throw new Error("Cannot scaffold an invalid lockfile");
if (!["interface", "package"].includes(edit.kind) || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(edit.name)) if (!["interface", "package", "build"].includes(edit.kind) || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(edit.name))
throw new Error("Invalid dependency selector"); throw new Error("Invalid dependency selector");
const parser = new QuixosLockParser(new CommonTokenStream(new QuixosLockLexer(CharStream.fromString(source)))); const parser = new QuixosLockParser(new CommonTokenStream(new QuixosLockLexer(CharStream.fromString(source))));
const tree = parser.document(); const tree = parser.document();
+3 -3
View File
@@ -13,7 +13,7 @@ import { parseQuixosLockDocument } from "../resource-lock/index.js";
import { withFileLock } from "./file-lock.js"; import { withFileLock } from "./file-lock.js";
export type StructuralRequest = { export type StructuralRequest = {
kind: "workspace" | "interface" | "package"; kind: "workspace" | "interface" | "package" | "build";
source?: { repository: string; commit: string }; source?: { repository: string; commit: string };
resourceRoot?: string; resourceRoot?: string;
validation?: "syntax" | "resource-graph"; validation?: "syntax" | "resource-graph";
@@ -159,10 +159,10 @@ export const planStructure = async (rootPath: string, request: StructuralRequest
const resourceRoot = path.join(snapshot.directory, request.resourceRoot ?? ""); const resourceRoot = path.join(snapshot.directory, request.resourceRoot ?? "");
if (request.kind === "workspace") if (request.kind === "workspace")
await compileWorkspaceRepository({ rootDirectory: resourceRoot, resolveResource }); await compileWorkspaceRepository({ rootDirectory: resourceRoot, resolveResource });
else if (["package", "interface"].includes(request.kind) && request.source) { else if (["package", "interface", "build"].includes(request.kind) && request.source) {
const compiled = await compileCapabilityResourceRepository({ const compiled = await compileCapabilityResourceRepository({
rootDirectory: resourceRoot, rootDirectory: resourceRoot,
kind: request.kind as "package" | "interface", kind: request.kind as "package" | "interface" | "build",
source: { resolver: "git", ...request.source }, source: { resolver: "git", ...request.source },
resolveResource, resolveResource,
}); });
+46 -16
View File
@@ -192,16 +192,16 @@ const main = async () => {
} }
if (command === "check-committed" && !args.includes("--help")) { if (command === "check-committed" && !args.includes("--help")) {
const [kind, repository, commit, log, ...extra] = args; const [kind, repository, commit, log, ...extra] = args;
if (!["workspace", "interface", "package"].includes(kind) || !log || extra.length) if (!["workspace", "interface", "package", "build"].includes(kind) || !log || extra.length)
throw new Error("usage: quixos-qx check-committed workspace|interface|package REPOSITORY COMMIT LOG_FILE"); throw new Error("usage: quixos-qx check-committed workspace|interface|package|build REPOSITORY COMMIT LOG_FILE");
process.stdout.write( process.stdout.write(
`${await buildImmutableCandidate({ repository, commit }, kind as "workspace" | "interface" | "package", log)}\n`, `${await buildImmutableCandidate({ repository, commit }, kind as "workspace" | "interface" | "package" | "build", log)}\n`,
); );
return; return;
} }
if (!command || command === "--help" || args.includes("--help")) { if (!command || command === "--help" || args.includes("--help")) {
process.stdout.write( process.stdout.write(
"quixos-qx: author-check, author-contract, converge, worklist, inspect, resources, check-committed, source-baseline, scaffold-package, scaffold-interface, scaffold-function, scaffold-query, scaffold-dependency, scaffold-structure, scaffold-resume, pin-upgrade, parse, lint, format\n" + "quixos-qx: author-check, author-contract, converge, worklist, inspect, resources, check-committed, source-baseline, scaffold-package, scaffold-interface, scaffold-build, scaffold-function, scaffold-query, scaffold-dependency, scaffold-structure, scaffold-resume, pin-upgrade, parse, lint, format\n" +
"inspect WORKBENCH [RESOURCE] shows provisional contracts, with explicit historical fallback; never verification evidence.\n" + "inspect WORKBENCH [RESOURCE] shows provisional contracts, with explicit historical fallback; never verification evidence.\n" +
"resources WORKBENCH lists registered editable repositories. Use qx-workspace for the workspace authoring workflow.\n", "resources WORKBENCH lists registered editable repositories. Use qx-workspace for the workspace authoring workflow.\n",
); );
@@ -226,7 +226,7 @@ const main = async () => {
if (flags.length && !flags[0].startsWith("--")) { if (flags.length && !flags[0].startsWith("--")) {
repository = flags.shift(); repository = flags.shift();
commit = flags.shift(); commit = flags.shift();
} else if (root && ["interface", "package"].includes(kind) && name) { } else if (root && ["interface", "package", "build"].includes(kind) && name) {
const context = await authoringContext(root); const context = await authoringContext(root);
const alias = await realpath(path.join(context.workbench, `${kind}s`, name)).catch(() => null); const alias = await realpath(path.join(context.workbench, `${kind}s`, name)).catch(() => null);
const matches = context.resources.filter( const matches = context.resources.filter(
@@ -256,15 +256,17 @@ const main = async () => {
} }
if ( if (
!root || !root ||
!["interface", "package"].includes(kind) || !["interface", "package", "build"].includes(kind) ||
!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name ?? "") || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(name ?? "") ||
!repository || !repository ||
!commit || !commit ||
flags.some((flag) => flag !== "--write") flags.some((flag) => flag !== "--write")
) )
throw new Error("usage: quixos-qx scaffold-dependency ROOT interface|package NAME REPOSITORY COMMIT [--write]"); throw new Error(
const resourceKind = kind as "package" | "interface"; "usage: quixos-qx scaffold-dependency ROOT interface|package|build NAME REPOSITORY COMMIT [--write]",
let entrypoint: "workspace" | "package" | "interface" | undefined; );
const resourceKind = kind as "package" | "interface" | "build";
let entrypoint: "workspace" | "package" | "interface" | "build" | undefined;
for (const candidate of ["workspace", "package", "interface"] as const) { for (const candidate of ["workspace", "package", "interface"] as const) {
try { try {
await readFile(path.join(root, `${candidate}.qx`)); await readFile(path.join(root, `${candidate}.qx`));
@@ -274,7 +276,14 @@ const main = async () => {
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error; if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
} }
} }
if (!entrypoint) throw new Error("No QX repository entrypoint"); if (!entrypoint) {
const context = await authoringContext(root);
const selected = context.resources.find(
(entry) => path.join(context.workbench, entry.directory) === path.resolve(root),
);
if (selected?.kind !== "build") throw new Error("No QX repository entrypoint");
entrypoint = "build";
}
const lock = await loadQuixosLock(path.join(root, "quixos.lock")); const lock = await loadQuixosLock(path.join(root, "quixos.lock"));
if (!lock.ok) throw new Error("Invalid resource lock"); if (!lock.ok) throw new Error("Invalid resource lock");
let target = "quixos.lock"; let target = "quixos.lock";
@@ -288,7 +297,9 @@ const main = async () => {
source: await authorSource(root), source: await authorSource(root),
validation: "syntax", validation: "syntax",
files: [ files: [
{ file: `${entrypoint}.qx`, edits: [{ operation: "import", kind: resourceKind, name }] }, ...(entrypoint !== "build" && resourceKind !== "build"
? [{ file: `${entrypoint}.qx`, edits: [{ operation: "import" as const, kind: resourceKind, name }] }]
: []),
{ {
file: target, file: target,
edits: [{ operation: "dependency", kind: resourceKind, name, source: { repository, commit } }], edits: [{ operation: "dependency", kind: resourceKind, name, source: { repository, commit } }],
@@ -301,26 +312,45 @@ const main = async () => {
); );
return; return;
} }
if (command === "scaffold-interface") { if (command === "scaffold-interface" || command === "scaffold-build") {
const isBuild = command === "scaffold-build";
const [root, specFile, ...flags] = args; const [root, specFile, ...flags] = args;
if (!root || !specFile || flags.some((flag) => flag !== "--write")) if (!root || !specFile || flags.some((flag) => flag !== "--write"))
throw new Error("usage: quixos-qx scaffold-interface ROOT SPEC_JSON [--write]"); throw new Error("usage: quixos-qx scaffold-interface|scaffold-build ROOT SPEC_JSON [--write]");
const spec = (await readSpec(specFile)) as ScaffoldRecipe; const spec = (await readSpec(specFile)) as ScaffoldRecipe;
if (!spec.name || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(spec.name) || !spec.id || !spec.revision || !spec.tools?.quixos) if (
throw new Error("Interface scaffold requires name, id, revision and Quixos toolchain source"); !spec.name ||
!/^[A-Za-z_][A-Za-z0-9_]*$/.test(spec.name) ||
(!isBuild && (!spec.id || !spec.revision)) ||
!spec.tools?.quixos
)
throw new Error(
isBuild
? "Build scaffold requires name and Quixos toolchain source"
: "Interface scaffold requires name, id, revision and Quixos toolchain source",
);
const request: StructuralRequest = { const request: StructuralRequest = {
kind: "interface", kind: isBuild ? "build" : "interface",
// Like package scaffolding, declaration creation is provisional. Imports // Like package scaffolding, declaration creation is provisional. Imports
// can be attached next; the normal check verifies the complete graph. // can be attached next; the normal check verifies the complete graph.
validation: "syntax", validation: "syntax",
source: spec.source, source: spec.source,
files: [ files: [
...(!isBuild
? [
{ {
file: "interface.qx", file: "interface.qx",
create: create:
spec.declaration ?? spec.declaration ??
`interface ${spec.name} id ${JSON.stringify(spec.id)} revision ${JSON.stringify(spec.revision)} {\n}\n`, `interface ${spec.name} id ${JSON.stringify(spec.id)} revision ${JSON.stringify(spec.revision)} {\n}\n`,
}, },
]
: [
{
file: "README.md",
create: `# ${spec.name}\n\nManaged build dependency. Consumers select sources or Nix outputs through context.dependencies.\n`,
},
]),
{ {
file: "quixos.lock", file: "quixos.lock",
create: formatQuixosLock({ create: formatQuixosLock({
+7 -2
View File
@@ -83,11 +83,15 @@ const main = async () => {
kind: node.kind, kind: node.kind,
source: node.source, source: node.source,
directory: node.directory, directory: node.directory,
...(node.resource.kind === "build"
? {}
: {
resourceId: resourceId:
node.resource.kind === "interface" node.resource.kind === "interface"
? node.resource.revision.interfaceId ? node.resource.revision.interfaceId
: node.resource.revision.packageId, : node.resource.revision.packageId,
revisionId: node.resource.revision.revisionId, revisionId: node.resource.revision.revisionId,
}),
dependencies: [...node.dependencies.entries()].map(([binding, dependency]) => ({ dependencies: [...node.dependencies.entries()].map(([binding, dependency]) => ({
binding, binding,
resourceKey: dependency.key, resourceKey: dependency.key,
@@ -108,14 +112,15 @@ const main = async () => {
} }
if (options.schemasOut) { if (options.schemasOut) {
const schemas: Record<string, unknown> = {}; const schemas: Record<string, unknown> = {};
for (const node of assembled.resources.filter((entry) => entry.kind === "package")) { for (const node of assembled.capabilityResources.filter((entry) => entry.kind === "package")) {
const closure = new Map<string, typeof node>(); const closure = new Map<string, typeof node>();
const visit = (entry: typeof node) => { const visit = (entry: typeof node) => {
if (closure.has(entry.key)) return; if (closure.has(entry.key) || entry.kind === "build") return;
closure.set(entry.key, entry); closure.set(entry.key, entry);
entry.dependencies.forEach(visit); entry.dependencies.forEach(visit);
}; };
visit(node); visit(node);
if (node.resource.kind !== "package") continue;
schemas[node.resource.revision.revisionId] = specializeBindingSchema( schemas[node.resource.revision.revisionId] = specializeBindingSchema(
bindingSchema({ resources: [...closure.values()] }), bindingSchema({ resources: [...closure.values()] }),
candidate, candidate,
+9 -5
View File
@@ -137,6 +137,7 @@ export function generatePackageQueryClientBindings(
export function generateComponentClientBindings(plan: ExecutionPlan, packageRevision: string): string { export function generateComponentClientBindings(plan: ExecutionPlan, packageRevision: string): string {
const pkg = plan.definition.workspace.packageImports.find((pkg) => pkg.revisionId === packageRevision); const pkg = plan.definition.workspace.packageImports.find((pkg) => pkg.revisionId === packageRevision);
const components = plan.definition.packages.find((pkg) => pkg.revision === packageRevision)?.components; const components = plan.definition.packages.find((pkg) => pkg.revision === packageRevision)?.components;
const modules = plan.definition.packages.find((pkg) => pkg.revision === packageRevision)?.modules ?? [];
if (!pkg || !components?.length) if (!pkg || !components?.length)
throw new ExecutionPlanError("NO_COMPONENT_CONTRACT", packageRevision, "Package declares no component entries"); throw new ExecutionPlanError("NO_COMPONENT_CONTRACT", packageRevision, "Package declares no component entries");
const byId = new Map(plan.definition.workspace.interfaceImports.map((iface) => [iface.revisionId as string, iface])); const byId = new Map(plan.definition.workspace.interfaceImports.map((iface) => [iface.revisionId as string, iface]));
@@ -166,12 +167,15 @@ export function generateComponentClientBindings(plan: ExecutionPlan, packageRevi
subjectBindings + subjectBindings +
"\n" + "\n" +
queries + queries +
"\nexport interface Components {\n" + "\nexport interface ModuleProps {}\n" +
"export type ExtraModuleProps<K extends string> = K extends keyof ModuleProps ? ModuleProps[K] : {};\n" +
"export interface Modules {\n" +
components components
.map( .map((component) => {
(component) => const module = modules.find((module) => module.id === component.id)!;
`${JSON.stringify(component.displayName)}: ComponentType<ComponentProps<${JSON.stringify(component.subject)}>>;`, const key = JSON.stringify([module.interfaceRevisionId, module.memberId]);
) return `${JSON.stringify(component.displayName)}: ComponentType<ComponentProps<${JSON.stringify(component.subject)}> & ExtraModuleProps<${JSON.stringify(key)}>>;`;
})
.join("\n") + .join("\n") +
"\n}\n" "\n}\n"
); );
+7 -1
View File
@@ -39,7 +39,13 @@ export function expectedArtifactReceipt(
// A process service may implement transactions in any language. Only the // A process service may implement transactions in any language. Only the
// checked JS module path promises generated TypeScript adapter evidence. // checked JS module path promises generated TypeScript adapter evidence.
const available = new Set( const available = new Set(
manifest.implementations.filter((i) => i.compatibility === "quixos-js-module-v1").map((i) => i.target), manifest.implementations
.filter(
(i) =>
i.compatibility === "quixos-js-module-v1" &&
i.exports.some((id) => pkg.exports.some((entry) => entry.id === id && entry.execution.kind !== "remote")),
)
.map((i) => i.target),
); );
const targets = [ const targets = [
...new Set( ...new Set(
@@ -7,6 +7,7 @@ null
'source' 'source'
'interface' 'interface'
'package' 'package'
'build'
'repository' 'repository'
'commit' 'commit'
'policy' 'policy'
@@ -34,6 +35,7 @@ QUIXOS
SOURCE SOURCE
INTERFACE INTERFACE
PACKAGE PACKAGE
BUILD
REPOSITORY REPOSITORY
COMMIT COMMIT
POLICY POLICY
@@ -66,4 +68,4 @@ stringLiteral
atn: atn:
[4, 1, 24, 87, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 1, 0, 1, 0, 3, 0, 23, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 31, 8, 0, 10, 0, 12, 0, 34, 9, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 74, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 0, 0, 10, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 0, 2, 1, 0, 6, 7, 1, 0, 12, 14, 81, 0, 20, 1, 0, 0, 0, 2, 38, 1, 0, 0, 0, 4, 42, 1, 0, 0, 0, 6, 47, 1, 0, 0, 0, 8, 51, 1, 0, 0, 0, 10, 53, 1, 0, 0, 0, 12, 62, 1, 0, 0, 0, 14, 80, 1, 0, 0, 0, 16, 82, 1, 0, 0, 0, 18, 84, 1, 0, 0, 0, 20, 22, 5, 1, 0, 0, 21, 23, 5, 2, 0, 0, 22, 21, 1, 0, 0, 0, 22, 23, 1, 0, 0, 0, 23, 24, 1, 0, 0, 0, 24, 25, 5, 3, 0, 0, 25, 26, 5, 19, 0, 0, 26, 32, 5, 16, 0, 0, 27, 31, 3, 2, 1, 0, 28, 31, 3, 6, 3, 0, 29, 31, 3, 4, 2, 0, 30, 27, 1, 0, 0, 0, 30, 28, 1, 0, 0, 0, 30, 29, 1, 0, 0, 0, 31, 34, 1, 0, 0, 0, 32, 30, 1, 0, 0, 0, 32, 33, 1, 0, 0, 0, 33, 35, 1, 0, 0, 0, 34, 32, 1, 0, 0, 0, 35, 36, 5, 17, 0, 0, 36, 37, 5, 0, 0, 1, 37, 1, 1, 0, 0, 0, 38, 39, 5, 4, 0, 0, 39, 40, 5, 5, 0, 0, 40, 41, 3, 12, 6, 0, 41, 3, 1, 0, 0, 0, 42, 43, 3, 8, 4, 0, 43, 44, 3, 16, 8, 0, 44, 45, 5, 5, 0, 0, 45, 46, 3, 10, 5, 0, 46, 5, 1, 0, 0, 0, 47, 48, 5, 15, 0, 0, 48, 49, 3, 18, 9, 0, 49, 50, 5, 18, 0, 0, 50, 7, 1, 0, 0, 0, 51, 52, 7, 0, 0, 0, 52, 9, 1, 0, 0, 0, 53, 54, 5, 16, 0, 0, 54, 55, 5, 8, 0, 0, 55, 56, 3, 18, 9, 0, 56, 57, 5, 18, 0, 0, 57, 58, 5, 9, 0, 0, 58, 59, 3, 18, 9, 0, 59, 60, 5, 18, 0, 0, 60, 61, 5, 17, 0, 0, 61, 11, 1, 0, 0, 0, 62, 63, 5, 16, 0, 0, 63, 64, 5, 8, 0, 0, 64, 65, 3, 18, 9, 0, 65, 73, 5, 18, 0, 0, 66, 67, 5, 10, 0, 0, 67, 68, 3, 14, 7, 0, 68, 69, 5, 18, 0, 0, 69, 70, 5, 11, 0, 0, 70, 71, 3, 18, 9, 0, 71, 72, 5, 18, 0, 0, 72, 74, 1, 0, 0, 0, 73, 66, 1, 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 75, 1, 0, 0, 0, 75, 76, 5, 9, 0, 0, 76, 77, 3, 18, 9, 0, 77, 78, 5, 18, 0, 0, 78, 79, 5, 17, 0, 0, 79, 13, 1, 0, 0, 0, 80, 81, 7, 1, 0, 0, 81, 15, 1, 0, 0, 0, 82, 83, 5, 20, 0, 0, 83, 17, 1, 0, 0, 0, 84, 85, 5, 21, 0, 0, 85, 19, 1, 0, 0, 0, 4, 22, 30, 32, 73] [4, 1, 25, 87, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 1, 0, 1, 0, 3, 0, 23, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 31, 8, 0, 10, 0, 12, 0, 34, 9, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 74, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 0, 0, 10, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 0, 2, 1, 0, 6, 8, 1, 0, 13, 15, 81, 0, 20, 1, 0, 0, 0, 2, 38, 1, 0, 0, 0, 4, 42, 1, 0, 0, 0, 6, 47, 1, 0, 0, 0, 8, 51, 1, 0, 0, 0, 10, 53, 1, 0, 0, 0, 12, 62, 1, 0, 0, 0, 14, 80, 1, 0, 0, 0, 16, 82, 1, 0, 0, 0, 18, 84, 1, 0, 0, 0, 20, 22, 5, 1, 0, 0, 21, 23, 5, 2, 0, 0, 22, 21, 1, 0, 0, 0, 22, 23, 1, 0, 0, 0, 23, 24, 1, 0, 0, 0, 24, 25, 5, 3, 0, 0, 25, 26, 5, 20, 0, 0, 26, 32, 5, 17, 0, 0, 27, 31, 3, 2, 1, 0, 28, 31, 3, 6, 3, 0, 29, 31, 3, 4, 2, 0, 30, 27, 1, 0, 0, 0, 30, 28, 1, 0, 0, 0, 30, 29, 1, 0, 0, 0, 31, 34, 1, 0, 0, 0, 32, 30, 1, 0, 0, 0, 32, 33, 1, 0, 0, 0, 33, 35, 1, 0, 0, 0, 34, 32, 1, 0, 0, 0, 35, 36, 5, 18, 0, 0, 36, 37, 5, 0, 0, 1, 37, 1, 1, 0, 0, 0, 38, 39, 5, 4, 0, 0, 39, 40, 5, 5, 0, 0, 40, 41, 3, 12, 6, 0, 41, 3, 1, 0, 0, 0, 42, 43, 3, 8, 4, 0, 43, 44, 3, 16, 8, 0, 44, 45, 5, 5, 0, 0, 45, 46, 3, 10, 5, 0, 46, 5, 1, 0, 0, 0, 47, 48, 5, 16, 0, 0, 48, 49, 3, 18, 9, 0, 49, 50, 5, 19, 0, 0, 50, 7, 1, 0, 0, 0, 51, 52, 7, 0, 0, 0, 52, 9, 1, 0, 0, 0, 53, 54, 5, 17, 0, 0, 54, 55, 5, 9, 0, 0, 55, 56, 3, 18, 9, 0, 56, 57, 5, 19, 0, 0, 57, 58, 5, 10, 0, 0, 58, 59, 3, 18, 9, 0, 59, 60, 5, 19, 0, 0, 60, 61, 5, 18, 0, 0, 61, 11, 1, 0, 0, 0, 62, 63, 5, 17, 0, 0, 63, 64, 5, 9, 0, 0, 64, 65, 3, 18, 9, 0, 65, 73, 5, 19, 0, 0, 66, 67, 5, 11, 0, 0, 67, 68, 3, 14, 7, 0, 68, 69, 5, 19, 0, 0, 69, 70, 5, 12, 0, 0, 70, 71, 3, 18, 9, 0, 71, 72, 5, 19, 0, 0, 72, 74, 1, 0, 0, 0, 73, 66, 1, 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 75, 1, 0, 0, 0, 75, 76, 5, 10, 0, 0, 76, 77, 3, 18, 9, 0, 77, 78, 5, 19, 0, 0, 78, 79, 5, 18, 0, 0, 79, 13, 1, 0, 0, 0, 80, 81, 7, 1, 0, 0, 81, 15, 1, 0, 0, 0, 82, 83, 5, 21, 0, 0, 83, 17, 1, 0, 0, 0, 84, 85, 5, 22, 0, 0, 85, 19, 1, 0, 0, 0, 4, 22, 30, 32, 73]
+30 -28
View File
@@ -5,23 +5,24 @@ QUIXOS=4
SOURCE=5 SOURCE=5
INTERFACE=6 INTERFACE=6
PACKAGE=7 PACKAGE=7
REPOSITORY=8 BUILD=8
COMMIT=9 REPOSITORY=9
POLICY=10 COMMIT=10
REF=11 POLICY=11
PINNED=12 REF=12
TRACK_RELEASE=13 PINNED=13
TRACK_DEVELOPMENT=14 TRACK_RELEASE=14
IMPORT=15 TRACK_DEVELOPMENT=15
LBRACE=16 IMPORT=16
RBRACE=17 LBRACE=17
SEMI=18 RBRACE=18
INTEGER=19 SEMI=19
IDENTIFIER=20 INTEGER=20
STRING_LITERAL=21 IDENTIFIER=21
LINE_COMMENT=22 STRING_LITERAL=22
BLOCK_COMMENT=23 LINE_COMMENT=23
WS=24 BLOCK_COMMENT=24
WS=25
'quixos-lock'=1 'quixos-lock'=1
'fragment'=2 'fragment'=2
'version'=3 'version'=3
@@ -29,14 +30,15 @@ WS=24
'source'=5 'source'=5
'interface'=6 'interface'=6
'package'=7 'package'=7
'repository'=8 'build'=8
'commit'=9 'repository'=9
'policy'=10 'commit'=10
'ref'=11 'policy'=11
'pinned'=12 'ref'=12
'track-release'=13 'pinned'=13
'track-development'=14 'track-release'=14
'import'=15 'track-development'=15
'{'=16 'import'=16
'}'=17 '{'=17
';'=18 '}'=18
';'=19
File diff suppressed because one or more lines are too long
@@ -5,23 +5,24 @@ QUIXOS=4
SOURCE=5 SOURCE=5
INTERFACE=6 INTERFACE=6
PACKAGE=7 PACKAGE=7
REPOSITORY=8 BUILD=8
COMMIT=9 REPOSITORY=9
POLICY=10 COMMIT=10
REF=11 POLICY=11
PINNED=12 REF=12
TRACK_RELEASE=13 PINNED=13
TRACK_DEVELOPMENT=14 TRACK_RELEASE=14
IMPORT=15 TRACK_DEVELOPMENT=15
LBRACE=16 IMPORT=16
RBRACE=17 LBRACE=17
SEMI=18 RBRACE=18
INTEGER=19 SEMI=19
IDENTIFIER=20 INTEGER=20
STRING_LITERAL=21 IDENTIFIER=21
LINE_COMMENT=22 STRING_LITERAL=22
BLOCK_COMMENT=23 LINE_COMMENT=23
WS=24 BLOCK_COMMENT=24
WS=25
'quixos-lock'=1 'quixos-lock'=1
'fragment'=2 'fragment'=2
'version'=3 'version'=3
@@ -29,14 +30,15 @@ WS=24
'source'=5 'source'=5
'interface'=6 'interface'=6
'package'=7 'package'=7
'repository'=8 'build'=8
'commit'=9 'repository'=9
'policy'=10 'commit'=10
'ref'=11 'policy'=11
'pinned'=12 'ref'=12
'track-release'=13 'pinned'=13
'track-development'=14 'track-release'=14
'import'=15 'track-development'=15
'{'=16 'import'=16
'}'=17 '{'=17
';'=18 '}'=18
';'=19
+122 -119
View File
@@ -11,23 +11,24 @@ export class QuixosLockLexer extends antlr.Lexer {
public static readonly SOURCE = 5; public static readonly SOURCE = 5;
public static readonly INTERFACE = 6; public static readonly INTERFACE = 6;
public static readonly PACKAGE = 7; public static readonly PACKAGE = 7;
public static readonly REPOSITORY = 8; public static readonly BUILD = 8;
public static readonly COMMIT = 9; public static readonly REPOSITORY = 9;
public static readonly POLICY = 10; public static readonly COMMIT = 10;
public static readonly REF = 11; public static readonly POLICY = 11;
public static readonly PINNED = 12; public static readonly REF = 12;
public static readonly TRACK_RELEASE = 13; public static readonly PINNED = 13;
public static readonly TRACK_DEVELOPMENT = 14; public static readonly TRACK_RELEASE = 14;
public static readonly IMPORT = 15; public static readonly TRACK_DEVELOPMENT = 15;
public static readonly LBRACE = 16; public static readonly IMPORT = 16;
public static readonly RBRACE = 17; public static readonly LBRACE = 17;
public static readonly SEMI = 18; public static readonly RBRACE = 18;
public static readonly INTEGER = 19; public static readonly SEMI = 19;
public static readonly IDENTIFIER = 20; public static readonly INTEGER = 20;
public static readonly STRING_LITERAL = 21; public static readonly IDENTIFIER = 21;
public static readonly LINE_COMMENT = 22; public static readonly STRING_LITERAL = 22;
public static readonly BLOCK_COMMENT = 23; public static readonly LINE_COMMENT = 23;
public static readonly WS = 24; public static readonly BLOCK_COMMENT = 24;
public static readonly WS = 25;
public static readonly channelNames = [ public static readonly channelNames = [
"DEFAULT_TOKEN_CHANNEL", "HIDDEN" "DEFAULT_TOKEN_CHANNEL", "HIDDEN"
@@ -35,17 +36,17 @@ export class QuixosLockLexer extends antlr.Lexer {
public static readonly literalNames = [ public static readonly literalNames = [
null, "'quixos-lock'", "'fragment'", "'version'", "'quixos'", "'source'", null, "'quixos-lock'", "'fragment'", "'version'", "'quixos'", "'source'",
"'interface'", "'package'", "'repository'", "'commit'", "'policy'", "'interface'", "'package'", "'build'", "'repository'", "'commit'",
"'ref'", "'pinned'", "'track-release'", "'track-development'", "'import'", "'policy'", "'ref'", "'pinned'", "'track-release'", "'track-development'",
"'{'", "'}'", "';'" "'import'", "'{'", "'}'", "';'"
]; ];
public static readonly symbolicNames = [ public static readonly symbolicNames = [
null, "QUIXOS_LOCK", "FRAGMENT", "VERSION", "QUIXOS", "SOURCE", null, "QUIXOS_LOCK", "FRAGMENT", "VERSION", "QUIXOS", "SOURCE",
"INTERFACE", "PACKAGE", "REPOSITORY", "COMMIT", "POLICY", "REF", "INTERFACE", "PACKAGE", "BUILD", "REPOSITORY", "COMMIT", "POLICY",
"PINNED", "TRACK_RELEASE", "TRACK_DEVELOPMENT", "IMPORT", "LBRACE", "REF", "PINNED", "TRACK_RELEASE", "TRACK_DEVELOPMENT", "IMPORT",
"RBRACE", "SEMI", "INTEGER", "IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT", "LBRACE", "RBRACE", "SEMI", "INTEGER", "IDENTIFIER", "STRING_LITERAL",
"BLOCK_COMMENT", "WS" "LINE_COMMENT", "BLOCK_COMMENT", "WS"
]; ];
public static readonly modeNames = [ public static readonly modeNames = [
@@ -54,10 +55,10 @@ export class QuixosLockLexer extends antlr.Lexer {
public static readonly ruleNames = [ public static readonly ruleNames = [
"QUIXOS_LOCK", "FRAGMENT", "VERSION", "QUIXOS", "SOURCE", "INTERFACE", "QUIXOS_LOCK", "FRAGMENT", "VERSION", "QUIXOS", "SOURCE", "INTERFACE",
"PACKAGE", "REPOSITORY", "COMMIT", "POLICY", "REF", "PINNED", "TRACK_RELEASE", "PACKAGE", "BUILD", "REPOSITORY", "COMMIT", "POLICY", "REF", "PINNED",
"TRACK_DEVELOPMENT", "IMPORT", "LBRACE", "RBRACE", "SEMI", "INTEGER", "TRACK_RELEASE", "TRACK_DEVELOPMENT", "IMPORT", "LBRACE", "RBRACE",
"IDENTIFIER", "STRING_LITERAL", "ESC", "HEX", "LINE_COMMENT", "BLOCK_COMMENT", "SEMI", "INTEGER", "IDENTIFIER", "STRING_LITERAL", "ESC", "HEX",
"WS", "LINE_COMMENT", "BLOCK_COMMENT", "WS",
]; ];
@@ -79,99 +80,101 @@ export class QuixosLockLexer extends antlr.Lexer {
public get modeNames(): string[] { return QuixosLockLexer.modeNames; } public get modeNames(): string[] { return QuixosLockLexer.modeNames; }
public static readonly _serializedATN: number[] = [ public static readonly _serializedATN: number[] = [
4,0,24,261,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5, 4,0,25,269,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,
2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2, 2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,
13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7, 13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,
19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,1, 19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1, 26,7,26,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,3,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,3,
3,1,3,1,3,1,3,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,5,1,5,1,5,1,5,1,5,1, 1,3,1,3,1,3,1,3,1,3,1,3,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,5,1,5,1,5,
5,1,5,1,5,1,5,1,5,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,7,1,7,1,7,1, 1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,7,
7,1,7,1,7,1,7,1,7,1,7,1,7,1,7,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,9,1, 1,7,1,7,1,7,1,7,1,7,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,
9,1,9,1,9,1,9,1,9,1,9,1,10,1,10,1,10,1,10,1,11,1,11,1,11,1,11,1, 1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,10,1,10,1,10,1,10,1,10,1,10,1,10,1,
11,1,11,1,11,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1, 11,1,11,1,11,1,11,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,13,1,13,1,
12,1,12,1,12,1,12,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1, 13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,14,1,
13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,14,1,14,1,14,1,14,1, 14,1,14,1,14,1,14,1,14,1,14,1,14,1,14,1,14,1,14,1,14,1,14,1,14,1,
14,1,14,1,14,1,15,1,15,1,16,1,16,1,17,1,17,1,18,4,18,197,8,18,11, 14,1,14,1,14,1,14,1,15,1,15,1,15,1,15,1,15,1,15,1,15,1,16,1,16,1,
18,12,18,198,1,19,1,19,5,19,203,8,19,10,19,12,19,206,9,19,1,20,1, 17,1,17,1,18,1,18,1,19,4,19,205,8,19,11,19,12,19,206,1,20,1,20,5,
20,1,20,5,20,211,8,20,10,20,12,20,214,9,20,1,20,1,20,1,21,1,21,1, 20,211,8,20,10,20,12,20,214,9,20,1,21,1,21,1,21,5,21,219,8,21,10,
21,1,21,1,21,1,21,1,21,1,21,3,21,226,8,21,1,22,1,22,1,23,1,23,1, 21,12,21,222,9,21,1,21,1,21,1,22,1,22,1,22,1,22,1,22,1,22,1,22,1,
23,1,23,5,23,234,8,23,10,23,12,23,237,9,23,1,23,1,23,1,24,1,24,1, 22,3,22,234,8,22,1,23,1,23,1,24,1,24,1,24,1,24,5,24,242,8,24,10,
24,1,24,5,24,245,8,24,10,24,12,24,248,9,24,1,24,1,24,1,24,1,24,1, 24,12,24,245,9,24,1,24,1,24,1,25,1,25,1,25,1,25,5,25,253,8,25,10,
24,1,25,4,25,256,8,25,11,25,12,25,257,1,25,1,25,1,246,0,26,1,1,3, 25,12,25,256,9,25,1,25,1,25,1,25,1,25,1,25,1,26,4,26,264,8,26,11,
2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,25,13,27,14, 26,12,26,265,1,26,1,26,1,254,0,27,1,1,3,2,5,3,7,4,9,5,11,6,13,7,
29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,0,45,0,47,22,49,23, 15,8,17,9,19,10,21,11,23,12,25,13,27,14,29,15,31,16,33,17,35,18,
51,24,1,0,8,1,0,48,57,3,0,65,90,95,95,97,122,4,0,48,57,65,90,95, 37,19,39,20,41,21,43,22,45,0,47,0,49,23,51,24,53,25,1,0,8,1,0,48,
95,97,122,4,0,10,10,13,13,34,34,92,92,8,0,34,34,47,47,92,92,98,98, 57,3,0,65,90,95,95,97,122,4,0,48,57,65,90,95,95,97,122,4,0,10,10,
102,102,110,110,114,114,116,116,3,0,48,57,65,70,97,102,2,0,10,10, 13,13,34,34,92,92,8,0,34,34,47,47,92,92,98,98,102,102,110,110,114,
13,13,3,0,9,10,13,13,32,32,266,0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0, 114,116,116,3,0,48,57,65,70,97,102,2,0,10,10,13,13,3,0,9,10,13,13,
0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0,0,0,13,1,0,0,0,0,15,1,0,0,0, 32,32,274,0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,
0,17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,23,1,0,0,0,0,25,1,0,0,0, 0,0,0,0,11,1,0,0,0,0,13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,
0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0, 0,0,0,0,21,1,0,0,0,0,23,1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,
0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,0, 0,0,0,0,31,1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,
0,51,1,0,0,0,1,53,1,0,0,0,3,65,1,0,0,0,5,74,1,0,0,0,7,82,1,0,0,0, 0,0,0,0,41,1,0,0,0,0,43,1,0,0,0,0,49,1,0,0,0,0,51,1,0,0,0,0,53,1,
9,89,1,0,0,0,11,96,1,0,0,0,13,106,1,0,0,0,15,114,1,0,0,0,17,125, 0,0,0,1,55,1,0,0,0,3,67,1,0,0,0,5,76,1,0,0,0,7,84,1,0,0,0,9,91,1,
1,0,0,0,19,132,1,0,0,0,21,139,1,0,0,0,23,143,1,0,0,0,25,150,1,0, 0,0,0,11,98,1,0,0,0,13,108,1,0,0,0,15,116,1,0,0,0,17,122,1,0,0,0,
0,0,27,164,1,0,0,0,29,182,1,0,0,0,31,189,1,0,0,0,33,191,1,0,0,0, 19,133,1,0,0,0,21,140,1,0,0,0,23,147,1,0,0,0,25,151,1,0,0,0,27,158,
35,193,1,0,0,0,37,196,1,0,0,0,39,200,1,0,0,0,41,207,1,0,0,0,43,217, 1,0,0,0,29,172,1,0,0,0,31,190,1,0,0,0,33,197,1,0,0,0,35,199,1,0,
1,0,0,0,45,227,1,0,0,0,47,229,1,0,0,0,49,240,1,0,0,0,51,255,1,0, 0,0,37,201,1,0,0,0,39,204,1,0,0,0,41,208,1,0,0,0,43,215,1,0,0,0,
0,0,53,54,5,113,0,0,54,55,5,117,0,0,55,56,5,105,0,0,56,57,5,120, 45,225,1,0,0,0,47,235,1,0,0,0,49,237,1,0,0,0,51,248,1,0,0,0,53,263,
0,0,57,58,5,111,0,0,58,59,5,115,0,0,59,60,5,45,0,0,60,61,5,108,0, 1,0,0,0,55,56,5,113,0,0,56,57,5,117,0,0,57,58,5,105,0,0,58,59,5,
0,61,62,5,111,0,0,62,63,5,99,0,0,63,64,5,107,0,0,64,2,1,0,0,0,65, 120,0,0,59,60,5,111,0,0,60,61,5,115,0,0,61,62,5,45,0,0,62,63,5,108,
66,5,102,0,0,66,67,5,114,0,0,67,68,5,97,0,0,68,69,5,103,0,0,69,70, 0,0,63,64,5,111,0,0,64,65,5,99,0,0,65,66,5,107,0,0,66,2,1,0,0,0,
5,109,0,0,70,71,5,101,0,0,71,72,5,110,0,0,72,73,5,116,0,0,73,4,1, 67,68,5,102,0,0,68,69,5,114,0,0,69,70,5,97,0,0,70,71,5,103,0,0,71,
0,0,0,74,75,5,118,0,0,75,76,5,101,0,0,76,77,5,114,0,0,77,78,5,115, 72,5,109,0,0,72,73,5,101,0,0,73,74,5,110,0,0,74,75,5,116,0,0,75,
0,0,78,79,5,105,0,0,79,80,5,111,0,0,80,81,5,110,0,0,81,6,1,0,0,0, 4,1,0,0,0,76,77,5,118,0,0,77,78,5,101,0,0,78,79,5,114,0,0,79,80,
82,83,5,113,0,0,83,84,5,117,0,0,84,85,5,105,0,0,85,86,5,120,0,0, 5,115,0,0,80,81,5,105,0,0,81,82,5,111,0,0,82,83,5,110,0,0,83,6,1,
86,87,5,111,0,0,87,88,5,115,0,0,88,8,1,0,0,0,89,90,5,115,0,0,90, 0,0,0,84,85,5,113,0,0,85,86,5,117,0,0,86,87,5,105,0,0,87,88,5,120,
91,5,111,0,0,91,92,5,117,0,0,92,93,5,114,0,0,93,94,5,99,0,0,94,95, 0,0,88,89,5,111,0,0,89,90,5,115,0,0,90,8,1,0,0,0,91,92,5,115,0,0,
5,101,0,0,95,10,1,0,0,0,96,97,5,105,0,0,97,98,5,110,0,0,98,99,5, 92,93,5,111,0,0,93,94,5,117,0,0,94,95,5,114,0,0,95,96,5,99,0,0,96,
116,0,0,99,100,5,101,0,0,100,101,5,114,0,0,101,102,5,102,0,0,102, 97,5,101,0,0,97,10,1,0,0,0,98,99,5,105,0,0,99,100,5,110,0,0,100,
103,5,97,0,0,103,104,5,99,0,0,104,105,5,101,0,0,105,12,1,0,0,0,106, 101,5,116,0,0,101,102,5,101,0,0,102,103,5,114,0,0,103,104,5,102,
107,5,112,0,0,107,108,5,97,0,0,108,109,5,99,0,0,109,110,5,107,0, 0,0,104,105,5,97,0,0,105,106,5,99,0,0,106,107,5,101,0,0,107,12,1,
0,110,111,5,97,0,0,111,112,5,103,0,0,112,113,5,101,0,0,113,14,1, 0,0,0,108,109,5,112,0,0,109,110,5,97,0,0,110,111,5,99,0,0,111,112,
0,0,0,114,115,5,114,0,0,115,116,5,101,0,0,116,117,5,112,0,0,117, 5,107,0,0,112,113,5,97,0,0,113,114,5,103,0,0,114,115,5,101,0,0,115,
118,5,111,0,0,118,119,5,115,0,0,119,120,5,105,0,0,120,121,5,116, 14,1,0,0,0,116,117,5,98,0,0,117,118,5,117,0,0,118,119,5,105,0,0,
0,0,121,122,5,111,0,0,122,123,5,114,0,0,123,124,5,121,0,0,124,16, 119,120,5,108,0,0,120,121,5,100,0,0,121,16,1,0,0,0,122,123,5,114,
1,0,0,0,125,126,5,99,0,0,126,127,5,111,0,0,127,128,5,109,0,0,128, 0,0,123,124,5,101,0,0,124,125,5,112,0,0,125,126,5,111,0,0,126,127,
129,5,109,0,0,129,130,5,105,0,0,130,131,5,116,0,0,131,18,1,0,0,0, 5,115,0,0,127,128,5,105,0,0,128,129,5,116,0,0,129,130,5,111,0,0,
132,133,5,112,0,0,133,134,5,111,0,0,134,135,5,108,0,0,135,136,5, 130,131,5,114,0,0,131,132,5,121,0,0,132,18,1,0,0,0,133,134,5,99,
105,0,0,136,137,5,99,0,0,137,138,5,121,0,0,138,20,1,0,0,0,139,140, 0,0,134,135,5,111,0,0,135,136,5,109,0,0,136,137,5,109,0,0,137,138,
5,114,0,0,140,141,5,101,0,0,141,142,5,102,0,0,142,22,1,0,0,0,143, 5,105,0,0,138,139,5,116,0,0,139,20,1,0,0,0,140,141,5,112,0,0,141,
144,5,112,0,0,144,145,5,105,0,0,145,146,5,110,0,0,146,147,5,110, 142,5,111,0,0,142,143,5,108,0,0,143,144,5,105,0,0,144,145,5,99,0,
0,0,147,148,5,101,0,0,148,149,5,100,0,0,149,24,1,0,0,0,150,151,5, 0,145,146,5,121,0,0,146,22,1,0,0,0,147,148,5,114,0,0,148,149,5,101,
116,0,0,151,152,5,114,0,0,152,153,5,97,0,0,153,154,5,99,0,0,154, 0,0,149,150,5,102,0,0,150,24,1,0,0,0,151,152,5,112,0,0,152,153,5,
155,5,107,0,0,155,156,5,45,0,0,156,157,5,114,0,0,157,158,5,101,0, 105,0,0,153,154,5,110,0,0,154,155,5,110,0,0,155,156,5,101,0,0,156,
0,158,159,5,108,0,0,159,160,5,101,0,0,160,161,5,97,0,0,161,162,5, 157,5,100,0,0,157,26,1,0,0,0,158,159,5,116,0,0,159,160,5,114,0,0,
115,0,0,162,163,5,101,0,0,163,26,1,0,0,0,164,165,5,116,0,0,165,166, 160,161,5,97,0,0,161,162,5,99,0,0,162,163,5,107,0,0,163,164,5,45,
5,114,0,0,166,167,5,97,0,0,167,168,5,99,0,0,168,169,5,107,0,0,169, 0,0,164,165,5,114,0,0,165,166,5,101,0,0,166,167,5,108,0,0,167,168,
170,5,45,0,0,170,171,5,100,0,0,171,172,5,101,0,0,172,173,5,118,0, 5,101,0,0,168,169,5,97,0,0,169,170,5,115,0,0,170,171,5,101,0,0,171,
0,173,174,5,101,0,0,174,175,5,108,0,0,175,176,5,111,0,0,176,177, 28,1,0,0,0,172,173,5,116,0,0,173,174,5,114,0,0,174,175,5,97,0,0,
5,112,0,0,177,178,5,109,0,0,178,179,5,101,0,0,179,180,5,110,0,0, 175,176,5,99,0,0,176,177,5,107,0,0,177,178,5,45,0,0,178,179,5,100,
180,181,5,116,0,0,181,28,1,0,0,0,182,183,5,105,0,0,183,184,5,109, 0,0,179,180,5,101,0,0,180,181,5,118,0,0,181,182,5,101,0,0,182,183,
0,0,184,185,5,112,0,0,185,186,5,111,0,0,186,187,5,114,0,0,187,188, 5,108,0,0,183,184,5,111,0,0,184,185,5,112,0,0,185,186,5,109,0,0,
5,116,0,0,188,30,1,0,0,0,189,190,5,123,0,0,190,32,1,0,0,0,191,192, 186,187,5,101,0,0,187,188,5,110,0,0,188,189,5,116,0,0,189,30,1,0,
5,125,0,0,192,34,1,0,0,0,193,194,5,59,0,0,194,36,1,0,0,0,195,197, 0,0,190,191,5,105,0,0,191,192,5,109,0,0,192,193,5,112,0,0,193,194,
7,0,0,0,196,195,1,0,0,0,197,198,1,0,0,0,198,196,1,0,0,0,198,199, 5,111,0,0,194,195,5,114,0,0,195,196,5,116,0,0,196,32,1,0,0,0,197,
1,0,0,0,199,38,1,0,0,0,200,204,7,1,0,0,201,203,7,2,0,0,202,201,1, 198,5,123,0,0,198,34,1,0,0,0,199,200,5,125,0,0,200,36,1,0,0,0,201,
0,0,0,203,206,1,0,0,0,204,202,1,0,0,0,204,205,1,0,0,0,205,40,1,0, 202,5,59,0,0,202,38,1,0,0,0,203,205,7,0,0,0,204,203,1,0,0,0,205,
0,0,206,204,1,0,0,0,207,212,5,34,0,0,208,211,3,43,21,0,209,211,8, 206,1,0,0,0,206,204,1,0,0,0,206,207,1,0,0,0,207,40,1,0,0,0,208,212,
3,0,0,210,208,1,0,0,0,210,209,1,0,0,0,211,214,1,0,0,0,212,210,1, 7,1,0,0,209,211,7,2,0,0,210,209,1,0,0,0,211,214,1,0,0,0,212,210,
0,0,0,212,213,1,0,0,0,213,215,1,0,0,0,214,212,1,0,0,0,215,216,5, 1,0,0,0,212,213,1,0,0,0,213,42,1,0,0,0,214,212,1,0,0,0,215,220,5,
34,0,0,216,42,1,0,0,0,217,225,5,92,0,0,218,226,7,4,0,0,219,220,5, 34,0,0,216,219,3,45,22,0,217,219,8,3,0,0,218,216,1,0,0,0,218,217,
117,0,0,220,221,3,45,22,0,221,222,3,45,22,0,222,223,3,45,22,0,223, 1,0,0,0,219,222,1,0,0,0,220,218,1,0,0,0,220,221,1,0,0,0,221,223,
224,3,45,22,0,224,226,1,0,0,0,225,218,1,0,0,0,225,219,1,0,0,0,226, 1,0,0,0,222,220,1,0,0,0,223,224,5,34,0,0,224,44,1,0,0,0,225,233,
44,1,0,0,0,227,228,7,5,0,0,228,46,1,0,0,0,229,230,5,47,0,0,230,231, 5,92,0,0,226,234,7,4,0,0,227,228,5,117,0,0,228,229,3,47,23,0,229,
5,47,0,0,231,235,1,0,0,0,232,234,8,6,0,0,233,232,1,0,0,0,234,237, 230,3,47,23,0,230,231,3,47,23,0,231,232,3,47,23,0,232,234,1,0,0,
1,0,0,0,235,233,1,0,0,0,235,236,1,0,0,0,236,238,1,0,0,0,237,235, 0,233,226,1,0,0,0,233,227,1,0,0,0,234,46,1,0,0,0,235,236,7,5,0,0,
1,0,0,0,238,239,6,23,0,0,239,48,1,0,0,0,240,241,5,47,0,0,241,242, 236,48,1,0,0,0,237,238,5,47,0,0,238,239,5,47,0,0,239,243,1,0,0,0,
5,42,0,0,242,246,1,0,0,0,243,245,9,0,0,0,244,243,1,0,0,0,245,248, 240,242,8,6,0,0,241,240,1,0,0,0,242,245,1,0,0,0,243,241,1,0,0,0,
1,0,0,0,246,247,1,0,0,0,246,244,1,0,0,0,247,249,1,0,0,0,248,246, 243,244,1,0,0,0,244,246,1,0,0,0,245,243,1,0,0,0,246,247,6,24,0,0,
1,0,0,0,249,250,5,42,0,0,250,251,5,47,0,0,251,252,1,0,0,0,252,253, 247,50,1,0,0,0,248,249,5,47,0,0,249,250,5,42,0,0,250,254,1,0,0,0,
6,24,0,0,253,50,1,0,0,0,254,256,7,7,0,0,255,254,1,0,0,0,256,257, 251,253,9,0,0,0,252,251,1,0,0,0,253,256,1,0,0,0,254,255,1,0,0,0,
1,0,0,0,257,255,1,0,0,0,257,258,1,0,0,0,258,259,1,0,0,0,259,260, 254,252,1,0,0,0,255,257,1,0,0,0,256,254,1,0,0,0,257,258,5,42,0,0,
6,25,0,0,260,52,1,0,0,0,9,0,198,204,210,212,225,235,246,257,1,6, 258,259,5,47,0,0,259,260,1,0,0,0,260,261,6,25,0,0,261,52,1,0,0,0,
0,0 262,264,7,7,0,0,263,262,1,0,0,0,264,265,1,0,0,0,265,263,1,0,0,0,
265,266,1,0,0,0,266,267,1,0,0,0,267,268,6,26,0,0,268,54,1,0,0,0,
9,0,206,212,218,220,233,243,254,265,1,6,0,0
]; ];
private static __ATN: antlr.ATN; private static __ATN: antlr.ATN;
+47 -42
View File
@@ -17,23 +17,24 @@ export class QuixosLockParser extends antlr.Parser {
public static readonly SOURCE = 5; public static readonly SOURCE = 5;
public static readonly INTERFACE = 6; public static readonly INTERFACE = 6;
public static readonly PACKAGE = 7; public static readonly PACKAGE = 7;
public static readonly REPOSITORY = 8; public static readonly BUILD = 8;
public static readonly COMMIT = 9; public static readonly REPOSITORY = 9;
public static readonly POLICY = 10; public static readonly COMMIT = 10;
public static readonly REF = 11; public static readonly POLICY = 11;
public static readonly PINNED = 12; public static readonly REF = 12;
public static readonly TRACK_RELEASE = 13; public static readonly PINNED = 13;
public static readonly TRACK_DEVELOPMENT = 14; public static readonly TRACK_RELEASE = 14;
public static readonly IMPORT = 15; public static readonly TRACK_DEVELOPMENT = 15;
public static readonly LBRACE = 16; public static readonly IMPORT = 16;
public static readonly RBRACE = 17; public static readonly LBRACE = 17;
public static readonly SEMI = 18; public static readonly RBRACE = 18;
public static readonly INTEGER = 19; public static readonly SEMI = 19;
public static readonly IDENTIFIER = 20; public static readonly INTEGER = 20;
public static readonly STRING_LITERAL = 21; public static readonly IDENTIFIER = 21;
public static readonly LINE_COMMENT = 22; public static readonly STRING_LITERAL = 22;
public static readonly BLOCK_COMMENT = 23; public static readonly LINE_COMMENT = 23;
public static readonly WS = 24; public static readonly BLOCK_COMMENT = 24;
public static readonly WS = 25;
public static readonly RULE_document = 0; public static readonly RULE_document = 0;
public static readonly RULE_quixosEntry = 1; public static readonly RULE_quixosEntry = 1;
public static readonly RULE_resourceEntry = 2; public static readonly RULE_resourceEntry = 2;
@@ -47,17 +48,17 @@ export class QuixosLockParser extends antlr.Parser {
public static readonly literalNames = [ public static readonly literalNames = [
null, "'quixos-lock'", "'fragment'", "'version'", "'quixos'", "'source'", null, "'quixos-lock'", "'fragment'", "'version'", "'quixos'", "'source'",
"'interface'", "'package'", "'repository'", "'commit'", "'policy'", "'interface'", "'package'", "'build'", "'repository'", "'commit'",
"'ref'", "'pinned'", "'track-release'", "'track-development'", "'import'", "'policy'", "'ref'", "'pinned'", "'track-release'", "'track-development'",
"'{'", "'}'", "';'" "'import'", "'{'", "'}'", "';'"
]; ];
public static readonly symbolicNames = [ public static readonly symbolicNames = [
null, "QUIXOS_LOCK", "FRAGMENT", "VERSION", "QUIXOS", "SOURCE", null, "QUIXOS_LOCK", "FRAGMENT", "VERSION", "QUIXOS", "SOURCE",
"INTERFACE", "PACKAGE", "REPOSITORY", "COMMIT", "POLICY", "REF", "INTERFACE", "PACKAGE", "BUILD", "REPOSITORY", "COMMIT", "POLICY",
"PINNED", "TRACK_RELEASE", "TRACK_DEVELOPMENT", "IMPORT", "LBRACE", "REF", "PINNED", "TRACK_RELEASE", "TRACK_DEVELOPMENT", "IMPORT",
"RBRACE", "SEMI", "INTEGER", "IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT", "LBRACE", "RBRACE", "SEMI", "INTEGER", "IDENTIFIER", "STRING_LITERAL",
"BLOCK_COMMENT", "WS" "LINE_COMMENT", "BLOCK_COMMENT", "WS"
]; ];
public static readonly ruleNames = [ public static readonly ruleNames = [
"document", "quixosEntry", "resourceEntry", "importEntry", "resourceKind", "document", "quixosEntry", "resourceEntry", "importEntry", "resourceKind",
@@ -107,7 +108,7 @@ export class QuixosLockParser extends antlr.Parser {
this.state = 32; this.state = 32;
this.errorHandler.sync(this); this.errorHandler.sync(this);
_la = this.tokenStream.LA(1); _la = this.tokenStream.LA(1);
while ((((_la) & ~0x1F) === 0 && ((1 << _la) & 32976) !== 0)) { while ((((_la) & ~0x1F) === 0 && ((1 << _la) & 66000) !== 0)) {
{ {
this.state = 30; this.state = 30;
this.errorHandler.sync(this); this.errorHandler.sync(this);
@@ -126,6 +127,7 @@ export class QuixosLockParser extends antlr.Parser {
break; break;
case QuixosLockParser.INTERFACE: case QuixosLockParser.INTERFACE:
case QuixosLockParser.PACKAGE: case QuixosLockParser.PACKAGE:
case QuixosLockParser.BUILD:
{ {
this.state = 29; this.state = 29;
this.resourceEntry(); this.resourceEntry();
@@ -250,7 +252,7 @@ export class QuixosLockParser extends antlr.Parser {
{ {
this.state = 51; this.state = 51;
_la = this.tokenStream.LA(1); _la = this.tokenStream.LA(1);
if(!(_la === 6 || _la === 7)) { if(!((((_la) & ~0x1F) === 0 && ((1 << _la) & 448) !== 0))) {
this.errorHandler.recoverInline(this); this.errorHandler.recoverInline(this);
} }
else { else {
@@ -327,7 +329,7 @@ export class QuixosLockParser extends antlr.Parser {
this.state = 73; this.state = 73;
this.errorHandler.sync(this); this.errorHandler.sync(this);
_la = this.tokenStream.LA(1); _la = this.tokenStream.LA(1);
if (_la === 10) { if (_la === 11) {
{ {
this.state = 66; this.state = 66;
this.match(QuixosLockParser.POLICY); this.match(QuixosLockParser.POLICY);
@@ -376,7 +378,7 @@ export class QuixosLockParser extends antlr.Parser {
{ {
this.state = 80; this.state = 80;
_la = this.tokenStream.LA(1); _la = this.tokenStream.LA(1);
if(!((((_la) & ~0x1F) === 0 && ((1 << _la) & 28672) !== 0))) { if(!((((_la) & ~0x1F) === 0 && ((1 << _la) & 57344) !== 0))) {
this.errorHandler.recoverInline(this); this.errorHandler.recoverInline(this);
} }
else { else {
@@ -446,31 +448,31 @@ export class QuixosLockParser extends antlr.Parser {
} }
public static readonly _serializedATN: number[] = [ public static readonly _serializedATN: number[] = [
4,1,24,87,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7, 4,1,25,87,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,
6,2,7,7,7,2,8,7,8,2,9,7,9,1,0,1,0,3,0,23,8,0,1,0,1,0,1,0,1,0,1,0, 6,2,7,7,7,2,8,7,8,2,9,7,9,1,0,1,0,3,0,23,8,0,1,0,1,0,1,0,1,0,1,0,
1,0,5,0,31,8,0,10,0,12,0,34,9,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,2, 1,0,5,0,31,8,0,10,0,12,0,34,9,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,2,
1,2,1,2,1,2,1,2,1,3,1,3,1,3,1,3,1,4,1,4,1,5,1,5,1,5,1,5,1,5,1,5, 1,2,1,2,1,2,1,2,1,3,1,3,1,3,1,3,1,4,1,4,1,5,1,5,1,5,1,5,1,5,1,5,
1,5,1,5,1,5,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,3,6,74,8, 1,5,1,5,1,5,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,3,6,74,8,
6,1,6,1,6,1,6,1,6,1,6,1,7,1,7,1,8,1,8,1,9,1,9,1,9,0,0,10,0,2,4,6, 6,1,6,1,6,1,6,1,6,1,6,1,7,1,7,1,8,1,8,1,9,1,9,1,9,0,0,10,0,2,4,6,
8,10,12,14,16,18,0,2,1,0,6,7,1,0,12,14,81,0,20,1,0,0,0,2,38,1,0, 8,10,12,14,16,18,0,2,1,0,6,8,1,0,13,15,81,0,20,1,0,0,0,2,38,1,0,
0,0,4,42,1,0,0,0,6,47,1,0,0,0,8,51,1,0,0,0,10,53,1,0,0,0,12,62,1, 0,0,4,42,1,0,0,0,6,47,1,0,0,0,8,51,1,0,0,0,10,53,1,0,0,0,12,62,1,
0,0,0,14,80,1,0,0,0,16,82,1,0,0,0,18,84,1,0,0,0,20,22,5,1,0,0,21, 0,0,0,14,80,1,0,0,0,16,82,1,0,0,0,18,84,1,0,0,0,20,22,5,1,0,0,21,
23,5,2,0,0,22,21,1,0,0,0,22,23,1,0,0,0,23,24,1,0,0,0,24,25,5,3,0, 23,5,2,0,0,22,21,1,0,0,0,22,23,1,0,0,0,23,24,1,0,0,0,24,25,5,3,0,
0,25,26,5,19,0,0,26,32,5,16,0,0,27,31,3,2,1,0,28,31,3,6,3,0,29,31, 0,25,26,5,20,0,0,26,32,5,17,0,0,27,31,3,2,1,0,28,31,3,6,3,0,29,31,
3,4,2,0,30,27,1,0,0,0,30,28,1,0,0,0,30,29,1,0,0,0,31,34,1,0,0,0, 3,4,2,0,30,27,1,0,0,0,30,28,1,0,0,0,30,29,1,0,0,0,31,34,1,0,0,0,
32,30,1,0,0,0,32,33,1,0,0,0,33,35,1,0,0,0,34,32,1,0,0,0,35,36,5, 32,30,1,0,0,0,32,33,1,0,0,0,33,35,1,0,0,0,34,32,1,0,0,0,35,36,5,
17,0,0,36,37,5,0,0,1,37,1,1,0,0,0,38,39,5,4,0,0,39,40,5,5,0,0,40, 18,0,0,36,37,5,0,0,1,37,1,1,0,0,0,38,39,5,4,0,0,39,40,5,5,0,0,40,
41,3,12,6,0,41,3,1,0,0,0,42,43,3,8,4,0,43,44,3,16,8,0,44,45,5,5, 41,3,12,6,0,41,3,1,0,0,0,42,43,3,8,4,0,43,44,3,16,8,0,44,45,5,5,
0,0,45,46,3,10,5,0,46,5,1,0,0,0,47,48,5,15,0,0,48,49,3,18,9,0,49, 0,0,45,46,3,10,5,0,46,5,1,0,0,0,47,48,5,16,0,0,48,49,3,18,9,0,49,
50,5,18,0,0,50,7,1,0,0,0,51,52,7,0,0,0,52,9,1,0,0,0,53,54,5,16,0, 50,5,19,0,0,50,7,1,0,0,0,51,52,7,0,0,0,52,9,1,0,0,0,53,54,5,17,0,
0,54,55,5,8,0,0,55,56,3,18,9,0,56,57,5,18,0,0,57,58,5,9,0,0,58,59, 0,54,55,5,9,0,0,55,56,3,18,9,0,56,57,5,19,0,0,57,58,5,10,0,0,58,
3,18,9,0,59,60,5,18,0,0,60,61,5,17,0,0,61,11,1,0,0,0,62,63,5,16, 59,3,18,9,0,59,60,5,19,0,0,60,61,5,18,0,0,61,11,1,0,0,0,62,63,5,
0,0,63,64,5,8,0,0,64,65,3,18,9,0,65,73,5,18,0,0,66,67,5,10,0,0,67, 17,0,0,63,64,5,9,0,0,64,65,3,18,9,0,65,73,5,19,0,0,66,67,5,11,0,
68,3,14,7,0,68,69,5,18,0,0,69,70,5,11,0,0,70,71,3,18,9,0,71,72,5, 0,67,68,3,14,7,0,68,69,5,19,0,0,69,70,5,12,0,0,70,71,3,18,9,0,71,
18,0,0,72,74,1,0,0,0,73,66,1,0,0,0,73,74,1,0,0,0,74,75,1,0,0,0,75, 72,5,19,0,0,72,74,1,0,0,0,73,66,1,0,0,0,73,74,1,0,0,0,74,75,1,0,
76,5,9,0,0,76,77,3,18,9,0,77,78,5,18,0,0,78,79,5,17,0,0,79,13,1, 0,0,75,76,5,10,0,0,76,77,3,18,9,0,77,78,5,19,0,0,78,79,5,18,0,0,
0,0,0,80,81,7,1,0,0,81,15,1,0,0,0,82,83,5,20,0,0,83,17,1,0,0,0,84, 79,13,1,0,0,0,80,81,7,1,0,0,81,15,1,0,0,0,82,83,5,21,0,0,83,17,1,
85,5,21,0,0,85,19,1,0,0,0,4,22,30,32,73 0,0,0,84,85,5,22,0,0,85,19,1,0,0,0,4,22,30,32,73
]; ];
private static __ATN: antlr.ATN; private static __ATN: antlr.ATN;
@@ -648,6 +650,9 @@ export class ResourceKindContext extends antlr.ParserRuleContext {
public PACKAGE(): antlr.TerminalNode | null { public PACKAGE(): antlr.TerminalNode | null {
return this.getToken(QuixosLockParser.PACKAGE, 0); return this.getToken(QuixosLockParser.PACKAGE, 0);
} }
public BUILD(): antlr.TerminalNode | null {
return this.getToken(QuixosLockParser.BUILD, 0);
}
public override get ruleIndex(): number { public override get ruleIndex(): number {
return QuixosLockParser.RULE_resourceKind; return QuixosLockParser.RULE_resourceKind;
} }
+5 -1
View File
@@ -296,7 +296,11 @@ export const parseQuixosLockDocument = (source: string, fileName = "<memory>"):
const resources: LockedResource[] = []; const resources: LockedResource[] = [];
const bindings = new Set<string>(); const bindings = new Set<string>();
for (const [index, context] of tree.resourceEntry().entries()) { for (const [index, context] of tree.resourceEntry().entries()) {
const kind = context.resourceKind().INTERFACE() ? "interface" : "package"; const kind = context.resourceKind().INTERFACE()
? "interface"
: context.resourceKind().BUILD()
? "build"
: "package";
const binding = context.identifier().getText(); const binding = context.identifier().getText();
const key = `${kind}\0${binding}`; const key = `${kind}\0${binding}`;
if (bindings.has(key)) { if (bindings.has(key)) {
+1 -1
View File
@@ -21,7 +21,7 @@ export type QuixosSource = GitSource &
} }
); );
export type LockedResourceKind = "interface" | "package"; export type LockedResourceKind = "interface" | "package" | "build";
export type LockedResource = { export type LockedResource = {
kind: LockedResourceKind; kind: LockedResourceKind;
+19
View File
@@ -154,3 +154,22 @@ test("transaction process services do not promise generated TypeScript modules",
throw Error("No adapter claimed"); throw Error("No adapter claimed");
}); });
}); });
test("a remote export group in a mixed package witnesses only its own adapter", async () => {
const { asyncObjectPlan } = await import("./async-fixture.js");
const { expectedArtifactReceipt } = await import("../src/execution-world/receipts.js");
const plan = await asyncObjectPlan();
const fixture = buildArtifactFixture(plan, "async:controller-runtime@1");
const pkg = plan.definition.packages.find((entry) => entry.revision === fixture.manifest.packageRevisionId)!;
fixture.manifest.implementations = fixture.manifest.implementations.filter(
(entry) => entry.target === "server" && entry.compatibility === "quixos-js-module-v1",
);
for (const implementation of fixture.manifest.implementations)
implementation.exports = implementation.exports.filter((id) =>
pkg.exports.some((entry) => entry.id === id && entry.execution.kind === "remote"),
);
assert.deepEqual(
expectedArtifactReceipt(plan, fixture.manifest, "a".repeat(64)).receipt.generated.map((file) => file.path),
["share/quixos/generated/remote.ts"],
);
});
+76
View File
@@ -0,0 +1,76 @@
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<string, string>) => {
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));
});
+21
View File
@@ -198,3 +198,24 @@ package Owner id "package:owner" revision "package:owner@1" {
} }
await import("./emit-controllers.js"); await import("./emit-controllers.js");
// Standalone public builder roots must work without opting into the other modes.
for (const kind of ["portable", "service"]) {
const pkg = compileCapabilityResourceSource(
`package Owner id "package:owner" revision "package:owner@1" {
function identity id "identity" : int32 -> record {pid:int32;child:int32;}
execution ${kind === "portable" ? "snapshot targets [browser,server]" : "remote"};
}`,
{ source },
);
assert.ok(pkg.ok && pkg.resource.kind === "package", JSON.stringify(pkg.diagnostics));
const workspace = compileCapabilitySource(
`workspace Simple id "workspace:simple" revision "workspace:simple@1" commit "${source.commit}" {import package Owner;}`,
"workspace.qx",
{ packages: new Map([["Owner", pkg.resource.revision]]) },
);
assert.ok(workspace.ok, JSON.stringify(workspace.diagnostics));
const directory = `dist/managed/standalone-${kind}`;
await mkdir(directory, { recursive: true });
await writeFile(`${directory}/execution-plan.json`, JSON.stringify(compileExecutionPlan(workspace.workspace)));
}
+13 -7
View File
@@ -76,7 +76,8 @@ test(
}, },
); );
test("pin upgrades publish children before parent locks and resume without republishing completed nodes", async (context) => { for (const dependencyKind of ["interface", "build"] as const)
test(`${dependencyKind} pin upgrades publish children before parent locks and resume without republishing completed nodes`, async (context) => {
const workbench = await fs.mkdtemp(path.join(os.tmpdir(), "qx-upgrade-test-")); const workbench = await fs.mkdtemp(path.join(os.tmpdir(), "qx-upgrade-test-"));
context.after(() => fs.rm(workbench, { recursive: true, force: true })); context.after(() => fs.rm(workbench, { recursive: true, force: true }));
const from = "a".repeat(40), const from = "a".repeat(40),
@@ -89,7 +90,7 @@ test("pin upgrades publish children before parent locks and resume without repub
source: { repository: "https://example.test/workspace.git", commit: from }, source: { repository: "https://example.test/workspace.git", commit: from },
}, },
{ {
kind: "interface" as const, kind: dependencyKind,
directory: "resources/Named", directory: "resources/Named",
source: { repository: "https://example.test/named.git", commit: from }, source: { repository: "https://example.test/named.git", commit: from },
}, },
@@ -105,18 +106,23 @@ test("pin upgrades publish children before parent locks and resume without repub
path.join(directory, "quixos.lock"), path.join(directory, "quixos.lock"),
lock + lock +
(node.kind === "workspace" (node.kind === "workspace"
? ` interface Named source { repository "${sources[1].source.repository}"; commit "${from}"; }` ? ` ${dependencyKind} Named source { repository "${sources[1].source.repository}"; commit "${from}"; }`
: "") + : "") +
" }", " }",
); );
} }
await fs.writeFile( await fs.writeFile(
path.join(workbench, "resources/Named/interface.qx"), path.join(
'interface Named id "interface:named" revision "interface:named@1" { value name id "member:name" : string { get id "op:get"; } }', workbench,
dependencyKind === "interface" ? "resources/Named/interface.qx" : "resources/Named/types.ts",
),
dependencyKind === "interface"
? 'interface Named id "interface:named" revision "interface:named@1" { value name id "member:name" : string { get id "op:get"; } }'
: "export type Name = string;",
); );
await fs.writeFile( await fs.writeFile(
path.join(workbench, "root/workspace.qx"), path.join(workbench, "root/workspace.qx"),
`workspace W id "workspace:w" revision "workspace:w@1" commit "${from}" { import interface Named; atom A id "atom:a"; }`, `workspace W id "workspace:w" revision "workspace:w@1" commit "${from}" { ${dependencyKind === "interface" ? "import interface Named;" : ""} atom A id "atom:a"; }`,
); );
const snapshotMap = path.join(workbench, "snapshots.json"); const snapshotMap = path.join(workbench, "snapshots.json");
await fs.writeFile( await fs.writeFile(
@@ -124,7 +130,7 @@ test("pin upgrades publish children before parent locks and resume without repub
JSON.stringify({ JSON.stringify({
resources: [ resources: [
{ {
kind: "interface", kind: dependencyKind,
repository: sources[1].source.repository, repository: sources[1].source.repository,
commit: to, commit: to,
directory: path.join(workbench, "resources/Named"), directory: path.join(workbench, "resources/Named"),