diff --git a/pkg/yqlib/context.go b/pkg/yqlib/context.go index 921eb7c2..e5d9fb83 100644 --- a/pkg/yqlib/context.go +++ b/pkg/yqlib/context.go @@ -60,3 +60,9 @@ func (n *Context) Clone() Context { } return clone } + +func (n *Context) ReadOnlyClone() Context { + clone := n.Clone() + clone.DontAutoCreate = true + return clone +} diff --git a/pkg/yqlib/operator_anchors_aliases.go b/pkg/yqlib/operator_anchors_aliases.go index 41e97126..c2f16b6f 100644 --- a/pkg/yqlib/operator_anchors_aliases.go +++ b/pkg/yqlib/operator_anchors_aliases.go @@ -12,7 +12,7 @@ func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode * aliasName := "" if !expressionNode.Operation.UpdateAssign { - rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs) + rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs) if err != nil { return Context{}, err } @@ -32,7 +32,7 @@ func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode * log.Debugf("Setting aliasName : %v", candidate.GetKey()) if expressionNode.Operation.UpdateAssign { - rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.Rhs) + rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs) if err != nil { return Context{}, err } @@ -41,8 +41,10 @@ func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode * } } - candidate.Node.Kind = yaml.AliasNode - candidate.Node.Value = aliasName + if aliasName != "" { + candidate.Node.Kind = yaml.AliasNode + candidate.Node.Value = aliasName + } } return context, nil } @@ -66,7 +68,7 @@ func assignAnchorOperator(d *dataTreeNavigator, context Context, expressionNode anchorName := "" if !expressionNode.Operation.UpdateAssign { - rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs) + rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs) if err != nil { return Context{}, err } @@ -87,7 +89,7 @@ func assignAnchorOperator(d *dataTreeNavigator, context Context, expressionNode log.Debugf("Setting anchorName of : %v", candidate.GetKey()) if expressionNode.Operation.UpdateAssign { - rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.Rhs) + rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs) if err != nil { return Context{}, err } diff --git a/pkg/yqlib/operator_anchors_aliases_test.go b/pkg/yqlib/operator_anchors_aliases_test.go index fb64f85f..bdb24ab2 100644 --- a/pkg/yqlib/operator_anchors_aliases_test.go +++ b/pkg/yqlib/operator_anchors_aliases_test.go @@ -58,6 +58,22 @@ var anchorOperatorScenarios = []expressionScenario{ "D0, P[], (doc)::a: &cat {b: cat}\n", }, }, + { + skipDoc: true, + document: `a: {c: cat}`, + expression: `.a anchor |= .b`, + expected: []string{ + "D0, P[], (doc)::a: {c: cat}\n", + }, + }, + { + skipDoc: true, + document: `a: {c: cat}`, + expression: `.a anchor = .b`, + expected: []string{ + "D0, P[], (doc)::a: {c: cat}\n", + }, + }, { description: "Get alias", document: `{b: &billyBob meow, a: *billyBob}`, @@ -74,6 +90,22 @@ var anchorOperatorScenarios = []expressionScenario{ "D0, P[], (doc)::{b: &meow purr, a: *meow}\n", }, }, + { + skipDoc: true, + document: `{b: &meow purr, a: cat}`, + expression: `.a alias = .c`, + expected: []string{ + "D0, P[], (doc)::{b: &meow purr, a: cat}\n", + }, + }, + { + skipDoc: true, + document: `{b: &meow purr, a: cat}`, + expression: `.a alias |= .c`, + expected: []string{ + "D0, P[], (doc)::{b: &meow purr, a: cat}\n", + }, + }, { description: "Set alias relatively using assign-update", document: `{b: &meow purr, a: {f: meow}}`, @@ -159,7 +191,7 @@ foobar: }, } -func TestAnchorAliaseOperatorScenarios(t *testing.T) { +func TestAnchorAliasOperatorScenarios(t *testing.T) { for _, tt := range anchorOperatorScenarios { testScenario(t, &tt) } diff --git a/pkg/yqlib/operator_booleans.go b/pkg/yqlib/operator_booleans.go index 5d4cf332..b8f37ac3 100644 --- a/pkg/yqlib/operator_booleans.go +++ b/pkg/yqlib/operator_booleans.go @@ -134,7 +134,7 @@ func anyOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi func orOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { log.Debugf("-- orOp") - return crossFunction(d, context, expressionNode, performBoolOp( + return crossFunction(d, context.ReadOnlyClone(), expressionNode, performBoolOp( func(b1 bool, b2 bool) bool { log.Debugf("-- peformingOrOp with %v and %v", b1, b2) return b1 || b2 @@ -143,7 +143,7 @@ func orOperator(d *dataTreeNavigator, context Context, expressionNode *Expressio func andOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { log.Debugf("-- AndOp") - return crossFunction(d, context, expressionNode, performBoolOp( + return crossFunction(d, context.ReadOnlyClone(), expressionNode, performBoolOp( func(b1 bool, b2 bool) bool { return b1 && b2 }), true) diff --git a/pkg/yqlib/operator_booleans_test.go b/pkg/yqlib/operator_booleans_test.go index ce6ef71f..d94eee5a 100644 --- a/pkg/yqlib/operator_booleans_test.go +++ b/pkg/yqlib/operator_booleans_test.go @@ -141,6 +141,22 @@ var booleanOperatorScenarios = []expressionScenario{ "D0, P[b], (!!bool)::true\n", }, }, + { + skipDoc: true, + document: `{}`, + expression: `(.a.b or .c) as $x`, + expected: []string{ + "D0, P[], (doc)::{}\n", + }, + }, + { + skipDoc: true, + document: `{}`, + expression: `(.a.b and .c) as $x`, + expected: []string{ + "D0, P[], (doc)::{}\n", + }, + }, { description: "Not true is false", expression: `true | not`, diff --git a/pkg/yqlib/operator_comments.go b/pkg/yqlib/operator_comments.go index 5eebf60c..6ece8f29 100644 --- a/pkg/yqlib/operator_comments.go +++ b/pkg/yqlib/operator_comments.go @@ -27,7 +27,7 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod comment := "" if !expressionNode.Operation.UpdateAssign { - rhs, err := d.GetMatchingNodes(context, expressionNode.Rhs) + rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs) if err != nil { return Context{}, err } @@ -41,7 +41,7 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod candidate := el.Value.(*CandidateNode) if expressionNode.Operation.UpdateAssign { - rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.Rhs) + rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.Rhs) if err != nil { return Context{}, err } diff --git a/pkg/yqlib/operator_comments_test.go b/pkg/yqlib/operator_comments_test.go index e137fe2b..d2798c00 100644 --- a/pkg/yqlib/operator_comments_test.go +++ b/pkg/yqlib/operator_comments_test.go @@ -62,6 +62,22 @@ var commentOperatorScenarios = []expressionScenario{ "D0, P[], (doc)::a: cat\n\n# cat\n", }, }, + { + skipDoc: true, + document: `a: cat`, + expression: `. footComment=.b.d`, + expected: []string{ + "D0, P[], (doc)::a: cat\n", + }, + }, + { + skipDoc: true, + document: `a: cat`, + expression: `. footComment|=.b.d`, + expected: []string{ + "D0, P[], (doc)::a: cat\n", + }, + }, { description: "Remove comment", document: "a: cat # comment\nb: dog # leave this", diff --git a/pkg/yqlib/operator_delete.go b/pkg/yqlib/operator_delete.go index cb6b94dd..8741a532 100644 --- a/pkg/yqlib/operator_delete.go +++ b/pkg/yqlib/operator_delete.go @@ -7,9 +7,7 @@ import ( ) func deleteChildOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { - contextToUse := context.Clone() - contextToUse.DontAutoCreate = true - nodesToDelete, err := d.GetMatchingNodes(contextToUse, expressionNode.Rhs) + nodesToDelete, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs) if err != nil { return Context{}, err diff --git a/pkg/yqlib/operator_has.go b/pkg/yqlib/operator_has.go index 474f1959..bce557a0 100644 --- a/pkg/yqlib/operator_has.go +++ b/pkg/yqlib/operator_has.go @@ -12,9 +12,7 @@ func hasOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi log.Debugf("-- hasOperation") var results = list.New() - readonlyContext := context.Clone() - readonlyContext.DontAutoCreate = true - rhs, err := d.GetMatchingNodes(readonlyContext, expressionNode.Rhs) + rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs) if err != nil { return Context{}, err diff --git a/pkg/yqlib/operator_strings.go b/pkg/yqlib/operator_strings.go index 18ef46a1..272c1224 100644 --- a/pkg/yqlib/operator_strings.go +++ b/pkg/yqlib/operator_strings.go @@ -13,9 +13,7 @@ func getSubstituteParameters(d *dataTreeNavigator, block *ExpressionNode, contex regEx := "" replacementText := "" - readonlyContext := context.Clone() - readonlyContext.DontAutoCreate = true - regExNodes, err := d.GetMatchingNodes(readonlyContext, block.Lhs) + regExNodes, err := d.GetMatchingNodes(context.ReadOnlyClone(), block.Lhs) if err != nil { return "", "", err } @@ -80,9 +78,7 @@ func joinStringOperator(d *dataTreeNavigator, context Context, expressionNode *E log.Debugf("-- joinStringOperator") joinStr := "" - readonlyContext := context.Clone() - readonlyContext.DontAutoCreate = true - rhs, err := d.GetMatchingNodes(readonlyContext, expressionNode.Rhs) + rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs) if err != nil { return Context{}, err } @@ -123,9 +119,7 @@ func splitStringOperator(d *dataTreeNavigator, context Context, expressionNode * log.Debugf("-- splitStringOperator") splitStr := "" - readonlyContext := context.Clone() - readonlyContext.DontAutoCreate = true - rhs, err := d.GetMatchingNodes(readonlyContext, expressionNode.Rhs) + rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs) if err != nil { return Context{}, err }