mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
Length (and some other operators) should not include head/foot comments #1231
This commit is contained in:
parent
70403375d7
commit
8d3be1a23c
@ -1,2 +1,12 @@
|
|||||||
a: mike
|
# --------------------------------------------------
|
||||||
b: [t, f]
|
# It's a test with comment
|
||||||
|
# --------------------------------------------------
|
||||||
|
test:
|
||||||
|
- name: a
|
||||||
|
- name: b
|
||||||
|
- name: c
|
||||||
|
groups:
|
||||||
|
- name: a
|
||||||
|
- name: b
|
||||||
|
- name: c
|
||||||
|
- name: c
|
@ -1,2 +1,5 @@
|
|||||||
c:
|
# --------------------------------------------------
|
||||||
d: hamster
|
# It's a test with comment
|
||||||
|
# --------------------------------------------------
|
||||||
|
groups:
|
||||||
|
- name: d
|
@ -86,18 +86,24 @@ func (n *CandidateNode) CreateChildInArray(index int, node *yaml.Node) *Candidat
|
|||||||
|
|
||||||
func (n *CandidateNode) CreateReplacement(node *yaml.Node) *CandidateNode {
|
func (n *CandidateNode) CreateReplacement(node *yaml.Node) *CandidateNode {
|
||||||
return &CandidateNode{
|
return &CandidateNode{
|
||||||
Node: node,
|
Node: node,
|
||||||
Path: n.createChildPath(nil),
|
Path: n.createChildPath(nil),
|
||||||
LeadingContent: n.LeadingContent,
|
Parent: n.Parent,
|
||||||
Parent: n.Parent,
|
Key: n.Key,
|
||||||
Key: n.Key,
|
IsMapKey: n.IsMapKey,
|
||||||
IsMapKey: n.IsMapKey,
|
Document: n.Document,
|
||||||
Document: n.Document,
|
Filename: n.Filename,
|
||||||
Filename: n.Filename,
|
FileIndex: n.FileIndex,
|
||||||
FileIndex: n.FileIndex,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *CandidateNode) CreateReplacementWithDocWrappers(node *yaml.Node) *CandidateNode {
|
||||||
|
replacement := n.CreateReplacement(node)
|
||||||
|
replacement.LeadingContent = n.LeadingContent
|
||||||
|
replacement.TrailingContent = n.TrailingContent
|
||||||
|
return replacement
|
||||||
|
}
|
||||||
|
|
||||||
func (n *CandidateNode) createChildPath(path interface{}) []interface{} {
|
func (n *CandidateNode) createChildPath(path interface{}) []interface{} {
|
||||||
if path == nil {
|
if path == nil {
|
||||||
newPath := make([]interface{}, len(n.Path))
|
newPath := make([]interface{}, len(n.Path))
|
||||||
|
@ -29,14 +29,23 @@ var collectOperatorScenarios = []expressionScenario{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: "{a: apple}\n---\n{b: frog}",
|
document: "{a: apple}\n---\n{b: frog}",
|
||||||
|
|
||||||
expression: `[.]`,
|
expression: `[.]`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!seq)::- {a: apple}\n- {b: frog}\n",
|
"D0, P[], (!!seq)::- {a: apple}\n- {b: frog}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "with comments",
|
||||||
|
skipDoc: true,
|
||||||
|
document: "# abc\n[{a: apple}]\n\n# xyz\n",
|
||||||
|
|
||||||
|
expression: `[.[]]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::- {a: apple}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: ``,
|
document: ``,
|
||||||
|
@ -20,7 +20,7 @@ func entrySeqFor(key *yaml.Node, value *yaml.Node) *yaml.Node {
|
|||||||
|
|
||||||
func toEntriesFromMap(candidateNode *CandidateNode) *CandidateNode {
|
func toEntriesFromMap(candidateNode *CandidateNode) *CandidateNode {
|
||||||
var sequence = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
|
var sequence = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
|
||||||
var entriesNode = candidateNode.CreateReplacement(sequence)
|
var entriesNode = candidateNode.CreateReplacementWithDocWrappers(sequence)
|
||||||
|
|
||||||
var contents = unwrapDoc(candidateNode.Node).Content
|
var contents = unwrapDoc(candidateNode.Node).Content
|
||||||
for index := 0; index < len(contents); index = index + 2 {
|
for index := 0; index < len(contents); index = index + 2 {
|
||||||
@ -34,7 +34,7 @@ func toEntriesFromMap(candidateNode *CandidateNode) *CandidateNode {
|
|||||||
|
|
||||||
func toEntriesfromSeq(candidateNode *CandidateNode) *CandidateNode {
|
func toEntriesfromSeq(candidateNode *CandidateNode) *CandidateNode {
|
||||||
var sequence = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
|
var sequence = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
|
||||||
var entriesNode = candidateNode.CreateReplacement(sequence)
|
var entriesNode = candidateNode.CreateReplacementWithDocWrappers(sequence)
|
||||||
|
|
||||||
var contents = unwrapDoc(candidateNode.Node).Content
|
var contents = unwrapDoc(candidateNode.Node).Content
|
||||||
for index := 0; index < len(contents); index = index + 1 {
|
for index := 0; index < len(contents); index = index + 1 {
|
||||||
@ -94,7 +94,7 @@ func parseEntry(entry *yaml.Node, position int) (*yaml.Node, *yaml.Node, error)
|
|||||||
|
|
||||||
func fromEntries(candidateNode *CandidateNode) (*CandidateNode, error) {
|
func fromEntries(candidateNode *CandidateNode) (*CandidateNode, error) {
|
||||||
var node = &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
|
var node = &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
|
||||||
var mapCandidateNode = candidateNode.CreateReplacement(node)
|
var mapCandidateNode = candidateNode.CreateReplacementWithDocWrappers(node)
|
||||||
|
|
||||||
var contents = unwrapDoc(candidateNode.Node).Content
|
var contents = unwrapDoc(candidateNode.Node).Content
|
||||||
|
|
||||||
@ -141,9 +141,11 @@ func withEntriesOperator(d *dataTreeNavigator, context Context, expressionNode *
|
|||||||
var results = list.New()
|
var results = list.New()
|
||||||
|
|
||||||
for el := toEntries.MatchingNodes.Front(); el != nil; el = el.Next() {
|
for el := toEntries.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
|
||||||
//run expression against entries
|
//run expression against entries
|
||||||
// splat toEntries and pipe it into Rhs
|
// splat toEntries and pipe it into Rhs
|
||||||
splatted, err := splat(context.SingleChildContext(el.Value.(*CandidateNode)), traversePreferences{})
|
splatted, err := splat(context.SingleChildContext(candidate), traversePreferences{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Context{}, err
|
return Context{}, err
|
||||||
}
|
}
|
||||||
@ -160,6 +162,10 @@ func withEntriesOperator(d *dataTreeNavigator, context Context, expressionNode *
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return Context{}, err
|
return Context{}, err
|
||||||
}
|
}
|
||||||
|
collected.LeadingContent = candidate.LeadingContent
|
||||||
|
collected.TrailingContent = candidate.TrailingContent
|
||||||
|
|
||||||
|
log.Debugf("**** collected %v", collected.LeadingContent)
|
||||||
|
|
||||||
fromEntries, err := fromEntriesOperator(d, context.SingleChildContext(collected), expressionNode)
|
fromEntries, err := fromEntriesOperator(d, context.SingleChildContext(collected), expressionNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -62,6 +62,15 @@ var entriesOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!map)::KEY_c: 1\nKEY_d: 2\n",
|
"D0, P[], (!!map)::KEY_c: 1\nKEY_d: 2\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[{a: 1, b: 2}, {c: 1, d: 2}]`,
|
||||||
|
expression: `.[] | with_entries(.key |= "KEY_" + .)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::KEY_a: 1\nKEY_b: 2\n",
|
||||||
|
"D0, P[], (!!map)::KEY_c: 1\nKEY_d: 2\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Use with_entries to filter the map",
|
description: "Use with_entries to filter the map",
|
||||||
document: `{a: { b: bird }, c: { d: dog }}`,
|
document: `{a: { b: bird }, c: { d: dog }}`,
|
||||||
@ -70,6 +79,15 @@ var entriesOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!map)::a: {b: bird}\n",
|
"D0, P[], (!!map)::a: {b: bird}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Use with_entries to filter the map; head comment",
|
||||||
|
skipDoc: true,
|
||||||
|
document: "# abc\n{a: { b: bird }, c: { d: dog }}\n# xyz",
|
||||||
|
expression: `with_entries(select(.value | has("b")))`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::# abc\na: {b: bird}\n# xyz\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEntriesOperatorScenarios(t *testing.T) {
|
func TestEntriesOperatorScenarios(t *testing.T) {
|
||||||
|
@ -150,6 +150,16 @@ var envOperatorScenarios = []expressionScenario{
|
|||||||
expression: `"the ${notThere} ${alsoNotThere}" | envsubst(nu,ff)`,
|
expression: `"the ${notThere} ${alsoNotThere}" | envsubst(nu,ff)`,
|
||||||
expectedError: "variable ${notThere} not set",
|
expectedError: "variable ${notThere} not set",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "with header/footer",
|
||||||
|
skipDoc: true,
|
||||||
|
environmentVariables: map[string]string{"myenv": "cat meow"},
|
||||||
|
document: "# abc\n{v: \"${myenv}\"}\n# xyz\n",
|
||||||
|
expression: `(.. | select(tag == "!!str")) |= envsubst`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::# abc\n{v: \"cat meow\"}\n# xyz\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnvOperatorScenarios(t *testing.T) {
|
func TestEnvOperatorScenarios(t *testing.T) {
|
||||||
|
@ -32,7 +32,7 @@ var lengthOperatorScenarios = []expressionScenario{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `{a: key no exist}`,
|
document: "# abc\n{a: key no exist}",
|
||||||
expression: `.b | length`,
|
expression: `.b | length`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[b], (!!int)::0\n",
|
"D0, P[b], (!!int)::0\n",
|
||||||
|
@ -79,7 +79,7 @@ func pickOperator(d *dataTreeNavigator, context Context, expressionNode *Express
|
|||||||
return Context{}, fmt.Errorf("cannot pick indicies from type %v (%v)", node.Tag, candidate.GetNicePath())
|
return Context{}, fmt.Errorf("cannot pick indicies from type %v (%v)", node.Tag, candidate.GetNicePath())
|
||||||
}
|
}
|
||||||
|
|
||||||
results.PushBack(candidate.CreateReplacement(replacement))
|
results.PushBack(candidate.CreateReplacementWithDocWrappers(replacement))
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.ChildContext(results), nil
|
return context.ChildContext(results), nil
|
||||||
|
@ -14,6 +14,15 @@ var pickOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (doc)::myMap: {hamster: squeek, cat: meow}\n",
|
"D0, P[], (doc)::myMap: {hamster: squeek, cat: meow}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Pick keys from map with comments",
|
||||||
|
skipDoc: true,
|
||||||
|
document: "# abc\nmyMap: {cat: meow, dog: bark, thing: hamster, hamster: squeek}\n# xyz\n",
|
||||||
|
expression: `.myMap |= pick(["hamster", "cat", "goat"])`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::# abc\nmyMap: {hamster: squeek, cat: meow}\n# xyz\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Pick indices from array",
|
description: "Pick indices from array",
|
||||||
subdescription: "Note that the order of the indexes matches the pick order and non existent indexes are skipped.",
|
subdescription: "Note that the order of the indexes matches the pick order and non existent indexes are skipped.",
|
||||||
@ -23,6 +32,15 @@ var pickOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!seq)::[lion, cat]\n",
|
"D0, P[], (!!seq)::[lion, cat]\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Pick indices from array with comments",
|
||||||
|
skipDoc: true,
|
||||||
|
document: "# abc\n[cat, leopard, lion]\n# xyz",
|
||||||
|
expression: `pick([2, 0, 734, -5])`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::# abc\n[lion, cat]\n# xyz\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPickOperatorScenarios(t *testing.T) {
|
func TestPickOperatorScenarios(t *testing.T) {
|
||||||
|
@ -25,7 +25,7 @@ func reverseOperator(d *dataTreeNavigator, context Context, expressionNode *Expr
|
|||||||
for i, originalNode := range candidateNode.Content {
|
for i, originalNode := range candidateNode.Content {
|
||||||
reverseList.Content[len(candidateNode.Content)-i-1] = originalNode
|
reverseList.Content[len(candidateNode.Content)-i-1] = originalNode
|
||||||
}
|
}
|
||||||
results.PushBack(candidate.CreateReplacement(reverseList))
|
results.PushBack(candidate.CreateReplacementWithDocWrappers(reverseList))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,15 @@ var reverseOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!seq)::[{a: cat}, {a: banana}, {a: apple}]\n",
|
"D0, P[], (!!seq)::[{a: cat}, {a: banana}, {a: apple}]\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Sort descending by string field, with comments",
|
||||||
|
skipDoc: true,
|
||||||
|
document: "# abc\n[{a: banana},{a: cat},{a: apple}]\n# xyz",
|
||||||
|
expression: `sort_by(.a) | reverse`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::# abc\n[{a: cat}, {a: banana}, {a: apple}]\n# xyz\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReverseOperatorScenarios(t *testing.T) {
|
func TestReverseOperatorScenarios(t *testing.T) {
|
||||||
|
@ -64,7 +64,7 @@ func sortByOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
|
|||||||
for i, sortedNode := range sortableArray {
|
for i, sortedNode := range sortableArray {
|
||||||
sortedList.Content[i] = sortedNode.Node
|
sortedList.Content[i] = sortedNode.Node
|
||||||
}
|
}
|
||||||
results.PushBack(candidate.CreateReplacement(sortedList))
|
results.PushBack(candidate.CreateReplacementWithDocWrappers(sortedList))
|
||||||
}
|
}
|
||||||
return context.ChildContext(results), nil
|
return context.ChildContext(results), nil
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN
|
|||||||
resultNode.Content = append(resultNode.Content, el.Value.(*yaml.Node))
|
resultNode.Content = append(resultNode.Content, el.Value.(*yaml.Node))
|
||||||
}
|
}
|
||||||
|
|
||||||
results.PushBack(candidate.CreateReplacement(resultNode))
|
results.PushBack(candidate.CreateReplacementWithDocWrappers(resultNode))
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.ChildContext(results), nil
|
return context.ChildContext(results), nil
|
||||||
|
@ -56,6 +56,14 @@ var uniqueOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!seq)::- {name: harry, pet: cat}\n",
|
"D0, P[], (!!seq)::- {name: harry, pet: cat}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "# abc\n[{name: harry, pet: cat}, {pet: fish}, {name: harry, pet: dog}]\n# xyz",
|
||||||
|
expression: `unique_by(.name)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::# abc\n- {name: harry, pet: cat}\n- {pet: fish}\n# xyz\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUniqueOperatorScenarios(t *testing.T) {
|
func TestUniqueOperatorScenarios(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user