Compare commits

..

8 Commits

Author SHA1 Message Date
Quixos Subtree Publisher fd6fee133d Publish quixos-protocol from b384206b9c01a9ac50030a583d028b71291bc8c5 2026-09-06 07:07:06 +00:00
timothy f5ced64533 Build workspace agent, capability graph, and versioned cutovers 2026-09-06 00:07:06 -07:00
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
Quixos Subtree Publisher fd6160ec67 Publish quixos-protocol from 3ea7dcc6a38ba0c5ddc099b966d48c5aeae732b1 2026-09-05 04:04:43 +00:00
timothy fd039f095b Introduce persisted Web Studio component capabilities 2026-09-04 21:04:43 -07:00
timothy f4987093f6 Introduce repository-backed capability workspaces
- define and validate the capability and resource-lock languages
- provision workspace source repositories through Central Gitea
- build package runtimes from pinned standalone sources
- replace legacy schema compilation with workspace persistence plans
- add stable optimistic registers and Automerge CRDT documents
- modernize TypeScript/Nix package builds and runtime activation readiness
2026-09-04 19:08:10 -07:00
54 changed files with 6247 additions and 2379 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": "4af89fa7c703d9fecf36b4e97b76658a503dd5aa", "sourceCommit": "b384206b9c01a9ac50030a583d028b71291bc8c5",
"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"
+80 -12
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,69 @@ 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 A resource lock is not a miniature workspace: it contains only the exact
interfaces and packages. The v1 Git source is deliberately only a repository Quixos commit that resource was authored against plus its dependency list.
URL and full commit ID; the publisher-owned reachability tag and Nix fetch It also pins exact Git sources for interfaces and packages named by that
details are derived from those values. resource's own manifest. Resource Git sources are deliberately only a
repository URL and full commit ID; the publisher-owned reachability tag and
Nix fetch details are derived from those values.
A workspace root additionally records its Quixos selection policy and ref.
Its `commit` is the exact compatibility baseline shared by the resource graph,
not necessarily the runtime candidate. `pinned` requires the ref, baseline,
and candidate to be one commit. `track-development` lets Central resolve the
named development ref to a newer candidate while preserving the authored
baseline. `track-release` is reserved for compatibility-filtered release-line
advancement and is not implemented yet.
```sh ```sh
quixos-lock-check quixos.lock quixos-lock-check quixos.lock
qx resource publish quixos-resource-compile \
--root . --kind package \
--repository https://repos.quixos.org/example/package-example.git \
--commit 1111111111111111111111111111111111111111 \
--checkout-root /tmp/quixos-resource-dependencies
qx-workspace 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";
policy track-development;
ref "dev/alice/main";
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 +126,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
''; '';
+41 -16
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
; ;
@@ -180,6 +193,11 @@ conformanceDecl
conformanceItem conformanceItem
: PRIVATE attachmentDecl : PRIVATE attachmentDecl
| operationBindingDecl | operationBindingDecl
| relationshipMaterializationDecl
;
relationshipMaterializationDecl
: MATERIALIZE identifier IF ABSENT USING CONSTRUCTOR identifier VIA EDGE identifier DOT identifier SEMI
; ;
operationBindingDecl operationBindingDecl
@@ -230,9 +248,9 @@ dependencyBindingBlock
; ;
dependencyBinding dependencyBinding
: identifier TO STATE identifier SEMI : identifier TO STATE identifier (VIA EDGE identifier DOT identifier)? SEMI
| identifier TO 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
; ;
@@ -302,6 +320,8 @@ stringLiteral
; ;
WORKSPACE: 'workspace'; WORKSPACE: 'workspace';
IMPORT: 'import';
EXTERNAL: 'external';
ATOM: 'atom'; ATOM: 'atom';
INTERFACE: 'interface'; INTERFACE: 'interface';
INTERFACES: 'interfaces'; INTERFACES: 'interfaces';
@@ -322,6 +342,11 @@ STATE: 'state';
EDGE: 'edge'; EDGE: 'edge';
PROJECTION: 'projection'; PROJECTION: 'projection';
WITH: 'with'; WITH: 'with';
USING: 'using';
VIA: 'via';
MATERIALIZE: 'materialize';
IF: 'if';
ABSENT: 'absent';
ON: 'on'; ON: 'on';
POLICY: 'policy'; POLICY: 'policy';
DEFAULT: 'default'; DEFAULT: 'default';
+28 -2
View File
@@ -1,17 +1,22 @@
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
: QUIXOS SOURCE sourceBlock : QUIXOS SOURCE quixosSourceBlock
; ;
resourceEntry resourceEntry
: resourceKind identifier SOURCE sourceBlock : resourceKind identifier SOURCE sourceBlock
; ;
importEntry
: IMPORT stringLiteral SEMI
;
resourceKind resourceKind
: INTERFACE : INTERFACE
| PACKAGE | PACKAGE
@@ -24,6 +29,20 @@ sourceBlock
RBRACE RBRACE
; ;
quixosSourceBlock
: LBRACE
REPOSITORY stringLiteral SEMI
(POLICY sourcePolicy SEMI REF stringLiteral SEMI)?
COMMIT stringLiteral SEMI
RBRACE
;
sourcePolicy
: PINNED
| TRACK_RELEASE
| TRACK_DEVELOPMENT
;
identifier identifier
: IDENTIFIER : IDENTIFIER
; ;
@@ -33,6 +52,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 +60,12 @@ INTERFACE: 'interface';
PACKAGE: 'package'; PACKAGE: 'package';
REPOSITORY: 'repository'; REPOSITORY: 'repository';
COMMIT: 'commit'; COMMIT: 'commit';
POLICY: 'policy';
REF: 'ref';
PINNED: 'pinned';
TRACK_RELEASE: 'track-release';
TRACK_DEVELOPMENT: 'track-development';
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"
}, },
+15
View File
@@ -11,6 +11,7 @@ service OrchestratorRuntime {
rpc InvokeCapability(InvokeCapabilityRequest) returns (InvokeCapabilityResponse); rpc InvokeCapability(InvokeCapabilityRequest) returns (InvokeCapabilityResponse);
rpc WatchCapability(WatchCapabilityRequest) returns (stream WatchCapabilityEvent); rpc WatchCapability(WatchCapabilityRequest) returns (stream WatchCapabilityEvent);
rpc ConstructObject(ConstructObjectRequest) returns (ConstructObjectResponse); rpc ConstructObject(ConstructObjectRequest) returns (ConstructObjectResponse);
rpc ResolveOrConstructRelatedObject(ResolveOrConstructRelatedObjectRequest) returns (ResolveOrConstructRelatedObjectResponse);
rpc GetWorkspace(GetWorkspaceRequest) returns (GetWorkspaceResponse); rpc GetWorkspace(GetWorkspaceRequest) returns (GetWorkspaceResponse);
rpc ListPackageDescriptors(ListPackageDescriptorsRequest) returns (ListPackageDescriptorsResponse); rpc ListPackageDescriptors(ListPackageDescriptorsRequest) returns (ListPackageDescriptorsResponse);
rpc ListPackageRuntimes(ListPackageRuntimesRequest) returns (ListPackageRuntimesResponse); rpc ListPackageRuntimes(ListPackageRuntimesRequest) returns (ListPackageRuntimesResponse);
@@ -24,10 +25,23 @@ message ConstructObjectRequest {
} }
message ConstructObjectResponse { camino.CaminoObject object = 1; } message ConstructObjectResponse { camino.CaminoObject object = 1; }
message ResolveOrConstructRelatedObjectRequest {
string object_id = 1;
string interface_revision_id = 2;
string member_id = 3;
}
message ResolveOrConstructRelatedObjectResponse {
camino.CaminoObject object = 1;
bool constructed = 2;
}
message InvokeCapabilityRequest { 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;
@@ -35,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 {
+4 -1
View File
@@ -17,9 +17,12 @@ 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
// select a related object explicitly before the package runtime starts.
string object_id = 6;
} }
message EdgeDependency { message EdgeDependency {
+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 {
+365
View File
@@ -0,0 +1,365 @@
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.policy) {
throw new Error(
`${locked.kind} ${locked.binding} lock declares workspace Quixos policy ` +
`${lockResult.lock.quixos.policy}; resource locks may only declare their exact authored-against commit`,
);
}
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,183 +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
ON=22 PROJECTION=22
POLICY=23 WITH=23
DEFAULT=24 USING=24
SOURCE=25 VIA=25
REPOSITORY=26 MATERIALIZE=26
COMMIT=27 IF=27
REVISION=28 ABSENT=28
ID=29 ON=29
DOC=30 POLICY=30
MODE=31 DEFAULT=31
EMITS=32 SOURCE=32
RECEIVER=33 REPOSITORY=33
REQUIRES=34 COMMIT=34
ANY=35 REVISION=35
GET=36 ID=36
SET=37 DOC=37
WATCH=38 MODE=38
START=39 EMITS=39
STOP=40 RECEIVER=40
READ=41 REQUIRES=41
WRITE=42 ANY=42
RESOLVE=43 GET=43
CONNECT=44 SET=44
DISCONNECT=45 WATCH=45
CALL=46 START=46
WATCH_START=47 STOP=47
WATCH_STOP=48 READ=48
SUBSCRIBE=49 WRITE=49
UNSUBSCRIBE=50 RESOLVE=50
OPTIMISTIC_REGISTER=51 CONNECT=51
CRDT=52 DISCONNECT=52
OPTIONAL_ONE=53 CALL=53
EXACTLY_ONE=54 WATCH_START=54
MANY_UNIQUE=55 WATCH_STOP=55
MANY=56 SUBSCRIBE=56
ORDERED=57 UNSUBSCRIBE=57
UNIT=58 OPTIMISTIC_REGISTER=58
WATCH_HANDLE=59 CRDT=59
MESSAGE=60 OPTIONAL_ONE=60
ATOM_REF=61 EXACTLY_ONE=61
INTERFACE_REF=62 MANY_UNIQUE=62
OPTIONAL=63 MANY=63
LIST=64 ORDERED=64
BOOL=65 UNIT=65
BYTES=66 WATCH_HANDLE=66
DOUBLE=67 MESSAGE=67
INT32=68 ATOM_REF=68
INT64=69 INTERFACE_REF=69
STRING=70 OPTIONAL=70
UINT32=71 LIST=71
UINT64=72 BOOL=72
TRUE=73 BYTES=73
FALSE=74 DOUBLE=74
NULL=75 INT32=75
ARROW=76 INT64=76
COLON=77 STRING=77
SEMI=78 UINT32=78
COMMA=79 UINT64=79
DOT=80 TRUE=80
LBRACE=81 FALSE=81
RBRACE=82 NULL=82
LBRACK=83 ARROW=83
RBRACK=84 COLON=84
LPAREN=85 SEMI=85
RPAREN=86 COMMA=86
LT=87 DOT=87
GT=88 LBRACE=88
INTEGER=89 RBRACE=89
JSON_NUMBER=90 LBRACK=90
IDENTIFIER=91 RBRACK=91
STRING_LITERAL=92 LPAREN=92
LINE_COMMENT=93 RPAREN=93
BLOCK_COMMENT=94 LT=94
WS=95 GT=95
INTEGER=96
JSON_NUMBER=97
IDENTIFIER=98
STRING_LITERAL=99
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
'on'=22 'projection'=22
'policy'=23 'with'=23
'default'=24 'using'=24
'source'=25 'via'=25
'repository'=26 'materialize'=26
'commit'=27 'if'=27
'revision'=28 'absent'=28
'id'=29 'on'=29
'doc'=30 'policy'=30
'mode'=31 'default'=31
'emits'=32 'source'=32
'receiver'=33 'repository'=33
'requires'=34 'commit'=34
'any'=35 'revision'=35
'get'=36 'id'=36
'set'=37 'doc'=37
'watch'=38 'mode'=38
'start'=39 'emits'=39
'stop'=40 'receiver'=40
'read'=41 'requires'=41
'write'=42 'any'=42
'resolve'=43 'get'=43
'connect'=44 'set'=44
'disconnect'=45 'watch'=45
'call'=46 'start'=46
'watch-start'=47 'stop'=47
'watch-stop'=48 'read'=48
'subscribe'=49 'write'=49
'unsubscribe'=50 'resolve'=50
'optimistic-register'=51 'connect'=51
'crdt'=52 'disconnect'=52
'optional-one'=53 'call'=53
'exactly-one'=54 'watch-start'=54
'many-unique'=55 'watch-stop'=55
'many'=56 'subscribe'=56
'ordered'=57 'unsubscribe'=57
'unit'=58 'optimistic-register'=58
'watch-handle'=59 'crdt'=59
'message'=60 'optional-one'=60
'atom-ref'=61 'exactly-one'=61
'interface-ref'=62 'many-unique'=62
'optional'=63 'many'=63
'list'=64 'ordered'=64
'bool'=65 'unit'=65
'bytes'=66 'watch-handle'=66
'double'=67 'message'=67
'int32'=68 'atom-ref'=68
'int64'=69 'interface-ref'=69
'string'=70 'optional'=70
'uint32'=71 'list'=71
'uint64'=72 'bool'=72
'true'=73 'bytes'=73
'false'=74 'double'=74
'null'=75 'int32'=75
'->'=76 'int64'=76
':'=77 'string'=77
';'=78 'uint32'=78
','=79 'uint64'=79
'.'=80 'true'=80
'{'=81 'false'=81
'}'=82 'null'=82
'['=83 '->'=83
']'=84 ':'=84
'('=85 ';'=85
')'=86 ','=86
'<'=87 '.'=87
'>'=88 '{'=88
'}'=89
'['=90
']'=91
'('=92
')'=93
'<'=94
'>'=95
File diff suppressed because one or more lines are too long
@@ -1,183 +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
ON=22 PROJECTION=22
POLICY=23 WITH=23
DEFAULT=24 USING=24
SOURCE=25 VIA=25
REPOSITORY=26 MATERIALIZE=26
COMMIT=27 IF=27
REVISION=28 ABSENT=28
ID=29 ON=29
DOC=30 POLICY=30
MODE=31 DEFAULT=31
EMITS=32 SOURCE=32
RECEIVER=33 REPOSITORY=33
REQUIRES=34 COMMIT=34
ANY=35 REVISION=35
GET=36 ID=36
SET=37 DOC=37
WATCH=38 MODE=38
START=39 EMITS=39
STOP=40 RECEIVER=40
READ=41 REQUIRES=41
WRITE=42 ANY=42
RESOLVE=43 GET=43
CONNECT=44 SET=44
DISCONNECT=45 WATCH=45
CALL=46 START=46
WATCH_START=47 STOP=47
WATCH_STOP=48 READ=48
SUBSCRIBE=49 WRITE=49
UNSUBSCRIBE=50 RESOLVE=50
OPTIMISTIC_REGISTER=51 CONNECT=51
CRDT=52 DISCONNECT=52
OPTIONAL_ONE=53 CALL=53
EXACTLY_ONE=54 WATCH_START=54
MANY_UNIQUE=55 WATCH_STOP=55
MANY=56 SUBSCRIBE=56
ORDERED=57 UNSUBSCRIBE=57
UNIT=58 OPTIMISTIC_REGISTER=58
WATCH_HANDLE=59 CRDT=59
MESSAGE=60 OPTIONAL_ONE=60
ATOM_REF=61 EXACTLY_ONE=61
INTERFACE_REF=62 MANY_UNIQUE=62
OPTIONAL=63 MANY=63
LIST=64 ORDERED=64
BOOL=65 UNIT=65
BYTES=66 WATCH_HANDLE=66
DOUBLE=67 MESSAGE=67
INT32=68 ATOM_REF=68
INT64=69 INTERFACE_REF=69
STRING=70 OPTIONAL=70
UINT32=71 LIST=71
UINT64=72 BOOL=72
TRUE=73 BYTES=73
FALSE=74 DOUBLE=74
NULL=75 INT32=75
ARROW=76 INT64=76
COLON=77 STRING=77
SEMI=78 UINT32=78
COMMA=79 UINT64=79
DOT=80 TRUE=80
LBRACE=81 FALSE=81
RBRACE=82 NULL=82
LBRACK=83 ARROW=83
RBRACK=84 COLON=84
LPAREN=85 SEMI=85
RPAREN=86 COMMA=86
LT=87 DOT=87
GT=88 LBRACE=88
INTEGER=89 RBRACE=89
JSON_NUMBER=90 LBRACK=90
IDENTIFIER=91 RBRACK=91
STRING_LITERAL=92 LPAREN=92
LINE_COMMENT=93 RPAREN=93
BLOCK_COMMENT=94 LT=94
WS=95 GT=95
INTEGER=96
JSON_NUMBER=97
IDENTIFIER=98
STRING_LITERAL=99
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
'on'=22 'projection'=22
'policy'=23 'with'=23
'default'=24 'using'=24
'source'=25 'via'=25
'repository'=26 'materialize'=26
'commit'=27 'if'=27
'revision'=28 'absent'=28
'id'=29 'on'=29
'doc'=30 'policy'=30
'mode'=31 'default'=31
'emits'=32 'source'=32
'receiver'=33 'repository'=33
'requires'=34 'commit'=34
'any'=35 'revision'=35
'get'=36 'id'=36
'set'=37 'doc'=37
'watch'=38 'mode'=38
'start'=39 'emits'=39
'stop'=40 'receiver'=40
'read'=41 'requires'=41
'write'=42 'any'=42
'resolve'=43 'get'=43
'connect'=44 'set'=44
'disconnect'=45 'watch'=45
'call'=46 'start'=46
'watch-start'=47 'stop'=47
'watch-stop'=48 'read'=48
'subscribe'=49 'write'=49
'unsubscribe'=50 'resolve'=50
'optimistic-register'=51 'connect'=51
'crdt'=52 'disconnect'=52
'optional-one'=53 'call'=53
'exactly-one'=54 'watch-start'=54
'many-unique'=55 'watch-stop'=55
'many'=56 'subscribe'=56
'ordered'=57 'unsubscribe'=57
'unit'=58 'optimistic-register'=58
'watch-handle'=59 'crdt'=59
'message'=60 'optional-one'=60
'atom-ref'=61 'exactly-one'=61
'interface-ref'=62 'many-unique'=62
'optional'=63 'many'=63
'list'=64 'ordered'=64
'bool'=65 'unit'=65
'bytes'=66 'watch-handle'=66
'double'=67 'message'=67
'int32'=68 'atom-ref'=68
'int64'=69 'interface-ref'=69
'string'=70 'optional'=70
'uint32'=71 'list'=71
'uint64'=72 'bool'=72
'true'=73 'bytes'=73
'false'=74 'double'=74
'null'=75 'int32'=75
'->'=76 'int64'=76
':'=77 'string'=77
';'=78 'uint32'=78
','=79 'uint64'=79
'.'=80 'true'=80
'{'=81 'false'=81
'}'=82 'null'=82
'['=83 '->'=83
']'=84 ':'=84
'('=85 ';'=85
')'=86 ','=86
'<'=87 '.'=87
'>'=88 '{'=88
'}'=89
'['=90
']'=91
'('=92
')'=93
'<'=94
'>'=95
@@ -5,129 +5,138 @@ 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 ON = 22; public static readonly PROJECTION = 22;
public static readonly POLICY = 23; public static readonly WITH = 23;
public static readonly DEFAULT = 24; public static readonly USING = 24;
public static readonly SOURCE = 25; public static readonly VIA = 25;
public static readonly REPOSITORY = 26; public static readonly MATERIALIZE = 26;
public static readonly COMMIT = 27; public static readonly IF = 27;
public static readonly REVISION = 28; public static readonly ABSENT = 28;
public static readonly ID = 29; public static readonly ON = 29;
public static readonly DOC = 30; public static readonly POLICY = 30;
public static readonly MODE = 31; public static readonly DEFAULT = 31;
public static readonly EMITS = 32; public static readonly SOURCE = 32;
public static readonly RECEIVER = 33; public static readonly REPOSITORY = 33;
public static readonly REQUIRES = 34; public static readonly COMMIT = 34;
public static readonly ANY = 35; public static readonly REVISION = 35;
public static readonly GET = 36; public static readonly ID = 36;
public static readonly SET = 37; public static readonly DOC = 37;
public static readonly WATCH = 38; public static readonly MODE = 38;
public static readonly START = 39; public static readonly EMITS = 39;
public static readonly STOP = 40; public static readonly RECEIVER = 40;
public static readonly READ = 41; public static readonly REQUIRES = 41;
public static readonly WRITE = 42; public static readonly ANY = 42;
public static readonly RESOLVE = 43; public static readonly GET = 43;
public static readonly CONNECT = 44; public static readonly SET = 44;
public static readonly DISCONNECT = 45; public static readonly WATCH = 45;
public static readonly CALL = 46; public static readonly START = 46;
public static readonly WATCH_START = 47; public static readonly STOP = 47;
public static readonly WATCH_STOP = 48; public static readonly READ = 48;
public static readonly SUBSCRIBE = 49; public static readonly WRITE = 49;
public static readonly UNSUBSCRIBE = 50; public static readonly RESOLVE = 50;
public static readonly OPTIMISTIC_REGISTER = 51; public static readonly CONNECT = 51;
public static readonly CRDT = 52; public static readonly DISCONNECT = 52;
public static readonly OPTIONAL_ONE = 53; public static readonly CALL = 53;
public static readonly EXACTLY_ONE = 54; public static readonly WATCH_START = 54;
public static readonly MANY_UNIQUE = 55; public static readonly WATCH_STOP = 55;
public static readonly MANY = 56; public static readonly SUBSCRIBE = 56;
public static readonly ORDERED = 57; public static readonly UNSUBSCRIBE = 57;
public static readonly UNIT = 58; public static readonly OPTIMISTIC_REGISTER = 58;
public static readonly WATCH_HANDLE = 59; public static readonly CRDT = 59;
public static readonly MESSAGE = 60; public static readonly OPTIONAL_ONE = 60;
public static readonly ATOM_REF = 61; public static readonly EXACTLY_ONE = 61;
public static readonly INTERFACE_REF = 62; public static readonly MANY_UNIQUE = 62;
public static readonly OPTIONAL = 63; public static readonly MANY = 63;
public static readonly LIST = 64; public static readonly ORDERED = 64;
public static readonly BOOL = 65; public static readonly UNIT = 65;
public static readonly BYTES = 66; public static readonly WATCH_HANDLE = 66;
public static readonly DOUBLE = 67; public static readonly MESSAGE = 67;
public static readonly INT32 = 68; public static readonly ATOM_REF = 68;
public static readonly INT64 = 69; public static readonly INTERFACE_REF = 69;
public static readonly STRING = 70; public static readonly OPTIONAL = 70;
public static readonly UINT32 = 71; public static readonly LIST = 71;
public static readonly UINT64 = 72; public static readonly BOOL = 72;
public static readonly TRUE = 73; public static readonly BYTES = 73;
public static readonly FALSE = 74; public static readonly DOUBLE = 74;
public static readonly NULL = 75; public static readonly INT32 = 75;
public static readonly ARROW = 76; public static readonly INT64 = 76;
public static readonly COLON = 77; public static readonly STRING = 77;
public static readonly SEMI = 78; public static readonly UINT32 = 78;
public static readonly COMMA = 79; public static readonly UINT64 = 79;
public static readonly DOT = 80; public static readonly TRUE = 80;
public static readonly LBRACE = 81; public static readonly FALSE = 81;
public static readonly RBRACE = 82; public static readonly NULL = 82;
public static readonly LBRACK = 83; public static readonly ARROW = 83;
public static readonly RBRACK = 84; public static readonly COLON = 84;
public static readonly LPAREN = 85; public static readonly SEMI = 85;
public static readonly RPAREN = 86; public static readonly COMMA = 86;
public static readonly LT = 87; public static readonly DOT = 87;
public static readonly GT = 88; public static readonly LBRACE = 88;
public static readonly INTEGER = 89; public static readonly RBRACE = 89;
public static readonly JSON_NUMBER = 90; public static readonly LBRACK = 90;
public static readonly IDENTIFIER = 91; public static readonly RBRACK = 91;
public static readonly STRING_LITERAL = 92; public static readonly LPAREN = 92;
public static readonly LINE_COMMENT = 93; public static readonly RPAREN = 93;
public static readonly BLOCK_COMMENT = 94; public static readonly LT = 94;
public static readonly WS = 95; public static readonly GT = 95;
public static readonly INTEGER = 96;
public static readonly JSON_NUMBER = 97;
public static readonly IDENTIFIER = 98;
public static readonly STRING_LITERAL = 99;
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'", "'on'", "'bind'", "'to'", "'private'", "'shared'", "'state'", "'edge'",
"'policy'", "'default'", "'source'", "'repository'", "'commit'", "'projection'", "'with'", "'using'", "'via'", "'materialize'", "'if'",
"'revision'", "'id'", "'doc'", "'mode'", "'emits'", "'receiver'", "'absent'", "'on'", "'policy'", "'default'", "'source'", "'repository'",
"'requires'", "'any'", "'get'", "'set'", "'watch'", "'start'", "'stop'", "'commit'", "'revision'", "'id'", "'doc'", "'mode'", "'emits'",
"'read'", "'write'", "'resolve'", "'connect'", "'disconnect'", "'call'", "'receiver'", "'requires'", "'any'", "'get'", "'set'", "'watch'",
"'watch-start'", "'watch-stop'", "'subscribe'", "'unsubscribe'", "'start'", "'stop'", "'read'", "'write'", "'resolve'", "'connect'",
"'optimistic-register'", "'crdt'", "'optional-one'", "'exactly-one'", "'disconnect'", "'call'", "'watch-start'", "'watch-stop'", "'subscribe'",
"'many-unique'", "'many'", "'ordered'", "'unit'", "'watch-handle'", "'unsubscribe'", "'optimistic-register'", "'crdt'", "'optional-one'",
"'message'", "'atom-ref'", "'interface-ref'", "'optional'", "'list'", "'exactly-one'", "'many-unique'", "'many'", "'ordered'", "'unit'",
"'bool'", "'bytes'", "'double'", "'int32'", "'int64'", "'string'", "'watch-handle'", "'message'", "'atom-ref'", "'interface-ref'",
"'uint32'", "'uint64'", "'true'", "'false'", "'null'", "'->'", "':'", "'optional'", "'list'", "'bool'", "'bytes'", "'double'", "'int32'",
"';'", "','", "'.'", "'{'", "'}'", "'['", "']'", "'('", "')'", "'<'", "'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", "ON", "POLICY", "DEFAULT", "SOURCE", "REPOSITORY", "STATE", "EDGE", "PROJECTION", "WITH", "USING", "VIA", "MATERIALIZE",
"IF", "ABSENT", "ON", "POLICY", "DEFAULT", "SOURCE", "REPOSITORY",
"COMMIT", "REVISION", "ID", "DOC", "MODE", "EMITS", "RECEIVER", "COMMIT", "REVISION", "ID", "DOC", "MODE", "EMITS", "RECEIVER",
"REQUIRES", "ANY", "GET", "SET", "WATCH", "START", "STOP", "READ", "REQUIRES", "ANY", "GET", "SET", "WATCH", "START", "STOP", "READ",
"WRITE", "RESOLVE", "CONNECT", "DISCONNECT", "CALL", "WATCH_START", "WRITE", "RESOLVE", "CONNECT", "DISCONNECT", "CALL", "WATCH_START",
@@ -146,10 +155,11 @@ 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", "ON", "POLICY", "DEFAULT", "SOURCE", "REPOSITORY", "STATE", "EDGE", "PROJECTION", "WITH", "USING", "VIA", "MATERIALIZE",
"IF", "ABSENT", "ON", "POLICY", "DEFAULT", "SOURCE", "REPOSITORY",
"COMMIT", "REVISION", "ID", "DOC", "MODE", "EMITS", "RECEIVER", "COMMIT", "REVISION", "ID", "DOC", "MODE", "EMITS", "RECEIVER",
"REQUIRES", "ANY", "GET", "SET", "WATCH", "START", "STOP", "READ", "REQUIRES", "ANY", "GET", "SET", "WATCH", "START", "STOP", "READ",
"WRITE", "RESOLVE", "CONNECT", "DISCONNECT", "CALL", "WATCH_START", "WRITE", "RESOLVE", "CONNECT", "DISCONNECT", "CALL", "WATCH_START",
@@ -183,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,95,895,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,
@@ -197,310 +207,333 @@ export class QuixosCapabilityLexer extends antlr.Lexer {
71,2,72,7,72,2,73,7,73,2,74,7,74,2,75,7,75,2,76,7,76,2,77,7,77,2, 71,2,72,7,72,2,73,7,73,2,74,7,74,2,75,7,75,2,76,7,76,2,77,7,77,2,
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,1,0,1, 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,
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,2,1,2,1, 97,2,98,7,98,2,99,7,99,2,100,7,100,2,101,7,101,2,102,7,102,2,103,
2,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,3,1,3,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,
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, 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,
5,1,6,1,6,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, 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,
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,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, 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,9,1,9,1,9,1,10,1,10,1,10,1,10,1,10,1,10, 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,10,1,10,1,10,1,10,1,10,1,11,1,11,1,11,1,11,1,11,1,11,1,11,1,11, 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,
1,12,1,12,1,12,1,13,1,13,1,13,1,13,1,13,1,14,1,14,1,14,1,15,1,15, 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,
1,15,1,15,1,15,1,15,1,15,1,15,1,16,1,16,1,16,1,16,1,16,1,16,1,16, 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,
1,17,1,17,1,17,1,17,1,17,1,17,1,18,1,18,1,18,1,18,1,18,1,19,1,19, 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,
1,19,1,19,1,19,1,19,1,19,1,19,1,19,1,19,1,19,1,20,1,20,1,20,1,20, 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,
1,20,1,21,1,21,1,21,1,22,1,22,1,22,1,22,1,22,1,22,1,22,1,23,1,23, 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,
1,23,1,23,1,23,1,23,1,23,1,23,1,24,1,24,1,24,1,24,1,24,1,24,1,24, 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,
1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,26,1,26, 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,
1,26,1,26,1,26,1,26,1,26,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27, 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,
1,27,1,28,1,28,1,28,1,29,1,29,1,29,1,29,1,30,1,30,1,30,1,30,1,30, 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,
1,31,1,31,1,31,1,31,1,31,1,31,1,32,1,32,1,32,1,32,1,32,1,32,1,32, 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,
1,32,1,32,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,34,1,34, 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,
1,34,1,34,1,35,1,35,1,35,1,35,1,36,1,36,1,36,1,36,1,37,1,37,1,37, 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,
1,37,1,37,1,37,1,38,1,38,1,38,1,38,1,38,1,38,1,39,1,39,1,39,1,39, 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,
1,39,1,40,1,40,1,40,1,40,1,40,1,41,1,41,1,41,1,41,1,41,1,41,1,42, 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,
1,42,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,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,
1,43,1,43,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44, 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,
1,45,1,45,1,45,1,45,1,45,1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,46, 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,
1,46,1,46,1,46,1,46,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47, 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,
1,47,1,47,1,48,1,48,1,48,1,48,1,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,50,1,50,1,50,1,50,1,50,1,50,1,50,
1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,50,1,50, 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,
1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50, 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,
1,50,1,50,1,50,1,50,1,50,1,51,1,51,1,51,1,51,1,51,1,52,1,52,1,52, 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,
1,52,1,52,1,52,1,52,1,52,1,52,1,52,1,52,1,52,1,52,1,53,1,53,1,53, 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,
1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,54,1,54,1,54,1,54, 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,
1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,55,1,55,1,55,1,55,1,55, 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,
1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,57,1,57,1,57,1,57,1,57, 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,
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,58, 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,
1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,60,1,60,1,60,1,60,1,60, 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,
1,60,1,60,1,60,1,60,1,61,1,61,1,61,1,61,1,61,1,61,1,61,1,61,1,61, 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,
1,61,1,61,1,61,1,61,1,61,1,62,1,62,1,62,1,62,1,62,1,62,1,62,1,62, 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,
1,62,1,63,1,63,1,63,1,63,1,63,1,64,1,64,1,64,1,64,1,64,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,65,1,65,1,66,
1,65,1,65,1,65,1,65,1,66,1,66,1,66,1,66,1,66,1,66,1,66,1,67,1,67, 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,
1,67,1,67,1,67,1,67,1,68,1,68,1,68,1,68,1,68,1,68,1,69,1,69,1,69, 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,
1,69,1,69,1,69,1,69,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,71,1,71, 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,
1,71,1,71,1,71,1,71,1,71,1,72,1,72,1,72,1,72,1,72,1,73,1,73,1,73, 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,
1,73,1,73,1,73,1,74,1,74,1,74,1,74,1,74,1,75,1,75,1,75,1,76,1,76, 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,
1,77,1,77,1,78,1,78,1,79,1,79,1,80,1,80,1,81,1,81,1,82,1,82,1,83, 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,
1,83,1,84,1,84,1,85,1,85,1,86,1,86,1,87,1,87,1,88,3,88,796,8,88, 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,
1,88,4,88,799,8,88,11,88,12,88,800,1,89,3,89,804,8,89,1,89,1,89, 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,
1,89,5,89,809,8,89,10,89,12,89,812,9,89,3,89,814,8,89,1,89,1,89, 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,
4,89,818,8,89,11,89,12,89,819,3,89,822,8,89,1,89,1,89,3,89,826,8, 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,
89,1,89,4,89,829,8,89,11,89,12,89,830,3,89,833,8,89,1,90,1,90,5, 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,
90,837,8,90,10,90,12,90,840,9,90,1,91,1,91,1,91,5,91,845,8,91,10, 4,95,861,8,95,11,95,12,95,862,1,96,3,96,866,8,96,1,96,1,96,1,96,
91,12,91,848,9,91,1,91,1,91,1,92,1,92,1,92,1,92,1,92,1,92,1,92,1, 5,96,871,8,96,10,96,12,96,874,9,96,3,96,876,8,96,1,96,1,96,4,96,
92,3,92,860,8,92,1,93,1,93,1,94,1,94,1,94,1,94,5,94,868,8,94,10, 880,8,96,11,96,12,96,881,3,96,884,8,96,1,96,1,96,3,96,888,8,96,1,
94,12,94,871,9,94,1,94,1,94,1,95,1,95,1,95,1,95,5,95,879,8,95,10, 96,4,96,891,8,96,11,96,12,96,892,3,96,895,8,96,1,97,1,97,5,97,899,
95,12,95,882,9,95,1,95,1,95,1,95,1,95,1,95,1,96,4,96,890,8,96,11, 8,97,10,97,12,97,902,9,97,1,98,1,98,1,98,5,98,907,8,98,10,98,12,
96,12,96,891,1,96,1,96,1,880,0,97,1,1,3,2,5,3,7,4,9,5,11,6,13,7, 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,
15,8,17,9,19,10,21,11,23,12,25,13,27,14,29,15,31,16,33,17,35,18, 99,922,8,99,1,100,1,100,1,101,1,101,1,101,1,101,5,101,930,8,101,
37,19,39,20,41,21,43,22,45,23,47,24,49,25,51,26,53,27,55,28,57,29, 10,101,12,101,933,9,101,1,101,1,101,1,102,1,102,1,102,1,102,5,102,
59,30,61,31,63,32,65,33,67,34,69,35,71,36,73,37,75,38,77,39,79,40, 941,8,102,10,102,12,102,944,9,102,1,102,1,102,1,102,1,102,1,102,
81,41,83,42,85,43,87,44,89,45,91,46,93,47,95,48,97,49,99,50,101, 1,103,4,103,952,8,103,11,103,12,103,953,1,103,1,103,1,942,0,104,
51,103,52,105,53,107,54,109,55,111,56,113,57,115,58,117,59,119,60, 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,
121,61,123,62,125,63,127,64,129,65,131,66,133,67,135,68,137,69,139, 27,14,29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,22,45,23,47,24,
70,141,71,143,72,145,73,147,74,149,75,151,76,153,77,155,78,157,79, 49,25,51,26,53,27,55,28,57,29,59,30,61,31,63,32,65,33,67,34,69,35,
159,80,161,81,163,82,165,83,167,84,169,85,171,86,173,87,175,88,177, 71,36,73,37,75,38,77,39,79,40,81,41,83,42,85,43,87,44,89,45,91,46,
89,179,90,181,91,183,92,185,0,187,0,189,93,191,94,193,95,1,0,11, 93,47,95,48,97,49,99,50,101,51,103,52,105,53,107,54,109,55,111,56,
1,0,48,57,1,0,49,57,2,0,69,69,101,101,2,0,43,43,45,45,3,0,65,90, 113,57,115,58,117,59,119,60,121,61,123,62,125,63,127,64,129,65,131,
95,95,97,122,4,0,48,57,65,90,95,95,97,122,4,0,10,10,13,13,34,34, 66,133,67,135,68,137,69,139,70,141,71,143,72,145,73,147,74,149,75,
92,92,8,0,34,34,47,47,92,92,98,98,102,102,110,110,114,114,116,116, 151,76,153,77,155,78,157,79,159,80,161,81,163,82,165,83,167,84,169,
3,0,48,57,65,70,97,102,2,0,10,10,13,13,3,0,9,10,13,13,32,32,909, 85,171,86,173,87,175,88,177,89,179,90,181,91,183,92,185,93,187,94,
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,0,11, 189,95,191,96,193,97,195,98,197,99,199,0,201,0,203,100,205,101,207,
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,0,21, 102,1,0,11,1,0,48,57,1,0,49,57,2,0,69,69,101,101,2,0,43,43,45,45,
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,0,31, 3,0,65,90,95,95,97,122,4,0,48,57,65,90,95,95,97,122,4,0,10,10,13,
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,41, 13,34,34,92,92,8,0,34,34,47,47,92,92,98,98,102,102,110,110,114,114,
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,51, 116,116,3,0,48,57,65,70,97,102,2,0,10,10,13,13,3,0,9,10,13,13,32,
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,61, 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,
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,71, 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,
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,81, 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,
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,91, 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,
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,101, 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,
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,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,111,1,0,0,0,0,113,1,0,0,0,0,115,1,0,0,0,0,117,1,0,0,0,0,119,1, 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,0,121,1,0,0,0,0,123,1,0,0,0,0,125,1,0,0,0,0,127,1,0,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,
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,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,139,1,0,0,0,0,141,1,0,0,0,0,143,1,0,0,0,0,145,1,0,0,0,0,147, 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,
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,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,157,1,0,0,0,0,159,1,0,0,0,0,161,1,0,0,0,0,163,1,0,0,0,0,165,1, 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,
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, 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,
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,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,189,1,0,0,0,0,191,1,0,0,0,0,193,1,0,0,0,1,195,1,0,0,0,3,205, 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,
1,0,0,0,5,210,1,0,0,0,7,220,1,0,0,0,9,231,1,0,0,0,11,239,1,0,0,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,
13,245,1,0,0,0,15,254,1,0,0,0,17,264,1,0,0,0,19,273,1,0,0,0,21,285, 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,23,296,1,0,0,0,25,304,1,0,0,0,27,307,1,0,0,0,29,312,1,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,0,31,315,1,0,0,0,33,323,1,0,0,0,35,330,1,0,0,0,37,336,1,0,0,0, 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,
39,341,1,0,0,0,41,352,1,0,0,0,43,357,1,0,0,0,45,360,1,0,0,0,47,367, 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,
1,0,0,0,49,375,1,0,0,0,51,382,1,0,0,0,53,393,1,0,0,0,55,400,1,0, 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,
0,0,57,409,1,0,0,0,59,412,1,0,0,0,61,416,1,0,0,0,63,421,1,0,0,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,
65,427,1,0,0,0,67,436,1,0,0,0,69,445,1,0,0,0,71,449,1,0,0,0,73,453, 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,
1,0,0,0,75,457,1,0,0,0,77,463,1,0,0,0,79,469,1,0,0,0,81,474,1,0, 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,
0,0,83,479,1,0,0,0,85,485,1,0,0,0,87,493,1,0,0,0,89,501,1,0,0,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,
91,512,1,0,0,0,93,517,1,0,0,0,95,529,1,0,0,0,97,540,1,0,0,0,99,550, 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,
1,0,0,0,101,562,1,0,0,0,103,582,1,0,0,0,105,587,1,0,0,0,107,600, 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,109,612,1,0,0,0,111,624,1,0,0,0,113,629,1,0,0,0,115,637, 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,
1,0,0,0,117,642,1,0,0,0,119,655,1,0,0,0,121,663,1,0,0,0,123,672, 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,
1,0,0,0,125,686,1,0,0,0,127,695,1,0,0,0,129,700,1,0,0,0,131,705, 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,133,711,1,0,0,0,135,718,1,0,0,0,137,724,1,0,0,0,139,730, 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,
1,0,0,0,141,737,1,0,0,0,143,744,1,0,0,0,145,751,1,0,0,0,147,756, 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,
1,0,0,0,149,762,1,0,0,0,151,767,1,0,0,0,153,770,1,0,0,0,155,772, 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,
1,0,0,0,157,774,1,0,0,0,159,776,1,0,0,0,161,778,1,0,0,0,163,780, 0,0,103,563,1,0,0,0,105,574,1,0,0,0,107,579,1,0,0,0,109,591,1,0,
1,0,0,0,165,782,1,0,0,0,167,784,1,0,0,0,169,786,1,0,0,0,171,788, 0,0,111,602,1,0,0,0,113,612,1,0,0,0,115,624,1,0,0,0,117,644,1,0,
1,0,0,0,173,790,1,0,0,0,175,792,1,0,0,0,177,795,1,0,0,0,179,803, 0,0,119,649,1,0,0,0,121,662,1,0,0,0,123,674,1,0,0,0,125,686,1,0,
1,0,0,0,181,834,1,0,0,0,183,841,1,0,0,0,185,851,1,0,0,0,187,861, 0,0,127,691,1,0,0,0,129,699,1,0,0,0,131,704,1,0,0,0,133,717,1,0,
1,0,0,0,189,863,1,0,0,0,191,874,1,0,0,0,193,889,1,0,0,0,195,196, 0,0,135,725,1,0,0,0,137,734,1,0,0,0,139,748,1,0,0,0,141,757,1,0,
5,119,0,0,196,197,5,111,0,0,197,198,5,114,0,0,198,199,5,107,0,0, 0,0,143,762,1,0,0,0,145,767,1,0,0,0,147,773,1,0,0,0,149,780,1,0,
199,200,5,115,0,0,200,201,5,112,0,0,201,202,5,97,0,0,202,203,5,99, 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,203,204,5,101,0,0,204,2,1,0,0,0,205,206,5,97,0,0,206,207,5,116, 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,207,208,5,111,0,0,208,209,5,109,0,0,209,4,1,0,0,0,210,211,5, 0,0,167,832,1,0,0,0,169,834,1,0,0,0,171,836,1,0,0,0,173,838,1,0,
105,0,0,211,212,5,110,0,0,212,213,5,116,0,0,213,214,5,101,0,0,214, 0,0,175,840,1,0,0,0,177,842,1,0,0,0,179,844,1,0,0,0,181,846,1,0,
215,5,114,0,0,215,216,5,102,0,0,216,217,5,97,0,0,217,218,5,99,0, 0,0,183,848,1,0,0,0,185,850,1,0,0,0,187,852,1,0,0,0,189,854,1,0,
0,218,219,5,101,0,0,219,6,1,0,0,0,220,221,5,105,0,0,221,222,5,110, 0,0,191,857,1,0,0,0,193,865,1,0,0,0,195,896,1,0,0,0,197,903,1,0,
0,0,222,223,5,116,0,0,223,224,5,101,0,0,224,225,5,114,0,0,225,226, 0,0,199,913,1,0,0,0,201,923,1,0,0,0,203,925,1,0,0,0,205,936,1,0,
5,102,0,0,226,227,5,97,0,0,227,228,5,99,0,0,228,229,5,101,0,0,229, 0,0,207,951,1,0,0,0,209,210,5,119,0,0,210,211,5,111,0,0,211,212,
230,5,115,0,0,230,8,1,0,0,0,231,232,5,112,0,0,232,233,5,97,0,0,233, 5,114,0,0,212,213,5,107,0,0,213,214,5,115,0,0,214,215,5,112,0,0,
234,5,99,0,0,234,235,5,107,0,0,235,236,5,97,0,0,236,237,5,103,0, 215,216,5,97,0,0,216,217,5,99,0,0,217,218,5,101,0,0,218,2,1,0,0,
0,237,238,5,101,0,0,238,10,1,0,0,0,239,240,5,118,0,0,240,241,5,97, 0,219,220,5,105,0,0,220,221,5,109,0,0,221,222,5,112,0,0,222,223,
0,0,241,242,5,108,0,0,242,243,5,117,0,0,243,244,5,101,0,0,244,12, 5,111,0,0,223,224,5,114,0,0,224,225,5,116,0,0,225,4,1,0,0,0,226,
1,0,0,0,245,246,5,114,0,0,246,247,5,101,0,0,247,248,5,108,0,0,248, 227,5,101,0,0,227,228,5,120,0,0,228,229,5,116,0,0,229,230,5,101,
249,5,97,0,0,249,250,5,116,0,0,250,251,5,105,0,0,251,252,5,111,0, 0,0,230,231,5,114,0,0,231,232,5,110,0,0,232,233,5,97,0,0,233,234,
0,252,253,5,110,0,0,253,14,1,0,0,0,254,255,5,111,0,0,255,256,5,112, 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,0,256,257,5,101,0,0,257,258,5,114,0,0,258,259,5,97,0,0,259,260, 5,111,0,0,238,239,5,109,0,0,239,8,1,0,0,0,240,241,5,105,0,0,241,
5,116,0,0,260,261,5,105,0,0,261,262,5,111,0,0,262,263,5,110,0,0, 242,5,110,0,0,242,243,5,116,0,0,243,244,5,101,0,0,244,245,5,114,
263,16,1,0,0,0,264,265,5,102,0,0,265,266,5,117,0,0,266,267,5,110, 0,0,245,246,5,102,0,0,246,247,5,97,0,0,247,248,5,99,0,0,248,249,
0,0,267,268,5,99,0,0,268,269,5,116,0,0,269,270,5,105,0,0,270,271, 5,101,0,0,249,10,1,0,0,0,250,251,5,105,0,0,251,252,5,110,0,0,252,
5,111,0,0,271,272,5,110,0,0,272,18,1,0,0,0,273,274,5,99,0,0,274, 253,5,116,0,0,253,254,5,101,0,0,254,255,5,114,0,0,255,256,5,102,
275,5,111,0,0,275,276,5,110,0,0,276,277,5,115,0,0,277,278,5,116, 0,0,256,257,5,97,0,0,257,258,5,99,0,0,258,259,5,101,0,0,259,260,
0,0,278,279,5,114,0,0,279,280,5,117,0,0,280,281,5,99,0,0,281,282, 5,115,0,0,260,12,1,0,0,0,261,262,5,112,0,0,262,263,5,97,0,0,263,
5,116,0,0,282,283,5,111,0,0,283,284,5,114,0,0,284,20,1,0,0,0,285, 264,5,99,0,0,264,265,5,107,0,0,265,266,5,97,0,0,266,267,5,103,0,
286,5,99,0,0,286,287,5,111,0,0,287,288,5,110,0,0,288,289,5,115,0, 0,267,268,5,101,0,0,268,14,1,0,0,0,269,270,5,118,0,0,270,271,5,97,
0,289,290,5,116,0,0,290,291,5,114,0,0,291,292,5,117,0,0,292,293, 0,0,271,272,5,108,0,0,272,273,5,117,0,0,273,274,5,101,0,0,274,16,
5,99,0,0,293,294,5,116,0,0,294,295,5,115,0,0,295,22,1,0,0,0,296, 1,0,0,0,275,276,5,114,0,0,276,277,5,101,0,0,277,278,5,108,0,0,278,
297,5,99,0,0,297,298,5,111,0,0,298,299,5,110,0,0,299,300,5,102,0, 279,5,97,0,0,279,280,5,116,0,0,280,281,5,105,0,0,281,282,5,111,0,
0,300,301,5,111,0,0,301,302,5,114,0,0,302,303,5,109,0,0,303,24,1, 0,282,283,5,110,0,0,283,18,1,0,0,0,284,285,5,111,0,0,285,286,5,112,
0,0,0,304,305,5,97,0,0,305,306,5,115,0,0,306,26,1,0,0,0,307,308, 0,0,286,287,5,101,0,0,287,288,5,114,0,0,288,289,5,97,0,0,289,290,
5,98,0,0,308,309,5,105,0,0,309,310,5,110,0,0,310,311,5,100,0,0,311, 5,116,0,0,290,291,5,105,0,0,291,292,5,111,0,0,292,293,5,110,0,0,
28,1,0,0,0,312,313,5,116,0,0,313,314,5,111,0,0,314,30,1,0,0,0,315, 293,20,1,0,0,0,294,295,5,102,0,0,295,296,5,117,0,0,296,297,5,110,
316,5,112,0,0,316,317,5,114,0,0,317,318,5,105,0,0,318,319,5,118, 0,0,297,298,5,99,0,0,298,299,5,116,0,0,299,300,5,105,0,0,300,301,
0,0,319,320,5,97,0,0,320,321,5,116,0,0,321,322,5,101,0,0,322,32, 5,111,0,0,301,302,5,110,0,0,302,22,1,0,0,0,303,304,5,99,0,0,304,
1,0,0,0,323,324,5,115,0,0,324,325,5,104,0,0,325,326,5,97,0,0,326, 305,5,111,0,0,305,306,5,110,0,0,306,307,5,115,0,0,307,308,5,116,
327,5,114,0,0,327,328,5,101,0,0,328,329,5,100,0,0,329,34,1,0,0,0, 0,0,308,309,5,114,0,0,309,310,5,117,0,0,310,311,5,99,0,0,311,312,
330,331,5,115,0,0,331,332,5,116,0,0,332,333,5,97,0,0,333,334,5,116, 5,116,0,0,312,313,5,111,0,0,313,314,5,114,0,0,314,24,1,0,0,0,315,
0,0,334,335,5,101,0,0,335,36,1,0,0,0,336,337,5,101,0,0,337,338,5, 316,5,99,0,0,316,317,5,111,0,0,317,318,5,110,0,0,318,319,5,115,0,
100,0,0,338,339,5,103,0,0,339,340,5,101,0,0,340,38,1,0,0,0,341,342, 0,319,320,5,116,0,0,320,321,5,114,0,0,321,322,5,117,0,0,322,323,
5,112,0,0,342,343,5,114,0,0,343,344,5,111,0,0,344,345,5,106,0,0, 5,99,0,0,323,324,5,116,0,0,324,325,5,115,0,0,325,26,1,0,0,0,326,
345,346,5,101,0,0,346,347,5,99,0,0,347,348,5,116,0,0,348,349,5,105, 327,5,99,0,0,327,328,5,111,0,0,328,329,5,110,0,0,329,330,5,102,0,
0,0,349,350,5,111,0,0,350,351,5,110,0,0,351,40,1,0,0,0,352,353,5, 0,330,331,5,111,0,0,331,332,5,114,0,0,332,333,5,109,0,0,333,28,1,
119,0,0,353,354,5,105,0,0,354,355,5,116,0,0,355,356,5,104,0,0,356, 0,0,0,334,335,5,97,0,0,335,336,5,115,0,0,336,30,1,0,0,0,337,338,
42,1,0,0,0,357,358,5,111,0,0,358,359,5,110,0,0,359,44,1,0,0,0,360, 5,98,0,0,338,339,5,105,0,0,339,340,5,110,0,0,340,341,5,100,0,0,341,
361,5,112,0,0,361,362,5,111,0,0,362,363,5,108,0,0,363,364,5,105, 32,1,0,0,0,342,343,5,116,0,0,343,344,5,111,0,0,344,34,1,0,0,0,345,
0,0,364,365,5,99,0,0,365,366,5,121,0,0,366,46,1,0,0,0,367,368,5, 346,5,112,0,0,346,347,5,114,0,0,347,348,5,105,0,0,348,349,5,118,
100,0,0,368,369,5,101,0,0,369,370,5,102,0,0,370,371,5,97,0,0,371, 0,0,349,350,5,97,0,0,350,351,5,116,0,0,351,352,5,101,0,0,352,36,
372,5,117,0,0,372,373,5,108,0,0,373,374,5,116,0,0,374,48,1,0,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,
375,376,5,115,0,0,376,377,5,111,0,0,377,378,5,117,0,0,378,379,5, 357,5,114,0,0,357,358,5,101,0,0,358,359,5,100,0,0,359,38,1,0,0,0,
114,0,0,379,380,5,99,0,0,380,381,5,101,0,0,381,50,1,0,0,0,382,383, 360,361,5,115,0,0,361,362,5,116,0,0,362,363,5,97,0,0,363,364,5,116,
5,114,0,0,383,384,5,101,0,0,384,385,5,112,0,0,385,386,5,111,0,0, 0,0,364,365,5,101,0,0,365,40,1,0,0,0,366,367,5,101,0,0,367,368,5,
386,387,5,115,0,0,387,388,5,105,0,0,388,389,5,116,0,0,389,390,5, 100,0,0,368,369,5,103,0,0,369,370,5,101,0,0,370,42,1,0,0,0,371,372,
111,0,0,390,391,5,114,0,0,391,392,5,121,0,0,392,52,1,0,0,0,393,394, 5,112,0,0,372,373,5,114,0,0,373,374,5,111,0,0,374,375,5,106,0,0,
5,99,0,0,394,395,5,111,0,0,395,396,5,109,0,0,396,397,5,109,0,0,397, 375,376,5,101,0,0,376,377,5,99,0,0,377,378,5,116,0,0,378,379,5,105,
398,5,105,0,0,398,399,5,116,0,0,399,54,1,0,0,0,400,401,5,114,0,0, 0,0,379,380,5,111,0,0,380,381,5,110,0,0,381,44,1,0,0,0,382,383,5,
401,402,5,101,0,0,402,403,5,118,0,0,403,404,5,105,0,0,404,405,5, 119,0,0,383,384,5,105,0,0,384,385,5,116,0,0,385,386,5,104,0,0,386,
115,0,0,405,406,5,105,0,0,406,407,5,111,0,0,407,408,5,110,0,0,408, 46,1,0,0,0,387,388,5,117,0,0,388,389,5,115,0,0,389,390,5,105,0,0,
56,1,0,0,0,409,410,5,105,0,0,410,411,5,100,0,0,411,58,1,0,0,0,412, 390,391,5,110,0,0,391,392,5,103,0,0,392,48,1,0,0,0,393,394,5,118,
413,5,100,0,0,413,414,5,111,0,0,414,415,5,99,0,0,415,60,1,0,0,0, 0,0,394,395,5,105,0,0,395,396,5,97,0,0,396,50,1,0,0,0,397,398,5,
416,417,5,109,0,0,417,418,5,111,0,0,418,419,5,100,0,0,419,420,5, 109,0,0,398,399,5,97,0,0,399,400,5,116,0,0,400,401,5,101,0,0,401,
101,0,0,420,62,1,0,0,0,421,422,5,101,0,0,422,423,5,109,0,0,423,424, 402,5,114,0,0,402,403,5,105,0,0,403,404,5,97,0,0,404,405,5,108,0,
5,105,0,0,424,425,5,116,0,0,425,426,5,115,0,0,426,64,1,0,0,0,427, 0,405,406,5,105,0,0,406,407,5,122,0,0,407,408,5,101,0,0,408,52,1,
428,5,114,0,0,428,429,5,101,0,0,429,430,5,99,0,0,430,431,5,101,0, 0,0,0,409,410,5,105,0,0,410,411,5,102,0,0,411,54,1,0,0,0,412,413,
0,431,432,5,105,0,0,432,433,5,118,0,0,433,434,5,101,0,0,434,435, 5,97,0,0,413,414,5,98,0,0,414,415,5,115,0,0,415,416,5,101,0,0,416,
5,114,0,0,435,66,1,0,0,0,436,437,5,114,0,0,437,438,5,101,0,0,438, 417,5,110,0,0,417,418,5,116,0,0,418,56,1,0,0,0,419,420,5,111,0,0,
439,5,113,0,0,439,440,5,117,0,0,440,441,5,105,0,0,441,442,5,114, 420,421,5,110,0,0,421,58,1,0,0,0,422,423,5,112,0,0,423,424,5,111,
0,0,442,443,5,101,0,0,443,444,5,115,0,0,444,68,1,0,0,0,445,446,5, 0,0,424,425,5,108,0,0,425,426,5,105,0,0,426,427,5,99,0,0,427,428,
97,0,0,446,447,5,110,0,0,447,448,5,121,0,0,448,70,1,0,0,0,449,450, 5,121,0,0,428,60,1,0,0,0,429,430,5,100,0,0,430,431,5,101,0,0,431,
5,103,0,0,450,451,5,101,0,0,451,452,5,116,0,0,452,72,1,0,0,0,453, 432,5,102,0,0,432,433,5,97,0,0,433,434,5,117,0,0,434,435,5,108,0,
454,5,115,0,0,454,455,5,101,0,0,455,456,5,116,0,0,456,74,1,0,0,0, 0,435,436,5,116,0,0,436,62,1,0,0,0,437,438,5,115,0,0,438,439,5,111,
457,458,5,119,0,0,458,459,5,97,0,0,459,460,5,116,0,0,460,461,5,99, 0,0,439,440,5,117,0,0,440,441,5,114,0,0,441,442,5,99,0,0,442,443,
0,0,461,462,5,104,0,0,462,76,1,0,0,0,463,464,5,115,0,0,464,465,5, 5,101,0,0,443,64,1,0,0,0,444,445,5,114,0,0,445,446,5,101,0,0,446,
116,0,0,465,466,5,97,0,0,466,467,5,114,0,0,467,468,5,116,0,0,468, 447,5,112,0,0,447,448,5,111,0,0,448,449,5,115,0,0,449,450,5,105,
78,1,0,0,0,469,470,5,115,0,0,470,471,5,116,0,0,471,472,5,111,0,0, 0,0,450,451,5,116,0,0,451,452,5,111,0,0,452,453,5,114,0,0,453,454,
472,473,5,112,0,0,473,80,1,0,0,0,474,475,5,114,0,0,475,476,5,101, 5,121,0,0,454,66,1,0,0,0,455,456,5,99,0,0,456,457,5,111,0,0,457,
0,0,476,477,5,97,0,0,477,478,5,100,0,0,478,82,1,0,0,0,479,480,5, 458,5,109,0,0,458,459,5,109,0,0,459,460,5,105,0,0,460,461,5,116,
119,0,0,480,481,5,114,0,0,481,482,5,105,0,0,482,483,5,116,0,0,483, 0,0,461,68,1,0,0,0,462,463,5,114,0,0,463,464,5,101,0,0,464,465,5,
484,5,101,0,0,484,84,1,0,0,0,485,486,5,114,0,0,486,487,5,101,0,0, 118,0,0,465,466,5,105,0,0,466,467,5,115,0,0,467,468,5,105,0,0,468,
487,488,5,115,0,0,488,489,5,111,0,0,489,490,5,108,0,0,490,491,5, 469,5,111,0,0,469,470,5,110,0,0,470,70,1,0,0,0,471,472,5,105,0,0,
118,0,0,491,492,5,101,0,0,492,86,1,0,0,0,493,494,5,99,0,0,494,495, 472,473,5,100,0,0,473,72,1,0,0,0,474,475,5,100,0,0,475,476,5,111,
5,111,0,0,495,496,5,110,0,0,496,497,5,110,0,0,497,498,5,101,0,0, 0,0,476,477,5,99,0,0,477,74,1,0,0,0,478,479,5,109,0,0,479,480,5,
498,499,5,99,0,0,499,500,5,116,0,0,500,88,1,0,0,0,501,502,5,100, 111,0,0,480,481,5,100,0,0,481,482,5,101,0,0,482,76,1,0,0,0,483,484,
0,0,502,503,5,105,0,0,503,504,5,115,0,0,504,505,5,99,0,0,505,506, 5,101,0,0,484,485,5,109,0,0,485,486,5,105,0,0,486,487,5,116,0,0,
5,111,0,0,506,507,5,110,0,0,507,508,5,110,0,0,508,509,5,101,0,0, 487,488,5,115,0,0,488,78,1,0,0,0,489,490,5,114,0,0,490,491,5,101,
509,510,5,99,0,0,510,511,5,116,0,0,511,90,1,0,0,0,512,513,5,99,0, 0,0,491,492,5,99,0,0,492,493,5,101,0,0,493,494,5,105,0,0,494,495,
0,513,514,5,97,0,0,514,515,5,108,0,0,515,516,5,108,0,0,516,92,1, 5,118,0,0,495,496,5,101,0,0,496,497,5,114,0,0,497,80,1,0,0,0,498,
0,0,0,517,518,5,119,0,0,518,519,5,97,0,0,519,520,5,116,0,0,520,521, 499,5,114,0,0,499,500,5,101,0,0,500,501,5,113,0,0,501,502,5,117,
5,99,0,0,521,522,5,104,0,0,522,523,5,45,0,0,523,524,5,115,0,0,524, 0,0,502,503,5,105,0,0,503,504,5,114,0,0,504,505,5,101,0,0,505,506,
525,5,116,0,0,525,526,5,97,0,0,526,527,5,114,0,0,527,528,5,116,0, 5,115,0,0,506,82,1,0,0,0,507,508,5,97,0,0,508,509,5,110,0,0,509,
0,528,94,1,0,0,0,529,530,5,119,0,0,530,531,5,97,0,0,531,532,5,116, 510,5,121,0,0,510,84,1,0,0,0,511,512,5,103,0,0,512,513,5,101,0,0,
0,0,532,533,5,99,0,0,533,534,5,104,0,0,534,535,5,45,0,0,535,536, 513,514,5,116,0,0,514,86,1,0,0,0,515,516,5,115,0,0,516,517,5,101,
5,115,0,0,536,537,5,116,0,0,537,538,5,111,0,0,538,539,5,112,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,
539,96,1,0,0,0,540,541,5,115,0,0,541,542,5,117,0,0,542,543,5,98, 97,0,0,521,522,5,116,0,0,522,523,5,99,0,0,523,524,5,104,0,0,524,
0,0,543,544,5,115,0,0,544,545,5,99,0,0,545,546,5,114,0,0,546,547, 90,1,0,0,0,525,526,5,115,0,0,526,527,5,116,0,0,527,528,5,97,0,0,
5,105,0,0,547,548,5,98,0,0,548,549,5,101,0,0,549,98,1,0,0,0,550, 528,529,5,114,0,0,529,530,5,116,0,0,530,92,1,0,0,0,531,532,5,115,
551,5,117,0,0,551,552,5,110,0,0,552,553,5,115,0,0,553,554,5,117, 0,0,532,533,5,116,0,0,533,534,5,111,0,0,534,535,5,112,0,0,535,94,
0,0,554,555,5,98,0,0,555,556,5,115,0,0,556,557,5,99,0,0,557,558, 1,0,0,0,536,537,5,114,0,0,537,538,5,101,0,0,538,539,5,97,0,0,539,
5,114,0,0,558,559,5,105,0,0,559,560,5,98,0,0,560,561,5,101,0,0,561, 540,5,100,0,0,540,96,1,0,0,0,541,542,5,119,0,0,542,543,5,114,0,0,
100,1,0,0,0,562,563,5,111,0,0,563,564,5,112,0,0,564,565,5,116,0, 543,544,5,105,0,0,544,545,5,116,0,0,545,546,5,101,0,0,546,98,1,0,
0,565,566,5,105,0,0,566,567,5,109,0,0,567,568,5,105,0,0,568,569, 0,0,547,548,5,114,0,0,548,549,5,101,0,0,549,550,5,115,0,0,550,551,
5,115,0,0,569,570,5,116,0,0,570,571,5,105,0,0,571,572,5,99,0,0,572, 5,111,0,0,551,552,5,108,0,0,552,553,5,118,0,0,553,554,5,101,0,0,
573,5,45,0,0,573,574,5,114,0,0,574,575,5,101,0,0,575,576,5,103,0, 554,100,1,0,0,0,555,556,5,99,0,0,556,557,5,111,0,0,557,558,5,110,
0,576,577,5,105,0,0,577,578,5,115,0,0,578,579,5,116,0,0,579,580, 0,0,558,559,5,110,0,0,559,560,5,101,0,0,560,561,5,99,0,0,561,562,
5,101,0,0,580,581,5,114,0,0,581,102,1,0,0,0,582,583,5,99,0,0,583, 5,116,0,0,562,102,1,0,0,0,563,564,5,100,0,0,564,565,5,105,0,0,565,
584,5,114,0,0,584,585,5,100,0,0,585,586,5,116,0,0,586,104,1,0,0, 566,5,115,0,0,566,567,5,99,0,0,567,568,5,111,0,0,568,569,5,110,0,
0,587,588,5,111,0,0,588,589,5,112,0,0,589,590,5,116,0,0,590,591, 0,569,570,5,110,0,0,570,571,5,101,0,0,571,572,5,99,0,0,572,573,5,
5,105,0,0,591,592,5,111,0,0,592,593,5,110,0,0,593,594,5,97,0,0,594, 116,0,0,573,104,1,0,0,0,574,575,5,99,0,0,575,576,5,97,0,0,576,577,
595,5,108,0,0,595,596,5,45,0,0,596,597,5,111,0,0,597,598,5,110,0, 5,108,0,0,577,578,5,108,0,0,578,106,1,0,0,0,579,580,5,119,0,0,580,
0,598,599,5,101,0,0,599,106,1,0,0,0,600,601,5,101,0,0,601,602,5, 581,5,97,0,0,581,582,5,116,0,0,582,583,5,99,0,0,583,584,5,104,0,
120,0,0,602,603,5,97,0,0,603,604,5,99,0,0,604,605,5,116,0,0,605, 0,584,585,5,45,0,0,585,586,5,115,0,0,586,587,5,116,0,0,587,588,5,
606,5,108,0,0,606,607,5,121,0,0,607,608,5,45,0,0,608,609,5,111,0, 97,0,0,588,589,5,114,0,0,589,590,5,116,0,0,590,108,1,0,0,0,591,592,
0,609,610,5,110,0,0,610,611,5,101,0,0,611,108,1,0,0,0,612,613,5, 5,119,0,0,592,593,5,97,0,0,593,594,5,116,0,0,594,595,5,99,0,0,595,
109,0,0,613,614,5,97,0,0,614,615,5,110,0,0,615,616,5,121,0,0,616, 596,5,104,0,0,596,597,5,45,0,0,597,598,5,115,0,0,598,599,5,116,0,
617,5,45,0,0,617,618,5,117,0,0,618,619,5,110,0,0,619,620,5,105,0, 0,599,600,5,111,0,0,600,601,5,112,0,0,601,110,1,0,0,0,602,603,5,
0,620,621,5,113,0,0,621,622,5,117,0,0,622,623,5,101,0,0,623,110, 115,0,0,603,604,5,117,0,0,604,605,5,98,0,0,605,606,5,115,0,0,606,
1,0,0,0,624,625,5,109,0,0,625,626,5,97,0,0,626,627,5,110,0,0,627, 607,5,99,0,0,607,608,5,114,0,0,608,609,5,105,0,0,609,610,5,98,0,
628,5,121,0,0,628,112,1,0,0,0,629,630,5,111,0,0,630,631,5,114,0, 0,610,611,5,101,0,0,611,112,1,0,0,0,612,613,5,117,0,0,613,614,5,
0,631,632,5,100,0,0,632,633,5,101,0,0,633,634,5,114,0,0,634,635, 110,0,0,614,615,5,115,0,0,615,616,5,117,0,0,616,617,5,98,0,0,617,
5,101,0,0,635,636,5,100,0,0,636,114,1,0,0,0,637,638,5,117,0,0,638, 618,5,115,0,0,618,619,5,99,0,0,619,620,5,114,0,0,620,621,5,105,0,
639,5,110,0,0,639,640,5,105,0,0,640,641,5,116,0,0,641,116,1,0,0, 0,621,622,5,98,0,0,622,623,5,101,0,0,623,114,1,0,0,0,624,625,5,111,
0,642,643,5,119,0,0,643,644,5,97,0,0,644,645,5,116,0,0,645,646,5, 0,0,625,626,5,112,0,0,626,627,5,116,0,0,627,628,5,105,0,0,628,629,
99,0,0,646,647,5,104,0,0,647,648,5,45,0,0,648,649,5,104,0,0,649, 5,109,0,0,629,630,5,105,0,0,630,631,5,115,0,0,631,632,5,116,0,0,
650,5,97,0,0,650,651,5,110,0,0,651,652,5,100,0,0,652,653,5,108,0, 632,633,5,105,0,0,633,634,5,99,0,0,634,635,5,45,0,0,635,636,5,114,
0,653,654,5,101,0,0,654,118,1,0,0,0,655,656,5,109,0,0,656,657,5, 0,0,636,637,5,101,0,0,637,638,5,103,0,0,638,639,5,105,0,0,639,640,
101,0,0,657,658,5,115,0,0,658,659,5,115,0,0,659,660,5,97,0,0,660, 5,115,0,0,640,641,5,116,0,0,641,642,5,101,0,0,642,643,5,114,0,0,
661,5,103,0,0,661,662,5,101,0,0,662,120,1,0,0,0,663,664,5,97,0,0, 643,116,1,0,0,0,644,645,5,99,0,0,645,646,5,114,0,0,646,647,5,100,
664,665,5,116,0,0,665,666,5,111,0,0,666,667,5,109,0,0,667,668,5, 0,0,647,648,5,116,0,0,648,118,1,0,0,0,649,650,5,111,0,0,650,651,
45,0,0,668,669,5,114,0,0,669,670,5,101,0,0,670,671,5,102,0,0,671, 5,112,0,0,651,652,5,116,0,0,652,653,5,105,0,0,653,654,5,111,0,0,
122,1,0,0,0,672,673,5,105,0,0,673,674,5,110,0,0,674,675,5,116,0, 654,655,5,110,0,0,655,656,5,97,0,0,656,657,5,108,0,0,657,658,5,45,
0,675,676,5,101,0,0,676,677,5,114,0,0,677,678,5,102,0,0,678,679, 0,0,658,659,5,111,0,0,659,660,5,110,0,0,660,661,5,101,0,0,661,120,
5,97,0,0,679,680,5,99,0,0,680,681,5,101,0,0,681,682,5,45,0,0,682, 1,0,0,0,662,663,5,101,0,0,663,664,5,120,0,0,664,665,5,97,0,0,665,
683,5,114,0,0,683,684,5,101,0,0,684,685,5,102,0,0,685,124,1,0,0, 666,5,99,0,0,666,667,5,116,0,0,667,668,5,108,0,0,668,669,5,121,0,
0,686,687,5,111,0,0,687,688,5,112,0,0,688,689,5,116,0,0,689,690, 0,669,670,5,45,0,0,670,671,5,111,0,0,671,672,5,110,0,0,672,673,5,
5,105,0,0,690,691,5,111,0,0,691,692,5,110,0,0,692,693,5,97,0,0,693, 101,0,0,673,122,1,0,0,0,674,675,5,109,0,0,675,676,5,97,0,0,676,677,
694,5,108,0,0,694,126,1,0,0,0,695,696,5,108,0,0,696,697,5,105,0, 5,110,0,0,677,678,5,121,0,0,678,679,5,45,0,0,679,680,5,117,0,0,680,
0,697,698,5,115,0,0,698,699,5,116,0,0,699,128,1,0,0,0,700,701,5, 681,5,110,0,0,681,682,5,105,0,0,682,683,5,113,0,0,683,684,5,117,
98,0,0,701,702,5,111,0,0,702,703,5,111,0,0,703,704,5,108,0,0,704, 0,0,684,685,5,101,0,0,685,124,1,0,0,0,686,687,5,109,0,0,687,688,
130,1,0,0,0,705,706,5,98,0,0,706,707,5,121,0,0,707,708,5,116,0,0, 5,97,0,0,688,689,5,110,0,0,689,690,5,121,0,0,690,126,1,0,0,0,691,
708,709,5,101,0,0,709,710,5,115,0,0,710,132,1,0,0,0,711,712,5,100, 692,5,111,0,0,692,693,5,114,0,0,693,694,5,100,0,0,694,695,5,101,
0,0,712,713,5,111,0,0,713,714,5,117,0,0,714,715,5,98,0,0,715,716, 0,0,695,696,5,114,0,0,696,697,5,101,0,0,697,698,5,100,0,0,698,128,
5,108,0,0,716,717,5,101,0,0,717,134,1,0,0,0,718,719,5,105,0,0,719, 1,0,0,0,699,700,5,117,0,0,700,701,5,110,0,0,701,702,5,105,0,0,702,
720,5,110,0,0,720,721,5,116,0,0,721,722,5,51,0,0,722,723,5,50,0, 703,5,116,0,0,703,130,1,0,0,0,704,705,5,119,0,0,705,706,5,97,0,0,
0,723,136,1,0,0,0,724,725,5,105,0,0,725,726,5,110,0,0,726,727,5, 706,707,5,116,0,0,707,708,5,99,0,0,708,709,5,104,0,0,709,710,5,45,
116,0,0,727,728,5,54,0,0,728,729,5,52,0,0,729,138,1,0,0,0,730,731, 0,0,710,711,5,104,0,0,711,712,5,97,0,0,712,713,5,110,0,0,713,714,
5,115,0,0,731,732,5,116,0,0,732,733,5,114,0,0,733,734,5,105,0,0, 5,100,0,0,714,715,5,108,0,0,715,716,5,101,0,0,716,132,1,0,0,0,717,
734,735,5,110,0,0,735,736,5,103,0,0,736,140,1,0,0,0,737,738,5,117, 718,5,109,0,0,718,719,5,101,0,0,719,720,5,115,0,0,720,721,5,115,
0,0,738,739,5,105,0,0,739,740,5,110,0,0,740,741,5,116,0,0,741,742, 0,0,721,722,5,97,0,0,722,723,5,103,0,0,723,724,5,101,0,0,724,134,
5,51,0,0,742,743,5,50,0,0,743,142,1,0,0,0,744,745,5,117,0,0,745, 1,0,0,0,725,726,5,97,0,0,726,727,5,116,0,0,727,728,5,111,0,0,728,
746,5,105,0,0,746,747,5,110,0,0,747,748,5,116,0,0,748,749,5,54,0, 729,5,109,0,0,729,730,5,45,0,0,730,731,5,114,0,0,731,732,5,101,0,
0,749,750,5,52,0,0,750,144,1,0,0,0,751,752,5,116,0,0,752,753,5,114, 0,732,733,5,102,0,0,733,136,1,0,0,0,734,735,5,105,0,0,735,736,5,
0,0,753,754,5,117,0,0,754,755,5,101,0,0,755,146,1,0,0,0,756,757, 110,0,0,736,737,5,116,0,0,737,738,5,101,0,0,738,739,5,114,0,0,739,
5,102,0,0,757,758,5,97,0,0,758,759,5,108,0,0,759,760,5,115,0,0,760, 740,5,102,0,0,740,741,5,97,0,0,741,742,5,99,0,0,742,743,5,101,0,
761,5,101,0,0,761,148,1,0,0,0,762,763,5,110,0,0,763,764,5,117,0, 0,743,744,5,45,0,0,744,745,5,114,0,0,745,746,5,101,0,0,746,747,5,
0,764,765,5,108,0,0,765,766,5,108,0,0,766,150,1,0,0,0,767,768,5, 102,0,0,747,138,1,0,0,0,748,749,5,111,0,0,749,750,5,112,0,0,750,
45,0,0,768,769,5,62,0,0,769,152,1,0,0,0,770,771,5,58,0,0,771,154, 751,5,116,0,0,751,752,5,105,0,0,752,753,5,111,0,0,753,754,5,110,
1,0,0,0,772,773,5,59,0,0,773,156,1,0,0,0,774,775,5,44,0,0,775,158, 0,0,754,755,5,97,0,0,755,756,5,108,0,0,756,140,1,0,0,0,757,758,5,
1,0,0,0,776,777,5,46,0,0,777,160,1,0,0,0,778,779,5,123,0,0,779,162, 108,0,0,758,759,5,105,0,0,759,760,5,115,0,0,760,761,5,116,0,0,761,
1,0,0,0,780,781,5,125,0,0,781,164,1,0,0,0,782,783,5,91,0,0,783,166, 142,1,0,0,0,762,763,5,98,0,0,763,764,5,111,0,0,764,765,5,111,0,0,
1,0,0,0,784,785,5,93,0,0,785,168,1,0,0,0,786,787,5,40,0,0,787,170, 765,766,5,108,0,0,766,144,1,0,0,0,767,768,5,98,0,0,768,769,5,121,
1,0,0,0,788,789,5,41,0,0,789,172,1,0,0,0,790,791,5,60,0,0,791,174, 0,0,769,770,5,116,0,0,770,771,5,101,0,0,771,772,5,115,0,0,772,146,
1,0,0,0,792,793,5,62,0,0,793,176,1,0,0,0,794,796,5,45,0,0,795,794, 1,0,0,0,773,774,5,100,0,0,774,775,5,111,0,0,775,776,5,117,0,0,776,
1,0,0,0,795,796,1,0,0,0,796,798,1,0,0,0,797,799,7,0,0,0,798,797, 777,5,98,0,0,777,778,5,108,0,0,778,779,5,101,0,0,779,148,1,0,0,0,
1,0,0,0,799,800,1,0,0,0,800,798,1,0,0,0,800,801,1,0,0,0,801,178, 780,781,5,105,0,0,781,782,5,110,0,0,782,783,5,116,0,0,783,784,5,
1,0,0,0,802,804,5,45,0,0,803,802,1,0,0,0,803,804,1,0,0,0,804,813, 51,0,0,784,785,5,50,0,0,785,150,1,0,0,0,786,787,5,105,0,0,787,788,
1,0,0,0,805,814,5,48,0,0,806,810,7,1,0,0,807,809,7,0,0,0,808,807, 5,110,0,0,788,789,5,116,0,0,789,790,5,54,0,0,790,791,5,52,0,0,791,
1,0,0,0,809,812,1,0,0,0,810,808,1,0,0,0,810,811,1,0,0,0,811,814, 152,1,0,0,0,792,793,5,115,0,0,793,794,5,116,0,0,794,795,5,114,0,
1,0,0,0,812,810,1,0,0,0,813,805,1,0,0,0,813,806,1,0,0,0,814,821, 0,795,796,5,105,0,0,796,797,5,110,0,0,797,798,5,103,0,0,798,154,
1,0,0,0,815,817,5,46,0,0,816,818,7,0,0,0,817,816,1,0,0,0,818,819, 1,0,0,0,799,800,5,117,0,0,800,801,5,105,0,0,801,802,5,110,0,0,802,
1,0,0,0,819,817,1,0,0,0,819,820,1,0,0,0,820,822,1,0,0,0,821,815, 803,5,116,0,0,803,804,5,51,0,0,804,805,5,50,0,0,805,156,1,0,0,0,
1,0,0,0,821,822,1,0,0,0,822,832,1,0,0,0,823,825,7,2,0,0,824,826, 806,807,5,117,0,0,807,808,5,105,0,0,808,809,5,110,0,0,809,810,5,
7,3,0,0,825,824,1,0,0,0,825,826,1,0,0,0,826,828,1,0,0,0,827,829, 116,0,0,810,811,5,54,0,0,811,812,5,52,0,0,812,158,1,0,0,0,813,814,
7,0,0,0,828,827,1,0,0,0,829,830,1,0,0,0,830,828,1,0,0,0,830,831, 5,116,0,0,814,815,5,114,0,0,815,816,5,117,0,0,816,817,5,101,0,0,
1,0,0,0,831,833,1,0,0,0,832,823,1,0,0,0,832,833,1,0,0,0,833,180, 817,160,1,0,0,0,818,819,5,102,0,0,819,820,5,97,0,0,820,821,5,108,
1,0,0,0,834,838,7,4,0,0,835,837,7,5,0,0,836,835,1,0,0,0,837,840, 0,0,821,822,5,115,0,0,822,823,5,101,0,0,823,162,1,0,0,0,824,825,
1,0,0,0,838,836,1,0,0,0,838,839,1,0,0,0,839,182,1,0,0,0,840,838, 5,110,0,0,825,826,5,117,0,0,826,827,5,108,0,0,827,828,5,108,0,0,
1,0,0,0,841,846,5,34,0,0,842,845,3,185,92,0,843,845,8,6,0,0,844, 828,164,1,0,0,0,829,830,5,45,0,0,830,831,5,62,0,0,831,166,1,0,0,
842,1,0,0,0,844,843,1,0,0,0,845,848,1,0,0,0,846,844,1,0,0,0,846, 0,832,833,5,58,0,0,833,168,1,0,0,0,834,835,5,59,0,0,835,170,1,0,
847,1,0,0,0,847,849,1,0,0,0,848,846,1,0,0,0,849,850,5,34,0,0,850, 0,0,836,837,5,44,0,0,837,172,1,0,0,0,838,839,5,46,0,0,839,174,1,
184,1,0,0,0,851,859,5,92,0,0,852,860,7,7,0,0,853,854,5,117,0,0,854, 0,0,0,840,841,5,123,0,0,841,176,1,0,0,0,842,843,5,125,0,0,843,178,
855,3,187,93,0,855,856,3,187,93,0,856,857,3,187,93,0,857,858,3,187, 1,0,0,0,844,845,5,91,0,0,845,180,1,0,0,0,846,847,5,93,0,0,847,182,
93,0,858,860,1,0,0,0,859,852,1,0,0,0,859,853,1,0,0,0,860,186,1,0, 1,0,0,0,848,849,5,40,0,0,849,184,1,0,0,0,850,851,5,41,0,0,851,186,
0,0,861,862,7,8,0,0,862,188,1,0,0,0,863,864,5,47,0,0,864,865,5,47, 1,0,0,0,852,853,5,60,0,0,853,188,1,0,0,0,854,855,5,62,0,0,855,190,
0,0,865,869,1,0,0,0,866,868,8,9,0,0,867,866,1,0,0,0,868,871,1,0, 1,0,0,0,856,858,5,45,0,0,857,856,1,0,0,0,857,858,1,0,0,0,858,860,
0,0,869,867,1,0,0,0,869,870,1,0,0,0,870,872,1,0,0,0,871,869,1,0, 1,0,0,0,859,861,7,0,0,0,860,859,1,0,0,0,861,862,1,0,0,0,862,860,
0,0,872,873,6,94,0,0,873,190,1,0,0,0,874,875,5,47,0,0,875,876,5, 1,0,0,0,862,863,1,0,0,0,863,192,1,0,0,0,864,866,5,45,0,0,865,864,
42,0,0,876,880,1,0,0,0,877,879,9,0,0,0,878,877,1,0,0,0,879,882,1, 1,0,0,0,865,866,1,0,0,0,866,875,1,0,0,0,867,876,5,48,0,0,868,872,
0,0,0,880,881,1,0,0,0,880,878,1,0,0,0,881,883,1,0,0,0,882,880,1, 7,1,0,0,869,871,7,0,0,0,870,869,1,0,0,0,871,874,1,0,0,0,872,870,
0,0,0,883,884,5,42,0,0,884,885,5,47,0,0,885,886,1,0,0,0,886,887, 1,0,0,0,872,873,1,0,0,0,873,876,1,0,0,0,874,872,1,0,0,0,875,867,
6,95,0,0,887,192,1,0,0,0,888,890,7,10,0,0,889,888,1,0,0,0,890,891, 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,891,889,1,0,0,0,891,892,1,0,0,0,892,893,1,0,0,0,893,894, 7,0,0,0,879,878,1,0,0,0,880,881,1,0,0,0,881,879,1,0,0,0,881,882,
6,96,0,0,894,194,1,0,0,0,18,0,795,800,803,810,813,819,821,825,830, 1,0,0,0,882,884,1,0,0,0,883,877,1,0,0,0,883,884,1,0,0,0,884,894,
832,838,844,846,859,869,880,891,1,6,0,0 1,0,0,0,885,887,7,2,0,0,886,888,7,3,0,0,887,886,1,0,0,0,887,888,
1,0,0,0,888,890,1,0,0,0,889,891,7,0,0,0,890,889,1,0,0,0,891,892,
1,0,0,0,892,890,1,0,0,0,892,893,1,0,0,0,893,895,1,0,0,0,894,885,
1,0,0,0,894,895,1,0,0,0,895,194,1,0,0,0,896,900,7,4,0,0,897,899,
7,5,0,0,898,897,1,0,0,0,899,902,1,0,0,0,900,898,1,0,0,0,900,901,
1,0,0,0,901,196,1,0,0,0,902,900,1,0,0,0,903,908,5,34,0,0,904,907,
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,908,906,1,0,0,0,908,909,1,0,0,0,909,911,1,0,0,0,910,908,
1,0,0,0,911,912,5,34,0,0,912,198,1,0,0,0,913,921,5,92,0,0,914,922,
7,7,0,0,915,916,5,117,0,0,916,917,3,201,100,0,917,918,3,201,100,
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,921,915,1,0,0,0,922,200,1,0,0,0,923,924,7,8,0,0,924,202,
1,0,0,0,925,926,5,47,0,0,926,927,5,47,0,0,927,931,1,0,0,0,928,930,
8,9,0,0,929,928,1,0,0,0,930,933,1,0,0,0,931,929,1,0,0,0,931,932,
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";
@@ -36,6 +39,7 @@ import { EdgeDeclContext } from "./QuixosCapabilityParser.js";
import { EdgeEndpointContext } from "./QuixosCapabilityParser.js"; import { EdgeEndpointContext } from "./QuixosCapabilityParser.js";
import { ConformanceDeclContext } from "./QuixosCapabilityParser.js"; import { ConformanceDeclContext } from "./QuixosCapabilityParser.js";
import { ConformanceItemContext } from "./QuixosCapabilityParser.js"; import { ConformanceItemContext } from "./QuixosCapabilityParser.js";
import { RelationshipMaterializationDeclContext } from "./QuixosCapabilityParser.js";
import { OperationBindingDeclContext } from "./QuixosCapabilityParser.js"; import { OperationBindingDeclContext } from "./QuixosCapabilityParser.js";
import { MemberOperationRefContext } from "./QuixosCapabilityParser.js"; import { MemberOperationRefContext } from "./QuixosCapabilityParser.js";
import { OperationNameContext } from "./QuixosCapabilityParser.js"; import { OperationNameContext } from "./QuixosCapabilityParser.js";
@@ -82,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
@@ -89,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
@@ -143,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
@@ -268,6 +290,12 @@ export class QuixosCapabilityVisitor<Result> extends AbstractParseTreeVisitor<Re
* @return the visitor result * @return the visitor result
*/ */
visitConformanceItem?: (ctx: ConformanceItemContext) => Result; visitConformanceItem?: (ctx: ConformanceItemContext) => Result;
/**
* Visit a parse tree produced by `QuixosCapabilityParser.relationshipMaterializationDecl`.
* @param ctx the parse tree
* @return the visitor result
*/
visitRelationshipMaterializationDecl?: (ctx: RelationshipMaterializationDeclContext) => Result;
/** /**
* Visit a parse tree produced by `QuixosCapabilityParser.operationBindingDecl`. * Visit a parse tree produced by `QuixosCapabilityParser.operationBindingDecl`.
* @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";
+553 -75
View File
@@ -22,10 +22,12 @@ import {
type EdgeEndpoint, type EdgeEndpoint,
type EdgeEndpointConstraint, type EdgeEndpointConstraint,
type EdgePrimitive, type EdgePrimitive,
type EdgeTraversal,
type InterfaceMember, type InterfaceMember,
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,
@@ -42,23 +44,72 @@ 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,
type ValueTypeContext, type ValueTypeContext,
type RelationshipMemberContext, type RelationshipMemberContext,
type RelationshipMaterializationDeclContext,
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"
@@ -79,6 +130,7 @@ export type CapabilitySourceCompileResult =
ok: true; ok: true;
workspace: WorkspaceRevision; workspace: WorkspaceRevision;
plan: CompiledWorkspaceRevision; plan: CompiledWorkspaceRevision;
imports: CapabilityResourceImport[];
diagnostics: []; diagnostics: [];
} }
| { | {
@@ -88,9 +140,11 @@ export type CapabilitySourceCompileResult =
interface InterfaceSymbol { interface InterfaceSymbol {
revisionId: InterfaceRevision["revisionId"]; revisionId: InterfaceRevision["revisionId"];
contractAvailable: boolean;
members: Map< members: Map<
string, string,
{ {
memberId: InterfaceMember["id"];
operations: Map<string, InterfaceOperation["id"]>; operations: Map<string, InterfaceOperation["id"]>;
} }
>; >;
@@ -217,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;
@@ -531,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) => {
@@ -556,6 +606,7 @@ const lowerInterface = (
symbol.members, symbol.members,
member.displayName, member.displayName,
{ {
memberId: member.id,
operations: new Map( operations: new Map(
member.operations.map((operation) => [operation.displayName, operation.id]), member.operations.map((operation) => [operation.displayName, operation.id]),
), ),
@@ -568,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,
}; };
}; };
@@ -648,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,
}, },
} }
@@ -811,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) => {
@@ -833,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,
}; };
}; };
@@ -1003,6 +1064,34 @@ const lowerBoundDependencies = (
if (!portId) { if (!portId) {
return []; return [];
} }
const traversal = (
edgeName: string,
projectionName: string,
): EdgeTraversal | undefined => {
const attachment = requireSymbol(
state,
state.attachments,
edgeName,
entry,
"attachment",
);
if (!attachment || attachment.attachment.kind !== "edge") {
if (attachment) {
loweringIssue(state, entry, "wrong-attachment-kind", `${edgeName} is state, not an edge`);
}
return undefined;
}
const projectionId = requireSymbol(
state,
attachment.projections,
projectionName,
entry,
`projection on ${edgeName}`,
);
return projectionId
? { edgeTypeId: attachment.attachment.id, projectionId }
: undefined;
};
if (entry.STATE()) { if (entry.STATE()) {
const attachmentName = identifier(entry.identifier(1)); const attachmentName = identifier(entry.identifier(1));
const attachment = requireSymbol( const attachment = requireSymbol(
@@ -1023,9 +1112,16 @@ const lowerBoundDependencies = (
} }
return []; return [];
} }
return [{ portId, binding: { kind: "state", slotId: attachment.attachment.id } }]; const via = entry.VIA()
? traversal(identifier(entry.identifier(2)), identifier(entry.identifier(3)))
: undefined;
if (entry.VIA() && !via) return [];
return [{
portId,
binding: { kind: "state", slotId: attachment.attachment.id, ...(via ? { via } : {}) },
}];
} }
if (entry.EDGE()) { 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(
@@ -1053,6 +1149,10 @@ const lowerBoundDependencies = (
entry, entry,
`projection on ${attachmentName}`, `projection on ${attachmentName}`,
); );
const via = entry.VIA()
? traversal(identifier(entry.identifier(3)), identifier(entry.identifier(4)))
: undefined;
if (entry.VIA() && !via) return [];
return projectionId return projectionId
? [ ? [
{ {
@@ -1061,6 +1161,7 @@ const lowerBoundDependencies = (
kind: "edge", kind: "edge",
edgeTypeId: attachment.attachment.id, edgeTypeId: attachment.attachment.id,
projectionId, projectionId,
...(via ? { via } : {}),
}, },
}, },
] ]
@@ -1075,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 } : {}),
}, },
}, },
] ]
@@ -1095,6 +1201,50 @@ const lowerBoundDependencies = (
}); });
}; };
const lowerRelationshipMaterialization = (
state: LoweringState,
interfaceName: string,
context: RelationshipMaterializationDeclContext,
): WorkspaceRevision["conformances"][number]["relationshipMaterializations"][number] | undefined => {
const memberName = identifier(context.identifier(0));
const member = requireSymbol(
state,
state.interfaces.get(interfaceName)?.members ?? new Map(),
memberName,
context,
`member on ${interfaceName}`,
);
const constructorAtom = requireSymbol(
state,
state.atoms,
identifier(context.identifier(1)),
context,
"constructor atom",
);
const edgeName = identifier(context.identifier(2));
const edge = requireSymbol(state, state.attachments, edgeName, context, "attachment");
if (edge && edge.attachment.kind !== "edge") {
loweringIssue(state, context, "wrong-attachment-kind", `${edgeName} is state, not an edge`);
}
const projectionId = edge?.attachment.kind === "edge"
? requireSymbol(
state,
edge.projections,
identifier(context.identifier(3)),
context,
`projection on ${edgeName}`,
)
: undefined;
return member && constructorAtom && edge?.attachment.kind === "edge" && projectionId
? {
memberId: member.memberId,
constructorAtomId: constructorAtom,
edgeTypeId: edge.attachment.id,
constructedProjectionId: projectionId,
}
: undefined;
};
const lowerConformance = ( const lowerConformance = (
state: LoweringState, state: LoweringState,
context: ConformanceDeclContext, context: ConformanceDeclContext,
@@ -1246,18 +1396,132 @@ const lowerConformance = (
] ]
: []; : [];
}); });
const relationshipMaterializations = context.conformanceItem().flatMap((item) => {
const materialization = item.relationshipMaterializationDecl();
if (!materialization) return [];
const lowered = lowerRelationshipMaterialization(state, interfaceName, materialization);
return lowered ? [lowered] : [];
});
return { return {
atomId, atomId,
interfaceRevisionId: interfaceSymbol.revisionId, interfaceRevisionId: interfaceSymbol.revisionId,
privateAttachments, privateAttachments,
operationBindings, operationBindings,
relationshipMaterializations,
}; };
}; };
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) {
@@ -1273,40 +1537,13 @@ const lowerWorkspace = (
); );
continue; continue;
} }
const interfaceContext = item.interfaceDecl(); }
if (interfaceContext) {
declareSymbol( const imports = registerImports(
state, state,
state.interfaces, items.flatMap((item) => item.resourceImportDecl() ?? []),
identifier(interfaceContext.identifier()), environment,
{
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 atoms = items.flatMap((item) => { const atoms = items.flatMap((item) => {
const atom = item.atomDecl(); const atom = item.atomDecl();
@@ -1327,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<
@@ -1425,6 +1662,8 @@ const lowerWorkspace = (
}); });
return { return {
imports,
workspace: {
id: capabilityId.workspaceRevision(stringValue(context.stringLiteral(1))), id: capabilityId.workspaceRevision(stringValue(context.stringLiteral(1))),
workspaceId: capabilityId.workspace(stringValue(context.stringLiteral(0))), workspaceId: capabilityId.workspace(stringValue(context.stringLiteral(0))),
parentRevisionIds: [], parentRevisionIds: [],
@@ -1435,13 +1674,14 @@ const lowerWorkspace = (
packageImports, packageImports,
conformances, conformances,
constructors, 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));
@@ -1453,27 +1693,27 @@ export const compileCapabilitySource = (
parser.removeErrorListeners(); parser.removeErrorListeners();
parser.addErrorListener(listener); parser.addErrorListener(listener);
const tree = parser.document(); const tree = parser.document();
if (diagnostics.length > 0) { return { tree, diagnostics };
return { ok: false, diagnostics }; };
}
const state: LoweringState = { const newLoweringState = (
fileName: string,
diagnostics: CapabilitySourceDiagnostic[],
): LoweringState => ({
fileName, fileName,
diagnostics, diagnostics,
atoms: new Map(), atoms: new Map(),
interfaces: new Map(), interfaces: new Map(),
packages: new Map(), packages: new Map(),
attachments: new Map(), attachments: new Map(),
}; });
const workspace = lowerWorkspace(state, tree.workspaceDecl());
if (diagnostics.length > 0) { const validationDiagnostics = (
return { ok: false, diagnostics }; fileName: string,
} issues: ReturnType<typeof compileWorkspaceRevision> extends infer _Result
const compiled = compileWorkspaceRevision(workspace); ? Array<{ code: string; message: string; path: string }>
if (!compiled.ok) { : never,
return { ): CapabilitySourceDiagnostic[] => issues.map((entry) => ({
ok: false,
diagnostics: compiled.issues.map((entry) => ({
phase: "validation", phase: "validation",
code: entry.code, code: entry.code,
message: entry.message, message: entry.message,
@@ -1481,8 +1721,246 @@ export const compileCapabilitySource = (
line: 0, line: 0,
column: 0, column: 0,
path: entry.path, 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) {
return { ok: false, diagnostics };
}
const interfaceContext = tree.interfaceResourceDecl();
const packageContext = tree.packageResourceDecl();
if (!interfaceContext && !packageContext) {
return {
ok: false,
diagnostics: [{
phase: "lowering",
code: "expected-resource",
message: "Expected a standalone interface or package resource document",
fileName,
line: 1,
column: 0,
}],
}; };
} }
return { ok: true, workspace, plan: compiled.plan, diagnostics: [] };
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) {
return { ok: false, diagnostics };
}
const compiled = compileWorkspaceRevision(
resourceValidationWorkspace(resource, environment),
);
if (!compiled.ok) {
return {
ok: false,
diagnostics: validationDiagnostics(fileName, compiled.issues),
};
}
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;
});
+24 -3
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 };
@@ -291,15 +291,17 @@ export interface PackageRevision {
} }
export type DependencyBinding = export type DependencyBinding =
| { kind: "state"; slotId: SlotId } | { kind: "state"; slotId: SlotId; via?: EdgeTraversal }
| { | {
kind: "edge"; kind: "edge";
edgeTypeId: EdgeTypeId; edgeTypeId: EdgeTypeId;
projectionId: EdgeProjectionId; projectionId: EdgeProjectionId;
via?: EdgeTraversal;
} }
| { | {
kind: "receiver-interface"; kind: "interface";
interfaceRevisionId: InterfaceRevisionId; interfaceRevisionId: InterfaceRevisionId;
via?: EdgeTraversal;
} }
| { kind: "constructor"; atomId: AtomId }; | { kind: "constructor"; atomId: AtomId };
@@ -308,6 +310,24 @@ export interface BoundDependency {
binding: DependencyBinding; binding: DependencyBinding;
} }
/** Selects the object at the other end of an exactly-one relationship. */
export interface EdgeTraversal {
edgeTypeId: EdgeTypeId;
projectionId: EdgeProjectionId;
}
/**
* Provisional get-or-create recipe for a relationship implementation. The
* host projection is supplied by the relationship's resolve binding; this
* projection originates at the object constructed for the relationship.
*/
export interface RelationshipMaterialization {
memberId: MemberId;
constructorAtomId: AtomId;
edgeTypeId: EdgeTypeId;
constructedProjectionId: EdgeProjectionId;
}
export type Binding = export type Binding =
| { | {
kind: "state"; kind: "state";
@@ -337,6 +357,7 @@ export interface Conformance {
interfaceRevisionId: InterfaceRevisionId; interfaceRevisionId: InterfaceRevisionId;
privateAttachments: PersistentAttachment[]; privateAttachments: PersistentAttachment[];
operationBindings: OperationBinding[]; operationBindings: OperationBinding[];
relationshipMaterializations: RelationshipMaterialization[];
} }
export interface AtomConstructorBinding { export interface AtomConstructorBinding {
+355 -18
View File
@@ -51,6 +51,7 @@ export type CapabilityValidationIssueCode =
| "duplicate-dependency-port" | "duplicate-dependency-port"
| "duplicate-conformance" | "duplicate-conformance"
| "duplicate-operation-binding" | "duplicate-operation-binding"
| "duplicate-relationship-materialization"
| "duplicate-constructor" | "duplicate-constructor"
| "unresolved-reference" | "unresolved-reference"
| "invalid-attachment" | "invalid-attachment"
@@ -60,11 +61,12 @@ 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"
| "invalid-constructor"; | "invalid-constructor"
| "invalid-relationship-materialization";
export interface CapabilityValidationIssue { export interface CapabilityValidationIssue {
code: CapabilityValidationIssueCode; code: CapabilityValidationIssueCode;
@@ -460,6 +462,16 @@ const atomSatisfiesConstraint = (
? constraint.atomId === atomId ? constraint.atomId === atomId
: conformances.has(conformanceKey(atomId, constraint.interfaceRevisionId)); : conformances.has(conformanceKey(atomId, constraint.interfaceRevisionId));
const constraintSatisfiesConstraint = (
actual: EdgeEndpointConstraint,
required: EdgeEndpointConstraint,
conformances: ReadonlyMap<string, Conformance>,
) => constraintsEqual(actual, required) || (
actual.kind === "atom" &&
required.kind === "interface" &&
atomSatisfiesConstraint(actual.atomId, required, conformances)
);
const canAccessAttachment = ( const canAccessAttachment = (
owner: AttachmentOwner, owner: AttachmentOwner,
conformance: Pick<Conformance, "atomId" | "interfaceRevisionId"> | undefined, conformance: Pick<Conformance, "atomId" | "interfaceRevisionId"> | undefined,
@@ -905,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,
@@ -958,6 +970,54 @@ const validateAttachmentAccess = (
return true; return true;
}; };
const validateTraversal = (
issues: CapabilityValidationIssue[],
indexes: ValidationIndexes,
atomId: AtomId,
traversal: { edgeTypeId: EdgeTypeId; projectionId: EdgeProjectionId },
path: string,
conformance?: Pick<Conformance, "atomId" | "interfaceRevisionId">,
) => {
const attachment = findAttachment(indexes, "edge", traversal.edgeTypeId);
if (!attachment || attachment.attachment.kind !== "edge") {
issue(
issues,
"invalid-dependency-binding",
`${path}.edgeTypeId`,
`Unknown traversal edge ${traversal.edgeTypeId}`,
);
return undefined;
}
validateAttachmentAccess(issues, attachment, conformance, `${path}.edgeTypeId`);
const projection = edgeProjection(attachment.attachment, traversal.projectionId);
if (!projection) {
issue(
issues,
"invalid-dependency-binding",
`${path}.projectionId`,
`Traversal projection ${traversal.projectionId} is not on edge ${traversal.edgeTypeId}`,
);
return undefined;
}
if (!atomSatisfiesConstraint(atomId, projection.endpoint.constraint, indexes.conformances)) {
issue(
issues,
"invalid-dependency-binding",
`${path}.projectionId`,
`Traversal projection ${traversal.projectionId} cannot originate at receiver atom ${atomId}`,
);
}
if (projection.endpoint.cardinality !== "exactly-one") {
issue(
issues,
"invalid-dependency-binding",
`${path}.projectionId`,
"Dependency traversal must select exactly one object",
);
}
return projection;
};
const validateBoundDependencies = ( const validateBoundDependencies = (
issues: CapabilityValidationIssue[], issues: CapabilityValidationIssue[],
params: { params: {
@@ -1020,12 +1080,32 @@ const validateBoundDependencies = (
break; break;
} }
validateAttachmentAccess(issues, attachment, params.conformance, `${path}.binding.slotId`); validateAttachmentAccess(issues, attachment, params.conformance, `${path}.binding.slotId`);
if (attachment.attachment.attachedTo !== params.atomId) { const traversal = stateBinding.via
? validateTraversal(
issues,
params.indexes,
params.atomId,
stateBinding.via,
`${path}.binding.via`,
params.conformance,
)
: undefined;
if (
stateBinding.via
? traversal && !atomSatisfiesConstraint(
attachment.attachment.attachedTo,
traversal.target.constraint,
params.indexes.conformances,
)
: attachment.attachment.attachedTo !== params.atomId
) {
issue( issue(
issues, issues,
"invalid-dependency-binding", "invalid-dependency-binding",
`${path}.binding.slotId`, `${path}.binding.slotId`,
`State ${stateBinding.slotId} is not attached to receiver atom ${params.atomId}`, stateBinding.via
? `State ${stateBinding.slotId} is not attached to the traversal target`
: `State ${stateBinding.slotId} is not attached to receiver atom ${params.atomId}`,
); );
} }
if (!valueTypesEqual(requirement.valueType, attachment.attachment.valueType)) { if (!valueTypesEqual(requirement.valueType, attachment.attachment.valueType)) {
@@ -1061,16 +1141,47 @@ const validateBoundDependencies = (
); );
break; break;
} }
if (!atomSatisfiesConstraint(params.atomId, projection.endpoint.constraint, params.indexes.conformances)) { const traversal = edgeBinding.via
? validateTraversal(
issues,
params.indexes,
params.atomId,
edgeBinding.via,
`${path}.binding.via`,
params.conformance,
)
: undefined;
const originMatches = edgeBinding.via
? traversal && (
projection.endpoint.constraint.kind === "atom"
? atomSatisfiesConstraint(
projection.endpoint.constraint.atomId,
traversal.target.constraint,
params.indexes.conformances,
)
: constraintsEqual(projection.endpoint.constraint, traversal.target.constraint)
)
: atomSatisfiesConstraint(
params.atomId,
projection.endpoint.constraint,
params.indexes.conformances,
);
if (!originMatches) {
issue( issue(
issues, issues,
"invalid-dependency-binding", "invalid-dependency-binding",
`${path}.binding.projectionId`, `${path}.binding.projectionId`,
`Projection ${edgeBinding.projectionId} cannot originate at receiver atom ${params.atomId}`, edgeBinding.via
? `Projection ${edgeBinding.projectionId} cannot originate at the traversal target`
: `Projection ${edgeBinding.projectionId} cannot originate at receiver atom ${params.atomId}`,
); );
} }
if ( if (
!constraintsEqual(requirement.target, projection.target.constraint) || !constraintSatisfiesConstraint(
projection.target.constraint,
requirement.target,
params.indexes.conformances,
) ||
requirement.cardinality !== projection.endpoint.cardinality requirement.cardinality !== projection.endpoint.cardinality
) { ) {
issue( issue(
@@ -1082,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(
@@ -1096,17 +1207,39 @@ const validateBoundDependencies = (
); );
break; break;
} }
const targetKey = conformanceKey(params.atomId, requirement.interfaceRevisionId); const traversal = interfaceBinding.via
? validateTraversal(
issues,
params.indexes,
params.atomId,
interfaceBinding.via,
`${path}.binding.via`,
params.conformance,
)
: 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)) { if (!params.indexes.conformances.has(targetKey)) {
issue( issue(
issues, issues,
"unsatisfied-receiver-interface", "unsatisfied-interface",
`${path}.binding.interfaceRevisionId`, `${path}.binding.interfaceRevisionId`,
`Receiver atom ${params.atomId} does not conform to ${requirement.interfaceRevisionId}`, `${interfaceBinding.via ? "Related" : "Receiver"} atom ${atomId} does not conform to ${requirement.interfaceRevisionId}`,
); );
} else if (params.graphSourceKey) { } else if (params.graphSourceKey) {
params.requirementGraph.get(params.graphSourceKey)?.add(targetKey); params.requirementGraph.get(params.graphSourceKey)?.add(targetKey);
} }
}
break; break;
} }
case "constructor": { case "constructor": {
@@ -1169,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}`,
); );
@@ -1290,8 +1423,21 @@ const validateConformances = (
} }
validateAttachmentAccess(issues, attachment, conformance, `${bindingPath}.binding.edgeTypeId`); validateAttachmentAccess(issues, attachment, conformance, `${bindingPath}.binding.edgeTypeId`);
const projection = edgeProjection(attachment.attachment, binding.projectionId); const projection = edgeProjection(attachment.attachment, binding.projectionId);
const relationshipMember = operationEntry.member.kind === "relationship"
? operationEntry.member
: undefined;
const operationEdge = relationshipMember
? {
...attachment.attachment,
endpoints: attachment.attachment.endpoints.map((endpoint, index) =>
index === (projection?.endpointIndex === 0 ? 1 : 0)
? { ...endpoint, constraint: relationshipMember.target }
: endpoint,
) as [EdgeEndpoint, EdgeEndpoint],
}
: attachment.attachment;
const expected = edgePrimitiveSignature( const expected = edgePrimitiveSignature(
attachment.attachment, operationEdge,
binding.projectionId, binding.projectionId,
binding.primitive, binding.primitive,
); );
@@ -1320,7 +1466,11 @@ const validateConformances = (
"Edge primitives may only implement relationship members", "Edge primitives may only implement relationship members",
); );
} else if ( } else if (
!constraintsEqual(operationEntry.member.target, projection.target.constraint) || !constraintSatisfiesConstraint(
projection.target.constraint,
operationEntry.member.target,
indexes.conformances,
) ||
operationEntry.member.cardinality !== projection.endpoint.cardinality operationEntry.member.cardinality !== projection.endpoint.cardinality
) { ) {
issue( issue(
@@ -1398,6 +1548,148 @@ const validateConformances = (
}); });
} }
const materializedMembers = new Set<string>();
for (const [materializationIndex, materialization] of
(conformance.relationshipMaterializations ?? []).entries()) {
const materializationPath =
`${path}.relationshipMaterializations[${materializationIndex}]`;
if (materializedMembers.has(materialization.memberId)) {
issue(
issues,
"duplicate-relationship-materialization",
materializationPath,
`Relationship ${materialization.memberId} has more than one materialization recipe`,
);
continue;
}
materializedMembers.add(materialization.memberId);
const member = interfaceEntry.revision.members.find((entry) =>
entry.id === materialization.memberId);
if (!member || member.kind !== "relationship") {
issue(
issues,
"invalid-relationship-materialization",
`${materializationPath}.memberId`,
`Member ${materialization.memberId} is not a relationship on ${conformance.interfaceRevisionId}`,
);
continue;
}
if (member.cardinality !== "optional-one") {
issue(
issues,
"invalid-relationship-materialization",
`${materializationPath}.memberId`,
"A lazily constructed relationship must be optional-one before construction",
);
}
const resolveOperation = member.operations.find((entry) =>
entry.displayName === "resolve");
const resolveBinding = resolveOperation
? bindings.get(resolveOperation.id)
: undefined;
if (!resolveBinding || resolveBinding.kind !== "edge") {
issue(
issues,
"invalid-relationship-materialization",
`${materializationPath}.memberId`,
"A materialized relationship must bind its resolve operation to an edge",
);
continue;
}
if (resolveBinding.edgeTypeId !== materialization.edgeTypeId) {
issue(
issues,
"invalid-relationship-materialization",
`${materializationPath}.edgeTypeId`,
"Materialization and relationship resolution must use the same edge",
);
}
const attachment = findAttachment(indexes, "edge", materialization.edgeTypeId);
if (!attachment || attachment.attachment.kind !== "edge") {
issue(
issues,
"invalid-relationship-materialization",
`${materializationPath}.edgeTypeId`,
`Unknown materialization edge ${materialization.edgeTypeId}`,
);
continue;
}
validateAttachmentAccess(
issues,
attachment,
conformance,
`${materializationPath}.edgeTypeId`,
);
const hostProjection = edgeProjection(
attachment.attachment,
resolveBinding.projectionId,
);
const constructedProjection = edgeProjection(
attachment.attachment,
materialization.constructedProjectionId,
);
if (!hostProjection || !constructedProjection ||
hostProjection.endpointIndex === constructedProjection.endpointIndex) {
issue(
issues,
"invalid-relationship-materialization",
`${materializationPath}.constructedProjectionId`,
"Materialization must connect through the opposite projection of the resolved edge",
);
continue;
}
if (!atomSatisfiesConstraint(
materialization.constructorAtomId,
member.target,
indexes.conformances,
)) {
issue(
issues,
"invalid-relationship-materialization",
`${materializationPath}.constructorAtomId`,
`Constructed atom ${materialization.constructorAtomId} does not satisfy the relationship target`,
);
}
if (!atomSatisfiesConstraint(
materialization.constructorAtomId,
constructedProjection.endpoint.constraint,
indexes.conformances,
) || !atomSatisfiesConstraint(
conformance.atomId,
constructedProjection.target.constraint,
indexes.conformances,
)) {
issue(
issues,
"invalid-relationship-materialization",
`${materializationPath}.constructedProjectionId`,
"Constructed projection does not connect the constructed atom back to the host atom",
);
}
const constructor = indexes.constructors.get(materialization.constructorAtomId);
const constructorExport = constructor
? indexes.packages.get(constructor.packageRevisionId)?.exports.get(constructor.exportId)
: undefined;
if (!constructor || !constructorExport || constructorExport.kind !== "constructor") {
issue(
issues,
"invalid-relationship-materialization",
`${materializationPath}.constructorAtomId`,
`Constructed atom ${materialization.constructorAtomId} has no valid constructor`,
);
} else if (!valueTypesEqual(
constructorExport.inputType,
valueType.atomRef(conformance.atomId),
)) {
issue(
issues,
"invalid-relationship-materialization",
`${materializationPath}.constructorAtomId`,
`Component constructor must accept ${typeLabel(valueType.atomRef(conformance.atomId))}`,
);
}
}
for (const operation of interfaceEntry.operations.values()) { for (const operation of interfaceEntry.operations.values()) {
if (!bindings.has(operation.operation.id)) { if (!bindings.has(operation.operation.id)) {
issue( issue(
@@ -1705,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,
@@ -1714,16 +2009,48 @@ export const computeCapabilityClosure = (
switch (dependency.binding.kind) { switch (dependency.binding.kind) {
case "state": case "state":
attachments.add(dependency.binding.slotId); attachments.add(dependency.binding.slotId);
if (dependency.binding.via) {
attachments.add(dependency.binding.via.edgeTypeId);
}
break; break;
case "edge": case "edge":
attachments.add(dependency.binding.edgeTypeId); attachments.add(dependency.binding.edgeTypeId);
if (dependency.binding.via) {
attachments.add(dependency.binding.via.edgeTypeId);
}
break; break;
case "receiver-interface": case "interface": {
if (dependency.binding.via) {
attachments.add(dependency.binding.via.edgeTypeId);
}
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({ queued.push({
atomId, atomId: targetAtom,
interfaceRevisionId: dependency.binding.interfaceRevisionId, 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);
@@ -1772,6 +2099,16 @@ export const computeCapabilityClosure = (
} }
} }
} }
for (const materialization of
conformance.source.relationshipMaterializations ?? []) {
attachments.add(materialization.edgeTypeId);
constructors.add(materialization.constructorAtomId);
const constructor = plan.constructors.get(materialization.constructorAtomId);
if (constructor) {
packages.add(constructor.packageRevisionId);
includeDependencies(materialization.constructorAtomId, constructor.dependencies);
}
}
} }
return { return {
+87 -17
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("ChFxdWl4b3Mvb3JjaC5wcm90bxILcXVpeG9zLm9yY2gipQEKFkNvbnN0cnVjdE9iamVjdFJlcXVlc3QSDwoHYXRvbV9pZBgBIAEoCRI9CgVpbnB1dBgCIAMoCzIuLnF1aXhvcy5vcmNoLkNvbnN0cnVjdE9iamVjdFJlcXVlc3QuSW5wdXRFbnRyeRo7CgpJbnB1dEVudHJ5EgsKA2tleRgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZToCOAEiPwoXQ29uc3RydWN0T2JqZWN0UmVzcG9uc2USJAoGb2JqZWN0GAEgASgLMhQuY2FtaW5vLkNhbWlub09iamVjdCLUAQoXSW52b2tlQ2FwYWJpbGl0eVJlcXVlc3QSKQoKY2FwYWJpbGl0eRgBIAEoCzIVLnF1aXhvcy5DYXBhYmlsaXR5UmVmEhEKCW9iamVjdF9pZBgCIAEoCRI+CgVpbnB1dBgDIAMoCzIvLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXF1ZXN0LklucHV0RW50cnkaOwoKSW5wdXRFbnRyeRILCgNrZXkYASABKAkSHAoFdmFsdWUYAiABKAsyDS5jYW1pbm8uVmFsdWU6AjgBIpgBChhJbnZva2VDYXBhYmlsaXR5UmVzcG9uc2USFQoNaW52b2NhdGlvbl9pZBgBIAEoCRIrCgphY3RpdmF0aW9uGAIgASgLMhcucXVpeG9zLm9yY2guQWN0aXZhdGlvbhIKCgJvaxgDIAEoCBIdCgZyZXN1bHQYBCABKAsyDS5jYW1pbm8uVmFsdWUSDQoFZXJyb3IYBSABKAki0gEKFldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QSKQoKY2FwYWJpbGl0eRgBIAEoCzIVLnF1aXhvcy5DYXBhYmlsaXR5UmVmEhEKCW9iamVjdF9pZBgCIAEoCRI9CgVpbnB1dBgDIAMoCzIuLnF1aXhvcy5vcmNoLldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QuSW5wdXRFbnRyeRo7CgpJbnB1dEVudHJ5EgsKA2tleRgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZToCOAEi4wEKFFdhdGNoQ2FwYWJpbGl0eUV2ZW50EhUKDWludm9jYXRpb25faWQYASABKAkSKwoKYWN0aXZhdGlvbhgCIAEoCzIXLnF1aXhvcy5vcmNoLkFjdGl2YXRpb24SEAoId2F0Y2hfaWQYAyABKAkSHAoFdmFsdWUYBCABKAsyDS5jYW1pbm8uVmFsdWUSNwoMZGVwZW5kZW5jaWVzGAUgAygLMiEucXVpeG9zLnJ1bnRpbWUuRGVyaXZlZERlcGVuZGVuY3kSDQoFZXJyb3IYBiABKAkSDwoHaW5pdGlhbBgHIAEoCCIVChNHZXRXb3Jrc3BhY2VSZXF1ZXN0ImcKFEdldFdvcmtzcGFjZVJlc3BvbnNlEhQKDHdvcmtzcGFjZV9pZBgBIAEoCRIdChV3b3Jrc3BhY2VfcmV2aXNpb25faWQYAiABKAkSGgoSc291cmNlX3Jvb3RfY29tbWl0GAMgASgJIhgKFkxpc3RBY3RpdmF0aW9uc1JlcXVlc3QiHwodTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1JlcXVlc3QiUAoeTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1Jlc3BvbnNlEi4KC2Rlc2NyaXB0b3JzGAEgAygLMhkucXVpeG9zLlBhY2thZ2VEZXNjcmlwdG9yIhwKGkxpc3RQYWNrYWdlUnVudGltZXNSZXF1ZXN0IlIKG0xpc3RQYWNrYWdlUnVudGltZXNSZXNwb25zZRIzCghydW50aW1lcxgBIAMoCzIhLnF1aXhvcy5vcmNoLlBhY2thZ2VSdW50aW1lU3RhdHVzIkcKF0xpc3RBY3RpdmF0aW9uc1Jlc3BvbnNlEiwKC2FjdGl2YXRpb25zGAEgAygLMhcucXVpeG9zLm9yY2guQWN0aXZhdGlvbiI/ChZDbG9zZUFjdGl2YXRpb25SZXF1ZXN0EhUKDWFjdGl2YXRpb25faWQYASABKAkSDgoGcmVhc29uGAIgASgJIkYKF0Nsb3NlQWN0aXZhdGlvblJlc3BvbnNlEisKCmFjdGl2YXRpb24YASABKAsyFy5xdWl4b3Mub3JjaC5BY3RpdmF0aW9uIusBCgpBY3RpdmF0aW9uEhUKDWFjdGl2YXRpb25faWQYASABKAkSKAoGZXhwb3J0GAIgASgLMhgucXVpeG9zLlBhY2thZ2VFeHBvcnRSZWYSEQoJb2JqZWN0X2lkGAMgASgJEg0KBXN0YXRlGAQgASgJEg4KBmRlbWFuZBgFIAEoDRIRCglvcGVuZWRfYXQYBiABKAkSFAoMbGFzdF91c2VkX2F0GAcgASgJEhgKEGlkbGVfZGVhZGxpbmVfYXQYCCABKAkSEQoJY2xvc2VkX2F0GAkgASgJEhQKDGNsb3NlX3JlYXNvbhgKIAEoCSKzAgoUUGFja2FnZVJ1bnRpbWVTdGF0dXMSEwoLcnVudGltZV9rZXkYASABKAkSGwoTcGFja2FnZV9yZXZpc2lvbl9pZBgCIAEoCRIZChFzb3VyY2VfcmVwb3NpdG9yeRgDIAEoCRIVCg1zb3VyY2VfY29tbWl0GAQgASgJEhQKDGJ1aWxkX3RhcmdldBgFIAEoCRITCgtzZXJ2ZXJfcGF0aBgGIAEoCRILCgNwaWQYByABKA0SDQoFc3RhdGUYCCABKAkSEgoKc3RhcnRlZF9hdBgJIAEoCRIZChFsYXN0X2hhbmRzaGFrZV9hdBgKIAEoCRIgChhydW50aW1lX3Byb3RvY29sX3ZlcnNpb24YCyABKAkSHwoXYWR2ZXJ0aXNlZF9leHBvcnRfY291bnQYDCABKA0ynwYKE09yY2hlc3RyYXRvclJ1bnRpbWUSXwoQSW52b2tlQ2FwYWJpbGl0eRIkLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXF1ZXN0GiUucXVpeG9zLm9yY2guSW52b2tlQ2FwYWJpbGl0eVJlc3BvbnNlElsKD1dhdGNoQ2FwYWJpbGl0eRIjLnF1aXhvcy5vcmNoLldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QaIS5xdWl4b3Mub3JjaC5XYXRjaENhcGFiaWxpdHlFdmVudDABElwKD0NvbnN0cnVjdE9iamVjdBIjLnF1aXhvcy5vcmNoLkNvbnN0cnVjdE9iamVjdFJlcXVlc3QaJC5xdWl4b3Mub3JjaC5Db25zdHJ1Y3RPYmplY3RSZXNwb25zZRJTCgxHZXRXb3Jrc3BhY2USIC5xdWl4b3Mub3JjaC5HZXRXb3Jrc3BhY2VSZXF1ZXN0GiEucXVpeG9zLm9yY2guR2V0V29ya3NwYWNlUmVzcG9uc2UScQoWTGlzdFBhY2thZ2VEZXNjcmlwdG9ycxIqLnF1aXhvcy5vcmNoLkxpc3RQYWNrYWdlRGVzY3JpcHRvcnNSZXF1ZXN0GisucXVpeG9zLm9yY2guTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1Jlc3BvbnNlEmgKE0xpc3RQYWNrYWdlUnVudGltZXMSJy5xdWl4b3Mub3JjaC5MaXN0UGFja2FnZVJ1bnRpbWVzUmVxdWVzdBooLnF1aXhvcy5vcmNoLkxpc3RQYWNrYWdlUnVudGltZXNSZXNwb25zZRJcCg9MaXN0QWN0aXZhdGlvbnMSIy5xdWl4b3Mub3JjaC5MaXN0QWN0aXZhdGlvbnNSZXF1ZXN0GiQucXVpeG9zLm9yY2guTGlzdEFjdGl2YXRpb25zUmVzcG9uc2USXAoPQ2xvc2VBY3RpdmF0aW9uEiMucXVpeG9zLm9yY2guQ2xvc2VBY3RpdmF0aW9uUmVxdWVzdBokLnF1aXhvcy5vcmNoLkNsb3NlQWN0aXZhdGlvblJlc3BvbnNlYgZwcm90bzM", [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
@@ -59,6 +59,55 @@ export type ConstructObjectResponse = Message<"quixos.orch.ConstructObjectRespon
export const ConstructObjectResponseSchema: GenMessage<ConstructObjectResponse> = /*@__PURE__*/ export const ConstructObjectResponseSchema: GenMessage<ConstructObjectResponse> = /*@__PURE__*/
messageDesc(file_quixos_orch, 1); messageDesc(file_quixos_orch, 1);
/**
* @generated from message quixos.orch.ResolveOrConstructRelatedObjectRequest
*/
export type ResolveOrConstructRelatedObjectRequest = Message<"quixos.orch.ResolveOrConstructRelatedObjectRequest"> & {
/**
* @generated from field: string object_id = 1;
*/
objectId: string;
/**
* @generated from field: string interface_revision_id = 2;
*/
interfaceRevisionId: string;
/**
* @generated from field: string member_id = 3;
*/
memberId: string;
};
/**
* Describes the message quixos.orch.ResolveOrConstructRelatedObjectRequest.
* Use `create(ResolveOrConstructRelatedObjectRequestSchema)` to create a new message.
*/
export const ResolveOrConstructRelatedObjectRequestSchema: GenMessage<ResolveOrConstructRelatedObjectRequest> = /*@__PURE__*/
messageDesc(file_quixos_orch, 2);
/**
* @generated from message quixos.orch.ResolveOrConstructRelatedObjectResponse
*/
export type ResolveOrConstructRelatedObjectResponse = Message<"quixos.orch.ResolveOrConstructRelatedObjectResponse"> & {
/**
* @generated from field: camino.CaminoObject object = 1;
*/
object?: CaminoObject | undefined;
/**
* @generated from field: bool constructed = 2;
*/
constructed: boolean;
};
/**
* Describes the message quixos.orch.ResolveOrConstructRelatedObjectResponse.
* Use `create(ResolveOrConstructRelatedObjectResponseSchema)` to create a new message.
*/
export const ResolveOrConstructRelatedObjectResponseSchema: GenMessage<ResolveOrConstructRelatedObjectResponse> = /*@__PURE__*/
messageDesc(file_quixos_orch, 3);
/** /**
* @generated from message quixos.orch.InvokeCapabilityRequest * @generated from message quixos.orch.InvokeCapabilityRequest
*/ */
@@ -77,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;
}; };
/** /**
@@ -84,7 +141,7 @@ export type InvokeCapabilityRequest = Message<"quixos.orch.InvokeCapabilityReque
* Use `create(InvokeCapabilityRequestSchema)` to create a new message. * Use `create(InvokeCapabilityRequestSchema)` to create a new message.
*/ */
export const InvokeCapabilityRequestSchema: GenMessage<InvokeCapabilityRequest> = /*@__PURE__*/ export const InvokeCapabilityRequestSchema: GenMessage<InvokeCapabilityRequest> = /*@__PURE__*/
messageDesc(file_quixos_orch, 2); messageDesc(file_quixos_orch, 4);
/** /**
* @generated from message quixos.orch.InvokeCapabilityResponse * @generated from message quixos.orch.InvokeCapabilityResponse
@@ -114,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[];
}; };
/** /**
@@ -121,7 +183,7 @@ export type InvokeCapabilityResponse = Message<"quixos.orch.InvokeCapabilityResp
* Use `create(InvokeCapabilityResponseSchema)` to create a new message. * Use `create(InvokeCapabilityResponseSchema)` to create a new message.
*/ */
export const InvokeCapabilityResponseSchema: GenMessage<InvokeCapabilityResponse> = /*@__PURE__*/ export const InvokeCapabilityResponseSchema: GenMessage<InvokeCapabilityResponse> = /*@__PURE__*/
messageDesc(file_quixos_orch, 3); messageDesc(file_quixos_orch, 5);
/** /**
* @generated from message quixos.orch.WatchCapabilityRequest * @generated from message quixos.orch.WatchCapabilityRequest
@@ -148,7 +210,7 @@ export type WatchCapabilityRequest = Message<"quixos.orch.WatchCapabilityRequest
* Use `create(WatchCapabilityRequestSchema)` to create a new message. * Use `create(WatchCapabilityRequestSchema)` to create a new message.
*/ */
export const WatchCapabilityRequestSchema: GenMessage<WatchCapabilityRequest> = /*@__PURE__*/ export const WatchCapabilityRequestSchema: GenMessage<WatchCapabilityRequest> = /*@__PURE__*/
messageDesc(file_quixos_orch, 4); messageDesc(file_quixos_orch, 6);
/** /**
* @generated from message quixos.orch.WatchCapabilityEvent * @generated from message quixos.orch.WatchCapabilityEvent
@@ -195,7 +257,7 @@ export type WatchCapabilityEvent = Message<"quixos.orch.WatchCapabilityEvent"> &
* Use `create(WatchCapabilityEventSchema)` to create a new message. * Use `create(WatchCapabilityEventSchema)` to create a new message.
*/ */
export const WatchCapabilityEventSchema: GenMessage<WatchCapabilityEvent> = /*@__PURE__*/ export const WatchCapabilityEventSchema: GenMessage<WatchCapabilityEvent> = /*@__PURE__*/
messageDesc(file_quixos_orch, 5); messageDesc(file_quixos_orch, 7);
/** /**
* @generated from message quixos.orch.GetWorkspaceRequest * @generated from message quixos.orch.GetWorkspaceRequest
@@ -208,7 +270,7 @@ export type GetWorkspaceRequest = Message<"quixos.orch.GetWorkspaceRequest"> & {
* Use `create(GetWorkspaceRequestSchema)` to create a new message. * Use `create(GetWorkspaceRequestSchema)` to create a new message.
*/ */
export const GetWorkspaceRequestSchema: GenMessage<GetWorkspaceRequest> = /*@__PURE__*/ export const GetWorkspaceRequestSchema: GenMessage<GetWorkspaceRequest> = /*@__PURE__*/
messageDesc(file_quixos_orch, 6); messageDesc(file_quixos_orch, 8);
/** /**
* @generated from message quixos.orch.GetWorkspaceResponse * @generated from message quixos.orch.GetWorkspaceResponse
@@ -235,7 +297,7 @@ export type GetWorkspaceResponse = Message<"quixos.orch.GetWorkspaceResponse"> &
* Use `create(GetWorkspaceResponseSchema)` to create a new message. * Use `create(GetWorkspaceResponseSchema)` to create a new message.
*/ */
export const GetWorkspaceResponseSchema: GenMessage<GetWorkspaceResponse> = /*@__PURE__*/ export const GetWorkspaceResponseSchema: GenMessage<GetWorkspaceResponse> = /*@__PURE__*/
messageDesc(file_quixos_orch, 7); messageDesc(file_quixos_orch, 9);
/** /**
* @generated from message quixos.orch.ListActivationsRequest * @generated from message quixos.orch.ListActivationsRequest
@@ -248,7 +310,7 @@ export type ListActivationsRequest = Message<"quixos.orch.ListActivationsRequest
* Use `create(ListActivationsRequestSchema)` to create a new message. * Use `create(ListActivationsRequestSchema)` to create a new message.
*/ */
export const ListActivationsRequestSchema: GenMessage<ListActivationsRequest> = /*@__PURE__*/ export const ListActivationsRequestSchema: GenMessage<ListActivationsRequest> = /*@__PURE__*/
messageDesc(file_quixos_orch, 8); messageDesc(file_quixos_orch, 10);
/** /**
* @generated from message quixos.orch.ListPackageDescriptorsRequest * @generated from message quixos.orch.ListPackageDescriptorsRequest
@@ -261,7 +323,7 @@ export type ListPackageDescriptorsRequest = Message<"quixos.orch.ListPackageDesc
* Use `create(ListPackageDescriptorsRequestSchema)` to create a new message. * Use `create(ListPackageDescriptorsRequestSchema)` to create a new message.
*/ */
export const ListPackageDescriptorsRequestSchema: GenMessage<ListPackageDescriptorsRequest> = /*@__PURE__*/ export const ListPackageDescriptorsRequestSchema: GenMessage<ListPackageDescriptorsRequest> = /*@__PURE__*/
messageDesc(file_quixos_orch, 9); messageDesc(file_quixos_orch, 11);
/** /**
* @generated from message quixos.orch.ListPackageDescriptorsResponse * @generated from message quixos.orch.ListPackageDescriptorsResponse
@@ -278,7 +340,7 @@ export type ListPackageDescriptorsResponse = Message<"quixos.orch.ListPackageDes
* Use `create(ListPackageDescriptorsResponseSchema)` to create a new message. * Use `create(ListPackageDescriptorsResponseSchema)` to create a new message.
*/ */
export const ListPackageDescriptorsResponseSchema: GenMessage<ListPackageDescriptorsResponse> = /*@__PURE__*/ export const ListPackageDescriptorsResponseSchema: GenMessage<ListPackageDescriptorsResponse> = /*@__PURE__*/
messageDesc(file_quixos_orch, 10); messageDesc(file_quixos_orch, 12);
/** /**
* @generated from message quixos.orch.ListPackageRuntimesRequest * @generated from message quixos.orch.ListPackageRuntimesRequest
@@ -291,7 +353,7 @@ export type ListPackageRuntimesRequest = Message<"quixos.orch.ListPackageRuntime
* Use `create(ListPackageRuntimesRequestSchema)` to create a new message. * Use `create(ListPackageRuntimesRequestSchema)` to create a new message.
*/ */
export const ListPackageRuntimesRequestSchema: GenMessage<ListPackageRuntimesRequest> = /*@__PURE__*/ export const ListPackageRuntimesRequestSchema: GenMessage<ListPackageRuntimesRequest> = /*@__PURE__*/
messageDesc(file_quixos_orch, 11); messageDesc(file_quixos_orch, 13);
/** /**
* @generated from message quixos.orch.ListPackageRuntimesResponse * @generated from message quixos.orch.ListPackageRuntimesResponse
@@ -308,7 +370,7 @@ export type ListPackageRuntimesResponse = Message<"quixos.orch.ListPackageRuntim
* Use `create(ListPackageRuntimesResponseSchema)` to create a new message. * Use `create(ListPackageRuntimesResponseSchema)` to create a new message.
*/ */
export const ListPackageRuntimesResponseSchema: GenMessage<ListPackageRuntimesResponse> = /*@__PURE__*/ export const ListPackageRuntimesResponseSchema: GenMessage<ListPackageRuntimesResponse> = /*@__PURE__*/
messageDesc(file_quixos_orch, 12); messageDesc(file_quixos_orch, 14);
/** /**
* @generated from message quixos.orch.ListActivationsResponse * @generated from message quixos.orch.ListActivationsResponse
@@ -325,7 +387,7 @@ export type ListActivationsResponse = Message<"quixos.orch.ListActivationsRespon
* Use `create(ListActivationsResponseSchema)` to create a new message. * Use `create(ListActivationsResponseSchema)` to create a new message.
*/ */
export const ListActivationsResponseSchema: GenMessage<ListActivationsResponse> = /*@__PURE__*/ export const ListActivationsResponseSchema: GenMessage<ListActivationsResponse> = /*@__PURE__*/
messageDesc(file_quixos_orch, 13); messageDesc(file_quixos_orch, 15);
/** /**
* @generated from message quixos.orch.CloseActivationRequest * @generated from message quixos.orch.CloseActivationRequest
@@ -347,7 +409,7 @@ export type CloseActivationRequest = Message<"quixos.orch.CloseActivationRequest
* Use `create(CloseActivationRequestSchema)` to create a new message. * Use `create(CloseActivationRequestSchema)` to create a new message.
*/ */
export const CloseActivationRequestSchema: GenMessage<CloseActivationRequest> = /*@__PURE__*/ export const CloseActivationRequestSchema: GenMessage<CloseActivationRequest> = /*@__PURE__*/
messageDesc(file_quixos_orch, 14); messageDesc(file_quixos_orch, 16);
/** /**
* @generated from message quixos.orch.CloseActivationResponse * @generated from message quixos.orch.CloseActivationResponse
@@ -364,7 +426,7 @@ export type CloseActivationResponse = Message<"quixos.orch.CloseActivationRespon
* Use `create(CloseActivationResponseSchema)` to create a new message. * Use `create(CloseActivationResponseSchema)` to create a new message.
*/ */
export const CloseActivationResponseSchema: GenMessage<CloseActivationResponse> = /*@__PURE__*/ export const CloseActivationResponseSchema: GenMessage<CloseActivationResponse> = /*@__PURE__*/
messageDesc(file_quixos_orch, 15); messageDesc(file_quixos_orch, 17);
/** /**
* @generated from message quixos.orch.Activation * @generated from message quixos.orch.Activation
@@ -426,7 +488,7 @@ export type Activation = Message<"quixos.orch.Activation"> & {
* Use `create(ActivationSchema)` to create a new message. * Use `create(ActivationSchema)` to create a new message.
*/ */
export const ActivationSchema: GenMessage<Activation> = /*@__PURE__*/ export const ActivationSchema: GenMessage<Activation> = /*@__PURE__*/
messageDesc(file_quixos_orch, 16); messageDesc(file_quixos_orch, 18);
/** /**
* @generated from message quixos.orch.PackageRuntimeStatus * @generated from message quixos.orch.PackageRuntimeStatus
@@ -498,7 +560,7 @@ export type PackageRuntimeStatus = Message<"quixos.orch.PackageRuntimeStatus"> &
* Use `create(PackageRuntimeStatusSchema)` to create a new message. * Use `create(PackageRuntimeStatusSchema)` to create a new message.
*/ */
export const PackageRuntimeStatusSchema: GenMessage<PackageRuntimeStatus> = /*@__PURE__*/ export const PackageRuntimeStatusSchema: GenMessage<PackageRuntimeStatus> = /*@__PURE__*/
messageDesc(file_quixos_orch, 17); messageDesc(file_quixos_orch, 19);
/** /**
* @generated from service quixos.orch.OrchestratorRuntime * @generated from service quixos.orch.OrchestratorRuntime
@@ -528,6 +590,14 @@ export const OrchestratorRuntime: GenService<{
input: typeof ConstructObjectRequestSchema; input: typeof ConstructObjectRequestSchema;
output: typeof ConstructObjectResponseSchema; output: typeof ConstructObjectResponseSchema;
}, },
/**
* @generated from rpc quixos.orch.OrchestratorRuntime.ResolveOrConstructRelatedObject
*/
resolveOrConstructRelatedObject: {
methodKind: "unary";
input: typeof ResolveOrConstructRelatedObjectRequestSchema;
output: typeof ResolveOrConstructRelatedObjectResponseSchema;
},
/** /**
* @generated from rpc quixos.orch.OrchestratorRuntime.GetWorkspace * @generated from rpc quixos.orch.OrchestratorRuntime.GetWorkspace
*/ */
+11 -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("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zIkQKDUNhcGFiaWxpdHlSZWYSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhQKDG9wZXJhdGlvbl9pZBgCIAEoCSJCChBQYWNrYWdlRXhwb3J0UmVmEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYASABKAkSEQoJZXhwb3J0X2lkGAIgASgJIroBChJJbmplY3RlZERlcGVuZGVuY3kSDwoHcG9ydF9pZBgBIAEoCRIXCg1zdGF0ZV9zbG90X2lkGAIgASgJSAASJgoEZWRnZRgDIAEoCzIWLnF1aXhvcy5FZGdlRGVwZW5kZW5jeUgAEigKHnJlY2VpdmVyX2ludGVyZmFjZV9yZXZpc2lvbl9pZBgEIAEoCUgAEh0KE2NvbnN0cnVjdG9yX2F0b21faWQYBSABKAlIAEIJCgdiaW5kaW5nIj0KDkVkZ2VEZXBlbmRlbmN5EhQKDGVkZ2VfdHlwZV9pZBgBIAEoCRIVCg1wcm9qZWN0aW9uX2lkGAIgASgJYgZwcm90bzM"); 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;
@@ -93,6 +93,14 @@ export type InjectedDependency = Message<"quixos.InjectedDependency"> & {
value: string; value: string;
case: "constructorAtomId"; case: "constructorAtomId";
} | { case: undefined; value?: undefined }; } | { case: undefined; value?: undefined };
/**
* Defaults to the invocation receiver. A checked dependency traversal can
* select a related object explicitly before the package runtime starts.
*
* @generated from field: string object_id = 6;
*/
objectId: string;
}; };
/** /**
+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(
+18 -1
View File
@@ -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,12 @@ null
'package' 'package'
'repository' 'repository'
'commit' 'commit'
'policy'
'ref'
'pinned'
'track-release'
'track-development'
'import'
'{' '{'
'}' '}'
';' ';'
@@ -21,6 +28,7 @@ null
token symbolic names: token symbolic names:
null null
QUIXOS_LOCK QUIXOS_LOCK
FRAGMENT
VERSION VERSION
QUIXOS QUIXOS
SOURCE SOURCE
@@ -28,6 +36,12 @@ INTERFACE
PACKAGE PACKAGE
REPOSITORY REPOSITORY
COMMIT COMMIT
POLICY
REF
PINNED
TRACK_RELEASE
TRACK_DEVELOPMENT
IMPORT
LBRACE LBRACE
RBRACE RBRACE
SEMI SEMI
@@ -42,11 +56,14 @@ rule names:
document document
quixosEntry quixosEntry
resourceEntry resourceEntry
importEntry
resourceKind resourceKind
sourceBlock sourceBlock
quixosSourceBlock
sourcePolicy
identifier identifier
stringLiteral 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, 24, 87, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 1, 0, 1, 0, 3, 0, 23, 8, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 31, 8, 0, 10, 0, 12, 0, 34, 9, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 74, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 0, 0, 10, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 0, 2, 1, 0, 6, 7, 1, 0, 12, 14, 81, 0, 20, 1, 0, 0, 0, 2, 38, 1, 0, 0, 0, 4, 42, 1, 0, 0, 0, 6, 47, 1, 0, 0, 0, 8, 51, 1, 0, 0, 0, 10, 53, 1, 0, 0, 0, 12, 62, 1, 0, 0, 0, 14, 80, 1, 0, 0, 0, 16, 82, 1, 0, 0, 0, 18, 84, 1, 0, 0, 0, 20, 22, 5, 1, 0, 0, 21, 23, 5, 2, 0, 0, 22, 21, 1, 0, 0, 0, 22, 23, 1, 0, 0, 0, 23, 24, 1, 0, 0, 0, 24, 25, 5, 3, 0, 0, 25, 26, 5, 19, 0, 0, 26, 32, 5, 16, 0, 0, 27, 31, 3, 2, 1, 0, 28, 31, 3, 6, 3, 0, 29, 31, 3, 4, 2, 0, 30, 27, 1, 0, 0, 0, 30, 28, 1, 0, 0, 0, 30, 29, 1, 0, 0, 0, 31, 34, 1, 0, 0, 0, 32, 30, 1, 0, 0, 0, 32, 33, 1, 0, 0, 0, 33, 35, 1, 0, 0, 0, 34, 32, 1, 0, 0, 0, 35, 36, 5, 17, 0, 0, 36, 37, 5, 0, 0, 1, 37, 1, 1, 0, 0, 0, 38, 39, 5, 4, 0, 0, 39, 40, 5, 5, 0, 0, 40, 41, 3, 12, 6, 0, 41, 3, 1, 0, 0, 0, 42, 43, 3, 8, 4, 0, 43, 44, 3, 16, 8, 0, 44, 45, 5, 5, 0, 0, 45, 46, 3, 10, 5, 0, 46, 5, 1, 0, 0, 0, 47, 48, 5, 15, 0, 0, 48, 49, 3, 18, 9, 0, 49, 50, 5, 18, 0, 0, 50, 7, 1, 0, 0, 0, 51, 52, 7, 0, 0, 0, 52, 9, 1, 0, 0, 0, 53, 54, 5, 16, 0, 0, 54, 55, 5, 8, 0, 0, 55, 56, 3, 18, 9, 0, 56, 57, 5, 18, 0, 0, 57, 58, 5, 9, 0, 0, 58, 59, 3, 18, 9, 0, 59, 60, 5, 18, 0, 0, 60, 61, 5, 17, 0, 0, 61, 11, 1, 0, 0, 0, 62, 63, 5, 16, 0, 0, 63, 64, 5, 8, 0, 0, 64, 65, 3, 18, 9, 0, 65, 73, 5, 18, 0, 0, 66, 67, 5, 10, 0, 0, 67, 68, 3, 14, 7, 0, 68, 69, 5, 18, 0, 0, 69, 70, 5, 11, 0, 0, 70, 71, 3, 18, 9, 0, 71, 72, 5, 18, 0, 0, 72, 74, 1, 0, 0, 0, 73, 66, 1, 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 75, 1, 0, 0, 0, 75, 76, 5, 9, 0, 0, 76, 77, 3, 18, 9, 0, 77, 78, 5, 18, 0, 0, 78, 79, 5, 17, 0, 0, 79, 13, 1, 0, 0, 0, 80, 81, 7, 1, 0, 0, 81, 15, 1, 0, 0, 0, 82, 83, 5, 20, 0, 0, 83, 17, 1, 0, 0, 0, 84, 85, 5, 21, 0, 0, 85, 19, 1, 0, 0, 0, 4, 22, 30, 32, 73]
+40 -26
View File
@@ -1,28 +1,42 @@
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 POLICY=10
SEMI=11 REF=11
INTEGER=12 PINNED=12
IDENTIFIER=13 TRACK_RELEASE=13
STRING_LITERAL=14 TRACK_DEVELOPMENT=14
LINE_COMMENT=15 IMPORT=15
BLOCK_COMMENT=16 LBRACE=16
WS=17 RBRACE=17
SEMI=18
INTEGER=19
IDENTIFIER=20
STRING_LITERAL=21
LINE_COMMENT=22
BLOCK_COMMENT=23
WS=24
'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 'policy'=10
';'=11 'ref'=11
'pinned'=12
'track-release'=13
'track-development'=14
'import'=15
'{'=16
'}'=17
';'=18
File diff suppressed because one or more lines are too long
@@ -1,28 +1,42 @@
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 POLICY=10
SEMI=11 REF=11
INTEGER=12 PINNED=12
IDENTIFIER=13 TRACK_RELEASE=13
STRING_LITERAL=14 TRACK_DEVELOPMENT=14
LINE_COMMENT=15 IMPORT=15
BLOCK_COMMENT=16 LBRACE=16
WS=17 RBRACE=17
SEMI=18
INTEGER=19
IDENTIFIER=20
STRING_LITERAL=21
LINE_COMMENT=22
BLOCK_COMMENT=23
WS=24
'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 'policy'=10
';'=11 'ref'=11
'pinned'=12
'track-release'=13
'track-development'=14
'import'=15
'{'=16
'}'=17
';'=18
+126 -87
View File
@@ -5,37 +5,47 @@ 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 POLICY = 10;
public static readonly SEMI = 11; public static readonly REF = 11;
public static readonly INTEGER = 12; public static readonly PINNED = 12;
public static readonly IDENTIFIER = 13; public static readonly TRACK_RELEASE = 13;
public static readonly STRING_LITERAL = 14; public static readonly TRACK_DEVELOPMENT = 14;
public static readonly LINE_COMMENT = 15; public static readonly IMPORT = 15;
public static readonly BLOCK_COMMENT = 16; public static readonly LBRACE = 16;
public static readonly WS = 17; public static readonly RBRACE = 17;
public static readonly SEMI = 18;
public static readonly INTEGER = 19;
public static readonly IDENTIFIER = 20;
public static readonly STRING_LITERAL = 21;
public static readonly LINE_COMMENT = 22;
public static readonly BLOCK_COMMENT = 23;
public static readonly WS = 24;
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'", "'policy'",
"'ref'", "'pinned'", "'track-release'", "'track-development'", "'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", "POLICY", "REF",
"IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT", "BLOCK_COMMENT", "PINNED", "TRACK_RELEASE", "TRACK_DEVELOPMENT", "IMPORT", "LBRACE",
"WS" "RBRACE", "SEMI", "INTEGER", "IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT",
"BLOCK_COMMENT", "WS"
]; ];
public static readonly modeNames = [ public static readonly modeNames = [
@@ -43,9 +53,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", "POLICY", "REF", "PINNED", "TRACK_RELEASE",
"STRING_LITERAL", "ESC", "HEX", "LINE_COMMENT", "BLOCK_COMMENT", "TRACK_DEVELOPMENT", "IMPORT", "LBRACE", "RBRACE", "SEMI", "INTEGER",
"IDENTIFIER", "STRING_LITERAL", "ESC", "HEX", "LINE_COMMENT", "BLOCK_COMMENT",
"WS", "WS",
]; ];
@@ -68,70 +79,98 @@ 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,24,261,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,
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,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,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, 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,
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,1,1,1,1,1,1,1,1,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,3,1,
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, 3,1,3,1,3,1,3,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,5,1,5,1,5,1,5,1,5,1,
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, 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,
11,12,11,118,1,12,1,12,5,12,123,8,12,10,12,12,12,126,9,12,1,13,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,1,8,1,8,1,9,1,
13,1,13,5,13,131,8,13,10,13,12,13,134,9,13,1,13,1,13,1,14,1,14,1, 9,1,9,1,9,1,9,1,9,1,9,1,10,1,10,1,10,1,10,1,11,1,11,1,11,1,11,1,
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, 11,1,11,1,11,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,
16,1,16,5,16,154,8,16,10,16,12,16,157,9,16,1,16,1,16,1,17,1,17,1, 12,1,12,1,12,1,12,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,
17,1,17,5,17,165,8,17,10,17,12,17,168,9,17,1,17,1,17,1,17,1,17,1, 13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,14,1,14,1,14,1,14,1,
17,1,18,4,18,176,8,18,11,18,12,18,177,1,18,1,18,1,166,0,19,1,1,3, 14,1,14,1,14,1,15,1,15,1,16,1,16,1,17,1,17,1,18,4,18,197,8,18,11,
18,12,18,198,1,19,1,19,5,19,203,8,19,10,19,12,19,206,9,19,1,20,1,
20,1,20,5,20,211,8,20,10,20,12,20,214,9,20,1,20,1,20,1,21,1,21,1,
21,1,21,1,21,1,21,1,21,1,21,3,21,226,8,21,1,22,1,22,1,23,1,23,1,
23,1,23,5,23,234,8,23,10,23,12,23,237,9,23,1,23,1,23,1,24,1,24,1,
24,1,24,5,24,245,8,24,10,24,12,24,248,9,24,1,24,1,24,1,24,1,24,1,
24,1,25,4,25,256,8,25,11,25,12,25,257,1,25,1,25,1,246,0,26,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,27,14, 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,
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, 29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,0,45,0,47,22,49,23,
4,0,48,57,65,90,95,95,97,122,4,0,10,10,13,13,34,34,92,92,8,0,34, 51,24,1,0,8,1,0,48,57,3,0,65,90,95,95,97,122,4,0,48,57,65,90,95,
34,47,47,92,92,98,98,102,102,110,110,114,114,116,116,3,0,48,57,65, 95,97,122,4,0,10,10,13,13,34,34,92,92,8,0,34,34,47,47,92,92,98,98,
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, 102,102,110,110,114,114,116,116,3,0,48,57,65,70,97,102,2,0,10,10,
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, 13,13,3,0,9,10,13,13,32,32,266,0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,
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,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0,0,0,13,1,0,0,0,0,15,1,0,0,0,
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,17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,23,1,0,0,0,0,25,1,0,0,0,
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,27,1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,
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,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,0,
0,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,51,1,0,0,0,1,53,1,0,0,0,3,65,1,0,0,0,5,74,1,0,0,0,7,82,1,0,0,0,
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, 9,89,1,0,0,0,11,96,1,0,0,0,13,106,1,0,0,0,15,114,1,0,0,0,17,125,
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, 1,0,0,0,19,132,1,0,0,0,21,139,1,0,0,0,23,143,1,0,0,0,25,150,1,0,
0,0,42,43,5,120,0,0,43,44,5,111,0,0,44,45,5,115,0,0,45,46,5,45,0, 0,0,27,164,1,0,0,0,29,182,1,0,0,0,31,189,1,0,0,0,33,191,1,0,0,0,
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, 35,193,1,0,0,0,37,196,1,0,0,0,39,200,1,0,0,0,41,207,1,0,0,0,43,217,
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, 1,0,0,0,45,227,1,0,0,0,47,229,1,0,0,0,49,240,1,0,0,0,51,255,1,0,
55,5,115,0,0,55,56,5,105,0,0,56,57,5,111,0,0,57,58,5,110,0,0,58, 0,0,53,54,5,113,0,0,54,55,5,117,0,0,55,56,5,105,0,0,56,57,5,120,
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, 0,0,57,58,5,111,0,0,58,59,5,115,0,0,59,60,5,45,0,0,60,61,5,108,0,
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, 0,61,62,5,111,0,0,62,63,5,99,0,0,63,64,5,107,0,0,64,2,1,0,0,0,65,
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, 66,5,102,0,0,66,67,5,114,0,0,67,68,5,97,0,0,68,69,5,103,0,0,69,70,
0,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, 5,109,0,0,70,71,5,101,0,0,71,72,5,110,0,0,72,73,5,116,0,0,73,4,1,
76,5,116,0,0,76,77,5,101,0,0,77,78,5,114,0,0,78,79,5,102,0,0,79, 0,0,0,74,75,5,118,0,0,75,76,5,101,0,0,76,77,5,114,0,0,77,78,5,115,
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, 0,0,78,79,5,105,0,0,79,80,5,111,0,0,80,81,5,110,0,0,81,6,1,0,0,0,
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, 82,83,5,113,0,0,83,84,5,117,0,0,84,85,5,105,0,0,85,86,5,120,0,0,
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, 86,87,5,111,0,0,87,88,5,115,0,0,88,8,1,0,0,0,89,90,5,115,0,0,90,
0,92,93,5,101,0,0,93,94,5,112,0,0,94,95,5,111,0,0,95,96,5,115,0, 91,5,111,0,0,91,92,5,117,0,0,92,93,5,114,0,0,93,94,5,99,0,0,94,95,
0,96,97,5,105,0,0,97,98,5,116,0,0,98,99,5,111,0,0,99,100,5,114,0, 5,101,0,0,95,10,1,0,0,0,96,97,5,105,0,0,97,98,5,110,0,0,98,99,5,
0,100,101,5,121,0,0,101,14,1,0,0,0,102,103,5,99,0,0,103,104,5,111, 116,0,0,99,100,5,101,0,0,100,101,5,114,0,0,101,102,5,102,0,0,102,
0,0,104,105,5,109,0,0,105,106,5,109,0,0,106,107,5,105,0,0,107,108, 103,5,97,0,0,103,104,5,99,0,0,104,105,5,101,0,0,105,12,1,0,0,0,106,
5,116,0,0,108,16,1,0,0,0,109,110,5,123,0,0,110,18,1,0,0,0,111,112, 107,5,112,0,0,107,108,5,97,0,0,108,109,5,99,0,0,109,110,5,107,0,
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,110,111,5,97,0,0,111,112,5,103,0,0,112,113,5,101,0,0,113,14,1,
7,0,0,0,116,115,1,0,0,0,117,118,1,0,0,0,118,116,1,0,0,0,118,119, 0,0,0,114,115,5,114,0,0,115,116,5,101,0,0,116,117,5,112,0,0,117,
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, 118,5,111,0,0,118,119,5,115,0,0,119,120,5,105,0,0,120,121,5,116,
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,121,122,5,111,0,0,122,123,5,114,0,0,123,124,5,121,0,0,124,16,
0,0,126,124,1,0,0,0,127,132,5,34,0,0,128,131,3,29,14,0,129,131,8, 1,0,0,0,125,126,5,99,0,0,126,127,5,111,0,0,127,128,5,109,0,0,128,
3,0,0,130,128,1,0,0,0,130,129,1,0,0,0,131,134,1,0,0,0,132,130,1, 129,5,109,0,0,129,130,5,105,0,0,130,131,5,116,0,0,131,18,1,0,0,0,
0,0,0,132,133,1,0,0,0,133,135,1,0,0,0,134,132,1,0,0,0,135,136,5, 132,133,5,112,0,0,133,134,5,111,0,0,134,135,5,108,0,0,135,136,5,
34,0,0,136,28,1,0,0,0,137,145,5,92,0,0,138,146,7,4,0,0,139,140,5, 105,0,0,136,137,5,99,0,0,137,138,5,121,0,0,138,20,1,0,0,0,139,140,
117,0,0,140,141,3,31,15,0,141,142,3,31,15,0,142,143,3,31,15,0,143, 5,114,0,0,140,141,5,101,0,0,141,142,5,102,0,0,142,22,1,0,0,0,143,
144,3,31,15,0,144,146,1,0,0,0,145,138,1,0,0,0,145,139,1,0,0,0,146, 144,5,112,0,0,144,145,5,105,0,0,145,146,5,110,0,0,146,147,5,110,
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, 0,0,147,148,5,101,0,0,148,149,5,100,0,0,149,24,1,0,0,0,150,151,5,
5,47,0,0,151,155,1,0,0,0,152,154,8,6,0,0,153,152,1,0,0,0,154,157, 116,0,0,151,152,5,114,0,0,152,153,5,97,0,0,153,154,5,99,0,0,154,
1,0,0,0,155,153,1,0,0,0,155,156,1,0,0,0,156,158,1,0,0,0,157,155, 155,5,107,0,0,155,156,5,45,0,0,156,157,5,114,0,0,157,158,5,101,0,
1,0,0,0,158,159,6,16,0,0,159,34,1,0,0,0,160,161,5,47,0,0,161,162, 0,158,159,5,108,0,0,159,160,5,101,0,0,160,161,5,97,0,0,161,162,5,
5,42,0,0,162,166,1,0,0,0,163,165,9,0,0,0,164,163,1,0,0,0,165,168, 115,0,0,162,163,5,101,0,0,163,26,1,0,0,0,164,165,5,116,0,0,165,166,
1,0,0,0,166,167,1,0,0,0,166,164,1,0,0,0,167,169,1,0,0,0,168,166, 5,114,0,0,166,167,5,97,0,0,167,168,5,99,0,0,168,169,5,107,0,0,169,
1,0,0,0,169,170,5,42,0,0,170,171,5,47,0,0,171,172,1,0,0,0,172,173, 170,5,45,0,0,170,171,5,100,0,0,171,172,5,101,0,0,172,173,5,118,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, 0,173,174,5,101,0,0,174,175,5,108,0,0,175,176,5,111,0,0,176,177,
1,0,0,0,177,175,1,0,0,0,177,178,1,0,0,0,178,179,1,0,0,0,179,180, 5,112,0,0,177,178,5,109,0,0,178,179,5,101,0,0,179,180,5,110,0,0,
6,18,0,0,180,38,1,0,0,0,9,0,118,124,130,132,145,155,166,177,1,6, 180,181,5,116,0,0,181,28,1,0,0,0,182,183,5,105,0,0,183,184,5,109,
0,0,184,185,5,112,0,0,185,186,5,111,0,0,186,187,5,114,0,0,187,188,
5,116,0,0,188,30,1,0,0,0,189,190,5,123,0,0,190,32,1,0,0,0,191,192,
5,125,0,0,192,34,1,0,0,0,193,194,5,59,0,0,194,36,1,0,0,0,195,197,
7,0,0,0,196,195,1,0,0,0,197,198,1,0,0,0,198,196,1,0,0,0,198,199,
1,0,0,0,199,38,1,0,0,0,200,204,7,1,0,0,201,203,7,2,0,0,202,201,1,
0,0,0,203,206,1,0,0,0,204,202,1,0,0,0,204,205,1,0,0,0,205,40,1,0,
0,0,206,204,1,0,0,0,207,212,5,34,0,0,208,211,3,43,21,0,209,211,8,
3,0,0,210,208,1,0,0,0,210,209,1,0,0,0,211,214,1,0,0,0,212,210,1,
0,0,0,212,213,1,0,0,0,213,215,1,0,0,0,214,212,1,0,0,0,215,216,5,
34,0,0,216,42,1,0,0,0,217,225,5,92,0,0,218,226,7,4,0,0,219,220,5,
117,0,0,220,221,3,45,22,0,221,222,3,45,22,0,222,223,3,45,22,0,223,
224,3,45,22,0,224,226,1,0,0,0,225,218,1,0,0,0,225,219,1,0,0,0,226,
44,1,0,0,0,227,228,7,5,0,0,228,46,1,0,0,0,229,230,5,47,0,0,230,231,
5,47,0,0,231,235,1,0,0,0,232,234,8,6,0,0,233,232,1,0,0,0,234,237,
1,0,0,0,235,233,1,0,0,0,235,236,1,0,0,0,236,238,1,0,0,0,237,235,
1,0,0,0,238,239,6,23,0,0,239,48,1,0,0,0,240,241,5,47,0,0,241,242,
5,42,0,0,242,246,1,0,0,0,243,245,9,0,0,0,244,243,1,0,0,0,245,248,
1,0,0,0,246,247,1,0,0,0,246,244,1,0,0,0,247,249,1,0,0,0,248,246,
1,0,0,0,249,250,5,42,0,0,250,251,5,47,0,0,251,252,1,0,0,0,252,253,
6,24,0,0,253,50,1,0,0,0,254,256,7,7,0,0,255,254,1,0,0,0,256,257,
1,0,0,0,257,255,1,0,0,0,257,258,1,0,0,0,258,259,1,0,0,0,259,260,
6,25,0,0,260,52,1,0,0,0,9,0,198,204,210,212,225,235,246,257,1,6,
0,0 0,0
]; ];
+381 -86
View File
@@ -11,44 +11,58 @@ 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 POLICY = 10;
public static readonly SEMI = 11; public static readonly REF = 11;
public static readonly INTEGER = 12; public static readonly PINNED = 12;
public static readonly IDENTIFIER = 13; public static readonly TRACK_RELEASE = 13;
public static readonly STRING_LITERAL = 14; public static readonly TRACK_DEVELOPMENT = 14;
public static readonly LINE_COMMENT = 15; public static readonly IMPORT = 15;
public static readonly BLOCK_COMMENT = 16; public static readonly LBRACE = 16;
public static readonly WS = 17; public static readonly RBRACE = 17;
public static readonly SEMI = 18;
public static readonly INTEGER = 19;
public static readonly IDENTIFIER = 20;
public static readonly STRING_LITERAL = 21;
public static readonly LINE_COMMENT = 22;
public static readonly BLOCK_COMMENT = 23;
public static readonly WS = 24;
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_quixosSourceBlock = 6;
public static readonly RULE_sourcePolicy = 7;
public static readonly RULE_identifier = 8;
public static readonly RULE_stringLiteral = 9;
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'", "'policy'",
"'ref'", "'pinned'", "'track-release'", "'track-development'", "'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", "POLICY", "REF",
"IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT", "BLOCK_COMMENT", "PINNED", "TRACK_RELEASE", "TRACK_DEVELOPMENT", "IMPORT", "LBRACE",
"WS" "RBRACE", "SEMI", "INTEGER", "IDENTIFIER", "STRING_LITERAL", "LINE_COMMENT",
"BLOCK_COMMENT", "WS"
]; ];
public static readonly ruleNames = [ public static readonly ruleNames = [
"document", "quixosEntry", "resourceEntry", "resourceKind", "sourceBlock", "document", "quixosEntry", "resourceEntry", "importEntry", "resourceKind",
"identifier", "stringLiteral", "sourceBlock", "quixosSourceBlock", "sourcePolicy", "identifier",
"stringLiteral",
]; ];
public get grammarFileName(): string { return "QuixosLock.g4"; } public get grammarFileName(): string { return "QuixosLock.g4"; }
@@ -72,33 +86,62 @@ export class QuixosLockParser extends antlr.Parser {
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 14; this.state = 20;
this.match(QuixosLockParser.QUIXOS_LOCK); this.match(QuixosLockParser.QUIXOS_LOCK);
this.state = 15;
this.match(QuixosLockParser.VERSION);
this.state = 16;
this.match(QuixosLockParser.INTEGER);
this.state = 17;
this.match(QuixosLockParser.LBRACE);
this.state = 18;
this.quixosEntry();
this.state = 22; 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 = 21;
this.match(QuixosLockParser.FRAGMENT);
}
}
this.state = 24;
this.match(QuixosLockParser.VERSION);
this.state = 25;
this.match(QuixosLockParser.INTEGER);
this.state = 26;
this.match(QuixosLockParser.LBRACE);
this.state = 32;
this.errorHandler.sync(this);
_la = this.tokenStream.LA(1);
while ((((_la) & ~0x1F) === 0 && ((1 << _la) & 32976) !== 0)) {
{ {
this.state = 19; this.state = 30;
this.errorHandler.sync(this);
switch (this.tokenStream.LA(1)) {
case QuixosLockParser.QUIXOS:
{
this.state = 27;
this.quixosEntry();
}
break;
case QuixosLockParser.IMPORT:
{
this.state = 28;
this.importEntry();
}
break;
case QuixosLockParser.INTERFACE:
case QuixosLockParser.PACKAGE:
{
this.state = 29;
this.resourceEntry(); this.resourceEntry();
} }
break;
default:
throw new antlr.NoViableAltException(this);
} }
this.state = 24; }
this.state = 34;
this.errorHandler.sync(this); this.errorHandler.sync(this);
_la = this.tokenStream.LA(1); _la = this.tokenStream.LA(1);
} }
this.state = 25; this.state = 35;
this.match(QuixosLockParser.RBRACE); this.match(QuixosLockParser.RBRACE);
this.state = 26; this.state = 36;
this.match(QuixosLockParser.EOF); this.match(QuixosLockParser.EOF);
} }
} }
@@ -121,12 +164,12 @@ export class QuixosLockParser extends antlr.Parser {
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 28; this.state = 38;
this.match(QuixosLockParser.QUIXOS); this.match(QuixosLockParser.QUIXOS);
this.state = 29; this.state = 39;
this.match(QuixosLockParser.SOURCE); this.match(QuixosLockParser.SOURCE);
this.state = 30; this.state = 40;
this.sourceBlock(); this.quixosSourceBlock();
} }
} }
catch (re) { catch (re) {
@@ -148,13 +191,13 @@ export class QuixosLockParser extends antlr.Parser {
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 32; this.state = 42;
this.resourceKind(); this.resourceKind();
this.state = 33; this.state = 43;
this.identifier(); this.identifier();
this.state = 34; this.state = 44;
this.match(QuixosLockParser.SOURCE); this.match(QuixosLockParser.SOURCE);
this.state = 35; this.state = 45;
this.sourceBlock(); this.sourceBlock();
} }
} }
@@ -171,16 +214,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 = 47;
this.match(QuixosLockParser.IMPORT);
this.state = 48;
this.stringLiteral();
this.state = 49;
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 = 51;
_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 +274,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 = 53;
this.match(QuixosLockParser.LBRACE); this.match(QuixosLockParser.LBRACE);
this.state = 40; this.state = 54;
this.match(QuixosLockParser.REPOSITORY); this.match(QuixosLockParser.REPOSITORY);
this.state = 41; this.state = 55;
this.stringLiteral(); this.stringLiteral();
this.state = 42; this.state = 56;
this.match(QuixosLockParser.SEMI); this.match(QuixosLockParser.SEMI);
this.state = 43; this.state = 57;
this.match(QuixosLockParser.COMMIT); this.match(QuixosLockParser.COMMIT);
this.state = 44; this.state = 58;
this.stringLiteral(); this.stringLiteral();
this.state = 45; this.state = 59;
this.match(QuixosLockParser.SEMI); this.match(QuixosLockParser.SEMI);
this.state = 46; this.state = 60;
this.match(QuixosLockParser.RBRACE); this.match(QuixosLockParser.RBRACE);
} }
} }
@@ -239,13 +309,102 @@ export class QuixosLockParser extends antlr.Parser {
} }
return localContext; return localContext;
} }
public quixosSourceBlock(): QuixosSourceBlockContext {
let localContext = new QuixosSourceBlockContext(this.context, this.state);
this.enterRule(localContext, 12, QuixosLockParser.RULE_quixosSourceBlock);
let _la: number;
try {
this.enterOuterAlt(localContext, 1);
{
this.state = 62;
this.match(QuixosLockParser.LBRACE);
this.state = 63;
this.match(QuixosLockParser.REPOSITORY);
this.state = 64;
this.stringLiteral();
this.state = 65;
this.match(QuixosLockParser.SEMI);
this.state = 73;
this.errorHandler.sync(this);
_la = this.tokenStream.LA(1);
if (_la === 10) {
{
this.state = 66;
this.match(QuixosLockParser.POLICY);
this.state = 67;
this.sourcePolicy();
this.state = 68;
this.match(QuixosLockParser.SEMI);
this.state = 69;
this.match(QuixosLockParser.REF);
this.state = 70;
this.stringLiteral();
this.state = 71;
this.match(QuixosLockParser.SEMI);
}
}
this.state = 75;
this.match(QuixosLockParser.COMMIT);
this.state = 76;
this.stringLiteral();
this.state = 77;
this.match(QuixosLockParser.SEMI);
this.state = 78;
this.match(QuixosLockParser.RBRACE);
}
}
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 sourcePolicy(): SourcePolicyContext {
let localContext = new SourcePolicyContext(this.context, this.state);
this.enterRule(localContext, 14, QuixosLockParser.RULE_sourcePolicy);
let _la: number;
try {
this.enterOuterAlt(localContext, 1);
{
this.state = 80;
_la = this.tokenStream.LA(1);
if(!((((_la) & ~0x1F) === 0 && ((1 << _la) & 28672) !== 0))) {
this.errorHandler.recoverInline(this);
}
else {
this.errorHandler.reportMatch(this);
this.consume();
}
}
}
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 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, 16, QuixosLockParser.RULE_identifier);
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 48; this.state = 82;
this.match(QuixosLockParser.IDENTIFIER); this.match(QuixosLockParser.IDENTIFIER);
} }
} }
@@ -264,11 +423,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, 18, QuixosLockParser.RULE_stringLiteral);
try { try {
this.enterOuterAlt(localContext, 1); this.enterOuterAlt(localContext, 1);
{ {
this.state = 50; this.state = 84;
this.match(QuixosLockParser.STRING_LITERAL); this.match(QuixosLockParser.STRING_LITERAL);
} }
} }
@@ -287,21 +446,31 @@ 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,24,87,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,
6,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,2,8,7,8,2,9,7,9,1,0,1,0,3,0,23,8,0,1,0,1,0,1,0,1,0,1,0,
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, 1,0,5,0,31,8,0,10,0,12,0,34,9,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,2,
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,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,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,5,1,5,1,5,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,3,6,74,8,
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, 6,1,6,1,6,1,6,1,6,1,6,1,7,1,7,1,8,1,8,1,9,1,9,1,9,0,0,10,0,2,4,6,
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, 8,10,12,14,16,18,0,2,1,0,6,7,1,0,12,14,81,0,20,1,0,0,0,2,38,1,0,
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, 0,0,4,42,1,0,0,0,6,47,1,0,0,0,8,51,1,0,0,0,10,53,1,0,0,0,12,62,1,
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,0,14,80,1,0,0,0,16,82,1,0,0,0,18,84,1,0,0,0,20,22,5,1,0,0,21,
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,5,2,0,0,22,21,1,0,0,0,22,23,1,0,0,0,23,24,1,0,0,0,24,25,5,3,0,
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,25,26,5,19,0,0,26,32,5,16,0,0,27,31,3,2,1,0,28,31,3,6,3,0,29,31,
0,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, 3,4,2,0,30,27,1,0,0,0,30,28,1,0,0,0,30,29,1,0,0,0,31,34,1,0,0,0,
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, 32,30,1,0,0,0,32,33,1,0,0,0,33,35,1,0,0,0,34,32,1,0,0,0,35,36,5,
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, 17,0,0,36,37,5,0,0,1,37,1,1,0,0,0,38,39,5,4,0,0,39,40,5,5,0,0,40,
13,1,0,0,0,1,22 41,3,12,6,0,41,3,1,0,0,0,42,43,3,8,4,0,43,44,3,16,8,0,44,45,5,5,
0,0,45,46,3,10,5,0,46,5,1,0,0,0,47,48,5,15,0,0,48,49,3,18,9,0,49,
50,5,18,0,0,50,7,1,0,0,0,51,52,7,0,0,0,52,9,1,0,0,0,53,54,5,16,0,
0,54,55,5,8,0,0,55,56,3,18,9,0,56,57,5,18,0,0,57,58,5,9,0,0,58,59,
3,18,9,0,59,60,5,18,0,0,60,61,5,17,0,0,61,11,1,0,0,0,62,63,5,16,
0,0,63,64,5,8,0,0,64,65,3,18,9,0,65,73,5,18,0,0,66,67,5,10,0,0,67,
68,3,14,7,0,68,69,5,18,0,0,69,70,5,11,0,0,70,71,3,18,9,0,71,72,5,
18,0,0,72,74,1,0,0,0,73,66,1,0,0,0,73,74,1,0,0,0,74,75,1,0,0,0,75,
76,5,9,0,0,76,77,3,18,9,0,77,78,5,18,0,0,78,79,5,17,0,0,79,13,1,
0,0,0,80,81,7,1,0,0,81,15,1,0,0,0,82,83,5,20,0,0,83,17,1,0,0,0,84,
85,5,21,0,0,85,19,1,0,0,0,4,22,30,32,73
]; ];
private static __ATN: antlr.ATN; private static __ATN: antlr.ATN;
@@ -339,15 +508,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 {
@@ -380,8 +567,8 @@ export class QuixosEntryContext extends antlr.ParserRuleContext {
public SOURCE(): antlr.TerminalNode { public SOURCE(): antlr.TerminalNode {
return this.getToken(QuixosLockParser.SOURCE, 0)!; return this.getToken(QuixosLockParser.SOURCE, 0)!;
} }
public sourceBlock(): SourceBlockContext { public quixosSourceBlock(): QuixosSourceBlockContext {
return this.getRuleContext(0, SourceBlockContext)!; return this.getRuleContext(0, QuixosSourceBlockContext)!;
} }
public override get ruleIndex(): number { public override get ruleIndex(): number {
return QuixosLockParser.RULE_quixosEntry; return QuixosLockParser.RULE_quixosEntry;
@@ -425,6 +612,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);
@@ -495,6 +708,88 @@ export class SourceBlockContext extends antlr.ParserRuleContext {
} }
export class QuixosSourceBlockContext extends antlr.ParserRuleContext {
public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) {
super(parent, invokingState);
}
public LBRACE(): antlr.TerminalNode {
return this.getToken(QuixosLockParser.LBRACE, 0)!;
}
public REPOSITORY(): antlr.TerminalNode {
return this.getToken(QuixosLockParser.REPOSITORY, 0)!;
}
public stringLiteral(): StringLiteralContext[];
public stringLiteral(i: number): StringLiteralContext | null;
public stringLiteral(i?: number): StringLiteralContext[] | StringLiteralContext | null {
if (i === undefined) {
return this.getRuleContexts(StringLiteralContext);
}
return this.getRuleContext(i, StringLiteralContext);
}
public SEMI(): antlr.TerminalNode[];
public SEMI(i: number): antlr.TerminalNode | null;
public SEMI(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] {
if (i === undefined) {
return this.getTokens(QuixosLockParser.SEMI);
} else {
return this.getToken(QuixosLockParser.SEMI, i);
}
}
public COMMIT(): antlr.TerminalNode {
return this.getToken(QuixosLockParser.COMMIT, 0)!;
}
public RBRACE(): antlr.TerminalNode {
return this.getToken(QuixosLockParser.RBRACE, 0)!;
}
public POLICY(): antlr.TerminalNode | null {
return this.getToken(QuixosLockParser.POLICY, 0);
}
public sourcePolicy(): SourcePolicyContext | null {
return this.getRuleContext(0, SourcePolicyContext);
}
public REF(): antlr.TerminalNode | null {
return this.getToken(QuixosLockParser.REF, 0);
}
public override get ruleIndex(): number {
return QuixosLockParser.RULE_quixosSourceBlock;
}
public override accept<Result>(visitor: QuixosLockVisitor<Result>): Result | null {
if (visitor.visitQuixosSourceBlock) {
return visitor.visitQuixosSourceBlock(this);
} else {
return visitor.visitChildren(this);
}
}
}
export class SourcePolicyContext extends antlr.ParserRuleContext {
public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) {
super(parent, invokingState);
}
public PINNED(): antlr.TerminalNode | null {
return this.getToken(QuixosLockParser.PINNED, 0);
}
public TRACK_RELEASE(): antlr.TerminalNode | null {
return this.getToken(QuixosLockParser.TRACK_RELEASE, 0);
}
public TRACK_DEVELOPMENT(): antlr.TerminalNode | null {
return this.getToken(QuixosLockParser.TRACK_DEVELOPMENT, 0);
}
public override get ruleIndex(): number {
return QuixosLockParser.RULE_sourcePolicy;
}
public override accept<Result>(visitor: QuixosLockVisitor<Result>): Result | null {
if (visitor.visitSourcePolicy) {
return visitor.visitSourcePolicy(this);
} else {
return visitor.visitChildren(this);
}
}
}
export class IdentifierContext extends antlr.ParserRuleContext { export class IdentifierContext 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,8 +5,11 @@ 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 { QuixosSourceBlockContext } from "./QuixosLockParser.js";
import { SourcePolicyContext } from "./QuixosLockParser.js";
import { IdentifierContext } from "./QuixosLockParser.js"; import { IdentifierContext } from "./QuixosLockParser.js";
import { StringLiteralContext } from "./QuixosLockParser.js"; import { StringLiteralContext } from "./QuixosLockParser.js";
@@ -37,6 +40,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
@@ -49,6 +58,18 @@ export class QuixosLockVisitor<Result> extends AbstractParseTreeVisitor<Result>
* @return the visitor result * @return the visitor result
*/ */
visitSourceBlock?: (ctx: SourceBlockContext) => Result; visitSourceBlock?: (ctx: SourceBlockContext) => Result;
/**
* Visit a parse tree produced by `QuixosLockParser.quixosSourceBlock`.
* @param ctx the parse tree
* @return the visitor result
*/
visitQuixosSourceBlock?: (ctx: QuixosSourceBlockContext) => Result;
/**
* Visit a parse tree produced by `QuixosLockParser.sourcePolicy`.
* @param ctx the parse tree
* @return the visitor result
*/
visitSourcePolicy?: (ctx: SourcePolicyContext) => Result;
/** /**
* Visit a parse tree produced by `QuixosLockParser.identifier`. * Visit a parse tree produced by `QuixosLockParser.identifier`.
* @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);
};
+245 -9
View File
@@ -10,16 +10,19 @@ import {
import { QuixosLockLexer } from "./generated/QuixosLockLexer.js"; import { QuixosLockLexer } from "./generated/QuixosLockLexer.js";
import { import {
QuixosLockParser, QuixosLockParser,
type QuixosSourceBlockContext,
type SourceBlockContext, type SourceBlockContext,
} from "./generated/QuixosLockParser.js"; } from "./generated/QuixosLockParser.js";
import type { import type {
GitSource, GitSource,
LockedResource, LockedResource,
QuixosLockDocument,
QuixosRepositoryLock, QuixosRepositoryLock,
QuixosSource,
} 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 +35,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,
@@ -68,22 +75,72 @@ const lowerSource = (context: SourceBlockContext): GitSource => ({
commit: stringValue(context.stringLiteral(1)!).toLowerCase(), commit: stringValue(context.stringLiteral(1)!).toLowerCase(),
}); });
const lowerQuixosSource = (context: QuixosSourceBlockContext): QuixosSource => {
const source = {
resolver: "git" as const,
repository: stringValue(context.stringLiteral(0)!),
commit: stringValue(context.stringLiteral(context.stringLiteral().length - 1)!).toLowerCase(),
};
const policyContext = context.sourcePolicy();
if (!policyContext) return source;
const policy = policyContext.PINNED()
? "pinned"
: policyContext.TRACK_RELEASE()
? "track-release"
: "track-development";
return {
...source,
policy,
ref: stringValue(context.stringLiteral(1)!),
};
};
const issue = ( const issue = (
diagnostics: QuixosLockDiagnostic[], diagnostics: QuixosLockDiagnostic[],
fileName: string, fileName: string,
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 +198,59 @@ const validateSource = (
} }
}; };
export const parseQuixosLock = ( const validateQuixosSource = (
source: QuixosSource,
fileName: string,
diagnostics: QuixosLockDiagnostic[],
) => {
validateSource(source, "quixos", fileName, diagnostics);
if (!source.policy) return;
const forbiddenRefCharacters = new Set("~^:?*[\\");
const invalidRef = !source.ref
|| [...source.ref].some((character) => {
const code = character.charCodeAt(0);
return code <= 0x20 || code === 0x7f || forbiddenRefCharacters.has(character);
})
|| source.ref.startsWith("/")
|| source.ref.endsWith("/")
|| source.ref.endsWith(".")
|| source.ref.includes("..")
|| source.ref.includes("@{")
|| source.ref.includes("//");
if (invalidRef) {
issue(
diagnostics,
fileName,
"invalid-quixos-ref",
"quixos.ref must be a non-empty Git ref without whitespace or Git ref metacharacters",
"quixos.ref",
);
}
if (source.policy === "pinned") {
if (!/^([0-9a-f]{40}|[0-9a-f]{64})$/.test(source.ref)) {
issue(
diagnostics,
fileName,
"pinned-quixos-ref-not-commit",
"A pinned Quixos source must use an exact commit as its ref",
"quixos.ref",
);
} else if (source.ref.toLowerCase() !== source.commit) {
issue(
diagnostics,
fileName,
"pinned-quixos-commit-mismatch",
"A pinned Quixos source ref and resolved commit must be identical",
"quixos.commit",
);
}
}
};
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 +273,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: QuixosSource | 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 = lowerQuixosSource(quixosEntries[0]!.quixosSourceBlock());
validateQuixosSource(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,7 +348,52 @@ 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: [],
};
};
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: [], diagnostics: [],
}; };
}; };
@@ -207,11 +405,22 @@ const sourceLines = (source: GitSource, indentation: string): string[] => [
`${indentation}commit ${quoted(source.commit.toLowerCase())};`, `${indentation}commit ${quoted(source.commit.toLowerCase())};`,
]; ];
const quixosSourceLines = (source: QuixosSource, indentation: string): string[] => [
`${indentation}repository ${quoted(source.repository)};`,
...(source.policy
? [
`${indentation}policy ${source.policy};`,
`${indentation}ref ${quoted(source.ref)};`,
]
: []),
`${indentation}commit ${quoted(source.commit.toLowerCase())};`,
];
export const formatQuixosLock = (lock: QuixosRepositoryLock): string => { export const formatQuixosLock = (lock: QuixosRepositoryLock): string => {
const lines = [ const lines = [
"quixos-lock version 1 {", "quixos-lock version 1 {",
" quixos source {", " quixos source {",
...sourceLines(lock.quixos, " "), ...quixosSourceLines(lock.quixos, " "),
" }", " }",
]; ];
for (const resource of lock.resources) { for (const resource of lock.resources) {
@@ -225,3 +434,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 {",
...quixosSourceLines(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");
};
+34 -1
View File
@@ -4,6 +4,19 @@ export type GitSource = {
commit: string; commit: string;
}; };
export type QuixosSourcePolicy = "pinned" | "track-release" | "track-development";
// Resource repositories only need the exact Quixos commit they were authored
// against. A workspace root additionally declares how a runtime may advance
// that exact baseline.
export type QuixosSource = GitSource & ({
policy: QuixosSourcePolicy;
ref: string;
} | {
policy?: undefined;
ref?: undefined;
});
export type LockedResourceKind = "interface" | "package"; export type LockedResourceKind = "interface" | "package";
export type LockedResource = { export type LockedResource = {
@@ -12,10 +25,30 @@ export type LockedResource = {
source: GitSource; source: GitSource;
}; };
export type QuixosLockRootDocument = {
kind: "root";
formatVersion: 1;
quixos: QuixosSource;
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: QuixosSource;
resources: LockedResource[]; resources: LockedResource[];
sourceFiles?: string[];
}; };
export type NixGitInput = { export type NixGitInput = {
+184
View File
@@ -0,0 +1,184 @@
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 repositories cannot own workspace Quixos selection policy", async (context) => {
const directory = await mkdtemp(path.join(os.tmpdir(), "quixos-resource-policy-"));
context.after(() => rm(directory, { recursive: true, force: true }));
await writeFile(path.join(directory, "quixos.lock"), `quixos-lock version 1 {
quixos source {
repository "https://example.test/quixos.git";
policy track-development;
ref "dev/alice/main";
commit "${quixosCommit}";
}
}`);
await writeFile(path.join(directory, "package.qx"), `package Runtime id "package:runtime" revision "package:runtime@1" { }\n`);
await assert.rejects(
compileCapabilityResourceRepository({
rootDirectory: directory,
kind: "package",
source: {
resolver: "git",
repository: "https://example.test/package-runtime.git",
commit: packageCommit,
},
resolveResource: async () => ({ directory }),
}),
/resource locks may only declare their exact authored-against commit/,
);
});
test("resource manifests cannot hide lock dependencies", async (context) => {
const directory = await mkdtemp(path.join(os.tmpdir(), "quixos-assembly-mismatch-"));
context.after(() => rm(directory, { recursive: true, force: true }));
const root = path.join(directory, "root");
const runtime = path.join(directory, "runtime");
await Promise.all([mkdir(root), mkdir(runtime)]);
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\)/,
);
});
+178 -35
View File
@@ -1,17 +1,97 @@
import assert from "node:assert/strict"; import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
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);
@@ -22,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"));
@@ -55,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
@@ -84,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(
@@ -101,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) =>
@@ -130,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(
@@ -146,3 +223,69 @@ test("well-formed but invalid programs report semantic paths", () => {
assert.equal(diagnostic.phase, "validation"); assert.equal(diagnostic.phase, "validation");
assert.ok(diagnostic.path?.includes("operationBindings")); assert.ok(diagnostic.path?.includes("operationBindings"));
}); });
test("Web Studio sidecars declare lazy materialization and checked cross-object ports", () => {
const result = compileWebStudioFixture();
assert.equal(result.ok, true);
if (!result.ok) return;
const host = result.workspace.conformances.find((entry) =>
entry.atomId === "atom:project" &&
entry.interfaceRevisionId === "interface:org.quixos.web-studio.has-react-component@1"
);
assert.deepEqual(host?.relationshipMaterializations, [{
memberId: "member:org.quixos.web-studio.has-react-component:component",
constructorAtomId: "atom:project-component",
edgeTypeId: "edge:project:component",
constructedProjectionId: "projection:component:subject",
}]);
const component = result.workspace.conformances.find((entry) =>
entry.atomId === "atom:project-component"
);
const binding = component?.operationBindings[0]?.binding;
assert.equal(binding?.kind, "package");
if (binding?.kind !== "package") return;
assert.deepEqual(binding.dependencies[0]?.binding, {
kind: "interface",
interfaceRevisionId: "interface:named@1",
via: {
edgeTypeId: "edge:project:component",
projectionId: "projection:component:subject",
},
});
});
test("relationship materializers require a constructor from the host atom", () => {
const result = compileWebStudioFixture((source) => source.replace(
"constructs ProjectComponent : atom-ref<Project>;",
"constructs ProjectComponent : unit;",
));
assert.equal(result.ok, false);
if (result.ok) return;
assert.ok(result.diagnostics.some((entry) =>
entry.code === "invalid-relationship-materialization" &&
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;
}
+35
View File
@@ -0,0 +1,35 @@
workspace WebStudioFixture id "workspace:web-studio-fixture" revision "workspace:web-studio-fixture@1" commit "1111111111111111111111111111111111111111" {
atom Project id "atom:project";
atom ProjectComponent id "atom:project-component";
import interface Named;
import interface ReactComponent;
import interface HasReactComponent;
import package ComponentRuntime;
shared state ProjectName id "slot:project:name" on Project : string
policy optimistic-register default "Untitled project";
shared edge ProjectComponentEdge id "edge:project:component" {
atom ProjectComponent projection subject id "projection:component:subject" exactly-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 {
bind component.resolve to edge ProjectComponentEdge.component.resolve;
materialize component if absent using constructor ProjectComponent via edge ProjectComponentEdge.subject;
}
conform ProjectComponent as ReactComponent {
bind props.get to package ComponentRuntime.propsGet with {
project to interface Named via edge ProjectComponentEdge.subject;
};
}
constructor ProjectComponent to ComponentRuntime.createComponent;
}
+183
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";
@@ -13,6 +20,8 @@ const packageCommit = "3".repeat(64);
const fixture = `quixos-lock version 1 { const fixture = `quixos-lock version 1 {
quixos source { quixos source {
repository "https://gitea.example/quixos/quixos.git"; repository "https://gitea.example/quixos/quixos.git";
policy track-development;
ref "dev/alice/main";
commit "${quixosCommit}"; commit "${quixosCommit}";
} }
@@ -34,6 +43,8 @@ test("parses and canonically formats a Git-only repository lock", () => {
if (!parsed.ok) return; if (!parsed.ok) return;
assert.equal(parsed.lock.formatVersion, 1); assert.equal(parsed.lock.formatVersion, 1);
assert.equal(parsed.lock.quixos.commit, quixosCommit); assert.equal(parsed.lock.quixos.commit, quixosCommit);
assert.equal(parsed.lock.quixos.policy, "track-development");
assert.equal(parsed.lock.quixos.ref, "dev/alice/main");
assert.deepEqual( assert.deepEqual(
parsed.lock.resources.map(({ kind, binding }) => ({ kind, binding })), parsed.lock.resources.map(({ kind, binding }) => ({ kind, binding })),
[ [
@@ -48,6 +59,29 @@ test("parses and canonically formats a Git-only repository lock", () => {
}); });
}); });
test("validates pinned Quixos selections without imposing policy on resource locks", () => {
const mismatch = parseQuixosLockDocument(`quixos-lock version 1 {
quixos source {
repository "https://gitea.example/quixos/quixos.git";
policy pinned;
ref "${namedCommit}";
commit "${quixosCommit}";
}
}`);
assert.equal(mismatch.ok, false);
if (!mismatch.ok) {
assert.equal(mismatch.diagnostics[0]?.code, "pinned-quixos-commit-mismatch");
}
const resourceBaseline = parseQuixosLockDocument(`quixos-lock version 1 {
quixos source {
repository "https://gitea.example/quixos/quixos.git";
commit "${quixosCommit}";
}
}`);
assert.equal(resourceBaseline.ok, true);
});
test("derives immutable retention and Nix inputs without storing extra identity", () => { test("derives immutable retention and Nix inputs without storing extra identity", () => {
const source = { const source = {
resolver: "git" as const, resolver: "git" as const,
@@ -92,3 +126,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