Fixing usage of quoted numeric keys #1247

This commit is contained in:
Mike Farah 2022-06-23 19:22:11 +10:00
parent c7c11ef68b
commit be05df03b5
4 changed files with 26 additions and 16 deletions

View File

@ -352,6 +352,13 @@ func parseInt(numberString string) (int, error) {
return int(parsed), err 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 { func createScalarNode(value interface{}, stringValue string) *yaml.Node {
var node = &yaml.Node{Kind: yaml.ScalarNode} var node = &yaml.Node{Kind: yaml.ScalarNode}
node.Value = stringValue node.Value = stringValue

View File

@ -72,20 +72,20 @@ func parseEntry(entry *yaml.Node, position int) (*yaml.Node, *yaml.Node, error)
prefs := traversePreferences{DontAutoCreate: true} prefs := traversePreferences{DontAutoCreate: true}
candidateNode := &CandidateNode{Node: entry} candidateNode := &CandidateNode{Node: entry}
keyResults, err := traverseMap(Context{}, candidateNode, "key", prefs, false) keyResults, err := traverseMap(Context{}, candidateNode, createStringScalarNode("key"), prefs, false)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} else if keyResults.Len() != 1 { } 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 { if err != nil {
return nil, nil, err return nil, nil, err
} else if valueResults.Len() != 1 { } 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 return keyResults.Front().Value.(*CandidateNode).Node, valueResults.Front().Value.(*CandidateNode).Node, nil

View File

@ -3,7 +3,6 @@ package yqlib
import ( import (
"container/list" "container/list"
"fmt" "fmt"
"strconv"
"github.com/elliotchance/orderedmap" "github.com/elliotchance/orderedmap"
yaml "gopkg.in/yaml.v3" yaml "gopkg.in/yaml.v3"
@ -57,7 +56,7 @@ func traverse(context Context, matchingNode *CandidateNode, operation *Operation
switch value.Kind { switch value.Kind {
case yaml.MappingNode: case yaml.MappingNode:
log.Debug("its a map with %v entries", len(value.Content)/2) 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: case yaml.SequenceNode:
log.Debug("its a sequence of %v things!", len(value.Content)) log.Debug("its a sequence of %v things!", len(value.Content))
@ -131,13 +130,10 @@ func traverseArrayIndices(context Context, matchingNode *CandidateNode, indicesT
node.Tag = "" node.Tag = ""
node.Kind = yaml.SequenceNode node.Kind = yaml.SequenceNode
//check that the indices are numeric, if not, then we should create an object //check that the indices are numeric, if not, then we should create an object
if len(indicesToTraverse) != 0 { if len(indicesToTraverse) != 0 && indicesToTraverse[0].Tag != "!!int" {
_, err := strconv.ParseInt(indicesToTraverse[0].Value, 10, 64)
if err != nil {
node.Kind = yaml.MappingNode node.Kind = yaml.MappingNode
} }
} }
}
if node.Kind == yaml.AliasNode { if node.Kind == yaml.AliasNode {
matchingNode.Node = node.Alias matchingNode.Node = node.Alias
@ -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) { func traverseMapWithIndices(context Context, candidate *CandidateNode, indices []*yaml.Node, prefs traversePreferences) (*list.List, error) {
if len(indices) == 0 { if len(indices) == 0 {
return traverseMap(context, candidate, "", prefs, true) return traverseMap(context, candidate, createStringScalarNode(""), prefs, true)
} }
var matchingNodeMap = list.New() var matchingNodeMap = list.New()
for _, indexNode := range indices { for _, indexNode := range indices {
log.Debug("traverseMapWithIndices: %v", indexNode.Value) 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 { if err != nil {
return nil, err return nil, err
} }
@ -224,9 +220,9 @@ func keyMatches(key *yaml.Node, wantedKey string) bool {
return matchKey(key.Value, wantedKey) 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() var newMatches = orderedmap.NewOrderedMap()
err := doTraverseMap(newMatches, matchingNode, key, prefs, splat) err := doTraverseMap(newMatches, matchingNode, keyNode.Value, prefs, splat)
if err != nil { if err != nil {
return nil, err return nil, err
@ -235,7 +231,7 @@ func traverseMap(context Context, matchingNode *CandidateNode, key string, prefs
if !prefs.DontAutoCreate && !context.DontAutoCreate && newMatches.Len() == 0 { if !prefs.DontAutoCreate && !context.DontAutoCreate && newMatches.Len() == 0 {
//no matches, create one automagically //no matches, create one automagically
valueNode := &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"} valueNode := &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"}
keyNode := &yaml.Node{Kind: yaml.ScalarNode, Value: key}
node := matchingNode.Node node := matchingNode.Node
if len(node.Content) == 0 { if len(node.Content) == 0 {

View File

@ -44,6 +44,13 @@ var traversePathOperatorScenarios = []expressionScenario{
"D0, P[0 0], (!!int)::1\n", "D0, P[0 0], (!!int)::1\n",
}, },
}, },
{
skipDoc: true,
expression: `.cat["12"] = "things"`,
expected: []string{
"D0, P[], ()::cat:\n \"12\": things\n",
},
},
{ {
skipDoc: true, skipDoc: true,
document: `blah: {}`, document: `blah: {}`,