Skip to content
This repository has been archived by the owner on Mar 8, 2020. It is now read-only.

Commit

Permalink
transformer: add Drop operation to Fields (#369)
Browse files Browse the repository at this point in the history
* transformer: add Drop operation to Fields

Signed-off-by: Denys Smirnov <[email protected]>
  • Loading branch information
dennwc authored Feb 21, 2019
1 parent 55fd7b1 commit 5a1a268
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 11 deletions.
31 changes: 22 additions & 9 deletions uast/transformer/ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -746,11 +746,26 @@ func (op opScope) Construct(st *State, n nodes.Node) (nodes.Node, error) {
// Field is an operation on a specific field of an object.
type Field struct {
Name string // name of the field
// Optional can be set to make a field optional. Provided string is used as a variable name to the state of the field.
// Note that "optional" means that the field may not exists in the object, and it does not mean that the field can be nil.
// Optional can be set to make a field optional. Provided string is used as a variable
// name to the state of the field. Note that "optional" means that the field may not
// exists in the object, and it does not mean that the field can be nil.
// To handle nil fields, see Opt operation.
Optional string
Op Op // operation used to check/construct the field value
// Drop the field if it exists. Optional is implied, but the variable won't be created
// in this case. Op should be set and it will be called to check the value before
// dropping it. If the check fails, the whole transform will be canceled.
//
// Please note that you should avoid dropping fields with Any unless there is no
// reasonable alternative.
Drop bool
Op Op // operation used to check/construct the field value
}

// Desc returns a field descriptor.
func (f Field) Desc() FieldDesc {
d := FieldDesc{Optional: f.Optional != "" || f.Drop}
d.SetValue(f.Op)
return d
}

var _ ObjectOp = Fields{}
Expand All @@ -770,9 +785,7 @@ func (Fields) Kinds() nodes.Kind {
func (o Fields) Fields() (FieldDescs, bool) {
fields := make(FieldDescs, len(o))
for _, f := range o {
fld := FieldDesc{Optional: f.Optional != ""}
fld.SetValue(f.Op)
fields[f.Name] = fld
fields[f.Name] = f.Desc()
}
return fields, true
}
Expand Down Expand Up @@ -800,11 +813,11 @@ func (o Fields) CheckObj(st *State, n nodes.Object) (bool, error) {
if err := st.SetVar(f.Optional, nodes.Bool(ok)); err != nil {
return false, errKey.Wrap(err, f.Name)
}
if !ok {
continue
}
}
if !ok {
if f.Optional != "" || f.Drop {
continue
}
if errorOnFilterCheck {
return filtered("field %+v is missing in %+v\n%+v", f, n, o)
}
Expand Down
108 changes: 106 additions & 2 deletions uast/transformer/ops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ var opsCases = []struct {
err *errors.Kind
skip bool
noRev bool // should only be set in exceptional cases
expRev func() un.Node
}{
{
name: "is",
Expand Down Expand Up @@ -429,6 +430,105 @@ var opsCases = []struct {
{Name: "v", Op: Opt("exists", Var("val"))},
},
},
{
name: "drop field any",
inp: func() un.Node {
return un.Object{
"t": nil,
"v": nil,
}
},
src: Fields{
{Name: "t", Drop: true, Op: Any()},
{Name: "v", Op: Is(nil)},
},
dst: Obj{"v": Is(nil)},
exp: func() un.Node {
return un.Object{
"v": nil,
}
},
},
{
name: "drop field op",
inp: func() un.Node {
return un.Object{
"t": un.String("a"),
"v": nil,
}
},
src: Fields{
{Name: "t", Drop: true, Op: String("a")},
{Name: "v", Op: Is(nil)},
},
dst: Obj{"v": Is(nil)},
exp: func() un.Node {
return un.Object{
"v": nil,
}
},
},
{
name: "drop field op fail",
inp: func() un.Node {
return un.Object{
"t": un.String("a"),
"v": nil,
}
},
src: Fields{
{Name: "t", Drop: true, Op: String("b")},
{Name: "v", Op: Is(nil)},
},
},
{
name: "drop field missing any",
inp: func() un.Node {
return un.Object{
"v": nil,
}
},
expRev: func() un.Node {
return un.Object{
"t": nil,
"v": nil,
}
},
src: Fields{
{Name: "t", Drop: true, Op: Any()},
{Name: "v", Op: Is(nil)},
},
dst: Obj{"v": Is(nil)},
exp: func() un.Node {
return un.Object{
"v": nil,
}
},
},
{
name: "drop field missing op",
inp: func() un.Node {
return un.Object{
"v": nil,
}
},
expRev: func() un.Node {
return un.Object{
"t": un.String("a"),
"v": nil,
}
},
src: Fields{
{Name: "t", Drop: true, Op: String("a")},
{Name: "v", Op: Is(nil)},
},
dst: Obj{"v": Is(nil)},
exp: func() un.Node {
return un.Object{
"v": nil,
}
},
},
{
name: "roles field",
inp: func() un.Node {
Expand Down Expand Up @@ -851,11 +951,15 @@ func TestOps(t *testing.T) {
return
}
// test reverse transformation
do(Reverse(m), nil, c.exp, c.inp)
expRev := c.inp
if c.expRev != nil {
expRev = c.expRev
}
do(Reverse(m), nil, c.exp, expRev)

// test identity transform (forward)
m = Identity(c.src)
do(m, nil, c.inp, c.inp)
do(m, nil, c.inp, expRev)

// test identity transform (reverse)
m = Identity(c.dst)
Expand Down

0 comments on commit 5a1a268

Please sign in to comment.