Skip to content

Commit 7a7165a

Browse files
committed
fix(protocol): emit Swift enums for literal unions
1 parent 928b593 commit 7a7165a

3 files changed

Lines changed: 63 additions & 0 deletions

File tree

apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@ public enum NodePresenceAliveReason: String, Codable, Sendable {
4646
case connect = "connect"
4747
}
4848

49+
public enum SessionFileKind: String, Codable, Sendable {
50+
case modified = "modified"
51+
case read = "read"
52+
}
53+
54+
public enum SessionFileRelevance: String, Codable, Sendable {
55+
case modified = "modified"
56+
case read = "read"
57+
case mixed = "mixed"
58+
}
59+
4960
public struct ConnectParams: Codable, Sendable {
5061
public let minprotocol: Int
5162
public let maxprotocol: Int

packages/gateway-protocol/src/native-protocol-levels.guard.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import fs from "node:fs/promises";
33
import path from "node:path";
44
import { describe, it } from "vitest";
5+
import { ProtocolSchemas } from "./schema/protocol-schemas.js";
56
import { MIN_CLIENT_PROTOCOL_VERSION, PROTOCOL_VERSION } from "./version.js";
67

78
/**
@@ -178,4 +179,37 @@ describe("native Gateway protocol levels", () => {
178179
);
179180
}
180181
});
182+
183+
it("emits named string-literal unions as Swift enums", async () => {
184+
const swiftGeneratedPath =
185+
"apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift";
186+
const swiftGenerated = await readRepoFile(swiftGeneratedPath);
187+
188+
for (const [name, schema] of Object.entries(ProtocolSchemas)) {
189+
const branches = schema.anyOf ?? schema.oneOf;
190+
if (!branches || branches.length < 2) {
191+
continue;
192+
}
193+
const values = branches.map((branch) => branch.const);
194+
if (values.some((value) => typeof value !== "string")) {
195+
continue;
196+
}
197+
198+
const enumStart = `public enum ${name}: String, Codable, Sendable {`;
199+
const start = swiftGenerated.indexOf(enumStart);
200+
if (start < 0) {
201+
throw new Error(`${swiftGeneratedPath}: missing Swift enum for ${name}.`);
202+
}
203+
const end = swiftGenerated.indexOf("\n}\n", start);
204+
const enumSource = swiftGenerated.slice(start, end);
205+
for (const value of values) {
206+
assertPattern(
207+
enumSource,
208+
swiftGeneratedPath,
209+
new RegExp(`= ${JSON.stringify(value)}$`, "m"),
210+
`${name} must include the ${JSON.stringify(value)} literal.`,
211+
);
212+
}
213+
}
214+
});
181215
});

scripts/protocol-gen-swift.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,19 @@ function emitEnum(name: string, schema: JsonSchema): string {
244244
].join("\n");
245245
}
246246

247+
function stringLiteralUnionValues(schema: JsonSchema): string[] | undefined {
248+
const branches = schema.oneOf ?? schema.anyOf;
249+
if (!branches || branches.length < 2) {
250+
return undefined;
251+
}
252+
const values = branches.map((branch) => literalSchemaValue(branch));
253+
if (values.some((value) => typeof value !== "string")) {
254+
return undefined;
255+
}
256+
const stringValues = values as string[];
257+
return new Set(stringValues).size === stringValues.length ? stringValues : undefined;
258+
}
259+
247260
function emitStruct(name: string, schema: JsonSchema): string {
248261
const props = schema.properties ?? {};
249262
const required = new Set(schema.required ?? []);
@@ -608,6 +621,11 @@ async function generate() {
608621
}
609622
if (schema.type === "string" && schema.enum) {
610623
parts.push(emitEnum(name, schema));
624+
continue;
625+
}
626+
const literalUnionValues = stringLiteralUnionValues(schema);
627+
if (literalUnionValues) {
628+
parts.push(emitEnum(name, { enum: literalUnionValues }));
611629
}
612630
}
613631

0 commit comments

Comments
 (0)