@@ -16,6 +16,7 @@ import {
1616 getApiSchemaPath ,
1717 writeGeneratedFile ,
1818 collectDefinitions ,
19+ postProcessSchema ,
1920 resolveRef ,
2021 refTypeName ,
2122 isRpcMethod ,
@@ -512,18 +513,25 @@ function resolveSessionPropertyType(
512513) : string {
513514 // Handle $ref by resolving against schema definitions
514515 if ( propSchema . $ref ) {
515- const typeName = refTypeName ( propSchema . $ref ) ;
516- const className = typeToClassName ( typeName ) ;
517- if ( ! nestedClasses . has ( className ) ) {
518- const refSchema = resolveRef ( propSchema . $ref , sessionDefinitions ) ;
519- if ( refSchema ) {
520- if ( refSchema . enum && Array . isArray ( refSchema . enum ) ) {
521- return getOrCreateEnum ( className , "" , refSchema . enum as string [ ] , enumOutput ) ;
522- }
516+ const className = typeToClassName ( refTypeName ( propSchema . $ref ) ) ;
517+ const refSchema = resolveRef ( propSchema . $ref , sessionDefinitions ) ;
518+ if ( ! refSchema ) {
519+ return isRequired ? className : `${ className } ?` ;
520+ }
521+
522+ if ( refSchema . enum && Array . isArray ( refSchema . enum ) ) {
523+ const enumName = getOrCreateEnum ( className , "" , refSchema . enum as string [ ] , enumOutput , refSchema . description ) ;
524+ return isRequired ? enumName : `${ enumName } ?` ;
525+ }
526+
527+ if ( refSchema . type === "object" && refSchema . properties ) {
528+ if ( ! nestedClasses . has ( className ) ) {
523529 nestedClasses . set ( className , generateNestedClass ( className , refSchema , knownTypes , nestedClasses , enumOutput ) ) ;
524530 }
531+ return isRequired ? className : `${ className } ?` ;
525532 }
526- return isRequired ? className : `${ className } ?` ;
533+
534+ return resolveSessionPropertyType ( refSchema , parentClassName , propName , isRequired , knownTypes , nestedClasses , enumOutput ) ;
527535 }
528536 if ( propSchema . anyOf ) {
529537 const hasNull = propSchema . anyOf . some ( ( s ) => typeof s === "object" && ( s as JSONSchema7 ) . type === "null" ) ;
@@ -556,40 +564,15 @@ function resolveSessionPropertyType(
556564 }
557565 if ( propSchema . type === "array" && propSchema . items ) {
558566 const items = propSchema . items as JSONSchema7 ;
559- // Handle $ref in array items
560- if ( items . $ref ) {
561- const typeName = refTypeName ( items . $ref ) ;
562- const className = typeToClassName ( typeName ) ;
563- if ( ! nestedClasses . has ( className ) ) {
564- const refSchema = resolveRef ( items . $ref , sessionDefinitions ) ;
565- if ( refSchema ) {
566- nestedClasses . set ( className , generateNestedClass ( className , refSchema , knownTypes , nestedClasses , enumOutput ) ) ;
567- }
568- }
569- return isRequired ? `${ className } []` : `${ className } []?` ;
570- }
571- // Array of discriminated union (anyOf with shared discriminator)
572- if ( items . anyOf && Array . isArray ( items . anyOf ) ) {
573- const variants = items . anyOf . filter ( ( v ) : v is JSONSchema7 => typeof v === "object" ) ;
574- const discriminatorInfo = findDiscriminator ( variants ) ;
575- if ( discriminatorInfo ) {
576- const baseClassName = `${ parentClassName } ${ propName } Item` ;
577- const renamedBase = applyTypeRename ( baseClassName ) ;
578- const polymorphicCode = generatePolymorphicClasses ( baseClassName , discriminatorInfo . property , variants , knownTypes , nestedClasses , enumOutput , items . description ) ;
579- nestedClasses . set ( renamedBase , polymorphicCode ) ;
580- return isRequired ? `${ renamedBase } []` : `${ renamedBase } []?` ;
581- }
582- }
583- if ( items . type === "object" && items . properties ) {
584- const itemClassName = `${ parentClassName } ${ propName } Item` ;
585- nestedClasses . set ( itemClassName , generateNestedClass ( itemClassName , items , knownTypes , nestedClasses , enumOutput ) ) ;
586- return isRequired ? `${ itemClassName } []` : `${ itemClassName } []?` ;
587- }
588- if ( items . enum && Array . isArray ( items . enum ) ) {
589- const enumName = getOrCreateEnum ( parentClassName , `${ propName } Item` , items . enum as string [ ] , enumOutput , items . description ) ;
590- return isRequired ? `${ enumName } []` : `${ enumName } []?` ;
591- }
592- const itemType = schemaTypeToCSharp ( items , true , knownTypes ) ;
567+ const itemType = resolveSessionPropertyType (
568+ items ,
569+ parentClassName ,
570+ `${ propName } Item` ,
571+ true ,
572+ knownTypes ,
573+ nestedClasses ,
574+ enumOutput
575+ ) ;
593576 return isRequired ? `${ itemType } []` : `${ itemType } []?` ;
594577 }
595578 return schemaTypeToCSharp ( propSchema , isRequired , knownTypes ) ;
@@ -725,7 +708,8 @@ export async function generateSessionEvents(schemaPath?: string): Promise<void>
725708 console . log ( "C#: generating session-events..." ) ;
726709 const resolvedPath = schemaPath ?? ( await getSessionEventsSchemaPath ( ) ) ;
727710 const schema = JSON . parse ( await fs . readFile ( resolvedPath , "utf-8" ) ) as JSONSchema7 ;
728- const code = generateSessionEventsCode ( schema ) ;
711+ const processed = postProcessSchema ( schema ) ;
712+ const code = generateSessionEventsCode ( processed ) ;
729713 const outPath = await writeGeneratedFile ( "dotnet/src/Generated/SessionEvents.cs" , code ) ;
730714 console . log ( ` ✓ ${ outPath } ` ) ;
731715 await formatCSharpFile ( outPath ) ;
@@ -773,13 +757,24 @@ function stableStringify(value: unknown): string {
773757function resolveRpcType ( schema : JSONSchema7 , isRequired : boolean , parentClassName : string , propName : string , classes : string [ ] ) : string {
774758 // Handle $ref by resolving against schema definitions and generating the referenced class
775759 if ( schema . $ref ) {
776- const typeName = refTypeName ( schema . $ref ) ;
760+ const typeName = typeToClassName ( refTypeName ( schema . $ref ) ) ;
777761 const refSchema = resolveRef ( schema . $ref , rpcDefinitions ) ;
778- if ( refSchema && ! emittedRpcClasses . has ( typeName ) ) {
762+ if ( ! refSchema ) {
763+ return isRequired ? typeName : `${ typeName } ?` ;
764+ }
765+
766+ if ( refSchema . enum && Array . isArray ( refSchema . enum ) ) {
767+ const enumName = getOrCreateEnum ( typeName , "" , refSchema . enum as string [ ] , rpcEnumOutput , refSchema . description ) ;
768+ return isRequired ? enumName : `${ enumName } ?` ;
769+ }
770+
771+ if ( refSchema . type === "object" && refSchema . properties ) {
779772 const cls = emitRpcClass ( typeName , refSchema , "public" , classes ) ;
780773 if ( cls ) classes . push ( cls ) ;
774+ return isRequired ? typeName : `${ typeName } ?` ;
781775 }
782- return isRequired ? typeName : `${ typeName } ?` ;
776+
777+ return resolveRpcType ( refSchema , isRequired , parentClassName , propName , classes ) ;
783778 }
784779 // Handle anyOf: [T, null] → T? (nullable typed property)
785780 if ( schema . anyOf ) {
@@ -801,32 +796,17 @@ function resolveRpcType(schema: JSONSchema7, isRequired: boolean, parentClassNam
801796 }
802797 if ( schema . type === "array" && schema . items ) {
803798 const items = schema . items as JSONSchema7 ;
804- // Handle $ref in array items
805- if ( items . $ref ) {
806- const typeName = refTypeName ( items . $ref ) ;
807- const refSchema = resolveRef ( items . $ref , rpcDefinitions ) ;
808- if ( refSchema && ! emittedRpcClasses . has ( typeName ) ) {
809- const cls = emitRpcClass ( typeName , refSchema , "public" , classes ) ;
810- if ( cls ) classes . push ( cls ) ;
811- }
812- return isRequired ? `List<${ typeName } >` : `List<${ typeName } >?` ;
813- }
814799 if ( items . type === "object" && items . properties ) {
815800 const itemClass = ( items . title as string ) ?? singularPascal ( propName ) ;
816801 classes . push ( emitRpcClass ( itemClass , items , "public" , classes ) ) ;
817802 return isRequired ? `IList<${ itemClass } >` : `IList<${ itemClass } >?` ;
818803 }
819- const itemType = schemaTypeToCSharp ( items , true , rpcKnownTypes ) ;
804+ const itemType = resolveRpcType ( items , true , parentClassName , ` ${ propName } Item` , classes ) ;
820805 return isRequired ? `IList<${ itemType } >` : `IList<${ itemType } >?` ;
821806 }
822807 if ( schema . type === "object" && schema . additionalProperties && typeof schema . additionalProperties === "object" ) {
823808 const vs = schema . additionalProperties as JSONSchema7 ;
824- if ( vs . type === "object" && vs . properties ) {
825- const valClass = `${ parentClassName } ${ propName } Value` ;
826- classes . push ( emitRpcClass ( valClass , vs , "public" , classes ) ) ;
827- return isRequired ? `IDictionary<string, ${ valClass } >` : `IDictionary<string, ${ valClass } >?` ;
828- }
829- const valueType = schemaTypeToCSharp ( vs , true , rpcKnownTypes ) ;
809+ const valueType = resolveRpcType ( vs , true , parentClassName , `${ propName } Value` , classes ) ;
830810 return isRequired ? `IDictionary<string, ${ valueType } >` : `IDictionary<string, ${ valueType } >?` ;
831811 }
832812 return schemaTypeToCSharp ( schema , isRequired , rpcKnownTypes ) ;
@@ -1007,15 +987,9 @@ function emitServerInstanceMethod(
1007987 if ( typeof pSchema !== "object" ) continue ;
1008988 const isReq = requiredSet . has ( pName ) ;
1009989 const jsonSchema = pSchema as JSONSchema7 ;
1010- let csType : string ;
1011- // If the property has an enum, resolve to the generated enum type
1012- if ( jsonSchema . enum && Array . isArray ( jsonSchema . enum ) && requestClassName ) {
1013- const valuesKey = [ ...jsonSchema . enum ] . sort ( ) . join ( "|" ) ;
1014- const match = [ ...generatedEnums . values ( ) ] . find ( ( e ) => [ ...e . values ] . sort ( ) . join ( "|" ) === valuesKey ) ;
1015- csType = match ? ( isReq ? match . enumName : `${ match . enumName } ?` ) : schemaTypeToCSharp ( jsonSchema , isReq , rpcKnownTypes ) ;
1016- } else {
1017- csType = schemaTypeToCSharp ( jsonSchema , isReq , rpcKnownTypes ) ;
1018- }
990+ const csType = requestClassName
991+ ? resolveRpcType ( jsonSchema , isReq , requestClassName , toPascalCase ( pName ) , classes )
992+ : schemaTypeToCSharp ( jsonSchema , isReq , rpcKnownTypes ) ;
1019993 sigParams . push ( `${ csType } ${ pName } ${ isReq ? "" : " = null" } ` ) ;
1020994 bodyAssignments . push ( `${ toPascalCase ( pName ) } = ${ pName } ` ) ;
1021995 }
0 commit comments