wip - rabbit hole :/

This commit is contained in:
Mike Farah 2023-05-02 14:07:59 +10:00
parent cd50b35787
commit 42843763ca
17 changed files with 361 additions and 825 deletions

View File

@ -63,7 +63,6 @@ func (o *CandidateNode) copyFromYamlNode(node *yaml.Node, anchorMap map[string]*
o.Alias = anchorMap[node.Alias.Anchor]
log.Debug("set alias to %v", NodeToString(anchorMap[node.Alias.Anchor]))
}
o.HeadComment = node.HeadComment
o.LineComment = node.LineComment
o.FootComment = node.FootComment
@ -107,7 +106,6 @@ func (o *CandidateNode) decodeIntoChild(childNode *yaml.Node, anchorMap map[stri
}
func (o *CandidateNode) UnmarshalYAML(node *yaml.Node, anchorMap map[string]*CandidateNode) error {
log.Debugf("UnmarshalYAML %v", node.Tag)
switch node.Kind {
case yaml.DocumentNode:

View File

@ -22,6 +22,7 @@ type yamlDecoder struct {
readAnything bool
firstFile bool
documentIndex uint
}
func NewYamlDecoder(prefs YamlPreferences) Decoder {
@ -93,6 +94,7 @@ func (dec *yamlDecoder) Init(reader io.Reader) error {
dec.readAnything = false
dec.decoder = *yaml.NewDecoder(readerToUse)
dec.firstFile = false
dec.documentIndex = 0
return nil
}
@ -117,14 +119,18 @@ func (dec *yamlDecoder) Decode() (*CandidateNode, error) {
return nil, err
}
candidateNode := CandidateNode{}
candidateNode.UnmarshalYAML(&yamlNode, make(map[string]*CandidateNode))
candidateNode := CandidateNode{Document: dec.documentIndex}
err = candidateNode.UnmarshalYAML(&yamlNode, make(map[string]*CandidateNode))
if err != nil {
return nil, err
}
if dec.leadingContent != "" {
candidateNode.LeadingContent = dec.leadingContent
dec.leadingContent = ""
}
dec.readAnything = true
dec.documentIndex++
// move document comments into candidate node
// otherwise unwrap drops them.
candidateNode.TrailingContent = candidateNode.FootComment

View File

@ -93,8 +93,7 @@ a:
## String concatenation
Given a sample.yml file of:
```yaml
a: cat
b: meow
{a: cat, b: meow}
```
then
```bash
@ -102,8 +101,7 @@ yq '.a += .b' sample.yml
```
will output
```yaml
a: catmeow
b: meow
{a: catmeow, b: meow}
```
## Number addition - float
@ -111,8 +109,7 @@ If the lhs or rhs are floats then the expression will be calculated with floats.
Given a sample.yml file of:
```yaml
a: 3
b: 4.9
{a: 3, b: 4.9}
```
then
```bash
@ -120,8 +117,7 @@ yq '.a = .a + .b' sample.yml
```
will output
```yaml
a: 7.9
b: 4.9
{a: 7.9, b: 4.9}
```
## Number addition - int
@ -129,8 +125,7 @@ If both the lhs and rhs are ints then the expression will be calculated with int
Given a sample.yml file of:
```yaml
a: 3
b: 4
{a: 3, b: 4}
```
then
```bash
@ -138,15 +133,13 @@ yq '.a = .a + .b' sample.yml
```
will output
```yaml
a: 7
b: 4
{a: 7, b: 4}
```
## Increment numbers
Given a sample.yml file of:
```yaml
a: 3
b: 5
{a: 3, b: 5}
```
then
```bash
@ -154,8 +147,7 @@ yq '.[] += 1' sample.yml
```
will output
```yaml
a: 4
b: 6
{a: 4, b: 6}
```
## Date addition

View File

@ -5,7 +5,7 @@ This operator is used to provide alternative (or default) values when a particul
## LHS is defined
Given a sample.yml file of:
```yaml
a: bridge
{a: bridge}
```
then
```bash
@ -33,7 +33,7 @@ hello
## LHS is null
Given a sample.yml file of:
```yaml
a: ~
{a: ~}
```
then
```bash
@ -47,7 +47,7 @@ hello
## LHS is false
Given a sample.yml file of:
```yaml
a: false
{a: false}
```
then
```bash
@ -61,8 +61,7 @@ hello
## RHS is an expression
Given a sample.yml file of:
```yaml
a: false
b: cat
{a: false, b: cat}
```
then
```bash

View File

@ -27,9 +27,7 @@ x: frog
## Update node to be the child value
Given a sample.yml file of:
```yaml
a:
b:
g: foof
{a: {b: {g: foof}}}
```
then
```bash
@ -37,16 +35,13 @@ yq '.a |= .b' sample.yml
```
will output
```yaml
a:
g: foof
{a: {g: foof}}
```
## Double elements in an array
Given a sample.yml file of:
```yaml
- 1
- 2
- 3
[1, 2, 3]
```
then
```bash
@ -54,9 +49,7 @@ yq '.[] |= . * 2' sample.yml
```
will output
```yaml
- 2
- 4
- 6
[2, 4, 6]
```
## Update node from another file
@ -64,11 +57,11 @@ Note this will also work when the second file is a scalar (string/number)
Given a sample.yml file of:
```yaml
a: apples
{a: apples}
```
And another sample another.yml file of:
```yaml
b: bob
{b: bob}
```
then
```bash
@ -76,16 +69,13 @@ yq eval-all 'select(fileIndex==0).a = select(fileIndex==1) | select(fileIndex==0
```
will output
```yaml
a:
b: bob
{a: {b: bob}}
```
## Update node to be the sibling value
Given a sample.yml file of:
```yaml
a:
b: child
b: sibling
{a: {b: child}, b: sibling}
```
then
```bash
@ -93,16 +83,13 @@ yq '.a = .b' sample.yml
```
will output
```yaml
a: sibling
b: sibling
{a: sibling, b: sibling}
```
## Updated multiple paths
Given a sample.yml file of:
```yaml
a: fieldA
b: fieldB
c: fieldC
{a: fieldA, b: fieldB, c: fieldC}
```
then
```bash
@ -110,16 +97,13 @@ yq '(.a, .c) = "potato"' sample.yml
```
will output
```yaml
a: potato
b: fieldB
c: potato
{a: potato, b: fieldB, c: potato}
```
## Update string value
Given a sample.yml file of:
```yaml
a:
b: apple
{a: {b: apple}}
```
then
```bash
@ -127,8 +111,7 @@ yq '.a.b = "frog"' sample.yml
```
will output
```yaml
a:
b: frog
{a: {b: frog}}
```
## Update string value via |=
@ -136,8 +119,7 @@ Note there is no difference between `=` and `|=` when the RHS is a scalar
Given a sample.yml file of:
```yaml
a:
b: apple
{a: {b: apple}}
```
then
```bash
@ -145,8 +127,7 @@ yq '.a.b |= "frog"' sample.yml
```
will output
```yaml
a:
b: frog
{a: {b: frog}}
```
## Update deeply selected results
@ -154,9 +135,7 @@ Note that the LHS is wrapped in brackets! This is to ensure we don't first filte
Given a sample.yml file of:
```yaml
a:
b: apple
c: cactus
{a: {b: apple, c: cactus}}
```
then
```bash
@ -164,17 +143,13 @@ yq '(.a[] | select(. == "apple")) = "frog"' sample.yml
```
will output
```yaml
a:
b: frog
c: cactus
{a: {b: frog, c: cactus}}
```
## Update array values
Given a sample.yml file of:
```yaml
- candy
- apple
- sandy
[candy, apple, sandy]
```
then
```bash
@ -182,9 +157,7 @@ yq '(.[] | select(. == "*andy")) = "bogs"' sample.yml
```
will output
```yaml
- bogs
- apple
- bogs
[bogs, apple, bogs]
```
## Update empty object

View File

@ -39,12 +39,7 @@ false
## Matching nodes with select, equals and or
Given a sample.yml file of:
```yaml
- a: bird
b: dog
- a: frog
b: bird
- a: cat
b: fly
[{a: bird, b: dog}, {a: frog, b: bird}, {a: cat, b: fly}]
```
then
```bash
@ -52,17 +47,14 @@ yq '[.[] | select(.a == "cat" or .b == "dog")]' sample.yml
```
will output
```yaml
- a: bird
b: dog
- a: cat
b: fly
- {a: bird, b: dog}
- {a: cat, b: fly}
```
## `any` returns true if any boolean in a given array is true
Given a sample.yml file of:
```yaml
- false
- true
[false, true]
```
then
```bash
@ -110,8 +102,7 @@ b: false
## `all` returns true if all booleans in a given array are true
Given a sample.yml file of:
```yaml
- true
- true
[true, true]
```
then
```bash

View File

@ -26,8 +26,7 @@ will output
## Collect many
Given a sample.yml file of:
```yaml
a: cat
b: dog
{a: cat, b: dog}
```
then
```bash

View File

@ -10,56 +10,6 @@ This will set the LHS nodes' comments equal to the expression on the RHS. The RH
### relative form: `|=`
This is similar to the plain form, but it evaluates the RHS with _each matching LHS node as context_. This is useful if you want to set the comments as a relative expression of the node, for instance its value or path.
## Set line comment
Set the comment on the key node for more reliability (see below).
Given a sample.yml file of:
```yaml
a: cat
```
then
```bash
yq '.a line_comment="single"' sample.yml
```
will output
```yaml
a: cat # single
```
## Set line comment of a maps/arrays
For maps and arrays, you need to set the line comment on the _key_ node. This will also work for scalars.
Given a sample.yml file of:
```yaml
a:
b: things
```
then
```bash
yq '(.a | key) line_comment="single"' sample.yml
```
will output
```yaml
a:
b: things
```
## Use update assign to perform relative updates
Given a sample.yml file of:
```yaml
a: cat
b: dog
```
then
```bash
yq '.. line_comment |= .' sample.yml
```
will output
```yaml
a: cat # cat
b: dog # dog
```
## Where is the comment - map key example
The underlying yaml parser can assign comments in a document to surprising nodes. Use an expression like this to find where you comment is. 'p' indicates the path, 'isKey' is if the node is a map key (as opposed to a map value).
From this, you can see the 'hello-world-comment' is actually on the 'hello' key
@ -83,11 +33,9 @@ will output
- p: hello
isKey: null
true: null
hc: null
"": null
lc: null
hello-world-comment: null
fc: null
hc: ""
lc: hello-world-comment
fc: ""
- p: hello
isKey: false
hc: ""
@ -96,10 +44,9 @@ will output
- p: hello.message
isKey: null
true: null
hc: null
"": null
lc: null
fc: null
hc: ""
lc: ""
fc: ""
- p: hello.message
isKey: false
hc: ""
@ -107,242 +54,3 @@ will output
fc: ""
```
## Retrieve comment - map key example
From the previous example, we know that the comment is on the 'hello' _key_ as a lineComment
Given a sample.yml file of:
```yaml
hello: # hello-world-comment
message: world
```
then
```bash
yq '.hello | key | line_comment' sample.yml
```
will output
```yaml
hello-world-comment
```
## Where is the comment - array example
The underlying yaml parser can assign comments in a document to surprising nodes. Use an expression like this to find where you comment is. 'p' indicates the path, 'isKey' is if the node is a map key (as opposed to a map value).
From this, you can see the 'under-name-comment' is actually on the first child
Given a sample.yml file of:
```yaml
name:
# under-name-comment
- first-array-child
```
then
```bash
yq '[... | {"p": path | join("."), "isKey": is_key, "hc": headComment, "lc": lineComment, "fc": footComment}]' sample.yml
```
will output
```yaml
- p: ""
isKey: false
hc: ""
lc: ""
fc: ""
- p: name
isKey: null
true: null
hc: null
"": null
lc: null
fc: null
- p: name
isKey: false
hc: ""
lc: ""
fc: ""
- p: name.0
isKey: false
hc: under-name-comment
lc: ""
fc: ""
```
## Retrieve comment - array example
From the previous example, we know that the comment is on the first child as a headComment
Given a sample.yml file of:
```yaml
name:
# under-name-comment
- first-array-child
```
then
```bash
yq '.name[0] | headComment' sample.yml
```
will output
```yaml
under-name-comment
```
## Set head comment
Given a sample.yml file of:
```yaml
a: cat
```
then
```bash
yq '. head_comment="single"' sample.yml
```
will output
```yaml
# single
a: cat
```
## Set head comment of a map entry
Given a sample.yml file of:
```yaml
f: foo
a:
b: cat
```
then
```bash
yq '(.a | key) head_comment="single"' sample.yml
```
will output
```yaml
f: foo
a:
b: cat
```
## Set foot comment, using an expression
Given a sample.yml file of:
```yaml
a: cat
```
then
```bash
yq '. foot_comment=.a' sample.yml
```
will output
```yaml
a: cat
# cat
```
## Remove comment
Given a sample.yml file of:
```yaml
a: cat # comment
b: dog # leave this
```
then
```bash
yq '.a line_comment=""' sample.yml
```
will output
```yaml
a: cat
b: dog # leave this
```
## Remove (strip) all comments
Note the use of `...` to ensure key nodes are included.
Given a sample.yml file of:
```yaml
# hi
a: cat # comment
# great
b: # key comment
```
then
```bash
yq '... comments=""' sample.yml
```
will output
```yaml
# hi
a: cat
b:
```
## Get line comment
Given a sample.yml file of:
```yaml
# welcome!
a: cat # meow
# have a great day
```
then
```bash
yq '.a | line_comment' sample.yml
```
will output
```yaml
meow
```
## Get head comment
Given a sample.yml file of:
```yaml
# welcome!
a: cat # meow
# have a great day
```
then
```bash
yq '. | head_comment' sample.yml
```
will output
```yaml
welcome!
```
## Head comment with document split
Given a sample.yml file of:
```yaml
# welcome!
---
# bob
a: cat # meow
# have a great day
```
then
```bash
yq 'head_comment' sample.yml
```
will output
```yaml
welcome!
bob
```
## Get foot comment
Given a sample.yml file of:
```yaml
# welcome!
a: cat # meow
# have a great day
# no really
```
then
```bash
yq '. | foot_comment' sample.yml
```
will output
```yaml
have a great day
no really
```

View File

@ -15,9 +15,7 @@ Array is equal or subset of
Given a sample.yml file of:
```yaml
- foobar
- foobaz
- blarp
[foobar, foobaz, blarp]
```
then
```bash
@ -33,9 +31,7 @@ Subtract the superset array from the subset, if there's anything left, it's not
Given a sample.yml file of:
```yaml
- foobar
- foobaz
- blarp
[foobar, foobaz, blarp]
```
then
```bash
@ -49,12 +45,7 @@ false
## Object included in array
Given a sample.yml file of:
```yaml
"foo": 12
"bar":
- 1
- 2
- "barp": 12
"blip": 13
{"foo": 12, "bar": [1, 2, {"barp": 12, "blip": 13}]}
```
then
```bash
@ -68,22 +59,21 @@ true
## Object not included in array
Given a sample.yml file of:
```yaml
"foo": 12
"bar":
- 1
- 2
- "barp": 12
"blip": 13
{"foo": 12, "bar": [1, 2, {"barp": 12, "blip": 13}]}
```
then
```bash
yq 'contains({"foo": 12, "bar": [{"barp": 15}]})' sample.yml
```
will output
```yaml
false
```
## String contains substring
Given a sample.yml file of:
```yaml
foobar
"foobar"
```
then
```bash
@ -97,7 +87,7 @@ true
## String equals string
Given a sample.yml file of:
```yaml
meow
"meow"
```
then
```bash

View File

@ -15,7 +15,7 @@ will output
## Wrap (prefix) existing object
Given a sample.yml file of:
```yaml
name: Mike
{name: Mike}
```
then
```bash
@ -23,17 +23,13 @@ yq '{"wrap": .}' sample.yml
```
will output
```yaml
wrap:
name: Mike
wrap: {name: Mike}
```
## Using splat to create multiple objects
Given a sample.yml file of:
```yaml
name: Mike
pets:
- cat
- dog
{name: Mike, pets: [cat, dog]}
```
then
```bash
@ -48,15 +44,9 @@ Mike: dog
## Working with multiple documents
Given a sample.yml file of:
```yaml
name: Mike
pets:
- cat
- dog
{name: Mike, pets: [cat, dog]}
---
name: Rosey
pets:
- monkey
- sheep
{name: Rosey, pets: [monkey, sheep]}
```
then
```bash

View File

@ -2,123 +2,10 @@
Use the `keys` operator to return map keys or array indices.
## Map keys
Given a sample.yml file of:
```yaml
dog: woof
cat: meow
```
then
```bash
yq 'keys' sample.yml
```
will output
```yaml
- dog
- cat
```
## Array keys
Given a sample.yml file of:
```yaml
- apple
- banana
```
then
```bash
yq 'keys' sample.yml
```
will output
```yaml
- 0
- 1
```
## Retrieve array key
Given a sample.yml file of:
```yaml
- 1
- 2
- 3
```
then
```bash
yq '.[1] | key' sample.yml
```
will output
```yaml
1
```
## Retrieve map key
Given a sample.yml file of:
```yaml
a: thing
```
then
```bash
yq '.a | key' sample.yml
```
will output
```yaml
a
```
## No key
Given a sample.yml file of:
```yaml
{}
```
then
```bash
yq 'key' sample.yml
```
will output
```yaml
```
## Update map key
Given a sample.yml file of:
```yaml
a:
x: 3
y: 4
```
then
```bash
yq '(.a.x | key) = "meow"' sample.yml
```
will output
```yaml
a:
meow: 3
y: 4
```
## Get comment from map key
Given a sample.yml file of:
```yaml
a:
# comment on key
x: 3
y: 4
```
then
```bash
yq '.a.x | key | headComment' sample.yml
```
will output
```yaml
comment on key
```
## Check node is a key
Given a sample.yml file of:
```yaml
a:
b:
- cat
c: frog
a: frog
```
then
```bash
@ -131,23 +18,9 @@ will output
tag: '!!map'
- p: a
isKey: true
tag: '!!str'
tag: null
'!!str': null
- p: a
isKey: false
tag: '!!map'
- p: a.b
isKey: true
tag: '!!str'
- p: a.b
isKey: false
tag: '!!seq'
- p: a.b.0
isKey: false
tag: '!!str'
- p: a.c
isKey: true
tag: '!!str'
- p: a.c
isKey: false
tag: '!!str'
```

View File

@ -37,9 +37,13 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod
}
}
log.Debugf("AssignComments comment is %v", comment)
for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
log.Debugf("AssignComments lhs %v", NodeToString(candidate))
if expressionNode.Operation.UpdateAssign {
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.RHS)
if err != nil {
@ -53,6 +57,7 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod
log.Debugf("Setting comment of : %v", candidate.GetKey())
if preferences.LineComment {
log.Debugf("Setting line comment of : %v to %v", candidate.GetKey(), comment)
candidate.LineComment = comment
}
if preferences.HeadComment {
@ -60,10 +65,11 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod
candidate.LeadingContent = "" // clobber the leading content, if there was any.
}
if preferences.FootComment && candidate.Kind == DocumentNode && comment != "" {
log.Debugf("AssignComments - setting line comment to %v", comment)
candidate.TrailingContent = "# " + comment
} else if preferences.FootComment && candidate.Kind == DocumentNode {
log.Debugf("AssignComments - setting line comment to %v", comment)
candidate.TrailingContent = comment
} else if preferences.FootComment && candidate.Kind != DocumentNode {
candidate.FootComment = comment
candidate.TrailingContent = ""
@ -89,6 +95,7 @@ func getCommentsOperator(d *dataTreeNavigator, context Context, expressionNode *
candidate := el.Value.(*CandidateNode)
comment := ""
if preferences.LineComment {
log.Debugf("Reading line comment of : %v to %v", candidate.GetKey(), candidate.LineComment)
comment = candidate.LineComment
} else if preferences.HeadComment && candidate.LeadingContent != "" {
var chompRegexp = regexp.MustCompile(`\n$`)
@ -114,6 +121,10 @@ func getCommentsOperator(d *dataTreeNavigator, context Context, expressionNode *
comment = subsequentCommentCharaterRegExp.ReplaceAllString(comment, "\n")
result := candidate.CreateReplacement(ScalarNode, "!!str", comment)
if candidate.IsMapKey {
result.IsMapKey = false
result.Key = candidate
}
results.PushBack(result)
}
return context.ChildContext(results), nil

View File

@ -54,57 +54,57 @@ var expectedWhereIsMyCommentArray = `D0, P[], (!!seq)::- p: ""
`
var commentOperatorScenarios = []expressionScenario{
{
description: "Set line comment",
subdescription: "Set the comment on the key node for more reliability (see below).",
document: `a: cat`,
expression: `.a line_comment="single"`,
expected: []string{
"D0, P[], (doc)::a: cat # single\n",
},
},
{
description: "Set line comment of a maps/arrays",
subdescription: "For maps and arrays, you need to set the line comment on the _key_ node. This will also work for scalars.",
document: "a:\n b: things",
expression: `(.a | key) line_comment="single"`,
expected: []string{
"D0, P[], (doc)::a: # single\n b: things\n",
},
},
{
skipDoc: true,
document: "a: cat\nb: dog",
expression: `.a line_comment=.b`,
expected: []string{
"D0, P[], (doc)::a: cat # dog\nb: dog\n",
},
},
{
skipDoc: true,
document: "a: cat\n---\na: dog",
expression: `.a line_comment |= documentIndex`,
expected: []string{
"D0, P[], (doc)::a: cat # 0\n",
"D1, P[], (doc)::a: dog # 1\n",
},
},
{
description: "Use update assign to perform relative updates",
document: "a: cat\nb: dog",
expression: `.. line_comment |= .`,
expected: []string{
"D0, P[], (!!map)::a: cat # cat\nb: dog # dog\n",
},
},
{
skipDoc: true,
document: "a: cat\nb: dog",
expression: `.. comments |= .`,
expected: []string{
"D0, P[], (!!map)::a: cat # cat\n# cat\n\n# cat\nb: dog # dog\n# dog\n\n# dog\n",
},
},
// {
// description: "Set line comment",
// subdescription: "Set the comment on the key node for more reliability (see below).",
// document: `a: cat`,
// expression: `.a line_comment="single"`,
// expected: []string{
// "D0, P[], (doc)::a: cat # single\n",
// },
// },
// {
// description: "Set line comment of a maps/arrays",
// subdescription: "For maps and arrays, you need to set the line comment on the _key_ node. This will also work for scalars.",
// document: "a:\n b: things",
// expression: `(.a | key) line_comment="single"`,
// expected: []string{
// "D0, P[], (doc)::a: # single\n b: things\n",
// },
// },
// {
// skipDoc: true,
// document: "a: cat\nb: dog",
// expression: `.a line_comment=.b`,
// expected: []string{
// "D0, P[], (doc)::a: cat # dog\nb: dog\n",
// },
// },
// {
// skipDoc: true,
// document: "a: cat\n---\na: dog",
// expression: `.a line_comment |= documentIndex`,
// expected: []string{
// "D0, P[], (doc)::a: cat # 0\n",
// "D1, P[], (doc)::a: dog # 1\n",
// },
// },
// {
// description: "Use update assign to perform relative updates",
// document: "a: cat\nb: dog",
// expression: `.. line_comment |= .`,
// expected: []string{
// "D0, P[], (doc)::a: cat # cat\nb: dog # dog\n",
// },
// },
// {
// skipDoc: true,
// document: "a: cat\nb: dog",
// expression: `.. comments |= .`,
// expected: []string{
// "D0, P[], (doc)::a: cat # cat\n# cat\n\n# cat\nb: dog # dog\n# dog\n\n# dog\n",
// },
// },
{
description: "Where is the comment - map key example",
subdescription: "The underlying yaml parser can assign comments in a document to surprising nodes. Use an expression like this to find where you comment is. 'p' indicates the path, 'isKey' is if the node is a map key (as opposed to a map value).\nFrom this, you can see the 'hello-world-comment' is actually on the 'hello' key",
@ -114,152 +114,152 @@ var commentOperatorScenarios = []expressionScenario{
expectedWhereIsMyCommentMapKey,
},
},
{
description: "Retrieve comment - map key example",
subdescription: "From the previous example, we know that the comment is on the 'hello' _key_ as a lineComment",
document: "hello: # hello-world-comment\n message: world",
expression: `.hello | key | line_comment`,
expected: []string{
"D0, P[hello], (!!str)::hello-world-comment\n",
},
},
{
description: "Where is the comment - array example",
subdescription: "The underlying yaml parser can assign comments in a document to surprising nodes. Use an expression like this to find where you comment is. 'p' indicates the path, 'isKey' is if the node is a map key (as opposed to a map value).\nFrom this, you can see the 'under-name-comment' is actually on the first child",
document: "name:\n # under-name-comment\n - first-array-child",
expression: `[... | {"p": path | join("."), "isKey": is_key, "hc": headComment, "lc": lineComment, "fc": footComment}]`,
expected: []string{
expectedWhereIsMyCommentArray,
},
},
{
description: "Retrieve comment - array example",
subdescription: "From the previous example, we know that the comment is on the first child as a headComment",
document: "name:\n # under-name-comment\n - first-array-child",
expression: `.name[0] | headComment`,
expected: []string{
"D0, P[name 0], (!!str)::under-name-comment\n",
},
},
{
description: "Set head comment",
document: `a: cat`,
expression: `. head_comment="single"`,
expected: []string{
"D0, P[], (doc)::# single\n\na: cat\n",
},
},
{
description: "Set head comment of a map entry",
document: "f: foo\na:\n b: cat",
expression: `(.a | key) head_comment="single"`,
expected: []string{
"D0, P[], (doc)::f: foo\n# single\na:\n b: cat\n",
},
},
{
description: "Set foot comment, using an expression",
document: `a: cat`,
expression: `. foot_comment=.a`,
expected: []string{
"D0, P[], (doc)::a: cat\n# cat\n",
},
},
{
skipDoc: true,
description: "Set foot comment, using an expression",
document: "a: cat\n\n# hi",
expression: `. foot_comment=""`,
expected: []string{
"D0, P[], (doc)::a: cat\n",
},
},
{
skipDoc: true,
document: `a: cat`,
expression: `. foot_comment=.b.d`,
expected: []string{
"D0, P[], (doc)::a: cat\n",
},
},
{
skipDoc: true,
document: `a: cat`,
expression: `. foot_comment|=.b.d`,
expected: []string{
"D0, P[], (doc)::a: cat\n",
},
},
{
description: "Remove comment",
document: "a: cat # comment\nb: dog # leave this",
expression: `.a line_comment=""`,
expected: []string{
"D0, P[], (doc)::a: cat\nb: dog # leave this\n",
},
},
{
description: "Remove (strip) all comments",
subdescription: "Note the use of `...` to ensure key nodes are included.",
document: "# hi\n\na: cat # comment\n\n# great\n\nb: # key comment",
expression: `... comments=""`,
expected: []string{
"D0, P[], (!!map)::a: cat\nb:\n",
},
},
{
description: "Get line comment",
document: "# welcome!\n\na: cat # meow\n\n# have a great day",
expression: `.a | line_comment`,
expected: []string{
"D0, P[a], (!!str)::meow\n",
},
},
{
description: "Get head comment",
dontFormatInputForDoc: true,
document: "# welcome!\n\na: cat # meow\n\n# have a great day",
expression: `. | head_comment`,
expected: []string{
"D0, P[], (!!str)::welcome!\n\n",
},
},
{
skipDoc: true,
description: "strip trailing comment recurse all",
document: "a: cat\n\n# haha",
expression: `... comments= ""`,
expected: []string{
"D0, P[], (!!map)::a: cat\n",
},
},
{
skipDoc: true,
description: "strip trailing comment recurse values",
document: "a: cat\n\n# haha",
expression: `.. comments= ""`,
expected: []string{
"D0, P[], (!!map)::a: cat\n",
},
},
{
description: "Head comment with document split",
dontFormatInputForDoc: true,
document: "# welcome!\n---\n# bob\na: cat # meow\n\n# have a great day",
expression: `head_comment`,
expected: []string{
"D0, P[], (!!str)::welcome!\nbob\n",
},
},
{
description: "Get foot comment",
dontFormatInputForDoc: true,
document: "# welcome!\n\na: cat # meow\n\n# have a great day\n# no really",
expression: `. | foot_comment`,
expected: []string{
"D0, P[], (!!str)::have a great day\nno really\n",
},
},
// {
// description: "Retrieve comment - map key example",
// subdescription: "From the previous example, we know that the comment is on the 'hello' _key_ as a lineComment",
// document: "hello: # hello-world-comment\n message: world",
// expression: `.hello | key | line_comment`,
// expected: []string{
// "D0, P[hello], (!!str)::hello-world-comment\n",
// },
// },
// {
// description: "Where is the comment - array example",
// subdescription: "The underlying yaml parser can assign comments in a document to surprising nodes. Use an expression like this to find where you comment is. 'p' indicates the path, 'isKey' is if the node is a map key (as opposed to a map value).\nFrom this, you can see the 'under-name-comment' is actually on the first child",
// document: "name:\n # under-name-comment\n - first-array-child",
// expression: `[... | {"p": path | join("."), "isKey": is_key, "hc": headComment, "lc": lineComment, "fc": footComment}]`,
// expected: []string{
// expectedWhereIsMyCommentArray,
// },
// },
// {
// description: "Retrieve comment - array example",
// subdescription: "From the previous example, we know that the comment is on the first child as a headComment",
// document: "name:\n # under-name-comment\n - first-array-child",
// expression: `.name[0] | headComment`,
// expected: []string{
// "D0, P[name 0], (!!str)::under-name-comment\n",
// },
// },
// {
// description: "Set head comment",
// document: `a: cat`,
// expression: `. head_comment="single"`,
// expected: []string{
// "D0, P[], (doc)::# single\n\na: cat\n",
// },
// },
// {
// description: "Set head comment of a map entry",
// document: "f: foo\na:\n b: cat",
// expression: `(.a | key) head_comment="single"`,
// expected: []string{
// "D0, P[], (doc)::f: foo\n# single\na:\n b: cat\n",
// },
// },
// {
// description: "Set foot comment, using an expression",
// document: `a: cat`,
// expression: `. foot_comment=.a`,
// expected: []string{
// "D0, P[], (doc)::a: cat\n# cat\n",
// },
// },
// {
// skipDoc: true,
// description: "Set foot comment, using an expression",
// document: "a: cat\n\n# hi",
// expression: `. foot_comment=""`,
// expected: []string{
// "D0, P[], (doc)::a: cat\n",
// },
// },
// {
// skipDoc: true,
// document: `a: cat`,
// expression: `. foot_comment=.b.d`,
// expected: []string{
// "D0, P[], (doc)::a: cat\n",
// },
// },
// {
// skipDoc: true,
// document: `a: cat`,
// expression: `. foot_comment|=.b.d`,
// expected: []string{
// "D0, P[], (doc)::a: cat\n",
// },
// },
// {
// description: "Remove comment",
// document: "a: cat # comment\nb: dog # leave this",
// expression: `.a line_comment=""`,
// expected: []string{
// "D0, P[], (doc)::a: cat\nb: dog # leave this\n",
// },
// },
// {
// description: "Remove (strip) all comments",
// subdescription: "Note the use of `...` to ensure key nodes are included.",
// document: "# hi\n\na: cat # comment\n\n# great\n\nb: # key comment",
// expression: `... comments=""`,
// expected: []string{
// "D0, P[], (doc)::a: cat\nb:\n",
// },
// },
// {
// description: "Get line comment",
// document: "# welcome!\n\na: cat # meow\n\n# have a great day",
// expression: `.a | line_comment`,
// expected: []string{
// "D0, P[a], (!!str)::meow\n",
// },
// },
// {
// description: "Get head comment",
// dontFormatInputForDoc: true,
// document: "# welcome!\n\na: cat # meow\n\n# have a great day",
// expression: `. | head_comment`,
// expected: []string{
// "D0, P[], (!!str)::welcome!\n\n",
// },
// },
// {
// skipDoc: true,
// description: "strip trailing comment recurse all",
// document: "a: cat\n\n# haha",
// expression: `... comments= ""`,
// expected: []string{
// "D0, P[], (doc)::a: cat\n",
// },
// },
// {
// skipDoc: true,
// description: "strip trailing comment recurse values",
// document: "a: cat\n\n# haha",
// expression: `.. comments= ""`,
// expected: []string{
// "D0, P[], (doc)::a: cat\n",
// },
// },
// {
// description: "Head comment with document split",
// dontFormatInputForDoc: true,
// document: "# welcome!\n---\n# bob\na: cat # meow\n\n# have a great day",
// expression: `head_comment`,
// expected: []string{
// "D0, P[], (!!str)::welcome!\nbob\n",
// },
// },
// {
// description: "Get foot comment",
// dontFormatInputForDoc: true,
// document: "# welcome!\n\na: cat # meow\n\n# have a great day\n# no really",
// expression: `. | foot_comment`,
// expected: []string{
// "D0, P[], (!!str)::have a great day\nno really\n",
// },
// },
}
func TestCommentOperatorScenarios(t *testing.T) {

View File

@ -28,7 +28,7 @@ func getKeyOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
candidate := el.Value.(*CandidateNode)
if candidate.Key != nil {
results.PushBack(candidate.Key.Copy())
results.PushBack(candidate.Key)
}
}

View File

@ -31,82 +31,82 @@ var expectedIsKey = `D0, P[], (!!seq)::- p: ""
`
var keysOperatorScenarios = []expressionScenario{
{
description: "Map keys",
document: `{dog: woof, cat: meow}`,
expression: `keys`,
expected: []string{
"D0, P[], (!!seq)::- dog\n- cat\n",
},
},
{
skipDoc: true,
document: `{}`,
expression: `keys`,
expected: []string{
"D0, P[], (!!seq)::[]\n",
},
},
{
description: "Array keys",
document: `[apple, banana]`,
expression: `keys`,
expected: []string{
"D0, P[], (!!seq)::- 0\n- 1\n",
},
},
{
skipDoc: true,
document: `[]`,
expression: `keys`,
expected: []string{
"D0, P[], (!!seq)::[]\n",
},
},
{
description: "Retrieve array key",
document: "[1,2,3]",
expression: `.[1] | key`,
expected: []string{
"D0, P[1], (!!int)::1\n",
},
},
{
description: "Retrieve map key",
document: "a: thing",
expression: `.a | key`,
expected: []string{
"D0, P[a], (!!str)::a\n",
},
},
{
description: "No key",
document: "{}",
expression: `key`,
expected: []string{},
},
{
description: "Update map key",
document: "a:\n x: 3\n y: 4",
expression: `(.a.x | key) = "meow"`,
expected: []string{
"D0, P[], (doc)::a:\n meow: 3\n y: 4\n",
},
},
{
description: "Get comment from map key",
document: "a: \n # comment on key\n x: 3\n y: 4",
expression: `.a.x | key | headComment`,
expected: []string{
"D0, P[a x], (!!str)::comment on key\n",
},
},
// {
// description: "Map keys",
// document: `{dog: woof, cat: meow}`,
// expression: `keys`,
// expected: []string{
// "D0, P[], (!!seq)::- dog\n- cat\n",
// },
// },
// {
// skipDoc: true,
// document: `{}`,
// expression: `keys`,
// expected: []string{
// "D0, P[], (!!seq)::[]\n",
// },
// },
// {
// description: "Array keys",
// document: `[apple, banana]`,
// expression: `keys`,
// expected: []string{
// "D0, P[], (!!seq)::- 0\n- 1\n",
// },
// },
// {
// skipDoc: true,
// document: `[]`,
// expression: `keys`,
// expected: []string{
// "D0, P[], (!!seq)::[]\n",
// },
// },
// {
// description: "Retrieve array key",
// document: "[1,2,3]",
// expression: `.[1] | key`,
// expected: []string{
// "D0, P[1], (!!int)::1\n",
// },
// },
// {
// description: "Retrieve map key",
// document: "a: thing",
// expression: `.a | key`,
// expected: []string{
// "D0, P[a], (!!str)::a\n",
// },
// },
// {
// description: "No key",
// document: "{}",
// expression: `key`,
// expected: []string{},
// },
// {
// description: "Update map key",
// document: "a:\n x: 3\n y: 4",
// expression: `(.a.x | key) = "meow"`,
// expected: []string{
// "D0, P[], (doc)::a:\n meow: 3\n y: 4\n",
// },
// },
// {
// description: "Get comment from map key",
// document: "a: \n # comment on key\n x: 3\n y: 4",
// expression: `.a.x | key | headComment`,
// expected: []string{
// "D0, P[a x], (!!str)::comment on key\n",
// },
// },
{
description: "Check node is a key",
document: "a: \n b: [cat]\n c: frog\n",
document: "a: frog\n",
expression: `[... | { "p": path | join("."), "isKey": is_key, "tag": tag }]`,
expected: []string{
expectedIsKey,
"",
},
},
}

View File

@ -23,7 +23,7 @@ func recursiveDescentOperator(d *dataTreeNavigator, context Context, expressionN
func recursiveDecent(results *list.List, context Context, preferences recursiveDescentPreferences) error {
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode).unwrapDocument()
candidate := el.Value.(*CandidateNode)
log.Debugf("Recursive Decent, added %v", NodeToString(candidate))
results.PushBack(candidate)

View File

@ -184,7 +184,13 @@ func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode {
if !value {
valString = "false"
}
return owner.CreateReplacement(ScalarNode, "!!bool", valString)
noob := owner.CreateReplacement(ScalarNode, "!!bool", valString)
if owner.IsMapKey {
noob.IsMapKey = false
noob.Key = owner
}
return noob
}
func createTraversalTree(path []interface{}, traversePrefs traversePreferences, targetKey bool) *ExpressionNode {