Compare commits

...

6 Commits

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