Repository: goadesign/goa
Pull request #2915 (2021-09-07 22:54:03)

Fix embedded references


Patch:
diff --git a/Makefile b/Makefile
index bfc670ed..ff24f8bc 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@ GOPATH=$(shell go env GOPATH)
 DEPEND=\
 	golang.org/x/lint/golint@v0.0.0-20210508222113-6edffad5e616  \
 	google.golang.org/protobuf/cmd/protoc-gen-go@v1.27.1 \
-        google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1.0 \
+	google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1 \
 	honnef.co/go/tools/cmd/staticcheck@v0.2.1
 
 all: lint test
diff --git a/codegen/service/views.go b/codegen/service/views.go
index 5b08aa1a..562e8035 100644
--- a/codegen/service/views.go
+++ b/codegen/service/views.go
@@ -115,10 +115,10 @@ func {{ .Name }}(result {{ .Ref }}) (err error) {
 // input: map[string]interface{}{"ViewedTypes": []*viewedType}
 const viewedMapT = `var (
 {{- range .ViewedTypes }}
-	{{ printf "%sMap is a map of attribute names in result type %s indexed by view name." .Name .Name | comment }}
+	{{ printf "%sMap is a map indexing the attribute names of %s by view name." .Name .Name | comment }}
 	{{ .Name }}Map = map[string][]string{
 	{{- range .Views }}
-		"{{ .Name }}": []string{
+		"{{ .Name }}": {
 			{{- range $n := .Attributes }}
 				"{{ $n }}",
 			{{- end }}
diff --git a/dsl/attribute.go b/dsl/attribute.go
index d8d672e9..03fca88f 100644
--- a/dsl/attribute.go
+++ b/dsl/attribute.go
@@ -156,8 +156,6 @@ func Attribute(name string, args ...interface{}) {
 				Description: description,
 			}
 		}
-		attr.References = parent.References
-		attr.Bases = parent.Bases
 		if fn != nil {
 			eval.Execute(fn, attr)
 		}
diff --git a/expr/attribute.go b/expr/attribute.go
index d753245c..00e63364 100644
--- a/expr/attribute.go
+++ b/expr/attribute.go
@@ -540,8 +540,9 @@ func (a *AttributeExpr) ExtractUserExamples() []*ExampleExpr {
 // Debug dumps the attribute to STDOUT in a goa developer friendly way.
 func (a *AttributeExpr) Debug(prefix string) { a.debug(prefix, make(map[*AttributeExpr]int), 0) }
 func (a *AttributeExpr) debug(prefix string, seen map[*AttributeExpr]int, indent int) {
-	tab := strings.Repeat("  ", indent)
-	prefix = tab + prefix
+	tab := "    "
+	tabs := strings.Repeat(tab, indent)
+	prefix = tabs + prefix
 	if c, ok := seen[a]; ok && c > 1 {
 		fmt.Printf("%s: ...\n", prefix)
 		return
@@ -561,38 +562,50 @@ func (a *AttributeExpr) debug(prefix string, seen map[*AttributeExpr]int, indent
 		m.ElemType.debug("elem", seen, indent+1)
 	}
 	if rt, ok := a.Type.(*ResultTypeExpr); ok {
-		fmt.Printf("%sviews\n", tab)
+		fmt.Printf("%s%sviews\n", tabs, tab)
 		for _, v := range rt.Views {
 			nats := *AsObject(v.AttributeExpr.Type)
 			keys := make([]string, len(nats))
 			for i, n := range nats {
 				keys[i] = n.Name
 			}
-			fmt.Printf("%s- %s: %v\n", tab+"  ", v.Name, keys)
+			fmt.Printf("%s%s- %s: %v\n", tabs+tab, tab, v.Name, keys)
 		}
 	}
 	if d := a.DefaultValue; d != nil {
-		fmt.Printf("%sdefault\n", tab)
-		fmt.Printf("%s  %#v\n", tab, a.DefaultValue)
-	}
-	if v := a.Validation; v != nil {
-		v.Debug(indent)
+		fmt.Printf("%s%sdefault\n", tabs, tab)
+		fmt.Printf("%s%s%#v\n", tabs+tab, tab, a.DefaultValue)
 	}
 	if len(a.UserExamples) > 0 {
-		fmt.Printf("%sexamples\n", tab)
+		fmt.Printf("%s%sexamples\n", tabs, tab)
 		for _, ex := range a.UserExamples {
-			fmt.Printf("%s- %s: %#v\n", tab+"  ", ex.Summary, ex.Value)
+			fmt.Printf("%s%s- %s: %#v\n", tabs+tab, tab, ex.Summary, ex.Value)
 		}
 	}
 	if len(a.Meta) > 0 {
-		fmt.Printf("%smeta\n", tab)
+		fmt.Printf("%s%smeta\n", tabs, tab)
 		for k, v := range a.Meta {
-			fmt.Printf("%s- %s: %s\n", tab+"  ", k, strings.Join(v, ", "))
+			fmt.Printf("%s%s- %s: %s\n", tabs+tab, tab, k, strings.Join(v, ", "))
 		}
 	}
+	if v := a.Validation; v != nil {
+		v.Debug("", tabs+tab, tab)
+	}
 	if t, ok := a.Type.(UserType); ok {
 		if v := t.Attribute().Validation; v != nil {
-			v.Debug(indent + 1)
+			v.Debug("user type ", tabs+tab, tab)
+		}
+	}
+	if len(a.Bases) > 0 {
+		fmt.Printf("%s%sbases\n", tabs, tab)
+		for _, b := range a.Bases {
+			fmt.Printf("%s%s- %s\n", tabs+tab, tab, b.Name())
+		}
+	}
+	if len(a.References) > 0 {
+		fmt.Printf("%s%sreferences\n", tabs, tab)
+		for _, r := range a.References {
+			fmt.Printf("%s%s- %s\n", tabs+tab, tab, r.Name())
 		}
 	}
 }
@@ -778,38 +791,40 @@ func (v *ValidationExpr) Dup() *ValidationExpr {
 }
 
 // Debug dumps the validation to STDOUT in a goa developer friendly way.
-func (v *ValidationExpr) Debug(indent int) {
-	prefix := strings.Repeat("  ", indent+1)
-	fmt.Printf("%svalidations\n", strings.Repeat("  ", indent))
+func (v *ValidationExpr) Debug(title, prefix, indent string) {
+	if v.HasRequiredOnly() && len(v.Required) == 0 {
+		return
+	}
+	fmt.Printf("%s%svalidations\n", prefix, title)
 	if len(v.Values) > 0 {
-		fmt.Printf("%s- enum: %s\n", prefix, fmt.Sprintf("%v", v.Values))
+		fmt.Printf("%s%s- enum: %s\n", prefix, indent, fmt.Sprintf("%v", v.Values))
 	}
 	if v.Format != "" {
-		fmt.Printf("%s- format: %s\n", prefix, v.Format)
+		fmt.Printf("%s%s- format: %s\n", prefix, indent, v.Format)
 	}
 	if v.Pattern != "" {
-		fmt.Printf("%s- pattern: %s\n", prefix, v.Pattern)
+		fmt.Printf("%s%s- pattern: %s\n", prefix, indent, v.Pattern)
 	}
 	if v.ExclusiveMinimum != nil {
-		fmt.Printf("%s- exclMin: %v\n", prefix, *v.ExclusiveMinimum)
+		fmt.Printf("%s%s- exclMin: %v\n", prefix, indent, *v.ExclusiveMinimum)
 	}
 	if v.Minimum != nil {
-		fmt.Printf("%s- min: %v\n", prefix, *v.Minimum)
+		fmt.Printf("%s%s- min: %v\n", prefix, indent, *v.Minimum)
 	}
 	if v.ExclusiveMaximum != nil {
-		fmt.Printf("%s- exclMax: %v\n", prefix, *v.ExclusiveMaximum)
+		fmt.Printf("%s%s- exclMax: %v\n", prefix, indent, *v.ExclusiveMaximum)
 	}
 	if v.Maximum != nil {
-		fmt.Printf("%s- max: %v\n", prefix, *v.Maximum)
+		fmt.Printf("%s%s- max: %v\n", prefix, indent, *v.Maximum)
 	}
 	if v.MinLength != nil {
-		fmt.Printf("%s- minLength: %v\n", prefix, *v.MinLength)
+		fmt.Printf("%s%s- minLength: %v\n", prefix, indent, *v.MinLength)
 	}
 	if v.MaxLength != nil {
-		fmt.Printf("%s- maxLength: %v\n", prefix, *v.MaxLength)
+		fmt.Printf("%s%s- maxLength: %v\n", prefix, indent, *v.MaxLength)
 	}
 	if len(v.Required) > 0 {
-		fmt.Printf("%s- required: %v\n", prefix, v.Required)
+		fmt.Printf("%s%s- required: %v\n", prefix, indent, v.Required)
 	}
 }
 
diff --git a/go.mod b/go.mod
index 9ace9754..a33a7762 100644
--- a/go.mod
+++ b/go.mod
@@ -20,7 +20,7 @@ require (
 	golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
 	golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912 // indirect
 	golang.org/x/tools v0.1.5
-	google.golang.org/genproto v0.0.0-20210816143620-e15ff196659d // indirect
+	google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83 // indirect
 	google.golang.org/grpc v1.40.0
 	google.golang.org/protobuf v1.27.1
 	gopkg.in/yaml.v2 v2.4.0
diff --git a/go.sum b/go.sum
index bd9e10fb..d4465d90 100644
--- a/go.sum
+++ b/go.sum
@@ -395,8 +395,8 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20210816143620-e15ff196659d h1:fPtHPeysWvGVJwQFKu3B7H2DB2sOEsW7UTayKkWESKw=
-google.golang.org/genproto v0.0.0-20210816143620-e15ff196659d/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83 h1:3V2dxSZpz4zozWWUq36vUxXEKnSYitEH2LdsAx+RUmg=
+google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=


Test patch:
diff --git a/codegen/service/testdata/views_code.go b/codegen/service/testdata/views_code.go
index 95ba908d..0934c228 100644
--- a/codegen/service/testdata/views_code.go
+++ b/codegen/service/testdata/views_code.go
@@ -15,14 +15,14 @@ type ResultTypeView struct {
 }
 
 var (
-	// ResultTypeMap is a map of attribute names in result type ResultType indexed
-	// by view name.
+	// ResultTypeMap is a map indexing the attribute names of ResultType by view
+	// name.
 	ResultTypeMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 			"b",
 		},
-		"tiny": []string{
+		"tiny": {
 			"a",
 		},
 	}
@@ -83,25 +83,25 @@ type ResultTypeView struct {
 }
 
 var (
-	// ResultTypeCollectionMap is a map of attribute names in result type
-	// ResultTypeCollection indexed by view name.
+	// ResultTypeCollectionMap is a map indexing the attribute names of
+	// ResultTypeCollection by view name.
 	ResultTypeCollectionMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 			"b",
 		},
-		"tiny": []string{
+		"tiny": {
 			"a",
 		},
 	}
-	// ResultTypeMap is a map of attribute names in result type ResultType indexed
-	// by view name.
+	// ResultTypeMap is a map indexing the attribute names of ResultType by view
+	// name.
 	ResultTypeMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 			"b",
 		},
-		"tiny": []string{
+		"tiny": {
 			"a",
 		},
 	}
@@ -185,14 +185,14 @@ type UserTypeView struct {
 }
 
 var (
-	// ResultTypeMap is a map of attribute names in result type ResultType indexed
-	// by view name.
+	// ResultTypeMap is a map indexing the attribute names of ResultType by view
+	// name.
 	ResultTypeMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 			"b",
 		},
-		"tiny": []string{
+		"tiny": {
 			"a",
 		},
 	}
@@ -272,40 +272,40 @@ type RT3View struct {
 }
 
 var (
-	// RTMap is a map of attribute names in result type RT indexed by view name.
+	// RTMap is a map indexing the attribute names of RT by view name.
 	RTMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 			"b",
 			"c",
 		},
-		"tiny": []string{
+		"tiny": {
 			"b",
 			"c",
 		},
 	}
-	// RT2Map is a map of attribute names in result type RT2 indexed by view name.
+	// RT2Map is a map indexing the attribute names of RT2 by view name.
 	RT2Map = map[string][]string{
-		"default": []string{
+		"default": {
 			"c",
 			"d",
 		},
-		"extended": []string{
+		"extended": {
 			"c",
 			"d",
 			"e",
 		},
-		"tiny": []string{
+		"tiny": {
 			"d",
 		},
 	}
-	// RT3Map is a map of attribute names in result type RT3 indexed by view name.
+	// RT3Map is a map indexing the attribute names of RT3 by view name.
 	RT3Map = map[string][]string{
-		"default": []string{
+		"default": {
 			"x",
 			"y",
 		},
-		"tiny": []string{
+		"tiny": {
 			"x",
 		},
 	}
@@ -433,12 +433,12 @@ type RTView struct {
 }
 
 var (
-	// RTMap is a map of attribute names in result type RT indexed by view name.
+	// RTMap is a map indexing the attribute names of RT by view name.
 	RTMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 		},
-		"tiny": []string{
+		"tiny": {
 			"a",
 		},
 	}
@@ -501,13 +501,13 @@ type RTView struct {
 }
 
 var (
-	// RTMap is a map of attribute names in result type RT indexed by view name.
+	// RTMap is a map indexing the attribute names of RT by view name.
 	RTMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 			"b",
 		},
-		"tiny": []string{
+		"tiny": {
 			"a",
 		},
 	}
@@ -582,37 +582,36 @@ type AnotherResultView struct {
 type AnotherResultCollectionView []*AnotherResultView
 
 var (
-	// SomeRTMap is a map of attribute names in result type SomeRT indexed by view
-	// name.
+	// SomeRTMap is a map indexing the attribute names of SomeRT by view name.
 	SomeRTMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 		},
-		"tiny": []string{
+		"tiny": {
 			"a",
 		},
 	}
-	// AnotherResultMap is a map of attribute names in result type AnotherResult
-	// indexed by view name.
+	// AnotherResultMap is a map indexing the attribute names of AnotherResult by
+	// view name.
 	AnotherResultMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 		},
 	}
-	// SomeRTCollectionMap is a map of attribute names in result type
-	// SomeRTCollection indexed by view name.
+	// SomeRTCollectionMap is a map indexing the attribute names of
+	// SomeRTCollection by view name.
 	SomeRTCollectionMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 		},
-		"tiny": []string{
+		"tiny": {
 			"a",
 		},
 	}
-	// AnotherResultCollectionMap is a map of attribute names in result type
-	// AnotherResultCollection indexed by view name.
+	// AnotherResultCollectionMap is a map indexing the attribute names of
+	// AnotherResultCollection by view name.
 	AnotherResultCollectionMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 		},
 	}
@@ -727,9 +726,9 @@ type RTView struct {
 }
 
 var (
-	// RTMap is a map of attribute names in result type RT indexed by view name.
+	// RTMap is a map indexing the attribute names of RT by view name.
 	RTMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"a",
 		},
 	}
@@ -771,10 +770,9 @@ type ResultView struct {
 type UserTypeView string
 
 var (
-	// ResultMap is a map of attribute names in result type Result indexed by view
-	// name.
+	// ResultMap is a map indexing the attribute names of Result by view name.
 	ResultMap = map[string][]string{
-		"default": []string{
+		"default": {
 			"t",
 		},
 	}