mirror of
https://github.com/mikefarah/yq.git
synced 2025-01-23 14:16:10 +00:00
comment ops!
This commit is contained in:
parent
b1f139c965
commit
5ab584afac
1
pkg/yqlib/doc/.gitignore
vendored
Normal file
1
pkg/yqlib/doc/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.md
|
@ -1,64 +0,0 @@
|
|||||||
# Equal Operator
|
|
||||||
## Examples
|
|
||||||
### Example 0
|
|
||||||
sample.yml:
|
|
||||||
```yaml
|
|
||||||
[cat,goat,dog]
|
|
||||||
```
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq '.[] | (. == "*at")' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
true
|
|
||||||
true
|
|
||||||
false
|
|
||||||
```
|
|
||||||
### Example 1
|
|
||||||
sample.yml:
|
|
||||||
```yaml
|
|
||||||
[3, 4, 5]
|
|
||||||
```
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq '.[] | (. == 4)' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
false
|
|
||||||
true
|
|
||||||
false
|
|
||||||
```
|
|
||||||
### Example 2
|
|
||||||
sample.yml:
|
|
||||||
```yaml
|
|
||||||
a: { cat: {b: apple, c: whatever}, pat: {b: banana} }
|
|
||||||
```
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq '.a | (.[].b == "apple")' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
true
|
|
||||||
false
|
|
||||||
```
|
|
||||||
### Example 3
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq 'null == null' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
true
|
|
||||||
```
|
|
||||||
### Example 4
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq 'null == ~' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
true
|
|
||||||
```
|
|
@ -18,14 +18,12 @@ type OperationType struct {
|
|||||||
|
|
||||||
// operators TODO:
|
// operators TODO:
|
||||||
// - generator doc from operator tests
|
// - generator doc from operator tests
|
||||||
// - stripComments not recursive
|
// - set comments not recursive
|
||||||
// - documentIndex - retrieves document index, can be used with select
|
// - documentIndex - retrieves document index, can be used with select
|
||||||
// - mergeAppend (merges and appends arrays)
|
// - mergeAppend (merges and appends arrays)
|
||||||
// - mergeEmpty (sets only if the document is empty, do I do that now?)
|
// - mergeEmpty (sets only if the document is empty, do I do that now?)
|
||||||
// - updateTag - not recursive
|
// - updateTag - not recursive
|
||||||
// - select by tag (tag==)
|
|
||||||
// - get tag (tag)
|
// - get tag (tag)
|
||||||
// - select by style (style==)
|
|
||||||
// - compare ??
|
// - compare ??
|
||||||
// - validate ??
|
// - validate ??
|
||||||
// - exists
|
// - exists
|
||||||
@ -38,6 +36,7 @@ var Union = &OperationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: U
|
|||||||
var Assign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: AssignUpdateOperator}
|
var Assign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: AssignUpdateOperator}
|
||||||
var AssignAttributes = &OperationType{Type: "ASSIGN_ATTRIBUTES", NumArgs: 2, Precedence: 40, Handler: AssignAttributesOperator}
|
var AssignAttributes = &OperationType{Type: "ASSIGN_ATTRIBUTES", NumArgs: 2, Precedence: 40, Handler: AssignAttributesOperator}
|
||||||
var AssignStyle = &OperationType{Type: "ASSIGN_STYLE", NumArgs: 2, Precedence: 40, Handler: AssignStyleOperator}
|
var AssignStyle = &OperationType{Type: "ASSIGN_STYLE", NumArgs: 2, Precedence: 40, Handler: AssignStyleOperator}
|
||||||
|
var AssignComment = &OperationType{Type: "ASSIGN_COMMENT", NumArgs: 2, Precedence: 40, Handler: AssignCommentsOperator}
|
||||||
|
|
||||||
var Multiply = &OperationType{Type: "MULTIPLY", NumArgs: 2, Precedence: 40, Handler: MultiplyOperator}
|
var Multiply = &OperationType{Type: "MULTIPLY", NumArgs: 2, Precedence: 40, Handler: MultiplyOperator}
|
||||||
|
|
||||||
|
47
pkg/yqlib/operator_comments.go
Normal file
47
pkg/yqlib/operator_comments.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import "container/list"
|
||||||
|
|
||||||
|
type AssignCommentPreferences struct {
|
||||||
|
LineComment bool
|
||||||
|
HeadComment bool
|
||||||
|
FootComment bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func AssignCommentsOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
|
||||||
|
log.Debugf("AssignComments operator!")
|
||||||
|
|
||||||
|
rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
comment := ""
|
||||||
|
if rhs.Front() != nil {
|
||||||
|
comment = rhs.Front().Value.(*CandidateNode).Node.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences := pathNode.Operation.Preferences.(*AssignCommentPreferences)
|
||||||
|
|
||||||
|
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
log.Debugf("Setting comment of : %v", candidate.GetKey())
|
||||||
|
if preferences.LineComment {
|
||||||
|
candidate.Node.LineComment = comment
|
||||||
|
}
|
||||||
|
if preferences.HeadComment {
|
||||||
|
candidate.Node.HeadComment = comment
|
||||||
|
}
|
||||||
|
if preferences.FootComment {
|
||||||
|
candidate.Node.FootComment = comment
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return matchingNodes, nil
|
||||||
|
}
|
55
pkg/yqlib/operator_comments_test.go
Normal file
55
pkg/yqlib/operator_comments_test.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var commentOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Add line comment",
|
||||||
|
document: `a: cat`,
|
||||||
|
expression: `.a lineComment="single"`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::a: cat # single\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Add head comment",
|
||||||
|
document: `a: cat`,
|
||||||
|
expression: `. headComment="single"`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::# single\n\na: cat\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Add foot comment, using an expression",
|
||||||
|
document: `a: cat`,
|
||||||
|
expression: `. footComment=.a`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::a: cat\n\n# cat\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Remove comment",
|
||||||
|
document: "a: cat # comment\nb: dog # leave this",
|
||||||
|
expression: `.a lineComment=""`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::a: cat\nb: dog # leave this\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Remove all comments",
|
||||||
|
document: "# hi\n\na: cat # comment\n\n# great\n",
|
||||||
|
expression: `.. comments=""`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::a: cat\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommentOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range commentOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentScenarios(t, "Comments Operator", commentOperatorScenarios)
|
||||||
|
}
|
@ -49,5 +49,5 @@ func TestEqualOperatorScenarios(t *testing.T) {
|
|||||||
for _, tt := range equalsOperatorScenarios {
|
for _, tt := range equalsOperatorScenarios {
|
||||||
testScenario(t, &tt)
|
testScenario(t, &tt)
|
||||||
}
|
}
|
||||||
documentScenarios(t, "Equal Operator", equalsOperatorScenarios)
|
documentScenarios(t, "Equals Operator", equalsOperatorScenarios)
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func AssignStyleOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func AssignStyleOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
customStyle := pathNode.Rhs.Operation.StringValue
|
|
||||||
log.Debugf("AssignStyleOperator: %v", customStyle)
|
log.Debugf("AssignStyleOperator: %v")
|
||||||
|
|
||||||
|
rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
customStyle := ""
|
||||||
|
|
||||||
|
if rhs.Front() != nil {
|
||||||
|
customStyle = rhs.Front().Value.(*CandidateNode).Node.Value
|
||||||
|
}
|
||||||
|
|
||||||
var style yaml.Style
|
var style yaml.Style
|
||||||
if customStyle == "tagged" {
|
if customStyle == "tagged" {
|
||||||
|
@ -12,6 +12,14 @@ var styleOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (doc)::{a: 'cat'}\n",
|
"D0, P[], (doc)::{a: 'cat'}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Set style using a path",
|
||||||
|
document: `{a: cat, b: double}`,
|
||||||
|
expression: `.a style=.b`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: \"cat\", b: double}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
document: `{a: "cat", b: 'dog'}`,
|
document: `{a: "cat", b: 'dog'}`,
|
||||||
expression: `.. style=""`,
|
expression: `.. style=""`,
|
||||||
@ -42,4 +50,5 @@ func TestStyleOperatorScenarios(t *testing.T) {
|
|||||||
for _, tt := range styleOperatorScenarios {
|
for _, tt := range styleOperatorScenarios {
|
||||||
testScenario(t, &tt)
|
testScenario(t, &tt)
|
||||||
}
|
}
|
||||||
|
documentScenarios(t, "Style Operator", styleOperatorScenarios)
|
||||||
}
|
}
|
||||||
|
@ -84,9 +84,13 @@ func documentToken() lex.Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func opToken(op *OperationType) lex.Action {
|
func opToken(op *OperationType) lex.Action {
|
||||||
|
return opTokenWithPrefs(op, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func opTokenWithPrefs(op *OperationType, preferences interface{}) lex.Action {
|
||||||
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
value := string(m.Bytes)
|
value := string(m.Bytes)
|
||||||
op := &Operation{OperationType: op, Value: op.Type, StringValue: value}
|
op := &Operation{OperationType: op, Value: op.Type, StringValue: value, Preferences: preferences}
|
||||||
return &Token{TokenType: OperationToken, Operation: op}, nil
|
return &Token{TokenType: OperationToken, Operation: op}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,6 +194,12 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`style\s*=`), opToken(AssignStyle))
|
lexer.Add([]byte(`style\s*=`), opToken(AssignStyle))
|
||||||
lexer.Add([]byte(`style`), opToken(GetStyle))
|
lexer.Add([]byte(`style`), opToken(GetStyle))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`lineComment\s*=`), opTokenWithPrefs(AssignComment, &AssignCommentPreferences{LineComment: true}))
|
||||||
|
lexer.Add([]byte(`headComment\s*=`), opTokenWithPrefs(AssignComment, &AssignCommentPreferences{HeadComment: true}))
|
||||||
|
lexer.Add([]byte(`footComment\s*=`), opTokenWithPrefs(AssignComment, &AssignCommentPreferences{FootComment: true}))
|
||||||
|
lexer.Add([]byte(`comments\s*=`), opTokenWithPrefs(AssignComment, &AssignCommentPreferences{LineComment: true, HeadComment: true, FootComment: true}))
|
||||||
|
// lexer.Add([]byte(`style`), opToken(GetStyle))
|
||||||
|
|
||||||
// lexer.Add([]byte(`and`), opToken())
|
// lexer.Add([]byte(`and`), opToken())
|
||||||
lexer.Add([]byte(`collect`), opToken(Collect))
|
lexer.Add([]byte(`collect`), opToken(Collect))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user