@@ -323,12 +323,6 @@ type Type struct {
323323 Comment string
324324}
325325
326- // Binding represents a field binding from headers, path, or query
327- type Binding struct {
328- From string // Source: header/path/query
329- Name string // Field name in the source
330- }
331-
332326// TypeField represents a field in a Go struct
333327type TypeField struct {
334328 Type string
@@ -340,6 +334,12 @@ type TypeField struct {
340334 Comment string
341335}
342336
337+ // Binding represents a field binding from headers, path, or query
338+ type Binding struct {
339+ From string // Source: header/path/query
340+ Name string // Field name in the source
341+ }
342+
343343// BindingCount returns the number of fields in the struct that have binding info
344344func (t * Type ) BindingCount () int {
345345 var count int
@@ -363,7 +363,7 @@ func (t *Type) ValidateCount() int {
363363}
364364
365365// convertTypes converts IDL struct types to Go struct types
366- func convertTypes (ctx Context , doc tidl.Document ) (_ []Type , err error ) {
366+ func convertTypes (ctx Context , doc tidl.Document ) ([]Type , error ) {
367367 var ret []Type
368368
369369 // Handle type keyword defined structs
@@ -372,16 +372,19 @@ func convertTypes(ctx Context, doc tidl.Document) (_ []Type, err error) {
372372 if t .GenericName != nil {
373373 continue
374374 }
375- var r Type
375+ var (
376+ typ Type
377+ err error
378+ )
376379 if t .Redefined != nil {
377- r , err = convertRedefinedType (ctx , t )
380+ typ , err = convertRedefinedType (ctx , t )
378381 } else {
379- r , err = convertType (ctx , t )
382+ typ , err = convertType (ctx , t )
380383 }
381384 if err != nil {
382385 return nil , err
383386 }
384- ret = append (ret , r )
387+ ret = append (ret , typ )
385388 }
386389
387390 return ret , nil
@@ -396,7 +399,7 @@ func convertRedefinedType(ctx Context, r tidl.Type) (Type, error) {
396399
397400 var fields []tidl.TypeField
398401 for _ , f := range t .Fields {
399- f .FieldType = resolveGenericType (f .FieldType , * t .GenericName , r .Redefined )
402+ f .FieldType = replaceGenericType (f .FieldType , * t .GenericName , r .Redefined . GenericType )
400403 fields = append (fields , f )
401404 }
402405
@@ -408,19 +411,19 @@ func convertRedefinedType(ctx Context, r tidl.Type) (Type, error) {
408411 })
409412}
410413
411- // resolveGenericType replaces a generic type in a field with a concrete type
412- func resolveGenericType (t tidl.TypeDefinition , genericName string , r * tidl.RedefinedType ) tidl.TypeDefinition {
414+ // replaceGenericType replaces a generic type in a field with a concrete type
415+ func replaceGenericType (t tidl.TypeDefinition , genericName string , genericType tidl.TypeDefinition ) tidl.TypeDefinition {
413416 switch u := t .(type ) {
414417 case tidl.UserType :
415418 if u .Name == genericName {
416- return r . GenericType
419+ return genericType
417420 }
418421 return u
419422 case tidl.ListType :
420- u .Item = resolveGenericType (u .Item , genericName , r )
423+ u .Item = replaceGenericType (u .Item , genericName , genericType )
421424 return u
422425 case tidl.MapType :
423- u .Value = resolveGenericType (u .Value , genericName , r )
426+ u .Value = replaceGenericType (u .Value , genericName , genericType )
424427 return u
425428 default :
426429 return t
@@ -433,6 +436,7 @@ func convertType(ctx Context, t tidl.Type) (Type, error) {
433436 Name : t .Name ,
434437 }
435438
439+ // Handle oneof
436440 if t .OneOf {
437441 r .Fields = append (r .Fields , TypeField {
438442 Type : r .Name + "TypeAsString" ,
@@ -442,25 +446,27 @@ func convertType(ctx Context, t tidl.Type) (Type, error) {
442446 })
443447 }
444448
449+ // Handle fields
445450 for _ , f := range t .Fields {
446451
447452 // Handle embedded types (flatten their fields into the struct)
448- if ft , ok := f .FieldType .(tidl.EmbedType ); ok {
449- et , ok := tidl .GetType (ctx .files , ft .Name )
453+ if embedType , ok := f .FieldType .(tidl.EmbedType ); ok {
454+ srcType , ok := tidl .GetType (ctx .files , embedType .Name )
450455 if ! ok {
451- return Type {}, fmt .Errorf ("embedded type %s not found for field in struct %s" , ft .Name , r .Name )
456+ return Type {}, fmt .Errorf ("embedded type %s not found for field in struct %s" , embedType .Name , r .Name )
452457 }
453- rt , err := convertType (ctx , et )
458+ retType , err := convertType (ctx , srcType )
454459 if err != nil {
455- return Type {}, fmt .Errorf ("failed to convert embedded type %s in struct %s: %w" , ft .Name , r .Name , err )
460+ return Type {}, fmt .Errorf ("failed to convert embedded type %s in struct %s: %w" , embedType .Name , r .Name , err )
456461 }
457462 // Append embedded type's fields
458- r .Fields = append (r .Fields , rt .Fields ... )
463+ r .Fields = append (r .Fields , retType .Fields ... )
459464 continue
460465 }
461466
462- // Get field name and Go type
463467 fieldName := tidl .ToPascal (f .Name )
468+
469+ // Get field name and Go type
464470 typeName , err := getTypeName (ctx , f .FieldType , f .Annotations )
465471 if err != nil {
466472 return Type {}, err
@@ -509,17 +515,23 @@ func convertType(ctx Context, t tidl.Type) (Type, error) {
509515func getTypeName (ctx Context , t tidl.TypeDefinition , arr []tidl.Annotation ) (string , error ) {
510516
511517 // Handle go.type annotation
512- if a , ok := tidl .GetAnnotation (arr , "go.type" ); ok && a .Value != nil {
518+ if a , ok := tidl .GetAnnotation (arr , "go.type" ); ok {
519+ if a .Value == nil {
520+ return "" , fmt .Errorf ("go.type annotation must have a value" )
521+ }
513522 s := strings .Trim (strings .TrimSpace (* a .Value ), "\" " )
523+ if s == "" {
524+ return "" , fmt .Errorf ("go.type annotation must not empty" )
525+ }
514526 return s , nil
515527 }
516528
517- switch ft := t .(type ) {
529+ switch typ := t .(type ) {
518530 case tidl.AnyType :
519531 return "" , fmt .Errorf ("any type must have go.type annotation" )
520532 case tidl.BaseType :
521533 var typeName string
522- switch ft .Name {
534+ switch typ .Name {
523535 case "string" :
524536 typeName = "string"
525537 case "int" :
@@ -529,56 +541,51 @@ func getTypeName(ctx Context, t tidl.TypeDefinition, arr []tidl.Annotation) (str
529541 case "bool" :
530542 typeName = "bool"
531543 default :
532- return "" , fmt .Errorf ("unknown base type: %s" , ft .Name )
544+ return "" , fmt .Errorf ("unknown base type: %s" , typ .Name )
533545 }
534- if ft .Optional {
546+ if typ .Optional {
535547 typeName = "*" + typeName
536548 }
537549 return typeName , nil
538550 case tidl.UserType :
539- typeName := ft .Name
540- if ft .Optional {
541- typeName = "*" + typeName
542- }
543-
551+ typeName := typ .Name
544552 // Handle enum_as_string annotation
545553 if _ , ok := tidl .GetAnnotation (arr , "enum_as_string" ); ok {
546- if _ , ok := tidl .GetEnum (ctx .files , ft .Name ); ! ok {
547- return "" , fmt .Errorf ("enum %s not found" , ft .Name )
554+ if _ , ok := tidl .GetEnum (ctx .files , typ .Name ); ! ok {
555+ return "" , fmt .Errorf ("enum %s not found" , typ .Name )
548556 }
549557 typeName += "AsString"
550558 }
559+ if typ .Optional {
560+ typeName = "*" + typeName
561+ }
551562 return typeName , nil
552563 case tidl.ListType :
553- itemType , err := getTypeName (ctx , ft .Item , nil )
564+ itemType , err := getTypeName (ctx , typ .Item , nil )
554565 if err != nil {
555566 return "" , err
556567 }
557568 return "[]" + itemType , nil
558569 case tidl.MapType :
559570 keyType := "string"
560- if ft .Key == "int" {
571+ if typ .Key == "int" {
561572 keyType = "int64"
562573 }
563- valueType , err := getTypeName (ctx , ft .Value , nil )
574+ valueType , err := getTypeName (ctx , typ .Value , nil )
564575 if err != nil {
565576 return "" , err
566577 }
567578 return fmt .Sprintf ("map[%s]%s" , keyType , valueType ), nil
568579 case tidl.BinaryType :
569- // todo (lvan100) handle file
570- return "[]byte" , nil
580+ return "[]byte" , nil // todo (lvan100) handle file
571581 default :
572582 return "" , fmt .Errorf ("unknown type: %s" , t .Text ())
573583 }
574584}
575585
576586// getTypeKind returns the category of a Go type (base, optional base, enum, struct, etc.)
577587func getTypeKind (ctx Context , typeName string ) (TypeKind , error ) {
578- optional := strings .HasPrefix (typeName , "*" )
579- if optional {
580- typeName = strings .TrimPrefix (typeName , "*" )
581- }
588+ typeName , optional := strings .CutPrefix (typeName , "*" )
582589
583590 switch typeName {
584591 case "int" , "int8" , "int16" , "int32" , "int64" ,
@@ -630,7 +637,10 @@ func parseBinding(arr []tidl.Annotation) (*Binding, error) {
630637 return nil , fmt .Errorf ("annotation %s value is nil" , a .Key )
631638 }
632639 val := strings .Trim (* a .Value , "\" " )
633- return & Binding {From : a .Key , Name : val }, nil
640+ return & Binding {
641+ From : a .Key ,
642+ Name : val ,
643+ }, nil
634644}
635645
636646// genFieldTag generates the struct tag for a field.
@@ -705,7 +715,6 @@ var builtinFuncs = map[string]struct{}{
705715// genValidate generates validation code for a field based on annotations.
706716// It returns a Go code snippet for validating the field.
707717func genValidate (receiverType , fieldName , fieldType string , arr []tidl.Annotation , funcs map [string ]ValidateFunc ) (* string , error ) {
708- optional := strings .HasPrefix (fieldType , "*" )
709718 a , ok := tidl .GetAnnotation (arr , "validate" )
710719 if ! ok {
711720 return nil , nil
@@ -729,6 +738,7 @@ func genValidate(receiverType, fieldName, fieldType string, arr []tidl.Annotatio
729738 return nil , err
730739 }
731740
741+ optional := strings .HasPrefix (fieldType , "*" )
732742 dollar := "x." + fieldName
733743 if optional {
734744 dollar = "*" + dollar
0 commit comments