Format authored monorepo code with pinned language formatters

This commit is contained in:
Timothy J. Aveni
2026-09-15 15:23:24 -07:00
parent a174faea5c
commit 00fc2b9ff1
69 changed files with 5135 additions and 3306 deletions
+162 -54
View File
@@ -9,9 +9,12 @@ export type BindingSchema = {
packages: PackageRevision[];
};
export const bindingSchema = (compiled: CompiledCapabilityResourceRepository): BindingSchema => ({
format: "quixos-bindings", version: 1,
interfaces: compiled.resources.flatMap((node) => node.resource.kind === "interface" ? [node.resource.revision] : []),
packages: compiled.resources.flatMap((node) => node.resource.kind === "package" ? [node.resource.revision] : []),
format: "quixos-bindings",
version: 1,
interfaces: compiled.resources.flatMap((node) =>
node.resource.kind === "interface" ? [node.resource.revision] : [],
),
packages: compiled.resources.flatMap((node) => (node.resource.kind === "package" ? [node.resource.revision] : [])),
});
export type TypeScriptBindingOptions = {
runtimeModule?: string;
@@ -19,33 +22,61 @@ export type TypeScriptBindingOptions = {
messages?: Record<string, { module: string; export: string }>;
};
export function generatePackageDescriptor(schema: BindingSchema, revisionId: string): string {
const pkg = schema.packages.find(entry => entry.revisionId === revisionId);
const pkg = schema.packages.find((entry) => entry.revisionId === revisionId);
if (!pkg) throw new Error(`Unknown package revision ${revisionId}`);
return `# Generated from the checked package contract\npackage_id: ${JSON.stringify(pkg.packageId)}\npackage_revision_id: ${JSON.stringify(pkg.revisionId)}\nruntime_protocol_version: "quixos-capabilities-v1"\n` +
pkg.exports.map(entry => `exports: { export_id: ${JSON.stringify(entry.id)} runtime_symbol: ${JSON.stringify(entry.displayName)} }\n`).join("");
return (
`# Generated from the checked package contract\npackage_id: ${JSON.stringify(pkg.packageId)}\npackage_revision_id: ${JSON.stringify(pkg.revisionId)}\nruntime_protocol_version: "quixos-capabilities-v1"\n` +
pkg.exports
.map(
(entry) =>
`exports: { export_id: ${JSON.stringify(entry.id)} runtime_symbol: ${JSON.stringify(entry.displayName)} }\n`,
)
.join("")
);
}
const q = JSON.stringify;
const object = (entries: [string, string][]) => `{ ${entries.map(([key, value]) => `${q(key)}: ${value}`).join("; ")} }`;
const object = (entries: [string, string][]) =>
`{ ${entries.map(([key, value]) => `${q(key)}: ${value}`).join("; ")} }`;
const unit = (type: ValueType) => type.kind === "builtin" && type.name === "unit";
export const generateTypeScriptBindings = (
schema: BindingSchema, packageRevisionId: string, options: TypeScriptBindingOptions = {},
schema: BindingSchema,
packageRevisionId: string,
options: TypeScriptBindingOptions = {},
) => {
if (schema.format !== "quixos-bindings" || schema.version !== 1) throw new Error("Unsupported binding schema version");
if (schema.format !== "quixos-bindings" || schema.version !== 1)
throw new Error("Unsupported binding schema version");
const pkg = schema.packages.find((entry) => entry.revisionId === packageRevisionId);
if (!pkg) throw new Error(`Unknown package revision ${packageRevisionId}`);
const messages = new Map<string, string>();
const type = (value: ValueType): string => {
switch (value.kind) {
case "builtin": return value.name === "unit" ? "null" : "QxWatchHandle";
case "scalar": return ({ bool: "boolean", bytes: "Uint8Array", string: "string", int64: "bigint", uint64: "bigint",
double: "number", int32: "number", uint32: "number" })[value.name];
case "object-ref": return `QxObjectRef<${q(value.expectation.kind === "atom" ? `atom:${value.expectation.atomId}` : `interface:${value.expectation.interfaceRevisionId}`)}>`;
case "optional": return `(${type(value.value)} | null)`;
case "list": return `Array<${type(value.value)}>`;
case "record": return `{ ${Object.entries(value.fields).map(([name, field]) => `${q(name)}: ${type(field)}`).join("; ")} }`;
case "builtin":
return value.name === "unit" ? "null" : "QxWatchHandle";
case "scalar":
return {
bool: "boolean",
bytes: "Uint8Array",
string: "string",
int64: "bigint",
uint64: "bigint",
double: "number",
int32: "number",
uint32: "number",
}[value.name];
case "object-ref":
return `QxObjectRef<${q(value.expectation.kind === "atom" ? `atom:${value.expectation.atomId}` : `interface:${value.expectation.interfaceRevisionId}`)}>`;
case "optional":
return `(${type(value.value)} | null)`;
case "list":
return `Array<${type(value.value)}>`;
case "record":
return `{ ${Object.entries(value.fields)
.map(([name, field]) => `${q(name)}: ${type(field)}`)
.join("; ")} }`;
case "message": {
if (!options.messages?.[value.descriptorId]) throw new Error(`Missing TypeScript message binding for ${value.descriptorId}`);
if (!options.messages?.[value.descriptorId])
throw new Error(`Missing TypeScript message binding for ${value.descriptorId}`);
if (!messages.has(value.descriptorId)) messages.set(value.descriptorId, `message${messages.size}`);
return `BindingValue<typeof ${messages.get(value.descriptorId)}>`;
}
@@ -53,7 +84,7 @@ export const generateTypeScriptBindings = (
};
const ref = (target: { kind: "atom"; atomId: string } | { kind: "interface"; interfaceRevisionId: string }) =>
`QxObjectRef<${q(target.kind === "atom" ? `atom:${target.atomId}` : `interface:${target.interfaceRevisionId}`)}>`;
const params = (input: ValueType) => unit(input) ? "" : `input: ${type(input)}`;
const params = (input: ValueType) => (unit(input) ? "" : `input: ${type(input)}`);
const port = (entry: DependencyPort): { type: string; spec: unknown } => {
const requirement = entry.requirement;
switch (requirement.kind) {
@@ -69,36 +100,76 @@ export const generateTypeScriptBindings = (
case "edge": {
const methods = requirement.primitives.map((primitive): [string, string] => {
if (primitive === "resolve") return [primitive, `() => Promise<Array<${ref(requirement.target)}>>`];
if (primitive === "connect" || primitive === "disconnect") return [primitive, `(target: ${ref(requirement.target)}) => Promise<void>`];
if (primitive === "connect" || primitive === "disconnect")
return [primitive, `(target: ${ref(requirement.target)}) => Promise<void>`];
throw new Error(`Edge primitive ${primitive} is not supported by the TypeScript runtime binding yet`);
});
if (requirement.primitives.includes("resolve")) methods.push(["collection", `() => Promise<RelationshipCollection<${ref(requirement.target)}>>`]);
if (["resolve", "connect", "disconnect"].every((primitive) => requirement.primitives.includes(primitive as "resolve"))) methods.push(["replace", `(entries: RelationshipEntry<${ref(requirement.target)}>[], expectedRevision: bigint) => Promise<RelationshipCollection<${ref(requirement.target)}>>`]);
if (requirement.primitives.includes("resolve"))
methods.push(["collection", `() => Promise<RelationshipCollection<${ref(requirement.target)}>>`]);
if (
["resolve", "connect", "disconnect"].every((primitive) =>
requirement.primitives.includes(primitive as "resolve"),
)
)
methods.push([
"replace",
`(entries: RelationshipEntry<${ref(requirement.target)}>[], expectedRevision: bigint) => Promise<RelationshipCollection<${ref(requirement.target)}>>`,
]);
return { type: object(methods), spec: { kind: "edge", id: entry.id, primitives: requirement.primitives } };
}
case "interface": {
const contract = schema.interfaces.find((candidate) => candidate.revisionId === requirement.interfaceRevisionId);
const contract = schema.interfaces.find(
(candidate) => candidate.revisionId === requirement.interfaceRevisionId,
);
if (!contract) throw new Error(`Missing imported interface contract ${requirement.interfaceRevisionId}`);
// Streaming ports need a future streaming ABI; ordinary calls are fully typed today.
const operations = contract.members.flatMap((member) => member.operations.filter((operation) => operation.mode === "call")
.map((operation) => ({ ...operation, name: `${member.displayName}.${operation.displayName}` })));
return { type: object([
["objectId", ref({ kind: "interface", interfaceRevisionId: requirement.interfaceRevisionId })],
["live", object(operations.map(operation => [operation.name, `(${params(operation.inputType)}) => Promise<QxLiveValue>`]))],
...operations.map((operation): [string, string] => [operation.name, `(${params(operation.inputType)}) => Promise<${type(operation.outputType)}>`]),
]),
spec: { kind: "interface", id: entry.id, operations: Object.fromEntries(operations.map(({name, id, inputType, outputType}) =>
[name, {id, inputType, outputType}])) } };
const operations = contract.members.flatMap((member) =>
member.operations
.filter((operation) => operation.mode === "call")
.map((operation) => ({ ...operation, name: `${member.displayName}.${operation.displayName}` })),
);
return {
type: object([
["objectId", ref({ kind: "interface", interfaceRevisionId: requirement.interfaceRevisionId })],
[
"live",
object(
operations.map((operation) => [
operation.name,
`(${params(operation.inputType)}) => Promise<QxLiveValue>`,
]),
),
],
...operations.map((operation): [string, string] => [
operation.name,
`(${params(operation.inputType)}) => Promise<${type(operation.outputType)}>`,
]),
]),
spec: {
kind: "interface",
id: entry.id,
operations: Object.fromEntries(
operations.map(({ name, id, inputType, outputType }) => [name, { id, inputType, outputType }]),
),
},
};
}
case "constructor": {
const input = requirement.inputType;
if (!input) throw new Error(`Constructor port ${entry.id} needs an explicit input contract: add 'input TYPE' after ${requirement.atomId} in QX`);
return { type: object([["construct", `(${params(input)}) => Promise<${ref({ kind: "atom", atomId: requirement.atomId })}>`]]),
spec: { kind: "constructor", id: entry.id, inputType: input } };
if (!input)
throw new Error(
`Constructor port ${entry.id} needs an explicit input contract: add 'input TYPE' after ${requirement.atomId} in QX`,
);
return {
type: object([
["construct", `(${params(input)}) => Promise<${ref({ kind: "atom", atomId: requirement.atomId })}>`],
]),
spec: { kind: "constructor", id: entry.id, inputType: input },
};
}
}
};
const exports = [...pkg.exports].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
const exports = [...pkg.exports].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
const names = new Set<string>();
const specs: Record<string, unknown> = {};
const contexts: [string, string][] = [];
@@ -107,38 +178,75 @@ export const generateTypeScriptBindings = (
if (names.has(entry.displayName)) throw new Error(`Duplicate export name ${entry.displayName}`);
names.add(entry.displayName);
const ports = entry.dependencyPorts.map((dependency) => ({ name: dependency.displayName, ...port(dependency) }));
if (new Set(ports.map((p) => p.name)).size !== ports.length) throw new Error(`Duplicate dependency name in ${entry.displayName}`);
const receiver = entry.kind === "constructor" ? ref({ kind: "atom", atomId: entry.constructsAtom }) :
entry.kind === "operation" && entry.receiverRequirement.kind === "exact-atom" ?
ref({ kind: "atom", atomId: entry.receiverRequirement.atomId }) :
entry.kind === "operation" && entry.receiverRequirement.kind === "all-interfaces" ?
`QxObjectRef<${entry.receiverRequirement.interfaceRevisionIds.map((id) => q(`interface:${id}`)).join(" | ") || "never"}>` : "QxObjectRef<string>";
const contextShape = object([["objectId", receiver], ["input", type(entry.inputType)],
["ports", object(ports.map((port) => [port.name, port.type]))]]);
contexts.push([entry.displayName, `${contextShape} & QxContextLifecycle<${contextShape} & {signal?: AbortSignal}>`]);
if (new Set(ports.map((p) => p.name)).size !== ports.length)
throw new Error(`Duplicate dependency name in ${entry.displayName}`);
const receiver =
entry.kind === "constructor"
? ref({ kind: "atom", atomId: entry.constructsAtom })
: entry.kind === "operation" && entry.receiverRequirement.kind === "exact-atom"
? ref({ kind: "atom", atomId: entry.receiverRequirement.atomId })
: entry.kind === "operation" && entry.receiverRequirement.kind === "all-interfaces"
? `QxObjectRef<${entry.receiverRequirement.interfaceRevisionIds.map((id) => q(`interface:${id}`)).join(" | ") || "never"}>`
: "QxObjectRef<string>";
const contextShape = object([
["objectId", receiver],
["input", type(entry.inputType)],
["ports", object(ports.map((port) => [port.name, port.type]))],
]);
contexts.push([
entry.displayName,
`${contextShape} & QxContextLifecycle<${contextShape} & {signal?: AbortSignal}>`,
]);
const event = entry.kind === "operation" ? entry.eventType : undefined;
const contextType = `Contexts[${q(entry.displayName)}]`;
const outputType = type(event ?? entry.outputType);
// Watch-start handlers produce events through the runtime's derived stream protocol.
handlers.push([entry.displayName, event ? `QxDerived<${contextType}, ${outputType}>` :
`QxHandler<${contextType}, ${outputType}>${entry.kind === "operation" && entry.mode === "call" ? ` | QxDerived<${contextType}, ${outputType}>` : ""}`]);
specs[entry.displayName] = { inputType: entry.inputType, outputType: entry.outputType,
...(event ? { eventType: event } : {}), ports: Object.fromEntries(ports.map((port) => [port.name, port.spec])) };
handlers.push([
entry.displayName,
event
? `QxDerived<${contextType}, ${outputType}>`
: `QxHandler<${contextType}, ${outputType}>${entry.kind === "operation" && entry.mode === "call" ? ` | QxDerived<${contextType}, ${outputType}>` : ""}`,
]);
specs[entry.displayName] = {
inputType: entry.inputType,
outputType: entry.outputType,
...(event ? { eventType: event } : {}),
ports: Object.fromEntries(ports.map((port) => [port.name, port.spec])),
};
}
const imports = [...messages].map(([id, alias]) => {
const binding = options.messages![id]!;
if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(binding.export)) throw new Error(`Invalid message binding export ${binding.export}`);
if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(binding.export))
throw new Error(`Invalid message binding export ${binding.export}`);
return `import { ${binding.export} as ${alias} } from ${q(binding.module)};`;
});
const signatures = `${object(contexts)} ${object(handlers)}`;
const typeImports = ["BindingValue", "QxObjectRef", "QxWatchHandle", "QxHandler", "QxDerived", "QxContextLifecycle", "QxLiveValue", "RelationshipCollection", "RelationshipEntry"].filter((name) => new RegExp(`\\b${name}\\b`).test(signatures));
return `// Generated by quixos-codegen-ts. Do not edit. Binding ABI version 1.\n` +
const typeImports = [
"BindingValue",
"QxObjectRef",
"QxWatchHandle",
"QxHandler",
"QxDerived",
"QxContextLifecycle",
"QxLiveValue",
"RelationshipCollection",
"RelationshipEntry",
].filter((name) => new RegExp(`\\b${name}\\b`).test(signatures));
return (
`// Generated by quixos-codegen-ts. Do not edit. Binding ABI version 1.\n` +
`import { ${exports.length ? "bindQxHandler, " : ""}${[...typeImports, "QxHandlerSpec", "QxMessages"].map((name) => `type ${name}`).join(", ")} } from ${q(options.runtimeModule ?? "@quixos/camino-package-runtime")};\n` +
imports.join("\n") + `\nexport const packageRevisionId = ${q(pkg.revisionId)};\n` +
imports.join("\n") +
`\nexport const packageRevisionId = ${q(pkg.revisionId)};\n` +
`export type Contexts = ${object(contexts)};\nexport type Implementation = ${object(handlers)};\n` +
`const messages = { ${[...messages].map(([id, alias]) => `${q(id)}: ${alias}`).join(", ")} } satisfies QxMessages;\n` +
`const specs = ${JSON.stringify(specs, null, 2)} satisfies Record<string, QxHandlerSpec>;\n` +
`export const createRuntime = (implementation: Implementation) => ({\n packageRevisionId,\n exports: {\n` +
exports.map((entry) => ` ${q(entry.id)}: bindQxHandler(specs[${q(entry.displayName)}], implementation[${q(entry.displayName)}], messages),`).join("\n") +
`\n },\n});\n`;
exports
.map(
(entry) =>
` ${q(entry.id)}: bindQxHandler(specs[${q(entry.displayName)}], implementation[${q(entry.displayName)}], messages),`,
)
.join("\n") +
`\n },\n});\n`
);
};