Compare commits

..

3 Commits

Author SHA1 Message Date
Quixos Subtree Publisher eabf721e94 Publish quixos-protocol from 33266c4ba9e0dd7b6370715522b281807e8b038b 2026-09-06 00:49:07 +00:00
timothy 0c46850973 Add the workspace coding agent, launch gate, and composable locks
- run a singleton Codex App Server adapter in each dev workspace
- gate Web Studio with a reloadable fragment-token to HttpOnly-session exchange
- add ChatGPT device login and streamed chat to Web Studio
- isolate authoring access in a declarative NixOS service account
- split Web Studio canvas, object, panel, and model concerns
- check generated Quixos protocol clients for drift
- resolve same-repository quixos.lock fragments deterministically
- preserve the collaborative canvas gesture fixes
2026-09-05 17:49:07 -07:00
timothy c4d42a0ac5 Use the client runtime for canvas state 2026-09-05 12:11:30 -07:00
54 changed files with 5068 additions and 2515 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"version": 1, "version": 1,
"sourceRepo": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos.git", "sourceRepo": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos.git",
"sourceCommit": "3ea7dcc6a38ba0c5ddc099b966d48c5aeae732b1", "sourceCommit": "33266c4ba9e0dd7b6370715522b281807e8b038b",
"sourcePath": "quixos-protocol", "sourcePath": "quixos-protocol",
"exportName": "quixos-protocol", "exportName": "quixos-protocol",
"mirrorRemote": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos-protocol.git" "mirrorRemote": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos-protocol.git"
+66 -9
View File
@@ -13,10 +13,29 @@ on parse-tree shapes or declaration order.
```sh ```sh
nix develop nix develop
quixos-capability-compile ../quixos-instance/workspaces/todo.capabilities.qx quixos-workspace-compile \
--root ../quixos-instance/workspaces/todo \
--checkout-root /tmp/quixos-resolved-resources
``` ```
The compiler validates exact identities, interface operation coverage, `workspace.qx` contains workspace-local atoms, attachments, conformances, and
constructor bindings. Each imported interface has an `interface.qx` in its own
repository; each imported package similarly has a `package.qx`. Source
locations never appear in those declarations. `quixos.lock` supplies their
exact Git repositories and commits, and the workspace compiler resolves that
dependency graph recursively.
Inside an interface or package manifest, `import interface Named;` is a true
source dependency: the repository lock must pin it, and tooling may use the
full contract for generated types. `external atom` and `external interface`
declare nominal identities which the final importing workspace must provide.
The latter is appropriate for relationship targets and other opaque
references; it deliberately does not grant the contract needed for an
interface invocation port. This distinction permits mutually referential
interface identities without creating a cycle in the Git Merkle graph.
The compiler validates exact identities, recursive lock/source agreement,
external requirement satisfaction, interface operation coverage,
attachment ownership, native state/edge providers, package receiver and attachment ownership, native state/edge providers, package receiver and
dependency-port requirements, constructors, and the exact runtime closure. dependency-port requirements, constructors, and the exact runtime closure.
Generics, interface composition, declarative forwarding, automatic Generics, interface composition, declarative forwarding, automatic
@@ -26,21 +45,58 @@ from v1.
## Repository locks ## Repository locks
Every workspace, interface, and package repository carries a `quixos.lock`. Every workspace, interface, and package repository carries a `quixos.lock`.
It pins the exact Quixos toolchain revision plus exact Git sources for imported This is not a miniature workspace: a resource lock is only a Quixos toolchain
interfaces and packages. The v1 Git source is deliberately only a repository pin plus a dependency list. It pins exact Git sources for the interfaces and
packages named by that resource's own manifest. The v1 Git source is deliberately only a repository
URL and full commit ID; the publisher-owned reachability tag and Nix fetch URL and full commit ID; the publisher-owned reachability tag and Nix fetch
details are derived from those values. details are derived from those values.
```sh ```sh
quixos-lock-check quixos.lock quixos-lock-check quixos.lock
quixos-resource-compile \
--root . --kind package \
--repository https://repos.quixos.org/example/package-example.git \
--commit 1111111111111111111111111111111111111111 \
--checkout-root /tmp/quixos-resource-dependencies
qx resource publish qx resource publish
``` ```
The second command runs from a jj checkout. It validates the lock, snapshots The resource compiler validates the local manifest against the recursively
the current working-copy commit, and pushes the immutable tag resolved locks without turning the resource into a workspace. The final
command runs from a jj checkout. It performs that same recursive compilation,
snapshots the current working-copy commit, and pushes the immutable tag
`refs/tags/quixos-reachability/<commit>` without advancing an authoring `refs/tags/quixos-reachability/<commit>` without advancing an authoring
bookmark. bookmark.
A workspace root may split its resource pins into same-repository fragments:
```text
quixos-lock version 1 {
quixos source {
repository "https://repos.quixos.org/quixos/quixos.git";
commit "1111111111111111111111111111111111111111";
}
import "locks/web-studio.lock";
}
```
```text
quixos-lock fragment version 1 {
package CanvasRuntime source {
repository "https://repos.quixos.org/org-quixos-web-studio/package-canvas-runtime.git";
commit "2222222222222222222222222222222222222222";
}
}
```
Import paths are normalized, repository-root-relative paths. Absolute paths,
URLs, traversal, empty segments, directories, and symbolic links are rejected.
Fragments may import other fragments; cycles fail, shared fragments are loaded
once, and duplicate resource bindings fail across the flattened closure.
`quixos-lock-check` resolves the complete closure and reports its `sourceFiles`
alongside the flattened resources. The root Git commit content-addresses every
fragment, so fragments do not become independent repositories or identities.
## Package descriptors ## Package descriptors
Executable package metadata remains protobuf text format: Executable package metadata remains protobuf text format:
@@ -59,6 +115,7 @@ their exact dependency ports.
nix develop -c yarn test nix develop -c yarn test
``` ```
The suite covers parsing/diagnostics, source-order independence, ordinary call The suite covers parsing/diagnostics, recursive repository assembly, external
operations, semantic validation, exact closure/tree-shaking, private and shared requirement validation, source-order independence, ordinary call operations,
attachments, package port injection, and constructors. semantic validation, exact closure/tree-shaking, private and shared
attachments, related-object interface-port injection, and constructors.
+26
View File
@@ -15,20 +15,34 @@
src = pkgs.lib.cleanSource ./.; src = pkgs.lib.cleanSource ./.;
overrideAttrs = old: { overrideAttrs = old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [
pkgs.diffutils
pkgs.esbuild pkgs.esbuild
pkgs.protobuf pkgs.protobuf
]; ];
buildPhase = '' buildPhase = ''
runHook preBuild runHook preBuild
mkdir -p "$TMPDIR/generated-before"
cp --recursive src/gen "$TMPDIR/generated-before/proto"
cp --recursive src/capability-language/generated "$TMPDIR/generated-before/capability"
cp --recursive src/resource-lock/generated "$TMPDIR/generated-before/lock"
export QUIXOS_PROTO_PATH="${pkgs.protobuf}/include:$PWD/proto''${QUIXOS_PROTO_PATH:+:$QUIXOS_PROTO_PATH}" export QUIXOS_PROTO_PATH="${pkgs.protobuf}/include:$PWD/proto''${QUIXOS_PROTO_PATH:+:$QUIXOS_PROTO_PATH}"
patchShebangs node_modules/.bin node_modules/@bufbuild/protoc-gen-es/bin patchShebangs node_modules/.bin node_modules/@bufbuild/protoc-gen-es/bin
yarn build yarn build
diff --recursive --unified "$TMPDIR/generated-before/proto" src/gen
diff --recursive --unified "$TMPDIR/generated-before/capability" src/capability-language/generated
diff --recursive --unified "$TMPDIR/generated-before/lock" src/resource-lock/generated
esbuild dist/src/descriptor-check.js \ esbuild dist/src/descriptor-check.js \
--bundle --platform=node --target=node24 --format=esm \ --bundle --platform=node --target=node24 --format=esm \
--outfile=quixos-descriptor-check.mjs --outfile=quixos-descriptor-check.mjs
esbuild dist/src/capability-language/cli.js \ esbuild dist/src/capability-language/cli.js \
--bundle --platform=node --target=node24 --format=esm \ --bundle --platform=node --target=node24 --format=esm \
--outfile=quixos-capability-compile.mjs --outfile=quixos-capability-compile.mjs
esbuild dist/src/capability-language/workspace-cli.js \
--bundle --platform=node --target=node24 --format=esm \
--outfile=quixos-workspace-compile.mjs
esbuild dist/src/capability-language/resource-cli.js \
--bundle --platform=node --target=node24 --format=esm \
--outfile=quixos-resource-compile.mjs
esbuild dist/src/resource-lock/cli.js \ esbuild dist/src/resource-lock/cli.js \
--bundle --platform=node --target=node24 --format=esm \ --bundle --platform=node --target=node24 --format=esm \
--outfile=quixos-lock-check.mjs --outfile=quixos-lock-check.mjs
@@ -60,6 +74,16 @@ EOF
exec ${pkgs.nodejs_24}/bin/node "$out/libexec/quixos-protocol/quixos-capability-compile.mjs" "\$@" exec ${pkgs.nodejs_24}/bin/node "$out/libexec/quixos-protocol/quixos-capability-compile.mjs" "\$@"
EOF EOF
chmod +x "$out/bin/quixos-capability-compile" chmod +x "$out/bin/quixos-capability-compile"
cat > "$out/bin/quixos-workspace-compile" <<EOF
#!/bin/sh
exec ${pkgs.nodejs_24}/bin/node "$out/libexec/quixos-protocol/quixos-workspace-compile.mjs" "\$@"
EOF
chmod +x "$out/bin/quixos-workspace-compile"
cat > "$out/bin/quixos-resource-compile" <<EOF
#!/bin/sh
exec ${pkgs.nodejs_24}/bin/node "$out/libexec/quixos-protocol/quixos-resource-compile.mjs" "\$@"
EOF
chmod +x "$out/bin/quixos-resource-compile"
cat > "$out/bin/quixos-lock-check" <<EOF cat > "$out/bin/quixos-lock-check" <<EOF
#!/bin/sh #!/bin/sh
exec ${pkgs.nodejs_24}/bin/node "$out/libexec/quixos-protocol/quixos-lock-check.mjs" "\$@" exec ${pkgs.nodejs_24}/bin/node "$out/libexec/quixos-protocol/quixos-lock-check.mjs" "\$@"
@@ -68,6 +92,8 @@ EOF
mkdir -p "$out/libexec/quixos-protocol" mkdir -p "$out/libexec/quixos-protocol"
install -m644 quixos-descriptor-check.mjs "$out/libexec/quixos-protocol/quixos-descriptor-check.mjs" install -m644 quixos-descriptor-check.mjs "$out/libexec/quixos-protocol/quixos-descriptor-check.mjs"
install -m644 quixos-capability-compile.mjs "$out/libexec/quixos-protocol/quixos-capability-compile.mjs" install -m644 quixos-capability-compile.mjs "$out/libexec/quixos-protocol/quixos-capability-compile.mjs"
install -m644 quixos-workspace-compile.mjs "$out/libexec/quixos-protocol/quixos-workspace-compile.mjs"
install -m644 quixos-resource-compile.mjs "$out/libexec/quixos-protocol/quixos-resource-compile.mjs"
install -m644 quixos-lock-check.mjs "$out/libexec/quixos-protocol/quixos-lock-check.mjs" install -m644 quixos-lock-check.mjs "$out/libexec/quixos-protocol/quixos-lock-check.mjs"
runHook postInstall runHook postInstall
''; '';
+29 -14
View File
@@ -2,6 +2,8 @@ grammar QuixosCapability;
document document
: workspaceDecl EOF : workspaceDecl EOF
| interfaceResourceDecl EOF
| packageResourceDecl EOF
; ;
workspaceDecl workspaceDecl
@@ -11,29 +13,40 @@ workspaceDecl
workspaceItem workspaceItem
: atomDecl : atomDecl
| interfaceDecl | resourceImportDecl
| packageDecl
| sharedAttachmentDecl | sharedAttachmentDecl
| conformanceDecl | conformanceDecl
| constructorBindingDecl | constructorBindingDecl
; ;
resourceImportDecl
: IMPORT INTERFACE identifier SEMI
| IMPORT PACKAGE identifier SEMI
;
externalAtomDecl
: EXTERNAL ATOM identifier ID stringLiteral SEMI
;
externalInterfaceDecl
: EXTERNAL INTERFACE identifier REVISION stringLiteral SEMI
;
resourcePreamble
: resourceImportDecl
| externalAtomDecl
| externalInterfaceDecl
;
atomDecl atomDecl
: ATOM identifier ID stringLiteral (DOC stringLiteral)? SEMI : ATOM identifier ID stringLiteral (DOC stringLiteral)? SEMI
; ;
interfaceDecl interfaceResourceDecl
: INTERFACE identifier ID stringLiteral REVISION stringLiteral sourceBlock : resourcePreamble* INTERFACE identifier ID stringLiteral REVISION stringLiteral
LBRACE interfaceMember* RBRACE LBRACE interfaceMember* RBRACE
; ;
sourceBlock
: SOURCE LBRACE
REPOSITORY stringLiteral SEMI
COMMIT stringLiteral SEMI
RBRACE
;
interfaceMember interfaceMember
: valueMember : valueMember
| relationshipMember | relationshipMember
@@ -73,8 +86,8 @@ targetConstraint
| INTERFACE identifier | INTERFACE identifier
; ;
packageDecl packageResourceDecl
: PACKAGE identifier ID stringLiteral REVISION stringLiteral sourceBlock : resourcePreamble* PACKAGE identifier ID stringLiteral REVISION stringLiteral
LBRACE packageExport* RBRACE LBRACE packageExport* RBRACE
; ;
@@ -237,7 +250,7 @@ dependencyBindingBlock
dependencyBinding dependencyBinding
: identifier TO STATE identifier (VIA EDGE identifier DOT identifier)? SEMI : identifier TO STATE identifier (VIA EDGE identifier DOT identifier)? SEMI
| identifier TO EDGE identifier DOT identifier (VIA EDGE identifier DOT identifier)? SEMI | identifier TO EDGE identifier DOT identifier (VIA EDGE identifier DOT identifier)? SEMI
| identifier TO INTERFACE identifier SEMI | identifier TO INTERFACE identifier (VIA EDGE identifier DOT identifier)? SEMI
| identifier TO CONSTRUCTOR identifier SEMI | identifier TO CONSTRUCTOR identifier SEMI
; ;
@@ -307,6 +320,8 @@ stringLiteral
; ;
WORKSPACE: 'workspace'; WORKSPACE: 'workspace';
IMPORT: 'import';
EXTERNAL: 'external';
ATOM: 'atom'; ATOM: 'atom';
INTERFACE: 'interface'; INTERFACE: 'interface';
INTERFACES: 'interfaces'; INTERFACES: 'interfaces';
+8 -1
View File
@@ -1,7 +1,8 @@
grammar QuixosLock; grammar QuixosLock;
document document
: QUIXOS_LOCK VERSION INTEGER LBRACE quixosEntry resourceEntry* RBRACE EOF : QUIXOS_LOCK FRAGMENT? VERSION INTEGER LBRACE
(quixosEntry | importEntry | resourceEntry)* RBRACE EOF
; ;
quixosEntry quixosEntry
@@ -12,6 +13,10 @@ resourceEntry
: resourceKind identifier SOURCE sourceBlock : resourceKind identifier SOURCE sourceBlock
; ;
importEntry
: IMPORT stringLiteral SEMI
;
resourceKind resourceKind
: INTERFACE : INTERFACE
| PACKAGE | PACKAGE
@@ -33,6 +38,7 @@ stringLiteral
; ;
QUIXOS_LOCK: 'quixos-lock'; QUIXOS_LOCK: 'quixos-lock';
FRAGMENT: 'fragment';
VERSION: 'version'; VERSION: 'version';
QUIXOS: 'quixos'; QUIXOS: 'quixos';
SOURCE: 'source'; SOURCE: 'source';
@@ -40,6 +46,7 @@ INTERFACE: 'interface';
PACKAGE: 'package'; PACKAGE: 'package';
REPOSITORY: 'repository'; REPOSITORY: 'repository';
COMMIT: 'commit'; COMMIT: 'commit';
IMPORT: 'import';
LBRACE: '{'; LBRACE: '{';
RBRACE: '}'; RBRACE: '}';
+2
View File
@@ -6,6 +6,8 @@
"type": "module", "type": "module",
"bin": { "bin": {
"quixos-capability-compile": "dist/src/capability-language/cli.js", "quixos-capability-compile": "dist/src/capability-language/cli.js",
"quixos-resource-compile": "dist/src/capability-language/resource-cli.js",
"quixos-workspace-compile": "dist/src/capability-language/workspace-cli.js",
"quixos-descriptor-check": "dist/src/descriptor-check.js", "quixos-descriptor-check": "dist/src/descriptor-check.js",
"quixos-lock-check": "dist/src/resource-lock/cli.js" "quixos-lock-check": "dist/src/resource-lock/cli.js"
}, },
+4
View File
@@ -39,6 +39,9 @@ message InvokeCapabilityRequest {
quixos.CapabilityRef capability = 1; quixos.CapabilityRef capability = 1;
string object_id = 2; string object_id = 2;
map<string, camino.Value> input = 3; map<string, camino.Value> input = 3;
// Identifies one logical client mutation across the capability and Camino
// layers so a live-value controller can recognize its own confirmation.
string client_mutation_id = 4;
} }
message InvokeCapabilityResponse { message InvokeCapabilityResponse {
string invocation_id = 1; string invocation_id = 1;
@@ -46,6 +49,7 @@ message InvokeCapabilityResponse {
bool ok = 3; bool ok = 3;
camino.Value result = 4; camino.Value result = 4;
string error = 5; string error = 5;
repeated quixos.runtime.DerivedDependency dependencies = 6;
} }
message WatchCapabilityRequest { message WatchCapabilityRequest {
+1 -1
View File
@@ -17,7 +17,7 @@ message InjectedDependency {
oneof binding { oneof binding {
string state_slot_id = 2; string state_slot_id = 2;
EdgeDependency edge = 3; EdgeDependency edge = 3;
string receiver_interface_revision_id = 4; string interface_revision_id = 4;
string constructor_atom_id = 5; string constructor_atom_id = 5;
} }
// Defaults to the invocation receiver. A checked dependency traversal can // Defaults to the invocation receiver. A checked dependency traversal can
+1
View File
@@ -29,6 +29,7 @@ message InvokeResponse {
bool ok = 1; bool ok = 1;
camino.Value result = 2; camino.Value result = 2;
string error = 3; string error = 3;
repeated DerivedDependency dependencies = 4;
} }
message WatchRequest { message WatchRequest {
+359
View File
@@ -0,0 +1,359 @@
import { readFile } from "node:fs/promises";
import path from "node:path";
import {
capabilityId,
compileWorkspaceRevision,
type AtomDefinition,
type CompiledWorkspaceRevision,
type InterfaceRevision,
type PackageRevision,
type SourceRevision,
type WorkspaceRevision,
} from "../capability-model/index.js";
import {
loadQuixosLock,
type GitSource,
type LockedResource,
type QuixosRepositoryLock,
} from "../resource-lock/index.js";
import {
compileCapabilityResourceSource,
compileCapabilitySource,
type CapabilityImportEnvironment,
type CapabilityResource,
type CapabilityResourceImport,
} from "./parser.js";
export type CapabilityRepositorySnapshot = {
directory: string;
};
export type CapabilityRepositoryResolver = (
source: GitSource,
kind: LockedResource["kind"],
) => Promise<CapabilityRepositorySnapshot>;
export type ResolvedCapabilityResource = {
key: string;
kind: LockedResource["kind"];
source: GitSource;
directory: string;
lock: QuixosRepositoryLock;
resource: CapabilityResource;
dependencies: ReadonlyMap<string, ResolvedCapabilityResource>;
};
export type CompiledWorkspaceRepository = {
workspace: WorkspaceRevision;
plan: CompiledWorkspaceRevision;
lock: QuixosRepositoryLock;
resources: ResolvedCapabilityResource[];
directResources: ReadonlyMap<string, ResolvedCapabilityResource>;
};
export type CompiledCapabilityResourceRepository = {
resource: CapabilityResource;
lock: QuixosRepositoryLock;
resources: ResolvedCapabilityResource[];
directResources: ReadonlyMap<string, ResolvedCapabilityResource>;
};
const sourceKey = (kind: LockedResource["kind"], source: GitSource) =>
`${kind}\0${source.repository}\0${source.commit.toLowerCase()}`;
const bindingKey = (kind: LockedResource["kind"], binding: string) =>
`${kind}\0${binding}`;
const importsKey = (entry: CapabilityResourceImport | LockedResource) =>
bindingKey(entry.kind, entry.binding);
const assertImportsMatchLock = (
label: string,
imports: readonly CapabilityResourceImport[],
resources: readonly LockedResource[],
) => {
const authored = [...imports].map(importsKey).sort();
const locked = [...resources].map(importsKey).sort();
if (
authored.length !== locked.length ||
authored.some((entry, index) => entry !== locked[index])
) {
throw new Error(
`${label} imports do not match quixos.lock:\n` +
`authored: ${authored.join(", ") || "none"}\n` +
`locked: ${locked.join(", ") || "none"}`,
);
}
};
const exactRevisions = <Revision extends {
revisionId: string;
source: SourceRevision;
}>(revisions: readonly Revision[]) => {
const seen = new Set<string>();
return revisions.filter((revision) => {
const key = `${revision.revisionId}\0${revision.source.repository}\0${revision.source.commit}`;
if (seen.has(key)) return false;
seen.add(key);
return true;
});
};
const exactAtoms = (atoms: readonly AtomDefinition[]) => {
const seen = new Set<string>();
return atoms.filter((atom) => {
if (seen.has(atom.id)) return false;
seen.add(atom.id);
return true;
});
};
const diagnosticsMessage = (
label: string,
diagnostics: readonly {
fileName: string;
line: number;
column: number;
phase: string;
code: string;
message: string;
path?: string;
}[],
) => `${label} did not compile:\n${diagnostics.map((entry) => {
const location = entry.line > 0
? `${entry.fileName}:${entry.line}:${entry.column + 1}`
: `${entry.fileName}${entry.path ? `:${entry.path}` : ""}`;
return `${location}: ${entry.phase} ${entry.code}: ${entry.message}`;
}).join("\n")}`;
const revisionFor = (node: ResolvedCapabilityResource) =>
node.resource.revision;
const resourceClosure = (
roots: readonly ResolvedCapabilityResource[],
): ResolvedCapabilityResource[] => {
const result: ResolvedCapabilityResource[] = [];
const seen = new Set<string>();
const visit = (node: ResolvedCapabilityResource) => {
if (seen.has(node.key)) return;
seen.add(node.key);
for (const dependency of node.dependencies.values()) visit(dependency);
result.push(node);
};
for (const root of roots) visit(root);
return result;
};
const environmentFor = (
direct: readonly [LockedResource, ResolvedCapabilityResource][],
closure: readonly ResolvedCapabilityResource[],
): CapabilityImportEnvironment => ({
interfaces: new Map(direct.flatMap(([locked, node]) =>
node.resource.kind === "interface"
? [[locked.binding, node.resource.revision] as const]
: [])),
packages: new Map(direct.flatMap(([locked, node]) =>
node.resource.kind === "package"
? [[locked.binding, node.resource.revision] as const]
: [])),
interfaceClosure: exactRevisions(closure.flatMap((node) =>
node.resource.kind === "interface" ? [node.resource.revision] : [])),
packageClosure: exactRevisions(closure.flatMap((node) =>
node.resource.kind === "package" ? [node.resource.revision] : [])),
externalAtoms: exactAtoms(closure.flatMap((node) => node.resource.externalAtoms)),
});
const createResourceGraphResolver = (
quixosCommit: string,
resolveResource: CapabilityRepositoryResolver,
) => {
const resolved = new Map<string, Promise<ResolvedCapabilityResource>>();
const active: string[] = [];
const visit = async (
locked: LockedResource,
suppliedSnapshot?: CapabilityRepositorySnapshot,
): Promise<ResolvedCapabilityResource> => {
const key = sourceKey(locked.kind, locked.source);
const cached = resolved.get(key);
if (cached) {
if (active.includes(key)) {
throw new Error(`Resource dependency cycle: ${[...active, key].join(" -> ")}`);
}
return await cached;
}
const pending = (async () => {
active.push(key);
try {
const snapshot = suppliedSnapshot ?? await resolveResource(locked.source, locked.kind);
const lockResult = await loadQuixosLock(path.join(snapshot.directory, "quixos.lock"));
if (!lockResult.ok) {
throw new Error(diagnosticsMessage(`${locked.kind} ${locked.binding} lock`, lockResult.diagnostics));
}
if (lockResult.lock.quixos.commit.toLowerCase() !== quixosCommit.toLowerCase()) {
throw new Error(
`${locked.kind} ${locked.binding} selects Quixos ${lockResult.lock.quixos.commit}, ` +
`but the repository graph selects ${quixosCommit}`,
);
}
const directPairs: Array<[LockedResource, ResolvedCapabilityResource]> = [];
for (const dependency of lockResult.lock.resources) {
directPairs.push([dependency, await visit(dependency)]);
}
const dependencyClosure = resourceClosure(
directPairs.map(([, node]) => node),
);
const environment = environmentFor(directPairs, dependencyClosure);
const manifestName = locked.kind === "interface" ? "interface.qx" : "package.qx";
const manifestPath = path.join(snapshot.directory, manifestName);
const sourceText = await readFile(manifestPath, "utf8");
const compiled = compileCapabilityResourceSource(sourceText, {
source: locked.source,
fileName: manifestPath,
environment,
});
if (!compiled.ok) {
throw new Error(diagnosticsMessage(`${locked.kind} ${locked.binding}`, compiled.diagnostics));
}
if (compiled.resource.kind !== locked.kind) {
throw new Error(
`${manifestPath} declares ${compiled.resource.kind}, not ${locked.kind}`,
);
}
assertImportsMatchLock(manifestPath, compiled.resource.imports, lockResult.lock.resources);
return {
key,
kind: locked.kind,
source: locked.source,
directory: snapshot.directory,
lock: lockResult.lock,
resource: compiled.resource,
dependencies: new Map(directPairs.map(([dependency, node]) => [
bindingKey(dependency.kind, dependency.binding),
node,
])),
};
} finally {
active.pop();
}
})();
resolved.set(key, pending);
return await pending;
};
return {
visit,
nodes: async () => await Promise.all(resolved.values()),
};
};
export const compileCapabilityResourceRepository = async (options: {
rootDirectory: string;
kind: LockedResource["kind"];
source: GitSource;
resolveResource: CapabilityRepositoryResolver;
}): Promise<CompiledCapabilityResourceRepository> => {
const lockResult = await loadQuixosLock(path.join(options.rootDirectory, "quixos.lock"));
if (!lockResult.ok) {
throw new Error(diagnosticsMessage("Resource lock", lockResult.diagnostics));
}
const resolver = createResourceGraphResolver(
lockResult.lock.quixos.commit,
options.resolveResource,
);
const root = await resolver.visit({
kind: options.kind,
binding: "<root>",
source: options.source,
}, { directory: options.rootDirectory });
return {
resource: root.resource,
lock: root.lock,
resources: await resolver.nodes(),
directResources: root.dependencies,
};
};
export const compileWorkspaceRepository = async (options: {
rootDirectory: string;
resolveResource: CapabilityRepositoryResolver;
workspaceId?: string;
workspaceRevisionId?: string;
sourceRootCommit?: string;
}): Promise<CompiledWorkspaceRepository> => {
const rootLockResult = await loadQuixosLock(
path.join(options.rootDirectory, "quixos.lock"),
);
if (!rootLockResult.ok) {
throw new Error(diagnosticsMessage("Workspace lock", rootLockResult.diagnostics));
}
const rootLock = rootLockResult.lock;
const resolver = createResourceGraphResolver(rootLock.quixos.commit, options.resolveResource);
const directPairs: Array<[LockedResource, ResolvedCapabilityResource]> = [];
for (const locked of rootLock.resources) {
directPairs.push([locked, await resolver.visit(locked)]);
}
const nodes = await resolver.nodes();
const environment = environmentFor(directPairs, nodes);
const workspacePath = path.join(options.rootDirectory, "workspace.qx");
const workspaceSource = await readFile(workspacePath, "utf8");
const compiled = compileCapabilitySource(workspaceSource, workspacePath, environment);
if (!compiled.ok) {
throw new Error(diagnosticsMessage("Workspace", compiled.diagnostics));
}
assertImportsMatchLock(workspacePath, compiled.imports, rootLock.resources);
const availableInterfaceIds = new Set(
nodes.flatMap((node) => node.resource.kind === "interface"
? [node.resource.revision.revisionId]
: []),
);
const availableAtomIds = new Set(compiled.workspace.atoms.map((atom) => atom.id));
for (const node of nodes) {
for (const requirement of node.resource.externalInterfaces) {
if (!availableInterfaceIds.has(requirement.revisionId)) {
throw new Error(
`${node.kind} ${node.resource.revision.displayName} requires external interface ` +
`${requirement.binding} (${requirement.revisionId}), but the workspace resource graph does not provide it`,
);
}
}
for (const atom of node.resource.externalAtoms) {
if (!availableAtomIds.has(atom.id)) {
throw new Error(
`${node.kind} ${node.resource.revision.displayName} requires external atom ` +
`${atom.displayName} (${atom.id}), but the workspace does not define it`,
);
}
}
}
const workspace: WorkspaceRevision = {
...compiled.workspace,
...(options.workspaceId
? { workspaceId: capabilityId.workspace(options.workspaceId) }
: {}),
...(options.workspaceRevisionId
? { id: capabilityId.workspaceRevision(options.workspaceRevisionId) }
: {}),
...(options.sourceRootCommit
? { sourceRootCommit: options.sourceRootCommit }
: {}),
};
const checked = compileWorkspaceRevision(workspace);
if (!checked.ok) {
throw new Error(
`Instantiated workspace did not compile:\n${checked.issues.map((entry) =>
`${entry.path}: ${entry.message}`).join("\n")}`,
);
}
return {
workspace,
plan: checked.plan,
lock: rootLock,
resources: nodes,
directResources: new Map(directPairs.map(([locked, node]) => [
bindingKey(locked.kind, locked.binding),
node,
])),
};
};
File diff suppressed because one or more lines are too long
@@ -1,193 +1,197 @@
WORKSPACE=1 WORKSPACE=1
ATOM=2 IMPORT=2
INTERFACE=3 EXTERNAL=3
INTERFACES=4 ATOM=4
PACKAGE=5 INTERFACE=5
VALUE=6 INTERFACES=6
RELATION=7 PACKAGE=7
OPERATION=8 VALUE=8
FUNCTION=9 RELATION=9
CONSTRUCTOR=10 OPERATION=10
CONSTRUCTS=11 FUNCTION=11
CONFORM=12 CONSTRUCTOR=12
AS=13 CONSTRUCTS=13
BIND=14 CONFORM=14
TO=15 AS=15
PRIVATE=16 BIND=16
SHARED=17 TO=17
STATE=18 PRIVATE=18
EDGE=19 SHARED=19
PROJECTION=20 STATE=20
WITH=21 EDGE=21
USING=22 PROJECTION=22
VIA=23 WITH=23
MATERIALIZE=24 USING=24
IF=25 VIA=25
ABSENT=26 MATERIALIZE=26
ON=27 IF=27
POLICY=28 ABSENT=28
DEFAULT=29 ON=29
SOURCE=30 POLICY=30
REPOSITORY=31 DEFAULT=31
COMMIT=32 SOURCE=32
REVISION=33 REPOSITORY=33
ID=34 COMMIT=34
DOC=35 REVISION=35
MODE=36 ID=36
EMITS=37 DOC=37
RECEIVER=38 MODE=38
REQUIRES=39 EMITS=39
ANY=40 RECEIVER=40
GET=41 REQUIRES=41
SET=42 ANY=42
WATCH=43 GET=43
START=44 SET=44
STOP=45 WATCH=45
READ=46 START=46
WRITE=47 STOP=47
RESOLVE=48 READ=48
CONNECT=49 WRITE=49
DISCONNECT=50 RESOLVE=50
CALL=51 CONNECT=51
WATCH_START=52 DISCONNECT=52
WATCH_STOP=53 CALL=53
SUBSCRIBE=54 WATCH_START=54
UNSUBSCRIBE=55 WATCH_STOP=55
OPTIMISTIC_REGISTER=56 SUBSCRIBE=56
CRDT=57 UNSUBSCRIBE=57
OPTIONAL_ONE=58 OPTIMISTIC_REGISTER=58
EXACTLY_ONE=59 CRDT=59
MANY_UNIQUE=60 OPTIONAL_ONE=60
MANY=61 EXACTLY_ONE=61
ORDERED=62 MANY_UNIQUE=62
UNIT=63 MANY=63
WATCH_HANDLE=64 ORDERED=64
MESSAGE=65 UNIT=65
ATOM_REF=66 WATCH_HANDLE=66
INTERFACE_REF=67 MESSAGE=67
OPTIONAL=68 ATOM_REF=68
LIST=69 INTERFACE_REF=69
BOOL=70 OPTIONAL=70
BYTES=71 LIST=71
DOUBLE=72 BOOL=72
INT32=73 BYTES=73
INT64=74 DOUBLE=74
STRING=75 INT32=75
UINT32=76 INT64=76
UINT64=77 STRING=77
TRUE=78 UINT32=78
FALSE=79 UINT64=79
NULL=80 TRUE=80
ARROW=81 FALSE=81
COLON=82 NULL=82
SEMI=83 ARROW=83
COMMA=84 COLON=84
DOT=85 SEMI=85
LBRACE=86 COMMA=86
RBRACE=87 DOT=87
LBRACK=88 LBRACE=88
RBRACK=89 RBRACE=89
LPAREN=90 LBRACK=90
RPAREN=91 RBRACK=91
LT=92 LPAREN=92
GT=93 RPAREN=93
INTEGER=94 LT=94
JSON_NUMBER=95 GT=95
IDENTIFIER=96 INTEGER=96
STRING_LITERAL=97 JSON_NUMBER=97
LINE_COMMENT=98 IDENTIFIER=98
BLOCK_COMMENT=99 STRING_LITERAL=99
WS=100 LINE_COMMENT=100
BLOCK_COMMENT=101
WS=102
'workspace'=1 'workspace'=1
'atom'=2 'import'=2
'interface'=3 'external'=3
'interfaces'=4 'atom'=4
'package'=5 'interface'=5
'value'=6 'interfaces'=6
'relation'=7 'package'=7
'operation'=8 'value'=8
'function'=9 'relation'=9
'constructor'=10 'operation'=10
'constructs'=11 'function'=11
'conform'=12 'constructor'=12
'as'=13 'constructs'=13
'bind'=14 'conform'=14
'to'=15 'as'=15
'private'=16 'bind'=16
'shared'=17 'to'=17
'state'=18 'private'=18
'edge'=19 'shared'=19
'projection'=20 'state'=20
'with'=21 'edge'=21
'using'=22 'projection'=22
'via'=23 'with'=23
'materialize'=24 'using'=24
'if'=25 'via'=25
'absent'=26 'materialize'=26
'on'=27 'if'=27
'policy'=28 'absent'=28
'default'=29 'on'=29
'source'=30 'policy'=30
'repository'=31 'default'=31
'commit'=32 'source'=32
'revision'=33 'repository'=33
'id'=34 'commit'=34
'doc'=35 'revision'=35
'mode'=36 'id'=36
'emits'=37 'doc'=37
'receiver'=38 'mode'=38
'requires'=39 'emits'=39
'any'=40 'receiver'=40
'get'=41 'requires'=41
'set'=42 'any'=42
'watch'=43 'get'=43
'start'=44 'set'=44
'stop'=45 'watch'=45
'read'=46 'start'=46
'write'=47 'stop'=47
'resolve'=48 'read'=48
'connect'=49 'write'=49
'disconnect'=50 'resolve'=50
'call'=51 'connect'=51
'watch-start'=52 'disconnect'=52
'watch-stop'=53 'call'=53
'subscribe'=54 'watch-start'=54
'unsubscribe'=55 'watch-stop'=55
'optimistic-register'=56 'subscribe'=56
'crdt'=57 'unsubscribe'=57
'optional-one'=58 'optimistic-register'=58
'exactly-one'=59 'crdt'=59
'many-unique'=60 'optional-one'=60
'many'=61 'exactly-one'=61
'ordered'=62 'many-unique'=62
'unit'=63 'many'=63
'watch-handle'=64 'ordered'=64
'message'=65 'unit'=65
'atom-ref'=66 'watch-handle'=66
'interface-ref'=67 'message'=67
'optional'=68 'atom-ref'=68
'list'=69 'interface-ref'=69
'bool'=70 'optional'=70
'bytes'=71 'list'=71
'double'=72 'bool'=72
'int32'=73 'bytes'=73
'int64'=74 'double'=74
'string'=75 'int32'=75
'uint32'=76 'int64'=76
'uint64'=77 'string'=77
'true'=78 'uint32'=78
'false'=79 'uint64'=79
'null'=80 'true'=80
'->'=81 'false'=81
':'=82 'null'=82
';'=83 '->'=83
','=84 ':'=84
'.'=85 ';'=85
'{'=86 ','=86
'}'=87 '.'=87
'['=88 '{'=88
']'=89 '}'=89
'('=90 '['=90
')'=91 ']'=91
'<'=92 '('=92
'>'=93 ')'=93
'<'=94
'>'=95
File diff suppressed because one or more lines are too long
@@ -1,193 +1,197 @@
WORKSPACE=1 WORKSPACE=1
ATOM=2 IMPORT=2
INTERFACE=3 EXTERNAL=3
INTERFACES=4 ATOM=4
PACKAGE=5 INTERFACE=5
VALUE=6 INTERFACES=6
RELATION=7 PACKAGE=7
OPERATION=8 VALUE=8
FUNCTION=9 RELATION=9
CONSTRUCTOR=10 OPERATION=10
CONSTRUCTS=11 FUNCTION=11
CONFORM=12 CONSTRUCTOR=12
AS=13 CONSTRUCTS=13
BIND=14 CONFORM=14
TO=15 AS=15
PRIVATE=16 BIND=16
SHARED=17 TO=17
STATE=18 PRIVATE=18
EDGE=19 SHARED=19
PROJECTION=20 STATE=20
WITH=21 EDGE=21
USING=22 PROJECTION=22
VIA=23 WITH=23
MATERIALIZE=24 USING=24
IF=25 VIA=25
ABSENT=26 MATERIALIZE=26
ON=27 IF=27
POLICY=28 ABSENT=28
DEFAULT=29 ON=29
SOURCE=30 POLICY=30
REPOSITORY=31 DEFAULT=31
COMMIT=32 SOURCE=32
REVISION=33 REPOSITORY=33
ID=34 COMMIT=34
DOC=35 REVISION=35
MODE=36 ID=36
EMITS=37 DOC=37
RECEIVER=38 MODE=38
REQUIRES=39 EMITS=39
ANY=40 RECEIVER=40
GET=41 REQUIRES=41
SET=42 ANY=42
WATCH=43 GET=43
START=44 SET=44
STOP=45 WATCH=45
READ=46 START=46
WRITE=47 STOP=47
RESOLVE=48 READ=48
CONNECT=49 WRITE=49
DISCONNECT=50 RESOLVE=50
CALL=51 CONNECT=51
WATCH_START=52 DISCONNECT=52
WATCH_STOP=53 CALL=53
SUBSCRIBE=54 WATCH_START=54
UNSUBSCRIBE=55 WATCH_STOP=55
OPTIMISTIC_REGISTER=56 SUBSCRIBE=56
CRDT=57 UNSUBSCRIBE=57
OPTIONAL_ONE=58 OPTIMISTIC_REGISTER=58
EXACTLY_ONE=59 CRDT=59
MANY_UNIQUE=60 OPTIONAL_ONE=60
MANY=61 EXACTLY_ONE=61
ORDERED=62 MANY_UNIQUE=62
UNIT=63 MANY=63
WATCH_HANDLE=64 ORDERED=64
MESSAGE=65 UNIT=65
ATOM_REF=66 WATCH_HANDLE=66
INTERFACE_REF=67 MESSAGE=67
OPTIONAL=68 ATOM_REF=68
LIST=69 INTERFACE_REF=69
BOOL=70 OPTIONAL=70
BYTES=71 LIST=71
DOUBLE=72 BOOL=72
INT32=73 BYTES=73
INT64=74 DOUBLE=74
STRING=75 INT32=75
UINT32=76 INT64=76
UINT64=77 STRING=77
TRUE=78 UINT32=78
FALSE=79 UINT64=79
NULL=80 TRUE=80
ARROW=81 FALSE=81
COLON=82 NULL=82
SEMI=83 ARROW=83
COMMA=84 COLON=84
DOT=85 SEMI=85
LBRACE=86 COMMA=86
RBRACE=87 DOT=87
LBRACK=88 LBRACE=88
RBRACK=89 RBRACE=89
LPAREN=90 LBRACK=90
RPAREN=91 RBRACK=91
LT=92 LPAREN=92
GT=93 RPAREN=93
INTEGER=94 LT=94
JSON_NUMBER=95 GT=95
IDENTIFIER=96 INTEGER=96
STRING_LITERAL=97 JSON_NUMBER=97
LINE_COMMENT=98 IDENTIFIER=98
BLOCK_COMMENT=99 STRING_LITERAL=99
WS=100 LINE_COMMENT=100
BLOCK_COMMENT=101
WS=102
'workspace'=1 'workspace'=1
'atom'=2 'import'=2
'interface'=3 'external'=3
'interfaces'=4 'atom'=4
'package'=5 'interface'=5
'value'=6 'interfaces'=6
'relation'=7 'package'=7
'operation'=8 'value'=8
'function'=9 'relation'=9
'constructor'=10 'operation'=10
'constructs'=11 'function'=11
'conform'=12 'constructor'=12
'as'=13 'constructs'=13
'bind'=14 'conform'=14
'to'=15 'as'=15
'private'=16 'bind'=16
'shared'=17 'to'=17
'state'=18 'private'=18
'edge'=19 'shared'=19
'projection'=20 'state'=20
'with'=21 'edge'=21
'using'=22 'projection'=22
'via'=23 'with'=23
'materialize'=24 'using'=24
'if'=25 'via'=25
'absent'=26 'materialize'=26
'on'=27 'if'=27
'policy'=28 'absent'=28
'default'=29 'on'=29
'source'=30 'policy'=30
'repository'=31 'default'=31
'commit'=32 'source'=32
'revision'=33 'repository'=33
'id'=34 'commit'=34
'doc'=35 'revision'=35
'mode'=36 'id'=36
'emits'=37 'doc'=37
'receiver'=38 'mode'=38
'requires'=39 'emits'=39
'any'=40 'receiver'=40
'get'=41 'requires'=41
'set'=42 'any'=42
'watch'=43 'get'=43
'start'=44 'set'=44
'stop'=45 'watch'=45
'read'=46 'start'=46
'write'=47 'stop'=47
'resolve'=48 'read'=48
'connect'=49 'write'=49
'disconnect'=50 'resolve'=50
'call'=51 'connect'=51
'watch-start'=52 'disconnect'=52
'watch-stop'=53 'call'=53
'subscribe'=54 'watch-start'=54
'unsubscribe'=55 'watch-stop'=55
'optimistic-register'=56 'subscribe'=56
'crdt'=57 'unsubscribe'=57
'optional-one'=58 'optimistic-register'=58
'exactly-one'=59 'crdt'=59
'many-unique'=60 'optional-one'=60
'many'=61 'exactly-one'=61
'ordered'=62 'many-unique'=62
'unit'=63 'many'=63
'watch-handle'=64 'ordered'=64
'message'=65 'unit'=65
'atom-ref'=66 'watch-handle'=66
'interface-ref'=67 'message'=67
'optional'=68 'atom-ref'=68
'list'=69 'interface-ref'=69
'bool'=70 'optional'=70
'bytes'=71 'list'=71
'double'=72 'bool'=72
'int32'=73 'bytes'=73
'int64'=74 'double'=74
'string'=75 'int32'=75
'uint32'=76 'int64'=76
'uint64'=77 'string'=77
'true'=78 'uint32'=78
'false'=79 'uint64'=79
'null'=80 'true'=80
'->'=81 'false'=81
':'=82 'null'=82
';'=83 '->'=83
','=84 ':'=84
'.'=85 ';'=85
'{'=86 ','=86
'}'=87 '.'=87
'['=88 '{'=88
']'=89 '}'=89
'('=90 '['=90
')'=91 ']'=91
'<'=92 '('=92
'>'=93 ')'=93
'<'=94
'>'=95
@@ -5,146 +5,149 @@ import { Token } from "antlr4ng";
export class QuixosCapabilityLexer extends antlr.Lexer { export class QuixosCapabilityLexer extends antlr.Lexer {
public static readonly WORKSPACE = 1; public static readonly WORKSPACE = 1;
public static readonly ATOM = 2; public static readonly IMPORT = 2;
public static readonly INTERFACE = 3; public static readonly EXTERNAL = 3;
public static readonly INTERFACES = 4; public static readonly ATOM = 4;
public static readonly PACKAGE = 5; public static readonly INTERFACE = 5;
public static readonly VALUE = 6; public static readonly INTERFACES = 6;
public static readonly RELATION = 7; public static readonly PACKAGE = 7;
public static readonly OPERATION = 8; public static readonly VALUE = 8;
public static readonly FUNCTION = 9; public static readonly RELATION = 9;
public static readonly CONSTRUCTOR = 10; public static readonly OPERATION = 10;
public static readonly CONSTRUCTS = 11; public static readonly FUNCTION = 11;
public static readonly CONFORM = 12; public static readonly CONSTRUCTOR = 12;
public static readonly AS = 13; public static readonly CONSTRUCTS = 13;
public static readonly BIND = 14; public static readonly CONFORM = 14;
public static readonly TO = 15; public static readonly AS = 15;
public static readonly PRIVATE = 16; public static readonly BIND = 16;
public static readonly SHARED = 17; public static readonly TO = 17;
public static readonly STATE = 18; public static readonly PRIVATE = 18;
public static readonly EDGE = 19; public static readonly SHARED = 19;
public static readonly PROJECTION = 20; public static readonly STATE = 20;
public static readonly WITH = 21; public static readonly EDGE = 21;
public static readonly USING = 22; public static readonly PROJECTION = 22;
public static readonly VIA = 23; public static readonly WITH = 23;
public static readonly MATERIALIZE = 24; public static readonly USING = 24;
public static readonly IF = 25; public static readonly VIA = 25;
public static readonly ABSENT = 26; public static readonly MATERIALIZE = 26;
public static readonly ON = 27; public static readonly IF = 27;
public static readonly POLICY = 28; public static readonly ABSENT = 28;
public static readonly DEFAULT = 29; public static readonly ON = 29;
public static readonly SOURCE = 30; public static readonly POLICY = 30;
public static readonly REPOSITORY = 31; public static readonly DEFAULT = 31;
public static readonly COMMIT = 32; public static readonly SOURCE = 32;
public static readonly REVISION = 33; public static readonly REPOSITORY = 33;
public static readonly ID = 34; public static readonly COMMIT = 34;
public static readonly DOC = 35; public static readonly REVISION = 35;
public static readonly MODE = 36; public static readonly ID = 36;
public static readonly EMITS = 37; public static readonly DOC = 37;
public static readonly RECEIVER = 38; public static readonly MODE = 38;
public static readonly REQUIRES = 39; public static readonly EMITS = 39;
public static readonly ANY = 40; public static readonly RECEIVER = 40;
public static readonly GET = 41; public static readonly REQUIRES = 41;
public static readonly SET = 42; public static readonly ANY = 42;
public static readonly WATCH = 43; public static readonly GET = 43;
public static readonly START = 44; public static readonly SET = 44;
public static readonly STOP = 45; public static readonly WATCH = 45;
public static readonly READ = 46; public static readonly START = 46;
public static readonly WRITE = 47; public static readonly STOP = 47;
public static readonly RESOLVE = 48; public static readonly READ = 48;
public static readonly CONNECT = 49; public static readonly WRITE = 49;
public static readonly DISCONNECT = 50; public static readonly RESOLVE = 50;
public static readonly CALL = 51; public static readonly CONNECT = 51;
public static readonly WATCH_START = 52; public static readonly DISCONNECT = 52;
public static readonly WATCH_STOP = 53; public static readonly CALL = 53;
public static readonly SUBSCRIBE = 54; public static readonly WATCH_START = 54;
public static readonly UNSUBSCRIBE = 55; public static readonly WATCH_STOP = 55;
public static readonly OPTIMISTIC_REGISTER = 56; public static readonly SUBSCRIBE = 56;
public static readonly CRDT = 57; public static readonly UNSUBSCRIBE = 57;
public static readonly OPTIONAL_ONE = 58; public static readonly OPTIMISTIC_REGISTER = 58;
public static readonly EXACTLY_ONE = 59; public static readonly CRDT = 59;
public static readonly MANY_UNIQUE = 60; public static readonly OPTIONAL_ONE = 60;
public static readonly MANY = 61; public static readonly EXACTLY_ONE = 61;
public static readonly ORDERED = 62; public static readonly MANY_UNIQUE = 62;
public static readonly UNIT = 63; public static readonly MANY = 63;
public static readonly WATCH_HANDLE = 64; public static readonly ORDERED = 64;
public static readonly MESSAGE = 65; public static readonly UNIT = 65;
public static readonly ATOM_REF = 66; public static readonly WATCH_HANDLE = 66;
public static readonly INTERFACE_REF = 67; public static readonly MESSAGE = 67;
public static readonly OPTIONAL = 68; public static readonly ATOM_REF = 68;
public static readonly LIST = 69; public static readonly INTERFACE_REF = 69;
public static readonly BOOL = 70; public static readonly OPTIONAL = 70;
public static readonly BYTES = 71; public static readonly LIST = 71;
public static readonly DOUBLE = 72; public static readonly BOOL = 72;
public static readonly INT32 = 73; public static readonly BYTES = 73;
public static readonly INT64 = 74; public static readonly DOUBLE = 74;
public static readonly STRING = 75; public static readonly INT32 = 75;
public static readonly UINT32 = 76; public static readonly INT64 = 76;
public static readonly UINT64 = 77; public static readonly STRING = 77;
public static readonly TRUE = 78; public static readonly UINT32 = 78;
public static readonly FALSE = 79; public static readonly UINT64 = 79;
public static readonly NULL = 80; public static readonly TRUE = 80;
public static readonly ARROW = 81; public static readonly FALSE = 81;
public static readonly COLON = 82; public static readonly NULL = 82;
public static readonly SEMI = 83; public static readonly ARROW = 83;
public static readonly COMMA = 84; public static readonly COLON = 84;
public static readonly DOT = 85; public static readonly SEMI = 85;
public static readonly LBRACE = 86; public static readonly COMMA = 86;
public static readonly RBRACE = 87; public static readonly DOT = 87;
public static readonly LBRACK = 88; public static readonly LBRACE = 88;
public static readonly RBRACK = 89; public static readonly RBRACE = 89;
public static readonly LPAREN = 90; public static readonly LBRACK = 90;
public static readonly RPAREN = 91; public static readonly RBRACK = 91;
public static readonly LT = 92; public static readonly LPAREN = 92;
public static readonly GT = 93; public static readonly RPAREN = 93;
public static readonly INTEGER = 94; public static readonly LT = 94;
public static readonly JSON_NUMBER = 95; public static readonly GT = 95;
public static readonly IDENTIFIER = 96; public static readonly INTEGER = 96;
public static readonly STRING_LITERAL = 97; public static readonly JSON_NUMBER = 97;
public static readonly LINE_COMMENT = 98; public static readonly IDENTIFIER = 98;
public static readonly BLOCK_COMMENT = 99; public static readonly STRING_LITERAL = 99;
public static readonly WS = 100; public static readonly LINE_COMMENT = 100;
public static readonly BLOCK_COMMENT = 101;
public static readonly WS = 102;
public static readonly channelNames = [ public static readonly channelNames = [
"DEFAULT_TOKEN_CHANNEL", "HIDDEN" "DEFAULT_TOKEN_CHANNEL", "HIDDEN"
]; ];
public static readonly literalNames = [ public static readonly literalNames = [
null, "'workspace'", "'atom'", "'interface'", "'interfaces'", "'package'", null, "'workspace'", "'import'", "'external'", "'atom'", "'interface'",
"'value'", "'relation'", "'operation'", "'function'", "'constructor'", "'interfaces'", "'package'", "'value'", "'relation'", "'operation'",
"'constructs'", "'conform'", "'as'", "'bind'", "'to'", "'private'", "'function'", "'constructor'", "'constructs'", "'conform'", "'as'",
"'shared'", "'state'", "'edge'", "'projection'", "'with'", "'using'", "'bind'", "'to'", "'private'", "'shared'", "'state'", "'edge'",
"'via'", "'materialize'", "'if'", "'absent'", "'on'", "'policy'", "'projection'", "'with'", "'using'", "'via'", "'materialize'", "'if'",
"'default'", "'source'", "'repository'", "'commit'", "'revision'", "'absent'", "'on'", "'policy'", "'default'", "'source'", "'repository'",
"'id'", "'doc'", "'mode'", "'emits'", "'receiver'", "'requires'", "'commit'", "'revision'", "'id'", "'doc'", "'mode'", "'emits'",
"'any'", "'get'", "'set'", "'watch'", "'start'", "'stop'", "'read'", "'receiver'", "'requires'", "'any'", "'get'", "'set'", "'watch'",
"'write'", "'resolve'", "'connect'", "'disconnect'", "'call'", "'watch-start'", "'start'", "'stop'", "'read'", "'write'", "'resolve'", "'connect'",
"'watch-stop'", "'subscribe'", "'unsubscribe'", "'optimistic-register'", "'disconnect'", "'call'", "'watch-start'", "'watch-stop'", "'subscribe'",
"'crdt'", "'optional-one'", "'exactly-one'", "'many-unique'", "'many'", "'unsubscribe'", "'optimistic-register'", "'crdt'", "'optional-one'",
"'ordered'", "'unit'", "'watch-handle'", "'message'", "'atom-ref'", "'exactly-one'", "'many-unique'", "'many'", "'ordered'", "'unit'",
"'interface-ref'", "'optional'", "'list'", "'bool'", "'bytes'", "'watch-handle'", "'message'", "'atom-ref'", "'interface-ref'",
"'double'", "'int32'", "'int64'", "'string'", "'uint32'", "'uint64'", "'optional'", "'list'", "'bool'", "'bytes'", "'double'", "'int32'",
"'true'", "'false'", "'null'", "'->'", "':'", "';'", "','", "'.'", "'int64'", "'string'", "'uint32'", "'uint64'", "'true'", "'false'",
"'{'", "'}'", "'['", "']'", "'('", "')'", "'<'", "'>'" "'null'", "'->'", "':'", "';'", "','", "'.'", "'{'", "'}'", "'['",
"']'", "'('", "')'", "'<'", "'>'"
]; ];
public static readonly symbolicNames = [ public static readonly symbolicNames = [
null, "WORKSPACE", "ATOM", "INTERFACE", "INTERFACES", "PACKAGE", null, "WORKSPACE", "IMPORT", "EXTERNAL", "ATOM", "INTERFACE", "INTERFACES",
"VALUE", "RELATION", "OPERATION", "FUNCTION", "CONSTRUCTOR", "CONSTRUCTS", "PACKAGE", "VALUE", "RELATION", "OPERATION", "FUNCTION", "CONSTRUCTOR",
"CONFORM", "AS", "BIND", "TO", "PRIVATE", "SHARED", "STATE", "EDGE", "CONSTRUCTS", "CONFORM", "AS", "BIND", "TO", "PRIVATE", "SHARED",
"PROJECTION", "WITH", "USING", "VIA", "MATERIALIZE", "IF", "ABSENT", "STATE", "EDGE", "PROJECTION", "WITH", "USING", "VIA", "MATERIALIZE",
"ON", "POLICY", "DEFAULT", "SOURCE", "REPOSITORY", "COMMIT", "REVISION", "IF", "ABSENT", "ON", "POLICY", "DEFAULT", "SOURCE", "REPOSITORY",
"ID", "DOC", "MODE", "EMITS", "RECEIVER", "REQUIRES", "ANY", "GET", "COMMIT", "REVISION", "ID", "DOC", "MODE", "EMITS", "RECEIVER",
"SET", "WATCH", "START", "STOP", "READ", "WRITE", "RESOLVE", "CONNECT", "REQUIRES", "ANY", "GET", "SET", "WATCH", "START", "STOP", "READ",
"DISCONNECT", "CALL", "WATCH_START", "WATCH_STOP", "SUBSCRIBE", "WRITE", "RESOLVE", "CONNECT", "DISCONNECT", "CALL", "WATCH_START",
"UNSUBSCRIBE", "OPTIMISTIC_REGISTER", "CRDT", "OPTIONAL_ONE", "EXACTLY_ONE", "WATCH_STOP", "SUBSCRIBE", "UNSUBSCRIBE", "OPTIMISTIC_REGISTER",
"MANY_UNIQUE", "MANY", "ORDERED", "UNIT", "WATCH_HANDLE", "MESSAGE", "CRDT", "OPTIONAL_ONE", "EXACTLY_ONE", "MANY_UNIQUE", "MANY", "ORDERED",
"ATOM_REF", "INTERFACE_REF", "OPTIONAL", "LIST", "BOOL", "BYTES", "UNIT", "WATCH_HANDLE", "MESSAGE", "ATOM_REF", "INTERFACE_REF",
"DOUBLE", "INT32", "INT64", "STRING", "UINT32", "UINT64", "TRUE", "OPTIONAL", "LIST", "BOOL", "BYTES", "DOUBLE", "INT32", "INT64",
"FALSE", "NULL", "ARROW", "COLON", "SEMI", "COMMA", "DOT", "LBRACE", "STRING", "UINT32", "UINT64", "TRUE", "FALSE", "NULL", "ARROW",
"RBRACE", "LBRACK", "RBRACK", "LPAREN", "RPAREN", "LT", "GT", "INTEGER", "COLON", "SEMI", "COMMA", "DOT", "LBRACE", "RBRACE", "LBRACK", "RBRACK",
"JSON_NUMBER", "IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT", "BLOCK_COMMENT", "LPAREN", "RPAREN", "LT", "GT", "INTEGER", "JSON_NUMBER", "IDENTIFIER",
"WS" "STRING_LITERAL", "LINE_COMMENT", "BLOCK_COMMENT", "WS"
]; ];
public static readonly modeNames = [ public static readonly modeNames = [
@@ -152,22 +155,23 @@ export class QuixosCapabilityLexer extends antlr.Lexer {
]; ];
public static readonly ruleNames = [ public static readonly ruleNames = [
"WORKSPACE", "ATOM", "INTERFACE", "INTERFACES", "PACKAGE", "VALUE", "WORKSPACE", "IMPORT", "EXTERNAL", "ATOM", "INTERFACE", "INTERFACES",
"RELATION", "OPERATION", "FUNCTION", "CONSTRUCTOR", "CONSTRUCTS", "PACKAGE", "VALUE", "RELATION", "OPERATION", "FUNCTION", "CONSTRUCTOR",
"CONFORM", "AS", "BIND", "TO", "PRIVATE", "SHARED", "STATE", "EDGE", "CONSTRUCTS", "CONFORM", "AS", "BIND", "TO", "PRIVATE", "SHARED",
"PROJECTION", "WITH", "USING", "VIA", "MATERIALIZE", "IF", "ABSENT", "STATE", "EDGE", "PROJECTION", "WITH", "USING", "VIA", "MATERIALIZE",
"ON", "POLICY", "DEFAULT", "SOURCE", "REPOSITORY", "COMMIT", "REVISION", "IF", "ABSENT", "ON", "POLICY", "DEFAULT", "SOURCE", "REPOSITORY",
"ID", "DOC", "MODE", "EMITS", "RECEIVER", "REQUIRES", "ANY", "GET", "COMMIT", "REVISION", "ID", "DOC", "MODE", "EMITS", "RECEIVER",
"SET", "WATCH", "START", "STOP", "READ", "WRITE", "RESOLVE", "CONNECT", "REQUIRES", "ANY", "GET", "SET", "WATCH", "START", "STOP", "READ",
"DISCONNECT", "CALL", "WATCH_START", "WATCH_STOP", "SUBSCRIBE", "WRITE", "RESOLVE", "CONNECT", "DISCONNECT", "CALL", "WATCH_START",
"UNSUBSCRIBE", "OPTIMISTIC_REGISTER", "CRDT", "OPTIONAL_ONE", "EXACTLY_ONE", "WATCH_STOP", "SUBSCRIBE", "UNSUBSCRIBE", "OPTIMISTIC_REGISTER",
"MANY_UNIQUE", "MANY", "ORDERED", "UNIT", "WATCH_HANDLE", "MESSAGE", "CRDT", "OPTIONAL_ONE", "EXACTLY_ONE", "MANY_UNIQUE", "MANY", "ORDERED",
"ATOM_REF", "INTERFACE_REF", "OPTIONAL", "LIST", "BOOL", "BYTES", "UNIT", "WATCH_HANDLE", "MESSAGE", "ATOM_REF", "INTERFACE_REF",
"DOUBLE", "INT32", "INT64", "STRING", "UINT32", "UINT64", "TRUE", "OPTIONAL", "LIST", "BOOL", "BYTES", "DOUBLE", "INT32", "INT64",
"FALSE", "NULL", "ARROW", "COLON", "SEMI", "COMMA", "DOT", "LBRACE", "STRING", "UINT32", "UINT64", "TRUE", "FALSE", "NULL", "ARROW",
"RBRACE", "LBRACK", "RBRACK", "LPAREN", "RPAREN", "LT", "GT", "INTEGER", "COLON", "SEMI", "COMMA", "DOT", "LBRACE", "RBRACE", "LBRACK", "RBRACK",
"JSON_NUMBER", "IDENTIFIER", "STRING_LITERAL", "ESC", "HEX", "LINE_COMMENT", "LPAREN", "RPAREN", "LT", "GT", "INTEGER", "JSON_NUMBER", "IDENTIFIER",
"BLOCK_COMMENT", "WS", "STRING_LITERAL", "ESC", "HEX", "LINE_COMMENT", "BLOCK_COMMENT",
"WS",
]; ];
@@ -189,7 +193,7 @@ export class QuixosCapabilityLexer extends antlr.Lexer {
public get modeNames(): string[] { return QuixosCapabilityLexer.modeNames; } public get modeNames(): string[] { return QuixosCapabilityLexer.modeNames; }
public static readonly _serializedATN: number[] = [ public static readonly _serializedATN: number[] = [
4,0,100,937,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,102,957,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,2, 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,
@@ -204,324 +208,332 @@ export class QuixosCapabilityLexer extends antlr.Lexer {
78,7,78,2,79,7,79,2,80,7,80,2,81,7,81,2,82,7,82,2,83,7,83,2,84,7, 78,7,78,2,79,7,79,2,80,7,80,2,81,7,81,2,82,7,82,2,83,7,83,2,84,7,
84,2,85,7,85,2,86,7,86,2,87,7,87,2,88,7,88,2,89,7,89,2,90,7,90,2, 84,2,85,7,85,2,86,7,86,2,87,7,87,2,88,7,88,2,89,7,89,2,90,7,90,2,
91,7,91,2,92,7,92,2,93,7,93,2,94,7,94,2,95,7,95,2,96,7,96,2,97,7, 91,7,91,2,92,7,92,2,93,7,93,2,94,7,94,2,95,7,95,2,96,7,96,2,97,7,
97,2,98,7,98,2,99,7,99,2,100,7,100,2,101,7,101,1,0,1,0,1,0,1,0,1, 97,2,98,7,98,2,99,7,99,2,100,7,100,2,101,7,101,2,102,7,102,2,103,
0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,2,1,2,1,2,1,2,1,2,1, 7,103,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,
2,1,2,1,2,1,2,1,2,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1, 1,1,1,1,1,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,3,1,3,1,
4,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,5,1,6,1,6,1, 3,1,4,1,4,1,4,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,
6,1,6,1,6,1,6,1,6,1,6,1,6,1,7,1,7,1,7,1,7,1,7,1,7,1,7,1,7,1,7,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,1,7,1,
7,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,9,1,9,1,9,1,9,1,9,1,9,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,9,1,9,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,10,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,10,
10,1,10,1,10,1,11,1,11,1,11,1,11,1,11,1,11,1,11,1,11,1,12,1,12,1, 1,10,1,11,1,11,1,11,1,11,1,11,1,11,1,11,1,11,1,11,1,11,1,11,1,11,
12,1,13,1,13,1,13,1,13,1,13,1,14,1,14,1,14,1,15,1,15,1,15,1,15,1, 1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,13,1,13,
15,1,15,1,15,1,15,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,17,1,17,1, 1,13,1,13,1,13,1,13,1,13,1,13,1,14,1,14,1,14,1,15,1,15,1,15,1,15,
17,1,17,1,17,1,17,1,18,1,18,1,18,1,18,1,18,1,19,1,19,1,19,1,19,1, 1,15,1,16,1,16,1,16,1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,18,
19,1,19,1,19,1,19,1,19,1,19,1,19,1,20,1,20,1,20,1,20,1,20,1,21,1, 1,18,1,18,1,18,1,18,1,18,1,18,1,19,1,19,1,19,1,19,1,19,1,19,1,20,
21,1,21,1,21,1,21,1,21,1,22,1,22,1,22,1,22,1,23,1,23,1,23,1,23,1, 1,20,1,20,1,20,1,20,1,21,1,21,1,21,1,21,1,21,1,21,1,21,1,21,1,21,
23,1,23,1,23,1,23,1,23,1,23,1,23,1,23,1,24,1,24,1,24,1,25,1,25,1, 1,21,1,21,1,22,1,22,1,22,1,22,1,22,1,23,1,23,1,23,1,23,1,23,1,23,
25,1,25,1,25,1,25,1,25,1,26,1,26,1,26,1,27,1,27,1,27,1,27,1,27,1, 1,24,1,24,1,24,1,24,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,25,
27,1,27,1,28,1,28,1,28,1,28,1,28,1,28,1,28,1,28,1,29,1,29,1,29,1, 1,25,1,25,1,25,1,26,1,26,1,26,1,27,1,27,1,27,1,27,1,27,1,27,1,27,
29,1,29,1,29,1,29,1,30,1,30,1,30,1,30,1,30,1,30,1,30,1,30,1,30,1, 1,28,1,28,1,28,1,29,1,29,1,29,1,29,1,29,1,29,1,29,1,30,1,30,1,30,
30,1,30,1,31,1,31,1,31,1,31,1,31,1,31,1,31,1,32,1,32,1,32,1,32,1, 1,30,1,30,1,30,1,30,1,30,1,31,1,31,1,31,1,31,1,31,1,31,1,31,1,32,
32,1,32,1,32,1,32,1,32,1,33,1,33,1,33,1,34,1,34,1,34,1,34,1,35,1, 1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,33,1,33,1,33,
35,1,35,1,35,1,35,1,36,1,36,1,36,1,36,1,36,1,36,1,37,1,37,1,37,1, 1,33,1,33,1,33,1,33,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,
37,1,37,1,37,1,37,1,37,1,37,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1, 1,35,1,35,1,35,1,36,1,36,1,36,1,36,1,37,1,37,1,37,1,37,1,37,1,38,
38,1,38,1,39,1,39,1,39,1,39,1,40,1,40,1,40,1,40,1,41,1,41,1,41,1, 1,38,1,38,1,38,1,38,1,38,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,
41,1,42,1,42,1,42,1,42,1,42,1,42,1,43,1,43,1,43,1,43,1,43,1,43,1, 1,39,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,41,1,41,1,41,
44,1,44,1,44,1,44,1,44,1,45,1,45,1,45,1,45,1,45,1,46,1,46,1,46,1, 1,41,1,42,1,42,1,42,1,42,1,43,1,43,1,43,1,43,1,44,1,44,1,44,1,44,
46,1,46,1,46,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,48,1,48,1, 1,44,1,44,1,45,1,45,1,45,1,45,1,45,1,45,1,46,1,46,1,46,1,46,1,46,
48,1,48,1,48,1,48,1,48,1,48,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1, 1,47,1,47,1,47,1,47,1,47,1,48,1,48,1,48,1,48,1,48,1,48,1,49,1,49,
49,1,49,1,49,1,49,1,50,1,50,1,50,1,50,1,50,1,51,1,51,1,51,1,51,1, 1,49,1,49,1,49,1,49,1,49,1,49,1,50,1,50,1,50,1,50,1,50,1,50,1,50,
51,1,51,1,51,1,51,1,51,1,51,1,51,1,51,1,52,1,52,1,52,1,52,1,52,1, 1,50,1,51,1,51,1,51,1,51,1,51,1,51,1,51,1,51,1,51,1,51,1,51,1,52,
52,1,52,1,52,1,52,1,52,1,52,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1, 1,52,1,52,1,52,1,52,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,53,
53,1,53,1,53,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1, 1,53,1,53,1,53,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,54,
54,1,54,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1, 1,54,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,56,1,56,
55,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,56,1,56,1,56,1,56,1, 1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,57,1,57,1,57,
56,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1, 1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,
57,1,58,1,58,1,58,1,58,1,58,1,58,1,58,1,58,1,58,1,58,1,58,1,58,1, 1,57,1,57,1,57,1,57,1,58,1,58,1,58,1,58,1,58,1,59,1,59,1,59,1,59,
59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,60,1, 1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,60,1,60,1,60,1,60,
60,1,60,1,60,1,60,1,61,1,61,1,61,1,61,1,61,1,61,1,61,1,61,1,62,1, 1,60,1,60,1,60,1,60,1,60,1,60,1,60,1,60,1,61,1,61,1,61,1,61,1,61,
62,1,62,1,62,1,62,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1, 1,61,1,61,1,61,1,61,1,61,1,61,1,61,1,62,1,62,1,62,1,62,1,62,1,63,
63,1,63,1,63,1,63,1,64,1,64,1,64,1,64,1,64,1,64,1,64,1,64,1,65,1, 1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,64,1,64,1,64,1,64,1,64,1,65,
65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,66,1,66,1,66,1,66,1,66,1, 1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,66,
66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,67,1,67,1,67,1,67,1, 1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,67,1,67,1,67,1,67,1,67,1,67,
67,1,67,1,67,1,67,1,67,1,68,1,68,1,68,1,68,1,68,1,69,1,69,1,69,1, 1,67,1,67,1,67,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,
69,1,69,1,70,1,70,1,70,1,70,1,70,1,70,1,71,1,71,1,71,1,71,1,71,1, 1,68,1,68,1,68,1,68,1,69,1,69,1,69,1,69,1,69,1,69,1,69,1,69,1,69,
71,1,71,1,72,1,72,1,72,1,72,1,72,1,72,1,73,1,73,1,73,1,73,1,73,1, 1,70,1,70,1,70,1,70,1,70,1,71,1,71,1,71,1,71,1,71,1,72,1,72,1,72,
73,1,74,1,74,1,74,1,74,1,74,1,74,1,74,1,75,1,75,1,75,1,75,1,75,1, 1,72,1,72,1,72,1,73,1,73,1,73,1,73,1,73,1,73,1,73,1,74,1,74,1,74,
75,1,75,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,77,1,77,1,77,1,77,1, 1,74,1,74,1,74,1,75,1,75,1,75,1,75,1,75,1,75,1,76,1,76,1,76,1,76,
77,1,78,1,78,1,78,1,78,1,78,1,78,1,79,1,79,1,79,1,79,1,79,1,80,1, 1,76,1,76,1,76,1,77,1,77,1,77,1,77,1,77,1,77,1,77,1,78,1,78,1,78,
80,1,80,1,81,1,81,1,82,1,82,1,83,1,83,1,84,1,84,1,85,1,85,1,86,1, 1,78,1,78,1,78,1,78,1,79,1,79,1,79,1,79,1,79,1,80,1,80,1,80,1,80,
86,1,87,1,87,1,88,1,88,1,89,1,89,1,90,1,90,1,91,1,91,1,92,1,92,1, 1,80,1,80,1,81,1,81,1,81,1,81,1,81,1,82,1,82,1,82,1,83,1,83,1,84,
93,3,93,838,8,93,1,93,4,93,841,8,93,11,93,12,93,842,1,94,3,94,846, 1,84,1,85,1,85,1,86,1,86,1,87,1,87,1,88,1,88,1,89,1,89,1,90,1,90,
8,94,1,94,1,94,1,94,5,94,851,8,94,10,94,12,94,854,9,94,3,94,856, 1,91,1,91,1,92,1,92,1,93,1,93,1,94,1,94,1,95,3,95,858,8,95,1,95,
8,94,1,94,1,94,4,94,860,8,94,11,94,12,94,861,3,94,864,8,94,1,94, 4,95,861,8,95,11,95,12,95,862,1,96,3,96,866,8,96,1,96,1,96,1,96,
1,94,3,94,868,8,94,1,94,4,94,871,8,94,11,94,12,94,872,3,94,875,8, 5,96,871,8,96,10,96,12,96,874,9,96,3,96,876,8,96,1,96,1,96,4,96,
94,1,95,1,95,5,95,879,8,95,10,95,12,95,882,9,95,1,96,1,96,1,96,5, 880,8,96,11,96,12,96,881,3,96,884,8,96,1,96,1,96,3,96,888,8,96,1,
96,887,8,96,10,96,12,96,890,9,96,1,96,1,96,1,97,1,97,1,97,1,97,1, 96,4,96,891,8,96,11,96,12,96,892,3,96,895,8,96,1,97,1,97,5,97,899,
97,1,97,1,97,1,97,3,97,902,8,97,1,98,1,98,1,99,1,99,1,99,1,99,5, 8,97,10,97,12,97,902,9,97,1,98,1,98,1,98,5,98,907,8,98,10,98,12,
99,910,8,99,10,99,12,99,913,9,99,1,99,1,99,1,100,1,100,1,100,1,100, 98,910,9,98,1,98,1,98,1,99,1,99,1,99,1,99,1,99,1,99,1,99,1,99,3,
5,100,921,8,100,10,100,12,100,924,9,100,1,100,1,100,1,100,1,100, 99,922,8,99,1,100,1,100,1,101,1,101,1,101,1,101,5,101,930,8,101,
1,100,1,101,4,101,932,8,101,11,101,12,101,933,1,101,1,101,1,922, 10,101,12,101,933,9,101,1,101,1,101,1,102,1,102,1,102,1,102,5,102,
0,102,1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12, 941,8,102,10,102,12,102,944,9,102,1,102,1,102,1,102,1,102,1,102,
25,13,27,14,29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,22,45,23, 1,103,4,103,952,8,103,11,103,12,103,953,1,103,1,103,1,942,0,104,
47,24,49,25,51,26,53,27,55,28,57,29,59,30,61,31,63,32,65,33,67,34, 1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,25,13,
69,35,71,36,73,37,75,38,77,39,79,40,81,41,83,42,85,43,87,44,89,45, 27,14,29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,22,45,23,47,24,
91,46,93,47,95,48,97,49,99,50,101,51,103,52,105,53,107,54,109,55, 49,25,51,26,53,27,55,28,57,29,59,30,61,31,63,32,65,33,67,34,69,35,
111,56,113,57,115,58,117,59,119,60,121,61,123,62,125,63,127,64,129, 71,36,73,37,75,38,77,39,79,40,81,41,83,42,85,43,87,44,89,45,91,46,
65,131,66,133,67,135,68,137,69,139,70,141,71,143,72,145,73,147,74, 93,47,95,48,97,49,99,50,101,51,103,52,105,53,107,54,109,55,111,56,
149,75,151,76,153,77,155,78,157,79,159,80,161,81,163,82,165,83,167, 113,57,115,58,117,59,119,60,121,61,123,62,125,63,127,64,129,65,131,
84,169,85,171,86,173,87,175,88,177,89,179,90,181,91,183,92,185,93, 66,133,67,135,68,137,69,139,70,141,71,143,72,145,73,147,74,149,75,
187,94,189,95,191,96,193,97,195,0,197,0,199,98,201,99,203,100,1, 151,76,153,77,155,78,157,79,159,80,161,81,163,82,165,83,167,84,169,
0,11,1,0,48,57,1,0,49,57,2,0,69,69,101,101,2,0,43,43,45,45,3,0,65, 85,171,86,173,87,175,88,177,89,179,90,181,91,183,92,185,93,187,94,
90,95,95,97,122,4,0,48,57,65,90,95,95,97,122,4,0,10,10,13,13,34, 189,95,191,96,193,97,195,98,197,99,199,0,201,0,203,100,205,101,207,
34,92,92,8,0,34,34,47,47,92,92,98,98,102,102,110,110,114,114,116, 102,1,0,11,1,0,48,57,1,0,49,57,2,0,69,69,101,101,2,0,43,43,45,45,
116,3,0,48,57,65,70,97,102,2,0,10,10,13,13,3,0,9,10,13,13,32,32, 3,0,65,90,95,95,97,122,4,0,48,57,65,90,95,95,97,122,4,0,10,10,13,
951,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,0,0, 13,34,34,92,92,8,0,34,34,47,47,92,92,98,98,102,102,110,110,114,114,
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,0,0, 116,116,3,0,48,57,65,70,97,102,2,0,10,10,13,13,3,0,9,10,13,13,32,
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,0,0, 32,971,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,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,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,0,
0,41,1,0,0,0,0,43,1,0,0,0,0,45,1,0,0,0,0,47,1,0,0,0,0,49,1,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,0,
0,51,1,0,0,0,0,53,1,0,0,0,0,55,1,0,0,0,0,57,1,0,0,0,0,59,1,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,0,
0,61,1,0,0,0,0,63,1,0,0,0,0,65,1,0,0,0,0,67,1,0,0,0,0,69,1,0,0,0, 0,0,41,1,0,0,0,0,43,1,0,0,0,0,45,1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,
0,71,1,0,0,0,0,73,1,0,0,0,0,75,1,0,0,0,0,77,1,0,0,0,0,79,1,0,0,0, 0,0,51,1,0,0,0,0,53,1,0,0,0,0,55,1,0,0,0,0,57,1,0,0,0,0,59,1,0,0,
0,81,1,0,0,0,0,83,1,0,0,0,0,85,1,0,0,0,0,87,1,0,0,0,0,89,1,0,0,0, 0,0,61,1,0,0,0,0,63,1,0,0,0,0,65,1,0,0,0,0,67,1,0,0,0,0,69,1,0,0,
0,91,1,0,0,0,0,93,1,0,0,0,0,95,1,0,0,0,0,97,1,0,0,0,0,99,1,0,0,0, 0,0,71,1,0,0,0,0,73,1,0,0,0,0,75,1,0,0,0,0,77,1,0,0,0,0,79,1,0,0,
0,101,1,0,0,0,0,103,1,0,0,0,0,105,1,0,0,0,0,107,1,0,0,0,0,109,1, 0,0,81,1,0,0,0,0,83,1,0,0,0,0,85,1,0,0,0,0,87,1,0,0,0,0,89,1,0,0,
0,0,0,0,111,1,0,0,0,0,113,1,0,0,0,0,115,1,0,0,0,0,117,1,0,0,0,0, 0,0,91,1,0,0,0,0,93,1,0,0,0,0,95,1,0,0,0,0,97,1,0,0,0,0,99,1,0,0,
119,1,0,0,0,0,121,1,0,0,0,0,123,1,0,0,0,0,125,1,0,0,0,0,127,1,0, 0,0,101,1,0,0,0,0,103,1,0,0,0,0,105,1,0,0,0,0,107,1,0,0,0,0,109,
0,0,0,129,1,0,0,0,0,131,1,0,0,0,0,133,1,0,0,0,0,135,1,0,0,0,0,137, 1,0,0,0,0,111,1,0,0,0,0,113,1,0,0,0,0,115,1,0,0,0,0,117,1,0,0,0,
1,0,0,0,0,139,1,0,0,0,0,141,1,0,0,0,0,143,1,0,0,0,0,145,1,0,0,0, 0,119,1,0,0,0,0,121,1,0,0,0,0,123,1,0,0,0,0,125,1,0,0,0,0,127,1,
0,147,1,0,0,0,0,149,1,0,0,0,0,151,1,0,0,0,0,153,1,0,0,0,0,155,1, 0,0,0,0,129,1,0,0,0,0,131,1,0,0,0,0,133,1,0,0,0,0,135,1,0,0,0,0,
0,0,0,0,157,1,0,0,0,0,159,1,0,0,0,0,161,1,0,0,0,0,163,1,0,0,0,0, 137,1,0,0,0,0,139,1,0,0,0,0,141,1,0,0,0,0,143,1,0,0,0,0,145,1,0,
165,1,0,0,0,0,167,1,0,0,0,0,169,1,0,0,0,0,171,1,0,0,0,0,173,1,0, 0,0,0,147,1,0,0,0,0,149,1,0,0,0,0,151,1,0,0,0,0,153,1,0,0,0,0,155,
0,0,0,175,1,0,0,0,0,177,1,0,0,0,0,179,1,0,0,0,0,181,1,0,0,0,0,183, 1,0,0,0,0,157,1,0,0,0,0,159,1,0,0,0,0,161,1,0,0,0,0,163,1,0,0,0,
1,0,0,0,0,185,1,0,0,0,0,187,1,0,0,0,0,189,1,0,0,0,0,191,1,0,0,0, 0,165,1,0,0,0,0,167,1,0,0,0,0,169,1,0,0,0,0,171,1,0,0,0,0,173,1,
0,193,1,0,0,0,0,199,1,0,0,0,0,201,1,0,0,0,0,203,1,0,0,0,1,205,1, 0,0,0,0,175,1,0,0,0,0,177,1,0,0,0,0,179,1,0,0,0,0,181,1,0,0,0,0,
0,0,0,3,215,1,0,0,0,5,220,1,0,0,0,7,230,1,0,0,0,9,241,1,0,0,0,11, 183,1,0,0,0,0,185,1,0,0,0,0,187,1,0,0,0,0,189,1,0,0,0,0,191,1,0,
249,1,0,0,0,13,255,1,0,0,0,15,264,1,0,0,0,17,274,1,0,0,0,19,283, 0,0,0,193,1,0,0,0,0,195,1,0,0,0,0,197,1,0,0,0,0,203,1,0,0,0,0,205,
1,0,0,0,21,295,1,0,0,0,23,306,1,0,0,0,25,314,1,0,0,0,27,317,1,0, 1,0,0,0,0,207,1,0,0,0,1,209,1,0,0,0,3,219,1,0,0,0,5,226,1,0,0,0,
0,0,29,322,1,0,0,0,31,325,1,0,0,0,33,333,1,0,0,0,35,340,1,0,0,0, 7,235,1,0,0,0,9,240,1,0,0,0,11,250,1,0,0,0,13,261,1,0,0,0,15,269,
37,346,1,0,0,0,39,351,1,0,0,0,41,362,1,0,0,0,43,367,1,0,0,0,45,373, 1,0,0,0,17,275,1,0,0,0,19,284,1,0,0,0,21,294,1,0,0,0,23,303,1,0,
1,0,0,0,47,377,1,0,0,0,49,389,1,0,0,0,51,392,1,0,0,0,53,399,1,0, 0,0,25,315,1,0,0,0,27,326,1,0,0,0,29,334,1,0,0,0,31,337,1,0,0,0,
0,0,55,402,1,0,0,0,57,409,1,0,0,0,59,417,1,0,0,0,61,424,1,0,0,0, 33,342,1,0,0,0,35,345,1,0,0,0,37,353,1,0,0,0,39,360,1,0,0,0,41,366,
63,435,1,0,0,0,65,442,1,0,0,0,67,451,1,0,0,0,69,454,1,0,0,0,71,458, 1,0,0,0,43,371,1,0,0,0,45,382,1,0,0,0,47,387,1,0,0,0,49,393,1,0,
1,0,0,0,73,463,1,0,0,0,75,469,1,0,0,0,77,478,1,0,0,0,79,487,1,0, 0,0,51,397,1,0,0,0,53,409,1,0,0,0,55,412,1,0,0,0,57,419,1,0,0,0,
0,0,81,491,1,0,0,0,83,495,1,0,0,0,85,499,1,0,0,0,87,505,1,0,0,0, 59,422,1,0,0,0,61,429,1,0,0,0,63,437,1,0,0,0,65,444,1,0,0,0,67,455,
89,511,1,0,0,0,91,516,1,0,0,0,93,521,1,0,0,0,95,527,1,0,0,0,97,535, 1,0,0,0,69,462,1,0,0,0,71,471,1,0,0,0,73,474,1,0,0,0,75,478,1,0,
1,0,0,0,99,543,1,0,0,0,101,554,1,0,0,0,103,559,1,0,0,0,105,571,1, 0,0,77,483,1,0,0,0,79,489,1,0,0,0,81,498,1,0,0,0,83,507,1,0,0,0,
0,0,0,107,582,1,0,0,0,109,592,1,0,0,0,111,604,1,0,0,0,113,624,1, 85,511,1,0,0,0,87,515,1,0,0,0,89,519,1,0,0,0,91,525,1,0,0,0,93,531,
0,0,0,115,629,1,0,0,0,117,642,1,0,0,0,119,654,1,0,0,0,121,666,1, 1,0,0,0,95,536,1,0,0,0,97,541,1,0,0,0,99,547,1,0,0,0,101,555,1,0,
0,0,0,123,671,1,0,0,0,125,679,1,0,0,0,127,684,1,0,0,0,129,697,1, 0,0,103,563,1,0,0,0,105,574,1,0,0,0,107,579,1,0,0,0,109,591,1,0,
0,0,0,131,705,1,0,0,0,133,714,1,0,0,0,135,728,1,0,0,0,137,737,1, 0,0,111,602,1,0,0,0,113,612,1,0,0,0,115,624,1,0,0,0,117,644,1,0,
0,0,0,139,742,1,0,0,0,141,747,1,0,0,0,143,753,1,0,0,0,145,760,1, 0,0,119,649,1,0,0,0,121,662,1,0,0,0,123,674,1,0,0,0,125,686,1,0,
0,0,0,147,766,1,0,0,0,149,772,1,0,0,0,151,779,1,0,0,0,153,786,1, 0,0,127,691,1,0,0,0,129,699,1,0,0,0,131,704,1,0,0,0,133,717,1,0,
0,0,0,155,793,1,0,0,0,157,798,1,0,0,0,159,804,1,0,0,0,161,809,1, 0,0,135,725,1,0,0,0,137,734,1,0,0,0,139,748,1,0,0,0,141,757,1,0,
0,0,0,163,812,1,0,0,0,165,814,1,0,0,0,167,816,1,0,0,0,169,818,1, 0,0,143,762,1,0,0,0,145,767,1,0,0,0,147,773,1,0,0,0,149,780,1,0,
0,0,0,171,820,1,0,0,0,173,822,1,0,0,0,175,824,1,0,0,0,177,826,1, 0,0,151,786,1,0,0,0,153,792,1,0,0,0,155,799,1,0,0,0,157,806,1,0,
0,0,0,179,828,1,0,0,0,181,830,1,0,0,0,183,832,1,0,0,0,185,834,1, 0,0,159,813,1,0,0,0,161,818,1,0,0,0,163,824,1,0,0,0,165,829,1,0,
0,0,0,187,837,1,0,0,0,189,845,1,0,0,0,191,876,1,0,0,0,193,883,1, 0,0,167,832,1,0,0,0,169,834,1,0,0,0,171,836,1,0,0,0,173,838,1,0,
0,0,0,195,893,1,0,0,0,197,903,1,0,0,0,199,905,1,0,0,0,201,916,1, 0,0,175,840,1,0,0,0,177,842,1,0,0,0,179,844,1,0,0,0,181,846,1,0,
0,0,0,203,931,1,0,0,0,205,206,5,119,0,0,206,207,5,111,0,0,207,208, 0,0,183,848,1,0,0,0,185,850,1,0,0,0,187,852,1,0,0,0,189,854,1,0,
5,114,0,0,208,209,5,107,0,0,209,210,5,115,0,0,210,211,5,112,0,0, 0,0,191,857,1,0,0,0,193,865,1,0,0,0,195,896,1,0,0,0,197,903,1,0,
211,212,5,97,0,0,212,213,5,99,0,0,213,214,5,101,0,0,214,2,1,0,0, 0,0,199,913,1,0,0,0,201,923,1,0,0,0,203,925,1,0,0,0,205,936,1,0,
0,215,216,5,97,0,0,216,217,5,116,0,0,217,218,5,111,0,0,218,219,5, 0,0,207,951,1,0,0,0,209,210,5,119,0,0,210,211,5,111,0,0,211,212,
109,0,0,219,4,1,0,0,0,220,221,5,105,0,0,221,222,5,110,0,0,222,223, 5,114,0,0,212,213,5,107,0,0,213,214,5,115,0,0,214,215,5,112,0,0,
5,116,0,0,223,224,5,101,0,0,224,225,5,114,0,0,225,226,5,102,0,0, 215,216,5,97,0,0,216,217,5,99,0,0,217,218,5,101,0,0,218,2,1,0,0,
226,227,5,97,0,0,227,228,5,99,0,0,228,229,5,101,0,0,229,6,1,0,0, 0,219,220,5,105,0,0,220,221,5,109,0,0,221,222,5,112,0,0,222,223,
0,230,231,5,105,0,0,231,232,5,110,0,0,232,233,5,116,0,0,233,234, 5,111,0,0,223,224,5,114,0,0,224,225,5,116,0,0,225,4,1,0,0,0,226,
5,101,0,0,234,235,5,114,0,0,235,236,5,102,0,0,236,237,5,97,0,0,237, 227,5,101,0,0,227,228,5,120,0,0,228,229,5,116,0,0,229,230,5,101,
238,5,99,0,0,238,239,5,101,0,0,239,240,5,115,0,0,240,8,1,0,0,0,241, 0,0,230,231,5,114,0,0,231,232,5,110,0,0,232,233,5,97,0,0,233,234,
242,5,112,0,0,242,243,5,97,0,0,243,244,5,99,0,0,244,245,5,107,0, 5,108,0,0,234,6,1,0,0,0,235,236,5,97,0,0,236,237,5,116,0,0,237,238,
0,245,246,5,97,0,0,246,247,5,103,0,0,247,248,5,101,0,0,248,10,1, 5,111,0,0,238,239,5,109,0,0,239,8,1,0,0,0,240,241,5,105,0,0,241,
0,0,0,249,250,5,118,0,0,250,251,5,97,0,0,251,252,5,108,0,0,252,253, 242,5,110,0,0,242,243,5,116,0,0,243,244,5,101,0,0,244,245,5,114,
5,117,0,0,253,254,5,101,0,0,254,12,1,0,0,0,255,256,5,114,0,0,256, 0,0,245,246,5,102,0,0,246,247,5,97,0,0,247,248,5,99,0,0,248,249,
257,5,101,0,0,257,258,5,108,0,0,258,259,5,97,0,0,259,260,5,116,0, 5,101,0,0,249,10,1,0,0,0,250,251,5,105,0,0,251,252,5,110,0,0,252,
0,260,261,5,105,0,0,261,262,5,111,0,0,262,263,5,110,0,0,263,14,1, 253,5,116,0,0,253,254,5,101,0,0,254,255,5,114,0,0,255,256,5,102,
0,0,0,264,265,5,111,0,0,265,266,5,112,0,0,266,267,5,101,0,0,267, 0,0,256,257,5,97,0,0,257,258,5,99,0,0,258,259,5,101,0,0,259,260,
268,5,114,0,0,268,269,5,97,0,0,269,270,5,116,0,0,270,271,5,105,0, 5,115,0,0,260,12,1,0,0,0,261,262,5,112,0,0,262,263,5,97,0,0,263,
0,271,272,5,111,0,0,272,273,5,110,0,0,273,16,1,0,0,0,274,275,5,102, 264,5,99,0,0,264,265,5,107,0,0,265,266,5,97,0,0,266,267,5,103,0,
0,0,275,276,5,117,0,0,276,277,5,110,0,0,277,278,5,99,0,0,278,279, 0,267,268,5,101,0,0,268,14,1,0,0,0,269,270,5,118,0,0,270,271,5,97,
5,116,0,0,279,280,5,105,0,0,280,281,5,111,0,0,281,282,5,110,0,0, 0,0,271,272,5,108,0,0,272,273,5,117,0,0,273,274,5,101,0,0,274,16,
282,18,1,0,0,0,283,284,5,99,0,0,284,285,5,111,0,0,285,286,5,110, 1,0,0,0,275,276,5,114,0,0,276,277,5,101,0,0,277,278,5,108,0,0,278,
0,0,286,287,5,115,0,0,287,288,5,116,0,0,288,289,5,114,0,0,289,290, 279,5,97,0,0,279,280,5,116,0,0,280,281,5,105,0,0,281,282,5,111,0,
5,117,0,0,290,291,5,99,0,0,291,292,5,116,0,0,292,293,5,111,0,0,293, 0,282,283,5,110,0,0,283,18,1,0,0,0,284,285,5,111,0,0,285,286,5,112,
294,5,114,0,0,294,20,1,0,0,0,295,296,5,99,0,0,296,297,5,111,0,0, 0,0,286,287,5,101,0,0,287,288,5,114,0,0,288,289,5,97,0,0,289,290,
297,298,5,110,0,0,298,299,5,115,0,0,299,300,5,116,0,0,300,301,5, 5,116,0,0,290,291,5,105,0,0,291,292,5,111,0,0,292,293,5,110,0,0,
114,0,0,301,302,5,117,0,0,302,303,5,99,0,0,303,304,5,116,0,0,304, 293,20,1,0,0,0,294,295,5,102,0,0,295,296,5,117,0,0,296,297,5,110,
305,5,115,0,0,305,22,1,0,0,0,306,307,5,99,0,0,307,308,5,111,0,0, 0,0,297,298,5,99,0,0,298,299,5,116,0,0,299,300,5,105,0,0,300,301,
308,309,5,110,0,0,309,310,5,102,0,0,310,311,5,111,0,0,311,312,5, 5,111,0,0,301,302,5,110,0,0,302,22,1,0,0,0,303,304,5,99,0,0,304,
114,0,0,312,313,5,109,0,0,313,24,1,0,0,0,314,315,5,97,0,0,315,316, 305,5,111,0,0,305,306,5,110,0,0,306,307,5,115,0,0,307,308,5,116,
5,115,0,0,316,26,1,0,0,0,317,318,5,98,0,0,318,319,5,105,0,0,319, 0,0,308,309,5,114,0,0,309,310,5,117,0,0,310,311,5,99,0,0,311,312,
320,5,110,0,0,320,321,5,100,0,0,321,28,1,0,0,0,322,323,5,116,0,0, 5,116,0,0,312,313,5,111,0,0,313,314,5,114,0,0,314,24,1,0,0,0,315,
323,324,5,111,0,0,324,30,1,0,0,0,325,326,5,112,0,0,326,327,5,114, 316,5,99,0,0,316,317,5,111,0,0,317,318,5,110,0,0,318,319,5,115,0,
0,0,327,328,5,105,0,0,328,329,5,118,0,0,329,330,5,97,0,0,330,331, 0,319,320,5,116,0,0,320,321,5,114,0,0,321,322,5,117,0,0,322,323,
5,116,0,0,331,332,5,101,0,0,332,32,1,0,0,0,333,334,5,115,0,0,334, 5,99,0,0,323,324,5,116,0,0,324,325,5,115,0,0,325,26,1,0,0,0,326,
335,5,104,0,0,335,336,5,97,0,0,336,337,5,114,0,0,337,338,5,101,0, 327,5,99,0,0,327,328,5,111,0,0,328,329,5,110,0,0,329,330,5,102,0,
0,338,339,5,100,0,0,339,34,1,0,0,0,340,341,5,115,0,0,341,342,5,116, 0,330,331,5,111,0,0,331,332,5,114,0,0,332,333,5,109,0,0,333,28,1,
0,0,342,343,5,97,0,0,343,344,5,116,0,0,344,345,5,101,0,0,345,36, 0,0,0,334,335,5,97,0,0,335,336,5,115,0,0,336,30,1,0,0,0,337,338,
1,0,0,0,346,347,5,101,0,0,347,348,5,100,0,0,348,349,5,103,0,0,349, 5,98,0,0,338,339,5,105,0,0,339,340,5,110,0,0,340,341,5,100,0,0,341,
350,5,101,0,0,350,38,1,0,0,0,351,352,5,112,0,0,352,353,5,114,0,0, 32,1,0,0,0,342,343,5,116,0,0,343,344,5,111,0,0,344,34,1,0,0,0,345,
353,354,5,111,0,0,354,355,5,106,0,0,355,356,5,101,0,0,356,357,5, 346,5,112,0,0,346,347,5,114,0,0,347,348,5,105,0,0,348,349,5,118,
99,0,0,357,358,5,116,0,0,358,359,5,105,0,0,359,360,5,111,0,0,360, 0,0,349,350,5,97,0,0,350,351,5,116,0,0,351,352,5,101,0,0,352,36,
361,5,110,0,0,361,40,1,0,0,0,362,363,5,119,0,0,363,364,5,105,0,0, 1,0,0,0,353,354,5,115,0,0,354,355,5,104,0,0,355,356,5,97,0,0,356,
364,365,5,116,0,0,365,366,5,104,0,0,366,42,1,0,0,0,367,368,5,117, 357,5,114,0,0,357,358,5,101,0,0,358,359,5,100,0,0,359,38,1,0,0,0,
0,0,368,369,5,115,0,0,369,370,5,105,0,0,370,371,5,110,0,0,371,372, 360,361,5,115,0,0,361,362,5,116,0,0,362,363,5,97,0,0,363,364,5,116,
5,103,0,0,372,44,1,0,0,0,373,374,5,118,0,0,374,375,5,105,0,0,375, 0,0,364,365,5,101,0,0,365,40,1,0,0,0,366,367,5,101,0,0,367,368,5,
376,5,97,0,0,376,46,1,0,0,0,377,378,5,109,0,0,378,379,5,97,0,0,379, 100,0,0,368,369,5,103,0,0,369,370,5,101,0,0,370,42,1,0,0,0,371,372,
380,5,116,0,0,380,381,5,101,0,0,381,382,5,114,0,0,382,383,5,105, 5,112,0,0,372,373,5,114,0,0,373,374,5,111,0,0,374,375,5,106,0,0,
0,0,383,384,5,97,0,0,384,385,5,108,0,0,385,386,5,105,0,0,386,387, 375,376,5,101,0,0,376,377,5,99,0,0,377,378,5,116,0,0,378,379,5,105,
5,122,0,0,387,388,5,101,0,0,388,48,1,0,0,0,389,390,5,105,0,0,390, 0,0,379,380,5,111,0,0,380,381,5,110,0,0,381,44,1,0,0,0,382,383,5,
391,5,102,0,0,391,50,1,0,0,0,392,393,5,97,0,0,393,394,5,98,0,0,394, 119,0,0,383,384,5,105,0,0,384,385,5,116,0,0,385,386,5,104,0,0,386,
395,5,115,0,0,395,396,5,101,0,0,396,397,5,110,0,0,397,398,5,116, 46,1,0,0,0,387,388,5,117,0,0,388,389,5,115,0,0,389,390,5,105,0,0,
0,0,398,52,1,0,0,0,399,400,5,111,0,0,400,401,5,110,0,0,401,54,1, 390,391,5,110,0,0,391,392,5,103,0,0,392,48,1,0,0,0,393,394,5,118,
0,0,0,402,403,5,112,0,0,403,404,5,111,0,0,404,405,5,108,0,0,405, 0,0,394,395,5,105,0,0,395,396,5,97,0,0,396,50,1,0,0,0,397,398,5,
406,5,105,0,0,406,407,5,99,0,0,407,408,5,121,0,0,408,56,1,0,0,0, 109,0,0,398,399,5,97,0,0,399,400,5,116,0,0,400,401,5,101,0,0,401,
409,410,5,100,0,0,410,411,5,101,0,0,411,412,5,102,0,0,412,413,5, 402,5,114,0,0,402,403,5,105,0,0,403,404,5,97,0,0,404,405,5,108,0,
97,0,0,413,414,5,117,0,0,414,415,5,108,0,0,415,416,5,116,0,0,416, 0,405,406,5,105,0,0,406,407,5,122,0,0,407,408,5,101,0,0,408,52,1,
58,1,0,0,0,417,418,5,115,0,0,418,419,5,111,0,0,419,420,5,117,0,0, 0,0,0,409,410,5,105,0,0,410,411,5,102,0,0,411,54,1,0,0,0,412,413,
420,421,5,114,0,0,421,422,5,99,0,0,422,423,5,101,0,0,423,60,1,0, 5,97,0,0,413,414,5,98,0,0,414,415,5,115,0,0,415,416,5,101,0,0,416,
0,0,424,425,5,114,0,0,425,426,5,101,0,0,426,427,5,112,0,0,427,428, 417,5,110,0,0,417,418,5,116,0,0,418,56,1,0,0,0,419,420,5,111,0,0,
5,111,0,0,428,429,5,115,0,0,429,430,5,105,0,0,430,431,5,116,0,0, 420,421,5,110,0,0,421,58,1,0,0,0,422,423,5,112,0,0,423,424,5,111,
431,432,5,111,0,0,432,433,5,114,0,0,433,434,5,121,0,0,434,62,1,0, 0,0,424,425,5,108,0,0,425,426,5,105,0,0,426,427,5,99,0,0,427,428,
0,0,435,436,5,99,0,0,436,437,5,111,0,0,437,438,5,109,0,0,438,439, 5,121,0,0,428,60,1,0,0,0,429,430,5,100,0,0,430,431,5,101,0,0,431,
5,109,0,0,439,440,5,105,0,0,440,441,5,116,0,0,441,64,1,0,0,0,442, 432,5,102,0,0,432,433,5,97,0,0,433,434,5,117,0,0,434,435,5,108,0,
443,5,114,0,0,443,444,5,101,0,0,444,445,5,118,0,0,445,446,5,105, 0,435,436,5,116,0,0,436,62,1,0,0,0,437,438,5,115,0,0,438,439,5,111,
0,0,446,447,5,115,0,0,447,448,5,105,0,0,448,449,5,111,0,0,449,450, 0,0,439,440,5,117,0,0,440,441,5,114,0,0,441,442,5,99,0,0,442,443,
5,110,0,0,450,66,1,0,0,0,451,452,5,105,0,0,452,453,5,100,0,0,453, 5,101,0,0,443,64,1,0,0,0,444,445,5,114,0,0,445,446,5,101,0,0,446,
68,1,0,0,0,454,455,5,100,0,0,455,456,5,111,0,0,456,457,5,99,0,0, 447,5,112,0,0,447,448,5,111,0,0,448,449,5,115,0,0,449,450,5,105,
457,70,1,0,0,0,458,459,5,109,0,0,459,460,5,111,0,0,460,461,5,100, 0,0,450,451,5,116,0,0,451,452,5,111,0,0,452,453,5,114,0,0,453,454,
0,0,461,462,5,101,0,0,462,72,1,0,0,0,463,464,5,101,0,0,464,465,5, 5,121,0,0,454,66,1,0,0,0,455,456,5,99,0,0,456,457,5,111,0,0,457,
109,0,0,465,466,5,105,0,0,466,467,5,116,0,0,467,468,5,115,0,0,468, 458,5,109,0,0,458,459,5,109,0,0,459,460,5,105,0,0,460,461,5,116,
74,1,0,0,0,469,470,5,114,0,0,470,471,5,101,0,0,471,472,5,99,0,0, 0,0,461,68,1,0,0,0,462,463,5,114,0,0,463,464,5,101,0,0,464,465,5,
472,473,5,101,0,0,473,474,5,105,0,0,474,475,5,118,0,0,475,476,5, 118,0,0,465,466,5,105,0,0,466,467,5,115,0,0,467,468,5,105,0,0,468,
101,0,0,476,477,5,114,0,0,477,76,1,0,0,0,478,479,5,114,0,0,479,480, 469,5,111,0,0,469,470,5,110,0,0,470,70,1,0,0,0,471,472,5,105,0,0,
5,101,0,0,480,481,5,113,0,0,481,482,5,117,0,0,482,483,5,105,0,0, 472,473,5,100,0,0,473,72,1,0,0,0,474,475,5,100,0,0,475,476,5,111,
483,484,5,114,0,0,484,485,5,101,0,0,485,486,5,115,0,0,486,78,1,0, 0,0,476,477,5,99,0,0,477,74,1,0,0,0,478,479,5,109,0,0,479,480,5,
0,0,487,488,5,97,0,0,488,489,5,110,0,0,489,490,5,121,0,0,490,80, 111,0,0,480,481,5,100,0,0,481,482,5,101,0,0,482,76,1,0,0,0,483,484,
1,0,0,0,491,492,5,103,0,0,492,493,5,101,0,0,493,494,5,116,0,0,494, 5,101,0,0,484,485,5,109,0,0,485,486,5,105,0,0,486,487,5,116,0,0,
82,1,0,0,0,495,496,5,115,0,0,496,497,5,101,0,0,497,498,5,116,0,0, 487,488,5,115,0,0,488,78,1,0,0,0,489,490,5,114,0,0,490,491,5,101,
498,84,1,0,0,0,499,500,5,119,0,0,500,501,5,97,0,0,501,502,5,116, 0,0,491,492,5,99,0,0,492,493,5,101,0,0,493,494,5,105,0,0,494,495,
0,0,502,503,5,99,0,0,503,504,5,104,0,0,504,86,1,0,0,0,505,506,5, 5,118,0,0,495,496,5,101,0,0,496,497,5,114,0,0,497,80,1,0,0,0,498,
115,0,0,506,507,5,116,0,0,507,508,5,97,0,0,508,509,5,114,0,0,509, 499,5,114,0,0,499,500,5,101,0,0,500,501,5,113,0,0,501,502,5,117,
510,5,116,0,0,510,88,1,0,0,0,511,512,5,115,0,0,512,513,5,116,0,0, 0,0,502,503,5,105,0,0,503,504,5,114,0,0,504,505,5,101,0,0,505,506,
513,514,5,111,0,0,514,515,5,112,0,0,515,90,1,0,0,0,516,517,5,114, 5,115,0,0,506,82,1,0,0,0,507,508,5,97,0,0,508,509,5,110,0,0,509,
0,0,517,518,5,101,0,0,518,519,5,97,0,0,519,520,5,100,0,0,520,92, 510,5,121,0,0,510,84,1,0,0,0,511,512,5,103,0,0,512,513,5,101,0,0,
1,0,0,0,521,522,5,119,0,0,522,523,5,114,0,0,523,524,5,105,0,0,524, 513,514,5,116,0,0,514,86,1,0,0,0,515,516,5,115,0,0,516,517,5,101,
525,5,116,0,0,525,526,5,101,0,0,526,94,1,0,0,0,527,528,5,114,0,0, 0,0,517,518,5,116,0,0,518,88,1,0,0,0,519,520,5,119,0,0,520,521,5,
528,529,5,101,0,0,529,530,5,115,0,0,530,531,5,111,0,0,531,532,5, 97,0,0,521,522,5,116,0,0,522,523,5,99,0,0,523,524,5,104,0,0,524,
108,0,0,532,533,5,118,0,0,533,534,5,101,0,0,534,96,1,0,0,0,535,536, 90,1,0,0,0,525,526,5,115,0,0,526,527,5,116,0,0,527,528,5,97,0,0,
5,99,0,0,536,537,5,111,0,0,537,538,5,110,0,0,538,539,5,110,0,0,539, 528,529,5,114,0,0,529,530,5,116,0,0,530,92,1,0,0,0,531,532,5,115,
540,5,101,0,0,540,541,5,99,0,0,541,542,5,116,0,0,542,98,1,0,0,0, 0,0,532,533,5,116,0,0,533,534,5,111,0,0,534,535,5,112,0,0,535,94,
543,544,5,100,0,0,544,545,5,105,0,0,545,546,5,115,0,0,546,547,5, 1,0,0,0,536,537,5,114,0,0,537,538,5,101,0,0,538,539,5,97,0,0,539,
99,0,0,547,548,5,111,0,0,548,549,5,110,0,0,549,550,5,110,0,0,550, 540,5,100,0,0,540,96,1,0,0,0,541,542,5,119,0,0,542,543,5,114,0,0,
551,5,101,0,0,551,552,5,99,0,0,552,553,5,116,0,0,553,100,1,0,0,0, 543,544,5,105,0,0,544,545,5,116,0,0,545,546,5,101,0,0,546,98,1,0,
554,555,5,99,0,0,555,556,5,97,0,0,556,557,5,108,0,0,557,558,5,108, 0,0,547,548,5,114,0,0,548,549,5,101,0,0,549,550,5,115,0,0,550,551,
0,0,558,102,1,0,0,0,559,560,5,119,0,0,560,561,5,97,0,0,561,562,5, 5,111,0,0,551,552,5,108,0,0,552,553,5,118,0,0,553,554,5,101,0,0,
116,0,0,562,563,5,99,0,0,563,564,5,104,0,0,564,565,5,45,0,0,565, 554,100,1,0,0,0,555,556,5,99,0,0,556,557,5,111,0,0,557,558,5,110,
566,5,115,0,0,566,567,5,116,0,0,567,568,5,97,0,0,568,569,5,114,0, 0,0,558,559,5,110,0,0,559,560,5,101,0,0,560,561,5,99,0,0,561,562,
0,569,570,5,116,0,0,570,104,1,0,0,0,571,572,5,119,0,0,572,573,5, 5,116,0,0,562,102,1,0,0,0,563,564,5,100,0,0,564,565,5,105,0,0,565,
97,0,0,573,574,5,116,0,0,574,575,5,99,0,0,575,576,5,104,0,0,576, 566,5,115,0,0,566,567,5,99,0,0,567,568,5,111,0,0,568,569,5,110,0,
577,5,45,0,0,577,578,5,115,0,0,578,579,5,116,0,0,579,580,5,111,0, 0,569,570,5,110,0,0,570,571,5,101,0,0,571,572,5,99,0,0,572,573,5,
0,580,581,5,112,0,0,581,106,1,0,0,0,582,583,5,115,0,0,583,584,5, 116,0,0,573,104,1,0,0,0,574,575,5,99,0,0,575,576,5,97,0,0,576,577,
117,0,0,584,585,5,98,0,0,585,586,5,115,0,0,586,587,5,99,0,0,587, 5,108,0,0,577,578,5,108,0,0,578,106,1,0,0,0,579,580,5,119,0,0,580,
588,5,114,0,0,588,589,5,105,0,0,589,590,5,98,0,0,590,591,5,101,0, 581,5,97,0,0,581,582,5,116,0,0,582,583,5,99,0,0,583,584,5,104,0,
0,591,108,1,0,0,0,592,593,5,117,0,0,593,594,5,110,0,0,594,595,5, 0,584,585,5,45,0,0,585,586,5,115,0,0,586,587,5,116,0,0,587,588,5,
115,0,0,595,596,5,117,0,0,596,597,5,98,0,0,597,598,5,115,0,0,598, 97,0,0,588,589,5,114,0,0,589,590,5,116,0,0,590,108,1,0,0,0,591,592,
599,5,99,0,0,599,600,5,114,0,0,600,601,5,105,0,0,601,602,5,98,0, 5,119,0,0,592,593,5,97,0,0,593,594,5,116,0,0,594,595,5,99,0,0,595,
0,602,603,5,101,0,0,603,110,1,0,0,0,604,605,5,111,0,0,605,606,5, 596,5,104,0,0,596,597,5,45,0,0,597,598,5,115,0,0,598,599,5,116,0,
112,0,0,606,607,5,116,0,0,607,608,5,105,0,0,608,609,5,109,0,0,609, 0,599,600,5,111,0,0,600,601,5,112,0,0,601,110,1,0,0,0,602,603,5,
610,5,105,0,0,610,611,5,115,0,0,611,612,5,116,0,0,612,613,5,105, 115,0,0,603,604,5,117,0,0,604,605,5,98,0,0,605,606,5,115,0,0,606,
0,0,613,614,5,99,0,0,614,615,5,45,0,0,615,616,5,114,0,0,616,617, 607,5,99,0,0,607,608,5,114,0,0,608,609,5,105,0,0,609,610,5,98,0,
5,101,0,0,617,618,5,103,0,0,618,619,5,105,0,0,619,620,5,115,0,0, 0,610,611,5,101,0,0,611,112,1,0,0,0,612,613,5,117,0,0,613,614,5,
620,621,5,116,0,0,621,622,5,101,0,0,622,623,5,114,0,0,623,112,1, 110,0,0,614,615,5,115,0,0,615,616,5,117,0,0,616,617,5,98,0,0,617,
0,0,0,624,625,5,99,0,0,625,626,5,114,0,0,626,627,5,100,0,0,627,628, 618,5,115,0,0,618,619,5,99,0,0,619,620,5,114,0,0,620,621,5,105,0,
5,116,0,0,628,114,1,0,0,0,629,630,5,111,0,0,630,631,5,112,0,0,631, 0,621,622,5,98,0,0,622,623,5,101,0,0,623,114,1,0,0,0,624,625,5,111,
632,5,116,0,0,632,633,5,105,0,0,633,634,5,111,0,0,634,635,5,110, 0,0,625,626,5,112,0,0,626,627,5,116,0,0,627,628,5,105,0,0,628,629,
0,0,635,636,5,97,0,0,636,637,5,108,0,0,637,638,5,45,0,0,638,639, 5,109,0,0,629,630,5,105,0,0,630,631,5,115,0,0,631,632,5,116,0,0,
5,111,0,0,639,640,5,110,0,0,640,641,5,101,0,0,641,116,1,0,0,0,642, 632,633,5,105,0,0,633,634,5,99,0,0,634,635,5,45,0,0,635,636,5,114,
643,5,101,0,0,643,644,5,120,0,0,644,645,5,97,0,0,645,646,5,99,0, 0,0,636,637,5,101,0,0,637,638,5,103,0,0,638,639,5,105,0,0,639,640,
0,646,647,5,116,0,0,647,648,5,108,0,0,648,649,5,121,0,0,649,650, 5,115,0,0,640,641,5,116,0,0,641,642,5,101,0,0,642,643,5,114,0,0,
5,45,0,0,650,651,5,111,0,0,651,652,5,110,0,0,652,653,5,101,0,0,653, 643,116,1,0,0,0,644,645,5,99,0,0,645,646,5,114,0,0,646,647,5,100,
118,1,0,0,0,654,655,5,109,0,0,655,656,5,97,0,0,656,657,5,110,0,0, 0,0,647,648,5,116,0,0,648,118,1,0,0,0,649,650,5,111,0,0,650,651,
657,658,5,121,0,0,658,659,5,45,0,0,659,660,5,117,0,0,660,661,5,110, 5,112,0,0,651,652,5,116,0,0,652,653,5,105,0,0,653,654,5,111,0,0,
0,0,661,662,5,105,0,0,662,663,5,113,0,0,663,664,5,117,0,0,664,665, 654,655,5,110,0,0,655,656,5,97,0,0,656,657,5,108,0,0,657,658,5,45,
5,101,0,0,665,120,1,0,0,0,666,667,5,109,0,0,667,668,5,97,0,0,668, 0,0,658,659,5,111,0,0,659,660,5,110,0,0,660,661,5,101,0,0,661,120,
669,5,110,0,0,669,670,5,121,0,0,670,122,1,0,0,0,671,672,5,111,0, 1,0,0,0,662,663,5,101,0,0,663,664,5,120,0,0,664,665,5,97,0,0,665,
0,672,673,5,114,0,0,673,674,5,100,0,0,674,675,5,101,0,0,675,676, 666,5,99,0,0,666,667,5,116,0,0,667,668,5,108,0,0,668,669,5,121,0,
5,114,0,0,676,677,5,101,0,0,677,678,5,100,0,0,678,124,1,0,0,0,679, 0,669,670,5,45,0,0,670,671,5,111,0,0,671,672,5,110,0,0,672,673,5,
680,5,117,0,0,680,681,5,110,0,0,681,682,5,105,0,0,682,683,5,116, 101,0,0,673,122,1,0,0,0,674,675,5,109,0,0,675,676,5,97,0,0,676,677,
0,0,683,126,1,0,0,0,684,685,5,119,0,0,685,686,5,97,0,0,686,687,5, 5,110,0,0,677,678,5,121,0,0,678,679,5,45,0,0,679,680,5,117,0,0,680,
116,0,0,687,688,5,99,0,0,688,689,5,104,0,0,689,690,5,45,0,0,690, 681,5,110,0,0,681,682,5,105,0,0,682,683,5,113,0,0,683,684,5,117,
691,5,104,0,0,691,692,5,97,0,0,692,693,5,110,0,0,693,694,5,100,0, 0,0,684,685,5,101,0,0,685,124,1,0,0,0,686,687,5,109,0,0,687,688,
0,694,695,5,108,0,0,695,696,5,101,0,0,696,128,1,0,0,0,697,698,5, 5,97,0,0,688,689,5,110,0,0,689,690,5,121,0,0,690,126,1,0,0,0,691,
109,0,0,698,699,5,101,0,0,699,700,5,115,0,0,700,701,5,115,0,0,701, 692,5,111,0,0,692,693,5,114,0,0,693,694,5,100,0,0,694,695,5,101,
702,5,97,0,0,702,703,5,103,0,0,703,704,5,101,0,0,704,130,1,0,0,0, 0,0,695,696,5,114,0,0,696,697,5,101,0,0,697,698,5,100,0,0,698,128,
705,706,5,97,0,0,706,707,5,116,0,0,707,708,5,111,0,0,708,709,5,109, 1,0,0,0,699,700,5,117,0,0,700,701,5,110,0,0,701,702,5,105,0,0,702,
0,0,709,710,5,45,0,0,710,711,5,114,0,0,711,712,5,101,0,0,712,713, 703,5,116,0,0,703,130,1,0,0,0,704,705,5,119,0,0,705,706,5,97,0,0,
5,102,0,0,713,132,1,0,0,0,714,715,5,105,0,0,715,716,5,110,0,0,716, 706,707,5,116,0,0,707,708,5,99,0,0,708,709,5,104,0,0,709,710,5,45,
717,5,116,0,0,717,718,5,101,0,0,718,719,5,114,0,0,719,720,5,102, 0,0,710,711,5,104,0,0,711,712,5,97,0,0,712,713,5,110,0,0,713,714,
0,0,720,721,5,97,0,0,721,722,5,99,0,0,722,723,5,101,0,0,723,724, 5,100,0,0,714,715,5,108,0,0,715,716,5,101,0,0,716,132,1,0,0,0,717,
5,45,0,0,724,725,5,114,0,0,725,726,5,101,0,0,726,727,5,102,0,0,727, 718,5,109,0,0,718,719,5,101,0,0,719,720,5,115,0,0,720,721,5,115,
134,1,0,0,0,728,729,5,111,0,0,729,730,5,112,0,0,730,731,5,116,0, 0,0,721,722,5,97,0,0,722,723,5,103,0,0,723,724,5,101,0,0,724,134,
0,731,732,5,105,0,0,732,733,5,111,0,0,733,734,5,110,0,0,734,735, 1,0,0,0,725,726,5,97,0,0,726,727,5,116,0,0,727,728,5,111,0,0,728,
5,97,0,0,735,736,5,108,0,0,736,136,1,0,0,0,737,738,5,108,0,0,738, 729,5,109,0,0,729,730,5,45,0,0,730,731,5,114,0,0,731,732,5,101,0,
739,5,105,0,0,739,740,5,115,0,0,740,741,5,116,0,0,741,138,1,0,0, 0,732,733,5,102,0,0,733,136,1,0,0,0,734,735,5,105,0,0,735,736,5,
0,742,743,5,98,0,0,743,744,5,111,0,0,744,745,5,111,0,0,745,746,5, 110,0,0,736,737,5,116,0,0,737,738,5,101,0,0,738,739,5,114,0,0,739,
108,0,0,746,140,1,0,0,0,747,748,5,98,0,0,748,749,5,121,0,0,749,750, 740,5,102,0,0,740,741,5,97,0,0,741,742,5,99,0,0,742,743,5,101,0,
5,116,0,0,750,751,5,101,0,0,751,752,5,115,0,0,752,142,1,0,0,0,753, 0,743,744,5,45,0,0,744,745,5,114,0,0,745,746,5,101,0,0,746,747,5,
754,5,100,0,0,754,755,5,111,0,0,755,756,5,117,0,0,756,757,5,98,0, 102,0,0,747,138,1,0,0,0,748,749,5,111,0,0,749,750,5,112,0,0,750,
0,757,758,5,108,0,0,758,759,5,101,0,0,759,144,1,0,0,0,760,761,5, 751,5,116,0,0,751,752,5,105,0,0,752,753,5,111,0,0,753,754,5,110,
105,0,0,761,762,5,110,0,0,762,763,5,116,0,0,763,764,5,51,0,0,764, 0,0,754,755,5,97,0,0,755,756,5,108,0,0,756,140,1,0,0,0,757,758,5,
765,5,50,0,0,765,146,1,0,0,0,766,767,5,105,0,0,767,768,5,110,0,0, 108,0,0,758,759,5,105,0,0,759,760,5,115,0,0,760,761,5,116,0,0,761,
768,769,5,116,0,0,769,770,5,54,0,0,770,771,5,52,0,0,771,148,1,0, 142,1,0,0,0,762,763,5,98,0,0,763,764,5,111,0,0,764,765,5,111,0,0,
0,0,772,773,5,115,0,0,773,774,5,116,0,0,774,775,5,114,0,0,775,776, 765,766,5,108,0,0,766,144,1,0,0,0,767,768,5,98,0,0,768,769,5,121,
5,105,0,0,776,777,5,110,0,0,777,778,5,103,0,0,778,150,1,0,0,0,779, 0,0,769,770,5,116,0,0,770,771,5,101,0,0,771,772,5,115,0,0,772,146,
780,5,117,0,0,780,781,5,105,0,0,781,782,5,110,0,0,782,783,5,116, 1,0,0,0,773,774,5,100,0,0,774,775,5,111,0,0,775,776,5,117,0,0,776,
0,0,783,784,5,51,0,0,784,785,5,50,0,0,785,152,1,0,0,0,786,787,5, 777,5,98,0,0,777,778,5,108,0,0,778,779,5,101,0,0,779,148,1,0,0,0,
117,0,0,787,788,5,105,0,0,788,789,5,110,0,0,789,790,5,116,0,0,790, 780,781,5,105,0,0,781,782,5,110,0,0,782,783,5,116,0,0,783,784,5,
791,5,54,0,0,791,792,5,52,0,0,792,154,1,0,0,0,793,794,5,116,0,0, 51,0,0,784,785,5,50,0,0,785,150,1,0,0,0,786,787,5,105,0,0,787,788,
794,795,5,114,0,0,795,796,5,117,0,0,796,797,5,101,0,0,797,156,1, 5,110,0,0,788,789,5,116,0,0,789,790,5,54,0,0,790,791,5,52,0,0,791,
0,0,0,798,799,5,102,0,0,799,800,5,97,0,0,800,801,5,108,0,0,801,802, 152,1,0,0,0,792,793,5,115,0,0,793,794,5,116,0,0,794,795,5,114,0,
5,115,0,0,802,803,5,101,0,0,803,158,1,0,0,0,804,805,5,110,0,0,805, 0,795,796,5,105,0,0,796,797,5,110,0,0,797,798,5,103,0,0,798,154,
806,5,117,0,0,806,807,5,108,0,0,807,808,5,108,0,0,808,160,1,0,0, 1,0,0,0,799,800,5,117,0,0,800,801,5,105,0,0,801,802,5,110,0,0,802,
0,809,810,5,45,0,0,810,811,5,62,0,0,811,162,1,0,0,0,812,813,5,58, 803,5,116,0,0,803,804,5,51,0,0,804,805,5,50,0,0,805,156,1,0,0,0,
0,0,813,164,1,0,0,0,814,815,5,59,0,0,815,166,1,0,0,0,816,817,5,44, 806,807,5,117,0,0,807,808,5,105,0,0,808,809,5,110,0,0,809,810,5,
0,0,817,168,1,0,0,0,818,819,5,46,0,0,819,170,1,0,0,0,820,821,5,123, 116,0,0,810,811,5,54,0,0,811,812,5,52,0,0,812,158,1,0,0,0,813,814,
0,0,821,172,1,0,0,0,822,823,5,125,0,0,823,174,1,0,0,0,824,825,5, 5,116,0,0,814,815,5,114,0,0,815,816,5,117,0,0,816,817,5,101,0,0,
91,0,0,825,176,1,0,0,0,826,827,5,93,0,0,827,178,1,0,0,0,828,829, 817,160,1,0,0,0,818,819,5,102,0,0,819,820,5,97,0,0,820,821,5,108,
5,40,0,0,829,180,1,0,0,0,830,831,5,41,0,0,831,182,1,0,0,0,832,833, 0,0,821,822,5,115,0,0,822,823,5,101,0,0,823,162,1,0,0,0,824,825,
5,60,0,0,833,184,1,0,0,0,834,835,5,62,0,0,835,186,1,0,0,0,836,838, 5,110,0,0,825,826,5,117,0,0,826,827,5,108,0,0,827,828,5,108,0,0,
5,45,0,0,837,836,1,0,0,0,837,838,1,0,0,0,838,840,1,0,0,0,839,841, 828,164,1,0,0,0,829,830,5,45,0,0,830,831,5,62,0,0,831,166,1,0,0,
7,0,0,0,840,839,1,0,0,0,841,842,1,0,0,0,842,840,1,0,0,0,842,843, 0,832,833,5,58,0,0,833,168,1,0,0,0,834,835,5,59,0,0,835,170,1,0,
1,0,0,0,843,188,1,0,0,0,844,846,5,45,0,0,845,844,1,0,0,0,845,846, 0,0,836,837,5,44,0,0,837,172,1,0,0,0,838,839,5,46,0,0,839,174,1,
1,0,0,0,846,855,1,0,0,0,847,856,5,48,0,0,848,852,7,1,0,0,849,851, 0,0,0,840,841,5,123,0,0,841,176,1,0,0,0,842,843,5,125,0,0,843,178,
7,0,0,0,850,849,1,0,0,0,851,854,1,0,0,0,852,850,1,0,0,0,852,853, 1,0,0,0,844,845,5,91,0,0,845,180,1,0,0,0,846,847,5,93,0,0,847,182,
1,0,0,0,853,856,1,0,0,0,854,852,1,0,0,0,855,847,1,0,0,0,855,848, 1,0,0,0,848,849,5,40,0,0,849,184,1,0,0,0,850,851,5,41,0,0,851,186,
1,0,0,0,856,863,1,0,0,0,857,859,5,46,0,0,858,860,7,0,0,0,859,858, 1,0,0,0,852,853,5,60,0,0,853,188,1,0,0,0,854,855,5,62,0,0,855,190,
1,0,0,0,860,861,1,0,0,0,861,859,1,0,0,0,861,862,1,0,0,0,862,864, 1,0,0,0,856,858,5,45,0,0,857,856,1,0,0,0,857,858,1,0,0,0,858,860,
1,0,0,0,863,857,1,0,0,0,863,864,1,0,0,0,864,874,1,0,0,0,865,867, 1,0,0,0,859,861,7,0,0,0,860,859,1,0,0,0,861,862,1,0,0,0,862,860,
7,2,0,0,866,868,7,3,0,0,867,866,1,0,0,0,867,868,1,0,0,0,868,870, 1,0,0,0,862,863,1,0,0,0,863,192,1,0,0,0,864,866,5,45,0,0,865,864,
1,0,0,0,869,871,7,0,0,0,870,869,1,0,0,0,871,872,1,0,0,0,872,870, 1,0,0,0,865,866,1,0,0,0,866,875,1,0,0,0,867,876,5,48,0,0,868,872,
1,0,0,0,872,873,1,0,0,0,873,875,1,0,0,0,874,865,1,0,0,0,874,875, 7,1,0,0,869,871,7,0,0,0,870,869,1,0,0,0,871,874,1,0,0,0,872,870,
1,0,0,0,875,190,1,0,0,0,876,880,7,4,0,0,877,879,7,5,0,0,878,877, 1,0,0,0,872,873,1,0,0,0,873,876,1,0,0,0,874,872,1,0,0,0,875,867,
1,0,0,0,879,882,1,0,0,0,880,878,1,0,0,0,880,881,1,0,0,0,881,192, 1,0,0,0,875,868,1,0,0,0,876,883,1,0,0,0,877,879,5,46,0,0,878,880,
1,0,0,0,882,880,1,0,0,0,883,888,5,34,0,0,884,887,3,195,97,0,885, 7,0,0,0,879,878,1,0,0,0,880,881,1,0,0,0,881,879,1,0,0,0,881,882,
887,8,6,0,0,886,884,1,0,0,0,886,885,1,0,0,0,887,890,1,0,0,0,888, 1,0,0,0,882,884,1,0,0,0,883,877,1,0,0,0,883,884,1,0,0,0,884,894,
886,1,0,0,0,888,889,1,0,0,0,889,891,1,0,0,0,890,888,1,0,0,0,891, 1,0,0,0,885,887,7,2,0,0,886,888,7,3,0,0,887,886,1,0,0,0,887,888,
892,5,34,0,0,892,194,1,0,0,0,893,901,5,92,0,0,894,902,7,7,0,0,895, 1,0,0,0,888,890,1,0,0,0,889,891,7,0,0,0,890,889,1,0,0,0,891,892,
896,5,117,0,0,896,897,3,197,98,0,897,898,3,197,98,0,898,899,3,197, 1,0,0,0,892,890,1,0,0,0,892,893,1,0,0,0,893,895,1,0,0,0,894,885,
98,0,899,900,3,197,98,0,900,902,1,0,0,0,901,894,1,0,0,0,901,895, 1,0,0,0,894,895,1,0,0,0,895,194,1,0,0,0,896,900,7,4,0,0,897,899,
1,0,0,0,902,196,1,0,0,0,903,904,7,8,0,0,904,198,1,0,0,0,905,906, 7,5,0,0,898,897,1,0,0,0,899,902,1,0,0,0,900,898,1,0,0,0,900,901,
5,47,0,0,906,907,5,47,0,0,907,911,1,0,0,0,908,910,8,9,0,0,909,908, 1,0,0,0,901,196,1,0,0,0,902,900,1,0,0,0,903,908,5,34,0,0,904,907,
1,0,0,0,910,913,1,0,0,0,911,909,1,0,0,0,911,912,1,0,0,0,912,914, 3,199,99,0,905,907,8,6,0,0,906,904,1,0,0,0,906,905,1,0,0,0,907,910,
1,0,0,0,913,911,1,0,0,0,914,915,6,99,0,0,915,200,1,0,0,0,916,917, 1,0,0,0,908,906,1,0,0,0,908,909,1,0,0,0,909,911,1,0,0,0,910,908,
5,47,0,0,917,918,5,42,0,0,918,922,1,0,0,0,919,921,9,0,0,0,920,919, 1,0,0,0,911,912,5,34,0,0,912,198,1,0,0,0,913,921,5,92,0,0,914,922,
1,0,0,0,921,924,1,0,0,0,922,923,1,0,0,0,922,920,1,0,0,0,923,925, 7,7,0,0,915,916,5,117,0,0,916,917,3,201,100,0,917,918,3,201,100,
1,0,0,0,924,922,1,0,0,0,925,926,5,42,0,0,926,927,5,47,0,0,927,928, 0,918,919,3,201,100,0,919,920,3,201,100,0,920,922,1,0,0,0,921,914,
1,0,0,0,928,929,6,100,0,0,929,202,1,0,0,0,930,932,7,10,0,0,931,930, 1,0,0,0,921,915,1,0,0,0,922,200,1,0,0,0,923,924,7,8,0,0,924,202,
1,0,0,0,932,933,1,0,0,0,933,931,1,0,0,0,933,934,1,0,0,0,934,935, 1,0,0,0,925,926,5,47,0,0,926,927,5,47,0,0,927,931,1,0,0,0,928,930,
1,0,0,0,935,936,6,101,0,0,936,204,1,0,0,0,18,0,837,842,845,852,855, 8,9,0,0,929,928,1,0,0,0,930,933,1,0,0,0,931,929,1,0,0,0,931,932,
861,863,867,872,874,880,886,888,901,911,922,933,1,6,0,0 1,0,0,0,932,934,1,0,0,0,933,931,1,0,0,0,934,935,6,101,0,0,935,204,
1,0,0,0,936,937,5,47,0,0,937,938,5,42,0,0,938,942,1,0,0,0,939,941,
9,0,0,0,940,939,1,0,0,0,941,944,1,0,0,0,942,943,1,0,0,0,942,940,
1,0,0,0,943,945,1,0,0,0,944,942,1,0,0,0,945,946,5,42,0,0,946,947,
5,47,0,0,947,948,1,0,0,0,948,949,6,102,0,0,949,206,1,0,0,0,950,952,
7,10,0,0,951,950,1,0,0,0,952,953,1,0,0,0,953,951,1,0,0,0,953,954,
1,0,0,0,954,955,1,0,0,0,955,956,6,103,0,0,956,208,1,0,0,0,18,0,857,
862,865,872,875,881,883,887,892,894,900,906,908,921,931,942,953,
1,6,0,0
]; ];
private static __ATN: antlr.ATN; private static __ATN: antlr.ATN;
File diff suppressed because it is too large Load Diff
@@ -5,9 +5,12 @@ import { AbstractParseTreeVisitor } from "antlr4ng";
import { DocumentContext } from "./QuixosCapabilityParser.js"; import { DocumentContext } from "./QuixosCapabilityParser.js";
import { WorkspaceDeclContext } from "./QuixosCapabilityParser.js"; import { WorkspaceDeclContext } from "./QuixosCapabilityParser.js";
import { WorkspaceItemContext } from "./QuixosCapabilityParser.js"; import { WorkspaceItemContext } from "./QuixosCapabilityParser.js";
import { ResourceImportDeclContext } from "./QuixosCapabilityParser.js";
import { ExternalAtomDeclContext } from "./QuixosCapabilityParser.js";
import { ExternalInterfaceDeclContext } from "./QuixosCapabilityParser.js";
import { ResourcePreambleContext } from "./QuixosCapabilityParser.js";
import { AtomDeclContext } from "./QuixosCapabilityParser.js"; import { AtomDeclContext } from "./QuixosCapabilityParser.js";
import { InterfaceDeclContext } from "./QuixosCapabilityParser.js"; import { InterfaceResourceDeclContext } from "./QuixosCapabilityParser.js";
import { SourceBlockContext } from "./QuixosCapabilityParser.js";
import { InterfaceMemberContext } from "./QuixosCapabilityParser.js"; import { InterfaceMemberContext } from "./QuixosCapabilityParser.js";
import { OperationMemberContext } from "./QuixosCapabilityParser.js"; import { OperationMemberContext } from "./QuixosCapabilityParser.js";
import { ValueMemberContext } from "./QuixosCapabilityParser.js"; import { ValueMemberContext } from "./QuixosCapabilityParser.js";
@@ -15,7 +18,7 @@ import { ValueMemberOperationContext } from "./QuixosCapabilityParser.js";
import { RelationshipMemberContext } from "./QuixosCapabilityParser.js"; import { RelationshipMemberContext } from "./QuixosCapabilityParser.js";
import { RelationshipOperationContext } from "./QuixosCapabilityParser.js"; import { RelationshipOperationContext } from "./QuixosCapabilityParser.js";
import { TargetConstraintContext } from "./QuixosCapabilityParser.js"; import { TargetConstraintContext } from "./QuixosCapabilityParser.js";
import { PackageDeclContext } from "./QuixosCapabilityParser.js"; import { PackageResourceDeclContext } from "./QuixosCapabilityParser.js";
import { PackageExportContext } from "./QuixosCapabilityParser.js"; import { PackageExportContext } from "./QuixosCapabilityParser.js";
import { PackageOperationExportContext } from "./QuixosCapabilityParser.js"; import { PackageOperationExportContext } from "./QuixosCapabilityParser.js";
import { PackageFunctionExportContext } from "./QuixosCapabilityParser.js"; import { PackageFunctionExportContext } from "./QuixosCapabilityParser.js";
@@ -83,6 +86,30 @@ export class QuixosCapabilityVisitor<Result> extends AbstractParseTreeVisitor<Re
* @return the visitor result * @return the visitor result
*/ */
visitWorkspaceItem?: (ctx: WorkspaceItemContext) => Result; visitWorkspaceItem?: (ctx: WorkspaceItemContext) => Result;
/**
* Visit a parse tree produced by `QuixosCapabilityParser.resourceImportDecl`.
* @param ctx the parse tree
* @return the visitor result
*/
visitResourceImportDecl?: (ctx: ResourceImportDeclContext) => Result;
/**
* Visit a parse tree produced by `QuixosCapabilityParser.externalAtomDecl`.
* @param ctx the parse tree
* @return the visitor result
*/
visitExternalAtomDecl?: (ctx: ExternalAtomDeclContext) => Result;
/**
* Visit a parse tree produced by `QuixosCapabilityParser.externalInterfaceDecl`.
* @param ctx the parse tree
* @return the visitor result
*/
visitExternalInterfaceDecl?: (ctx: ExternalInterfaceDeclContext) => Result;
/**
* Visit a parse tree produced by `QuixosCapabilityParser.resourcePreamble`.
* @param ctx the parse tree
* @return the visitor result
*/
visitResourcePreamble?: (ctx: ResourcePreambleContext) => Result;
/** /**
* Visit a parse tree produced by `QuixosCapabilityParser.atomDecl`. * Visit a parse tree produced by `QuixosCapabilityParser.atomDecl`.
* @param ctx the parse tree * @param ctx the parse tree
@@ -90,17 +117,11 @@ export class QuixosCapabilityVisitor<Result> extends AbstractParseTreeVisitor<Re
*/ */
visitAtomDecl?: (ctx: AtomDeclContext) => Result; visitAtomDecl?: (ctx: AtomDeclContext) => Result;
/** /**
* Visit a parse tree produced by `QuixosCapabilityParser.interfaceDecl`. * Visit a parse tree produced by `QuixosCapabilityParser.interfaceResourceDecl`.
* @param ctx the parse tree * @param ctx the parse tree
* @return the visitor result * @return the visitor result
*/ */
visitInterfaceDecl?: (ctx: InterfaceDeclContext) => Result; visitInterfaceResourceDecl?: (ctx: InterfaceResourceDeclContext) => Result;
/**
* Visit a parse tree produced by `QuixosCapabilityParser.sourceBlock`.
* @param ctx the parse tree
* @return the visitor result
*/
visitSourceBlock?: (ctx: SourceBlockContext) => Result;
/** /**
* Visit a parse tree produced by `QuixosCapabilityParser.interfaceMember`. * Visit a parse tree produced by `QuixosCapabilityParser.interfaceMember`.
* @param ctx the parse tree * @param ctx the parse tree
@@ -144,11 +165,11 @@ export class QuixosCapabilityVisitor<Result> extends AbstractParseTreeVisitor<Re
*/ */
visitTargetConstraint?: (ctx: TargetConstraintContext) => Result; visitTargetConstraint?: (ctx: TargetConstraintContext) => Result;
/** /**
* Visit a parse tree produced by `QuixosCapabilityParser.packageDecl`. * Visit a parse tree produced by `QuixosCapabilityParser.packageResourceDecl`.
* @param ctx the parse tree * @param ctx the parse tree
* @return the visitor result * @return the visitor result
*/ */
visitPackageDecl?: (ctx: PackageDeclContext) => Result; visitPackageResourceDecl?: (ctx: PackageResourceDeclContext) => Result;
/** /**
* Visit a parse tree produced by `QuixosCapabilityParser.packageExport`. * Visit a parse tree produced by `QuixosCapabilityParser.packageExport`.
* @param ctx the parse tree * @param ctx the parse tree
+86
View File
@@ -0,0 +1,86 @@
import childProcess from "node:child_process";
import crypto from "node:crypto";
import { mkdir, readFile, realpath } from "node:fs/promises";
import path from "node:path";
import { promisify } from "node:util";
import type { CapabilityRepositoryResolver } from "./assembly.js";
const execFile = promisify(childProcess.execFile);
const sourceKey = (kind: string, repository: string, commit: string) =>
`${kind}\0${repository}\0${commit.toLowerCase()}`;
const checkoutName = (kind: string, repository: string, commit: string) => {
const digest = crypto
.createHash("sha256")
.update(sourceKey(kind, repository, commit))
.digest("hex")
.slice(0, 24);
return `${kind}-${digest}`;
};
export const createGitCapabilityResolver = async (options: {
checkoutRoot: string;
snapshotMap?: string;
}): Promise<CapabilityRepositoryResolver> => {
await mkdir(options.checkoutRoot, { recursive: true });
const checkoutRoot = await realpath(options.checkoutRoot);
const snapshots = new Map<string, string>();
if (options.snapshotMap) {
const snapshotMapPath = await realpath(options.snapshotMap);
const document = JSON.parse(await readFile(snapshotMapPath, "utf8")) as {
resources?: Array<{
kind: string;
repository: string;
commit: string;
directory: string;
}>;
};
for (const entry of document.resources ?? []) {
if (entry.kind !== "interface" && entry.kind !== "package") {
throw new Error(`Snapshot map has unsupported resource kind ${entry.kind}`);
}
const key = sourceKey(entry.kind, entry.repository, entry.commit);
if (snapshots.has(key)) throw new Error(`Snapshot map repeats ${key}`);
const directory = path.resolve(path.dirname(snapshotMapPath), entry.directory);
snapshots.set(key, await realpath(directory));
}
}
const checkouts = new Map<string, Promise<{ directory: string }>>();
return async (source, kind) => {
const key = sourceKey(kind, source.repository, source.commit);
const snapshot = snapshots.get(key);
if (snapshot) return { directory: snapshot };
const existing = checkouts.get(key);
if (existing) return await existing;
const pending = (async () => {
const directory = path.join(
checkoutRoot,
checkoutName(kind, source.repository, source.commit),
);
await execFile("git", [
"-c",
"advice.detachedHead=false",
"clone",
"--depth",
"1",
"--single-branch",
"--branch",
`quixos-reachability/${source.commit.toLowerCase()}`,
source.repository,
directory,
]);
const { stdout } = await execFile("git", ["-C", directory, "rev-parse", "HEAD"]);
if (stdout.trim().toLowerCase() !== source.commit.toLowerCase()) {
throw new Error(
`Locked commit mismatch for ${source.repository}: ` +
`wanted ${source.commit}, fetched ${stdout.trim()}`,
);
}
return { directory };
})();
checkouts.set(key, pending);
return await pending;
};
};
+1
View File
@@ -1 +1,2 @@
export * from "./parser.js"; export * from "./parser.js";
export * from "./assembly.js";
+473 -90
View File
@@ -27,6 +27,7 @@ import {
type InterfaceOperation, type InterfaceOperation,
type InterfaceOperationMode, type InterfaceOperationMode,
type InterfaceRevision, type InterfaceRevision,
type AtomDefinition,
type PackageExport, type PackageExport,
type PackageReceiverRequirement, type PackageReceiverRequirement,
type PackageRevision, type PackageRevision,
@@ -43,15 +44,19 @@ import { QuixosCapabilityParser,
type ConformanceDeclContext, type ConformanceDeclContext,
type DependencyBindingBlockContext, type DependencyBindingBlockContext,
type DependencyPortContext, type DependencyPortContext,
type DocumentContext,
type EdgeDeclContext, type EdgeDeclContext,
type EdgeEndpointContext, type EdgeEndpointContext,
type InterfaceDeclContext, type ExternalAtomDeclContext,
type ExternalInterfaceDeclContext,
type InterfaceResourceDeclContext,
type PackageConstructorExportContext, type PackageConstructorExportContext,
type PackageDeclContext, type PackageResourceDeclContext,
type PackageFunctionExportContext, type PackageFunctionExportContext,
type PackageOperationExportContext, type PackageOperationExportContext,
type OperationMemberContext, type OperationMemberContext,
type SourceBlockContext, type ResourceImportDeclContext,
type ResourcePreambleContext,
type StateDeclContext, type StateDeclContext,
type TargetConstraintContext, type TargetConstraintContext,
type ValueMemberContext, type ValueMemberContext,
@@ -61,6 +66,50 @@ import { QuixosCapabilityParser,
type WorkspaceDeclContext, type WorkspaceDeclContext,
} from "./generated/QuixosCapabilityParser.js"; } from "./generated/QuixosCapabilityParser.js";
export type CapabilityResourceKind = "interface" | "package";
export type CapabilityResourceImport = {
kind: CapabilityResourceKind;
binding: string;
};
export type CapabilityExternalInterface = {
binding: string;
revisionId: InterfaceRevision["revisionId"];
};
export type CapabilityImportEnvironment = {
interfaces?: ReadonlyMap<string, InterfaceRevision>;
packages?: ReadonlyMap<string, PackageRevision>;
/** Complete resolved closure; direct maps above provide local authoring names. */
interfaceClosure?: readonly InterfaceRevision[];
packageClosure?: readonly PackageRevision[];
/** External nominal atoms required by imported resources. */
externalAtoms?: readonly AtomDefinition[];
/** External nominal interfaces supplied by the importing workspace. */
externalInterfaces?: readonly CapabilityExternalInterface[];
};
export type CapabilityResource =
| {
kind: "interface";
imports: CapabilityResourceImport[];
externalAtoms: AtomDefinition[];
externalInterfaces: CapabilityExternalInterface[];
revision: InterfaceRevision;
}
| {
kind: "package";
imports: CapabilityResourceImport[];
externalAtoms: AtomDefinition[];
externalInterfaces: CapabilityExternalInterface[];
revision: PackageRevision;
};
export type CapabilityResourceCompileResult =
| { ok: true; resource: CapabilityResource; diagnostics: [] }
| { ok: false; diagnostics: CapabilitySourceDiagnostic[] };
export type CapabilitySourceDiagnosticPhase = export type CapabilitySourceDiagnosticPhase =
| "syntax" | "syntax"
| "lowering" | "lowering"
@@ -81,6 +130,7 @@ export type CapabilitySourceCompileResult =
ok: true; ok: true;
workspace: WorkspaceRevision; workspace: WorkspaceRevision;
plan: CompiledWorkspaceRevision; plan: CompiledWorkspaceRevision;
imports: CapabilityResourceImport[];
diagnostics: []; diagnostics: [];
} }
| { | {
@@ -90,6 +140,7 @@ export type CapabilitySourceCompileResult =
interface InterfaceSymbol { interface InterfaceSymbol {
revisionId: InterfaceRevision["revisionId"]; revisionId: InterfaceRevision["revisionId"];
contractAvailable: boolean;
members: Map< members: Map<
string, string,
{ {
@@ -220,11 +271,6 @@ const requireSymbol = <Value>(
return value; return value;
}; };
const lowerSource = (context: SourceBlockContext): SourceRevision => ({
repository: stringValue(context.stringLiteral(0)),
commit: stringValue(context.stringLiteral(1)),
});
const lowerCardinality = ( const lowerCardinality = (
context: { getText(): string } | null, context: { getText(): string } | null,
): EdgeCardinality => text(context) as EdgeCardinality; ): EdgeCardinality => text(context) as EdgeCardinality;
@@ -534,7 +580,8 @@ const lowerOperationMember = (
const lowerInterface = ( const lowerInterface = (
state: LoweringState, state: LoweringState,
context: InterfaceDeclContext, context: InterfaceResourceDeclContext,
source: SourceRevision,
): InterfaceRevision => { ): InterfaceRevision => {
const alias = identifier(context.identifier()); const alias = identifier(context.identifier());
const members = context.interfaceMember().flatMap((entry) => { const members = context.interfaceMember().flatMap((entry) => {
@@ -572,7 +619,7 @@ const lowerInterface = (
interfaceId: capabilityId.interface(stringValue(context.stringLiteral(0))), interfaceId: capabilityId.interface(stringValue(context.stringLiteral(0))),
revisionId: symbol.revisionId, revisionId: symbol.revisionId,
displayName: alias, displayName: alias,
source: lowerSource(context.sourceBlock()), source,
members, members,
}; };
}; };
@@ -652,12 +699,21 @@ const lowerDependencyPort = (
context, context,
"interface", "interface",
); );
if (target && !target.contractAvailable) {
loweringIssue(
state,
context,
"nominal-interface-port",
`Interface port ${name} needs the full ${targetName} contract; use import interface ${targetName}`,
);
return undefined;
}
return target return target
? { ? {
id, id,
displayName: name, displayName: name,
requirement: { requirement: {
kind: "receiver-interface", kind: "interface",
interfaceRevisionId: target.revisionId, interfaceRevisionId: target.revisionId,
}, },
} }
@@ -815,7 +871,8 @@ const lowerPackageConstructor = (
const lowerPackage = ( const lowerPackage = (
state: LoweringState, state: LoweringState,
context: PackageDeclContext, context: PackageResourceDeclContext,
source: SourceRevision,
): PackageRevision => { ): PackageRevision => {
const alias = identifier(context.identifier()); const alias = identifier(context.identifier());
const exports = context.packageExport().map((exportContext) => { const exports = context.packageExport().map((exportContext) => {
@@ -837,7 +894,7 @@ const lowerPackage = (
packageId: capabilityId.package(stringValue(context.stringLiteral(0))), packageId: capabilityId.package(stringValue(context.stringLiteral(0))),
revisionId: state.packages.get(alias)!.revisionId, revisionId: state.packages.get(alias)!.revisionId,
displayName: alias, displayName: alias,
source: lowerSource(context.sourceBlock()), source,
exports, exports,
}; };
}; };
@@ -1064,7 +1121,7 @@ const lowerBoundDependencies = (
binding: { kind: "state", slotId: attachment.attachment.id, ...(via ? { via } : {}) }, binding: { kind: "state", slotId: attachment.attachment.id, ...(via ? { via } : {}) },
}]; }];
} }
if (entry.EDGE(0)) { if (entry.EDGE(0) && !entry.INTERFACE()) {
const attachmentName = identifier(entry.identifier(1)); const attachmentName = identifier(entry.identifier(1));
const projectionName = identifier(entry.identifier(2)); const projectionName = identifier(entry.identifier(2));
const attachment = requireSymbol( const attachment = requireSymbol(
@@ -1119,13 +1176,18 @@ const lowerBoundDependencies = (
entry, entry,
"interface", "interface",
); );
const via = entry.VIA()
? traversal(identifier(entry.identifier(2)), identifier(entry.identifier(3)))
: undefined;
if (entry.VIA() && !via) return [];
return interfaceSymbol return interfaceSymbol
? [ ? [
{ {
portId, portId,
binding: { binding: {
kind: "receiver-interface", kind: "interface",
interfaceRevisionId: interfaceSymbol.revisionId, interfaceRevisionId: interfaceSymbol.revisionId,
...(via ? { via } : {}),
}, },
}, },
] ]
@@ -1349,10 +1411,117 @@ const lowerConformance = (
}; };
}; };
const interfaceSymbolFor = (revision: InterfaceRevision): InterfaceSymbol => ({
revisionId: revision.revisionId,
contractAvailable: true,
members: new Map(revision.members.map((member) => [
member.displayName,
{
memberId: member.id,
operations: new Map(member.operations.map((operation) => [
operation.displayName,
operation.id,
])),
},
])),
});
const packageSymbolFor = (revision: PackageRevision): PackageSymbol => ({
revisionId: revision.revisionId,
exports: new Map(revision.exports.map((entry) => [
entry.displayName,
{
exportId: entry.id,
ports: new Map(entry.dependencyPorts.map((port) => [
port.displayName,
port.id,
])),
},
])),
});
const resourceImport = (
context: ResourceImportDeclContext,
): CapabilityResourceImport => ({
kind: context.INTERFACE() ? "interface" : "package",
binding: identifier(context.identifier()),
});
const registerImports = (
state: LoweringState,
contexts: readonly ResourceImportDeclContext[],
environment: CapabilityImportEnvironment,
) => contexts.map((context) => {
const imported = resourceImport(context);
if (imported.kind === "interface") {
const revision = environment.interfaces?.get(imported.binding);
if (!revision) {
loweringIssue(
state,
context,
"missing-import",
`No resolved interface is available for lock binding ${imported.binding}`,
);
} else {
declareSymbol(
state,
state.interfaces,
imported.binding,
interfaceSymbolFor(revision),
context,
"interface",
);
}
} else {
const revision = environment.packages?.get(imported.binding);
if (!revision) {
loweringIssue(
state,
context,
"missing-import",
`No resolved package is available for lock binding ${imported.binding}`,
);
} else {
declareSymbol(
state,
state.packages,
imported.binding,
packageSymbolFor(revision),
context,
"package",
);
}
}
return imported;
});
const uniqueExactRevisions = <Revision extends {
revisionId: string;
source: SourceRevision;
}>(revisions: readonly Revision[]): Revision[] => {
const seen = new Set<string>();
return revisions.filter((revision) => {
const key = `${revision.revisionId}\0${revision.source.repository}\0${revision.source.commit}`;
if (seen.has(key)) return false;
seen.add(key);
return true;
});
};
const uniqueAtoms = (atoms: readonly AtomDefinition[]): AtomDefinition[] => {
const seen = new Set<string>();
return atoms.filter((atom) => {
if (seen.has(atom.id)) return false;
seen.add(atom.id);
return true;
});
};
const lowerWorkspace = ( const lowerWorkspace = (
state: LoweringState, state: LoweringState,
context: WorkspaceDeclContext, context: WorkspaceDeclContext,
): WorkspaceRevision => { environment: CapabilityImportEnvironment,
): { workspace: WorkspaceRevision; imports: CapabilityResourceImport[] } => {
const items = context.workspaceItem(); const items = context.workspaceItem();
for (const item of items) { for (const item of items) {
@@ -1368,41 +1537,14 @@ const lowerWorkspace = (
); );
continue; continue;
} }
const interfaceContext = item.interfaceDecl();
if (interfaceContext) {
declareSymbol(
state,
state.interfaces,
identifier(interfaceContext.identifier()),
{
revisionId: capabilityId.interfaceRevision(
stringValue(interfaceContext.stringLiteral(1)),
),
members: new Map(),
},
interfaceContext,
"interface",
);
continue;
}
const packageContext = item.packageDecl();
if (packageContext) {
declareSymbol(
state,
state.packages,
identifier(packageContext.identifier()),
{
revisionId: capabilityId.packageRevision(
stringValue(packageContext.stringLiteral(1)),
),
exports: new Map(),
},
packageContext,
"package",
);
}
} }
const imports = registerImports(
state,
items.flatMap((item) => item.resourceImportDecl() ?? []),
environment,
);
const atoms = items.flatMap((item) => { const atoms = items.flatMap((item) => {
const atom = item.atomDecl(); const atom = item.atomDecl();
if (!atom) { if (!atom) {
@@ -1422,15 +1564,15 @@ const lowerWorkspace = (
: []; : [];
}); });
const interfaceImports = items.flatMap((item) => { const interfaceImports = uniqueExactRevisions([
const interfaceContext = item.interfaceDecl(); ...(environment.interfaceClosure ?? []),
return interfaceContext ? [lowerInterface(state, interfaceContext)] : []; ...[...(environment.interfaces?.values() ?? [])],
}); ]);
const packageImports = items.flatMap((item) => { const packageImports = uniqueExactRevisions([
const packageContext = item.packageDecl(); ...(environment.packageClosure ?? []),
return packageContext ? [lowerPackage(state, packageContext)] : []; ...[...(environment.packages?.values() ?? [])],
}); ]);
const sharedAttachments: PersistentAttachment[] = []; const sharedAttachments: PersistentAttachment[] = [];
const privateAttachments = new Map< const privateAttachments = new Map<
@@ -1520,23 +1662,26 @@ const lowerWorkspace = (
}); });
return { return {
id: capabilityId.workspaceRevision(stringValue(context.stringLiteral(1))), imports,
workspaceId: capabilityId.workspace(stringValue(context.stringLiteral(0))), workspace: {
parentRevisionIds: [], id: capabilityId.workspaceRevision(stringValue(context.stringLiteral(1))),
sourceRootCommit: stringValue(context.stringLiteral(2)), workspaceId: capabilityId.workspace(stringValue(context.stringLiteral(0))),
atoms, parentRevisionIds: [],
sharedAttachments, sourceRootCommit: stringValue(context.stringLiteral(2)),
interfaceImports, atoms,
packageImports, sharedAttachments,
conformances, interfaceImports,
constructors, packageImports,
conformances,
constructors,
},
}; };
}; };
export const compileCapabilitySource = ( const parseDocument = (
source: string, source: string,
fileName = "<memory>", fileName: string,
): CapabilitySourceCompileResult => { ): { tree: DocumentContext; diagnostics: CapabilitySourceDiagnostic[] } => {
const diagnostics: CapabilitySourceDiagnostic[] = []; const diagnostics: CapabilitySourceDiagnostic[] = [];
const listener = new SyntaxErrorListener(fileName, diagnostics); const listener = new SyntaxErrorListener(fileName, diagnostics);
const lexer = new QuixosCapabilityLexer(CharStream.fromString(source)); const lexer = new QuixosCapabilityLexer(CharStream.fromString(source));
@@ -1548,36 +1693,274 @@ export const compileCapabilitySource = (
parser.removeErrorListeners(); parser.removeErrorListeners();
parser.addErrorListener(listener); parser.addErrorListener(listener);
const tree = parser.document(); const tree = parser.document();
return { tree, diagnostics };
};
const newLoweringState = (
fileName: string,
diagnostics: CapabilitySourceDiagnostic[],
): LoweringState => ({
fileName,
diagnostics,
atoms: new Map(),
interfaces: new Map(),
packages: new Map(),
attachments: new Map(),
});
const validationDiagnostics = (
fileName: string,
issues: ReturnType<typeof compileWorkspaceRevision> extends infer _Result
? Array<{ code: string; message: string; path: string }>
: never,
): CapabilitySourceDiagnostic[] => issues.map((entry) => ({
phase: "validation",
code: entry.code,
message: entry.message,
fileName,
line: 0,
column: 0,
path: entry.path,
}));
const externalAtomsFrom = (
state: LoweringState,
contexts: readonly ExternalAtomDeclContext[],
): AtomDefinition[] => contexts.map((context) => {
const atom: AtomDefinition = {
id: capabilityId.atom(stringValue(context.stringLiteral())),
displayName: identifier(context.identifier()),
};
declareSymbol(
state,
state.atoms,
atom.displayName,
atom.id,
context,
"external atom",
);
return atom;
});
const externalInterfacesFrom = (
state: LoweringState,
contexts: readonly ExternalInterfaceDeclContext[],
): CapabilityExternalInterface[] => contexts.map((context) => {
const requirement: CapabilityExternalInterface = {
binding: identifier(context.identifier()),
revisionId: capabilityId.interfaceRevision(stringValue(context.stringLiteral())),
};
declareSymbol(
state,
state.interfaces,
requirement.binding,
{
revisionId: requirement.revisionId,
contractAvailable: false,
members: new Map(),
},
context,
"external interface",
);
return requirement;
});
const resourcePreambleParts = (contexts: readonly ResourcePreambleContext[]) => ({
imports: contexts.flatMap((context) => context.resourceImportDecl() ?? []),
atoms: contexts.flatMap((context) => context.externalAtomDecl() ?? []),
interfaces: contexts.flatMap((context) => context.externalInterfaceDecl() ?? []),
});
const resourceValidationWorkspace = (
resource: CapabilityResource,
environment: CapabilityImportEnvironment,
): WorkspaceRevision => {
const resolvedInterfaceIds = new Set([
...(environment.interfaceClosure ?? []).map((revision) => revision.revisionId),
...[...(environment.interfaces?.values() ?? [])].map((revision) => revision.revisionId),
...(resource.kind === "interface" ? [resource.revision.revisionId] : []),
]);
return ({
id: capabilityId.workspaceRevision("workspace-revision:resource-validation"),
workspaceId: capabilityId.workspace("workspace:resource-validation"),
parentRevisionIds: [],
sourceRootCommit: resource.revision.source.commit,
atoms: uniqueAtoms([
...(environment.externalAtoms ?? []),
...resource.externalAtoms,
]),
sharedAttachments: [],
interfaceImports: uniqueExactRevisions([
...(environment.interfaceClosure ?? []),
...[...(environment.interfaces?.values() ?? [])],
...(resource.kind === "interface" ? [resource.revision] : []),
...resource.externalInterfaces
.filter((requirement) => !resolvedInterfaceIds.has(requirement.revisionId))
.map((requirement): InterfaceRevision => ({
interfaceId: capabilityId.interface(`external:${requirement.revisionId}`),
revisionId: requirement.revisionId,
displayName: requirement.binding,
source: {
repository: `https://external.invalid/${encodeURIComponent(requirement.revisionId)}.git`,
commit: "0".repeat(40),
},
members: [],
})),
]),
packageImports: uniqueExactRevisions([
...(environment.packageClosure ?? []),
...[...(environment.packages?.values() ?? [])],
...(resource.kind === "package" ? [resource.revision] : []),
]),
conformances: [],
constructors: [],
});
};
export const compileCapabilityResourceSource = (
sourceText: string,
options: {
source: SourceRevision;
fileName?: string;
environment?: CapabilityImportEnvironment;
},
): CapabilityResourceCompileResult => {
const fileName = options.fileName ?? "<memory>";
const environment = options.environment ?? {};
const { tree, diagnostics } = parseDocument(sourceText, fileName);
if (diagnostics.length > 0) { if (diagnostics.length > 0) {
return { ok: false, diagnostics }; return { ok: false, diagnostics };
} }
const state: LoweringState = { const interfaceContext = tree.interfaceResourceDecl();
fileName, const packageContext = tree.packageResourceDecl();
diagnostics, if (!interfaceContext && !packageContext) {
atoms: new Map(), return {
interfaces: new Map(), ok: false,
packages: new Map(), diagnostics: [{
attachments: new Map(), phase: "lowering",
}; code: "expected-resource",
const workspace = lowerWorkspace(state, tree.workspaceDecl()); message: "Expected a standalone interface or package resource document",
fileName,
line: 1,
column: 0,
}],
};
}
const state = newLoweringState(fileName, diagnostics);
const preamble = resourcePreambleParts(
(interfaceContext ?? packageContext)!.resourcePreamble(),
);
const externalAtoms = externalAtomsFrom(state, preamble.atoms);
const imports = registerImports(state, preamble.imports, environment);
const externalInterfaces = externalInterfacesFrom(state, preamble.interfaces);
let resource: CapabilityResource;
if (interfaceContext) {
const alias = identifier(interfaceContext.identifier());
declareSymbol(
state,
state.interfaces,
alias,
{
revisionId: capabilityId.interfaceRevision(
stringValue(interfaceContext.stringLiteral(1)),
),
contractAvailable: true,
members: new Map(),
},
interfaceContext,
"interface",
);
resource = {
kind: "interface",
imports,
externalAtoms,
externalInterfaces,
revision: lowerInterface(state, interfaceContext, options.source),
};
} else {
const context = packageContext!;
const alias = identifier(context.identifier());
declareSymbol(
state,
state.packages,
alias,
{
revisionId: capabilityId.packageRevision(
stringValue(context.stringLiteral(1)),
),
exports: new Map(),
},
context,
"package",
);
resource = {
kind: "package",
imports,
externalAtoms,
externalInterfaces,
revision: lowerPackage(state, context, options.source),
};
}
if (diagnostics.length > 0) { if (diagnostics.length > 0) {
return { ok: false, diagnostics }; return { ok: false, diagnostics };
} }
const compiled = compileWorkspaceRevision(workspace); const compiled = compileWorkspaceRevision(
resourceValidationWorkspace(resource, environment),
);
if (!compiled.ok) { if (!compiled.ok) {
return { return {
ok: false, ok: false,
diagnostics: compiled.issues.map((entry) => ({ diagnostics: validationDiagnostics(fileName, compiled.issues),
phase: "validation",
code: entry.code,
message: entry.message,
fileName,
line: 0,
column: 0,
path: entry.path,
})),
}; };
} }
return { ok: true, workspace, plan: compiled.plan, diagnostics: [] }; return { ok: true, resource, diagnostics: [] };
};
export const compileCapabilitySource = (
source: string,
fileName = "<memory>",
environment: CapabilityImportEnvironment = {},
): CapabilitySourceCompileResult => {
const { tree, diagnostics } = parseDocument(source, fileName);
if (diagnostics.length > 0) {
return { ok: false, diagnostics };
}
const workspaceContext = tree.workspaceDecl();
if (!workspaceContext) {
return {
ok: false,
diagnostics: [{
phase: "lowering",
code: "expected-workspace",
message: "Expected a workspace document",
fileName,
line: 1,
column: 0,
}],
};
}
const state = newLoweringState(fileName, diagnostics);
const lowered = lowerWorkspace(state, workspaceContext, environment);
if (diagnostics.length > 0) {
return { ok: false, diagnostics };
}
const compiled = compileWorkspaceRevision(lowered.workspace);
if (!compiled.ok) {
return {
ok: false,
diagnostics: validationDiagnostics(fileName, compiled.issues),
};
}
return {
ok: true,
workspace: lowered.workspace,
plan: compiled.plan,
imports: lowered.imports,
diagnostics: [],
};
}; };
+101
View File
@@ -0,0 +1,101 @@
#!/usr/bin/env node
import { writeFile } from "node:fs/promises";
import process from "node:process";
import {
compileCapabilityResourceRepository,
type ResolvedCapabilityResource,
} from "./assembly.js";
import { createGitCapabilityResolver } from "./git-resolver.js";
const usage = `usage: quixos-resource-compile --root DIRECTORY --kind interface|package
--repository URL --commit GIT_REV --checkout-root DIRECTORY
[--snapshot-map PATH] [--graph-out PATH]
Resolves a standalone resource's recursive dependency-lock graph, validates
its interface.qx or package.qx manifest, and emits the checked resource as JSON.`;
const parseArgs = (args: string[]) => {
const values = new Map<string, string>();
for (let index = 0; index < args.length; index += 2) {
const key = args[index];
const value = args[index + 1];
if (!key?.startsWith("--") || !value) throw new Error(usage);
values.set(key, value);
}
const rootDirectory = values.get("--root");
const kind = values.get("--kind");
const repository = values.get("--repository");
const commit = values.get("--commit")?.toLowerCase();
const checkoutRoot = values.get("--checkout-root");
if (!rootDirectory || !repository || !commit || !checkoutRoot ||
(kind !== "interface" && kind !== "package")) {
throw new Error(usage);
}
if (!/^([0-9a-f]{40}|[0-9a-f]{64})$/.test(commit)) {
throw new Error("--commit must be a full Git object ID");
}
return {
rootDirectory,
kind,
repository,
commit,
checkoutRoot,
snapshotMap: values.get("--snapshot-map"),
graphOut: values.get("--graph-out"),
} as const;
};
const graphEntry = (node: ResolvedCapabilityResource) => ({
key: node.key,
kind: node.kind,
source: node.source,
directory: node.directory,
resourceId: node.resource.kind === "interface"
? node.resource.revision.interfaceId
: node.resource.revision.packageId,
revisionId: node.resource.revision.revisionId,
dependencies: [...node.dependencies.entries()].map(([binding, dependency]) => ({
binding,
resourceKey: dependency.key,
})),
});
const main = async () => {
if (process.argv.includes("--help") || process.argv.includes("-h")) {
process.stdout.write(`${usage}\n`);
return;
}
const options = parseArgs(process.argv.slice(2));
const resolveResource = await createGitCapabilityResolver({
checkoutRoot: options.checkoutRoot,
snapshotMap: options.snapshotMap,
});
const compiled = await compileCapabilityResourceRepository({
rootDirectory: options.rootDirectory,
kind: options.kind,
source: {
resolver: "git",
repository: options.repository,
commit: options.commit,
},
resolveResource,
});
if (options.graphOut) {
await writeFile(options.graphOut, `${JSON.stringify({
formatVersion: 1,
quixos: compiled.lock.quixos,
root: graphEntry(compiled.resources.find((node) =>
node.source.repository === options.repository &&
node.source.commit === options.commit &&
node.kind === options.kind)!),
resources: compiled.resources.map(graphEntry),
}, null, 2)}\n`);
}
process.stdout.write(`${JSON.stringify(compiled.resource, null, 2)}\n`);
};
main().catch((error: unknown) => {
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
process.exitCode = 1;
});
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env node
import { writeFile } from "node:fs/promises";
import process from "node:process";
import { compileWorkspaceRepository } from "./assembly.js";
import { createGitCapabilityResolver } from "./git-resolver.js";
const usage = `usage: quixos-workspace-compile --root DIRECTORY --checkout-root DIRECTORY
[--snapshot-map PATH] [--graph-out PATH] [--workspace-id ID] [--workspace-revision-id ID]
[--source-root-commit GIT_REV]
Resolves a workspace's recursive resource-lock graph, clones every exact
resource revision, validates standalone interface/package manifests, and emits
the checked workspace plan as JSON.`;
const parseArgs = (args: string[]) => {
const values = new Map<string, string>();
for (let index = 0; index < args.length; index += 2) {
const key = args[index];
const value = args[index + 1];
if (!key?.startsWith("--") || !value) throw new Error(usage);
values.set(key, value);
}
const rootDirectory = values.get("--root");
const checkoutRoot = values.get("--checkout-root");
if (!rootDirectory || !checkoutRoot) throw new Error(usage);
return {
rootDirectory,
checkoutRoot,
graphOut: values.get("--graph-out"),
snapshotMap: values.get("--snapshot-map"),
workspaceId: values.get("--workspace-id"),
workspaceRevisionId: values.get("--workspace-revision-id"),
sourceRootCommit: values.get("--source-root-commit"),
};
};
const main = async () => {
if (process.argv.includes("--help") || process.argv.includes("-h")) {
process.stdout.write(`${usage}\n`);
return;
}
const options = parseArgs(process.argv.slice(2));
const resolveResource = await createGitCapabilityResolver({
checkoutRoot: options.checkoutRoot,
snapshotMap: options.snapshotMap,
});
const assembled = await compileWorkspaceRepository({
rootDirectory: options.rootDirectory,
workspaceId: options.workspaceId,
workspaceRevisionId: options.workspaceRevisionId,
sourceRootCommit: options.sourceRootCommit,
resolveResource,
});
if (options.graphOut) {
await writeFile(options.graphOut, `${JSON.stringify({
formatVersion: 1,
quixos: assembled.lock.quixos,
directResources: [...assembled.directResources.entries()].map(([bindingKey, node]) => {
const [kind, binding] = bindingKey.split("\0");
return { kind, binding, resourceKey: node.key, directory: node.directory };
}),
resources: assembled.resources.map((node) => ({
key: node.key,
kind: node.kind,
source: node.source,
directory: node.directory,
resourceId: node.resource.kind === "interface"
? node.resource.revision.interfaceId
: node.resource.revision.packageId,
revisionId: node.resource.revision.revisionId,
dependencies: [...node.dependencies.entries()].map(([binding, dependency]) => ({
binding,
resourceKey: dependency.key,
})),
})),
}, null, 2)}\n`);
}
process.stdout.write(`${JSON.stringify(assembled.workspace, null, 2)}\n`);
};
main().catch((error: unknown) => {
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
process.exitCode = 1;
});
+3 -2
View File
@@ -242,7 +242,7 @@ export type DependencyPortRequirement =
primitives: EdgePrimitive[]; primitives: EdgePrimitive[];
} }
| { | {
kind: "receiver-interface"; kind: "interface";
interfaceRevisionId: InterfaceRevisionId; interfaceRevisionId: InterfaceRevisionId;
} }
| { kind: "constructor"; atomId: AtomId }; | { kind: "constructor"; atomId: AtomId };
@@ -299,8 +299,9 @@ export type DependencyBinding =
via?: EdgeTraversal; via?: EdgeTraversal;
} }
| { | {
kind: "receiver-interface"; kind: "interface";
interfaceRevisionId: InterfaceRevisionId; interfaceRevisionId: InterfaceRevisionId;
via?: EdgeTraversal;
} }
| { kind: "constructor"; atomId: AtomId }; | { kind: "constructor"; atomId: AtomId };
+75 -20
View File
@@ -61,7 +61,7 @@ export type CapabilityValidationIssueCode =
| "invalid-dependency-binding" | "invalid-dependency-binding"
| "private-attachment-access" | "private-attachment-access"
| "incompatible-package-receiver" | "incompatible-package-receiver"
| "unsatisfied-receiver-interface" | "unsatisfied-interface"
| "cyclic-conformance-requirement" | "cyclic-conformance-requirement"
| "missing-operation-binding" | "missing-operation-binding"
| "unknown-operation-binding" | "unknown-operation-binding"
@@ -917,7 +917,7 @@ const validatePackages = (
validateConstraint(issues, port.requirement.target, `${portPath}.requirement.target`, indexes); validateConstraint(issues, port.requirement.target, `${portPath}.requirement.target`, indexes);
uniquePrimitiveList(issues, port.requirement.primitives, `${portPath}.requirement.primitives`); uniquePrimitiveList(issues, port.requirement.primitives, `${portPath}.requirement.primitives`);
break; break;
case "receiver-interface": case "interface":
if (!indexes.interfaces.has(port.requirement.interfaceRevisionId)) { if (!indexes.interfaces.has(port.requirement.interfaceRevisionId)) {
issue( issue(
issues, issues,
@@ -976,6 +976,7 @@ const validateTraversal = (
atomId: AtomId, atomId: AtomId,
traversal: { edgeTypeId: EdgeTypeId; projectionId: EdgeProjectionId }, traversal: { edgeTypeId: EdgeTypeId; projectionId: EdgeProjectionId },
path: string, path: string,
conformance?: Pick<Conformance, "atomId" | "interfaceRevisionId">,
) => { ) => {
const attachment = findAttachment(indexes, "edge", traversal.edgeTypeId); const attachment = findAttachment(indexes, "edge", traversal.edgeTypeId);
if (!attachment || attachment.attachment.kind !== "edge") { if (!attachment || attachment.attachment.kind !== "edge") {
@@ -987,6 +988,7 @@ const validateTraversal = (
); );
return undefined; return undefined;
} }
validateAttachmentAccess(issues, attachment, conformance, `${path}.edgeTypeId`);
const projection = edgeProjection(attachment.attachment, traversal.projectionId); const projection = edgeProjection(attachment.attachment, traversal.projectionId);
if (!projection) { if (!projection) {
issue( issue(
@@ -1085,6 +1087,7 @@ const validateBoundDependencies = (
params.atomId, params.atomId,
stateBinding.via, stateBinding.via,
`${path}.binding.via`, `${path}.binding.via`,
params.conformance,
) )
: undefined; : undefined;
if ( if (
@@ -1145,6 +1148,7 @@ const validateBoundDependencies = (
params.atomId, params.atomId,
edgeBinding.via, edgeBinding.via,
`${path}.binding.via`, `${path}.binding.via`,
params.conformance,
) )
: undefined; : undefined;
const originMatches = edgeBinding.via const originMatches = edgeBinding.via
@@ -1189,10 +1193,10 @@ const validateBoundDependencies = (
} }
break; break;
} }
case "receiver-interface": { case "interface": {
const interfaceBinding = binding as Extract< const interfaceBinding = binding as Extract<
DependencyBinding, DependencyBinding,
{ kind: "receiver-interface" } { kind: "interface" }
>; >;
if (interfaceBinding.interfaceRevisionId !== requirement.interfaceRevisionId) { if (interfaceBinding.interfaceRevisionId !== requirement.interfaceRevisionId) {
issue( issue(
@@ -1203,16 +1207,38 @@ const validateBoundDependencies = (
); );
break; break;
} }
const targetKey = conformanceKey(params.atomId, requirement.interfaceRevisionId); const traversal = interfaceBinding.via
if (!params.indexes.conformances.has(targetKey)) { ? validateTraversal(
issue( issues,
issues, params.indexes,
"unsatisfied-receiver-interface", params.atomId,
`${path}.binding.interfaceRevisionId`, interfaceBinding.via,
`Receiver atom ${params.atomId} does not conform to ${requirement.interfaceRevisionId}`, `${path}.binding.via`,
); params.conformance,
} else if (params.graphSourceKey) { )
params.requirementGraph.get(params.graphSourceKey)?.add(targetKey); : undefined;
const candidateAtoms = interfaceBinding.via
? traversal
? [...params.indexes.atoms.keys()].filter((atomId) =>
atomSatisfiesConstraint(
atomId as AtomId,
traversal.target.constraint,
params.indexes.conformances,
)) as AtomId[]
: []
: [params.atomId];
for (const atomId of candidateAtoms) {
const targetKey = conformanceKey(atomId, requirement.interfaceRevisionId);
if (!params.indexes.conformances.has(targetKey)) {
issue(
issues,
"unsatisfied-interface",
`${path}.binding.interfaceRevisionId`,
`${interfaceBinding.via ? "Related" : "Receiver"} atom ${atomId} does not conform to ${requirement.interfaceRevisionId}`,
);
} else if (params.graphSourceKey) {
params.requirementGraph.get(params.graphSourceKey)?.add(targetKey);
}
} }
break; break;
} }
@@ -1276,7 +1302,7 @@ const validatePackageReceiver = (
if (!params.indexes.conformances.has(targetKey)) { if (!params.indexes.conformances.has(targetKey)) {
issue( issue(
issues, issues,
"unsatisfied-receiver-interface", "unsatisfied-interface",
params.path, params.path,
`Atom ${params.atomId} does not conform to ${requiredInterface}`, `Atom ${params.atomId} does not conform to ${requiredInterface}`,
); );
@@ -1971,6 +1997,9 @@ export const computeCapabilityClosure = (
const constructors = new Set<AtomId>(); const constructors = new Set<AtomId>();
const queued = [...roots]; const queued = [...roots];
const visited = new Set<string>(); const visited = new Set<string>();
const sourceConformances = new Map(
[...plan.conformances].map(([key, value]) => [key, value.source]),
);
const includeDependencies = ( const includeDependencies = (
atomId: AtomId, atomId: AtomId,
@@ -1990,12 +2019,38 @@ export const computeCapabilityClosure = (
attachments.add(dependency.binding.via.edgeTypeId); attachments.add(dependency.binding.via.edgeTypeId);
} }
break; break;
case "receiver-interface": case "interface": {
queued.push({ if (dependency.binding.via) {
atomId, attachments.add(dependency.binding.via.edgeTypeId);
interfaceRevisionId: dependency.binding.interfaceRevisionId, }
}); const targetAtoms = dependency.binding.via
? (() => {
const attachment = plan.attachments.get(
`edge\u0000${dependency.binding.via!.edgeTypeId}`,
)?.attachment;
if (!attachment || attachment.kind !== "edge") return [];
const projection = edgeProjection(
attachment,
dependency.binding.via!.projectionId,
);
return projection
? [...plan.atoms.keys()].filter((candidate) =>
atomSatisfiesConstraint(
candidate,
projection.target.constraint,
sourceConformances,
))
: [];
})()
: [atomId];
for (const targetAtom of targetAtoms) {
queued.push({
atomId: targetAtom,
interfaceRevisionId: dependency.binding.interfaceRevisionId,
});
}
break; break;
}
case "constructor": { case "constructor": {
constructors.add(dependency.binding.atomId); constructors.add(dependency.binding.atomId);
const constructor = plan.constructors.get(dependency.binding.atomId); const constructor = plan.constructors.get(dependency.binding.atomId);
+14 -1
View File
@@ -18,7 +18,7 @@ import type { Message } from "@bufbuild/protobuf";
* Describes the file quixos/orch.proto. * Describes the file quixos/orch.proto.
*/ */
export const file_quixos_orch: GenFile = /*@__PURE__*/ export const file_quixos_orch: GenFile = /*@__PURE__*/
fileDesc("ChFxdWl4b3Mvb3JjaC5wcm90bxILcXVpeG9zLm9yY2gipQEKFkNvbnN0cnVjdE9iamVjdFJlcXVlc3QSDwoHYXRvbV9pZBgBIAEoCRI9CgVpbnB1dBgCIAMoCzIuLnF1aXhvcy5vcmNoLkNvbnN0cnVjdE9iamVjdFJlcXVlc3QuSW5wdXRFbnRyeRo7CgpJbnB1dEVudHJ5EgsKA2tleRgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZToCOAEiPwoXQ29uc3RydWN0T2JqZWN0UmVzcG9uc2USJAoGb2JqZWN0GAEgASgLMhQuY2FtaW5vLkNhbWlub09iamVjdCJtCiZSZXNvbHZlT3JDb25zdHJ1Y3RSZWxhdGVkT2JqZWN0UmVxdWVzdBIRCglvYmplY3RfaWQYASABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAIgASgJEhEKCW1lbWJlcl9pZBgDIAEoCSJkCidSZXNvbHZlT3JDb25zdHJ1Y3RSZWxhdGVkT2JqZWN0UmVzcG9uc2USJAoGb2JqZWN0GAEgASgLMhQuY2FtaW5vLkNhbWlub09iamVjdBITCgtjb25zdHJ1Y3RlZBgCIAEoCCLUAQoXSW52b2tlQ2FwYWJpbGl0eVJlcXVlc3QSKQoKY2FwYWJpbGl0eRgBIAEoCzIVLnF1aXhvcy5DYXBhYmlsaXR5UmVmEhEKCW9iamVjdF9pZBgCIAEoCRI+CgVpbnB1dBgDIAMoCzIvLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXF1ZXN0LklucHV0RW50cnkaOwoKSW5wdXRFbnRyeRILCgNrZXkYASABKAkSHAoFdmFsdWUYAiABKAsyDS5jYW1pbm8uVmFsdWU6AjgBIpgBChhJbnZva2VDYXBhYmlsaXR5UmVzcG9uc2USFQoNaW52b2NhdGlvbl9pZBgBIAEoCRIrCgphY3RpdmF0aW9uGAIgASgLMhcucXVpeG9zLm9yY2guQWN0aXZhdGlvbhIKCgJvaxgDIAEoCBIdCgZyZXN1bHQYBCABKAsyDS5jYW1pbm8uVmFsdWUSDQoFZXJyb3IYBSABKAki0gEKFldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QSKQoKY2FwYWJpbGl0eRgBIAEoCzIVLnF1aXhvcy5DYXBhYmlsaXR5UmVmEhEKCW9iamVjdF9pZBgCIAEoCRI9CgVpbnB1dBgDIAMoCzIuLnF1aXhvcy5vcmNoLldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QuSW5wdXRFbnRyeRo7CgpJbnB1dEVudHJ5EgsKA2tleRgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZToCOAEi4wEKFFdhdGNoQ2FwYWJpbGl0eUV2ZW50EhUKDWludm9jYXRpb25faWQYASABKAkSKwoKYWN0aXZhdGlvbhgCIAEoCzIXLnF1aXhvcy5vcmNoLkFjdGl2YXRpb24SEAoId2F0Y2hfaWQYAyABKAkSHAoFdmFsdWUYBCABKAsyDS5jYW1pbm8uVmFsdWUSNwoMZGVwZW5kZW5jaWVzGAUgAygLMiEucXVpeG9zLnJ1bnRpbWUuRGVyaXZlZERlcGVuZGVuY3kSDQoFZXJyb3IYBiABKAkSDwoHaW5pdGlhbBgHIAEoCCIVChNHZXRXb3Jrc3BhY2VSZXF1ZXN0ImcKFEdldFdvcmtzcGFjZVJlc3BvbnNlEhQKDHdvcmtzcGFjZV9pZBgBIAEoCRIdChV3b3Jrc3BhY2VfcmV2aXNpb25faWQYAiABKAkSGgoSc291cmNlX3Jvb3RfY29tbWl0GAMgASgJIhgKFkxpc3RBY3RpdmF0aW9uc1JlcXVlc3QiHwodTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1JlcXVlc3QiUAoeTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1Jlc3BvbnNlEi4KC2Rlc2NyaXB0b3JzGAEgAygLMhkucXVpeG9zLlBhY2thZ2VEZXNjcmlwdG9yIhwKGkxpc3RQYWNrYWdlUnVudGltZXNSZXF1ZXN0IlIKG0xpc3RQYWNrYWdlUnVudGltZXNSZXNwb25zZRIzCghydW50aW1lcxgBIAMoCzIhLnF1aXhvcy5vcmNoLlBhY2thZ2VSdW50aW1lU3RhdHVzIkcKF0xpc3RBY3RpdmF0aW9uc1Jlc3BvbnNlEiwKC2FjdGl2YXRpb25zGAEgAygLMhcucXVpeG9zLm9yY2guQWN0aXZhdGlvbiI/ChZDbG9zZUFjdGl2YXRpb25SZXF1ZXN0EhUKDWFjdGl2YXRpb25faWQYASABKAkSDgoGcmVhc29uGAIgASgJIkYKF0Nsb3NlQWN0aXZhdGlvblJlc3BvbnNlEisKCmFjdGl2YXRpb24YASABKAsyFy5xdWl4b3Mub3JjaC5BY3RpdmF0aW9uIusBCgpBY3RpdmF0aW9uEhUKDWFjdGl2YXRpb25faWQYASABKAkSKAoGZXhwb3J0GAIgASgLMhgucXVpeG9zLlBhY2thZ2VFeHBvcnRSZWYSEQoJb2JqZWN0X2lkGAMgASgJEg0KBXN0YXRlGAQgASgJEg4KBmRlbWFuZBgFIAEoDRIRCglvcGVuZWRfYXQYBiABKAkSFAoMbGFzdF91c2VkX2F0GAcgASgJEhgKEGlkbGVfZGVhZGxpbmVfYXQYCCABKAkSEQoJY2xvc2VkX2F0GAkgASgJEhQKDGNsb3NlX3JlYXNvbhgKIAEoCSKzAgoUUGFja2FnZVJ1bnRpbWVTdGF0dXMSEwoLcnVudGltZV9rZXkYASABKAkSGwoTcGFja2FnZV9yZXZpc2lvbl9pZBgCIAEoCRIZChFzb3VyY2VfcmVwb3NpdG9yeRgDIAEoCRIVCg1zb3VyY2VfY29tbWl0GAQgASgJEhQKDGJ1aWxkX3RhcmdldBgFIAEoCRITCgtzZXJ2ZXJfcGF0aBgGIAEoCRILCgNwaWQYByABKA0SDQoFc3RhdGUYCCABKAkSEgoKc3RhcnRlZF9hdBgJIAEoCRIZChFsYXN0X2hhbmRzaGFrZV9hdBgKIAEoCRIgChhydW50aW1lX3Byb3RvY29sX3ZlcnNpb24YCyABKAkSHwoXYWR2ZXJ0aXNlZF9leHBvcnRfY291bnQYDCABKA0yrgcKE09yY2hlc3RyYXRvclJ1bnRpbWUSXwoQSW52b2tlQ2FwYWJpbGl0eRIkLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXF1ZXN0GiUucXVpeG9zLm9yY2guSW52b2tlQ2FwYWJpbGl0eVJlc3BvbnNlElsKD1dhdGNoQ2FwYWJpbGl0eRIjLnF1aXhvcy5vcmNoLldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QaIS5xdWl4b3Mub3JjaC5XYXRjaENhcGFiaWxpdHlFdmVudDABElwKD0NvbnN0cnVjdE9iamVjdBIjLnF1aXhvcy5vcmNoLkNvbnN0cnVjdE9iamVjdFJlcXVlc3QaJC5xdWl4b3Mub3JjaC5Db25zdHJ1Y3RPYmplY3RSZXNwb25zZRKMAQofUmVzb2x2ZU9yQ29uc3RydWN0UmVsYXRlZE9iamVjdBIzLnF1aXhvcy5vcmNoLlJlc29sdmVPckNvbnN0cnVjdFJlbGF0ZWRPYmplY3RSZXF1ZXN0GjQucXVpeG9zLm9yY2guUmVzb2x2ZU9yQ29uc3RydWN0UmVsYXRlZE9iamVjdFJlc3BvbnNlElMKDEdldFdvcmtzcGFjZRIgLnF1aXhvcy5vcmNoLkdldFdvcmtzcGFjZVJlcXVlc3QaIS5xdWl4b3Mub3JjaC5HZXRXb3Jrc3BhY2VSZXNwb25zZRJxChZMaXN0UGFja2FnZURlc2NyaXB0b3JzEioucXVpeG9zLm9yY2guTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1JlcXVlc3QaKy5xdWl4b3Mub3JjaC5MaXN0UGFja2FnZURlc2NyaXB0b3JzUmVzcG9uc2USaAoTTGlzdFBhY2thZ2VSdW50aW1lcxInLnF1aXhvcy5vcmNoLkxpc3RQYWNrYWdlUnVudGltZXNSZXF1ZXN0GigucXVpeG9zLm9yY2guTGlzdFBhY2thZ2VSdW50aW1lc1Jlc3BvbnNlElwKD0xpc3RBY3RpdmF0aW9ucxIjLnF1aXhvcy5vcmNoLkxpc3RBY3RpdmF0aW9uc1JlcXVlc3QaJC5xdWl4b3Mub3JjaC5MaXN0QWN0aXZhdGlvbnNSZXNwb25zZRJcCg9DbG9zZUFjdGl2YXRpb24SIy5xdWl4b3Mub3JjaC5DbG9zZUFjdGl2YXRpb25SZXF1ZXN0GiQucXVpeG9zLm9yY2guQ2xvc2VBY3RpdmF0aW9uUmVzcG9uc2ViBnByb3RvMw", [file_camino_api, file_quixos_package, file_quixos_refs, file_quixos_runtime]); fileDesc("ChFxdWl4b3Mvb3JjaC5wcm90bxILcXVpeG9zLm9yY2gipQEKFkNvbnN0cnVjdE9iamVjdFJlcXVlc3QSDwoHYXRvbV9pZBgBIAEoCRI9CgVpbnB1dBgCIAMoCzIuLnF1aXhvcy5vcmNoLkNvbnN0cnVjdE9iamVjdFJlcXVlc3QuSW5wdXRFbnRyeRo7CgpJbnB1dEVudHJ5EgsKA2tleRgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZToCOAEiPwoXQ29uc3RydWN0T2JqZWN0UmVzcG9uc2USJAoGb2JqZWN0GAEgASgLMhQuY2FtaW5vLkNhbWlub09iamVjdCJtCiZSZXNvbHZlT3JDb25zdHJ1Y3RSZWxhdGVkT2JqZWN0UmVxdWVzdBIRCglvYmplY3RfaWQYASABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAIgASgJEhEKCW1lbWJlcl9pZBgDIAEoCSJkCidSZXNvbHZlT3JDb25zdHJ1Y3RSZWxhdGVkT2JqZWN0UmVzcG9uc2USJAoGb2JqZWN0GAEgASgLMhQuY2FtaW5vLkNhbWlub09iamVjdBITCgtjb25zdHJ1Y3RlZBgCIAEoCCLwAQoXSW52b2tlQ2FwYWJpbGl0eVJlcXVlc3QSKQoKY2FwYWJpbGl0eRgBIAEoCzIVLnF1aXhvcy5DYXBhYmlsaXR5UmVmEhEKCW9iamVjdF9pZBgCIAEoCRI+CgVpbnB1dBgDIAMoCzIvLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXF1ZXN0LklucHV0RW50cnkSGgoSY2xpZW50X211dGF0aW9uX2lkGAQgASgJGjsKCklucHV0RW50cnkSCwoDa2V5GAEgASgJEhwKBXZhbHVlGAIgASgLMg0uY2FtaW5vLlZhbHVlOgI4ASLRAQoYSW52b2tlQ2FwYWJpbGl0eVJlc3BvbnNlEhUKDWludm9jYXRpb25faWQYASABKAkSKwoKYWN0aXZhdGlvbhgCIAEoCzIXLnF1aXhvcy5vcmNoLkFjdGl2YXRpb24SCgoCb2sYAyABKAgSHQoGcmVzdWx0GAQgASgLMg0uY2FtaW5vLlZhbHVlEg0KBWVycm9yGAUgASgJEjcKDGRlcGVuZGVuY2llcxgGIAMoCzIhLnF1aXhvcy5ydW50aW1lLkRlcml2ZWREZXBlbmRlbmN5ItIBChZXYXRjaENhcGFiaWxpdHlSZXF1ZXN0EikKCmNhcGFiaWxpdHkYASABKAsyFS5xdWl4b3MuQ2FwYWJpbGl0eVJlZhIRCglvYmplY3RfaWQYAiABKAkSPQoFaW5wdXQYAyADKAsyLi5xdWl4b3Mub3JjaC5XYXRjaENhcGFiaWxpdHlSZXF1ZXN0LklucHV0RW50cnkaOwoKSW5wdXRFbnRyeRILCgNrZXkYASABKAkSHAoFdmFsdWUYAiABKAsyDS5jYW1pbm8uVmFsdWU6AjgBIuMBChRXYXRjaENhcGFiaWxpdHlFdmVudBIVCg1pbnZvY2F0aW9uX2lkGAEgASgJEisKCmFjdGl2YXRpb24YAiABKAsyFy5xdWl4b3Mub3JjaC5BY3RpdmF0aW9uEhAKCHdhdGNoX2lkGAMgASgJEhwKBXZhbHVlGAQgASgLMg0uY2FtaW5vLlZhbHVlEjcKDGRlcGVuZGVuY2llcxgFIAMoCzIhLnF1aXhvcy5ydW50aW1lLkRlcml2ZWREZXBlbmRlbmN5Eg0KBWVycm9yGAYgASgJEg8KB2luaXRpYWwYByABKAgiFQoTR2V0V29ya3NwYWNlUmVxdWVzdCJnChRHZXRXb3Jrc3BhY2VSZXNwb25zZRIUCgx3b3Jrc3BhY2VfaWQYASABKAkSHQoVd29ya3NwYWNlX3JldmlzaW9uX2lkGAIgASgJEhoKEnNvdXJjZV9yb290X2NvbW1pdBgDIAEoCSIYChZMaXN0QWN0aXZhdGlvbnNSZXF1ZXN0Ih8KHUxpc3RQYWNrYWdlRGVzY3JpcHRvcnNSZXF1ZXN0IlAKHkxpc3RQYWNrYWdlRGVzY3JpcHRvcnNSZXNwb25zZRIuCgtkZXNjcmlwdG9ycxgBIAMoCzIZLnF1aXhvcy5QYWNrYWdlRGVzY3JpcHRvciIcChpMaXN0UGFja2FnZVJ1bnRpbWVzUmVxdWVzdCJSChtMaXN0UGFja2FnZVJ1bnRpbWVzUmVzcG9uc2USMwoIcnVudGltZXMYASADKAsyIS5xdWl4b3Mub3JjaC5QYWNrYWdlUnVudGltZVN0YXR1cyJHChdMaXN0QWN0aXZhdGlvbnNSZXNwb25zZRIsCgthY3RpdmF0aW9ucxgBIAMoCzIXLnF1aXhvcy5vcmNoLkFjdGl2YXRpb24iPwoWQ2xvc2VBY3RpdmF0aW9uUmVxdWVzdBIVCg1hY3RpdmF0aW9uX2lkGAEgASgJEg4KBnJlYXNvbhgCIAEoCSJGChdDbG9zZUFjdGl2YXRpb25SZXNwb25zZRIrCgphY3RpdmF0aW9uGAEgASgLMhcucXVpeG9zLm9yY2guQWN0aXZhdGlvbiLrAQoKQWN0aXZhdGlvbhIVCg1hY3RpdmF0aW9uX2lkGAEgASgJEigKBmV4cG9ydBgCIAEoCzIYLnF1aXhvcy5QYWNrYWdlRXhwb3J0UmVmEhEKCW9iamVjdF9pZBgDIAEoCRINCgVzdGF0ZRgEIAEoCRIOCgZkZW1hbmQYBSABKA0SEQoJb3BlbmVkX2F0GAYgASgJEhQKDGxhc3RfdXNlZF9hdBgHIAEoCRIYChBpZGxlX2RlYWRsaW5lX2F0GAggASgJEhEKCWNsb3NlZF9hdBgJIAEoCRIUCgxjbG9zZV9yZWFzb24YCiABKAkiswIKFFBhY2thZ2VSdW50aW1lU3RhdHVzEhMKC3J1bnRpbWVfa2V5GAEgASgJEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYAiABKAkSGQoRc291cmNlX3JlcG9zaXRvcnkYAyABKAkSFQoNc291cmNlX2NvbW1pdBgEIAEoCRIUCgxidWlsZF90YXJnZXQYBSABKAkSEwoLc2VydmVyX3BhdGgYBiABKAkSCwoDcGlkGAcgASgNEg0KBXN0YXRlGAggASgJEhIKCnN0YXJ0ZWRfYXQYCSABKAkSGQoRbGFzdF9oYW5kc2hha2VfYXQYCiABKAkSIAoYcnVudGltZV9wcm90b2NvbF92ZXJzaW9uGAsgASgJEh8KF2FkdmVydGlzZWRfZXhwb3J0X2NvdW50GAwgASgNMq4HChNPcmNoZXN0cmF0b3JSdW50aW1lEl8KEEludm9rZUNhcGFiaWxpdHkSJC5xdWl4b3Mub3JjaC5JbnZva2VDYXBhYmlsaXR5UmVxdWVzdBolLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXNwb25zZRJbCg9XYXRjaENhcGFiaWxpdHkSIy5xdWl4b3Mub3JjaC5XYXRjaENhcGFiaWxpdHlSZXF1ZXN0GiEucXVpeG9zLm9yY2guV2F0Y2hDYXBhYmlsaXR5RXZlbnQwARJcCg9Db25zdHJ1Y3RPYmplY3QSIy5xdWl4b3Mub3JjaC5Db25zdHJ1Y3RPYmplY3RSZXF1ZXN0GiQucXVpeG9zLm9yY2guQ29uc3RydWN0T2JqZWN0UmVzcG9uc2USjAEKH1Jlc29sdmVPckNvbnN0cnVjdFJlbGF0ZWRPYmplY3QSMy5xdWl4b3Mub3JjaC5SZXNvbHZlT3JDb25zdHJ1Y3RSZWxhdGVkT2JqZWN0UmVxdWVzdBo0LnF1aXhvcy5vcmNoLlJlc29sdmVPckNvbnN0cnVjdFJlbGF0ZWRPYmplY3RSZXNwb25zZRJTCgxHZXRXb3Jrc3BhY2USIC5xdWl4b3Mub3JjaC5HZXRXb3Jrc3BhY2VSZXF1ZXN0GiEucXVpeG9zLm9yY2guR2V0V29ya3NwYWNlUmVzcG9uc2UScQoWTGlzdFBhY2thZ2VEZXNjcmlwdG9ycxIqLnF1aXhvcy5vcmNoLkxpc3RQYWNrYWdlRGVzY3JpcHRvcnNSZXF1ZXN0GisucXVpeG9zLm9yY2guTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1Jlc3BvbnNlEmgKE0xpc3RQYWNrYWdlUnVudGltZXMSJy5xdWl4b3Mub3JjaC5MaXN0UGFja2FnZVJ1bnRpbWVzUmVxdWVzdBooLnF1aXhvcy5vcmNoLkxpc3RQYWNrYWdlUnVudGltZXNSZXNwb25zZRJcCg9MaXN0QWN0aXZhdGlvbnMSIy5xdWl4b3Mub3JjaC5MaXN0QWN0aXZhdGlvbnNSZXF1ZXN0GiQucXVpeG9zLm9yY2guTGlzdEFjdGl2YXRpb25zUmVzcG9uc2USXAoPQ2xvc2VBY3RpdmF0aW9uEiMucXVpeG9zLm9yY2guQ2xvc2VBY3RpdmF0aW9uUmVxdWVzdBokLnF1aXhvcy5vcmNoLkNsb3NlQWN0aXZhdGlvblJlc3BvbnNlYgZwcm90bzM", [file_camino_api, file_quixos_package, file_quixos_refs, file_quixos_runtime]);
/** /**
* @generated from message quixos.orch.ConstructObjectRequest * @generated from message quixos.orch.ConstructObjectRequest
@@ -126,6 +126,14 @@ export type InvokeCapabilityRequest = Message<"quixos.orch.InvokeCapabilityReque
* @generated from field: map<string, camino.Value> input = 3; * @generated from field: map<string, camino.Value> input = 3;
*/ */
input: { [key: string]: Value }; input: { [key: string]: Value };
/**
* Identifies one logical client mutation across the capability and Camino
* layers so a live-value controller can recognize its own confirmation.
*
* @generated from field: string client_mutation_id = 4;
*/
clientMutationId: string;
}; };
/** /**
@@ -163,6 +171,11 @@ export type InvokeCapabilityResponse = Message<"quixos.orch.InvokeCapabilityResp
* @generated from field: string error = 5; * @generated from field: string error = 5;
*/ */
error: string; error: string;
/**
* @generated from field: repeated quixos.runtime.DerivedDependency dependencies = 6;
*/
dependencies: DerivedDependency[];
}; };
/** /**
+3 -3
View File
@@ -10,7 +10,7 @@ import type { Message } from "@bufbuild/protobuf";
* Describes the file quixos/refs.proto. * Describes the file quixos/refs.proto.
*/ */
export const file_quixos_refs: GenFile = /*@__PURE__*/ export const file_quixos_refs: GenFile = /*@__PURE__*/
fileDesc("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zIkQKDUNhcGFiaWxpdHlSZWYSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhQKDG9wZXJhdGlvbl9pZBgCIAEoCSJCChBQYWNrYWdlRXhwb3J0UmVmEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYASABKAkSEQoJZXhwb3J0X2lkGAIgASgJIs0BChJJbmplY3RlZERlcGVuZGVuY3kSDwoHcG9ydF9pZBgBIAEoCRIXCg1zdGF0ZV9zbG90X2lkGAIgASgJSAASJgoEZWRnZRgDIAEoCzIWLnF1aXhvcy5FZGdlRGVwZW5kZW5jeUgAEigKHnJlY2VpdmVyX2ludGVyZmFjZV9yZXZpc2lvbl9pZBgEIAEoCUgAEh0KE2NvbnN0cnVjdG9yX2F0b21faWQYBSABKAlIABIRCglvYmplY3RfaWQYBiABKAlCCQoHYmluZGluZyI9Cg5FZGdlRGVwZW5kZW5jeRIUCgxlZGdlX3R5cGVfaWQYASABKAkSFQoNcHJvamVjdGlvbl9pZBgCIAEoCWIGcHJvdG8z"); fileDesc("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zIkQKDUNhcGFiaWxpdHlSZWYSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhQKDG9wZXJhdGlvbl9pZBgCIAEoCSJCChBQYWNrYWdlRXhwb3J0UmVmEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYASABKAkSEQoJZXhwb3J0X2lkGAIgASgJIsQBChJJbmplY3RlZERlcGVuZGVuY3kSDwoHcG9ydF9pZBgBIAEoCRIXCg1zdGF0ZV9zbG90X2lkGAIgASgJSAASJgoEZWRnZRgDIAEoCzIWLnF1aXhvcy5FZGdlRGVwZW5kZW5jeUgAEh8KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgEIAEoCUgAEh0KE2NvbnN0cnVjdG9yX2F0b21faWQYBSABKAlIABIRCglvYmplY3RfaWQYBiABKAlCCQoHYmluZGluZyI9Cg5FZGdlRGVwZW5kZW5jeRIUCgxlZGdlX3R5cGVfaWQYASABKAkSFQoNcHJvamVjdGlvbl9pZBgCIAEoCWIGcHJvdG8z");
/** /**
* @generated from message quixos.CapabilityRef * @generated from message quixos.CapabilityRef
@@ -82,10 +82,10 @@ export type InjectedDependency = Message<"quixos.InjectedDependency"> & {
case: "edge"; case: "edge";
} | { } | {
/** /**
* @generated from field: string receiver_interface_revision_id = 4; * @generated from field: string interface_revision_id = 4;
*/ */
value: string; value: string;
case: "receiverInterfaceRevisionId"; case: "interfaceRevisionId";
} | { } | {
/** /**
* @generated from field: string constructor_atom_id = 5; * @generated from field: string constructor_atom_id = 5;
+6 -1
View File
@@ -14,7 +14,7 @@ import type { Message } from "@bufbuild/protobuf";
* Describes the file quixos/runtime.proto. * Describes the file quixos/runtime.proto.
*/ */
export const file_quixos_runtime: GenFile = /*@__PURE__*/ export const file_quixos_runtime: GenFile = /*@__PURE__*/
fileDesc("ChRxdWl4b3MvcnVudGltZS5wcm90bxIOcXVpeG9zLnJ1bnRpbWUiMQoQSGFuZHNoYWtlUmVxdWVzdBIdChVvcmNoX3Byb3RvY29sX3ZlcnNpb24YASABKAkiZgoRSGFuZHNoYWtlUmVzcG9uc2USGwoTcGFja2FnZV9yZXZpc2lvbl9pZBgBIAEoCRIgChhydW50aW1lX3Byb3RvY29sX3ZlcnNpb24YAiABKAkSEgoKZXhwb3J0X2lkcxgDIAMoCSKLAgoNSW52b2tlUmVxdWVzdBIVCg1pbnZvY2F0aW9uX2lkGAEgASgJEigKBmV4cG9ydBgCIAEoCzIYLnF1aXhvcy5QYWNrYWdlRXhwb3J0UmVmEhEKCW9iamVjdF9pZBgDIAEoCRI3CgVpbnB1dBgEIAMoCzIoLnF1aXhvcy5ydW50aW1lLkludm9rZVJlcXVlc3QuSW5wdXRFbnRyeRIwCgxkZXBlbmRlbmNpZXMYBSADKAsyGi5xdWl4b3MuSW5qZWN0ZWREZXBlbmRlbmN5GjsKCklucHV0RW50cnkSCwoDa2V5GAEgASgJEhwKBXZhbHVlGAIgASgLMg0uY2FtaW5vLlZhbHVlOgI4ASJKCg5JbnZva2VSZXNwb25zZRIKCgJvaxgBIAEoCBIdCgZyZXN1bHQYAiABKAsyDS5jYW1pbm8uVmFsdWUSDQoFZXJyb3IYAyABKAkiiQIKDFdhdGNoUmVxdWVzdBIVCg1pbnZvY2F0aW9uX2lkGAEgASgJEigKBmV4cG9ydBgCIAEoCzIYLnF1aXhvcy5QYWNrYWdlRXhwb3J0UmVmEhEKCW9iamVjdF9pZBgDIAEoCRI2CgVpbnB1dBgEIAMoCzInLnF1aXhvcy5ydW50aW1lLldhdGNoUmVxdWVzdC5JbnB1dEVudHJ5EjAKDGRlcGVuZGVuY2llcxgFIAMoCzIaLnF1aXhvcy5JbmplY3RlZERlcGVuZGVuY3kaOwoKSW5wdXRFbnRyeRILCgNrZXkYASABKAkSHAoFdmFsdWUYAiABKAsyDS5jYW1pbm8uVmFsdWU6AjgBImIKEURlcml2ZWREZXBlbmRlbmN5EgwKBGtpbmQYASABKAkSEQoJb2JqZWN0X2lkGAIgASgJEhUKDWF0dGFjaG1lbnRfaWQYAyABKAkSFQoNcHJvamVjdGlvbl9pZBgEIAEoCSKVAQoKV2F0Y2hFdmVudBIQCgh3YXRjaF9pZBgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZRI3CgxkZXBlbmRlbmNpZXMYAyADKAsyIS5xdWl4b3MucnVudGltZS5EZXJpdmVkRGVwZW5kZW5jeRINCgVlcnJvchgEIAEoCRIPCgdpbml0aWFsGAUgASgIMvABCg5QYWNrYWdlUnVudGltZRJQCglIYW5kc2hha2USIC5xdWl4b3MucnVudGltZS5IYW5kc2hha2VSZXF1ZXN0GiEucXVpeG9zLnJ1bnRpbWUuSGFuZHNoYWtlUmVzcG9uc2USRwoGSW52b2tlEh0ucXVpeG9zLnJ1bnRpbWUuSW52b2tlUmVxdWVzdBoeLnF1aXhvcy5ydW50aW1lLkludm9rZVJlc3BvbnNlEkMKBVdhdGNoEhwucXVpeG9zLnJ1bnRpbWUuV2F0Y2hSZXF1ZXN0GhoucXVpeG9zLnJ1bnRpbWUuV2F0Y2hFdmVudDABYgZwcm90bzM", [file_camino_api, file_quixos_refs]); fileDesc("ChRxdWl4b3MvcnVudGltZS5wcm90bxIOcXVpeG9zLnJ1bnRpbWUiMQoQSGFuZHNoYWtlUmVxdWVzdBIdChVvcmNoX3Byb3RvY29sX3ZlcnNpb24YASABKAkiZgoRSGFuZHNoYWtlUmVzcG9uc2USGwoTcGFja2FnZV9yZXZpc2lvbl9pZBgBIAEoCRIgChhydW50aW1lX3Byb3RvY29sX3ZlcnNpb24YAiABKAkSEgoKZXhwb3J0X2lkcxgDIAMoCSKLAgoNSW52b2tlUmVxdWVzdBIVCg1pbnZvY2F0aW9uX2lkGAEgASgJEigKBmV4cG9ydBgCIAEoCzIYLnF1aXhvcy5QYWNrYWdlRXhwb3J0UmVmEhEKCW9iamVjdF9pZBgDIAEoCRI3CgVpbnB1dBgEIAMoCzIoLnF1aXhvcy5ydW50aW1lLkludm9rZVJlcXVlc3QuSW5wdXRFbnRyeRIwCgxkZXBlbmRlbmNpZXMYBSADKAsyGi5xdWl4b3MuSW5qZWN0ZWREZXBlbmRlbmN5GjsKCklucHV0RW50cnkSCwoDa2V5GAEgASgJEhwKBXZhbHVlGAIgASgLMg0uY2FtaW5vLlZhbHVlOgI4ASKDAQoOSW52b2tlUmVzcG9uc2USCgoCb2sYASABKAgSHQoGcmVzdWx0GAIgASgLMg0uY2FtaW5vLlZhbHVlEg0KBWVycm9yGAMgASgJEjcKDGRlcGVuZGVuY2llcxgEIAMoCzIhLnF1aXhvcy5ydW50aW1lLkRlcml2ZWREZXBlbmRlbmN5IokCCgxXYXRjaFJlcXVlc3QSFQoNaW52b2NhdGlvbl9pZBgBIAEoCRIoCgZleHBvcnQYAiABKAsyGC5xdWl4b3MuUGFja2FnZUV4cG9ydFJlZhIRCglvYmplY3RfaWQYAyABKAkSNgoFaW5wdXQYBCADKAsyJy5xdWl4b3MucnVudGltZS5XYXRjaFJlcXVlc3QuSW5wdXRFbnRyeRIwCgxkZXBlbmRlbmNpZXMYBSADKAsyGi5xdWl4b3MuSW5qZWN0ZWREZXBlbmRlbmN5GjsKCklucHV0RW50cnkSCwoDa2V5GAEgASgJEhwKBXZhbHVlGAIgASgLMg0uY2FtaW5vLlZhbHVlOgI4ASJiChFEZXJpdmVkRGVwZW5kZW5jeRIMCgRraW5kGAEgASgJEhEKCW9iamVjdF9pZBgCIAEoCRIVCg1hdHRhY2htZW50X2lkGAMgASgJEhUKDXByb2plY3Rpb25faWQYBCABKAkilQEKCldhdGNoRXZlbnQSEAoId2F0Y2hfaWQYASABKAkSHAoFdmFsdWUYAiABKAsyDS5jYW1pbm8uVmFsdWUSNwoMZGVwZW5kZW5jaWVzGAMgAygLMiEucXVpeG9zLnJ1bnRpbWUuRGVyaXZlZERlcGVuZGVuY3kSDQoFZXJyb3IYBCABKAkSDwoHaW5pdGlhbBgFIAEoCDLwAQoOUGFja2FnZVJ1bnRpbWUSUAoJSGFuZHNoYWtlEiAucXVpeG9zLnJ1bnRpbWUuSGFuZHNoYWtlUmVxdWVzdBohLnF1aXhvcy5ydW50aW1lLkhhbmRzaGFrZVJlc3BvbnNlEkcKBkludm9rZRIdLnF1aXhvcy5ydW50aW1lLkludm9rZVJlcXVlc3QaHi5xdWl4b3MucnVudGltZS5JbnZva2VSZXNwb25zZRJDCgVXYXRjaBIcLnF1aXhvcy5ydW50aW1lLldhdGNoUmVxdWVzdBoaLnF1aXhvcy5ydW50aW1lLldhdGNoRXZlbnQwAWIGcHJvdG8z", [file_camino_api, file_quixos_refs]);
/** /**
* @generated from message quixos.runtime.HandshakeRequest * @generated from message quixos.runtime.HandshakeRequest
@@ -115,6 +115,11 @@ export type InvokeResponse = Message<"quixos.runtime.InvokeResponse"> & {
* @generated from field: string error = 3; * @generated from field: string error = 3;
*/ */
error: string; error: string;
/**
* @generated from field: repeated quixos.runtime.DerivedDependency dependencies = 4;
*/
dependencies: DerivedDependency[];
}; };
/** /**
+2 -3
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env node #!/usr/bin/env node
import { readFile } from "node:fs/promises"; import { loadQuixosLock } from "./loader.js";
import { parseQuixosLock } from "./parser.js";
const fileName = process.argv[2]; const fileName = process.argv[2];
if (!fileName || process.argv.length !== 3) { if (!fileName || process.argv.length !== 3) {
@@ -8,7 +7,7 @@ if (!fileName || process.argv.length !== 3) {
process.exit(2); process.exit(2);
} }
const result = parseQuixosLock(await readFile(fileName, "utf8"), fileName); const result = await loadQuixosLock(fileName);
if (!result.ok) { if (!result.ok) {
for (const diagnostic of result.diagnostics) { for (const diagnostic of result.diagnostics) {
console.error( console.error(
@@ -1,6 +1,7 @@
token literal names: token literal names:
null null
'quixos-lock' 'quixos-lock'
'fragment'
'version' 'version'
'quixos' 'quixos'
'source' 'source'
@@ -8,6 +9,7 @@ null
'package' 'package'
'repository' 'repository'
'commit' 'commit'
'import'
'{' '{'
'}' '}'
';' ';'
@@ -21,6 +23,7 @@ null
token symbolic names: token symbolic names:
null null
QUIXOS_LOCK QUIXOS_LOCK
FRAGMENT
VERSION VERSION
QUIXOS QUIXOS
SOURCE SOURCE
@@ -28,6 +31,7 @@ INTERFACE
PACKAGE PACKAGE
REPOSITORY REPOSITORY
COMMIT COMMIT
IMPORT
LBRACE LBRACE
RBRACE RBRACE
SEMI SEMI
@@ -42,6 +46,7 @@ rule names:
document document
quixosEntry quixosEntry
resourceEntry resourceEntry
importEntry
resourceKind resourceKind
sourceBlock sourceBlock
identifier identifier
@@ -49,4 +54,4 @@ stringLiteral
atn: atn:
[4, 1, 17, 53, 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, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 21, 8, 0, 10, 0, 12, 0, 24, 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, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 0, 0, 7, 0, 2, 4, 6, 8, 10, 12, 0, 1, 1, 0, 5, 6, 46, 0, 14, 1, 0, 0, 0, 2, 28, 1, 0, 0, 0, 4, 32, 1, 0, 0, 0, 6, 37, 1, 0, 0, 0, 8, 39, 1, 0, 0, 0, 10, 48, 1, 0, 0, 0, 12, 50, 1, 0, 0, 0, 14, 15, 5, 1, 0, 0, 15, 16, 5, 2, 0, 0, 16, 17, 5, 12, 0, 0, 17, 18, 5, 9, 0, 0, 18, 22, 3, 2, 1, 0, 19, 21, 3, 4, 2, 0, 20, 19, 1, 0, 0, 0, 21, 24, 1, 0, 0, 0, 22, 20, 1, 0, 0, 0, 22, 23, 1, 0, 0, 0, 23, 25, 1, 0, 0, 0, 24, 22, 1, 0, 0, 0, 25, 26, 5, 10, 0, 0, 26, 27, 5, 0, 0, 1, 27, 1, 1, 0, 0, 0, 28, 29, 5, 3, 0, 0, 29, 30, 5, 4, 0, 0, 30, 31, 3, 8, 4, 0, 31, 3, 1, 0, 0, 0, 32, 33, 3, 6, 3, 0, 33, 34, 3, 10, 5, 0, 34, 35, 5, 4, 0, 0, 35, 36, 3, 8, 4, 0, 36, 5, 1, 0, 0, 0, 37, 38, 7, 0, 0, 0, 38, 7, 1, 0, 0, 0, 39, 40, 5, 9, 0, 0, 40, 41, 5, 7, 0, 0, 41, 42, 3, 12, 6, 0, 42, 43, 5, 11, 0, 0, 43, 44, 5, 8, 0, 0, 44, 45, 3, 12, 6, 0, 45, 46, 5, 11, 0, 0, 46, 47, 5, 10, 0, 0, 47, 9, 1, 0, 0, 0, 48, 49, 5, 13, 0, 0, 49, 11, 1, 0, 0, 0, 50, 51, 5, 14, 0, 0, 51, 13, 1, 0, 0, 0, 1, 22] [4, 1, 19, 63, 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, 1, 0, 1, 0, 3, 0, 19, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 27, 8, 0, 10, 0, 12, 0, 30, 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, 7, 1, 7, 1, 7, 0, 0, 8, 0, 2, 4, 6, 8, 10, 12, 14, 0, 1, 1, 0, 6, 7, 58, 0, 16, 1, 0, 0, 0, 2, 34, 1, 0, 0, 0, 4, 38, 1, 0, 0, 0, 6, 43, 1, 0, 0, 0, 8, 47, 1, 0, 0, 0, 10, 49, 1, 0, 0, 0, 12, 58, 1, 0, 0, 0, 14, 60, 1, 0, 0, 0, 16, 18, 5, 1, 0, 0, 17, 19, 5, 2, 0, 0, 18, 17, 1, 0, 0, 0, 18, 19, 1, 0, 0, 0, 19, 20, 1, 0, 0, 0, 20, 21, 5, 3, 0, 0, 21, 22, 5, 14, 0, 0, 22, 28, 5, 11, 0, 0, 23, 27, 3, 2, 1, 0, 24, 27, 3, 6, 3, 0, 25, 27, 3, 4, 2, 0, 26, 23, 1, 0, 0, 0, 26, 24, 1, 0, 0, 0, 26, 25, 1, 0, 0, 0, 27, 30, 1, 0, 0, 0, 28, 26, 1, 0, 0, 0, 28, 29, 1, 0, 0, 0, 29, 31, 1, 0, 0, 0, 30, 28, 1, 0, 0, 0, 31, 32, 5, 12, 0, 0, 32, 33, 5, 0, 0, 1, 33, 1, 1, 0, 0, 0, 34, 35, 5, 4, 0, 0, 35, 36, 5, 5, 0, 0, 36, 37, 3, 10, 5, 0, 37, 3, 1, 0, 0, 0, 38, 39, 3, 8, 4, 0, 39, 40, 3, 12, 6, 0, 40, 41, 5, 5, 0, 0, 41, 42, 3, 10, 5, 0, 42, 5, 1, 0, 0, 0, 43, 44, 5, 10, 0, 0, 44, 45, 3, 14, 7, 0, 45, 46, 5, 13, 0, 0, 46, 7, 1, 0, 0, 0, 47, 48, 7, 0, 0, 0, 48, 9, 1, 0, 0, 0, 49, 50, 5, 11, 0, 0, 50, 51, 5, 8, 0, 0, 51, 52, 3, 14, 7, 0, 52, 53, 5, 13, 0, 0, 53, 54, 5, 9, 0, 0, 54, 55, 3, 14, 7, 0, 55, 56, 5, 13, 0, 0, 56, 57, 5, 12, 0, 0, 57, 11, 1, 0, 0, 0, 58, 59, 5, 15, 0, 0, 59, 13, 1, 0, 0, 0, 60, 61, 5, 16, 0, 0, 61, 15, 1, 0, 0, 0, 3, 18, 26, 28]
+30 -26
View File
@@ -1,28 +1,32 @@
QUIXOS_LOCK=1 QUIXOS_LOCK=1
VERSION=2 FRAGMENT=2
QUIXOS=3 VERSION=3
SOURCE=4 QUIXOS=4
INTERFACE=5 SOURCE=5
PACKAGE=6 INTERFACE=6
REPOSITORY=7 PACKAGE=7
COMMIT=8 REPOSITORY=8
LBRACE=9 COMMIT=9
RBRACE=10 IMPORT=10
SEMI=11 LBRACE=11
INTEGER=12 RBRACE=12
IDENTIFIER=13 SEMI=13
STRING_LITERAL=14 INTEGER=14
LINE_COMMENT=15 IDENTIFIER=15
BLOCK_COMMENT=16 STRING_LITERAL=16
WS=17 LINE_COMMENT=17
BLOCK_COMMENT=18
WS=19
'quixos-lock'=1 'quixos-lock'=1
'version'=2 'fragment'=2
'quixos'=3 'version'=3
'source'=4 'quixos'=4
'interface'=5 'source'=5
'package'=6 'interface'=6
'repository'=7 'package'=7
'commit'=8 'repository'=8
'{'=9 'commit'=9
'}'=10 'import'=10
';'=11 '{'=11
'}'=12
';'=13
File diff suppressed because one or more lines are too long
@@ -1,28 +1,32 @@
QUIXOS_LOCK=1 QUIXOS_LOCK=1
VERSION=2 FRAGMENT=2
QUIXOS=3 VERSION=3
SOURCE=4 QUIXOS=4
INTERFACE=5 SOURCE=5
PACKAGE=6 INTERFACE=6
REPOSITORY=7 PACKAGE=7
COMMIT=8 REPOSITORY=8
LBRACE=9 COMMIT=9
RBRACE=10 IMPORT=10
SEMI=11 LBRACE=11
INTEGER=12 RBRACE=12
IDENTIFIER=13 SEMI=13
STRING_LITERAL=14 INTEGER=14
LINE_COMMENT=15 IDENTIFIER=15
BLOCK_COMMENT=16 STRING_LITERAL=16
WS=17 LINE_COMMENT=17
BLOCK_COMMENT=18
WS=19
'quixos-lock'=1 'quixos-lock'=1
'version'=2 'fragment'=2
'quixos'=3 'version'=3
'source'=4 'quixos'=4
'interface'=5 'source'=5
'package'=6 'interface'=6
'repository'=7 'package'=7
'commit'=8 'repository'=8
'{'=9 'commit'=9
'}'=10 'import'=10
';'=11 '{'=11
'}'=12
';'=13
+99 -90
View File
@@ -5,37 +5,40 @@ import { Token } from "antlr4ng";
export class QuixosLockLexer extends antlr.Lexer { export class QuixosLockLexer extends antlr.Lexer {
public static readonly QUIXOS_LOCK = 1; public static readonly QUIXOS_LOCK = 1;
public static readonly VERSION = 2; public static readonly FRAGMENT = 2;
public static readonly QUIXOS = 3; public static readonly VERSION = 3;
public static readonly SOURCE = 4; public static readonly QUIXOS = 4;
public static readonly INTERFACE = 5; public static readonly SOURCE = 5;
public static readonly PACKAGE = 6; public static readonly INTERFACE = 6;
public static readonly REPOSITORY = 7; public static readonly PACKAGE = 7;
public static readonly COMMIT = 8; public static readonly REPOSITORY = 8;
public static readonly LBRACE = 9; public static readonly COMMIT = 9;
public static readonly RBRACE = 10; public static readonly IMPORT = 10;
public static readonly SEMI = 11; public static readonly LBRACE = 11;
public static readonly INTEGER = 12; public static readonly RBRACE = 12;
public static readonly IDENTIFIER = 13; public static readonly SEMI = 13;
public static readonly STRING_LITERAL = 14; public static readonly INTEGER = 14;
public static readonly LINE_COMMENT = 15; public static readonly IDENTIFIER = 15;
public static readonly BLOCK_COMMENT = 16; public static readonly STRING_LITERAL = 16;
public static readonly WS = 17; public static readonly LINE_COMMENT = 17;
public static readonly BLOCK_COMMENT = 18;
public static readonly WS = 19;
public static readonly channelNames = [ public static readonly channelNames = [
"DEFAULT_TOKEN_CHANNEL", "HIDDEN" "DEFAULT_TOKEN_CHANNEL", "HIDDEN"
]; ];
public static readonly literalNames = [ public static readonly literalNames = [
null, "'quixos-lock'", "'version'", "'quixos'", "'source'", "'interface'", null, "'quixos-lock'", "'fragment'", "'version'", "'quixos'", "'source'",
"'package'", "'repository'", "'commit'", "'{'", "'}'", "';'" "'interface'", "'package'", "'repository'", "'commit'", "'import'",
"'{'", "'}'", "';'"
]; ];
public static readonly symbolicNames = [ public static readonly symbolicNames = [
null, "QUIXOS_LOCK", "VERSION", "QUIXOS", "SOURCE", "INTERFACE", null, "QUIXOS_LOCK", "FRAGMENT", "VERSION", "QUIXOS", "SOURCE",
"PACKAGE", "REPOSITORY", "COMMIT", "LBRACE", "RBRACE", "SEMI", "INTEGER", "INTERFACE", "PACKAGE", "REPOSITORY", "COMMIT", "IMPORT", "LBRACE",
"IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT", "BLOCK_COMMENT", "RBRACE", "SEMI", "INTEGER", "IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT",
"WS" "BLOCK_COMMENT", "WS"
]; ];
public static readonly modeNames = [ public static readonly modeNames = [
@@ -43,10 +46,10 @@ export class QuixosLockLexer extends antlr.Lexer {
]; ];
public static readonly ruleNames = [ public static readonly ruleNames = [
"QUIXOS_LOCK", "VERSION", "QUIXOS", "SOURCE", "INTERFACE", "PACKAGE", "QUIXOS_LOCK", "FRAGMENT", "VERSION", "QUIXOS", "SOURCE", "INTERFACE",
"REPOSITORY", "COMMIT", "LBRACE", "RBRACE", "SEMI", "INTEGER", "IDENTIFIER", "PACKAGE", "REPOSITORY", "COMMIT", "IMPORT", "LBRACE", "RBRACE",
"STRING_LITERAL", "ESC", "HEX", "LINE_COMMENT", "BLOCK_COMMENT", "SEMI", "INTEGER", "IDENTIFIER", "STRING_LITERAL", "ESC", "HEX",
"WS", "LINE_COMMENT", "BLOCK_COMMENT", "WS",
]; ];
@@ -68,71 +71,77 @@ 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,17,181,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,19,201,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,1,0,1, 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,
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, 19,2,20,7,20,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,2,1,2,1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,3,1,3,1,3,1,3,1, 1,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,
3,1,4,1,4,1,4,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,3,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,5,1,5,
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,1,7,1,7,1, 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,
7,1,7,1,7,1,7,1,7,1,8,1,8,1,9,1,9,1,10,1,10,1,11,4,11,117,8,11,11, 1,7,1,7,1,7,1,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,
11,12,11,118,1,12,1,12,5,12,123,8,12,10,12,12,12,126,9,12,1,13,1, 1,8,1,8,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,10,1,10,1,11,1,11,1,12,1,12,
13,1,13,5,13,131,8,13,10,13,12,13,134,9,13,1,13,1,13,1,14,1,14,1, 1,13,4,13,137,8,13,11,13,12,13,138,1,14,1,14,5,14,143,8,14,10,14,
14,1,14,1,14,1,14,1,14,1,14,3,14,146,8,14,1,15,1,15,1,16,1,16,1, 12,14,146,9,14,1,15,1,15,1,15,5,15,151,8,15,10,15,12,15,154,9,15,
16,1,16,5,16,154,8,16,10,16,12,16,157,9,16,1,16,1,16,1,17,1,17,1, 1,15,1,15,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,3,16,166,8,16,
17,1,17,5,17,165,8,17,10,17,12,17,168,9,17,1,17,1,17,1,17,1,17,1, 1,17,1,17,1,18,1,18,1,18,1,18,5,18,174,8,18,10,18,12,18,177,9,18,
17,1,18,4,18,176,8,18,11,18,12,18,177,1,18,1,18,1,166,0,19,1,1,3, 1,18,1,18,1,19,1,19,1,19,1,19,5,19,185,8,19,10,19,12,19,188,9,19,
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, 1,19,1,19,1,19,1,19,1,19,1,20,4,20,196,8,20,11,20,12,20,197,1,20,
29,0,31,0,33,15,35,16,37,17,1,0,8,1,0,48,57,3,0,65,90,95,95,97,122, 1,20,1,186,0,21,1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,
4,0,48,57,65,90,95,95,97,122,4,0,10,10,13,13,34,34,92,92,8,0,34, 11,23,12,25,13,27,14,29,15,31,16,33,0,35,0,37,17,39,18,41,19,1,0,
34,47,47,92,92,98,98,102,102,110,110,114,114,116,116,3,0,48,57,65, 8,1,0,48,57,3,0,65,90,95,95,97,122,4,0,48,57,65,90,95,95,97,122,
70,97,102,2,0,10,10,13,13,3,0,9,10,13,13,32,32,186,0,1,1,0,0,0,0, 4,0,10,10,13,13,34,34,92,92,8,0,34,34,47,47,92,92,98,98,102,102,
3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0,0,0,13, 110,110,114,114,116,116,3,0,48,57,65,70,97,102,2,0,10,10,13,13,3,
1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,23, 0,9,10,13,13,32,32,206,0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,
1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,37, 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,0,17,1,
1,0,0,0,1,39,1,0,0,0,3,51,1,0,0,0,5,59,1,0,0,0,7,66,1,0,0,0,9,73, 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,27,1,
1,0,0,0,11,83,1,0,0,0,13,91,1,0,0,0,15,102,1,0,0,0,17,109,1,0,0, 0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,
0,19,111,1,0,0,0,21,113,1,0,0,0,23,116,1,0,0,0,25,120,1,0,0,0,27, 0,0,0,1,43,1,0,0,0,3,55,1,0,0,0,5,64,1,0,0,0,7,72,1,0,0,0,9,79,1,
127,1,0,0,0,29,137,1,0,0,0,31,147,1,0,0,0,33,149,1,0,0,0,35,160, 0,0,0,11,86,1,0,0,0,13,96,1,0,0,0,15,104,1,0,0,0,17,115,1,0,0,0,
1,0,0,0,37,175,1,0,0,0,39,40,5,113,0,0,40,41,5,117,0,0,41,42,5,105, 19,122,1,0,0,0,21,129,1,0,0,0,23,131,1,0,0,0,25,133,1,0,0,0,27,136,
0,0,42,43,5,120,0,0,43,44,5,111,0,0,44,45,5,115,0,0,45,46,5,45,0, 1,0,0,0,29,140,1,0,0,0,31,147,1,0,0,0,33,157,1,0,0,0,35,167,1,0,
0,46,47,5,108,0,0,47,48,5,111,0,0,48,49,5,99,0,0,49,50,5,107,0,0, 0,0,37,169,1,0,0,0,39,180,1,0,0,0,41,195,1,0,0,0,43,44,5,113,0,0,
50,2,1,0,0,0,51,52,5,118,0,0,52,53,5,101,0,0,53,54,5,114,0,0,54, 44,45,5,117,0,0,45,46,5,105,0,0,46,47,5,120,0,0,47,48,5,111,0,0,
55,5,115,0,0,55,56,5,105,0,0,56,57,5,111,0,0,57,58,5,110,0,0,58, 48,49,5,115,0,0,49,50,5,45,0,0,50,51,5,108,0,0,51,52,5,111,0,0,52,
4,1,0,0,0,59,60,5,113,0,0,60,61,5,117,0,0,61,62,5,105,0,0,62,63, 53,5,99,0,0,53,54,5,107,0,0,54,2,1,0,0,0,55,56,5,102,0,0,56,57,5,
5,120,0,0,63,64,5,111,0,0,64,65,5,115,0,0,65,6,1,0,0,0,66,67,5,115, 114,0,0,57,58,5,97,0,0,58,59,5,103,0,0,59,60,5,109,0,0,60,61,5,101,
0,0,67,68,5,111,0,0,68,69,5,117,0,0,69,70,5,114,0,0,70,71,5,99,0, 0,0,61,62,5,110,0,0,62,63,5,116,0,0,63,4,1,0,0,0,64,65,5,118,0,0,
0,71,72,5,101,0,0,72,8,1,0,0,0,73,74,5,105,0,0,74,75,5,110,0,0,75, 65,66,5,101,0,0,66,67,5,114,0,0,67,68,5,115,0,0,68,69,5,105,0,0,
76,5,116,0,0,76,77,5,101,0,0,77,78,5,114,0,0,78,79,5,102,0,0,79, 69,70,5,111,0,0,70,71,5,110,0,0,71,6,1,0,0,0,72,73,5,113,0,0,73,
80,5,97,0,0,80,81,5,99,0,0,81,82,5,101,0,0,82,10,1,0,0,0,83,84,5, 74,5,117,0,0,74,75,5,105,0,0,75,76,5,120,0,0,76,77,5,111,0,0,77,
112,0,0,84,85,5,97,0,0,85,86,5,99,0,0,86,87,5,107,0,0,87,88,5,97, 78,5,115,0,0,78,8,1,0,0,0,79,80,5,115,0,0,80,81,5,111,0,0,81,82,
0,0,88,89,5,103,0,0,89,90,5,101,0,0,90,12,1,0,0,0,91,92,5,114,0, 5,117,0,0,82,83,5,114,0,0,83,84,5,99,0,0,84,85,5,101,0,0,85,10,1,
0,92,93,5,101,0,0,93,94,5,112,0,0,94,95,5,111,0,0,95,96,5,115,0, 0,0,0,86,87,5,105,0,0,87,88,5,110,0,0,88,89,5,116,0,0,89,90,5,101,
0,96,97,5,105,0,0,97,98,5,116,0,0,98,99,5,111,0,0,99,100,5,114,0, 0,0,90,91,5,114,0,0,91,92,5,102,0,0,92,93,5,97,0,0,93,94,5,99,0,
0,100,101,5,121,0,0,101,14,1,0,0,0,102,103,5,99,0,0,103,104,5,111, 0,94,95,5,101,0,0,95,12,1,0,0,0,96,97,5,112,0,0,97,98,5,97,0,0,98,
0,0,104,105,5,109,0,0,105,106,5,109,0,0,106,107,5,105,0,0,107,108, 99,5,99,0,0,99,100,5,107,0,0,100,101,5,97,0,0,101,102,5,103,0,0,
5,116,0,0,108,16,1,0,0,0,109,110,5,123,0,0,110,18,1,0,0,0,111,112, 102,103,5,101,0,0,103,14,1,0,0,0,104,105,5,114,0,0,105,106,5,101,
5,125,0,0,112,20,1,0,0,0,113,114,5,59,0,0,114,22,1,0,0,0,115,117, 0,0,106,107,5,112,0,0,107,108,5,111,0,0,108,109,5,115,0,0,109,110,
7,0,0,0,116,115,1,0,0,0,117,118,1,0,0,0,118,116,1,0,0,0,118,119, 5,105,0,0,110,111,5,116,0,0,111,112,5,111,0,0,112,113,5,114,0,0,
1,0,0,0,119,24,1,0,0,0,120,124,7,1,0,0,121,123,7,2,0,0,122,121,1, 113,114,5,121,0,0,114,16,1,0,0,0,115,116,5,99,0,0,116,117,5,111,
0,0,0,123,126,1,0,0,0,124,122,1,0,0,0,124,125,1,0,0,0,125,26,1,0, 0,0,117,118,5,109,0,0,118,119,5,109,0,0,119,120,5,105,0,0,120,121,
0,0,126,124,1,0,0,0,127,132,5,34,0,0,128,131,3,29,14,0,129,131,8, 5,116,0,0,121,18,1,0,0,0,122,123,5,105,0,0,123,124,5,109,0,0,124,
3,0,0,130,128,1,0,0,0,130,129,1,0,0,0,131,134,1,0,0,0,132,130,1, 125,5,112,0,0,125,126,5,111,0,0,126,127,5,114,0,0,127,128,5,116,
0,0,0,132,133,1,0,0,0,133,135,1,0,0,0,134,132,1,0,0,0,135,136,5, 0,0,128,20,1,0,0,0,129,130,5,123,0,0,130,22,1,0,0,0,131,132,5,125,
34,0,0,136,28,1,0,0,0,137,145,5,92,0,0,138,146,7,4,0,0,139,140,5, 0,0,132,24,1,0,0,0,133,134,5,59,0,0,134,26,1,0,0,0,135,137,7,0,0,
117,0,0,140,141,3,31,15,0,141,142,3,31,15,0,142,143,3,31,15,0,143, 0,136,135,1,0,0,0,137,138,1,0,0,0,138,136,1,0,0,0,138,139,1,0,0,
144,3,31,15,0,144,146,1,0,0,0,145,138,1,0,0,0,145,139,1,0,0,0,146, 0,139,28,1,0,0,0,140,144,7,1,0,0,141,143,7,2,0,0,142,141,1,0,0,0,
30,1,0,0,0,147,148,7,5,0,0,148,32,1,0,0,0,149,150,5,47,0,0,150,151, 143,146,1,0,0,0,144,142,1,0,0,0,144,145,1,0,0,0,145,30,1,0,0,0,146,
5,47,0,0,151,155,1,0,0,0,152,154,8,6,0,0,153,152,1,0,0,0,154,157, 144,1,0,0,0,147,152,5,34,0,0,148,151,3,33,16,0,149,151,8,3,0,0,150,
1,0,0,0,155,153,1,0,0,0,155,156,1,0,0,0,156,158,1,0,0,0,157,155, 148,1,0,0,0,150,149,1,0,0,0,151,154,1,0,0,0,152,150,1,0,0,0,152,
1,0,0,0,158,159,6,16,0,0,159,34,1,0,0,0,160,161,5,47,0,0,161,162, 153,1,0,0,0,153,155,1,0,0,0,154,152,1,0,0,0,155,156,5,34,0,0,156,
5,42,0,0,162,166,1,0,0,0,163,165,9,0,0,0,164,163,1,0,0,0,165,168, 32,1,0,0,0,157,165,5,92,0,0,158,166,7,4,0,0,159,160,5,117,0,0,160,
1,0,0,0,166,167,1,0,0,0,166,164,1,0,0,0,167,169,1,0,0,0,168,166, 161,3,35,17,0,161,162,3,35,17,0,162,163,3,35,17,0,163,164,3,35,17,
1,0,0,0,169,170,5,42,0,0,170,171,5,47,0,0,171,172,1,0,0,0,172,173, 0,164,166,1,0,0,0,165,158,1,0,0,0,165,159,1,0,0,0,166,34,1,0,0,0,
6,17,0,0,173,36,1,0,0,0,174,176,7,7,0,0,175,174,1,0,0,0,176,177, 167,168,7,5,0,0,168,36,1,0,0,0,169,170,5,47,0,0,170,171,5,47,0,0,
1,0,0,0,177,175,1,0,0,0,177,178,1,0,0,0,178,179,1,0,0,0,179,180, 171,175,1,0,0,0,172,174,8,6,0,0,173,172,1,0,0,0,174,177,1,0,0,0,
6,18,0,0,180,38,1,0,0,0,9,0,118,124,130,132,145,155,166,177,1,6, 175,173,1,0,0,0,175,176,1,0,0,0,176,178,1,0,0,0,177,175,1,0,0,0,
0,0 178,179,6,18,0,0,179,38,1,0,0,0,180,181,5,47,0,0,181,182,5,42,0,
0,182,186,1,0,0,0,183,185,9,0,0,0,184,183,1,0,0,0,185,188,1,0,0,
0,186,187,1,0,0,0,186,184,1,0,0,0,187,189,1,0,0,0,188,186,1,0,0,
0,189,190,5,42,0,0,190,191,5,47,0,0,191,192,1,0,0,0,192,193,6,19,
0,0,193,40,1,0,0,0,194,196,7,7,0,0,195,194,1,0,0,0,196,197,1,0,0,
0,197,195,1,0,0,0,197,198,1,0,0,0,198,199,1,0,0,0,199,200,6,20,0,
0,200,42,1,0,0,0,9,0,138,144,150,152,165,175,186,197,1,6,0,0
]; ];
private static __ATN: antlr.ATN; private static __ATN: antlr.ATN;
+191 -84
View File
@@ -11,44 +11,48 @@ type int = number;
export class QuixosLockParser extends antlr.Parser { export class QuixosLockParser extends antlr.Parser {
public static readonly QUIXOS_LOCK = 1; public static readonly QUIXOS_LOCK = 1;
public static readonly VERSION = 2; public static readonly FRAGMENT = 2;
public static readonly QUIXOS = 3; public static readonly VERSION = 3;
public static readonly SOURCE = 4; public static readonly QUIXOS = 4;
public static readonly INTERFACE = 5; public static readonly SOURCE = 5;
public static readonly PACKAGE = 6; public static readonly INTERFACE = 6;
public static readonly REPOSITORY = 7; public static readonly PACKAGE = 7;
public static readonly COMMIT = 8; public static readonly REPOSITORY = 8;
public static readonly LBRACE = 9; public static readonly COMMIT = 9;
public static readonly RBRACE = 10; public static readonly IMPORT = 10;
public static readonly SEMI = 11; public static readonly LBRACE = 11;
public static readonly INTEGER = 12; public static readonly RBRACE = 12;
public static readonly IDENTIFIER = 13; public static readonly SEMI = 13;
public static readonly STRING_LITERAL = 14; public static readonly INTEGER = 14;
public static readonly LINE_COMMENT = 15; public static readonly IDENTIFIER = 15;
public static readonly BLOCK_COMMENT = 16; public static readonly STRING_LITERAL = 16;
public static readonly WS = 17; public static readonly LINE_COMMENT = 17;
public static readonly BLOCK_COMMENT = 18;
public static readonly WS = 19;
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;
public static readonly RULE_resourceKind = 3; public static readonly RULE_importEntry = 3;
public static readonly RULE_sourceBlock = 4; public static readonly RULE_resourceKind = 4;
public static readonly RULE_identifier = 5; public static readonly RULE_sourceBlock = 5;
public static readonly RULE_stringLiteral = 6; public static readonly RULE_identifier = 6;
public static readonly RULE_stringLiteral = 7;
public static readonly literalNames = [ public static readonly literalNames = [
null, "'quixos-lock'", "'version'", "'quixos'", "'source'", "'interface'", null, "'quixos-lock'", "'fragment'", "'version'", "'quixos'", "'source'",
"'package'", "'repository'", "'commit'", "'{'", "'}'", "';'" "'interface'", "'package'", "'repository'", "'commit'", "'import'",
"'{'", "'}'", "';'"
]; ];
public static readonly symbolicNames = [ public static readonly symbolicNames = [
null, "QUIXOS_LOCK", "VERSION", "QUIXOS", "SOURCE", "INTERFACE", null, "QUIXOS_LOCK", "FRAGMENT", "VERSION", "QUIXOS", "SOURCE",
"PACKAGE", "REPOSITORY", "COMMIT", "LBRACE", "RBRACE", "SEMI", "INTEGER", "INTERFACE", "PACKAGE", "REPOSITORY", "COMMIT", "IMPORT", "LBRACE",
"IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT", "BLOCK_COMMENT", "RBRACE", "SEMI", "INTEGER", "IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT",
"WS" "BLOCK_COMMENT", "WS"
]; ];
public static readonly ruleNames = [ public static readonly ruleNames = [
"document", "quixosEntry", "resourceEntry", "resourceKind", "sourceBlock", "document", "quixosEntry", "resourceEntry", "importEntry", "resourceKind",
"identifier", "stringLiteral", "sourceBlock", "identifier", "stringLiteral",
]; ];
public get grammarFileName(): string { return "QuixosLock.g4"; } public get grammarFileName(): string { return "QuixosLock.g4"; }
@@ -72,33 +76,62 @@ export class QuixosLockParser extends antlr.Parser {
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 14;
this.match(QuixosLockParser.QUIXOS_LOCK);
this.state = 15;
this.match(QuixosLockParser.VERSION);
this.state = 16; this.state = 16;
this.match(QuixosLockParser.INTEGER); this.match(QuixosLockParser.QUIXOS_LOCK);
this.state = 17;
this.match(QuixosLockParser.LBRACE);
this.state = 18; this.state = 18;
this.quixosEntry();
this.state = 22;
this.errorHandler.sync(this); this.errorHandler.sync(this);
_la = this.tokenStream.LA(1); _la = this.tokenStream.LA(1);
while (_la === 5 || _la === 6) { if (_la === 2) {
{ {
this.state = 17;
this.match(QuixosLockParser.FRAGMENT);
}
}
this.state = 20;
this.match(QuixosLockParser.VERSION);
this.state = 21;
this.match(QuixosLockParser.INTEGER);
this.state = 22;
this.match(QuixosLockParser.LBRACE);
this.state = 28;
this.errorHandler.sync(this);
_la = this.tokenStream.LA(1);
while ((((_la) & ~0x1F) === 0 && ((1 << _la) & 1232) !== 0)) {
{ {
this.state = 19; this.state = 26;
this.resourceEntry(); this.errorHandler.sync(this);
switch (this.tokenStream.LA(1)) {
case QuixosLockParser.QUIXOS:
{
this.state = 23;
this.quixosEntry();
}
break;
case QuixosLockParser.IMPORT:
{
this.state = 24;
this.importEntry();
}
break;
case QuixosLockParser.INTERFACE:
case QuixosLockParser.PACKAGE:
{
this.state = 25;
this.resourceEntry();
}
break;
default:
throw new antlr.NoViableAltException(this);
} }
} }
this.state = 24; this.state = 30;
this.errorHandler.sync(this); this.errorHandler.sync(this);
_la = this.tokenStream.LA(1); _la = this.tokenStream.LA(1);
} }
this.state = 25; this.state = 31;
this.match(QuixosLockParser.RBRACE); this.match(QuixosLockParser.RBRACE);
this.state = 26; this.state = 32;
this.match(QuixosLockParser.EOF); this.match(QuixosLockParser.EOF);
} }
} }
@@ -121,11 +154,11 @@ export class QuixosLockParser extends antlr.Parser {
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 28; this.state = 34;
this.match(QuixosLockParser.QUIXOS); this.match(QuixosLockParser.QUIXOS);
this.state = 29; this.state = 35;
this.match(QuixosLockParser.SOURCE); this.match(QuixosLockParser.SOURCE);
this.state = 30; this.state = 36;
this.sourceBlock(); this.sourceBlock();
} }
} }
@@ -148,13 +181,13 @@ export class QuixosLockParser extends antlr.Parser {
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 32; this.state = 38;
this.resourceKind(); this.resourceKind();
this.state = 33; this.state = 39;
this.identifier(); this.identifier();
this.state = 34; this.state = 40;
this.match(QuixosLockParser.SOURCE); this.match(QuixosLockParser.SOURCE);
this.state = 35; this.state = 41;
this.sourceBlock(); this.sourceBlock();
} }
} }
@@ -171,16 +204,43 @@ export class QuixosLockParser extends antlr.Parser {
} }
return localContext; return localContext;
} }
public importEntry(): ImportEntryContext {
let localContext = new ImportEntryContext(this.context, this.state);
this.enterRule(localContext, 6, QuixosLockParser.RULE_importEntry);
try {
this.enterOuterAlt(localContext, 1);
{
this.state = 43;
this.match(QuixosLockParser.IMPORT);
this.state = 44;
this.stringLiteral();
this.state = 45;
this.match(QuixosLockParser.SEMI);
}
}
catch (re) {
if (re instanceof antlr.RecognitionException) {
this.errorHandler.reportError(this, re);
this.errorHandler.recover(this, re);
} else {
throw re;
}
}
finally {
this.exitRule();
}
return localContext;
}
public resourceKind(): ResourceKindContext { public resourceKind(): ResourceKindContext {
let localContext = new ResourceKindContext(this.context, this.state); let localContext = new ResourceKindContext(this.context, this.state);
this.enterRule(localContext, 6, QuixosLockParser.RULE_resourceKind); this.enterRule(localContext, 8, QuixosLockParser.RULE_resourceKind);
let _la: number; let _la: number;
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 37; this.state = 47;
_la = this.tokenStream.LA(1); _la = this.tokenStream.LA(1);
if(!(_la === 5 || _la === 6)) { if(!(_la === 6 || _la === 7)) {
this.errorHandler.recoverInline(this); this.errorHandler.recoverInline(this);
} }
else { else {
@@ -204,25 +264,25 @@ export class QuixosLockParser extends antlr.Parser {
} }
public sourceBlock(): SourceBlockContext { public sourceBlock(): SourceBlockContext {
let localContext = new SourceBlockContext(this.context, this.state); let localContext = new SourceBlockContext(this.context, this.state);
this.enterRule(localContext, 8, QuixosLockParser.RULE_sourceBlock); this.enterRule(localContext, 10, QuixosLockParser.RULE_sourceBlock);
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 39; this.state = 49;
this.match(QuixosLockParser.LBRACE); this.match(QuixosLockParser.LBRACE);
this.state = 40; this.state = 50;
this.match(QuixosLockParser.REPOSITORY); this.match(QuixosLockParser.REPOSITORY);
this.state = 41; this.state = 51;
this.stringLiteral(); this.stringLiteral();
this.state = 42; this.state = 52;
this.match(QuixosLockParser.SEMI); this.match(QuixosLockParser.SEMI);
this.state = 43; this.state = 53;
this.match(QuixosLockParser.COMMIT); this.match(QuixosLockParser.COMMIT);
this.state = 44; this.state = 54;
this.stringLiteral(); this.stringLiteral();
this.state = 45; this.state = 55;
this.match(QuixosLockParser.SEMI); this.match(QuixosLockParser.SEMI);
this.state = 46; this.state = 56;
this.match(QuixosLockParser.RBRACE); this.match(QuixosLockParser.RBRACE);
} }
} }
@@ -241,11 +301,11 @@ export class QuixosLockParser extends antlr.Parser {
} }
public identifier(): IdentifierContext { public identifier(): IdentifierContext {
let localContext = new IdentifierContext(this.context, this.state); let localContext = new IdentifierContext(this.context, this.state);
this.enterRule(localContext, 10, QuixosLockParser.RULE_identifier); this.enterRule(localContext, 12, QuixosLockParser.RULE_identifier);
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 48; this.state = 58;
this.match(QuixosLockParser.IDENTIFIER); this.match(QuixosLockParser.IDENTIFIER);
} }
} }
@@ -264,11 +324,11 @@ export class QuixosLockParser extends antlr.Parser {
} }
public stringLiteral(): StringLiteralContext { public stringLiteral(): StringLiteralContext {
let localContext = new StringLiteralContext(this.context, this.state); let localContext = new StringLiteralContext(this.context, this.state);
this.enterRule(localContext, 12, QuixosLockParser.RULE_stringLiteral); this.enterRule(localContext, 14, QuixosLockParser.RULE_stringLiteral);
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 50; this.state = 60;
this.match(QuixosLockParser.STRING_LITERAL); this.match(QuixosLockParser.STRING_LITERAL);
} }
} }
@@ -287,21 +347,24 @@ export class QuixosLockParser extends antlr.Parser {
} }
public static readonly _serializedATN: number[] = [ public static readonly _serializedATN: number[] = [
4,1,17,53,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,19,63,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,1,0,1,0,1,0,1,0,1,0,1,0,5,0,21,8,0,10,0,12,0,24,9,0,1,0,1,0,1, 6,2,7,7,7,1,0,1,0,3,0,19,8,0,1,0,1,0,1,0,1,0,1,0,1,0,5,0,27,8,0,
0,1,1,1,1,1,1,1,1,1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,4,1,4,1,4,1,4,1, 10,0,12,0,30,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,
4,1,4,1,4,1,4,1,4,1,5,1,5,1,6,1,6,1,6,0,0,7,0,2,4,6,8,10,12,0,1, 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,0,5,6,46,0,14,1,0,0,0,2,28,1,0,0,0,4,32,1,0,0,0,6,37,1,0,0,0,8, 1,6,1,7,1,7,1,7,0,0,8,0,2,4,6,8,10,12,14,0,1,1,0,6,7,58,0,16,1,0,
39,1,0,0,0,10,48,1,0,0,0,12,50,1,0,0,0,14,15,5,1,0,0,15,16,5,2,0, 0,0,2,34,1,0,0,0,4,38,1,0,0,0,6,43,1,0,0,0,8,47,1,0,0,0,10,49,1,
0,16,17,5,12,0,0,17,18,5,9,0,0,18,22,3,2,1,0,19,21,3,4,2,0,20,19, 0,0,0,12,58,1,0,0,0,14,60,1,0,0,0,16,18,5,1,0,0,17,19,5,2,0,0,18,
1,0,0,0,21,24,1,0,0,0,22,20,1,0,0,0,22,23,1,0,0,0,23,25,1,0,0,0, 17,1,0,0,0,18,19,1,0,0,0,19,20,1,0,0,0,20,21,5,3,0,0,21,22,5,14,
24,22,1,0,0,0,25,26,5,10,0,0,26,27,5,0,0,1,27,1,1,0,0,0,28,29,5, 0,0,22,28,5,11,0,0,23,27,3,2,1,0,24,27,3,6,3,0,25,27,3,4,2,0,26,
3,0,0,29,30,5,4,0,0,30,31,3,8,4,0,31,3,1,0,0,0,32,33,3,6,3,0,33, 23,1,0,0,0,26,24,1,0,0,0,26,25,1,0,0,0,27,30,1,0,0,0,28,26,1,0,0,
34,3,10,5,0,34,35,5,4,0,0,35,36,3,8,4,0,36,5,1,0,0,0,37,38,7,0,0, 0,28,29,1,0,0,0,29,31,1,0,0,0,30,28,1,0,0,0,31,32,5,12,0,0,32,33,
0,38,7,1,0,0,0,39,40,5,9,0,0,40,41,5,7,0,0,41,42,3,12,6,0,42,43, 5,0,0,1,33,1,1,0,0,0,34,35,5,4,0,0,35,36,5,5,0,0,36,37,3,10,5,0,
5,11,0,0,43,44,5,8,0,0,44,45,3,12,6,0,45,46,5,11,0,0,46,47,5,10, 37,3,1,0,0,0,38,39,3,8,4,0,39,40,3,12,6,0,40,41,5,5,0,0,41,42,3,
0,0,47,9,1,0,0,0,48,49,5,13,0,0,49,11,1,0,0,0,50,51,5,14,0,0,51, 10,5,0,42,5,1,0,0,0,43,44,5,10,0,0,44,45,3,14,7,0,45,46,5,13,0,0,
13,1,0,0,0,1,22 46,7,1,0,0,0,47,48,7,0,0,0,48,9,1,0,0,0,49,50,5,11,0,0,50,51,5,8,
0,0,51,52,3,14,7,0,52,53,5,13,0,0,53,54,5,9,0,0,54,55,3,14,7,0,55,
56,5,13,0,0,56,57,5,12,0,0,57,11,1,0,0,0,58,59,5,15,0,0,59,13,1,
0,0,0,60,61,5,16,0,0,61,15,1,0,0,0,3,18,26,28
]; ];
private static __ATN: antlr.ATN; private static __ATN: antlr.ATN;
@@ -339,15 +402,33 @@ export class DocumentContext extends antlr.ParserRuleContext {
public LBRACE(): antlr.TerminalNode { public LBRACE(): antlr.TerminalNode {
return this.getToken(QuixosLockParser.LBRACE, 0)!; return this.getToken(QuixosLockParser.LBRACE, 0)!;
} }
public quixosEntry(): QuixosEntryContext {
return this.getRuleContext(0, QuixosEntryContext)!;
}
public RBRACE(): antlr.TerminalNode { public RBRACE(): antlr.TerminalNode {
return this.getToken(QuixosLockParser.RBRACE, 0)!; return this.getToken(QuixosLockParser.RBRACE, 0)!;
} }
public EOF(): antlr.TerminalNode { public EOF(): antlr.TerminalNode {
return this.getToken(QuixosLockParser.EOF, 0)!; return this.getToken(QuixosLockParser.EOF, 0)!;
} }
public FRAGMENT(): antlr.TerminalNode | null {
return this.getToken(QuixosLockParser.FRAGMENT, 0);
}
public quixosEntry(): QuixosEntryContext[];
public quixosEntry(i: number): QuixosEntryContext | null;
public quixosEntry(i?: number): QuixosEntryContext[] | QuixosEntryContext | null {
if (i === undefined) {
return this.getRuleContexts(QuixosEntryContext);
}
return this.getRuleContext(i, QuixosEntryContext);
}
public importEntry(): ImportEntryContext[];
public importEntry(i: number): ImportEntryContext | null;
public importEntry(i?: number): ImportEntryContext[] | ImportEntryContext | null {
if (i === undefined) {
return this.getRuleContexts(ImportEntryContext);
}
return this.getRuleContext(i, ImportEntryContext);
}
public resourceEntry(): ResourceEntryContext[]; public resourceEntry(): ResourceEntryContext[];
public resourceEntry(i: number): ResourceEntryContext | null; public resourceEntry(i: number): ResourceEntryContext | null;
public resourceEntry(i?: number): ResourceEntryContext[] | ResourceEntryContext | null { public resourceEntry(i?: number): ResourceEntryContext[] | ResourceEntryContext | null {
@@ -425,6 +506,32 @@ export class ResourceEntryContext extends antlr.ParserRuleContext {
} }
export class ImportEntryContext extends antlr.ParserRuleContext {
public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) {
super(parent, invokingState);
}
public IMPORT(): antlr.TerminalNode {
return this.getToken(QuixosLockParser.IMPORT, 0)!;
}
public stringLiteral(): StringLiteralContext {
return this.getRuleContext(0, StringLiteralContext)!;
}
public SEMI(): antlr.TerminalNode {
return this.getToken(QuixosLockParser.SEMI, 0)!;
}
public override get ruleIndex(): number {
return QuixosLockParser.RULE_importEntry;
}
public override accept<Result>(visitor: QuixosLockVisitor<Result>): Result | null {
if (visitor.visitImportEntry) {
return visitor.visitImportEntry(this);
} else {
return visitor.visitChildren(this);
}
}
}
export class ResourceKindContext extends antlr.ParserRuleContext { export class ResourceKindContext extends antlr.ParserRuleContext {
public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) {
super(parent, invokingState); super(parent, invokingState);
@@ -5,6 +5,7 @@ import { AbstractParseTreeVisitor } from "antlr4ng";
import { DocumentContext } from "./QuixosLockParser.js"; import { DocumentContext } from "./QuixosLockParser.js";
import { QuixosEntryContext } from "./QuixosLockParser.js"; import { QuixosEntryContext } from "./QuixosLockParser.js";
import { ResourceEntryContext } from "./QuixosLockParser.js"; import { ResourceEntryContext } from "./QuixosLockParser.js";
import { ImportEntryContext } from "./QuixosLockParser.js";
import { ResourceKindContext } from "./QuixosLockParser.js"; import { ResourceKindContext } from "./QuixosLockParser.js";
import { SourceBlockContext } from "./QuixosLockParser.js"; import { SourceBlockContext } from "./QuixosLockParser.js";
import { IdentifierContext } from "./QuixosLockParser.js"; import { IdentifierContext } from "./QuixosLockParser.js";
@@ -37,6 +38,12 @@ export class QuixosLockVisitor<Result> extends AbstractParseTreeVisitor<Result>
* @return the visitor result * @return the visitor result
*/ */
visitResourceEntry?: (ctx: ResourceEntryContext) => Result; visitResourceEntry?: (ctx: ResourceEntryContext) => Result;
/**
* Visit a parse tree produced by `QuixosLockParser.importEntry`.
* @param ctx the parse tree
* @return the visitor result
*/
visitImportEntry?: (ctx: ImportEntryContext) => Result;
/** /**
* Visit a parse tree produced by `QuixosLockParser.resourceKind`. * Visit a parse tree produced by `QuixosLockParser.resourceKind`.
* @param ctx the parse tree * @param ctx the parse tree
+1
View File
@@ -1,2 +1,3 @@
export * from "./loader.js";
export * from "./parser.js"; export * from "./parser.js";
export * from "./types.js"; export * from "./types.js";
+150
View File
@@ -0,0 +1,150 @@
import { lstat, readFile } from "node:fs/promises";
import path from "node:path";
import {
parseQuixosLockDocument,
type QuixosLockDiagnostic,
type QuixosLockParseResult,
} from "./parser.js";
import type {
LockedResource,
QuixosLockDocument,
QuixosRepositoryLock,
} from "./types.js";
export type QuixosLockSourceReader = (relativePath: string) => Promise<string>;
const diagnostic = (
code: string,
message: string,
fileName: string,
path?: string,
): QuixosLockDiagnostic => ({
phase: "resolution",
code,
message,
fileName,
line: 1,
column: 0,
path,
});
export const resolveQuixosLock = async (
rootSource: string,
readSource: QuixosLockSourceReader,
rootFileName = "quixos.lock",
): Promise<QuixosLockParseResult> => {
const root = parseQuixosLockDocument(rootSource, rootFileName);
if (!root.ok) return root;
if (root.document.kind !== "root") {
return {
ok: false,
diagnostics: [diagnostic(
"expected-root-lock",
"The entrypoint must be a root Quixos lock, not a fragment",
rootFileName,
)],
};
}
const diagnostics: QuixosLockDiagnostic[] = [];
const resources: LockedResource[] = [];
const sourceFiles = [rootFileName];
const visited = new Set<string>();
const active: string[] = [];
const addResources = (document: QuixosLockDocument, fileName: string) => {
for (const resource of document.resources) {
const duplicate = resources.find((entry) =>
entry.kind === resource.kind && entry.binding === resource.binding);
if (duplicate) {
diagnostics.push(diagnostic(
"duplicate-resource-binding",
`Duplicate ${resource.kind} binding ${resource.binding} across imported lock files`,
fileName,
`${resource.kind}.${resource.binding}`,
));
} else {
resources.push(resource);
}
}
};
const visit = async (importPath: string) => {
if (active.includes(importPath)) {
diagnostics.push(diagnostic(
"import-cycle",
`Lock import cycle: ${[...active, importPath].join(" -> ")}`,
importPath,
));
return;
}
if (visited.has(importPath)) return;
active.push(importPath);
let source: string;
try {
source = await readSource(importPath);
} catch (cause) {
diagnostics.push(diagnostic(
"import-read-failed",
`Could not read lock import ${importPath}: ${cause instanceof Error ? cause.message : String(cause)}`,
importPath,
));
active.pop();
return;
}
const parsed = parseQuixosLockDocument(source, importPath);
if (!parsed.ok) {
diagnostics.push(...parsed.diagnostics);
active.pop();
return;
}
if (parsed.document.kind !== "fragment") {
diagnostics.push(diagnostic(
"imported-root-lock",
`Imported file ${importPath} must begin with "quixos-lock fragment"`,
importPath,
));
active.pop();
return;
}
visited.add(importPath);
sourceFiles.push(importPath);
addResources(parsed.document, importPath);
for (const nested of parsed.document.imports) await visit(nested);
active.pop();
};
addResources(root.document, rootFileName);
for (const importPath of root.document.imports) await visit(importPath);
if (diagnostics.length) return { ok: false, diagnostics };
const lock: QuixosRepositoryLock = {
formatVersion: 1,
quixos: root.document.quixos,
resources,
sourceFiles,
};
return { ok: true, lock, diagnostics: [] };
};
export const loadQuixosLock = async (fileName: string): Promise<QuixosLockParseResult> => {
const absoluteRoot = path.resolve(fileName);
const repositoryRoot = path.dirname(absoluteRoot);
const rootName = path.basename(absoluteRoot);
const rootSource = await readFile(absoluteRoot, "utf8");
return await resolveQuixosLock(rootSource, async (relativePath) => {
let absoluteImport = repositoryRoot;
const segments = relativePath.split("/");
for (const [index, segment] of segments.entries()) {
absoluteImport = path.join(absoluteImport, segment);
const metadata = await lstat(absoluteImport);
if (metadata.isSymbolicLink()) {
throw new Error("imports must not traverse symbolic links");
}
const final = index === segments.length - 1;
if ((!final && !metadata.isDirectory()) || (final && !metadata.isFile())) {
throw new Error("imports must be ordinary files beneath ordinary directories");
}
}
return await readFile(absoluteImport, "utf8");
}, rootName);
};
+162 -8
View File
@@ -15,11 +15,12 @@ import {
import type { import type {
GitSource, GitSource,
LockedResource, LockedResource,
QuixosLockDocument,
QuixosRepositoryLock, QuixosRepositoryLock,
} from "./types.js"; } from "./types.js";
export type QuixosLockDiagnostic = { export type QuixosLockDiagnostic = {
phase: "syntax" | "validation"; phase: "syntax" | "validation" | "resolution";
code: string; code: string;
message: string; message: string;
fileName: string; fileName: string;
@@ -32,6 +33,10 @@ export type QuixosLockParseResult =
| { ok: true; lock: QuixosRepositoryLock; diagnostics: [] } | { ok: true; lock: QuixosRepositoryLock; diagnostics: [] }
| { ok: false; diagnostics: QuixosLockDiagnostic[] }; | { ok: false; diagnostics: QuixosLockDiagnostic[] };
export type QuixosLockDocumentParseResult =
| { ok: true; document: QuixosLockDocument; diagnostics: [] }
| { ok: false; diagnostics: QuixosLockDiagnostic[] };
class SyntaxErrorListener extends BaseErrorListener { class SyntaxErrorListener extends BaseErrorListener {
constructor( constructor(
private readonly fileName: string, private readonly fileName: string,
@@ -74,16 +79,46 @@ const issue = (
code: string, code: string,
message: string, message: string,
path?: string, path?: string,
line = 1,
column = 0,
) => diagnostics.push({ ) => diagnostics.push({
phase: "validation", phase: "validation",
code, code,
message, message,
fileName, fileName,
line: 1, line,
column: 0, column,
path, path,
}); });
const validateImport = (
importPath: string,
index: number,
fileName: string,
diagnostics: QuixosLockDiagnostic[],
line: number,
column: number,
) => {
const path = `imports[${index}]`;
if (
!importPath
|| importPath.startsWith("/")
|| importPath.includes("\\")
|| importPath.split("/").some((segment) => !segment || segment === "." || segment === "..")
|| /^[A-Za-z][A-Za-z0-9+.-]*:/.test(importPath)
) {
issue(
diagnostics,
fileName,
"invalid-import-path",
`${path} must be a normalized relative path beneath the workspace repository root`,
path,
line,
column,
);
}
};
const validateSource = ( const validateSource = (
source: GitSource, source: GitSource,
path: string, path: string,
@@ -141,10 +176,10 @@ const validateSource = (
} }
}; };
export const parseQuixosLock = ( export const parseQuixosLockDocument = (
source: string, source: string,
fileName = "<memory>", fileName = "<memory>",
): QuixosLockParseResult => { ): QuixosLockDocumentParseResult => {
const diagnostics: QuixosLockDiagnostic[] = []; const diagnostics: QuixosLockDiagnostic[] = [];
const listener = new SyntaxErrorListener(fileName, diagnostics); const listener = new SyntaxErrorListener(fileName, diagnostics);
const lexer = new QuixosLockLexer(CharStream.fromString(source)); const lexer = new QuixosLockLexer(CharStream.fromString(source));
@@ -167,8 +202,55 @@ export const parseQuixosLock = (
); );
} }
const quixos = lowerSource(tree.quixosEntry().sourceBlock()); const fragment = Boolean(tree.FRAGMENT());
validateSource(quixos, "quixos", fileName, diagnostics); const quixosEntries = tree.quixosEntry();
let quixos: GitSource | undefined;
if (fragment && quixosEntries.length) {
issue(
diagnostics,
fileName,
"fragment-has-quixos-source",
"A lock fragment inherits the root document's Quixos source and must not redeclare it",
"quixos",
);
} else if (!fragment && quixosEntries.length !== 1) {
issue(
diagnostics,
fileName,
"root-quixos-source-count",
"A root lock document must contain exactly one Quixos source",
"quixos",
);
} else if (!fragment) {
quixos = lowerSource(quixosEntries[0]!.sourceBlock());
validateSource(quixos, "quixos", fileName, diagnostics);
}
const imports = tree.importEntry().map((context, index) => {
const importPath = stringValue(context.stringLiteral());
validateImport(
importPath,
index,
fileName,
diagnostics,
context.start?.line ?? 1,
context.start?.column ?? 0,
);
return importPath;
});
const repeatedImports = new Set<string>();
imports.forEach((importPath, index) => {
if (repeatedImports.has(importPath)) {
issue(
diagnostics,
fileName,
"duplicate-import",
`Duplicate lock import ${importPath}`,
`imports[${index}]`,
);
}
repeatedImports.add(importPath);
});
const resources: LockedResource[] = []; const resources: LockedResource[] = [];
const bindings = new Set<string>(); const bindings = new Set<string>();
@@ -195,11 +277,56 @@ export const parseQuixosLock = (
? { ok: false, diagnostics } ? { ok: false, diagnostics }
: { : {
ok: true, ok: true,
lock: { formatVersion: 1, quixos, resources }, document: fragment
? { kind: "fragment", formatVersion: 1, imports, resources }
: { kind: "root", formatVersion: 1, quixos: quixos!, imports, resources },
diagnostics: [], diagnostics: [],
}; };
}; };
export const parseQuixosLock = (
source: string,
fileName = "<memory>",
): QuixosLockParseResult => {
const parsed = parseQuixosLockDocument(source, fileName);
if (!parsed.ok) return parsed;
if (parsed.document.kind === "fragment") {
return {
ok: false,
diagnostics: [{
phase: "validation",
code: "expected-root-lock",
message: "Expected a root Quixos lock, found a lock fragment",
fileName,
line: 1,
column: 0,
}],
};
}
if (parsed.document.imports.length) {
return {
ok: false,
diagnostics: [{
phase: "resolution",
code: "imports-require-file-resolution",
message: "This lock has imports and must be loaded from its repository rather than parsed as an isolated string",
fileName,
line: 1,
column: 0,
}],
};
}
return {
ok: true,
lock: {
formatVersion: 1,
quixos: parsed.document.quixos,
resources: parsed.document.resources,
},
diagnostics: [],
};
};
const quoted = (value: string) => JSON.stringify(value); const quoted = (value: string) => JSON.stringify(value);
const sourceLines = (source: GitSource, indentation: string): string[] => [ const sourceLines = (source: GitSource, indentation: string): string[] => [
@@ -225,3 +352,30 @@ export const formatQuixosLock = (lock: QuixosRepositoryLock): string => {
lines.push("}", ""); lines.push("}", "");
return lines.join("\n"); return lines.join("\n");
}; };
export const formatQuixosLockDocument = (document: QuixosLockDocument): string => {
const lines = [
`quixos-lock${document.kind === "fragment" ? " fragment" : ""} version 1 {`,
];
if (document.kind === "root") {
lines.push(
" quixos source {",
...sourceLines(document.quixos, " "),
" }",
);
}
for (const importPath of document.imports) {
if (lines.length > 1) lines.push("");
lines.push(` import ${quoted(importPath)};`);
}
for (const resource of document.resources) {
if (lines.length > 1) lines.push("");
lines.push(
` ${resource.kind} ${resource.binding} source {`,
...sourceLines(resource.source, " "),
" }",
);
}
lines.push("}", "");
return lines.join("\n");
};
+20
View File
@@ -12,10 +12,30 @@ export type LockedResource = {
source: GitSource; source: GitSource;
}; };
export type QuixosLockRootDocument = {
kind: "root";
formatVersion: 1;
quixos: GitSource;
imports: string[];
resources: LockedResource[];
};
export type QuixosLockFragmentDocument = {
kind: "fragment";
formatVersion: 1;
imports: string[];
resources: LockedResource[];
};
export type QuixosLockDocument =
| QuixosLockRootDocument
| QuixosLockFragmentDocument;
export type QuixosRepositoryLock = { export type QuixosRepositoryLock = {
formatVersion: 1; formatVersion: 1;
quixos: GitSource; quixos: GitSource;
resources: LockedResource[]; resources: LockedResource[];
sourceFiles?: string[];
}; };
export type NixGitInput = { export type NixGitInput = {
+156
View File
@@ -0,0 +1,156 @@
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";
import {
compileCapabilityResourceRepository,
compileWorkspaceRepository,
} from "../src/capability-language/index.js";
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)]);
await writeFile(path.join(root, "quixos.lock"), lock(`package Runtime source {
repository "https://example.test/package-runtime.git";
commit "${packageCommit}";
}`));
await writeFile(path.join(root, "workspace.qx"), `workspace Test id "workspace:test" revision "workspace:test@1" commit "${"4".repeat(40)}" {
atom Subject id "atom:subject";
import package Runtime;
}
`);
await writeFile(path.join(named, "quixos.lock"), lock());
await writeFile(path.join(named, "interface.qx"), `interface Named id "interface:named" revision "interface:named@1" {
value name id "member:named:name" : string {
get id "operation:named:name:get";
}
}
`);
await writeFile(path.join(runtime, "quixos.lock"), lock(`interface Named source {
repository "https://example.test/interface-named.git";
commit "${namedCommit}";
}`));
await writeFile(path.join(runtime, "package.qx"), `import interface Named;
package Runtime id "package:runtime" revision "package:runtime@1" {
function describe id "export:runtime:describe" : interface-ref<Named> -> string;
}
`);
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 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)]);
await writeFile(path.join(root, "quixos.lock"), lock(`package Runtime source {
repository "https://example.test/package-runtime.git";
commit "${packageCommit}";
}`));
await writeFile(path.join(root, "workspace.qx"), `workspace Test id "workspace:test" revision "workspace:test@1" commit "${"4".repeat(40)}" {
atom Subject id "atom:subject";
import package Runtime;
}
`);
await writeFile(path.join(runtime, "quixos.lock"), lock());
await writeFile(path.join(runtime, "package.qx"), `import interface Hidden;
package Runtime id "package:runtime" revision "package:runtime@1" { }
`);
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)]);
await writeFile(path.join(root, "quixos.lock"), lock(`package Runtime source {
repository "https://example.test/package-runtime.git";
commit "${packageCommit}";
}`));
await writeFile(path.join(root, "workspace.qx"), `workspace Test id "workspace:test" revision "workspace:test@1" commit "${"4".repeat(40)}" {
atom Subject id "atom:subject";
import package Runtime;
}
`);
await writeFile(path.join(runtime, "quixos.lock"), lock());
await writeFile(path.join(runtime, "package.qx"), `external interface Named revision "interface:named@1";
package Runtime id "package:runtime" revision "package:runtime@1" { }
`);
await assert.rejects(
compileWorkspaceRepository({
rootDirectory: root,
resolveResource: async () => ({ directory: runtime }),
}),
/requires external interface Named \(interface:named@1\)/,
);
});
+137 -49
View File
@@ -2,18 +2,96 @@ import assert from "node:assert/strict";
import { readFileSync } from "node:fs"; import { readFileSync } from "node:fs";
import { resolve } from "node:path"; import { resolve } from "node:path";
import { test } from "node:test"; import { test } from "node:test";
import { compileCapabilitySource } from "../src/capability-language/index.js";
import { import {
capabilityFixturePath, compileCapabilityResourceSource,
compileCapabilitySource,
} from "../src/capability-language/index.js";
import {
capabilityFixtureSource, capabilityFixtureSource,
capabilityResourceSources,
compileCapabilityFixture,
fixtureId, fixtureId,
} from "./fixtures/capability-model.js"; } from "./fixtures/capability-model.js";
test("ANTLR parses and validates a complete capability workspace", () => { const compileWebStudioFixture = (packageTransform = (source: string) => source) => {
const result = compileCapabilitySource( const fixture = (name: string) => readFileSync(
capabilityFixtureSource, resolve(process.cwd(), "test/fixtures", name),
capabilityFixturePath, "utf8",
); );
const react = compileCapabilityResourceSource(
fixture("react-component.interface.qx"),
{
source: {
repository: "https://repos.quixos.org/org-quixos-web-studio/interface-react-component.git",
commit: "2".repeat(40),
},
},
);
if (!react.ok || react.resource.kind !== "interface") {
throw new Error("ReactComponent fixture did not compile");
}
const named = compileCapabilityResourceSource(
fixture("named.interface.qx"),
{
source: {
repository: "https://repos.quixos.org/quixos-test/interface-named.git",
commit: "5".repeat(40),
},
},
);
if (!named.ok || named.resource.kind !== "interface") {
throw new Error("Named fixture did not compile");
}
const has = compileCapabilityResourceSource(
fixture("has-react-component.interface.qx"),
{
source: {
repository: "https://repos.quixos.org/org-quixos-web-studio/interface-has-react-component.git",
commit: "3".repeat(40),
},
environment: {
interfaces: new Map([["ReactComponent", react.resource.revision]]),
interfaceClosure: [react.resource.revision],
},
},
);
if (!has.ok || has.resource.kind !== "interface") {
throw new Error("HasReactComponent fixture did not compile");
}
const component = compileCapabilityResourceSource(
packageTransform(fixture("component-runtime.package.qx")),
{
source: {
repository: "https://repos.quixos.org/quixos-test/package-component-runtime.git",
commit: "4".repeat(40),
},
environment: {
interfaces: new Map([["Named", named.resource.revision]]),
interfaceClosure: [named.resource.revision],
},
},
);
if (!component.ok || component.resource.kind !== "package") {
throw new Error("ComponentRuntime fixture did not compile");
}
return compileCapabilitySource(
fixture("web-studio.capabilities.qx"),
"web-studio.capabilities.qx",
{
interfaces: new Map([
["Named", named.resource.revision],
["ReactComponent", react.resource.revision],
["HasReactComponent", has.resource.revision],
]),
packages: new Map([["ComponentRuntime", component.resource.revision]]),
interfaceClosure: [named.resource.revision, react.resource.revision, has.resource.revision],
packageClosure: [component.resource.revision],
},
);
};
test("ANTLR parses and validates a complete capability workspace", () => {
const result = compileCapabilityFixture();
assert.equal(result.ok, true); assert.equal(result.ok, true);
if (!result.ok) return; if (!result.ok) return;
assert.equal(result.workspace.workspaceId, fixtureId.workspace); assert.equal(result.workspace.workspaceId, fixtureId.workspace);
@@ -24,26 +102,24 @@ test("ANTLR parses and validates a complete capability workspace", () => {
}); });
test("conformances do not accept authored IDs", () => { test("conformances do not accept authored IDs", () => {
const result = compileCapabilitySource( const result = compileCapabilityFixture({
capabilityFixtureSource.replace( workspace: capabilityFixtureSource.replace(
"conform Project as Named {", "conform Project as Named {",
'conform Project as Named id "conformance:project:named" {', 'conform Project as Named id "conformance:project:named" {',
), ),
"conformance-id.qx", });
);
assert.equal(result.ok, false); assert.equal(result.ok, false);
if (result.ok) return; if (result.ok) return;
assert.ok(result.diagnostics.some((entry) => entry.phase === "syntax")); assert.ok(result.diagnostics.some((entry) => entry.phase === "syntax"));
}); });
test("the v1 language has no implicit relationship materialization rule", () => { test("the v1 language has no implicit relationship materialization rule", () => {
const result = compileCapabilitySource( const result = compileCapabilityFixture({
capabilityFixtureSource.replace( workspace: capabilityFixtureSource.replace(
/\n}\s*$/, /\n}\s*$/,
'\n materialize ProjectOwner.owner if absent with Person;\n}\n', '\n materialize ProjectOwner.owner if absent with Person;\n}\n',
), ),
"materialize.qx", });
);
assert.equal(result.ok, false); assert.equal(result.ok, false);
if (result.ok) return; if (result.ok) return;
assert.ok(result.diagnostics.some((entry) => entry.phase === "syntax")); assert.ok(result.diagnostics.some((entry) => entry.phase === "syntax"));
@@ -57,21 +133,23 @@ test("forward declarations make source order irrelevant", () => {
/\n}\s*$/, /\n}\s*$/,
'\n atom Project id "atom:project";\n atom Person id "atom:person";\n}\n', '\n atom Project id "atom:project";\n atom Person id "atom:person";\n}\n',
); );
assert.equal(compileCapabilitySource(source, "reordered.qx").ok, true); assert.equal(compileCapabilityFixture({ workspace: source }).ok, true);
}); });
test("interfaces can declare ordinary call operations", () => { test("interfaces can declare ordinary call operations", () => {
const source = capabilityFixtureSource.replace( const workspace = capabilityFixtureSource.replace(
" value summary id \"member:summary:summary\" : string {\n get id \"operation:summary:summary:get\";\n }",
" operation summarize id \"member:summary:summarize\" : string -> string {\n call id \"operation:summary:summarize\";\n }",
).replace(
"bind summary.get to package TodoRuntime.summaryGet", "bind summary.get to package TodoRuntime.summaryGet",
"bind summarize.call to package TodoRuntime.summaryGet", "bind summarize.call to package TodoRuntime.summaryGet",
).replace( );
const summary = capabilityResourceSources.summary.replace(
" value summary id \"member:summary:summary\" : string {\n get id \"operation:summary:summary:get\";\n }",
" operation summarize id \"member:summary:summarize\" : string -> string {\n call id \"operation:summary:summarize\";\n }",
);
const todo = capabilityResourceSources.todo.replace(
"operation summaryGet id \"export:todo-runtime:summary-get\" : unit -> string", "operation summaryGet id \"export:todo-runtime:summary-get\" : unit -> string",
"operation summaryGet id \"export:todo-runtime:summary-get\" : string -> string", "operation summaryGet id \"export:todo-runtime:summary-get\" : string -> string",
); );
const result = compileCapabilitySource(source, "operation-member.qx"); const result = compileCapabilityFixture({ workspace, summary, todo });
assert.equal(result.ok, true); assert.equal(result.ok, true);
if (!result.ok) return; if (!result.ok) return;
const member = result.workspace.interfaceImports const member = result.workspace.interfaceImports
@@ -86,7 +164,7 @@ test("state defaults accept recursive JSON values", () => {
shared state ProjectMetadata id "slot:project:metadata" on Project : message "example.Metadata" shared state ProjectMetadata id "slot:project:metadata" on Project : message "example.Metadata"
policy optimistic-register default {"labels":["compiler","runtime"],"score":1.5,"enabled":true,"extra":null};`, policy optimistic-register default {"labels":["compiler","runtime"],"score":1.5,"enabled":true,"extra":null};`,
); );
const result = compileCapabilitySource(source, "json-default.qx"); const result = compileCapabilityFixture({ workspace: source });
assert.equal(result.ok, true); assert.equal(result.ok, true);
if (!result.ok) return; if (!result.ok) return;
const metadata = result.workspace.sharedAttachments.find( const metadata = result.workspace.sharedAttachments.find(
@@ -103,25 +181,23 @@ test("state defaults accept recursive JSON values", () => {
}); });
test("syntax errors retain source locations", () => { test("syntax errors retain source locations", () => {
const result = compileCapabilitySource( const result = compileCapabilityFixture({
capabilityFixtureSource.replace("atom Project", "atom Project ???"), workspace: capabilityFixtureSource.replace("atom Project", "atom Project ???"),
"broken.qx", });
);
assert.equal(result.ok, false); assert.equal(result.ok, false);
if (result.ok) return; if (result.ok) return;
assert.ok(result.diagnostics.some((entry) => assert.ok(result.diagnostics.some((entry) =>
entry.phase === "syntax" && entry.fileName === "broken.qx" && entry.line > 0 entry.phase === "syntax" && entry.line > 0
)); ));
}); });
test("unknown authoring names are lowering errors", () => { test("unknown authoring names are lowering errors", () => {
const result = compileCapabilitySource( const result = compileCapabilityFixture({
capabilityFixtureSource.replace( workspace: capabilityFixtureSource.replace(
"to state ProjectTitle.read", "to state ProjectTitle.read",
"to state NotAState.read", "to state NotAState.read",
), ),
"unknown-name.qx", });
);
assert.equal(result.ok, false); assert.equal(result.ok, false);
if (result.ok) return; if (result.ok) return;
assert.ok(result.diagnostics.some((entry) => assert.ok(result.diagnostics.some((entry) =>
@@ -132,13 +208,12 @@ test("unknown authoring names are lowering errors", () => {
}); });
test("well-formed but invalid programs report semantic paths", () => { test("well-formed but invalid programs report semantic paths", () => {
const result = compileCapabilitySource( const result = compileCapabilityFixture({
capabilityFixtureSource.replace( workspace: capabilityFixtureSource.replace(
"bind name.get to state ProjectTitle.read", "bind name.get to state ProjectTitle.read",
"bind name.get to state ProjectTitle.write", "bind name.get to state ProjectTitle.write",
), ),
"invalid-binding.qx", });
);
assert.equal(result.ok, false); assert.equal(result.ok, false);
if (result.ok) return; if (result.ok) return;
const diagnostic = result.diagnostics.find( const diagnostic = result.diagnostics.find(
@@ -150,11 +225,7 @@ test("well-formed but invalid programs report semantic paths", () => {
}); });
test("Web Studio sidecars declare lazy materialization and checked cross-object ports", () => { test("Web Studio sidecars declare lazy materialization and checked cross-object ports", () => {
const source = readFileSync( const result = compileWebStudioFixture();
resolve(process.cwd(), "test/fixtures/web-studio.capabilities.qx"),
"utf8",
);
const result = compileCapabilitySource(source, "web-studio.capabilities.qx");
assert.equal(result.ok, true); assert.equal(result.ok, true);
if (!result.ok) return; if (!result.ok) return;
@@ -175,9 +246,9 @@ test("Web Studio sidecars declare lazy materialization and checked cross-object
const binding = component?.operationBindings[0]?.binding; const binding = component?.operationBindings[0]?.binding;
assert.equal(binding?.kind, "package"); assert.equal(binding?.kind, "package");
if (binding?.kind !== "package") return; if (binding?.kind !== "package") return;
assert.deepEqual(binding.dependencies[1]?.binding, { assert.deepEqual(binding.dependencies[0]?.binding, {
kind: "state", kind: "interface",
slotId: "slot:project:name", interfaceRevisionId: "interface:named@1",
via: { via: {
edgeTypeId: "edge:project:component", edgeTypeId: "edge:project:component",
projectionId: "projection:component:subject", projectionId: "projection:component:subject",
@@ -186,14 +257,10 @@ test("Web Studio sidecars declare lazy materialization and checked cross-object
}); });
test("relationship materializers require a constructor from the host atom", () => { test("relationship materializers require a constructor from the host atom", () => {
const source = readFileSync( const result = compileWebStudioFixture((source) => source.replace(
resolve(process.cwd(), "test/fixtures/web-studio.capabilities.qx"),
"utf8",
).replace(
"constructs ProjectComponent : atom-ref<Project>;", "constructs ProjectComponent : atom-ref<Project>;",
"constructs ProjectComponent : unit;", "constructs ProjectComponent : unit;",
); ));
const result = compileCapabilitySource(source, "invalid-materializer.qx");
assert.equal(result.ok, false); assert.equal(result.ok, false);
if (result.ok) return; if (result.ok) return;
assert.ok(result.diagnostics.some((entry) => assert.ok(result.diagnostics.some((entry) =>
@@ -201,3 +268,24 @@ test("relationship materializers require a constructor from the host atom", () =
entry.message.includes("must accept") entry.message.includes("must accept")
)); ));
}); });
test("callable interface ports require a full source dependency, not a nominal reference", () => {
const result = compileCapabilityResourceSource(`
external interface Named revision "interface:named@1";
package Runtime id "package:runtime" revision "package:runtime@1" {
function readName id "export:runtime:read-name" : unit -> string requires {
interface named id "port:runtime:named" : Named;
};
}
`, {
source: {
repository: "https://repos.quixos.org/quixos-test/package-runtime.git",
commit: "6".repeat(40),
},
});
assert.equal(result.ok, false);
if (result.ok) return;
assert.ok(result.diagnostics.some((entry) =>
entry.code === "nominal-interface-port" && entry.message.includes("import interface Named")
));
});
+20 -1
View File
@@ -92,7 +92,7 @@ test("the representative v1 workspace compiles to native and package plans", ()
summary.dependencies.map((entry) => [entry.port.id, entry.binding.kind]), summary.dependencies.map((entry) => [entry.port.id, entry.binding.kind]),
[ [
[fixtureId.titlePort, "state"], [fixtureId.titlePort, "state"],
[fixtureId.namedPort, "receiver-interface"], [fixtureId.namedPort, "interface"],
[fixtureId.personPort, "constructor"], [fixtureId.personPort, "constructor"],
], ],
); );
@@ -164,6 +164,25 @@ test("private attachments are visible only to their owning conformance", () => {
expectIssue(workspace, "private-attachment-access"); expectIssue(workspace, "private-attachment-access");
}); });
test("related-object dependency views cannot traverse another conformance's private edge", () => {
const workspace = makeValidCapabilityWorkspace();
const packageBinding = conformance(
workspace,
fixtureId.projectSummaryConformance,
).operationBindings[0]!.binding;
assert.equal(packageBinding.kind, "package");
if (packageBinding.kind !== "package") return;
const named = packageBinding.dependencies.find(
(dependency) => dependency.portId === fixtureId.namedPort,
);
assert.ok(named && named.binding.kind === "interface");
named.binding.via = {
edgeTypeId: fixtureId.projectOwner,
projectionId: fixtureId.projectOwnerProjection,
};
expectIssue(workspace, "private-attachment-access");
});
test("native state and edge providers must match operation shape", () => { test("native state and edge providers must match operation shape", () => {
const stateWorkspace = makeValidCapabilityWorkspace(); const stateWorkspace = makeValidCapabilityWorkspace();
const state = conformance( const state = conformance(
+121 -5
View File
@@ -4,7 +4,15 @@ import {
capabilityId, capabilityId,
type WorkspaceRevision, type WorkspaceRevision,
} from "../../src/capability-model/index.js"; } from "../../src/capability-model/index.js";
import { compileCapabilitySource } from "../../src/capability-language/index.js"; import {
compileCapabilityResourceSource,
compileCapabilitySource,
type CapabilityImportEnvironment,
} from "../../src/capability-language/index.js";
import type {
InterfaceRevision,
PackageRevision,
} from "../../src/capability-model/index.js";
export const fixtureId = { export const fixtureId = {
workspace: capabilityId.workspace("workspace:todo"), workspace: capabilityId.workspace("workspace:todo"),
@@ -62,11 +70,119 @@ export const capabilityFixtureSource = readFileSync(
"utf8", "utf8",
); );
export const makeValidCapabilityWorkspace = (): WorkspaceRevision => { const resourceSource = (name: string) => readFileSync(
const result = compileCapabilitySource( resolve(process.cwd(), "test/fixtures", name),
capabilityFixtureSource, "utf8",
capabilityFixturePath, );
export const capabilityResourceSources = {
named: resourceSource("named.interface.qx"),
owned: resourceSource("owned.interface.qx"),
summary: resourceSource("summary.interface.qx"),
todo: resourceSource("todo.package.qx"),
} as const;
const source = (repository: string, commit: string) => ({ repository, commit });
const interfaceRevision = (
resource: { kind: "interface"; revision: InterfaceRevision } |
{ kind: "package"; revision: PackageRevision },
) => {
if (resource.kind !== "interface") throw new Error("Expected interface fixture");
return resource.revision;
};
const packageRevision = (
resource: { kind: "interface"; revision: InterfaceRevision } |
{ kind: "package"; revision: PackageRevision },
) => {
if (resource.kind !== "package") throw new Error("Expected package fixture");
return resource.revision;
};
export const compileCapabilityFixture = (overrides: Partial<{
workspace: string;
named: string;
owned: string;
summary: string;
todo: string;
}> = {}) => {
const named = compileCapabilityResourceSource(
overrides.named ?? capabilityResourceSources.named,
{
source: source(
"https://repos.quixos.org/quixos-todo/interface-named.git",
"2".repeat(40),
),
fileName: "named.interface.qx",
},
); );
if (!named.ok) return named;
const namedRevision = interfaceRevision(named.resource);
const namedEnvironment: CapabilityImportEnvironment = {
interfaces: new Map([["Named", namedRevision]]),
interfaceClosure: [namedRevision],
};
const owned = compileCapabilityResourceSource(
overrides.owned ?? capabilityResourceSources.owned,
{
source: source(
"https://repos.quixos.org/quixos-todo/interface-owned.git",
"3".repeat(40),
),
fileName: "owned.interface.qx",
environment: namedEnvironment,
},
);
if (!owned.ok) return owned;
const ownedRevision = interfaceRevision(owned.resource);
const summary = compileCapabilityResourceSource(
overrides.summary ?? capabilityResourceSources.summary,
{
source: source(
"https://repos.quixos.org/quixos-todo/interface-summary.git",
"4".repeat(40),
),
fileName: "summary.interface.qx",
},
);
if (!summary.ok) return summary;
const summaryRevision = interfaceRevision(summary.resource);
const todo = compileCapabilityResourceSource(
overrides.todo ?? capabilityResourceSources.todo,
{
source: source(
"https://repos.quixos.org/quixos-todo/package-todo-runtime.git",
"5".repeat(40),
),
fileName: "todo.package.qx",
environment: namedEnvironment,
},
);
if (!todo.ok) return todo;
const todoRevision = packageRevision(todo.resource);
return compileCapabilitySource(
overrides.workspace ?? capabilityFixtureSource,
capabilityFixturePath,
{
interfaces: new Map([
["Named", namedRevision],
["Owned", ownedRevision],
["Summary", summaryRevision],
]),
packages: new Map([["TodoRuntime", todoRevision]]),
interfaceClosure: [
namedRevision,
ownedRevision,
summaryRevision,
],
packageClosure: [todoRevision],
},
);
};
export const makeValidCapabilityWorkspace = (): WorkspaceRevision => {
const result = compileCapabilityFixture();
if (!result.ok) { if (!result.ok) {
throw new Error( throw new Error(
result.diagnostics result.diagnostics
+10
View File
@@ -0,0 +1,10 @@
import interface Named;
external atom Project id "atom:project";
external atom ProjectComponent id "atom:project-component";
package ComponentRuntime id "package:component-runtime" revision "package:component-runtime@1" {
constructor createComponent id "export:component-runtime:create-component" constructs ProjectComponent : atom-ref<Project>;
operation propsGet id "export:component-runtime:props-get" : unit -> string mode call receiver atom ProjectComponent requires {
interface project id "port:component:project" : Named;
};
}
+7
View File
@@ -0,0 +1,7 @@
import interface ReactComponent;
interface HasReactComponent id "interface:org.quixos.web-studio.has-react-component" revision "interface:org.quixos.web-studio.has-react-component@1" {
relation component id "member:org.quixos.web-studio.has-react-component:component" : optional-one interface ReactComponent {
resolve id "operation:org.quixos.web-studio.has-react-component:component:resolve";
}
}
+7
View File
@@ -0,0 +1,7 @@
interface Named id "interface:named" revision "interface:named@1" {
value name id "member:named:name" : string {
get id "operation:named:name:get";
set id "operation:named:name:set";
watch start id "operation:named:name:watch-start" stop id "operation:named:name:watch-stop";
}
}
+10
View File
@@ -0,0 +1,10 @@
import interface Named;
interface Owned id "interface:owned" revision "interface:owned@1" {
relation owner id "member:owned:owner" : exactly-one interface Named {
resolve id "operation:owned:owner:resolve";
connect id "operation:owned:owner:connect";
disconnect id "operation:owned:owner:disconnect";
watch start id "operation:owned:owner:watch-start" stop id "operation:owned:owner:watch-stop";
}
}
+5
View File
@@ -0,0 +1,5 @@
interface ReactComponent id "interface:org.quixos.web-studio.react-component" revision "interface:org.quixos.web-studio.react-component@1" {
value props id "member:org.quixos.web-studio.react-component:props" : string {
get id "operation:org.quixos.web-studio.react-component:props:get";
}
}
+5
View File
@@ -0,0 +1,5 @@
interface Summary id "interface:summary" revision "interface:summary@1" {
value summary id "member:summary:summary" : string {
get id "operation:summary:summary:get";
}
}
+4 -44
View File
@@ -2,50 +2,10 @@ workspace Todo id "workspace:todo" revision "workspace:todo@1" commit "111111111
atom Project id "atom:project" doc "A project containing work."; atom Project id "atom:project" doc "A project containing work.";
atom Person id "atom:person"; atom Person id "atom:person";
interface Named id "interface:named" revision "interface:named@1" source { import interface Named;
repository "https://repos.quixos.org/quixos-todo/interface-named.git"; import interface Owned;
commit "2222222222222222222222222222222222222222"; import interface Summary;
} { import package TodoRuntime;
value name id "member:named:name" : string {
get id "operation:named:name:get";
set id "operation:named:name:set";
watch start id "operation:named:name:watch-start" stop id "operation:named:name:watch-stop";
}
}
interface Owned id "interface:owned" revision "interface:owned@1" source {
repository "https://repos.quixos.org/quixos-todo/interface-owned.git";
commit "3333333333333333333333333333333333333333";
} {
relation owner id "member:owned:owner" : exactly-one interface Named {
resolve id "operation:owned:owner:resolve";
connect id "operation:owned:owner:connect";
disconnect id "operation:owned:owner:disconnect";
watch start id "operation:owned:owner:watch-start" stop id "operation:owned:owner:watch-stop";
}
}
interface Summary id "interface:summary" revision "interface:summary@1" source {
repository "https://repos.quixos.org/quixos-todo/interface-summary.git";
commit "4444444444444444444444444444444444444444";
} {
value summary id "member:summary:summary" : string {
get id "operation:summary:summary:get";
}
}
package TodoRuntime id "package:todo-runtime" revision "package:todo-runtime@1" source {
repository "https://repos.quixos.org/quixos-todo/package-todo-runtime.git";
commit "5555555555555555555555555555555555555555";
} {
operation summaryGet id "export:todo-runtime:summary-get" : unit -> string
mode call receiver interfaces [Named] requires {
state title id "port:summary:title" : string [read];
interface named id "port:summary:named" : Named;
constructor person id "port:summary:person" : Person;
};
constructor createPerson id "export:todo-runtime:create-person" constructs Person : unit;
}
shared state ProjectTitle id "slot:project:title" on Project : string shared state ProjectTitle id "slot:project:title" on Project : string
policy optimistic-register default "Untitled project"; policy optimistic-register default "Untitled project";
+12
View File
@@ -0,0 +1,12 @@
import interface Named;
external atom Person id "atom:person";
package TodoRuntime id "package:todo-runtime" revision "package:todo-runtime@1" {
operation summaryGet id "export:todo-runtime:summary-get" : unit -> string
mode call receiver interfaces [Named] requires {
state title id "port:summary:title" : string [read];
interface named id "port:summary:named" : Named;
constructor person id "port:summary:person" : Person;
};
constructor createPerson id "export:todo-runtime:create-person" constructs Person : unit;
}
+12 -30
View File
@@ -2,34 +2,10 @@ workspace WebStudioFixture id "workspace:web-studio-fixture" revision "workspace
atom Project id "atom:project"; atom Project id "atom:project";
atom ProjectComponent id "atom:project-component"; atom ProjectComponent id "atom:project-component";
interface ReactComponent id "interface:org.quixos.web-studio.react-component" revision "interface:org.quixos.web-studio.react-component@1" source { import interface Named;
repository "https://repos.quixos.org/org-quixos-web-studio/interface-react-component.git"; import interface ReactComponent;
commit "2222222222222222222222222222222222222222"; import interface HasReactComponent;
} { import package ComponentRuntime;
value props id "member:org.quixos.web-studio.react-component:props" : string {
get id "operation:org.quixos.web-studio.react-component:props:get";
}
}
interface HasReactComponent id "interface:org.quixos.web-studio.has-react-component" revision "interface:org.quixos.web-studio.has-react-component@1" source {
repository "https://repos.quixos.org/org-quixos-web-studio/interface-has-react-component.git";
commit "3333333333333333333333333333333333333333";
} {
relation component id "member:org.quixos.web-studio.has-react-component:component" : optional-one interface ReactComponent {
resolve id "operation:org.quixos.web-studio.has-react-component:component:resolve";
}
}
package ComponentRuntime id "package:component-runtime" revision "package:component-runtime@1" source {
repository "https://repos.quixos.org/quixos-test/package-component-runtime.git";
commit "4444444444444444444444444444444444444444";
} {
constructor createComponent id "export:component-runtime:create-component" constructs ProjectComponent : atom-ref<Project>;
operation propsGet id "export:component-runtime:props-get" : unit -> string mode call receiver atom ProjectComponent requires {
edge subject id "port:component:subject" : exactly-one atom Project [resolve];
state projectName id "port:component:project-name" : string [read];
};
}
shared state ProjectName id "slot:project:name" on Project : string shared state ProjectName id "slot:project:name" on Project : string
policy optimistic-register default "Untitled project"; policy optimistic-register default "Untitled project";
@@ -38,14 +14,20 @@ workspace WebStudioFixture id "workspace:web-studio-fixture" revision "workspace
atom Project projection component id "projection:project:component" optional-one; atom Project projection component id "projection:project:component" optional-one;
} }
conform Project as Named {
bind name.get to state ProjectName.read;
bind name.set to state ProjectName.write;
bind name.watch-start to state ProjectName.watch-start;
bind name.watch-stop to state ProjectName.watch-stop;
}
conform Project as HasReactComponent { conform Project as HasReactComponent {
bind component.resolve to edge ProjectComponentEdge.component.resolve; bind component.resolve to edge ProjectComponentEdge.component.resolve;
materialize component if absent using constructor ProjectComponent via edge ProjectComponentEdge.subject; materialize component if absent using constructor ProjectComponent via edge ProjectComponentEdge.subject;
} }
conform ProjectComponent as ReactComponent { conform ProjectComponent as ReactComponent {
bind props.get to package ComponentRuntime.propsGet with { bind props.get to package ComponentRuntime.propsGet with {
subject to edge ProjectComponentEdge.subject; project to interface Named via edge ProjectComponentEdge.subject;
projectName to state ProjectName via edge ProjectComponentEdge.subject;
}; };
} }
+156
View File
@@ -1,9 +1,16 @@
import assert from "node:assert/strict"; import assert from "node:assert/strict";
import { mkdtemp, mkdir, rm, symlink, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import test from "node:test"; import test from "node:test";
import { import {
formatQuixosLock, formatQuixosLock,
formatQuixosLockDocument,
loadQuixosLock,
nixGitInput, nixGitInput,
parseQuixosLock, parseQuixosLock,
parseQuixosLockDocument,
resolveQuixosLock,
retentionTagForCommit, retentionTagForCommit,
} from "../src/resource-lock/index.js"; } from "../src/resource-lock/index.js";
@@ -92,3 +99,152 @@ test("rejects mutable revisions, embedded credentials, and duplicate bindings",
]), ]),
); );
}); });
test("resolves root-relative lock fragments into one deterministic resource closure", async () => {
const root = `quixos-lock version 1 {
quixos source {
repository "https://gitea.example/quixos/quixos.git";
commit "${quixosCommit}";
}
import "locks/web-studio.lock";
import "locks/domain.lock";
package RootRuntime source {
repository "https://repos.example/alice/package-root.git";
commit "${packageCommit}";
}
}`;
const sources = new Map([
["locks/web-studio.lock", `quixos-lock fragment version 1 {
import "locks/shared.lock";
interface Placeable source {
repository "https://repos.example/alice/interface-placeable.git";
commit "${namedCommit}";
}
}`],
["locks/shared.lock", `quixos-lock fragment version 1 {
interface Named source {
repository "https://repos.example/alice/interface-named.git";
commit "${namedCommit}";
}
}`],
["locks/domain.lock", `quixos-lock fragment version 1 {
package TodoRuntime source {
repository "https://repos.example/alice/package-todo.git";
commit "${packageCommit}";
}
}`],
]);
const result = await resolveQuixosLock(root, async (relativePath) => {
const source = sources.get(relativePath);
if (!source) throw new Error("missing fixture");
return source;
});
assert.equal(result.ok, true);
if (!result.ok) return;
assert.deepEqual(result.lock.sourceFiles, [
"quixos.lock",
"locks/web-studio.lock",
"locks/shared.lock",
"locks/domain.lock",
]);
assert.deepEqual(result.lock.resources.map(({ kind, binding }) => ({ kind, binding })), [
{ kind: "package", binding: "RootRuntime" },
{ kind: "interface", binding: "Placeable" },
{ kind: "interface", binding: "Named" },
{ kind: "package", binding: "TodoRuntime" },
]);
});
test("lock fragments format canonically and cannot redeclare the Quixos source", () => {
const document = {
kind: "fragment" as const,
formatVersion: 1 as const,
imports: ["locks/shared.lock"],
resources: [{
kind: "interface" as const,
binding: "Named",
source: {
resolver: "git" as const,
repository: "https://repos.example/alice/interface-named.git",
commit: namedCommit,
},
}],
};
assert.deepEqual(parseQuixosLockDocument(formatQuixosLockDocument(document)), {
ok: true,
document,
diagnostics: [],
});
const invalid = parseQuixosLockDocument(`quixos-lock fragment version 1 {
quixos source {
repository "https://gitea.example/quixos/quixos.git";
commit "${quixosCommit}";
}
}`, "bad.lock");
assert.equal(invalid.ok, false);
if (!invalid.ok) assert.equal(invalid.diagnostics[0]?.code, "fragment-has-quixos-source");
});
test("lock imports reject traversal, cycles, root documents, and cross-file binding collisions", async () => {
const invalidPath = parseQuixosLockDocument(`quixos-lock fragment version 1 {
import "../outside.lock";
}`, "bad-path.lock");
assert.equal(invalidPath.ok, false);
if (!invalidPath.ok) assert.equal(invalidPath.diagnostics[0]?.code, "invalid-import-path");
const root = `quixos-lock version 1 {
quixos source {
repository "https://gitea.example/quixos/quixos.git";
commit "${quixosCommit}";
}
import "a.lock";
import "root-again.lock";
interface Named source {
repository "https://repos.example/alice/interface-named.git";
commit "${namedCommit}";
}
}`;
const sources = new Map([
["a.lock", `quixos-lock fragment version 1 {
import "b.lock";
interface Named source {
repository "https://repos.example/alice/interface-named-copy.git";
commit "${namedCommit}";
}
}`],
["b.lock", `quixos-lock fragment version 1 { import "a.lock"; }`],
["root-again.lock", root],
]);
const result = await resolveQuixosLock(root, async (relativePath) => sources.get(relativePath) ?? "");
assert.equal(result.ok, false);
if (!result.ok) {
assert.deepEqual(new Set(result.diagnostics.map(({ code }) => code)), new Set([
"duplicate-resource-binding",
"import-cycle",
"imported-root-lock",
]));
}
});
test("file loading rejects a symlink in any import path component", async (context) => {
const directory = await mkdtemp(path.join(os.tmpdir(), "quixos-lock-test-"));
context.after(() => rm(directory, { recursive: true, force: true }));
const outside = path.join(directory, "outside");
await mkdir(outside);
await writeFile(path.join(outside, "fragment.lock"), "quixos-lock fragment version 1 {}\n");
await symlink(outside, path.join(directory, "linked"), "dir");
await writeFile(path.join(directory, "quixos.lock"), `quixos-lock version 1 {
quixos source {
repository "https://gitea.example/quixos/quixos.git";
commit "${quixosCommit}";
}
import "linked/fragment.lock";
}`);
const result = await loadQuixosLock(path.join(directory, "quixos.lock"));
assert.equal(result.ok, false);
if (!result.ok) {
assert.equal(result.diagnostics[0]?.code, "import-read-failed");
assert.match(result.diagnostics[0]?.message ?? "", /symbolic links/);
}
});
+2
View File
@@ -54,6 +54,8 @@ __metadata:
quixos-capability-compile: dist/src/capability-language/cli.js quixos-capability-compile: dist/src/capability-language/cli.js
quixos-descriptor-check: dist/src/descriptor-check.js quixos-descriptor-check: dist/src/descriptor-check.js
quixos-lock-check: dist/src/resource-lock/cli.js quixos-lock-check: dist/src/resource-lock/cli.js
quixos-resource-compile: dist/src/capability-language/resource-cli.js
quixos-workspace-compile: dist/src/capability-language/workspace-cli.js
languageName: unknown languageName: unknown
linkType: soft linkType: soft