Skip to content

Commit 5d7eba5

Browse files
Update codegenerators to handle RPC methods returning primitives
1 parent 461636e commit 5d7eba5

8 files changed

Lines changed: 90 additions & 107 deletions

File tree

dotnet/src/Generated/Rpc.cs

Lines changed: 7 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go/rpc/generated_rpc.go

Lines changed: 5 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nodejs/src/generated/rpc.ts

Lines changed: 3 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/copilot/generated/rpc.py

Lines changed: 9 additions & 45 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/codegen/csharp.ts

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
getRpcSchemaTypeName,
1818
getSessionEventsSchemaPath,
1919
isNodeFullyExperimental,
20+
isObjectSchema,
2021
isRpcMethod,
2122
REPO_ROOT,
2223
writeGeneratedFile,
@@ -596,6 +597,7 @@ export async function generateSessionEvents(schemaPath?: string): Promise<void>
596597
// ══════════════════════════════════════════════════════════════════════════════
597598

598599
let emittedRpcClasses = new Set<string>();
600+
let emittedRpcEnumResultTypes = new Set<string>();
599601
let experimentalRpcTypes = new Set<string>();
600602
let rpcKnownTypes = new Map<string, string>();
601603
let rpcEnumOutput: string[] = [];
@@ -718,6 +720,21 @@ function emitRpcClass(className: string, schema: JSONSchema7, visibility: "publi
718720
return lines.join("\n");
719721
}
720722

723+
/**
724+
* Emit the type for a non-object RPC result schema (e.g., a bare enum).
725+
* Returns the C# type name to use in method signatures. For enums, ensures the enum
726+
* is created via getOrCreateEnum. For other primitives, returns the mapped C# type.
727+
*/
728+
function emitNonObjectResultType(typeName: string, schema: JSONSchema7, classes: string[]): string {
729+
if (schema.enum && Array.isArray(schema.enum)) {
730+
const enumName = getOrCreateEnum("", typeName, schema.enum as string[], rpcEnumOutput, schema.description, typeName);
731+
emittedRpcEnumResultTypes.add(enumName);
732+
return enumName;
733+
}
734+
// For other non-object types, use the basic type mapping
735+
return schemaTypeToCSharp(schema, true, rpcKnownTypes);
736+
}
737+
721738
/**
722739
* Emit ServerRpc as an instance class (like SessionRpc but without sessionId).
723740
*/
@@ -803,12 +820,16 @@ function emitServerInstanceMethod(
803820
groupExperimental: boolean
804821
): void {
805822
const methodName = toPascalCase(name);
806-
const resultClassName = resultTypeName(method);
823+
let resultClassName = resultTypeName(method);
807824
if (method.stability === "experimental") {
808825
experimentalRpcTypes.add(resultClassName);
809826
}
810-
const resultClass = emitRpcClass(resultClassName, method.result, "public", classes);
811-
if (resultClass) classes.push(resultClass);
827+
if (isObjectSchema(method.result)) {
828+
const resultClass = emitRpcClass(resultClassName, method.result, "public", classes);
829+
if (resultClass) classes.push(resultClass);
830+
} else if (method.result) {
831+
resultClassName = emitNonObjectResultType(resultClassName, method.result, classes);
832+
}
812833

813834
const paramEntries = method.params?.properties ? Object.entries(method.params.properties) : [];
814835
const requiredSet = new Set(method.params?.required || []);
@@ -890,12 +911,16 @@ function emitSessionRpcClasses(node: Record<string, unknown>, classes: string[])
890911

891912
function emitSessionMethod(key: string, method: RpcMethod, lines: string[], classes: string[], indent: string, groupExperimental: boolean): void {
892913
const methodName = toPascalCase(key);
893-
const resultClassName = resultTypeName(method);
914+
let resultClassName = resultTypeName(method);
894915
if (method.stability === "experimental") {
895916
experimentalRpcTypes.add(resultClassName);
896917
}
897-
const resultClass = emitRpcClass(resultClassName, method.result, "public", classes);
898-
if (resultClass) classes.push(resultClass);
918+
if (isObjectSchema(method.result)) {
919+
const resultClass = emitRpcClass(resultClassName, method.result, "public", classes);
920+
if (resultClass) classes.push(resultClass);
921+
} else if (method.result) {
922+
resultClassName = emitNonObjectResultType(resultClassName, method.result, classes);
923+
}
899924

900925
const paramEntries = (method.params?.properties ? Object.entries(method.params.properties) : []).filter(([k]) => k !== "sessionId");
901926
const requiredSet = new Set(method.params?.required || []);
@@ -982,8 +1007,12 @@ function emitClientSessionApiRegistration(clientSchema: Record<string, unknown>,
9821007
for (const { methods } of groups) {
9831008
for (const method of methods) {
9841009
if (method.result) {
985-
const resultClass = emitRpcClass(resultTypeName(method), method.result, "public", classes);
986-
if (resultClass) classes.push(resultClass);
1010+
if (isObjectSchema(method.result)) {
1011+
const resultClass = emitRpcClass(resultTypeName(method), method.result, "public", classes);
1012+
if (resultClass) classes.push(resultClass);
1013+
} else {
1014+
emitNonObjectResultType(resultTypeName(method), method.result, classes);
1015+
}
9871016
}
9881017

9891018
if (method.params?.properties && Object.keys(method.params.properties).length > 0) {
@@ -1079,6 +1108,7 @@ function emitClientSessionApiRegistration(clientSchema: Record<string, unknown>,
10791108

10801109
function generateRpcCode(schema: ApiSchema): string {
10811110
emittedRpcClasses.clear();
1111+
emittedRpcEnumResultTypes.clear();
10821112
experimentalRpcTypes.clear();
10831113
rpcKnownTypes.clear();
10841114
rpcEnumOutput = [];
@@ -1122,7 +1152,7 @@ internal static class Diagnostics
11221152
if (clientSessionParts.length > 0) lines.push(...clientSessionParts, "");
11231153

11241154
// Add JsonSerializerContext for AOT/trimming support
1125-
const typeNames = [...emittedRpcClasses].sort();
1155+
const typeNames = [...emittedRpcClasses, ...emittedRpcEnumResultTypes].sort();
11261156
if (typeNames.length > 0) {
11271157
lines.push(`[JsonSourceGenerationOptions(`);
11281158
lines.push(` JsonSerializerDefaults.Web,`);

scripts/codegen/go.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -918,9 +918,9 @@ async function generateRpc(schemaPath?: string): Promise<void> {
918918

919919
// Extract actual type names generated by quicktype (may differ from toPascalCase)
920920
const actualTypeNames = new Map<string, string>();
921-
const structRe = /^type\s+(\w+)\s+struct\b/gm;
921+
const typeRe = /^type\s+(\w+)\s+/gm;
922922
let sm;
923-
while ((sm = structRe.exec(qtCode)) !== null) {
923+
while ((sm = typeRe.exec(qtCode)) !== null) {
924924
actualTypeNames.set(sm[1].toLowerCase(), sm[1]);
925925
}
926926
const resolveType = (name: string): string => actualTypeNames.get(name.toLowerCase()) ?? name;

0 commit comments

Comments
 (0)