Skip to content

Commit

Permalink
Fixing usage of quoted numeric keys #1247
Browse files Browse the repository at this point in the history
  • Loading branch information
mikefarah committed Jun 23, 2022
1 parent c7c11ef commit be05df0
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 16 deletions.
7 changes: 7 additions & 0 deletions pkg/yqlib/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,13 @@ func parseInt(numberString string) (int, error) {
return int(parsed), err
}

func createStringScalarNode(stringValue string) *yaml.Node {
var node = &yaml.Node{Kind: yaml.ScalarNode}
node.Value = stringValue
node.Tag = "!!str"
return node
}

func createScalarNode(value interface{}, stringValue string) *yaml.Node {
var node = &yaml.Node{Kind: yaml.ScalarNode}
node.Value = stringValue
Expand Down
8 changes: 4 additions & 4 deletions pkg/yqlib/operator_entries.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,20 @@ func parseEntry(entry *yaml.Node, position int) (*yaml.Node, *yaml.Node, error)
prefs := traversePreferences{DontAutoCreate: true}
candidateNode := &CandidateNode{Node: entry}

keyResults, err := traverseMap(Context{}, candidateNode, "key", prefs, false)
keyResults, err := traverseMap(Context{}, candidateNode, createStringScalarNode("key"), prefs, false)

if err != nil {
return nil, nil, err
} else if keyResults.Len() != 1 {
return nil, nil, fmt.Errorf("Expected to find one 'key' entry but found %v in position %v", keyResults.Len(), position)
return nil, nil, fmt.Errorf("expected to find one 'key' entry but found %v in position %v", keyResults.Len(), position)
}

valueResults, err := traverseMap(Context{}, candidateNode, "value", prefs, false)
valueResults, err := traverseMap(Context{}, candidateNode, createStringScalarNode("value"), prefs, false)

if err != nil {
return nil, nil, err
} else if valueResults.Len() != 1 {
return nil, nil, fmt.Errorf("Expected to find one 'value' entry but found %v in position %v", valueResults.Len(), position)
return nil, nil, fmt.Errorf("expected to find one 'value' entry but found %v in position %v", valueResults.Len(), position)
}

return keyResults.Front().Value.(*CandidateNode).Node, valueResults.Front().Value.(*CandidateNode).Node, nil
Expand Down
20 changes: 8 additions & 12 deletions pkg/yqlib/operator_traverse_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package yqlib
import (
"container/list"
"fmt"
"strconv"

"github.com/elliotchance/orderedmap"
yaml "gopkg.in/yaml.v3"
Expand Down Expand Up @@ -57,7 +56,7 @@ func traverse(context Context, matchingNode *CandidateNode, operation *Operation
switch value.Kind {
case yaml.MappingNode:
log.Debug("its a map with %v entries", len(value.Content)/2)
return traverseMap(context, matchingNode, operation.StringValue, operation.Preferences.(traversePreferences), false)
return traverseMap(context, matchingNode, createStringScalarNode(operation.StringValue), operation.Preferences.(traversePreferences), false)

case yaml.SequenceNode:
log.Debug("its a sequence of %v things!", len(value.Content))
Expand Down Expand Up @@ -131,11 +130,8 @@ func traverseArrayIndices(context Context, matchingNode *CandidateNode, indicesT
node.Tag = ""
node.Kind = yaml.SequenceNode
//check that the indices are numeric, if not, then we should create an object
if len(indicesToTraverse) != 0 {
_, err := strconv.ParseInt(indicesToTraverse[0].Value, 10, 64)
if err != nil {
node.Kind = yaml.MappingNode
}
if len(indicesToTraverse) != 0 && indicesToTraverse[0].Tag != "!!int" {
node.Kind = yaml.MappingNode
}
}

Expand All @@ -155,14 +151,14 @@ func traverseArrayIndices(context Context, matchingNode *CandidateNode, indicesT

func traverseMapWithIndices(context Context, candidate *CandidateNode, indices []*yaml.Node, prefs traversePreferences) (*list.List, error) {
if len(indices) == 0 {
return traverseMap(context, candidate, "", prefs, true)
return traverseMap(context, candidate, createStringScalarNode(""), prefs, true)
}

var matchingNodeMap = list.New()

for _, indexNode := range indices {
log.Debug("traverseMapWithIndices: %v", indexNode.Value)
newNodes, err := traverseMap(context, candidate, indexNode.Value, prefs, false)
newNodes, err := traverseMap(context, candidate, indexNode, prefs, false)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -224,9 +220,9 @@ func keyMatches(key *yaml.Node, wantedKey string) bool {
return matchKey(key.Value, wantedKey)
}

func traverseMap(context Context, matchingNode *CandidateNode, key string, prefs traversePreferences, splat bool) (*list.List, error) {
func traverseMap(context Context, matchingNode *CandidateNode, keyNode *yaml.Node, prefs traversePreferences, splat bool) (*list.List, error) {
var newMatches = orderedmap.NewOrderedMap()
err := doTraverseMap(newMatches, matchingNode, key, prefs, splat)
err := doTraverseMap(newMatches, matchingNode, keyNode.Value, prefs, splat)

if err != nil {
return nil, err
Expand All @@ -235,7 +231,7 @@ func traverseMap(context Context, matchingNode *CandidateNode, key string, prefs
if !prefs.DontAutoCreate && !context.DontAutoCreate && newMatches.Len() == 0 {
//no matches, create one automagically
valueNode := &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"}
keyNode := &yaml.Node{Kind: yaml.ScalarNode, Value: key}

node := matchingNode.Node

if len(node.Content) == 0 {
Expand Down
7 changes: 7 additions & 0 deletions pkg/yqlib/operator_traverse_path_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ var traversePathOperatorScenarios = []expressionScenario{
"D0, P[0 0], (!!int)::1\n",
},
},
{
skipDoc: true,
expression: `.cat["12"] = "things"`,
expected: []string{
"D0, P[], ()::cat:\n \"12\": things\n",
},
},
{
skipDoc: true,
document: `blah: {}`,
Expand Down

0 comments on commit be05df0

Please sign in to comment.