cue: deprecate Value.FieldByName
Can be replaced by LookupPath.
Also
- make Def behave like LookupDef
- update some other deprecation comments
- copy over tests
Change-Id: If7fa60fda28c9fea1b5328a41d79f52fafde394b
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9349
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
diff --git a/cue/path.go b/cue/path.go
index 4ffb2db..4f57056 100644
--- a/cue/path.go
+++ b/cue/path.go
@@ -334,7 +334,7 @@
// not prefixed with a #. It will panic if s cannot be written as a valid
// identifier.
func Def(s string) Selector {
- if !strings.HasPrefix(s, "#") {
+ if !strings.HasPrefix(s, "#") && !strings.HasPrefix(s, "_#") {
s = "#" + s
}
if !ast.IsValidIdent(s) {
diff --git a/cue/path_test.go b/cue/path_test.go
index b126438..334bb39 100644
--- a/cue/path_test.go
+++ b/cue/path_test.go
@@ -70,7 +70,7 @@
}, {
path: ParsePath("#Foo.a.c"),
str: "#Foo.a.c",
- out: `_|_ // value "c" not found`,
+ out: `_|_ // field "c" not found`,
}, {
path: ParsePath(`b[2]`),
str: `b[2]`,
diff --git a/cue/query.go b/cue/query.go
index 542a9af..41ee6b9 100644
--- a/cue/query.go
+++ b/cue/query.go
@@ -88,7 +88,7 @@
x = &adt.Bottom{Err: err.Error}
} else {
// TODO: better message.
- x = v.idx.mkErr(n, adt.NotExistError, "value %q not found", sel.sel)
+ x = v.idx.mkErr(n, adt.NotExistError, "field %q not found", sel.sel)
}
v := makeValue(v.idx, n)
return newErrValue(v, x)
diff --git a/cue/query_test.go b/cue/query_test.go
index 5301be2..5f147d6 100644
--- a/cue/query_test.go
+++ b/cue/query_test.go
@@ -26,18 +26,12 @@
r := &cue.Runtime{}
testCases := []struct {
- in string
- path cue.Path
- out string `test:"update"` // :nerdSnipe:
- notExist bool `test:"update"` // :nerdSnipe:
+ in string
+ path cue.Path
+ out string `test:"update"` // :nerdSnipe:
+ err string `test:"update"` // :nerdSnipe:
}{{
in: `
- [Name=string]: { a: Name }
- `,
- path: cue.MakePath(cue.Str("a")),
- notExist: true,
- }, {
- in: `
#V: {
x: int
}
@@ -49,6 +43,22 @@
path: cue.ParsePath("v.x"),
out: `int64`,
}, {
+ in: `#foo: 3`,
+ path: cue.ParsePath("#foo"),
+ out: `3`,
+ }, {
+ in: `_foo: 3`,
+ path: cue.MakePath(cue.Def("_foo")),
+ err: `field "#_foo" not found`,
+ }, {
+ in: `_#foo: 3`,
+ path: cue.MakePath(cue.Def("_#foo")),
+ err: `field "_#foo" not found`,
+ }, {
+ in: `"foo", #foo: 3`,
+ path: cue.ParsePath("#foo"),
+ out: `3`,
+ }, {
in: `
a: [...int]
`,
@@ -89,8 +99,8 @@
in: `
[Name=string]: { a: Name }
`,
- path: cue.MakePath(cue.Str("a")),
- notExist: true,
+ path: cue.MakePath(cue.Str("a")),
+ err: `field "a" not found`,
}}
for _, tc := range testCases {
t.Run(tc.path.String(), func(t *testing.T) {
@@ -98,8 +108,14 @@
v = v.LookupPath(tc.path)
- if exists := v.Exists(); exists != !tc.notExist {
- t.Fatalf("exists: got %v; want: %v", exists, !tc.notExist)
+ if err := v.Err(); err != nil || tc.err != "" {
+ if got := err.Error(); got != tc.err {
+ t.Errorf("error: got %v; want %v", got, tc.err)
+ }
+ }
+
+ if exists := v.Exists(); exists != (tc.err == "") {
+ t.Fatalf("exists: got %v; want: %v", exists, tc.err == "")
} else if !exists {
return
}
diff --git a/cue/types.go b/cue/types.go
index bfcc02c..2038a70 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -1362,6 +1362,7 @@
// Struct returns the underlying struct of a value or an error if the value
// is not a struct.
func (v Value) Struct() (*Struct, error) {
+ // TODO: deprecate
ctx := v.ctx()
obj, err := v.structValOpts(ctx, options{})
if err != nil {
@@ -1451,7 +1452,7 @@
}
// Lookup reports the value at a path starting from v. The empty path returns v
-// itself. Use LookupDef for definitions or LookupField for any kind of field.
+// itself.
//
// The Exists() method can be used to verify if the returned value existed.
// Lookup cannot be used to look up hidden or optional fields or definitions.
@@ -1499,35 +1500,11 @@
return Path{path: a}
}
-// LookupDef reports the definition with the given name within struct v. The
-// Exists method of the returned value will report false if the definition did
-// not exist. The Err method reports if any error occurred during evaluation.
+// LookupDef is equal to LookupPath(MakePath(Def(name))).
//
// Deprecated: use LookupPath.
func (v Value) LookupDef(name string) Value {
- ctx := v.ctx()
- o, err := v.structValFull(ctx)
- if err != nil {
- return newErrValue(v, err)
- }
-
- f := v.ctx().Label(name, true)
- for i, a := range o.features {
- if a == f {
- if f.IsHidden() || !f.IsDef() { // optional not possible for now
- break
- }
- return newChildValue(&o, i)
- }
- }
- if !strings.HasPrefix(name, "#") {
- alt := v.LookupDef("#" + name)
- // Use the original error message if this resulted in an error as well.
- if alt.Err() == nil {
- return alt
- }
- }
- return newErrValue(v, ctx.mkErr(v.v, "definition %q not found", name))
+ return v.LookupPath(MakePath(Def(name)))
}
var errNotFound = errors.Newf(token.NoPos, "field not found")
@@ -1535,6 +1512,8 @@
// FieldByName looks up a field for the given name. If isIdent is true, it will
// look up a definition or hidden field (starting with `_` or `_#`). Otherwise
// it interprets name as an arbitrary string for a regular field.
+//
+// Deprecated: use LookupPath.
func (v Value) FieldByName(name string, isIdent bool) (f FieldInfo, err error) {
s, err := v.Struct()
if err != nil {
@@ -1545,7 +1524,7 @@
// LookupField reports information about a field of v.
//
-// Deprecated: this API does not work with new-style definitions. Use FieldByName.
+// Deprecated: use LookupPath
func (v Value) LookupField(name string) (FieldInfo, error) {
s, err := v.Struct()
if err != nil {
diff --git a/cue/types_test.go b/cue/types_test.go
index 51d84a2..afb3848 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -1432,11 +1432,11 @@
}, {
in: `_foo: 3`,
def: "_foo",
- out: `_|_ // definition "_foo" not found`,
+ out: `_|_ // field "#_foo" not found`,
}, {
in: `_#foo: 3`,
def: "_#foo",
- out: `_|_ // definition "_#foo" not found`,
+ out: `_|_ // field "_#foo" not found`,
}, {
in: `"foo", #foo: 3`,
def: "#foo",