Skip to content

Commit 67ea9cf

Browse files
uhthomasmvdan
authored andcommitted
cmd/cue: support optional comments in get go
The Kuberentes ecosystem use comments to denote whether a field is optional or required. The comment has a direct effect on the produced OpenAPI schema, and often means otherwise correct Go "schemas" will be represented incorrectly with CUE. https://github.com/kubernetes/community/blob/e977e6ea355f26130ca555d1e8704893727ee024/contributors/devel/sig-architecture/api-conventions.md#optional-vs-required In addition to the heuristics of the "omitempty" struct tag, the "// +optional" comment will now also mark a field as optional. The behaviour from the Kubernetes project which parses this comment as a key/value pair (tag) is also preserved. https://pkg.go.dev/k8s.io/gengo/types#ExtractCommentTags Fixes #2679 Change-Id: Ieeb2e7bee61e16ed9910ea46e68cb1a3eaa47197 Signed-off-by: Thomas Way <[email protected]> Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1171971 Reviewed-by: Daniel Martí <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent 112b0b2 commit 67ea9cf

File tree

2 files changed

+73
-6
lines changed

2 files changed

+73
-6
lines changed

cmd/cue/cmd/get_go.go

+17-6
Original file line numberDiff line numberDiff line change
@@ -1292,15 +1292,15 @@ func (e *extractor) addFields(x *types.Struct, st *cueast.StructLit) {
12921292
if name == "-" {
12931293
continue
12941294
}
1295+
1296+
doc := docs[i]
1297+
12951298
// TODO: check referrers
12961299
kind := regular
1297-
if e.isOptional(tag) {
1298-
kind = optional
1299-
}
1300-
if _, ok := f.Type().(*types.Pointer); ok {
1300+
if e.isOptional(f, doc, tag) {
13011301
kind = optional
13021302
}
1303-
field, cueType := e.makeField(name, kind, f.Type(), docs[i], count > 0)
1303+
field, cueType := e.makeField(name, kind, f.Type(), doc, count > 0)
13041304
add(field)
13051305

13061306
if s := reflect.StructTag(tag).Get("cue"); s != "" {
@@ -1395,7 +1395,18 @@ func (e *extractor) isInline(tag string) bool {
13951395
hasFlag(tag, "yaml", "inline", 1)
13961396
}
13971397

1398-
func (e *extractor) isOptional(tag string) bool {
1398+
func (e *extractor) isOptional(f *types.Var, doc *ast.CommentGroup, tag string) bool {
1399+
if _, ok := f.Type().(*types.Pointer); ok {
1400+
return true
1401+
}
1402+
1403+
for _, line := range strings.Split(doc.Text(), "\n") {
1404+
before, _, _ := strings.Cut(strings.TrimSpace(line), "=")
1405+
if before == "+optional" {
1406+
return true
1407+
}
1408+
}
1409+
13991410
// TODO: also when the type is a list or other kind of pointer.
14001411
return hasFlag(tag, "json", "omitempty", 1) ||
14011412
hasFlag(tag, "yaml", "omitempty", 1)

cmd/cue/cmd/testdata/script/get_go_types.txtar

+56
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,35 @@ type Foozer struct {
103103
Embed struct{ CustomJSON }
104104

105105
Unsupported map[int]string
106+
107+
OptionalOmitEmptyJSON string `json:"optionalOmitEmptyJSON,omitempty"`
108+
109+
OptionalOmitEmptyYAML string `yaml:"optionalOmitEmptyYAML,omitempty"`
110+
111+
// +optional
112+
OptionalComment string `json:"optionalComment"`
113+
114+
//+optional
115+
OptionalCommentNoSpace string `json:"optionalCommentNoSpace"`
116+
117+
// Something before
118+
//
119+
// +optional
120+
//
121+
// Something after
122+
OptionalCommentExtra string `json:"optionalCommentExtra"`
123+
124+
// +optional=
125+
OptionalCommentTag string `json:"optionalCommentTag"`
126+
127+
// +optional=some-value
128+
OptionalCommentTagValue string `json:"optionalCommentTagValue"`
129+
130+
// some-prefix+optional
131+
RequiredCommentPrefix string `json:"requiredCommentPrefix"`
132+
133+
// +optional-some-suffix
134+
RequiredCommentSuffix string `json:"requiredCommentSuffix"`
106135
}
107136

108137
type Identifier string
@@ -293,6 +322,33 @@ import (
293322
Embed: {
294323
CustomJSON: #CustomJSON
295324
} @go(,struct{CustomJSON})
325+
optionalOmitEmptyJSON?: string @go(OptionalOmitEmptyJSON)
326+
optionalOmitEmptyYAML?: string @go(OptionalOmitEmptyYAML)
327+
328+
// +optional
329+
optionalComment?: string @go(OptionalComment)
330+
331+
//+optional
332+
optionalCommentNoSpace?: string @go(OptionalCommentNoSpace)
333+
334+
// Something before
335+
//
336+
// +optional
337+
//
338+
// Something after
339+
optionalCommentExtra?: string @go(OptionalCommentExtra)
340+
341+
// +optional=
342+
optionalCommentTag?: string @go(OptionalCommentTag)
343+
344+
// +optional=some-value
345+
optionalCommentTagValue?: string @go(OptionalCommentTagValue)
346+
347+
// some-prefix+optional
348+
requiredCommentPrefix: string @go(RequiredCommentPrefix)
349+
350+
// +optional-some-suffix
351+
requiredCommentSuffix: string @go(RequiredCommentSuffix)
296352
}
297353

298354
#Identifier: string // #enumIdentifier

0 commit comments

Comments
 (0)