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  )