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