this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

internal/core/convert: split the cue tag commas after the last quote

This allows the package to support Go field tags such as:

Letters string `json:"letters,omitempty" cue:"=~\"^[a-z](,[a-z])*$\",opt"`

The previous code would split at the first comma, inside the regular
expression, which would break the CUE expression.

There are multiple ways to fix this problem, but since the trailing
options do not currently contain any quotes, it's easiest to only split
by commas after the last quote character, if there is any.

Fixes #1887.
Closes #2187 as merged.

Signed-off-by: Alexander Graf <ghostwheel42@users.noreply.github.com>
Co-authored-by: Daniel Martí <mvdan@mvdan.cc>
Change-Id: I4ca1b28aa942667bf1ee07e74ac4ad93de693562
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/552623
Reviewed-by: Marcel van Lohuizen <mpvl@gmail.com>
Unity-Result: CUEcueckoo <cueckoo@cuelang.org>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

authored by

Alexander Graf
Daniel Martí
and committed by
Daniel Martí
49a64f4c 9082446a

+27 -5
+13 -5
internal/core/convert/go.go
··· 78 78 79 79 // parseTag parses a CUE expression from a cue tag. 80 80 func parseTag(ctx *adt.OpContext, obj *ast.StructLit, field, tag string) ast.Expr { 81 - if p := strings.Index(tag, ","); p >= 0 { 82 - tag = tag[:p] 83 - } 81 + tag, _ = splitTag(tag) 84 82 if tag == "" { 85 83 return topSentinel 86 84 } ··· 94 92 return expr 95 93 } 96 94 95 + // splitTag splits a cue tag into cue and options. 96 + func splitTag(tag string) (cue string, options string) { 97 + q := strings.LastIndexByte(tag, '"') 98 + if c := strings.IndexByte(tag[q+1:], ','); c >= 0 { 99 + return tag[:q+1+c], tag[q+1+c+1:] 100 + } 101 + return tag, "" 102 + } 103 + 97 104 // TODO: should we allow mapping names in cue tags? This only seems like a good 98 105 // idea if we ever want to allow mapping CUE to a different name than JSON. 99 106 var tagsWithNames = []string{"json", "yaml", "protobuf"} ··· 105 112 } 106 113 for _, s := range tagsWithNames { 107 114 if tag, ok := f.Tag.Lookup(s); ok { 108 - if p := strings.Index(tag, ","); p >= 0 { 115 + if p := strings.IndexByte(tag, ','); p >= 0 { 109 116 tag = tag[:p] 110 117 } 111 118 if tag != "" { ··· 129 136 } 130 137 if tag, ok := f.Tag.Lookup("cue"); ok { 131 138 // TODO: only if first field is not empty. 139 + _, opt := splitTag(tag) 132 140 isOptional = false 133 - for _, f := range strings.Split(tag, ",")[1:] { 141 + for _, f := range strings.Split(opt, ",") { 134 142 switch f { 135 143 case "opt": 136 144 isOptional = true
+14
internal/core/convert/go_test.go
··· 369 369 }, { 370 370 time.Now, // a function 371 371 "_|_(unsupported Go type (func() time.Time))", 372 + }, { 373 + struct { 374 + Foobar string `cue:"\"foo,bar\",opt"` 375 + }{}, 376 + `{ 377 + Foobar?: (string & "foo,bar") 378 + }`, 379 + }, { 380 + struct { 381 + Foobar string `cue:"\"foo,opt,bar\""` 382 + }{}, 383 + `{ 384 + Foobar: (string & "foo,opt,bar") 385 + }`, 372 386 }} 373 387 374 388 r := runtime.New()