mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Compare commits
5 Commits
v4.2.0
...
traverse_a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
822d56a673 | ||
|
|
4e1a1025c3 | ||
|
|
7b54bead5e | ||
|
|
f7f8bed955 | ||
|
|
6a13c8b78f |
@@ -14,6 +14,5 @@ var noDocSeparators = false
|
|||||||
var nullInput = false
|
var nullInput = false
|
||||||
var verbose = false
|
var verbose = false
|
||||||
var version = false
|
var version = false
|
||||||
var prettyPrint = false
|
|
||||||
|
|
||||||
var completedSuccessfully = false
|
var completedSuccessfully = false
|
||||||
|
|||||||
@@ -65,19 +65,19 @@ func evaluateAll(cmd *cobra.Command, args []string) error {
|
|||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0:
|
case 0:
|
||||||
if pipingStdIn {
|
if pipingStdIn {
|
||||||
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer)
|
err = allAtOnceEvaluator.EvaluateFiles("", []string{"-"}, printer)
|
||||||
} else {
|
} else {
|
||||||
cmd.Println(cmd.UsageString())
|
cmd.Println(cmd.UsageString())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
if nullInput {
|
if nullInput {
|
||||||
err = yqlib.NewStreamEvaluator().EvaluateNew(processExpression(args[0]), printer)
|
err = yqlib.NewStreamEvaluator().EvaluateNew(args[0], printer)
|
||||||
} else {
|
} else {
|
||||||
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer)
|
err = allAtOnceEvaluator.EvaluateFiles("", []string{args[0]}, printer)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err = allAtOnceEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer)
|
err = allAtOnceEvaluator.EvaluateFiles(args[0], args[1:], printer)
|
||||||
}
|
}
|
||||||
|
|
||||||
completedSuccessfully = err == nil
|
completedSuccessfully = err == nil
|
||||||
|
|||||||
@@ -33,16 +33,6 @@ yq e '.a.b = "cool"' -i file.yaml
|
|||||||
}
|
}
|
||||||
return cmdEvalSequence
|
return cmdEvalSequence
|
||||||
}
|
}
|
||||||
|
|
||||||
func processExpression(expression string) string {
|
|
||||||
if prettyPrint && expression == "" {
|
|
||||||
return `... style=""`
|
|
||||||
} else if prettyPrint {
|
|
||||||
return fmt.Sprintf("%v | ... style= \"\"", expression)
|
|
||||||
}
|
|
||||||
return expression
|
|
||||||
}
|
|
||||||
|
|
||||||
func evaluateSequence(cmd *cobra.Command, args []string) error {
|
func evaluateSequence(cmd *cobra.Command, args []string) error {
|
||||||
cmd.SilenceUsage = true
|
cmd.SilenceUsage = true
|
||||||
// 0 args, read std in
|
// 0 args, read std in
|
||||||
@@ -86,16 +76,16 @@ func evaluateSequence(cmd *cobra.Command, args []string) error {
|
|||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0:
|
case 0:
|
||||||
if pipingStdIn {
|
if pipingStdIn {
|
||||||
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer)
|
err = streamEvaluator.EvaluateFiles("", []string{"-"}, printer)
|
||||||
} else {
|
} else {
|
||||||
cmd.Println(cmd.UsageString())
|
cmd.Println(cmd.UsageString())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
if nullInput {
|
if nullInput {
|
||||||
err = streamEvaluator.EvaluateNew(processExpression(args[0]), printer)
|
err = streamEvaluator.EvaluateNew(args[0], printer)
|
||||||
} else {
|
} else {
|
||||||
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer)
|
err = streamEvaluator.EvaluateFiles("", []string{args[0]}, printer)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err = streamEvaluator.EvaluateFiles(args[0], args[1:], printer)
|
err = streamEvaluator.EvaluateFiles(args[0], args[1:], printer)
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ func New() *cobra.Command {
|
|||||||
rootCmd.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit")
|
rootCmd.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace of first yaml file given.")
|
rootCmd.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace of first yaml file given.")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&unwrapScalar, "unwrapScalar", "", true, "unwrap scalar, print the value with no quotes, colors or comments")
|
rootCmd.PersistentFlags().BoolVarP(&unwrapScalar, "unwrapScalar", "", true, "unwrap scalar, print the value with no quotes, colors or comments")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print, shorthand for '... style = \"\"'")
|
|
||||||
rootCmd.PersistentFlags().BoolVarP(&exitStatus, "exit-status", "e", false, "set exit status if there are no matches or null or false is returned")
|
rootCmd.PersistentFlags().BoolVarP(&exitStatus, "exit-status", "e", false, "set exit status if there are no matches or null or false is returned")
|
||||||
|
|
||||||
rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors")
|
rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ var (
|
|||||||
GitDescribe string
|
GitDescribe string
|
||||||
|
|
||||||
// Version is main version number that is being run at the moment.
|
// Version is main version number that is being run at the moment.
|
||||||
Version = "4.2.0"
|
Version = "4.1.0"
|
||||||
|
|
||||||
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string)
|
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string)
|
||||||
// then it means that it is a final release. Otherwise, this is a pre-release
|
// then it means that it is a final release. Otherwise, this is a pre-release
|
||||||
|
|||||||
@@ -1,55 +1,8 @@
|
|||||||
This operator recursively matches all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches. It can be used in either the
|
This operator recursively matches all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches, for instance to set the `style` of all nodes in a yaml doc:
|
||||||
|
|
||||||
## match values form `..`
|
|
||||||
This will, like the `jq` equivalent, recursively match all _value_ nodes. Use it to find/manipulate particular values.
|
|
||||||
|
|
||||||
For instance to set the `style` of all _value_ nodes in a yaml doc, excluding map keys:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yq eval '.. style= "flow"' file.yaml
|
yq eval '.. style= "flow"' file.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
## match values and map keys form `...`
|
|
||||||
The also includes map keys in the results set. This is particularly useful in YAML as unlike JSON, map keys can have their own styling, tags and use anchors and aliases.
|
|
||||||
|
|
||||||
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yq eval '... style= "flow"' file.yaml
|
|
||||||
```
|
|
||||||
## Recurse map (values only)
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: frog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '..' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: frog
|
|
||||||
frog
|
|
||||||
```
|
|
||||||
|
|
||||||
## Recurse map (values and keys)
|
|
||||||
Note that the map key appears in the results
|
|
||||||
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: frog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '...' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: frog
|
|
||||||
a
|
|
||||||
frog
|
|
||||||
```
|
|
||||||
|
|
||||||
## Aliases are not traversed
|
## Aliases are not traversed
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -40,26 +40,6 @@ c: "3.2"
|
|||||||
e: "true"
|
e: "true"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Set double quote style on map keys too
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
b: 5
|
|
||||||
c: 3.2
|
|
||||||
e: true
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '... style="double"' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
"a": "cat"
|
|
||||||
"b": "5"
|
|
||||||
"c": "3.2"
|
|
||||||
"e": "true"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Set single quote style
|
## Set single quote style
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
@@ -146,18 +126,18 @@ will output
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Pretty print
|
## Pretty print
|
||||||
Set empty (default) quote style, note the usage of `...` to match keys too.
|
Set empty (default) quote style
|
||||||
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
"b": 5
|
b: 5
|
||||||
'c': 3.2
|
c: 3.2
|
||||||
"e": true
|
e: true
|
||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '... style=""' sample.yml
|
yq eval '.. style=""' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ b: *cat
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.b[]' sample.yml
|
yq eval '.b.[]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -290,7 +290,7 @@ foobar:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.foobar[]' sample.yml
|
yq eval '.foobar.[]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -356,7 +356,7 @@ foobar:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.foobarList[]' sample.yml
|
yq eval '.foobarList.[]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -1,19 +1,5 @@
|
|||||||
This operator recursively matches all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches. It can be used in either the
|
This operator recursively matches all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches, for instance to set the `style` of all nodes in a yaml doc:
|
||||||
|
|
||||||
## match values form `..`
|
|
||||||
This will, like the `jq` equivalent, recursively match all _value_ nodes. Use it to find/manipulate particular values.
|
|
||||||
|
|
||||||
For instance to set the `style` of all _value_ nodes in a yaml doc, excluding map keys:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yq eval '.. style= "flow"' file.yaml
|
yq eval '.. style= "flow"' file.yaml
|
||||||
```
|
|
||||||
|
|
||||||
## match values and map keys form `...`
|
|
||||||
The also includes map keys in the results set. This is particularly useful in YAML as unlike JSON, map keys can have their own styling, tags and use anchors and aliases.
|
|
||||||
|
|
||||||
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yq eval '... style= "flow"' file.yaml
|
|
||||||
```
|
```
|
||||||
@@ -19,7 +19,7 @@ type OperationType struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// operators TODO:
|
// operators TODO:
|
||||||
// - keys operator for controlling key metadata (particularly anchors/aliases)
|
// - cookbook doc for common things
|
||||||
// - 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?)
|
||||||
|
|
||||||
var Or = &OperationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: OrOperator}
|
var Or = &OperationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: OrOperator}
|
||||||
|
|||||||
@@ -67,9 +67,7 @@ func collect(d *dataTreeNavigator, aggregate *list.List, remainingMatches *list.
|
|||||||
}
|
}
|
||||||
|
|
||||||
candidate := remainingMatches.Remove(remainingMatches.Front()).(*CandidateNode)
|
candidate := remainingMatches.Remove(remainingMatches.Front()).(*CandidateNode)
|
||||||
|
splatted, err := Splat(d, nodeToMap(candidate))
|
||||||
splatted, err := Splat(d, nodeToMap(candidate),
|
|
||||||
&TraversePreferences{FollowAlias: false, IncludeMapKeys: false})
|
|
||||||
|
|
||||||
for splatEl := splatted.Front(); splatEl != nil; splatEl = splatEl.Next() {
|
for splatEl := splatted.Front(); splatEl != nil; splatEl = splatEl.Next() {
|
||||||
splatEl.Value.(*CandidateNode).Path = nil
|
splatEl.Value.(*CandidateNode).Path = nil
|
||||||
|
|||||||
@@ -85,9 +85,7 @@ func mergeObjects(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode,
|
|||||||
var results = list.New()
|
var results = list.New()
|
||||||
|
|
||||||
// shouldn't recurse arrays if appending
|
// shouldn't recurse arrays if appending
|
||||||
prefs := &RecursiveDescentPreferences{RecurseArray: !shouldAppendArrays,
|
err := recursiveDecent(d, results, nodeToMap(rhs), !shouldAppendArrays)
|
||||||
TraversePreferences: &TraversePreferences{FollowAlias: false}}
|
|
||||||
err := recursiveDecent(d, results, nodeToMap(rhs), prefs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,10 @@ import (
|
|||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RecursiveDescentPreferences struct {
|
|
||||||
TraversePreferences *TraversePreferences
|
|
||||||
RecurseArray bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
var results = list.New()
|
var results = list.New()
|
||||||
|
|
||||||
preferences := pathNode.Operation.Preferences.(*RecursiveDescentPreferences)
|
err := recursiveDecent(d, results, matchMap, true)
|
||||||
err := recursiveDecent(d, results, matchMap, preferences)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -23,7 +17,7 @@ func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *list.List, pathNod
|
|||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func recursiveDecent(d *dataTreeNavigator, results *list.List, matchMap *list.List, preferences *RecursiveDescentPreferences) error {
|
func recursiveDecent(d *dataTreeNavigator, results *list.List, matchMap *list.List, recurseArray bool) error {
|
||||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||||
candidate := el.Value.(*CandidateNode)
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
|
||||||
@@ -33,14 +27,14 @@ func recursiveDecent(d *dataTreeNavigator, results *list.List, matchMap *list.Li
|
|||||||
results.PushBack(candidate)
|
results.PushBack(candidate)
|
||||||
|
|
||||||
if candidate.Node.Kind != yaml.AliasNode && len(candidate.Node.Content) > 0 &&
|
if candidate.Node.Kind != yaml.AliasNode && len(candidate.Node.Content) > 0 &&
|
||||||
(preferences.RecurseArray || candidate.Node.Kind != yaml.SequenceNode) {
|
(recurseArray || candidate.Node.Kind != yaml.SequenceNode) {
|
||||||
|
|
||||||
children, err := Splat(d, nodeToMap(candidate), preferences.TraversePreferences)
|
children, err := Splat(d, nodeToMap(candidate))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = recursiveDecent(d, results, children, preferences)
|
err = recursiveDecent(d, results, children, recurseArray)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,6 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!map)::{}\n",
|
"D0, P[], (!!map)::{}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `{}`,
|
|
||||||
expression: `...`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::{}\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `[]`,
|
document: `[]`,
|
||||||
@@ -29,14 +21,6 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!seq)::[]\n",
|
"D0, P[], (!!seq)::[]\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `[]`,
|
|
||||||
expression: `...`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::[]\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `cat`,
|
document: `cat`,
|
||||||
@@ -47,32 +31,13 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `cat`,
|
document: `{a: frog}`,
|
||||||
expression: `...`,
|
expression: `..`,
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!str)::cat\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Recurse map (values only)",
|
|
||||||
document: `{a: frog}`,
|
|
||||||
expression: `..`,
|
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!map)::{a: frog}\n",
|
"D0, P[], (!!map)::{a: frog}\n",
|
||||||
"D0, P[a], (!!str)::frog\n",
|
"D0, P[a], (!!str)::frog\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
description: "Recurse map (values and keys)",
|
|
||||||
subdescription: "Note that the map key appears in the results",
|
|
||||||
document: `{a: frog}`,
|
|
||||||
expression: `...`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::{a: frog}\n",
|
|
||||||
"D0, P[a], (!!str)::a\n",
|
|
||||||
"D0, P[a], (!!str)::frog\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `{a: {b: apple}}`,
|
document: `{a: {b: apple}}`,
|
||||||
@@ -83,18 +48,6 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[a b], (!!str)::apple\n",
|
"D0, P[a b], (!!str)::apple\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `{a: {b: apple}}`,
|
|
||||||
expression: `...`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::{a: {b: apple}}\n",
|
|
||||||
"D0, P[a], (!!str)::a\n",
|
|
||||||
"D0, P[a], (!!map)::{b: apple}\n",
|
|
||||||
"D0, P[a b], (!!str)::b\n",
|
|
||||||
"D0, P[a b], (!!str)::apple\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `[1,2,3]`,
|
document: `[1,2,3]`,
|
||||||
@@ -106,17 +59,6 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[2], (!!int)::3\n",
|
"D0, P[2], (!!int)::3\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `[1,2,3]`,
|
|
||||||
expression: `...`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::[1, 2, 3]\n",
|
|
||||||
"D0, P[0], (!!int)::1\n",
|
|
||||||
"D0, P[1], (!!int)::2\n",
|
|
||||||
"D0, P[2], (!!int)::3\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `[{a: cat},2,true]`,
|
document: `[{a: cat},2,true]`,
|
||||||
@@ -129,19 +71,6 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[2], (!!bool)::true\n",
|
"D0, P[2], (!!bool)::true\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `[{a: cat},2,true]`,
|
|
||||||
expression: `...`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!seq)::[{a: cat}, 2, true]\n",
|
|
||||||
"D0, P[0], (!!map)::{a: cat}\n",
|
|
||||||
"D0, P[0 a], (!!str)::a\n",
|
|
||||||
"D0, P[0 a], (!!str)::cat\n",
|
|
||||||
"D0, P[1], (!!int)::2\n",
|
|
||||||
"D0, P[2], (!!bool)::true\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
description: "Aliases are not traversed",
|
description: "Aliases are not traversed",
|
||||||
document: `{a: &cat {c: frog}, b: *cat}`,
|
document: `{a: &cat {c: frog}, b: *cat}`,
|
||||||
@@ -150,20 +79,6 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[a], (!!seq)::- {a: &cat {c: frog}, b: *cat}\n- &cat {c: frog}\n- frog\n- *cat\n",
|
"D0, P[a], (!!seq)::- {a: &cat {c: frog}, b: *cat}\n- &cat {c: frog}\n- frog\n- *cat\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `{a: &cat {c: frog}, b: *cat}`,
|
|
||||||
expression: `...`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::{a: &cat {c: frog}, b: *cat}\n",
|
|
||||||
"D0, P[a], (!!str)::a\n",
|
|
||||||
"D0, P[a], (!!map)::&cat {c: frog}\n",
|
|
||||||
"D0, P[a c], (!!str)::c\n",
|
|
||||||
"D0, P[a c], (!!str)::frog\n",
|
|
||||||
"D0, P[b], (!!str)::b\n",
|
|
||||||
"D0, P[b], (alias)::*cat\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
description: "Merge docs are not traversed",
|
description: "Merge docs are not traversed",
|
||||||
document: mergeDocSample,
|
document: mergeDocSample,
|
||||||
@@ -172,14 +87,6 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[foobar], (!!seq)::- c: foobar_c\n !!merge <<: *foo\n thing: foobar_thing\n- foobar_c\n- *foo\n- foobar_thing\n",
|
"D0, P[foobar], (!!seq)::- c: foobar_c\n !!merge <<: *foo\n thing: foobar_thing\n- foobar_c\n- *foo\n- foobar_thing\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: mergeDocSample,
|
|
||||||
expression: `.foobar | [...]`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[foobar], (!!seq)::- c: foobar_c\n !!merge <<: *foo\n thing: foobar_thing\n- c\n- foobar_c\n- !!merge <<\n- *foo\n- thing\n- foobar_thing\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: mergeDocSample,
|
document: mergeDocSample,
|
||||||
@@ -193,22 +100,6 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[foobarList c], (!!str)::foobarList_c\n",
|
"D0, P[foobarList c], (!!str)::foobarList_c\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: mergeDocSample,
|
|
||||||
expression: `.foobarList | ...`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[foobarList], (!!map)::b: foobarList_b\n!!merge <<: [*foo, *bar]\nc: foobarList_c\n",
|
|
||||||
"D0, P[foobarList b], (!!str)::b\n",
|
|
||||||
"D0, P[foobarList b], (!!str)::foobarList_b\n",
|
|
||||||
"D0, P[foobarList <<], (!!merge)::!!merge <<\n",
|
|
||||||
"D0, P[foobarList <<], (!!seq)::[*foo, *bar]\n",
|
|
||||||
"D0, P[foobarList << 0], (alias)::*foo\n",
|
|
||||||
"D0, P[foobarList << 1], (alias)::*bar\n",
|
|
||||||
"D0, P[foobarList c], (!!str)::c\n",
|
|
||||||
"D0, P[foobarList c], (!!str)::foobarList_c\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecursiveDescentOperatorScenarios(t *testing.T) {
|
func TestRecursiveDescentOperatorScenarios(t *testing.T) {
|
||||||
|
|||||||
@@ -21,22 +21,6 @@ var styleOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!map)::a: \"cat\"\nb: \"5\"\nc: \"3.2\"\ne: \"true\"\n",
|
"D0, P[], (!!map)::a: \"cat\"\nb: \"5\"\nc: \"3.2\"\ne: \"true\"\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
description: "Set double quote style on map keys too",
|
|
||||||
document: `{a: cat, b: 5, c: 3.2, e: true}`,
|
|
||||||
expression: `... style="double"`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::\"a\": \"cat\"\n\"b\": \"5\"\n\"c\": \"3.2\"\n\"e\": \"true\"\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: "bing: &foo frog\na:\n c: cat\n <<: [*foo]",
|
|
||||||
expression: `(... | select(tag=="!!str")) style="single"`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::'bing': &foo 'frog'\n'a':\n 'c': 'cat'\n !!merge <<: [*foo]\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
description: "Set single quote style",
|
description: "Set single quote style",
|
||||||
document: `{a: cat, b: 5, c: 3.2, e: true}`,
|
document: `{a: cat, b: 5, c: 3.2, e: true}`,
|
||||||
@@ -87,9 +71,9 @@ e: >-
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Pretty print",
|
description: "Pretty print",
|
||||||
subdescription: "Set empty (default) quote style, note the usage of `...` to match keys too.",
|
subdescription: "Set empty (default) quote style",
|
||||||
document: `{a: cat, "b": 5, 'c': 3.2, "e": true}`,
|
document: `{a: cat, b: 5, c: 3.2, e: true}`,
|
||||||
expression: `... style=""`,
|
expression: `.. style=""`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!map)::a: cat\nb: 5\nc: 3.2\ne: true\n",
|
"D0, P[], (!!map)::a: cat\nb: 5\nc: 3.2\ne: true\n",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,12 +10,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type TraversePreferences struct {
|
type TraversePreferences struct {
|
||||||
FollowAlias bool
|
DontFollowAlias bool
|
||||||
IncludeMapKeys bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Splat(d *dataTreeNavigator, matches *list.List, prefs *TraversePreferences) (*list.List, error) {
|
func Splat(d *dataTreeNavigator, matches *list.List) (*list.List, error) {
|
||||||
return traverseNodesWithArrayIndices(matches, make([]*yaml.Node, 0), prefs)
|
return traverseNodesWithArrayIndices(matches, make([]*yaml.Node, 0), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TraversePathOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func TraversePathOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
@@ -54,8 +53,12 @@ func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, operation *Oper
|
|||||||
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)
|
||||||
prefs := &TraversePreferences{FollowAlias: true}
|
followAlias := true
|
||||||
return traverseMap(matchingNode, operation.StringValue, prefs, false)
|
|
||||||
|
if operation.Preferences != nil {
|
||||||
|
followAlias = !operation.Preferences.(*TraversePreferences).DontFollowAlias
|
||||||
|
}
|
||||||
|
return traverseMap(matchingNode, operation.StringValue, followAlias, 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))
|
||||||
@@ -86,15 +89,15 @@ func TraverseArrayOperator(d *dataTreeNavigator, matchingNodes *list.List, pathN
|
|||||||
}
|
}
|
||||||
|
|
||||||
var indicesToTraverse = rhs.Front().Value.(*CandidateNode).Node.Content
|
var indicesToTraverse = rhs.Front().Value.(*CandidateNode).Node.Content
|
||||||
prefs := &TraversePreferences{FollowAlias: true}
|
|
||||||
return traverseNodesWithArrayIndices(matchingNodes, indicesToTraverse, prefs)
|
return traverseNodesWithArrayIndices(matchingNodes, indicesToTraverse, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func traverseNodesWithArrayIndices(matchingNodes *list.List, indicesToTraverse []*yaml.Node, prefs *TraversePreferences) (*list.List, error) {
|
func traverseNodesWithArrayIndices(matchingNodes *list.List, indicesToTraverse []*yaml.Node, followAlias bool) (*list.List, error) {
|
||||||
var matchingNodeMap = list.New()
|
var matchingNodeMap = list.New()
|
||||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
candidate := el.Value.(*CandidateNode)
|
candidate := el.Value.(*CandidateNode)
|
||||||
newNodes, err := traverseArrayIndices(candidate, indicesToTraverse, prefs)
|
newNodes, err := traverseArrayIndices(candidate, indicesToTraverse, followAlias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -104,7 +107,7 @@ func traverseNodesWithArrayIndices(matchingNodes *list.List, indicesToTraverse [
|
|||||||
return matchingNodeMap, nil
|
return matchingNodeMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func traverseArrayIndices(matchingNode *CandidateNode, indicesToTraverse []*yaml.Node, prefs *TraversePreferences) (*list.List, error) { // call this if doc / alias like the other traverse
|
func traverseArrayIndices(matchingNode *CandidateNode, indicesToTraverse []*yaml.Node, followAlias bool) (*list.List, error) { // call this if doc / alias like the other traverse
|
||||||
node := matchingNode.Node
|
node := matchingNode.Node
|
||||||
if node.Tag == "!!null" {
|
if node.Tag == "!!null" {
|
||||||
log.Debugf("OperatorArrayTraverse got a null - turning it into an empty array")
|
log.Debugf("OperatorArrayTraverse got a null - turning it into an empty array")
|
||||||
@@ -115,32 +118,32 @@ func traverseArrayIndices(matchingNode *CandidateNode, indicesToTraverse []*yaml
|
|||||||
|
|
||||||
if node.Kind == yaml.AliasNode {
|
if node.Kind == yaml.AliasNode {
|
||||||
matchingNode.Node = node.Alias
|
matchingNode.Node = node.Alias
|
||||||
return traverseArrayIndices(matchingNode, indicesToTraverse, prefs)
|
return traverseArrayIndices(matchingNode, indicesToTraverse, followAlias)
|
||||||
} else if node.Kind == yaml.SequenceNode {
|
} else if node.Kind == yaml.SequenceNode {
|
||||||
return traverseArrayWithIndices(matchingNode, indicesToTraverse)
|
return traverseArrayWithIndices(matchingNode, indicesToTraverse)
|
||||||
} else if node.Kind == yaml.MappingNode {
|
} else if node.Kind == yaml.MappingNode {
|
||||||
return traverseMapWithIndices(matchingNode, indicesToTraverse, prefs)
|
return traverseMapWithIndices(matchingNode, indicesToTraverse, followAlias)
|
||||||
} else if node.Kind == yaml.DocumentNode {
|
} else if node.Kind == yaml.DocumentNode {
|
||||||
return traverseArrayIndices(&CandidateNode{
|
return traverseArrayIndices(&CandidateNode{
|
||||||
Node: matchingNode.Node.Content[0],
|
Node: matchingNode.Node.Content[0],
|
||||||
Filename: matchingNode.Filename,
|
Filename: matchingNode.Filename,
|
||||||
FileIndex: matchingNode.FileIndex,
|
FileIndex: matchingNode.FileIndex,
|
||||||
Document: matchingNode.Document}, indicesToTraverse, prefs)
|
Document: matchingNode.Document}, indicesToTraverse, followAlias)
|
||||||
}
|
}
|
||||||
log.Debugf("OperatorArrayTraverse skipping %v as its a %v", matchingNode, node.Tag)
|
log.Debugf("OperatorArrayTraverse skipping %v as its a %v", matchingNode, node.Tag)
|
||||||
return list.New(), nil
|
return list.New(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func traverseMapWithIndices(candidate *CandidateNode, indices []*yaml.Node, prefs *TraversePreferences) (*list.List, error) {
|
func traverseMapWithIndices(candidate *CandidateNode, indices []*yaml.Node, followAlias bool) (*list.List, error) {
|
||||||
if len(indices) == 0 {
|
if len(indices) == 0 {
|
||||||
return traverseMap(candidate, "", prefs, true)
|
return traverseMap(candidate, "", followAlias, 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(candidate, indexNode.Value, prefs, false)
|
newNodes, err := traverseMap(candidate, indexNode.Value, followAlias, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -203,9 +206,9 @@ func keyMatches(key *yaml.Node, wantedKey string) bool {
|
|||||||
return Match(key.Value, wantedKey)
|
return Match(key.Value, wantedKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func traverseMap(matchingNode *CandidateNode, key string, prefs *TraversePreferences, splat bool) (*list.List, error) {
|
func traverseMap(matchingNode *CandidateNode, key string, followAlias bool, splat bool) (*list.List, error) {
|
||||||
var newMatches = orderedmap.NewOrderedMap()
|
var newMatches = orderedmap.NewOrderedMap()
|
||||||
err := doTraverseMap(newMatches, matchingNode, key, prefs, splat)
|
err := doTraverseMap(newMatches, matchingNode, key, followAlias, splat)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -234,7 +237,7 @@ func traverseMap(matchingNode *CandidateNode, key string, prefs *TraversePrefere
|
|||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, wantedKey string, prefs *TraversePreferences, splat bool) error {
|
func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, wantedKey string, followAlias bool, splat bool) error {
|
||||||
// value.Content is a concatenated array of key, value,
|
// value.Content is a concatenated array of key, value,
|
||||||
// so keys are in the even indexes, values in odd.
|
// so keys are in the even indexes, values in odd.
|
||||||
// merge aliases are defined first, but we only want to traverse them
|
// merge aliases are defined first, but we only want to traverse them
|
||||||
@@ -249,22 +252,14 @@ func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode,
|
|||||||
|
|
||||||
log.Debug("checking %v (%v)", key.Value, key.Tag)
|
log.Debug("checking %v (%v)", key.Value, key.Tag)
|
||||||
//skip the 'merge' tag, find a direct match first
|
//skip the 'merge' tag, find a direct match first
|
||||||
if key.Tag == "!!merge" && prefs.FollowAlias {
|
if key.Tag == "!!merge" && followAlias {
|
||||||
log.Debug("Merge anchor")
|
log.Debug("Merge anchor")
|
||||||
err := traverseMergeAnchor(newMatches, candidate, value, wantedKey, prefs, splat)
|
err := traverseMergeAnchor(newMatches, candidate, value, wantedKey, splat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if splat || keyMatches(key, wantedKey) {
|
} else if splat || keyMatches(key, wantedKey) {
|
||||||
log.Debug("MATCHED")
|
log.Debug("MATCHED")
|
||||||
if prefs.IncludeMapKeys {
|
|
||||||
candidateNode := &CandidateNode{
|
|
||||||
Node: key,
|
|
||||||
Path: candidate.CreateChildPath(key.Value),
|
|
||||||
Document: candidate.Document,
|
|
||||||
}
|
|
||||||
newMatches.Set(fmt.Sprintf("keyOf-%v", candidateNode.GetKey()), candidateNode)
|
|
||||||
}
|
|
||||||
candidateNode := &CandidateNode{
|
candidateNode := &CandidateNode{
|
||||||
Node: value,
|
Node: value,
|
||||||
Path: candidate.CreateChildPath(key.Value),
|
Path: candidate.CreateChildPath(key.Value),
|
||||||
@@ -277,7 +272,7 @@ func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, originalCandidate *CandidateNode, value *yaml.Node, wantedKey string, prefs *TraversePreferences, splat bool) error {
|
func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, originalCandidate *CandidateNode, value *yaml.Node, wantedKey string, splat bool) error {
|
||||||
switch value.Kind {
|
switch value.Kind {
|
||||||
case yaml.AliasNode:
|
case yaml.AliasNode:
|
||||||
candidateNode := &CandidateNode{
|
candidateNode := &CandidateNode{
|
||||||
@@ -285,10 +280,10 @@ func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, originalCandidate *C
|
|||||||
Path: originalCandidate.Path,
|
Path: originalCandidate.Path,
|
||||||
Document: originalCandidate.Document,
|
Document: originalCandidate.Document,
|
||||||
}
|
}
|
||||||
return doTraverseMap(newMatches, candidateNode, wantedKey, prefs, splat)
|
return doTraverseMap(newMatches, candidateNode, wantedKey, true, splat)
|
||||||
case yaml.SequenceNode:
|
case yaml.SequenceNode:
|
||||||
for _, childValue := range value.Content {
|
for _, childValue := range value.Content {
|
||||||
err := traverseMergeAnchor(newMatches, originalCandidate, childValue, wantedKey, prefs, splat)
|
err := traverseMergeAnchor(newMatches, originalCandidate, childValue, wantedKey, splat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,15 +137,7 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Traversing aliases with splat",
|
description: "Traversing aliases with splat",
|
||||||
document: `{a: &cat {c: frog}, b: *cat}`,
|
document: `{a: &cat {c: frog}, b: *cat}`,
|
||||||
expression: `.b[]`,
|
expression: `.b.[]`,
|
||||||
expected: []string{
|
|
||||||
"D0, P[b c], (!!str)::frog\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `{a: &cat {c: frog}, b: *cat}`,
|
|
||||||
expression: `.b.[]`,
|
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[b c], (!!str)::frog\n",
|
"D0, P[b c], (!!str)::frog\n",
|
||||||
},
|
},
|
||||||
@@ -217,17 +209,7 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Splatting merge anchors",
|
description: "Splatting merge anchors",
|
||||||
document: mergeDocSample,
|
document: mergeDocSample,
|
||||||
expression: `.foobar[]`,
|
expression: `.foobar.[]`,
|
||||||
expected: []string{
|
|
||||||
"D0, P[foobar c], (!!str)::foo_c\n",
|
|
||||||
"D0, P[foobar a], (!!str)::foo_a\n",
|
|
||||||
"D0, P[foobar thing], (!!str)::foobar_thing\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: mergeDocSample,
|
|
||||||
expression: `.foobar.[]`,
|
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[foobar c], (!!str)::foo_c\n",
|
"D0, P[foobar c], (!!str)::foo_c\n",
|
||||||
"D0, P[foobar a], (!!str)::foo_a\n",
|
"D0, P[foobar a], (!!str)::foo_a\n",
|
||||||
@@ -278,18 +260,7 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Splatting merge anchor lists",
|
description: "Splatting merge anchor lists",
|
||||||
document: mergeDocSample,
|
document: mergeDocSample,
|
||||||
expression: `.foobarList[]`,
|
expression: `.foobarList.[]`,
|
||||||
expected: []string{
|
|
||||||
"D0, P[foobarList b], (!!str)::bar_b\n",
|
|
||||||
"D0, P[foobarList a], (!!str)::foo_a\n",
|
|
||||||
"D0, P[foobarList thing], (!!str)::bar_thing\n",
|
|
||||||
"D0, P[foobarList c], (!!str)::foobarList_c\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: mergeDocSample,
|
|
||||||
expression: `.foobarList.[]`,
|
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[foobarList b], (!!str)::bar_b\n",
|
"D0, P[foobarList b], (!!str)::bar_b\n",
|
||||||
"D0, P[foobarList a], (!!str)::foo_a\n",
|
"D0, P[foobarList a], (!!str)::foo_a\n",
|
||||||
@@ -341,6 +312,14 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[a 2], (!!str)::c\n",
|
"D0, P[a 2], (!!str)::c\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a.[0]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a 0], (!!str)::a\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `{a: [a,b,c]}`,
|
document: `{a: [a,b,c]}`,
|
||||||
|
|||||||
@@ -172,12 +172,9 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`\(`), literalToken(OpenBracket, false))
|
lexer.Add([]byte(`\(`), literalToken(OpenBracket, false))
|
||||||
lexer.Add([]byte(`\)`), literalToken(CloseBracket, true))
|
lexer.Add([]byte(`\)`), literalToken(CloseBracket, true))
|
||||||
|
|
||||||
|
// lexer.Add([]byte(`\.\[\]`), pathToken(false)) // traverseCollect(false)
|
||||||
lexer.Add([]byte(`\.\[`), literalToken(TraverseArrayCollect, false))
|
lexer.Add([]byte(`\.\[`), literalToken(TraverseArrayCollect, false))
|
||||||
lexer.Add([]byte(`\.\.`), opTokenWithPrefs(RecursiveDescent, nil, &RecursiveDescentPreferences{RecurseArray: true,
|
lexer.Add([]byte(`\.\.`), opToken(RecursiveDescent))
|
||||||
TraversePreferences: &TraversePreferences{FollowAlias: false, IncludeMapKeys: false}}))
|
|
||||||
|
|
||||||
lexer.Add([]byte(`\.\.\.`), opTokenWithPrefs(RecursiveDescent, nil, &RecursiveDescentPreferences{RecurseArray: true,
|
|
||||||
TraversePreferences: &TraversePreferences{FollowAlias: false, IncludeMapKeys: true}}))
|
|
||||||
|
|
||||||
lexer.Add([]byte(`,`), opToken(Union))
|
lexer.Add([]byte(`,`), opToken(Union))
|
||||||
lexer.Add([]byte(`:\s*`), opToken(CreateMap))
|
lexer.Add([]byte(`:\s*`), opToken(CreateMap))
|
||||||
@@ -219,6 +216,8 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
|
|
||||||
lexer.Add([]byte(`\s*\|=\s*`), opTokenWithPrefs(Assign, nil, &AssignOpPreferences{true}))
|
lexer.Add([]byte(`\s*\|=\s*`), opTokenWithPrefs(Assign, nil, &AssignOpPreferences{true}))
|
||||||
|
|
||||||
|
// lexer.Add([]byte(`\.\[-?[0-9]+\]`), arrayIndextoken(true)) // traverseCollect(true)
|
||||||
|
|
||||||
lexer.Add([]byte("( |\t|\n|\r)+"), skip)
|
lexer.Add([]byte("( |\t|\n|\r)+"), skip)
|
||||||
|
|
||||||
lexer.Add([]byte(`d[0-9]+`), documentToken())
|
lexer.Add([]byte(`d[0-9]+`), documentToken())
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: yq
|
name: yq
|
||||||
version: '4.2.0'
|
version: '4.1.0'
|
||||||
summary: A lightweight and portable command-line YAML processor
|
summary: A lightweight and portable command-line YAML processor
|
||||||
description: |
|
description: |
|
||||||
The aim of the project is to be the jq or sed of yaml files.
|
The aim of the project is to be the jq or sed of yaml files.
|
||||||
|
|||||||
Reference in New Issue
Block a user