From 9042ed078bb8ac2c60fbaec9bb4c4340ba597635 Mon Sep 17 00:00:00 2001 From: iyear Date: Fri, 21 Apr 2023 16:45:34 +0800 Subject: [PATCH] Fix: make any as top value in cue (#5893) * Fix: make any as top value in cue Signed-off-by: iyear * Feat: support different cue special type in type option Signed-off-by: iyear * Fix: unit test type option Signed-off-by: iyear --------- Signed-off-by: iyear --- references/cuegen/README.md | 3 +-- references/cuegen/convert.go | 13 +++++++--- references/cuegen/convert_test.go | 4 ++- references/cuegen/generator_test.go | 7 +++-- references/cuegen/option.go | 31 +++++++++++++++------- references/cuegen/option_test.go | 39 ++++++++++++++++++---------- references/cuegen/testdata/valid.cue | 8 ++---- references/cuegen/util.go | 4 --- references/cuegen/util_test.go | 4 --- 9 files changed, 68 insertions(+), 45 deletions(-) diff --git a/references/cuegen/README.md b/references/cuegen/README.md index 86ef8b2b8..2033afa86 100644 --- a/references/cuegen/README.md +++ b/references/cuegen/README.md @@ -28,8 +28,7 @@ Auto generation of CUE schema and docs from Go struct | `byte` | `uint8` | | `uintptr` | `uint64` | | `[]byte` | `bytes` | -| `interface{}/any` | `{...}` | -| `interface{ ... }` | `_` | +| `interface{}/any` | `_` | ### Map Type diff --git a/references/cuegen/convert.go b/references/cuegen/convert.go index 12f8d9d83..7033f3621 100644 --- a/references/cuegen/convert.go +++ b/references/cuegen/convert.go @@ -80,9 +80,16 @@ func (g *Generator) convertDecls(x *goast.GenDecl) (decls []cueast.Decl, _ error } func (g *Generator) convert(typ gotypes.Type) (cueast.Expr, error) { - // if type is registered as any, return {...} - if _, ok := g.opts.anyTypes[typ.String()]; ok { - return anyLit(), nil + // if type is registered as special type, use it directly + if t, ok := g.opts.types[typ.String()]; ok { + switch t { + case TypeAny: + return Ident("_", false), nil + case TypeEllipsis: + return &cueast.StructLit{Elts: []cueast.Decl{&cueast.Ellipsis{}}}, nil + default: + return nil, fmt.Errorf("unsupported special cue type %d", t) + } } switch t := typ.(type) { diff --git a/references/cuegen/convert_test.go b/references/cuegen/convert_test.go index e38e17b68..9a5721d4f 100644 --- a/references/cuegen/convert_test.go +++ b/references/cuegen/convert_test.go @@ -33,7 +33,9 @@ func TestConvert(t *testing.T) { got := &bytes.Buffer{} decls, err := g.Generate( - WithAnyTypes("*k8s.io/apimachinery/pkg/apis/meta/v1/unstructured.Unstructured"), + WithTypes(map[string]Type{ + "*k8s.io/apimachinery/pkg/apis/meta/v1/unstructured.Unstructured": TypeEllipsis, + }), WithTypeFilter(func(typ *goast.TypeSpec) bool { if typ.Name == nil { return true diff --git a/references/cuegen/generator_test.go b/references/cuegen/generator_test.go index 22c2f2b5b..573e36999 100644 --- a/references/cuegen/generator_test.go +++ b/references/cuegen/generator_test.go @@ -40,7 +40,7 @@ func TestNewGenerator(t *testing.T) { assert.NotNil(t, g.pkg) assert.NotNil(t, g.types) - assert.Equal(t, g.opts.anyTypes, newDefaultOptions().anyTypes) + assert.Equal(t, g.opts.types, newDefaultOptions().types) assert.Equal(t, g.opts.nullable, newDefaultOptions().nullable) // assert can't compare function assert.True(t, g.opts.typeFilter(nil)) @@ -57,7 +57,10 @@ func TestGeneratorPackage(t *testing.T) { func TestGeneratorGenerate(t *testing.T) { g := testGenerator(t) - decls, err := g.Generate(WithAnyTypes("foo", "bar"), nil) + decls, err := g.Generate(WithTypes(map[string]Type{ + "foo": TypeAny, + "bar": TypeAny, + }), nil) assert.NoError(t, err) assert.NotNil(t, decls) diff --git a/references/cuegen/option.go b/references/cuegen/option.go index e02ef7c43..fc0eb7731 100644 --- a/references/cuegen/option.go +++ b/references/cuegen/option.go @@ -18,8 +18,18 @@ package cuegen import goast "go/ast" +// Type is a special cue type +type Type int + +const ( + // TypeAny converts go type to _(top value) in cue + TypeAny Type = iota + // TypeEllipsis converts go type to {...} in cue + TypeEllipsis +) + type options struct { - anyTypes map[string]struct{} + types map[string]Type nullable bool typeFilter func(typ *goast.TypeSpec) bool } @@ -29,24 +39,25 @@ type Option func(opts *options) func newDefaultOptions() *options { return &options{ - anyTypes: map[string]struct{}{ - "map[string]interface{}": {}, "map[string]any": {}, - "interface{}": {}, "any": {}, + types: map[string]Type{ + "map[string]interface{}": TypeEllipsis, "map[string]any": TypeEllipsis, + "interface{}": TypeAny, "any": TypeAny, }, nullable: false, typeFilter: func(_ *goast.TypeSpec) bool { return true }, } } -// WithAnyTypes appends go types as any type({...}) in CUE +// WithTypes appends go types as specified cue types in generation // -// Example:*k8s.io/apimachinery/pkg/apis/meta/v1/unstructured.Unstructured +// Example:*k8s.io/apimachinery/pkg/apis/meta/v1/unstructured.Unstructured, TypeEllipsis // -// Default any types are: map[string]interface{}, map[string]any, interface{}, any -func WithAnyTypes(types ...string) Option { +// - Default any types: interface{}, any +// - Default ellipsis types: map[string]interface{}, map[string]any +func WithTypes(types map[string]Type) Option { return func(opts *options) { - for _, t := range types { - opts.anyTypes[t] = struct{}{} + for k, v := range types { + opts.types[k] = v } } } diff --git a/references/cuegen/option_test.go b/references/cuegen/option_test.go index 60c2a775b..19e2d9e38 100644 --- a/references/cuegen/option_test.go +++ b/references/cuegen/option_test.go @@ -27,32 +27,45 @@ func TestWithAnyTypes(t *testing.T) { tests := []struct { name string opts []Option - extra map[string]struct{} + extra map[string]Type }{ { name: "default", opts: nil, - extra: map[string]struct{}{}, + extra: map[string]Type{}, }, { - name: "single", - opts: []Option{WithAnyTypes("foo", "bar")}, - extra: map[string]struct{}{"foo": {}, "bar": {}}, + name: "single", + opts: []Option{WithTypes(map[string]Type{ + "foo": TypeAny, + "bar": TypeEllipsis, + })}, + extra: map[string]Type{"foo": TypeAny, "bar": TypeEllipsis}, }, { name: "multiple", - opts: []Option{WithAnyTypes("foo", "bar"), - WithAnyTypes("baz", "qux")}, - extra: map[string]struct{}{"foo": {}, "bar": {}, "baz": {}, "qux": {}}, + opts: []Option{WithTypes(map[string]Type{ + "foo": TypeAny, + "bar": TypeEllipsis, + }), WithTypes(map[string]Type{ + "baz": TypeEllipsis, + "qux": TypeAny, + })}, + extra: map[string]Type{ + "foo": TypeAny, + "bar": TypeEllipsis, + "baz": TypeEllipsis, + "qux": TypeAny, + }, }, } for _, tt := range tests { - opts := options{anyTypes: map[string]struct{}{}} + opts := options{types: map[string]Type{}} for _, opt := range tt.opts { opt(&opts) } - assert.Equal(t, opts.anyTypes, tt.extra, tt.name) + assert.Equal(t, opts.types, tt.extra, tt.name) } } @@ -127,9 +140,9 @@ func TestWithTypeFilter(t *testing.T) { func TestDefaultOptions(t *testing.T) { opts := newDefaultOptions() - assert.Equal(t, opts.anyTypes, map[string]struct{}{ - "map[string]interface{}": {}, "map[string]any": {}, - "interface{}": {}, "any": {}, + assert.Equal(t, opts.types, map[string]Type{ + "map[string]interface{}": TypeEllipsis, "map[string]any": TypeEllipsis, + "interface{}": TypeAny, "any": TypeAny, }) assert.Equal(t, opts.nullable, false) // assert can't compare function diff --git a/references/cuegen/testdata/valid.cue b/references/cuegen/testdata/valid.cue index c7d40872e..b04468d21 100644 --- a/references/cuegen/testdata/valid.cue +++ b/references/cuegen/testdata/valid.cue @@ -18,12 +18,8 @@ BasicType: { field15: uint64 field16: uint8 field17: rune - field18: { - ... - } - field19: { - ... - } + field18: _ + field19: _ } TagName: { f1: string diff --git a/references/cuegen/util.go b/references/cuegen/util.go index c1f7035d1..943b489d5 100644 --- a/references/cuegen/util.go +++ b/references/cuegen/util.go @@ -46,10 +46,6 @@ func basicType(x *gotypes.Basic) cueast.Expr { } } -func anyLit() cueast.Expr { - return &cueast.StructLit{Elts: []cueast.Decl{&cueast.Ellipsis{}}} -} - func basicLabel(t *gotypes.Basic, v string) (cueast.Expr, error) { switch { case t.Info()&gotypes.IsInteger != 0: diff --git a/references/cuegen/util_test.go b/references/cuegen/util_test.go index 4b7d3ed1f..283f9c9d4 100644 --- a/references/cuegen/util_test.go +++ b/references/cuegen/util_test.go @@ -73,10 +73,6 @@ func TestBasicType(t *testing.T) { } } -func TestAnyLit(t *testing.T) { - assert.Equal(t, anyLit(), &cueast.StructLit{Elts: []cueast.Decl{&cueast.Ellipsis{}}}) -} - func TestBasicLabel(t *testing.T) { overflowInt64 := strconv.FormatInt(math.MaxInt64, 10) + "0" overflowUint64 := strconv.FormatUint(math.MaxUint64, 10) + "0"