github.com/blp1526/goa@v1.4.0/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  )