@@ -361,44 +361,95 @@ function generateCode() {
361361 writeLine ( "// Structures\n" ) ;
362362
363363 for ( const structure of model . structures ) {
364- write ( formatDocumentation ( structure . documentation ) ) ;
364+ /**
365+ * @param {string } name
366+ * @param {boolean } includeDocumentation
367+ */
368+ function generateStructFields ( name , includeDocumentation ) {
369+ if ( includeDocumentation ) {
370+ write ( formatDocumentation ( structure . documentation ) ) ;
371+ }
372+
373+ writeLine ( `type ${ name } struct {` ) ;
365374
366- writeLine ( `type ${ structure . name } struct {` ) ; // Embed extended types and mixins
367- for ( const e of structure . extends || [ ] ) {
368- if ( e . kind !== "reference" ) {
369- throw new Error ( `Unexpected extends kind: ${ e . kind } ` ) ;
375+ // Embed extended types and mixins
376+ for ( const e of structure . extends || [ ] ) {
377+ if ( e . kind !== "reference" ) {
378+ throw new Error ( `Unexpected extends kind: ${ e . kind } ` ) ;
379+ }
380+ writeLine ( `\t${ e . name } ` ) ;
370381 }
371- writeLine ( `\t${ e . name } ` ) ;
372- }
373382
374- for ( const m of structure . mixins || [ ] ) {
375- if ( m . kind !== "reference" ) {
376- throw new Error ( `Unexpected mixin kind: ${ m . kind } ` ) ;
383+ for ( const m of structure . mixins || [ ] ) {
384+ if ( m . kind !== "reference" ) {
385+ throw new Error ( `Unexpected mixin kind: ${ m . kind } ` ) ;
386+ }
387+ writeLine ( `\t${ m . name } ` ) ;
377388 }
378- writeLine ( `\t${ m . name } ` ) ;
379- }
380389
381- // Insert a blank line after embeds if there were any
382- if (
383- ( structure . extends && structure . extends . length > 0 ) ||
384- ( structure . mixins && structure . mixins . length > 0 )
385- ) {
386- writeLine ( "" ) ;
387- }
390+ // Insert a blank line after embeds if there were any
391+ if (
392+ ( structure . extends && structure . extends . length > 0 ) ||
393+ ( structure . mixins && structure . mixins . length > 0 )
394+ ) {
395+ writeLine ( "" ) ;
396+ }
397+
398+ // Then properties
399+ for ( const prop of structure . properties ) {
400+ if ( includeDocumentation ) {
401+ write ( formatDocumentation ( prop . documentation ) ) ;
402+ }
403+
404+ const type = resolveType ( prop . type ) ;
405+ const goType = prop . optional || type . needsPointer ? `*${ type . name } ` : type . name ;
388406
389- // Then properties
390- for ( const prop of structure . properties ) {
391- write ( formatDocumentation ( prop . documentation ) ) ;
407+ writeLine ( `\t${ titleCase ( prop . name ) } ${ goType } \`json:"${ prop . name } ${ prop . optional ? ",omitempty" : "" } "\`` ) ;
392408
393- const type = resolveType ( prop . type ) ;
394- const goType = prop . optional || type . needsPointer ? `*${ type . name } ` : type . name ;
409+ if ( includeDocumentation ) {
410+ writeLine ( "" ) ;
411+ }
412+ }
395413
396- writeLine ( `\t ${ titleCase ( prop . name ) } ${ goType } \`json:" ${ prop . name } ${ prop . optional ? ",omitempty" : "" } "\`` ) ;
414+ writeLine ( "}" ) ;
397415 writeLine ( "" ) ;
398416 }
399417
400- writeLine ( "}" ) ;
418+ generateStructFields ( structure . name , true ) ;
401419 writeLine ( "" ) ;
420+
421+ // Generate UnmarshalJSON method for structure validation
422+ const requiredProps = structure . properties ?. filter ( p => ! p . optional ) || [ ] ;
423+ if ( requiredProps . length > 0 ) {
424+ writeLine ( `func (s *${ structure . name } ) UnmarshalJSON(data []byte) error {` ) ;
425+ writeLine ( `\t// Check required props` ) ;
426+ writeLine ( `\ttype requiredProps struct {` ) ;
427+ for ( const prop of requiredProps ) {
428+ writeLine ( `\t\t${ titleCase ( prop . name ) } requiredProp \`json:"${ prop . name } "\`` ) ;
429+ }
430+ writeLine ( `}` ) ;
431+ writeLine ( "" ) ;
432+
433+ writeLine ( `\tvar keys requiredProps` ) ;
434+ writeLine ( `\tif err := json.Unmarshal(data, &keys); err != nil {` ) ;
435+ writeLine ( `\t\treturn err` ) ;
436+ writeLine ( `\t}` ) ;
437+ writeLine ( "" ) ;
438+
439+ // writeLine(`\t// Check for missing required keys`);
440+ for ( const prop of requiredProps ) {
441+ writeLine ( `if !keys.${ titleCase ( prop . name ) } {` ) ;
442+ writeLine ( `\t\treturn fmt.Errorf("required key '${ prop . name } ' is missing")` ) ;
443+ writeLine ( `}` ) ;
444+ }
445+
446+ writeLine ( `` ) ;
447+ writeLine ( `\t// Redeclare the struct to prevent infinite recursion` ) ;
448+ generateStructFields ( "temp" , false ) ;
449+ writeLine ( `\treturn json.Unmarshal(data, (*temp)(s))` ) ;
450+ writeLine ( `}` ) ;
451+ writeLine ( "" ) ;
452+ }
402453 }
403454
404455 // Generate enumerations
0 commit comments