github.com/ManabuSeki/goa-v1@v1.4.3/goagen/codegen/publicizer.go (about) 1 package codegen 2 3 import ( 4 "fmt" 5 "strings" 6 "text/template" 7 8 "github.com/goadesign/goa/design" 9 ) 10 11 var ( 12 simplePublicizeT *template.Template 13 recursivePublicizeT *template.Template 14 objectPublicizeT *template.Template 15 arrayPublicizeT *template.Template 16 hashPublicizeT *template.Template 17 ) 18 19 func init() { 20 var err error 21 fm := template.FuncMap{ 22 "tabs": Tabs, 23 "goify": Goify, 24 "gotyperef": GoTypeRef, 25 "gotypedef": GoTypeDef, 26 "add": Add, 27 "publicizer": Publicizer, 28 "recursivePublicizer": RecursivePublicizer, 29 } 30 if simplePublicizeT, err = template.New("simplePublicize").Funcs(fm).Parse(simplePublicizeTmpl); err != nil { 31 panic(err) 32 } 33 if recursivePublicizeT, err = template.New("recursivePublicize").Funcs(fm).Parse(recursivePublicizeTmpl); err != nil { 34 panic(err) 35 } 36 if objectPublicizeT, err = template.New("objectPublicize").Funcs(fm).Parse(objectPublicizeTmpl); err != nil { 37 panic(err) 38 } 39 if arrayPublicizeT, err = template.New("arrPublicize").Funcs(fm).Parse(arrayPublicizeTmpl); err != nil { 40 panic(err) 41 } 42 if hashPublicizeT, err = template.New("hashPublicize").Funcs(fm).Parse(hashPublicizeTmpl); err != nil { 43 panic(err) 44 } 45 } 46 47 // RecursivePublicizer produces code that copies fields from the private struct to the 48 // public struct 49 func RecursivePublicizer(att *design.AttributeDefinition, source, target string, depth int) string { 50 var publications []string 51 if o := att.Type.ToObject(); o != nil { 52 if ds, ok := att.Type.(design.DataStructure); ok { 53 att = ds.Definition() 54 } 55 o.IterateAttributes(func(n string, catt *design.AttributeDefinition) error { 56 publication := Publicizer( 57 catt, 58 fmt.Sprintf("%s.%s", source, Goify(n, true)), 59 fmt.Sprintf("%s.%s", target, Goify(n, true)), 60 catt.Type.IsPrimitive() && !att.IsPrimitivePointer(n) && !att.IsInterface(n), 61 depth+1, 62 false, 63 ) 64 publication = fmt.Sprintf("%sif %s.%s != nil {\n%s\n%s}", 65 Tabs(depth), source, Goify(n, true), publication, Tabs(depth)) 66 publications = append(publications, publication) 67 return nil 68 }) 69 } 70 return strings.Join(publications, "\n") 71 } 72 73 // Publicizer publicizes a single attribute based on the type. 74 func Publicizer(att *design.AttributeDefinition, sourceField, targetField string, dereference bool, depth int, init bool) string { 75 var publication string 76 data := map[string]interface{}{ 77 "sourceField": sourceField, 78 "targetField": targetField, 79 "depth": depth, 80 "att": att, 81 "dereference": dereference, 82 "init": init, 83 } 84 switch { 85 case att.Type.IsPrimitive(): 86 publication = RunTemplate(simplePublicizeT, data) 87 case att.Type.IsObject(): 88 if _, ok := att.Type.(*design.MediaTypeDefinition); ok { 89 publication = RunTemplate(recursivePublicizeT, data) 90 } else if _, ok := att.Type.(*design.UserTypeDefinition); ok { 91 publication = RunTemplate(recursivePublicizeT, data) 92 } else { 93 publication = RunTemplate(objectPublicizeT, data) 94 } 95 case att.Type.IsArray(): 96 // If the array element is primitive type, we can simply copy the elements over (i.e) []string 97 if att.Type.HasAttributes() { 98 data["elemType"] = att.Type.ToArray().ElemType 99 publication = RunTemplate(arrayPublicizeT, data) 100 } else { 101 publication = RunTemplate(simplePublicizeT, data) 102 } 103 case att.Type.IsHash(): 104 if att.Type.HasAttributes() { 105 h := att.Type.ToHash() 106 data["keyType"] = h.KeyType 107 data["elemType"] = h.ElemType 108 publication = RunTemplate(hashPublicizeT, data) 109 } else { 110 publication = RunTemplate(simplePublicizeT, data) 111 } 112 } 113 return publication 114 } 115 116 const ( 117 simplePublicizeTmpl = `{{ tabs .depth }}{{ .targetField }} {{ if .init }}:{{ end }}= {{ if .dereference }}*{{ end }}{{ .sourceField }}` 118 119 recursivePublicizeTmpl = `{{ tabs .depth }}{{ .targetField }} {{ if .init }}:{{ end }}= {{ .sourceField }}.Publicize()` 120 121 objectPublicizeTmpl = `{{ tabs .depth }}{{ .targetField }} = &{{ gotypedef .att .depth true false }}{} 122 {{ recursivePublicizer .att .sourceField .targetField .depth }}` 123 124 arrayPublicizeTmpl = `{{ tabs .depth }}{{ .targetField }} {{ if .init }}:{{ end }}= make({{ gotyperef .att.Type .att.AllRequired .depth false }}, len({{ .sourceField }})){{/* 125 */}}{{ $i := printf "%s%d" "i" .depth }}{{ $elem := printf "%s%d" "elem" .depth }} 126 {{ tabs .depth }}for {{ $i }}, {{ $elem }} := range {{ .sourceField }} { 127 {{ tabs .depth }}{{ publicizer .elemType $elem (printf "%s[%s]" .targetField $i) .dereference (add .depth 1) false }} 128 {{ tabs .depth }}}` 129 130 hashPublicizeTmpl = `{{ tabs .depth }}{{ .targetField }} {{ if .init }}:{{ end }}= make({{ gotyperef .att.Type .att.AllRequired .depth false }}, len({{ .sourceField }})){{/* 131 */}}{{ $k := printf "%s%d" "k" .depth }}{{ $v := printf "%s%d" "v" .depth }} 132 {{ tabs .depth }}for {{ $k }}, {{ $v }} := range {{ .sourceField }} { 133 {{ $pubk := printf "%s%s" "pub" $k }}{{ $pubv := printf "%s%s" "pub" $v }}{{/* 134 */}}{{ tabs (add .depth 1) }}{{ if .keyType.Type.IsObject }}var {{ $pubk }} {{ gotyperef .keyType.Type .AllRequired .depth false}} 135 {{ tabs (add .depth 1) }}if {{ $k }} != nil { 136 {{ tabs (add .depth 1) }}{{ publicizer .keyType $k $pubk .dereference (add .depth 1) false }} 137 {{ tabs (add .depth 1) }}}{{ else }}{{ publicizer .keyType $k $pubk .dereference (add .depth 1) true }}{{ end }} 138 {{ tabs (add .depth 1) }}{{if .elemType.Type.IsObject }}var {{ $pubv }} {{ gotyperef .elemType.Type .AllRequired .depth false }} 139 {{ tabs (add .depth 1) }}if {{ $v }} != nil { 140 {{ tabs (add .depth 1) }}{{ publicizer .elemType $v $pubv .dereference (add .depth 1) false }} 141 {{ tabs (add .depth 1) }}}{{ else }}{{ publicizer .elemType $v $pubv .dereference (add .depth 1) true }}{{ end }} 142 {{ tabs .depth }} {{ printf "%s[%s]" .targetField $pubk }} = {{ $pubv }} 143 {{ tabs .depth }}}` 144 )