diff --git a/pkg/yqlib/operator_traverse_path.go b/pkg/yqlib/operator_traverse_path.go index 903ae323..0d1db100 100644 --- a/pkg/yqlib/operator_traverse_path.go +++ b/pkg/yqlib/operator_traverse_path.go @@ -295,17 +295,26 @@ func doTraverseMap(newMatches *orderedmap.OrderedMap, node *CandidateNode, wante func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, value *CandidateNode, wantedKey string, prefs traversePreferences, splat bool) error { switch value.Kind { case AliasNode: - if value.Alias.Kind != MappingNode { - return fmt.Errorf("can only use merge anchors with maps (!!map), but got %v", value.Alias.Tag) - } - return doTraverseMap(newMatches, value.Alias, wantedKey, prefs, splat) + return traverseMergeAnchor(newMatches, value.Alias, wantedKey, prefs, splat) + case MappingNode: + return doTraverseMap(newMatches, value, wantedKey, prefs, splat) case SequenceNode: for _, childValue := range value.Content { - err := traverseMergeAnchor(newMatches, childValue, wantedKey, prefs, splat) + if childValue.Kind == AliasNode { + childValue = childValue.Alias + } + if childValue.Kind != MappingNode { + return fmt.Errorf( + "can only use merge anchors with maps (!!map) or sequences (!!seq) of maps, but got sequence containing %v", + childValue.Tag) + } + err := doTraverseMap(newMatches, childValue, wantedKey, prefs, splat) if err != nil { return err } } + default: + return fmt.Errorf("can only use merge anchors with maps (!!map) or sequences (!!seq) of maps, but got %v", value.Tag) } return nil } diff --git a/pkg/yqlib/operator_traverse_path_test.go b/pkg/yqlib/operator_traverse_path_test.go index a069e9f6..c81f797e 100644 --- a/pkg/yqlib/operator_traverse_path_test.go +++ b/pkg/yqlib/operator_traverse_path_test.go @@ -25,7 +25,7 @@ foobar: thing: foobar_thing ` -// cannot use merge anchors with arrays +// cannot use merge anchors with arrays of non-maps var badAliasSample = ` _common: &common-docker-file - FROM ubuntu:18.04 @@ -365,6 +365,22 @@ var traversePathOperatorScenarios = []expressionScenario{ "D0, P[0], (!!null)::null\n", }, }, + { + skipDoc: true, + document: `{<<: {a: 42}}`, + expression: `.a`, + expected: []string{ + "D0, P[<< a], (!!int)::42\n", + }, + }, + { + skipDoc: true, + document: `{<<: [{a: 42}]}`, + expression: `.a`, + expected: []string{ + "D0, P[<< 0 a], (!!int)::42\n", + }, + }, { skipDoc: true, document: mergeDocSample, @@ -553,9 +569,16 @@ var traversePathOperatorScenarios = []expressionScenario{ skipDoc: true, document: badAliasSample, expression: ".steps[]", - expectedError: "can only use merge anchors with maps (!!map), but got !!seq", + expectedError: "can only use merge anchors with maps (!!map) or sequences (!!seq) of maps, but got sequence containing !!str", skipForGoccy: true, // throws an error on parsing, that's fine }, + { + skipDoc: true, + document: `{<<: 42}`, + expression: ".[]", + expectedError: "can only use merge anchors with maps (!!map) or sequences (!!seq) of maps, but got !!int", + skipForGoccy: true, + }, } func TestTraversePathOperatorScenarios(t *testing.T) {