Skip to content

Commit 8961c8b

Browse files
refactor: simplify C# RPC class tracking
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 52beae2 commit 8961c8b

File tree

1 file changed

+16
-25
lines changed

1 file changed

+16
-25
lines changed

scripts/codegen/csharp.ts

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,6 @@ export async function generateSessionEvents(schemaPath?: string): Promise<void>
595595
// RPC TYPES
596596
// ══════════════════════════════════════════════════════════════════════════════
597597

598-
let emittedRpcClasses = new Set<string>();
599598
let emittedRpcClassSchemas = new Map<string, string>();
600599
let experimentalRpcTypes = new Set<string>();
601600
let rpcKnownTypes = new Map<string, string>();
@@ -628,20 +627,6 @@ function stableStringify(value: unknown): string {
628627
return JSON.stringify(value);
629628
}
630629

631-
function chooseRpcClassName(preferredName: string, fallbackName: string, schema: JSONSchema7): string {
632-
const schemaKey = stableStringify(schema);
633-
const existingPreferred = emittedRpcClassSchemas.get(preferredName);
634-
if (!existingPreferred || existingPreferred === schemaKey) return preferredName;
635-
636-
let candidate = fallbackName;
637-
let suffix = 2;
638-
while (true) {
639-
const existing = emittedRpcClassSchemas.get(candidate);
640-
if (!existing || existing === schemaKey) return candidate;
641-
candidate = `${fallbackName}${suffix++}`;
642-
}
643-
}
644-
645630
function resolveRpcType(schema: JSONSchema7, isRequired: boolean, parentClassName: string, propName: string, classes: string[]): string {
646631
// Handle anyOf: [T, null] → T? (nullable typed property)
647632
if (schema.anyOf) {
@@ -664,10 +649,8 @@ function resolveRpcType(schema: JSONSchema7, isRequired: boolean, parentClassNam
664649
if (schema.type === "array" && schema.items) {
665650
const items = schema.items as JSONSchema7;
666651
if (items.type === "object" && items.properties) {
667-
const defaultName = (items.title as string) ?? singularPascal(propName);
668-
const contextualName = `${parentClassName}${defaultName}`;
669-
const itemClass = chooseRpcClassName(defaultName, contextualName, items);
670-
if (!emittedRpcClasses.has(itemClass)) classes.push(emitRpcClass(itemClass, items, "public", classes));
652+
const itemClass = (items.title as string) ?? singularPascal(propName);
653+
classes.push(emitRpcClass(itemClass, items, "public", classes));
671654
return isRequired ? `List<${itemClass}>` : `List<${itemClass}>?`;
672655
}
673656
const itemType = schemaTypeToCSharp(items, true, rpcKnownTypes);
@@ -687,9 +670,18 @@ function resolveRpcType(schema: JSONSchema7, isRequired: boolean, parentClassNam
687670
}
688671

689672
function emitRpcClass(className: string, schema: JSONSchema7, visibility: "public" | "internal", extraClasses: string[]): string {
690-
if (emittedRpcClasses.has(className)) return "";
691-
emittedRpcClasses.add(className);
692-
emittedRpcClassSchemas.set(className, stableStringify(schema));
673+
const schemaKey = stableStringify(schema);
674+
const existingSchema = emittedRpcClassSchemas.get(className);
675+
if (existingSchema) {
676+
if (existingSchema !== schemaKey) {
677+
throw new Error(
678+
`Conflicting RPC class name "${className}" for different schemas. Add a schema title/withTypeName to disambiguate.`
679+
);
680+
}
681+
return "";
682+
}
683+
684+
emittedRpcClassSchemas.set(className, schemaKey);
693685

694686
const requiredSet = new Set(schema.required || []);
695687
const lines: string[] = [];
@@ -718,7 +710,7 @@ function emitRpcClass(className: string, schema: JSONSchema7, visibility: "publi
718710
else if (csharpType === "object") defaultVal = " = null!;";
719711
else if (csharpType.startsWith("List<") || csharpType.startsWith("Dictionary<")) {
720712
propAccessors = "{ get => field ??= []; set; }";
721-
} else if (emittedRpcClasses.has(csharpType)) {
713+
} else if (emittedRpcClassSchemas.has(csharpType)) {
722714
propAccessors = "{ get => field ??= new(); set; }";
723715
}
724716
}
@@ -1089,7 +1081,6 @@ function emitClientSessionApiRegistration(clientSchema: Record<string, unknown>,
10891081
}
10901082

10911083
function generateRpcCode(schema: ApiSchema): string {
1092-
emittedRpcClasses.clear();
10931084
emittedRpcClassSchemas.clear();
10941085
experimentalRpcTypes.clear();
10951086
rpcKnownTypes.clear();
@@ -1134,7 +1125,7 @@ internal static class Diagnostics
11341125
if (clientSessionParts.length > 0) lines.push(...clientSessionParts, "");
11351126

11361127
// Add JsonSerializerContext for AOT/trimming support
1137-
const typeNames = [...emittedRpcClasses].sort();
1128+
const typeNames = [...emittedRpcClassSchemas.keys()].sort();
11381129
if (typeNames.length > 0) {
11391130
lines.push(`[JsonSourceGenerationOptions(`);
11401131
lines.push(` JsonSerializerDefaults.Web,`);

0 commit comments

Comments
 (0)