mirror of
				https://github.com/taigrr/yq
				synced 2025-01-18 04:53:17 -08: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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user