From 13d1bbb45f01735156395ccde0029ad9633d63da Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Wed, 18 Oct 2023 12:11:53 +1100 Subject: [PATCH] Generic ast (#1829) Remove dependency on yaml.Node for internal AST representation. Yaml decoder is now just another decoder. --- acceptance_tests/load-file.sh | 4 +- examples/data1.yaml | 3 +- examples/mike.xml | 2 +- examples/sample.yaml | 13 +- go.mod | 4 +- go.sum | 15 +- pkg/yqlib/all_at_once_evaluator.go | 16 +- pkg/yqlib/all_at_once_evaluator_test.go | 22 +- pkg/yqlib/candidate_node.go | 433 ++- pkg/yqlib/candidate_node_goccy_yaml.go | 180 + pkg/yqlib/candidate_node_test.go | 149 + pkg/yqlib/candidate_node_yaml.go | 218 ++ pkg/yqlib/candidiate_node_json.go | 172 + pkg/yqlib/context.go | 6 +- pkg/yqlib/cover.out | 3111 +++++++++++++++++ pkg/yqlib/csv_test.go | 16 + pkg/yqlib/data_tree_navigator.go | 11 +- pkg/yqlib/decoder_base64.go | 10 +- pkg/yqlib/decoder_csv_object.go | 23 +- pkg/yqlib/decoder_goccy_yaml.go | 42 + pkg/yqlib/decoder_json.go | 71 +- pkg/yqlib/decoder_lua.go | 68 +- pkg/yqlib/decoder_properties.go | 36 +- pkg/yqlib/decoder_test.go | 5 + pkg/yqlib/decoder_toml.go | 85 +- pkg/yqlib/decoder_uri.go | 10 +- pkg/yqlib/decoder_xml.go | 34 +- pkg/yqlib/decoder_yaml.go | 38 +- pkg/yqlib/doc/operators/comment-operators.md | 1 - .../operators/create-collect-into-object.md | 1 + pkg/yqlib/doc/operators/document-index.md | 1 + pkg/yqlib/doc/operators/file-operators.md | 1 - pkg/yqlib/doc/usage/convert.md | 12 +- pkg/yqlib/doc/usage/xml.md | 4 +- pkg/yqlib/encoder.go | 8 +- pkg/yqlib/encoder_base64.go | 9 +- pkg/yqlib/encoder_csv.go | 35 +- pkg/yqlib/encoder_json.go | 16 +- pkg/yqlib/encoder_lua.go | 41 +- pkg/yqlib/encoder_properties.go | 21 +- pkg/yqlib/encoder_properties_test.go | 2 +- pkg/yqlib/encoder_sh.go | 9 +- pkg/yqlib/encoder_shellvariables.go | 15 +- pkg/yqlib/encoder_shellvariables_test.go | 2 +- pkg/yqlib/encoder_test.go | 18 +- pkg/yqlib/encoder_toml.go | 6 +- pkg/yqlib/encoder_uri.go | 9 +- pkg/yqlib/encoder_xml.go | 56 +- pkg/yqlib/encoder_yaml.go | 33 +- pkg/yqlib/goccy_yaml_test.go | 170 + pkg/yqlib/json_test.go | 67 +- pkg/yqlib/lexer_participle_test.go | 41 +- pkg/yqlib/lib.go | 195 +- pkg/yqlib/lib_test.go | 64 +- pkg/yqlib/lua_test.go | 32 + pkg/yqlib/matchKeyString.go | 1 - pkg/yqlib/operator_add.go | 142 +- pkg/yqlib/operator_add_test.go | 54 +- pkg/yqlib/operator_alternative.go | 15 +- pkg/yqlib/operator_alternative_test.go | 4 +- pkg/yqlib/operator_anchors_aliases.go | 64 +- pkg/yqlib/operator_anchors_aliases_test.go | 95 +- pkg/yqlib/operator_array_to_map_test.go | 2 +- pkg/yqlib/operator_assign.go | 12 +- pkg/yqlib/operator_assign_test.go | 50 +- pkg/yqlib/operator_booleans.go | 76 +- pkg/yqlib/operator_booleans_test.go | 14 +- pkg/yqlib/operator_collect.go | 18 +- pkg/yqlib/operator_collect_object.go | 50 +- pkg/yqlib/operator_collect_object_test.go | 38 +- pkg/yqlib/operator_collect_test.go | 7 + pkg/yqlib/operator_column.go | 5 +- pkg/yqlib/operator_comments.go | 42 +- pkg/yqlib/operator_comments_test.go | 60 +- pkg/yqlib/operator_compare.go | 27 +- pkg/yqlib/operator_contains.go | 33 +- pkg/yqlib/operator_create_map.go | 52 +- pkg/yqlib/operator_create_map_test.go | 32 + pkg/yqlib/operator_datetime.go | 57 +- pkg/yqlib/operator_datetime_test.go | 22 +- pkg/yqlib/operator_delete.go | 62 +- pkg/yqlib/operator_delete_test.go | 28 +- pkg/yqlib/operator_divide.go | 37 +- pkg/yqlib/operator_divide_test.go | 18 +- pkg/yqlib/operator_document_index.go | 5 +- pkg/yqlib/operator_document_index_test.go | 6 +- pkg/yqlib/operator_encoder_decoder.go | 20 +- pkg/yqlib/operator_encoder_decoder_test.go | 34 +- pkg/yqlib/operator_entries.go | 73 +- pkg/yqlib/operator_env.go | 38 +- pkg/yqlib/operator_env_test.go | 4 +- pkg/yqlib/operator_equals.go | 20 +- pkg/yqlib/operator_equals_test.go | 12 +- pkg/yqlib/operator_error.go | 2 +- pkg/yqlib/operator_error_test.go | 2 +- pkg/yqlib/operator_eval.go | 2 +- pkg/yqlib/operator_eval_test.go | 2 +- pkg/yqlib/operator_file.go | 8 +- pkg/yqlib/operator_filter.go | 2 +- pkg/yqlib/operator_flatten.go | 20 +- pkg/yqlib/operator_flatten_test.go | 8 +- pkg/yqlib/operator_group_by.go | 27 +- pkg/yqlib/operator_has.go | 16 +- pkg/yqlib/operator_has_test.go | 2 +- pkg/yqlib/operator_keys.go | 37 +- pkg/yqlib/operator_keys_test.go | 2 +- pkg/yqlib/operator_kind.go | 17 +- pkg/yqlib/operator_length.go | 22 +- pkg/yqlib/operator_line.go | 5 +- pkg/yqlib/operator_load.go | 14 +- pkg/yqlib/operator_load_test.go | 16 +- pkg/yqlib/operator_map.go | 2 +- pkg/yqlib/operator_map_test.go | 6 +- pkg/yqlib/operator_modulo.go | 31 +- pkg/yqlib/operator_modulo_test.go | 14 +- pkg/yqlib/operator_multiply.go | 111 +- pkg/yqlib/operator_multiply_test.go | 26 +- pkg/yqlib/operator_path.go | 31 +- pkg/yqlib/operator_path_test.go | 12 +- pkg/yqlib/operator_pick.go | 42 +- pkg/yqlib/operator_pick_test.go | 6 +- pkg/yqlib/operator_pipe_test.go | 2 +- pkg/yqlib/operator_recursive_descent.go | 8 +- pkg/yqlib/operator_reverse.go | 19 +- pkg/yqlib/operator_select.go | 7 +- pkg/yqlib/operator_select_test.go | 12 +- pkg/yqlib/operator_shuffle.go | 13 +- pkg/yqlib/operator_shuffle_test.go | 2 +- pkg/yqlib/operator_slice.go | 26 +- pkg/yqlib/operator_sort.go | 44 +- pkg/yqlib/operator_sort_keys.go | 17 +- pkg/yqlib/operator_sort_keys_test.go | 4 +- pkg/yqlib/operator_sort_test.go | 4 +- pkg/yqlib/operator_split_document.go | 3 +- pkg/yqlib/operator_strings.go | 152 +- pkg/yqlib/operator_strings_test.go | 18 +- pkg/yqlib/operator_style.go | 43 +- pkg/yqlib/operator_style_test.go | 8 +- pkg/yqlib/operator_subtract.go | 68 +- pkg/yqlib/operator_subtract_test.go | 18 +- pkg/yqlib/operator_tag.go | 11 +- pkg/yqlib/operator_tag_test.go | 18 +- pkg/yqlib/operator_to_number.go | 16 +- pkg/yqlib/operator_traverse_path.go | 126 +- pkg/yqlib/operator_traverse_path_test.go | 103 +- pkg/yqlib/operator_union.go | 19 +- pkg/yqlib/operator_union_test.go | 2 +- pkg/yqlib/operator_unique.go | 17 +- pkg/yqlib/operator_unique_test.go | 14 +- pkg/yqlib/operator_value.go | 12 +- pkg/yqlib/operator_variables.go | 5 +- pkg/yqlib/operator_variables_test.go | 6 +- pkg/yqlib/operator_with_test.go | 8 +- pkg/yqlib/operators.go | 22 +- pkg/yqlib/operators_test.go | 28 +- pkg/yqlib/ordered_map.go | 14 - pkg/yqlib/ordered_map_json.go | 83 - pkg/yqlib/ordered_map_yaml.go | 79 - pkg/yqlib/printer.go | 20 +- pkg/yqlib/printer_test.go | 24 +- pkg/yqlib/printer_writer.go | 9 +- pkg/yqlib/properties_test.go | 36 + pkg/yqlib/recipes_test.go | 6 +- pkg/yqlib/stream_evaluator.go | 15 +- pkg/yqlib/string_evaluator.go | 4 +- pkg/yqlib/toml_test.go | 24 + pkg/yqlib/utils.go | 6 +- pkg/yqlib/xml_test.go | 16 +- pkg/yqlib/yaml_test.go | 109 + project-words.txt | 3 +- test/utils.go | 12 - 171 files changed, 6398 insertions(+), 2417 deletions(-) create mode 100644 pkg/yqlib/candidate_node_goccy_yaml.go create mode 100644 pkg/yqlib/candidate_node_test.go create mode 100644 pkg/yqlib/candidate_node_yaml.go create mode 100644 pkg/yqlib/candidiate_node_json.go create mode 100644 pkg/yqlib/cover.out create mode 100644 pkg/yqlib/decoder_goccy_yaml.go create mode 100644 pkg/yqlib/goccy_yaml_test.go delete mode 100644 pkg/yqlib/ordered_map.go delete mode 100644 pkg/yqlib/ordered_map_json.go delete mode 100644 pkg/yqlib/ordered_map_yaml.go create mode 100644 pkg/yqlib/yaml_test.go diff --git a/acceptance_tests/load-file.sh b/acceptance_tests/load-file.sh index 48ebb6c8a00..4a64295cd87 100755 --- a/acceptance_tests/load-file.sh +++ b/acceptance_tests/load-file.sh @@ -9,7 +9,7 @@ testLoadFileNotExist() { testLoadFileExpNotExist() { result=$(./yq e -n 'load(.a)' 2>&1) assertEquals 1 $? - assertEquals "Error: Filename expression returned nil" "$result" + assertEquals "Error: filename expression returned nil" "$result" } testStrLoadFileNotExist() { @@ -21,7 +21,7 @@ testStrLoadFileNotExist() { testStrLoadFileExpNotExist() { result=$(./yq e -n 'strload(.a)' 2>&1) assertEquals 1 $? - assertEquals "Error: Filename expression returned nil" "$result" + assertEquals "Error: filename expression returned nil" "$result" } source ./scripts/shunit2 \ No newline at end of file diff --git a/examples/data1.yaml b/examples/data1.yaml index 850ab075836..a15395faa52 100644 --- a/examples/data1.yaml +++ b/examples/data1.yaml @@ -1 +1,2 @@ -["foobar", "foobaz", "blarp"] \ No newline at end of file +a: #things + meow \ No newline at end of file diff --git a/examples/mike.xml b/examples/mike.xml index b582fff1081..df8e8c9a058 100644 --- a/examples/mike.xml +++ b/examples/mike.xml @@ -1 +1 @@ -3 \ No newline at end of file +boing \ No newline at end of file diff --git a/examples/sample.yaml b/examples/sample.yaml index 9b925d75c7b..8e7fa374bd7 100644 --- a/examples/sample.yaml +++ b/examples/sample.yaml @@ -1,11 +1,2 @@ -# Some doc - -a: true -b: - c: 2 - d: [3, 4, 5] - e: - - name: fred - value: 3 - - name: sam - value: 4 \ No newline at end of file + # things +a: apple \ No newline at end of file diff --git a/go.mod b/go.mod index c755e5f0afa..43f71a24365 100644 --- a/go.mod +++ b/go.mod @@ -25,9 +25,9 @@ require ( require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect golang.org/x/sys v0.13.0 // indirect - golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect ) go 1.20 diff --git a/go.sum b/go.sum index fde4c7ca6b2..195442fd520 100644 --- a/go.sum +++ b/go.sum @@ -15,22 +15,27 @@ github.com/elliotchance/orderedmap v1.5.0 h1:1IsExUsjv5XNBD3ZdC7jkAAqLWOOKdbPTmk github.com/elliotchance/orderedmap v1.5.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ= github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= @@ -52,15 +57,17 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE= github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE= diff --git a/pkg/yqlib/all_at_once_evaluator.go b/pkg/yqlib/all_at_once_evaluator.go index 4dbed3d1343..bdeddd200cb 100644 --- a/pkg/yqlib/all_at_once_evaluator.go +++ b/pkg/yqlib/all_at_once_evaluator.go @@ -2,8 +2,6 @@ package yqlib import ( "container/list" - - yaml "gopkg.in/yaml.v3" ) // A yaml expression evaluator that runs the expression once against all files/nodes in memory. @@ -11,7 +9,7 @@ type Evaluator interface { EvaluateFiles(expression string, filenames []string, printer Printer, decoder Decoder) error // EvaluateNodes takes an expression and one or more yaml nodes, returning a list of matching candidate nodes - EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error) + EvaluateNodes(expression string, nodes ...*CandidateNode) (*list.List, error) // EvaluateCandidateNodes takes an expression and list of candidate nodes, returning a list of matching candidate nodes EvaluateCandidateNodes(expression string, inputCandidateNodes *list.List) (*list.List, error) @@ -26,10 +24,10 @@ func NewAllAtOnceEvaluator() Evaluator { return &allAtOnceEvaluator{treeNavigator: NewDataTreeNavigator()} } -func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error) { +func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*CandidateNode) (*list.List, error) { inputCandidates := list.New() for _, node := range nodes { - inputCandidates.PushBack(&CandidateNode{Node: node}) + inputCandidates.PushBack(node) } return e.EvaluateCandidateNodes(expression, inputCandidates) } @@ -65,13 +63,7 @@ func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string } if allDocuments.Len() == 0 { - candidateNode := &CandidateNode{ - Document: 0, - Filename: "", - Node: &yaml.Node{Kind: yaml.DocumentNode, Content: []*yaml.Node{{Tag: "!!null", Kind: yaml.ScalarNode}}}, - FileIndex: 0, - LeadingContent: "", - } + candidateNode := createScalarNode(nil, "") allDocuments.PushBack(candidateNode) } diff --git a/pkg/yqlib/all_at_once_evaluator_test.go b/pkg/yqlib/all_at_once_evaluator_test.go index 2e9abc4370f..c3e49c4509a 100644 --- a/pkg/yqlib/all_at_once_evaluator_test.go +++ b/pkg/yqlib/all_at_once_evaluator_test.go @@ -1,6 +1,8 @@ package yqlib import ( + "bufio" + "strings" "testing" "github.com/mikefarah/yq/v4/test" @@ -18,7 +20,7 @@ var evaluateNodesScenario = []expressionScenario{ document: `a: hello`, expression: `.`, expected: []string{ - "D0, P[], (doc)::a: hello\n", + "D0, P[], (!!map)::a: hello\n", }, }, { @@ -32,9 +34,23 @@ var evaluateNodesScenario = []expressionScenario{ func TestAllAtOnceEvaluateNodes(t *testing.T) { var evaluator = NewAllAtOnceEvaluator() + // logging.SetLevel(logging.DEBUG, "") for _, tt := range evaluateNodesScenario { - node := test.ParseData(tt.document) - list, _ := evaluator.EvaluateNodes(tt.expression, &node) + decoder := NewYamlDecoder(NewDefaultYamlPreferences()) + reader := bufio.NewReader(strings.NewReader(tt.document)) + err := decoder.Init(reader) + if err != nil { + t.Error(err) + return + } + candidateNode, errorReading := decoder.Decode() + + if errorReading != nil { + t.Error(errorReading) + return + } + + list, _ := evaluator.EvaluateNodes(tt.expression, candidateNode) test.AssertResultComplex(t, tt.expected, resultsToString(t, list)) } } diff --git a/pkg/yqlib/candidate_node.go b/pkg/yqlib/candidate_node.go index 24a5d43fb27..fbee0d1097d 100644 --- a/pkg/yqlib/candidate_node.go +++ b/pkg/yqlib/candidate_node.go @@ -3,51 +3,189 @@ package yqlib import ( "container/list" "fmt" + "strconv" "strings" +) + +type Kind uint32 + +const ( + SequenceNode Kind = 1 << iota + MappingNode + ScalarNode + AliasNode +) + +type Style uint32 - "github.com/jinzhu/copier" - yaml "gopkg.in/yaml.v3" +const ( + TaggedStyle Style = 1 << iota + DoubleQuotedStyle + SingleQuotedStyle + LiteralStyle + FoldedStyle + FlowStyle ) +func createStringScalarNode(stringValue string) *CandidateNode { + var node = &CandidateNode{Kind: ScalarNode} + node.Value = stringValue + node.Tag = "!!str" + return node +} + +func createScalarNode(value interface{}, stringValue string) *CandidateNode { + var node = &CandidateNode{Kind: ScalarNode} + node.Value = stringValue + + switch value.(type) { + case float32, float64: + node.Tag = "!!float" + case int, int64, int32: + node.Tag = "!!int" + case bool: + node.Tag = "!!bool" + case string: + node.Tag = "!!str" + case nil: + node.Tag = "!!null" + } + return node +} + type CandidateNode struct { - Node *yaml.Node // the actual node + Kind Kind + Style Style + + Tag string + Value string + Anchor string + Alias *CandidateNode + Content []*CandidateNode + + HeadComment string + LineComment string + FootComment string + Parent *CandidateNode // parent node - Key *yaml.Node // node key, if this is a value from a map (or index in an array) + Key *CandidateNode // node key, if this is a value from a map (or index in an array) + + LeadingContent string - LeadingContent string - TrailingContent string + document uint // the document index of this node + filename string - Path []interface{} /// the path we took to get to this node - Document uint // the document index of this node - Filename string - FileIndex int + Line int + Column int + + fileIndex int // when performing op against all nodes given, this will treat all the nodes as one // (e.g. top level cross document merge). This property does not propagate to child nodes. EvaluateTogether bool IsMapKey bool } +func (n *CandidateNode) CreateChild() *CandidateNode { + return &CandidateNode{ + Parent: n, + } +} + +func (n *CandidateNode) SetDocument(idx uint) { + n.document = idx +} + +func (n *CandidateNode) GetDocument() uint { + // defer to parent + if n.Parent != nil { + return n.Parent.GetDocument() + } + return n.document +} + +func (n *CandidateNode) SetFilename(name string) { + n.filename = name +} + +func (n *CandidateNode) GetFilename() string { + if n.Parent != nil { + return n.Parent.GetFilename() + } + return n.filename +} + +func (n *CandidateNode) SetFileIndex(idx int) { + n.fileIndex = idx +} + +func (n *CandidateNode) GetFileIndex() int { + if n.Parent != nil { + return n.Parent.GetFileIndex() + } + return n.fileIndex +} + func (n *CandidateNode) GetKey() string { keyPrefix := "" if n.IsMapKey { - keyPrefix = "key-" + keyPrefix = fmt.Sprintf("key-%v-", n.Value) + } + key := "" + if n.Key != nil { + key = n.Key.Value + } + return fmt.Sprintf("%v%v - %v", keyPrefix, n.GetDocument(), key) +} + +func (n *CandidateNode) getParsedKey() interface{} { + if n.IsMapKey { + return n.Value + } + if n.Key == nil { + return nil + } + if n.Key.Tag == "!!str" { + return n.Key.Value } - return fmt.Sprintf("%v%v - %v", keyPrefix, n.Document, n.Path) + index, err := parseInt(n.Key.Value) + if err != nil { + return n.Key.Value + } + return index + } -func (n *CandidateNode) GetNiceTag() string { - return unwrapDoc(n.Node).Tag +func (n *CandidateNode) GetPath() []interface{} { + key := n.getParsedKey() + if n.Parent != nil && key != nil { + return append(n.Parent.GetPath(), key) + } + + if key != nil { + return []interface{}{key} + } + return make([]interface{}, 0) } func (n *CandidateNode) GetNicePath() string { - if n.Path != nil && len(n.Path) >= 0 { - pathStr := make([]string, len(n.Path)) - for i, v := range n.Path { - pathStr[i] = fmt.Sprintf("%v", v) + var sb strings.Builder + path := n.GetPath() + for i, element := range path { + elementStr := fmt.Sprintf("%v", element) + switch element.(type) { + case int: + sb.WriteString("[" + elementStr + "]") + default: + if i == 0 { + sb.WriteString(elementStr) + } else if strings.ContainsRune(elementStr, '.') { + sb.WriteString("[" + elementStr + "]") + } else { + sb.WriteString("." + elementStr) + } } - return strings.Join(pathStr, ".") } - return "" + return sb.String() } func (n *CandidateNode) AsList() *list.List { @@ -56,134 +194,233 @@ func (n *CandidateNode) AsList() *list.List { return elMap } -func (n *CandidateNode) CreateChildInMap(key *yaml.Node, node *yaml.Node) *CandidateNode { - var value interface{} - if key != nil { - value = key.Value +func (n *CandidateNode) SetParent(parent *CandidateNode) { + n.Parent = parent +} + +func (n *CandidateNode) AddKeyValueChild(rawKey *CandidateNode, rawValue *CandidateNode) (*CandidateNode, *CandidateNode) { + key := rawKey.Copy() + key.SetParent(n) + key.IsMapKey = true + + value := rawValue.Copy() + value.SetParent(n) + value.Key = key + + n.Content = append(n.Content, key, value) + return key, value +} + +func (n *CandidateNode) AddChild(rawChild *CandidateNode) { + value := rawChild.Copy() + value.SetParent(n) + if value.Key != nil { + value.Key.SetParent(n) + } else { + index := len(n.Content) + keyNode := createScalarNode(index, fmt.Sprintf("%v", index)) + keyNode.SetParent(n) + value.Key = keyNode } - return &CandidateNode{ - Node: node, - Path: n.createChildPath(value), - Parent: n, - Key: key, - Document: n.Document, - Filename: n.Filename, - FileIndex: n.FileIndex, + n.Content = append(n.Content, value) +} + +func (n *CandidateNode) AddChildren(children []*CandidateNode) { + if n.Kind == MappingNode { + for i := 0; i < len(children); i += 2 { + key := children[i] + value := children[i+1] + n.AddKeyValueChild(key, value) + } + + } else { + for _, rawChild := range children { + n.AddChild(rawChild) + } } } -func (n *CandidateNode) CreateChildInArray(index int, node *yaml.Node) *CandidateNode { - return &CandidateNode{ - Node: node, - Path: n.createChildPath(index), - Parent: n, - Key: &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", index), Tag: "!!int"}, - Document: n.Document, - Filename: n.Filename, - FileIndex: n.FileIndex, +func (n *CandidateNode) GetValueRep() (interface{}, error) { + log.Debugf("GetValueRep for %v value: %v", n.GetNicePath(), n.Value) + realTag := n.guessTagFromCustomType() + + switch realTag { + case "!!int": + _, val, err := parseInt64(n.Value) + return val, err + case "!!float": + // need to test this + return strconv.ParseFloat(n.Value, 64) + case "!!bool": + return isTruthyNode(n), nil + case "!!null": + return nil, nil } + + return n.Value, nil } -func (n *CandidateNode) CreateReplacement(node *yaml.Node) *CandidateNode { - return &CandidateNode{ - Node: node, - Path: n.createChildPath(nil), - Parent: n.Parent, - Key: n.Key, - IsMapKey: n.IsMapKey, - Document: n.Document, - Filename: n.Filename, - FileIndex: n.FileIndex, +func (n *CandidateNode) guessTagFromCustomType() string { + if strings.HasPrefix(n.Tag, "!!") { + return n.Tag + } else if n.Value == "" { + log.Debug("guessTagFromCustomType: node has no value to guess the type with") + return n.Tag + } + dataBucket, errorReading := parseSnippet(n.Value) + + if errorReading != nil { + log.Debug("guessTagFromCustomType: could not guess underlying tag type %v", errorReading) + return n.Tag + } + guessedTag := dataBucket.Tag + log.Info("im guessing the tag %v is a %v", n.Tag, guessedTag) + return guessedTag +} + +func (n *CandidateNode) CreateReplacement(kind Kind, tag string, value string) *CandidateNode { + node := &CandidateNode{ + Kind: kind, + Tag: tag, + Value: value, + } + return n.CopyAsReplacement(node) +} + +func (n *CandidateNode) CopyAsReplacement(replacement *CandidateNode) *CandidateNode { + newCopy := replacement.Copy() + newCopy.Parent = n.Parent + + if n.IsMapKey { + newCopy.Key = n + } else { + newCopy.Key = n.Key } + + return newCopy } -func (n *CandidateNode) CreateReplacementWithDocWrappers(node *yaml.Node) *CandidateNode { - replacement := n.CreateReplacement(node) +func (n *CandidateNode) CreateReplacementWithComments(kind Kind, tag string, style Style) *CandidateNode { + replacement := n.CreateReplacement(kind, tag, "") replacement.LeadingContent = n.LeadingContent - replacement.TrailingContent = n.TrailingContent + replacement.HeadComment = n.HeadComment + replacement.LineComment = n.LineComment + replacement.FootComment = n.FootComment + replacement.Style = style return replacement } -func (n *CandidateNode) createChildPath(path interface{}) []interface{} { - if path == nil { - newPath := make([]interface{}, len(n.Path)) - copy(newPath, n.Path) - return newPath - } +func (n *CandidateNode) Copy() *CandidateNode { + return n.doCopy(true) +} - //don't use append as they may actually modify the path of the original node! - newPath := make([]interface{}, len(n.Path)+1) - copy(newPath, n.Path) - newPath[len(n.Path)] = path - return newPath +func (n *CandidateNode) CopyWithoutContent() *CandidateNode { + return n.doCopy(false) } -func (n *CandidateNode) Copy() (*CandidateNode, error) { - clone := &CandidateNode{} - err := copier.Copy(clone, n) - if err != nil { - return nil, err +func (n *CandidateNode) doCopy(cloneContent bool) *CandidateNode { + var content []*CandidateNode + + var copyKey *CandidateNode + if n.Key != nil { + copyKey = n.Key.Copy() + } + + clone := &CandidateNode{ + Kind: n.Kind, + Style: n.Style, + + Tag: n.Tag, + Value: n.Value, + Anchor: n.Anchor, + + // ok not to clone this, + // as its a reference to somewhere else. + Alias: n.Alias, + Content: content, + + HeadComment: n.HeadComment, + LineComment: n.LineComment, + FootComment: n.FootComment, + + Parent: n.Parent, + Key: copyKey, + + LeadingContent: n.LeadingContent, + + document: n.document, + filename: n.filename, + fileIndex: n.fileIndex, + + Line: n.Line, + Column: n.Column, + + EvaluateTogether: n.EvaluateTogether, + IsMapKey: n.IsMapKey, + } + + if cloneContent { + clone.AddChildren(n.Content) } - clone.Node = deepClone(n.Node) - return clone, nil + + return clone } // updates this candidate from the given candidate node func (n *CandidateNode) UpdateFrom(other *CandidateNode, prefs assignPreferences) { // if this is an empty map or empty array, use the style of other node. - if (n.Node.Kind != yaml.ScalarNode && len(n.Node.Content) == 0) || + if (n.Kind != ScalarNode && len(n.Content) == 0) || // if the tag has changed (e.g. from str to bool) - (guessTagFromCustomType(n.Node) != guessTagFromCustomType(other.Node)) { - n.Node.Style = other.Node.Style + (n.guessTagFromCustomType() != other.guessTagFromCustomType()) { + n.Style = other.Style } - n.Node.Content = deepCloneContent(other.Node.Content) - n.Node.Kind = other.Node.Kind - n.Node.Value = other.Node.Value + n.Content = make([]*CandidateNode, 0) + n.Kind = other.Kind + n.AddChildren(other.Content) + + n.Value = other.Value n.UpdateAttributesFrom(other, prefs) } func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignPreferences) { - log.Debug("UpdateAttributesFrom: n: %v other: %v", n.GetKey(), other.GetKey()) - if n.Node.Kind != other.Node.Kind { + log.Debug("UpdateAttributesFrom: n: %v other: %v", NodeToString(n), NodeToString(other)) + if n.Kind != other.Kind { // clear out the contents when switching to a different type // e.g. map to array - n.Node.Content = make([]*yaml.Node, 0) - n.Node.Value = "" + n.Content = make([]*CandidateNode, 0) + n.Value = "" } - n.Node.Kind = other.Node.Kind + n.Kind = other.Kind // don't clobber custom tags... - if prefs.ClobberCustomTags || strings.HasPrefix(n.Node.Tag, "!!") || n.Node.Tag == "" { - n.Node.Tag = other.Node.Tag + if prefs.ClobberCustomTags || strings.HasPrefix(n.Tag, "!!") || n.Tag == "" { + n.Tag = other.Tag } - n.Node.Alias = other.Node.Alias + n.Alias = other.Alias if !prefs.DontOverWriteAnchor { - n.Node.Anchor = other.Node.Anchor + n.Anchor = other.Anchor } // merge will pickup the style of the new thing // when autocreating nodes - if n.Node.Style == 0 { - n.Node.Style = other.Node.Style + if n.Style == 0 { + n.Style = other.Style } - if other.Node.FootComment != "" { - n.Node.FootComment = other.Node.FootComment - } - if other.TrailingContent != "" { - n.TrailingContent = other.TrailingContent + if other.FootComment != "" { + n.FootComment = other.FootComment } - if other.Node.HeadComment != "" { - n.Node.HeadComment = other.Node.HeadComment + if other.HeadComment != "" { + n.HeadComment = other.HeadComment } - if other.Node.LineComment != "" { - n.Node.LineComment = other.Node.LineComment + if other.LineComment != "" { + n.LineComment = other.LineComment } } diff --git a/pkg/yqlib/candidate_node_goccy_yaml.go b/pkg/yqlib/candidate_node_goccy_yaml.go new file mode 100644 index 00000000000..7974c7231f0 --- /dev/null +++ b/pkg/yqlib/candidate_node_goccy_yaml.go @@ -0,0 +1,180 @@ +package yqlib + +import ( + "fmt" + "strings" + + yaml "github.com/goccy/go-yaml" + "github.com/goccy/go-yaml/ast" + goccyToken "github.com/goccy/go-yaml/token" +) + +func (o *CandidateNode) goccyDecodeIntoChild(childNode ast.Node, cm yaml.CommentMap) (*CandidateNode, error) { + newChild := o.CreateChild() + + err := newChild.UnmarshalGoccyYAML(childNode, cm) + return newChild, err +} + +func (o *CandidateNode) UnmarshalGoccyYAML(node ast.Node, cm yaml.CommentMap) error { + log.Debugf("UnmarshalYAML %v", node) + log.Debugf("UnmarshalYAML %v", node.Type().String()) + log.Debugf("UnmarshalYAML Node Value: %v", node.String()) + log.Debugf("UnmarshalYAML Node GetComment: %v", node.GetComment()) + + if node.GetComment() != nil { + commentMapComments := cm[node.GetPath()] + for _, comment := range node.GetComment().Comments { + // need to use the comment map to find the position :/ + log.Debugf("%v has a comment of [%v]", node.GetPath(), comment.Token.Value) + for _, commentMapComment := range commentMapComments { + commentMapValue := strings.Join(commentMapComment.Texts, "\n") + if commentMapValue == comment.Token.Value { + log.Debug("found a matching entry in comment map") + // we found the comment in the comment map, + // now we can process the position + switch commentMapComment.Position { + case yaml.CommentHeadPosition: + o.HeadComment = comment.String() + log.Debug("its a head comment %v", comment.String()) + case yaml.CommentLinePosition: + o.LineComment = comment.String() + log.Debug("its a line comment %v", comment.String()) + case yaml.CommentFootPosition: + o.FootComment = comment.String() + log.Debug("its a foot comment %v", comment.String()) + } + } + } + + } + } + + o.Value = node.String() + switch node.Type() { + case ast.IntegerType: + o.Kind = ScalarNode + o.Tag = "!!int" + case ast.FloatType: + o.Kind = ScalarNode + o.Tag = "!!float" + case ast.BoolType: + o.Kind = ScalarNode + o.Tag = "!!bool" + case ast.NullType: + o.Kind = ScalarNode + o.Tag = "!!null" + o.Value = node.GetToken().Value + case ast.StringType: + o.Kind = ScalarNode + o.Tag = "!!str" + switch node.GetToken().Type { + case goccyToken.SingleQuoteType: + o.Style = SingleQuotedStyle + case goccyToken.DoubleQuoteType: + o.Style = DoubleQuotedStyle + } + o.Value = node.(*ast.StringNode).Value + log.Debugf("string value %v", node.(*ast.StringNode).Value) + case ast.LiteralType: + o.Kind = ScalarNode + o.Tag = "!!str" + o.Style = LiteralStyle + astLiteral := node.(*ast.LiteralNode) + log.Debugf("astLiteral.Start.Type %v", astLiteral.Start.Type) + if astLiteral.Start.Type == goccyToken.FoldedType { + log.Debugf("folded Type %v", astLiteral.Start.Type) + o.Style = FoldedStyle + } + log.Debug("start value: %v ", node.(*ast.LiteralNode).Start.Value) + log.Debug("start value: %v ", node.(*ast.LiteralNode).Start.Type) + // TODO: here I could put the original value with line breaks + // to solve the multiline > problem + o.Value = astLiteral.Value.Value + case ast.TagType: + if err := o.UnmarshalGoccyYAML(node.(*ast.TagNode).Value, cm); err != nil { + return err + } + o.Tag = node.(*ast.TagNode).Start.Value + case ast.MappingType: + log.Debugf("UnmarshalYAML - a mapping node") + o.Kind = MappingNode + o.Tag = "!!map" + + mappingNode := node.(*ast.MappingNode) + if mappingNode.IsFlowStyle { + o.Style = FlowStyle + } + for _, mappingValueNode := range mappingNode.Values { + err := o.goccyProcessMappingValueNode(mappingValueNode, cm) + if err != nil { + return ast.ErrInvalidAnchorName + } + } + if mappingNode.FootComment != nil { + log.Debugf("mapping node has a foot comment of: %v", mappingNode.FootComment) + o.FootComment = mappingNode.FootComment.String() + } + case ast.MappingValueType: + log.Debugf("UnmarshalYAML - a mapping node") + o.Kind = MappingNode + o.Tag = "!!map" + mappingValueNode := node.(*ast.MappingValueNode) + err := o.goccyProcessMappingValueNode(mappingValueNode, cm) + if err != nil { + return ast.ErrInvalidAnchorName + } + case ast.SequenceType: + log.Debugf("UnmarshalYAML - a sequence node") + o.Kind = SequenceNode + o.Tag = "!!seq" + sequenceNode := node.(*ast.SequenceNode) + if sequenceNode.IsFlowStyle { + o.Style = FlowStyle + } + astSeq := sequenceNode.Values + o.Content = make([]*CandidateNode, len(astSeq)) + for i := 0; i < len(astSeq); i++ { + keyNode := o.CreateChild() + keyNode.IsMapKey = true + keyNode.Tag = "!!int" + keyNode.Kind = ScalarNode + keyNode.Value = fmt.Sprintf("%v", i) + + valueNode, err := o.goccyDecodeIntoChild(astSeq[i], cm) + if err != nil { + return err + } + + valueNode.Key = keyNode + o.Content[i] = valueNode + } + + default: + log.Debugf("UnmarshalYAML - node idea of the type!!") + } + log.Debugf("KIND: %v", o.Kind) + return nil +} + +func (o *CandidateNode) goccyProcessMappingValueNode(mappingEntry *ast.MappingValueNode, cm yaml.CommentMap) error { + log.Debug("UnmarshalYAML MAP KEY entry %v", mappingEntry.Key) + keyNode, err := o.goccyDecodeIntoChild(mappingEntry.Key, cm) + if err != nil { + return err + } + keyNode.IsMapKey = true + + log.Debug("UnmarshalYAML MAP VALUE entry %v", mappingEntry.Value) + valueNode, err := o.goccyDecodeIntoChild(mappingEntry.Value, cm) + if err != nil { + return err + } + + if mappingEntry.FootComment != nil { + valueNode.FootComment = mappingEntry.FootComment.String() + } + o.AddKeyValueChild(keyNode, valueNode) + + return nil +} diff --git a/pkg/yqlib/candidate_node_test.go b/pkg/yqlib/candidate_node_test.go new file mode 100644 index 00000000000..1ca707ba9d7 --- /dev/null +++ b/pkg/yqlib/candidate_node_test.go @@ -0,0 +1,149 @@ +package yqlib + +import ( + "fmt" + "testing" + + "github.com/mikefarah/yq/v4/test" +) + +type valueRepScenario struct { + input string + tag string + expected interface{} +} + +var valueRepScenarios = []valueRepScenario{ + { + input: `"cat"`, + expected: `"cat"`, + }, + { + input: `3`, + expected: int64(3), + }, + { + input: `3.1`, + expected: float64(3.1), + }, + { + input: `true`, + expected: true, + }, + { + input: `y`, + tag: "!!bool", + expected: true, + }, + { + tag: "!!null", + expected: nil, + }, +} + +func TestCandidateNodeGetValueRepScenarios(t *testing.T) { + for _, tt := range valueRepScenarios { + node := CandidateNode{Value: tt.input, Tag: tt.tag} + actual, err := node.GetValueRep() + if err != nil { + t.Error(err) + return + } + test.AssertResult(t, tt.expected, actual) + } +} + +func TestCandidateNodeChildWhenParentUpdated(t *testing.T) { + parent := CandidateNode{} + child := parent.CreateChild() + parent.SetDocument(1) + parent.SetFileIndex(2) + parent.SetFilename("meow") + test.AssertResultWithContext(t, "meow", child.GetFilename(), "filename") + test.AssertResultWithContext(t, 2, child.GetFileIndex(), "file index") + test.AssertResultWithContext(t, uint(1), child.GetDocument(), "document index") +} + +type createScalarNodeScenario struct { + value interface{} + stringValue string + expectedTag string +} + +var createScalarScenarios = []createScalarNodeScenario{ + { + value: "mike", + stringValue: "mike", + expectedTag: "!!str", + }, + { + value: 3, + stringValue: "3", + expectedTag: "!!int", + }, + { + value: 3.1, + stringValue: "3.1", + expectedTag: "!!float", + }, + { + value: true, + stringValue: "true", + expectedTag: "!!bool", + }, + { + value: nil, + stringValue: "~", + expectedTag: "!!null", + }, +} + +func TestCreateScalarNodeScenarios(t *testing.T) { + for _, tt := range createScalarScenarios { + actual := createScalarNode(tt.value, tt.stringValue) + test.AssertResultWithContext(t, tt.stringValue, actual.Value, fmt.Sprintf("Value for: Value: [%v], String: %v", tt.value, tt.stringValue)) + test.AssertResultWithContext(t, tt.expectedTag, actual.Tag, fmt.Sprintf("Value for: Value: [%v], String: %v", tt.value, tt.stringValue)) + } +} + +func TestGetKeyForMapValue(t *testing.T) { + key := createStringScalarNode("yourKey") + n := CandidateNode{Key: key, Value: "meow", document: 3} + test.AssertResult(t, "3 - yourKey", n.GetKey()) +} + +func TestGetKeyForMapKey(t *testing.T) { + key := createStringScalarNode("yourKey") + key.IsMapKey = true + key.document = 3 + test.AssertResult(t, "key-yourKey-3 - ", key.GetKey()) +} + +func TestGetKeyForValue(t *testing.T) { + n := CandidateNode{Value: "meow", document: 3} + test.AssertResult(t, "3 - ", n.GetKey()) +} + +func TestGetParsedKeyForMapKey(t *testing.T) { + key := createStringScalarNode("yourKey") + key.IsMapKey = true + key.document = 3 + test.AssertResult(t, "yourKey", key.getParsedKey()) +} + +func TestGetParsedKeyForLooseValue(t *testing.T) { + n := CandidateNode{Value: "meow", document: 3} + test.AssertResult(t, nil, n.getParsedKey()) +} + +func TestGetParsedKeyForMapValue(t *testing.T) { + key := createStringScalarNode("yourKey") + n := CandidateNode{Key: key, Value: "meow", document: 3} + test.AssertResult(t, "yourKey", n.getParsedKey()) +} + +func TestGetParsedKeyForArrayValue(t *testing.T) { + key := createScalarNode(4, "4") + n := CandidateNode{Key: key, Value: "meow", document: 3} + test.AssertResult(t, 4, n.getParsedKey()) +} diff --git a/pkg/yqlib/candidate_node_yaml.go b/pkg/yqlib/candidate_node_yaml.go new file mode 100644 index 00000000000..67f57a4803b --- /dev/null +++ b/pkg/yqlib/candidate_node_yaml.go @@ -0,0 +1,218 @@ +package yqlib + +import ( + "fmt" + + yaml "gopkg.in/yaml.v3" +) + +func MapYamlStyle(original yaml.Style) Style { + switch original { + case yaml.TaggedStyle: + return TaggedStyle + case yaml.DoubleQuotedStyle: + return DoubleQuotedStyle + case yaml.SingleQuotedStyle: + return SingleQuotedStyle + case yaml.LiteralStyle: + return LiteralStyle + case yaml.FoldedStyle: + return FoldedStyle + case yaml.FlowStyle: + return FlowStyle + case 0: + return 0 + } + return Style(original) +} + +func MapToYamlStyle(original Style) yaml.Style { + switch original { + case TaggedStyle: + return yaml.TaggedStyle + case DoubleQuotedStyle: + return yaml.DoubleQuotedStyle + case SingleQuotedStyle: + return yaml.SingleQuotedStyle + case LiteralStyle: + return yaml.LiteralStyle + case FoldedStyle: + return yaml.FoldedStyle + case FlowStyle: + return yaml.FlowStyle + case 0: + return 0 + } + return yaml.Style(original) +} + +func (o *CandidateNode) copyFromYamlNode(node *yaml.Node, anchorMap map[string]*CandidateNode) { + o.Style = MapYamlStyle(node.Style) + + o.Tag = node.Tag + o.Value = node.Value + o.Anchor = node.Anchor + + if o.Anchor != "" { + anchorMap[o.Anchor] = o + log.Debug("set anchor %v to %v", o.Anchor, NodeToString(o)) + } + + // its a single alias + if node.Alias != nil && node.Alias.Anchor != "" { + 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 + + o.Line = node.Line + o.Column = node.Column +} + +func (o *CandidateNode) copyToYamlNode(node *yaml.Node) { + node.Style = MapToYamlStyle(o.Style) + + node.Tag = o.Tag + node.Value = o.Value + node.Anchor = o.Anchor + + // node.Alias = TODO - find Alias in our own structure + // might need to be a post process thing + + node.HeadComment = o.HeadComment + + node.LineComment = o.LineComment + node.FootComment = o.FootComment + + node.Line = o.Line + node.Column = o.Column +} + +func (o *CandidateNode) decodeIntoChild(childNode *yaml.Node, anchorMap map[string]*CandidateNode) (*CandidateNode, error) { + newChild := o.CreateChild() + + // null yaml.Nodes to not end up calling UnmarshalYAML + // so we call it explicitly + if childNode.Tag == "!!null" { + newChild.Kind = ScalarNode + newChild.copyFromYamlNode(childNode, anchorMap) + return newChild, nil + } + + err := newChild.UnmarshalYAML(childNode, anchorMap) + return newChild, err +} + +func (o *CandidateNode) UnmarshalYAML(node *yaml.Node, anchorMap map[string]*CandidateNode) error { + log.Debugf("UnmarshalYAML %v", node.Tag) + switch node.Kind { + case yaml.AliasNode: + log.Debug("UnmarshalYAML - alias from yaml: %v", o.Tag) + o.Kind = AliasNode + o.copyFromYamlNode(node, anchorMap) + return nil + case yaml.ScalarNode: + log.Debugf("UnmarshalYAML - a scalar") + o.Kind = ScalarNode + o.copyFromYamlNode(node, anchorMap) + return nil + case yaml.MappingNode: + log.Debugf("UnmarshalYAML - a mapping node") + o.Kind = MappingNode + o.copyFromYamlNode(node, anchorMap) + o.Content = make([]*CandidateNode, len(node.Content)) + for i := 0; i < len(node.Content); i += 2 { + + keyNode, err := o.decodeIntoChild(node.Content[i], anchorMap) + if err != nil { + return err + } + + keyNode.IsMapKey = true + + valueNode, err := o.decodeIntoChild(node.Content[i+1], anchorMap) + if err != nil { + return err + } + + valueNode.Key = keyNode + + o.Content[i] = keyNode + o.Content[i+1] = valueNode + } + log.Debugf("UnmarshalYAML - finished mapping node") + return nil + case yaml.SequenceNode: + log.Debugf("UnmarshalYAML - a sequence: %v", len(node.Content)) + o.Kind = SequenceNode + + o.copyFromYamlNode(node, anchorMap) + log.Debugf("node Style: %v", node.Style) + log.Debugf("o Style: %v", o.Style) + o.Content = make([]*CandidateNode, len(node.Content)) + for i := 0; i < len(node.Content); i++ { + keyNode := o.CreateChild() + keyNode.IsMapKey = true + keyNode.Tag = "!!int" + keyNode.Kind = ScalarNode + keyNode.Value = fmt.Sprintf("%v", i) + + valueNode, err := o.decodeIntoChild(node.Content[i], anchorMap) + if err != nil { + return err + } + + valueNode.Key = keyNode + o.Content[i] = valueNode + } + return nil + case 0: + // not sure when this happens + o.copyFromYamlNode(node, anchorMap) + log.Debugf("UnmarshalYAML - err.. %v", NodeToString(o)) + return nil + default: + return fmt.Errorf("orderedMap: invalid yaml node") + } +} + +func (o *CandidateNode) MarshalYAML() (*yaml.Node, error) { + log.Debug("MarshalYAML to yaml: %v", o.Tag) + switch o.Kind { + case AliasNode: + log.Debug("MarshalYAML - alias to yaml: %v", o.Tag) + target := &yaml.Node{Kind: yaml.AliasNode} + o.copyToYamlNode(target) + return target, nil + case ScalarNode: + log.Debug("MarshalYAML - scalar: %v", o.Value) + target := &yaml.Node{Kind: yaml.ScalarNode} + o.copyToYamlNode(target) + return target, nil + case MappingNode, SequenceNode: + targetKind := yaml.MappingNode + if o.Kind == SequenceNode { + targetKind = yaml.SequenceNode + } + target := &yaml.Node{Kind: targetKind} + o.copyToYamlNode(target) + log.Debugf("original style: %v", o.Style) + log.Debugf("original: %v, tag: %v, style: %v, kind: %v", NodeToString(o), target.Tag, target.Style, target.Kind == yaml.SequenceNode) + target.Content = make([]*yaml.Node, len(o.Content)) + for i := 0; i < len(o.Content); i++ { + + child, err := o.Content[i].MarshalYAML() + + if err != nil { + return nil, err + } + target.Content[i] = child + } + return target, nil + } + target := &yaml.Node{} + o.copyToYamlNode(target) + return target, nil +} diff --git a/pkg/yqlib/candidiate_node_json.go b/pkg/yqlib/candidiate_node_json.go new file mode 100644 index 00000000000..728e5afb7bd --- /dev/null +++ b/pkg/yqlib/candidiate_node_json.go @@ -0,0 +1,172 @@ +package yqlib + +import ( + "bytes" + "errors" + "fmt" + "io" + + "github.com/goccy/go-json" +) + +func (o *CandidateNode) setScalarFromJson(value interface{}) error { + o.Kind = ScalarNode + switch rawData := value.(type) { + case nil: + o.Tag = "!!null" + o.Value = "null" + case float64, float32: + o.Value = fmt.Sprintf("%v", value) + o.Tag = "!!float" + // json decoder returns ints as float. + if value == float64(int64(rawData.(float64))) { + // aha it's an int disguised as a float + o.Tag = "!!int" + o.Value = fmt.Sprintf("%v", int64(value.(float64))) + } + case int, int64, int32: + o.Value = fmt.Sprintf("%v", value) + o.Tag = "!!int" + case bool: + o.Value = fmt.Sprintf("%v", value) + o.Tag = "!!bool" + case string: + o.Value = rawData + o.Tag = "!!str" + default: + return fmt.Errorf("unrecognised type :( %v", rawData) + } + return nil +} + +func (o *CandidateNode) UnmarshalJSON(data []byte) error { + log.Debug("UnmarshalJSON") + switch data[0] { + case '{': + log.Debug("UnmarshalJSON - its a map!") + // its a map + o.Kind = MappingNode + o.Tag = "!!map" + + dec := json.NewDecoder(bytes.NewReader(data)) + _, err := dec.Token() // open object + if err != nil { + return err + } + + // cycle through k/v + var tok json.Token + for tok, err = dec.Token(); err == nil; tok, err = dec.Token() { + // we can expect two types: string or Delim. Delim automatically means + // that it is the closing bracket of the object, whereas string means + // that there is another key. + if _, ok := tok.(json.Delim); ok { + break + } + + childKey := o.CreateChild() + childKey.IsMapKey = true + childKey.Value = tok.(string) + childKey.Kind = ScalarNode + childKey.Tag = "!!str" + + childValue := o.CreateChild() + childValue.Key = childKey + + if err := dec.Decode(childValue); err != nil { + return err + } + o.Content = append(o.Content, childKey, childValue) + } + // unexpected error + if err != nil && !errors.Is(err, io.EOF) { + return err + } + return nil + case '[': + o.Kind = SequenceNode + o.Tag = "!!seq" + log.Debug("UnmarshalJSON - its an array!") + var children []*CandidateNode + if err := json.Unmarshal(data, &children); err != nil { + return err + } + // now we put the children into the content, and set a key value for them + for i, child := range children { + + if child == nil { + // need to represent it as a null scalar + child = createScalarNode(nil, "null") + } + childKey := o.CreateChild() + childKey.Kind = ScalarNode + childKey.Tag = "!!int" + childKey.Value = fmt.Sprintf("%v", i) + childKey.IsMapKey = true + + child.Parent = o + child.Key = childKey + o.Content = append(o.Content, child) + } + return nil + } + log.Debug("UnmarshalJSON - its a scalar!") + // otherwise, must be a scalar + var scalar interface{} + err := json.Unmarshal(data, &scalar) + + if err != nil { + return err + } + log.Debug("UnmarshalJSON - scalar is %v", scalar) + + return o.setScalarFromJson(scalar) + +} + +func (o *CandidateNode) MarshalJSON() ([]byte, error) { + log.Debugf("MarshalJSON %v", NodeToString(o)) + buf := new(bytes.Buffer) + enc := json.NewEncoder(buf) + enc.SetIndent("", " ") + enc.SetEscapeHTML(false) // do not escape html chars e.g. &, <, > + + switch o.Kind { + case AliasNode: + log.Debugf("MarshalJSON AliasNode") + err := enc.Encode(o.Alias) + return buf.Bytes(), err + case ScalarNode: + log.Debugf("MarshalJSON ScalarNode") + value, err := o.GetValueRep() + if err != nil { + return buf.Bytes(), err + } + err = enc.Encode(value) + return buf.Bytes(), err + case MappingNode: + log.Debugf("MarshalJSON MappingNode") + buf.WriteByte('{') + for i := 0; i < len(o.Content); i += 2 { + if err := enc.Encode(o.Content[i].Value); err != nil { + return nil, err + } + buf.WriteByte(':') + if err := enc.Encode(o.Content[i+1]); err != nil { + return nil, err + } + if i != len(o.Content)-2 { + buf.WriteByte(',') + } + } + buf.WriteByte('}') + return buf.Bytes(), nil + case SequenceNode: + log.Debugf("MarshalJSON SequenceNode") + err := enc.Encode(o.Content) + return buf.Bytes(), err + default: + err := enc.Encode(nil) + return buf.Bytes(), err + } +} diff --git a/pkg/yqlib/context.go b/pkg/yqlib/context.go index 17cddb3cbbd..d2dc656bf0f 100644 --- a/pkg/yqlib/context.go +++ b/pkg/yqlib/context.go @@ -83,11 +83,7 @@ func (n *Context) DeepClone() Context { // copier doesn't do lists properly for some reason clone.MatchingNodes = list.New() for el := n.MatchingNodes.Front(); el != nil; el = el.Next() { - clonedNode, err := el.Value.(*CandidateNode).Copy() - if err != nil { - log.Error("Error cloning context :(") - panic(err) - } + clonedNode := el.Value.(*CandidateNode).Copy() clone.MatchingNodes.PushBack(clonedNode) } diff --git a/pkg/yqlib/cover.out b/pkg/yqlib/cover.out new file mode 100644 index 00000000000..6c07f264a92 --- /dev/null +++ b/pkg/yqlib/cover.out @@ -0,0 +1,3111 @@ +mode: set +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:22.40,25.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:27.108,29.29 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:29.29,31.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:32.2,32.62 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:35.120,37.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:37.16,39.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:40.2,41.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:41.16,43.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:44.2,44.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:47.123,51.37 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:51.37,53.17 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:53.17,55.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:57.3,58.17 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:58.17,60.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:61.3,62.28 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:65.2,65.29 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:65.29,68.3 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:70.2,71.16 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:71.16,73.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/all_at_once_evaluator.go:74.2,74.38 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:30.64,35.2 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:37.77,41.22 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:42.24,43.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:44.25,45.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:46.12,47.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:48.14,49.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:50.11,51.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:53.2,53.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:88.54,92.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:94.47,96.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:98.44,100.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:100.21,102.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:103.2,103.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:106.50,108.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:110.46,111.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:111.21,113.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:114.2,114.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:117.47,119.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:121.44,122.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:122.21,124.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:125.2,125.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:128.41,130.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:130.16,132.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:133.2,134.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:134.18,136.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:137.2,137.66 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:140.57,145.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:147.45,149.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:151.52,152.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:152.16,154.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:155.2,155.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:155.18,157.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:158.2,158.26 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:158.26,160.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:161.2,162.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:162.16,164.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:165.2,165.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:169.49,171.35 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:171.35,173.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:175.2,175.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:175.16,177.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:178.2,178.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:181.46,184.31 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:184.31,186.25 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:187.12,188.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:189.11,190.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:190.14,192.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:192.10,192.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:192.52,194.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:194.10,196.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:199.2,199.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:202.45,206.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:208.58,210.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:212.123,223.2 8 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:225.59,228.22 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:228.22,230.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:230.8,235.3 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:236.2,236.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:239.64,240.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:240.27,241.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:241.41,245.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:247.8,248.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:248.37,250.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:254.60,258.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:259.15,261.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:262.17,264.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:265.16,266.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:267.16,268.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:271.2,271.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:274.57,275.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:275.36,277.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:277.8,277.26 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:277.26,280.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:281.2,283.25 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:283.25,286.3 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:287.2,289.19 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:292.95,299.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:301.86,305.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:305.16,307.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:307.8,309.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:311.2,311.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:314.106,322.2 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:324.47,326.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:328.61,330.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:332.66,336.18 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:336.18,338.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:340.2,373.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:373.18,375.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:377.2,377.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:381.83,386.66 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:386.66,388.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:390.2,396.38 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:400.93,402.26 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:402.26,407.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:408.2,411.78 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:411.78,413.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:415.2,417.32 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:417.32,419.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:424.2,424.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:424.18,426.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:428.2,428.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:428.29,430.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:431.2,431.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:431.29,433.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:434.2,434.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node.go:434.29,436.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:9.46,10.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:11.24,12.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:13.30,14.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:15.30,16.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:17.25,18.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:19.24,20.21 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:21.22,22.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:23.9,24.11 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:26.2,26.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:29.48,30.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:31.19,32.26 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:33.25,34.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:35.25,36.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:37.20,38.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:39.19,40.26 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:41.17,42.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:43.9,44.11 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:46.2,46.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:49.96,56.20 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:56.20,59.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:62.2,62.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:62.50,65.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:66.2,71.24 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:74.57,91.2 9 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:93.124,98.31 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:98.31,102.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:104.2,105.22 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:108.99,110.19 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:127.22,131.13 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:132.23,136.13 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:137.24,142.45 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:142.45,145.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:145.18,147.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:149.4,152.18 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:152.18,154.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:156.4,159.30 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:161.3,162.13 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:163.25,171.42 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:171.42,179.18 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:179.18,181.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:183.4,184.28 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:186.3,186.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:187.9,191.13 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:192.10,193.53 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:197.59,199.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:213.17,217.21 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:218.18,222.21 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:223.33,225.29 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:225.29,227.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:228.3,233.39 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:233.39,237.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:237.18,239.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:240.4,240.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:242.3,242.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidate_node_yaml.go:244.2,246.20 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:12.68,14.33 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:15.11,17.19 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:18.24,22.47 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:22.47,25.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:26.25,28.18 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:29.12,31.19 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:32.14,34.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:35.10,36.56 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:38.2,38.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:41.58,43.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:44.11,52.17 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:52.17,54.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:57.3,58.66 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:58.66,62.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:62.37,63.10 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:66.4,75.49 8 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:75.49,77.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:79.4,79.55 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:82.3,82.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:82.44,84.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:85.3,85.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:86.11,91.57 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:91.57,93.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:95.3,95.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:95.34,97.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:97.20,100.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:101.4,109.40 8 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:111.3,111.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:113.2,118.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:118.16,120.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:121.2,123.36 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:127.55,134.16 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:139.17,142.26 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:143.18,146.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:146.17,148.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:149.3,150.26 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:151.19,154.42 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:154.42,155.57 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:155.57,157.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:158.4,159.53 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:159.53,161.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:162.4,162.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:162.29,164.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:166.3,167.26 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:168.20,171.26 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/candidiate_node_json.go:172.10,174.26 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/chown_linux.go:11.57,12.50 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/chown_linux.go:12.50,17.17 4 0 +github.com/mikefarah/yq/v4/pkg/yqlib/chown_linux.go:17.17,22.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/chown_linux.go:24.2,24.12 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:16.42,18.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:20.65,23.36 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:23.36,28.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:29.2,29.38 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:29.38,34.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:35.2,35.38 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:35.38,40.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:41.2,41.38 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:41.38,46.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:47.2,47.37 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:47.37,52.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:53.2,53.38 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:53.38,58.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/color_print.go:59.2,60.12 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:19.80,25.2 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:27.72,31.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:33.63,35.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:37.46,38.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:38.28,40.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:41.2,41.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:44.55,45.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:45.24,47.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:48.2,48.26 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:51.62,52.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:52.24,54.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:55.2,55.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:58.60,61.26 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:61.26,63.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:63.17,65.14 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:68.2,69.14 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:72.37,73.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:73.38,75.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:76.2,77.48 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:80.39,85.63 4 0 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:85.63,88.3 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:90.2,90.16 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:90.16,92.13 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:94.2,94.14 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:97.35,101.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:101.16,103.13 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:105.2,105.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:108.43,112.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/context.go:114.43,118.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/data_tree_navigator.go:21.47,23.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/data_tree_navigator.go:25.118,39.2 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/data_tree_navigator.go:41.112,42.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/data_tree_navigator.go:42.27,45.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/data_tree_navigator.go:46.2,47.37 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/data_tree_navigator.go:47.37,48.70 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/data_tree_navigator.go:48.70,50.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/data_tree_navigator.go:52.2,53.20 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/data_tree_navigator.go:53.20,55.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/data_tree_navigator.go:56.2,56.93 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:28.64,29.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:30.26,31.30 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:32.18,33.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:34.34,35.36 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:36.29,37.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:38.18,39.35 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:40.18,41.35 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:42.14,43.30 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:44.10,45.100 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:49.49,51.20 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:51.20,54.16 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:54.16,58.4 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder.go:61.2,62.15 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:15.53,20.2 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:22.54,26.37 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:26.37,28.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:29.2,29.15 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:39.33,41.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:43.56,48.2 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:50.60,51.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:51.18,53.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:54.2,57.54 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:57.54,59.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:60.2,60.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:60.20,66.23 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:66.23,68.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_base64.go:70.2,71.50 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:17.50,19.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:21.59,28.2 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:30.75,32.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:32.16,34.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:35.2,35.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:38.99,41.35 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:41.35,43.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:44.2,44.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:47.63,48.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:48.18,50.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:51.2,53.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:53.16,55.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:57.2,61.40 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:61.40,66.3 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:67.2,67.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:67.29,69.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_csv_object.go:71.2,71.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_json.go:15.31,17.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_json.go:19.54,22.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_json.go:24.58,28.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_json.go:28.16,30.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_json.go:32.2,32.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:19.37,21.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:23.60,27.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:29.45,32.39 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:32.39,34.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:34.17,36.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:36.9,38.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:40.2,40.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:43.63,44.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:44.13,46.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:47.2,47.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:50.115,72.2 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:74.115,79.31 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:79.31,81.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:81.17,83.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:86.2,89.51 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:92.64,93.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:93.18,95.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:96.2,98.52 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:98.52,100.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:101.2,101.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:101.20,104.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:105.2,106.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:106.16,108.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:109.2,119.40 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:119.40,120.69 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:120.69,122.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_properties.go:125.2,127.21 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:23.31,28.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:30.54,34.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:34.16,36.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:37.2,42.12 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:45.72,47.6 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:47.6,50.22 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:50.22,52.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:56.99,62.16 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:62.16,64.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:66.2,69.53 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:72.107,74.70 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:74.70,76.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:78.2,78.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:78.34,82.37 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:82.37,83.72 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:83.72,85.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:86.9,91.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:93.2,94.19 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:97.91,102.22 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:102.22,104.34 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:104.34,106.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:108.3,113.70 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:113.70,115.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:117.3,117.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:120.2,124.8 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:127.82,130.22 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:130.22,133.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:133.17,135.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:136.3,136.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:139.2,143.8 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:147.89,150.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:152.87,155.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:157.90,161.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:163.91,167.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:169.88,173.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:175.81,176.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:177.29,178.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:179.17,180.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:181.20,182.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:183.21,184.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:185.18,186.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:187.18,188.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:189.24,190.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:191.10,192.63 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:197.58,198.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:198.18,200.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:203.2,204.15 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:204.15,205.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:205.31,208.11 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:208.11,210.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:214.2,217.58 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:217.58,219.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:219.27,221.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:223.3,227.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:227.17,229.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:233.2,234.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:234.16,236.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:239.2,241.35 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:241.35,243.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:245.2,245.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:249.83,253.36 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:253.36,255.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:255.8,255.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:255.48,257.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:257.8,259.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:261.2,262.34 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:265.76,271.15 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:271.15,273.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:275.2,281.38 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:281.38,284.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:286.2,288.43 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:288.43,290.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:291.2,295.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:295.16,297.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:298.2,298.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:301.104,320.2 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:322.81,331.15 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:331.15,333.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:335.2,343.43 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:343.43,345.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_toml.go:346.2,353.34 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:15.30,17.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:19.53,24.2 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:26.57,27.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:27.18,29.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:31.2,33.52 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:33.52,35.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:36.2,36.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:36.20,42.23 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:42.23,44.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:46.2,47.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:47.16,49.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_uri.go:50.2,51.46 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:24.50,29.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:31.53,36.2 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:38.81,40.30 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:40.30,42.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:42.17,44.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:45.3,45.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:48.2,48.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:53.56,54.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:54.13,56.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:61.2,63.20 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:66.70,70.21 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:70.21,78.3 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:80.2,80.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:80.42,87.13 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:87.13,91.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:92.3,96.24 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:96.24,98.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:98.18,100.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:101.9,105.71 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:105.71,106.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:106.34,111.6 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:111.11,115.6 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:117.4,118.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:118.18,120.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:122.3,122.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:125.2,125.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:128.80,129.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:130.9,131.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:132.9,133.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:134.10,136.32 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:136.32,138.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:139.3,143.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:147.78,148.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:148.25,150.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:152.2,157.27 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:157.27,160.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:162.2,164.20 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:167.57,168.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:168.18,170.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:171.2,175.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:175.16,177.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:178.2,180.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:180.16,182.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:182.8,182.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:182.38,184.23 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:184.23,186.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:188.2,191.23 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:209.50,211.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:211.23,213.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:214.2,216.40 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:216.40,217.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:217.24,222.4 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:224.2,225.73 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:238.55,252.40 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:252.40,253.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:253.28,255.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:256.3,256.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:259.2,259.6 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:259.6,261.40 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:261.40,263.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:264.3,264.15 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:264.15,265.9 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:268.3,268.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:269.25,280.30 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:280.30,281.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:281.32,282.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:282.28,284.7 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:286.5,286.95 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:288.21,292.35 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:292.35,294.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:296.4,296.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:296.23,300.5 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:301.23,305.26 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:305.26,307.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:310.4,310.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:311.20,314.31 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:314.31,317.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:317.10,317.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:317.39,320.5 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:320.10,323.5 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:325.21,326.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:326.31,328.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:329.22,330.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:330.33,332.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:334.3,334.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:337.2,337.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:340.57,343.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:343.30,348.60 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:348.60,351.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:351.9,353.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:354.8,357.3 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:360.63,362.33 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:362.33,363.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:363.16,365.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:367.2,367.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:376.38,377.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:377.13,379.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:381.2,383.30 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:383.30,384.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:384.50,385.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:388.3,388.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:388.19,392.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:392.9,394.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:398.2,398.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:398.18,400.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_xml.go:402.2,402.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:28.52,30.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:32.92,36.6 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:36.6,38.29 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:38.29,41.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:41.9,41.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:41.24,43.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:43.9,43.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:43.42,46.30 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:46.30,48.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:48.10,48.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:48.25,50.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:51.9,51.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:51.40,54.30 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:54.30,56.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:56.10,56.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:56.25,58.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:59.9,59.118 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:59.118,62.30 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:62.30,64.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:64.10,64.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:64.25,66.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:67.9,69.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:73.54,81.93 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:81.93,83.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:83.17,85.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:86.8,86.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:86.51,92.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:93.2,98.12 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:101.58,105.77 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:105.77,109.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:109.8,109.98 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:109.98,114.31 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:114.31,116.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:117.3,117.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:118.8,118.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:118.23,120.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:122.2,125.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:125.16,127.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:129.2,132.30 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:132.30,135.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:136.2,138.28 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/decoder_yaml.go:141.63,145.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder.go:14.44,16.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder.go:16.30,17.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder.go:17.42,18.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder.go:18.20,20.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder.go:24.2,24.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder.go:24.37,26.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_base64.go:13.33,15.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_base64.go:17.49,19.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_base64.go:21.72,23.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_base64.go:25.85,27.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_base64.go:29.85,31.46 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_base64.go:31.46,33.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_base64.go:34.2,35.12 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:13.44,15.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:17.46,19.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:21.69,23.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:25.82,27.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:29.88,32.33 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:32.33,34.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:34.31,36.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:37.3,37.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:39.2,39.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:42.90,43.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:43.32,45.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:45.33,47.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:48.3,49.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:49.17,51.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:53.2,53.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:56.84,57.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:57.31,59.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:60.2,61.29 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:64.102,66.33 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:66.33,69.21 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:69.21,71.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:72.3,72.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:74.2,74.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:78.91,80.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:80.16,82.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:84.2,85.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:85.16,87.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:89.2,89.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:89.32,90.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:90.32,92.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:93.3,95.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:95.17,97.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:100.2,100.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:103.82,104.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:104.37,106.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:108.2,113.31 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:113.31,115.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:115.8,115.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:115.35,117.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:118.2,118.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:118.40,120.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:122.2,122.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:122.41,124.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_csv.go:126.2,126.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:18.75,21.42 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:21.42,23.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:25.2,25.59 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:28.48,30.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:32.71,34.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:36.84,38.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:40.76,44.48 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:44.48,46.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:48.2,50.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:50.17,52.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:54.2,59.16 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:59.16,61.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:62.2,62.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:62.17,64.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_json.go:65.2,65.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:17.54,21.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:23.54,25.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:27.77,29.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:31.90,33.6 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:33.6,36.58 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:36.58,38.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:39.3,39.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:39.53,41.60 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:41.60,43.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:45.9,46.56 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:46.56,48.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:51.3,51.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:51.36,52.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:52.22,54.53 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:54.53,56.6 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:58.4,58.9 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:61.2,61.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:64.82,66.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:66.29,68.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:70.2,73.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:73.16,75.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:77.2,78.12 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:81.129,84.20 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:84.20,87.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:88.2,92.19 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:93.18,95.60 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:95.60,97.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:97.9,99.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:100.3,101.13 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:102.20,103.47 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:104.19,105.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:106.17,107.47 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:108.10,109.53 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:113.78,114.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:114.16,116.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:117.2,117.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:120.110,121.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:121.33,123.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:123.17,125.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:127.2,127.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:130.108,131.55 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:131.55,135.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:135.17,137.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_properties.go:139.2,139.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:16.29,18.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:20.45,22.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:24.68,26.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:28.81,30.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:32.81,34.46 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:34.46,36.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:38.2,38.58 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:42.49,48.27 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:48.27,50.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:50.18,51.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:51.20,55.5 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:57.4,57.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:58.9,59.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:59.42,63.5 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:66.3,66.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:69.2,69.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:69.18,71.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:72.2,72.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_sh.go:75.47,77.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:15.41,17.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:19.58,21.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:23.76,25.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:27.83,29.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:31.86,35.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:35.16,37.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:39.2,39.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:42.97,46.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:47.18,49.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:49.17,54.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:55.3,56.13 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:57.20,58.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:58.42,60.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:60.18,62.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:64.3,64.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:65.19,66.64 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:66.64,70.18 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:70.18,72.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:74.3,74.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:75.17,76.42 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:77.10,78.53 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:82.63,111.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:111.39,112.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:112.36,114.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:114.9,114.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:114.31,116.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:117.3,117.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:120.2,120.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:120.22,122.38 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:122.38,124.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:125.3,125.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:127.2,127.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:130.38,132.26 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:132.26,133.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:133.37,135.9 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:138.2,138.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:138.18,140.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:141.2,141.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:144.39,146.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_shellvariables.go:148.46,150.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_toml.go:11.31,13.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_toml.go:15.76,16.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_toml.go:16.29,18.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_toml.go:19.2,19.195 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_toml.go:22.71,24.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_toml.go:26.84,28.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_toml.go:30.48,32.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_uri.go:12.30,14.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_uri.go:16.46,18.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_uri.go:20.69,22.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_uri.go:24.82,26.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_uri.go:28.82,30.46 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_uri.go:30.46,32.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_uri.go:33.2,34.12 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:20.62,23.42 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:23.42,25.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:26.2,26.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:29.46,31.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:33.69,35.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:37.82,40.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:42.74,50.28 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:50.28,52.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:52.48,56.53 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:56.53,59.57 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:59.57,61.6 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:62.5,62.59 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:62.59,64.6 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:69.2,69.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:69.28,73.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:73.17,75.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:76.3,77.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:77.17,79.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:82.2,82.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:83.19,85.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:85.17,87.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:88.18,91.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:91.17,93.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:94.3,94.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:95.10,96.84 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:99.2,99.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:103.89,105.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:105.16,107.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:108.2,108.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:108.44,115.17 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:115.17,117.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:118.3,118.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:118.36,121.18 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:121.18,123.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:126.3,126.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:126.53,128.4 0 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:128.9,128.66 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:128.66,131.56 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:131.56,133.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:134.4,134.58 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:134.58,136.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:137.9,137.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:137.48,139.57 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:139.57,141.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:142.4,142.58 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:142.58,144.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:145.9,150.18 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:150.18,152.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:154.3,155.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:155.17,157.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:159.2,159.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:162.107,164.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:164.16,166.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:167.2,167.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:170.105,172.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:172.16,174.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:175.2,175.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:178.104,179.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:180.19,181.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:182.20,183.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:184.18,186.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:186.17,188.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:190.3,192.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:192.17,194.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:196.3,196.68 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:196.68,198.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:200.3,200.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:202.2,202.52 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:209.83,210.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:210.22,213.85 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:213.85,219.53 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:219.53,221.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:223.9,225.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:227.3,227.82 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:227.82,230.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:231.3,235.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:235.17,237.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:239.2,239.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:242.107,244.75 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:244.75,246.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:248.2,248.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:248.41,250.66 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:250.66,252.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:254.2,254.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:257.52,262.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:264.105,268.44 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:268.44,272.31 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:272.31,273.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:273.32,276.5 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:276.10,278.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:282.2,283.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:283.16,285.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:288.2,288.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:288.44,293.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:293.17,295.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:296.3,296.59 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:296.59,299.56 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:299.56,301.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:302.9,302.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:302.48,304.57 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:304.57,306.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:307.9,307.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:307.46,310.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:310.18,312.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:313.4,315.18 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:315.18,317.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:318.4,319.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:319.18,321.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:322.9,322.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:322.39,325.18 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:325.18,327.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:329.3,330.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:330.17,332.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_xml.go:335.2,335.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:20.79,21.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:21.16,23.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:24.2,24.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:27.48,29.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:31.71,32.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:32.33,34.54 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:34.54,36.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:38.2,38.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:41.84,47.6 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:47.6,50.58 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:50.58,52.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:53.3,53.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:53.53,55.60 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:55.60,57.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:59.9,60.110 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:60.110,62.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:63.4,63.56 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:63.56,65.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:68.3,68.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:68.36,69.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:69.22,71.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:71.53,73.6 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:75.4,75.9 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:79.2,79.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:82.76,84.54 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:84.54,86.54 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:86.54,88.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:89.3,89.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:92.2,94.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:94.17,96.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:98.2,104.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:104.16,106.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:108.2,111.47 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:111.47,113.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:115.2,115.77 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:115.77,117.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:119.2,119.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:119.17,121.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/encoder_yaml.go:122.2,122.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:23.54,25.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:27.92,30.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:30.16,32.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:33.2,35.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:35.16,37.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:38.2,38.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:41.104,44.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:44.27,46.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:48.2,48.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:48.40,51.42 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:51.42,53.20 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:53.20,54.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:54.23,56.6 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:57.5,59.22 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:60.10,60.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:60.27,61.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:61.23,63.6 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:64.5,67.22 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:70.3,70.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:72.2,72.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:72.21,74.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_parser.go:75.2,75.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:17.51,19.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:21.84,26.2 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:28.47,29.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:29.36,31.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:31.8,31.49 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:31.49,33.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:33.8,33.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:33.43,35.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:36.2,36.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:39.96,45.38 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:45.38,47.33 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:48.52,50.70 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:51.41,54.52 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:54.52,57.5 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:59.4,59.72 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:59.72,61.38 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:61.38,63.6 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:64.5,64.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:66.4,66.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:66.25,68.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:70.4,80.55 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:80.55,82.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:83.4,85.29 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:85.29,88.5 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:92.4,92.142 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:92.142,95.5 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:97.21,98.77 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:98.77,100.38 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:100.38,102.6 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:104.5,104.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:106.4,106.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:106.25,108.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:110.4,110.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:112.11,117.84 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:117.84,119.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:121.4,122.70 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:126.2,127.22 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:127.22,129.33 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:129.33,131.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:133.3,133.123 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:136.2,136.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:136.37,138.39 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:138.39,140.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/expression_postfix.go:143.2,143.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:9.50,10.60 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:10.60,16.64 4 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:16.64,18.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:19.3,19.26 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:21.2,21.12 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:24.41,27.22 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:27.22,29.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:33.52,38.16 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:38.16,40.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:41.2,43.16 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:43.16,45.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:46.2,47.43 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:47.43,49.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:50.2,50.19 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:53.42,54.33 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:55.16,56.26 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:60.37,62.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:62.16,65.3 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:68.41,70.24 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:70.24,72.17 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:72.17,74.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:75.8,75.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:75.23,77.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:79.2,80.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:80.16,82.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/file_utils.go:84.2,84.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:23.72,25.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:27.70,29.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:31.63,33.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:35.44,37.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:42.48,45.31 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:45.31,47.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:47.8,49.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:49.17,51.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:52.3,52.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:54.2,57.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:57.16,59.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:60.2,65.6 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:65.6,67.29 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:67.29,69.9 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:70.9,70.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:70.24,72.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:73.3,73.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:73.50,75.9 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:77.3,79.58 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:79.58,81.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:83.3,85.24 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:85.24,87.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/front_matter.go:90.2,92.12 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:33.46,34.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:34.35,35.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:35.13,37.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:38.3,38.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:39.8,39.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:39.39,41.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:41.8,41.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:41.40,43.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:43.8,43.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:43.39,45.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:45.8,45.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:45.40,47.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:47.8,47.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:47.45,49.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:49.8,49.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:49.46,51.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:51.8,51.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:51.48,54.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:54.8,56.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:59.34,61.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:63.56,67.26 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:67.26,69.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:70.2,70.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:73.59,76.23 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:76.23,78.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:79.2,81.66 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:84.50,89.28 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:89.28,90.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:90.20,92.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:92.9,94.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:97.2,97.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:100.62,102.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:104.119,110.52 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:110.52,125.3 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:127.2,127.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:127.50,130.56 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:130.56,134.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:137.2,138.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:138.48,143.3 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:145.2,148.50 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:148.50,151.74 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:151.74,156.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:159.2,161.102 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:161.102,165.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:167.2,170.57 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:170.57,174.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:175.2,176.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:176.44,181.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer.go:182.2,182.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:237.69,239.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:241.102,243.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:245.47,247.43 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:247.43,249.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:250.2,253.43 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:253.43,255.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:257.2,257.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:260.39,261.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:261.52,265.34 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:265.34,268.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:270.3,271.14 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:271.14,273.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:274.3,276.91 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:280.59,289.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:291.109,292.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:292.52,296.26 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:296.26,298.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:299.3,299.88 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:303.52,304.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:304.52,308.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:311.34,312.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:312.52,315.27 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:315.27,317.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:319.3,321.63 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:325.54,326.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:326.52,337.3 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:340.48,341.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:341.52,345.35 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:345.35,347.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:348.3,349.63 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:353.38,354.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:354.52,356.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:359.27,360.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:360.52,362.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:365.29,366.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:366.52,374.3 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:377.34,378.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:378.52,382.13 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:382.13,386.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:386.9,389.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:391.3,395.73 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:399.37,400.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:400.52,407.14 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:407.14,409.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:410.3,410.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:410.14,412.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:414.3,415.63 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:419.52,420.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:420.52,424.37 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:424.37,426.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:427.3,427.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:427.37,429.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:430.3,430.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:430.37,432.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:433.3,433.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:433.37,435.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:436.3,436.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:436.37,438.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:439.3,441.63 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:446.36,447.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:447.52,456.3 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:459.26,460.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:460.52,465.27 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:465.27,467.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:469.3,469.105 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:473.28,474.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:474.52,477.27 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:477.27,479.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:480.3,480.103 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:484.29,485.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:485.52,488.27 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:488.27,490.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:492.3,492.103 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:496.67,497.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:497.52,500.27 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:500.27,502.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:504.3,506.63 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:510.78,513.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:515.49,518.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:520.58,523.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:525.42,527.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:529.61,530.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:530.52,532.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:535.83,536.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:536.43,537.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:537.50,539.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:541.2,541.28 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:544.73,546.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:546.16,548.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:549.2,551.6 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:551.6,553.15 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:553.15,555.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:555.9,555.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:555.40,557.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:559.3,560.38 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:560.38,562.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:562.16,564.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lexer_participle.go:565.4,565.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:16.29,17.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:17.29,19.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:27.34,29.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:190.73,191.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:191.42,193.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:195.2,195.62 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:195.62,196.66 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:196.66,198.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:200.2,200.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:203.65,205.64 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:205.64,206.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:206.53,208.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:210.2,210.11 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:213.68,215.66 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:215.66,216.55 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:216.55,218.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:220.2,220.11 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:223.74,224.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:224.42,226.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:228.2,228.62 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:228.62,234.80 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:234.80,236.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:238.2,238.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:241.57,242.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:242.17,247.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:248.2,250.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:250.16,252.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:253.2,254.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:254.16,256.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:257.2,260.20 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:263.70,264.26 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:264.26,266.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:268.2,268.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:268.28,275.23 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:275.23,277.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:280.2,280.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:280.25,283.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:283.8,283.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:283.35,285.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:285.8,285.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:285.37,287.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:287.8,287.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:287.36,289.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:290.2,290.14 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:294.61,296.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:296.41,299.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:300.2,301.23 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:304.49,308.41 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:308.41,310.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:310.8,312.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:314.2,314.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:314.16,316.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:316.8,316.57 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:316.57,318.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:320.2,320.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:323.53,325.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:327.46,329.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:331.46,333.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:335.46,337.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:339.77,349.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:352.39,353.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:353.14,355.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:356.2,356.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:356.43,358.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:358.8,358.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:358.51,360.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:360.8,360.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:360.43,362.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:362.8,364.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:368.50,369.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:369.38,371.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:373.2,374.58 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:374.58,376.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:377.2,377.15 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:380.47,381.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:381.38,383.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:384.2,384.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:384.17,386.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:387.2,388.28 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:388.28,390.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:391.2,392.22 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:392.22,394.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:395.2,395.125 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:398.65,399.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:399.38,401.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:402.2,403.37 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:403.37,404.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:404.30,406.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:407.3,410.54 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:412.2,412.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:415.35,416.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:417.18,418.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:419.20,420.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:421.19,422.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:423.17,424.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/lib.go:425.10,426.20 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:3.59,4.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:4.19,6.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:7.2,7.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:7.20,10.3 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:11.2,11.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:16.43,21.42 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:21.42,22.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:22.24,24.13 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:25.12,26.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:26.40,29.14 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:31.13,32.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:32.23,35.14 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:37.13,44.13 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:48.3,48.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:48.40,51.12 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:53.3,53.15 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/matchKeyString.go:56.2,56.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:10.76,14.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:16.112,18.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:20.77,21.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:21.31,23.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:25.2,27.24 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:28.20,29.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:30.10,31.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:31.27,33.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:34.3,34.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:39.106,43.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:45.113,51.29 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:51.29,53.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:55.2,57.22 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:58.19,59.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:59.30,61.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:62.3,62.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:63.20,64.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:65.18,66.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:66.29,68.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:69.3,71.67 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:71.67,73.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:75.2,75.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:78.103,82.38 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:82.38,86.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:88.2,91.70 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:91.70,94.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:96.2,96.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:96.16,99.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:99.8,99.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:99.30,102.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:102.8,102.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:102.30,105.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:105.8,105.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:105.51,107.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:107.17,109.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:110.3,111.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:111.17,113.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:114.3,116.42 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:117.8,117.101 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:117.101,119.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:119.17,121.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:122.3,123.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:123.17,125.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:126.3,127.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:127.18,129.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:129.9,131.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:132.3,132.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:133.8,135.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:136.2,136.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:139.103,142.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:142.16,144.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:146.2,147.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:147.16,149.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:151.2,153.12 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:157.82,160.27 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:160.27,163.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:164.2,169.32 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:172.79,176.27 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:176.27,179.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:181.2,184.62 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:184.62,190.21 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:190.21,193.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:193.9,198.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:200.2,201.26 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:201.26,203.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_add.go:204.2,204.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:3.114,8.68 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:8.68,9.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:9.18,11.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:12.4,13.14 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:13.14,15.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:16.4,16.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:19.2,19.66 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:22.125,23.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:23.16,25.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:26.2,26.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:26.16,28.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:30.2,31.12 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:31.12,33.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_alternative.go:34.2,34.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:8.114,13.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:13.44,15.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:15.17,17.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:18.3,18.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:18.39,20.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:23.2,25.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:25.16,27.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:29.2,29.65 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:29.65,33.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:33.44,35.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:35.18,37.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:38.4,38.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:38.40,40.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:43.3,43.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:43.22,46.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:48.2,48.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:51.111,55.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:55.69,59.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:60.2,60.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:63.115,68.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:68.44,70.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:70.17,72.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:74.3,74.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:74.39,76.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:79.2,81.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:81.16,83.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:85.2,85.65 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:85.65,89.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:89.44,91.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:91.18,93.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:95.4,95.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:95.40,97.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:100.3,100.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:102.2,102.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:105.112,109.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:109.69,114.3 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:115.2,115.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:118.110,121.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:121.69,126.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:126.17,128.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:129.3,129.86 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:129.86,131.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:131.18,133.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:138.2,138.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:141.72,146.63 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:146.63,150.28 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:150.28,152.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:152.18,154.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:155.9,156.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:156.38,158.76 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:158.76,161.20 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:161.20,163.7 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:165.10,168.19 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:168.19,170.6 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:174.2,175.70 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:175.70,177.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:178.2,178.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:181.62,184.19 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:185.20,186.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:186.48,189.29 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:189.29,191.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:193.3,193.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:194.17,196.24 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:196.24,203.4 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:204.3,205.13 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:206.19,209.64 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:209.64,211.29 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:211.29,213.10 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:217.3,217.15 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:217.15,220.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:222.3,222.64 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:222.64,226.18 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:226.18,228.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:229.4,230.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:230.18,232.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:234.3,234.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:235.10,236.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:240.102,242.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:242.18,244.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:245.2,246.31 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:246.31,248.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:249.2,249.64 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:249.64,254.17 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:254.17,256.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:258.2,258.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:261.125,265.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:265.16,267.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:269.2,269.84 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:269.84,273.77 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:273.77,277.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:278.3,278.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:281.2,281.76 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:281.76,284.57 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:284.57,287.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:290.2,291.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:291.16,293.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_anchors_aliases.go:294.2,297.12 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:9.73,10.117 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:10.117,11.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:11.50,13.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:14.3,14.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:20.70,23.41 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:24.25,25.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:26.27,27.32 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:29.2,29.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:32.115,34.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:34.16,36.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:38.2,42.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:42.44,46.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:48.2,48.65 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:48.65,53.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:53.17,55.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:58.3,60.19 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:60.19,63.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:66.2,66.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:70.119,73.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:73.16,75.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:76.2,76.65 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:76.65,81.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:81.17,83.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:86.3,88.19 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:88.19,90.51 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:90.51,92.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:93.4,93.57 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:93.57,95.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_assign.go:98.2,98.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:9.50,10.22 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:10.22,12.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:13.2,14.26 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:14.26,16.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:17.2,17.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:17.53,24.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:25.2,25.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:28.70,31.30 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:31.30,33.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:33.8,33.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:33.23,35.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:36.2,36.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:39.125,44.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:46.86,47.58 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:47.58,51.57 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:51.57,53.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:54.3,55.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:55.17,57.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:58.3,58.56 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:62.147,63.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:63.44,65.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:65.28,68.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:68.18,70.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:71.4,71.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:71.35,73.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:73.10,75.13 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:79.3,79.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:79.37,81.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:83.2,83.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:86.106,89.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:89.69,92.41 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:92.41,94.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:95.3,96.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:96.17,98.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:99.3,100.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:102.2,102.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:105.106,108.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:108.69,111.41 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:111.41,113.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:114.3,115.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:115.17,117.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:118.3,119.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:121.2,121.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:124.105,131.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:133.106,140.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:142.106,146.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:146.69,152.3 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_booleans.go:153.2,153.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:7.117,9.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:9.69,12.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:12.17,14.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:15.3,15.96 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:15.96,19.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:21.2,21.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:24.110,27.38 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:27.38,31.3 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:33.2,34.89 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:34.89,36.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:36.27,37.9 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:41.2,41.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:41.25,44.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:44.17,46.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:47.3,47.56 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:51.2,52.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:52.69,60.17 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:60.17,62.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:64.3,64.96 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:64.96,68.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:69.3,71.37 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect.go:74.2,74.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:18.124,23.38 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:23.38,27.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:28.2,31.42 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:31.42,33.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:35.2,35.69 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:35.69,38.43 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:38.43,42.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:44.2,47.42 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:47.42,49.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:49.17,51.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:54.3,54.72 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:54.72,64.4 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:67.2,67.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:71.99,72.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:72.33,74.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:76.2,82.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:82.16,84.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:86.2,86.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:86.38,89.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:91.2,93.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:93.69,95.91 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:95.91,103.18 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:103.18,105.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:106.4,106.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_collect_object.go:109.2,109.67 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_column.go:8.109,13.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_column.go:13.69,17.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_column.go:19.2,19.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:16.117,22.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:22.16,24.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:26.2,29.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:29.44,31.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:31.17,33.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:35.3,35.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:35.39,37.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:40.2,42.65 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:42.65,47.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:47.44,49.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:49.18,51.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:53.4,53.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:53.40,55.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:58.3,59.30 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:59.30,62.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:63.3,63.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:63.30,66.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:67.3,67.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:67.30,69.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:72.2,72.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:75.114,87.69 9 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:87.69,90.30 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:90.30,93.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:93.9,93.71 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:93.71,98.88 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:98.88,100.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:101.4,101.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:101.41,103.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:104.4,105.55 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:106.9,106.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:106.37,108.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:108.9,108.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:108.37,110.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:111.3,115.25 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:115.25,118.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:119.3,119.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_comments.go:121.2,121.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:13.110,17.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:19.145,20.117 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:20.117,22.31 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:22.31,25.4 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:25.9,25.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:25.24,28.4 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:28.9,28.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:28.24,31.4 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:33.3,36.20 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:37.20,38.67 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:39.21,40.69 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:41.11,42.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:42.31,44.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:45.4,48.53 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:53.114,55.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:55.16,57.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:59.2,60.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:60.16,62.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:64.2,64.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:64.45,66.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:67.2,67.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:67.19,69.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:70.2,70.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:74.115,80.23 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:80.23,83.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:84.2,84.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:84.16,86.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:86.8,86.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:86.51,88.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:88.17,90.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:91.3,92.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:92.17,94.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:96.3,96.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:96.40,98.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:99.3,99.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:99.20,101.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:102.3,102.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:103.8,103.101 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:103.101,105.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:105.17,107.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:108.3,109.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:109.17,111.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:112.3,112.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:112.40,114.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:115.3,115.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:115.20,117.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:118.3,118.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:119.8,119.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:119.51,120.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:120.46,122.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:123.3,123.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:123.20,125.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:126.3,126.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:127.8,127.70 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:127.70,129.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:129.8,129.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:129.53,131.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_compare.go:133.2,133.74 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:8.111,10.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:12.84,13.64 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:13.64,15.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:15.17,17.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:18.3,18.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:18.23,20.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:22.2,22.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:25.74,26.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:26.30,28.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:29.2,29.62 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:29.62,31.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:31.17,33.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:34.3,34.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:34.19,36.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:38.2,38.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:41.75,42.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:42.29,44.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:45.2,45.62 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:45.62,51.44 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:51.44,53.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:54.3,59.17 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:59.17,61.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:62.3,62.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:62.19,64.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:66.2,66.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:69.76,70.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:70.24,72.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:73.2,73.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:76.69,77.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:78.19,79.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:80.20,81.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:82.18,83.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:83.51,85.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:86.3,86.26 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:86.26,88.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:89.3,89.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:92.2,92.72 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:95.129,99.26 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:99.26,101.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:103.2,104.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:104.16,106.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_contains.go:108.2,108.49 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:7.112,15.37 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:15.37,17.118 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:17.118,20.18 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:20.18,22.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:23.4,23.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:25.8,27.17 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:27.17,29.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:30.3,30.35 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:33.2,35.46 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:39.142,46.25 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:46.25,51.3 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:53.2,56.111 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:56.111,68.4 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:70.2,70.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:70.16,72.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:73.2,78.23 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:83.52,85.64 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:85.64,89.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_create_map.go:90.2,90.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:11.133,14.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:14.16,16.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:16.8,16.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:16.44,18.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:20.2,20.71 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:23.113,24.124 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:24.124,26.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:26.17,28.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:29.3,30.61 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:33.2,33.147 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:40.100,50.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:52.73,55.42 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:55.42,58.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:59.2,59.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:63.109,67.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:67.16,69.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:70.2,72.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:72.69,76.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:76.17,78.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:79.3,82.26 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:82.26,89.4 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:90.3,92.25 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:95.2,95.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:98.99,102.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:102.16,104.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:105.2,108.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:108.16,110.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:112.2,112.69 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:112.69,116.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:116.17,118.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:119.3,121.98 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:124.2,124.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:127.56,130.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:130.16,132.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:134.2,134.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:137.105,141.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:141.69,146.53 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:146.53,148.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:150.3,151.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:151.17,153.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:155.3,157.25 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:160.2,160.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:163.103,169.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:169.69,173.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:173.17,175.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:177.3,177.107 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_datetime.go:180.2,180.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:8.114,11.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:11.16,13.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:15.2,15.74 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:15.74,18.30 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:18.30,21.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:22.3,29.37 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:29.37,31.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:31.9,31.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:31.45,33.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:33.9,35.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:37.2,37.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:40.84,42.77 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:42.77,44.33 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:44.33,46.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:46.9,48.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:50.2,50.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:53.69,59.59 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:59.59,67.20 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:67.20,69.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:71.2,71.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:74.71,80.59 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:80.59,85.20 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:85.20,87.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_delete.go:89.2,89.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:9.109,13.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:15.118,19.25 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:19.25,21.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:23.2,25.54 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:25.54,26.57 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:26.57,28.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:29.8,31.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:33.2,33.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:36.89,40.38 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:40.38,44.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:46.2,46.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:46.44,51.3 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:51.8,51.101 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:51.101,56.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:56.17,58.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:59.3,60.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:60.17,62.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:63.3,64.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:64.18,66.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:66.9,68.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:69.3,69.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:70.8,72.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_divide.go:73.2,73.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_document_index.go:8.119,11.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_document_index.go:11.69,15.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_document_index.go:16.2,16.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:12.71,13.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:14.24,15.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:16.25,17.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:18.23,19.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:20.23,21.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:22.24,23.66 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:24.23,25.57 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:26.26,27.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:28.23,29.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:30.22,31.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:33.2,33.26 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:36.89,41.20 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:41.20,43.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:45.2,47.29 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:57.109,65.69 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:65.69,69.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:69.17,71.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:75.3,76.98 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:76.98,81.55 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:81.55,83.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:87.3,89.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:89.42,91.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:93.3,93.82 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:95.2,95.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:102.48,104.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:105.23,106.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:107.23,108.54 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:109.22,110.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:111.25,112.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:113.29,114.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:115.28,116.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:117.28,118.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:119.22,120.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:122.2,122.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:126.109,131.20 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:131.20,133.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:135.2,136.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:136.69,144.17 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:144.17,146.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:148.3,149.26 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:149.26,151.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:153.3,157.25 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_encoder_decoder.go:159.2,159.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:8.75,17.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:19.68,23.59 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:23.59,28.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:29.2,29.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:32.68,36.59 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:36.59,41.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:42.2,42.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:45.112,47.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:47.69,51.29 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:52.20,53.49 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:55.21,56.49 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:57.11,58.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:58.37,60.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:64.2,64.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:67.101,72.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:72.16,74.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:74.8,74.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:74.34,76.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:78.2,80.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:80.16,82.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:82.8,82.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:82.36,84.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:86.2,86.100 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:90.72,95.59 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:95.59,97.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:97.17,99.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:101.3,101.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:103.2,105.18 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:108.114,110.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:110.69,114.29 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:115.21,117.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:117.18,119.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:120.4,120.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:121.11,122.73 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:126.2,126.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:129.114,133.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:133.16,135.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:137.2,139.71 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:139.71,145.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:145.17,147.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:149.3,152.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:152.17,154.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:156.3,158.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:158.17,160.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:161.3,172.17 9 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:172.17,174.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:175.3,175.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_entries.go:180.2,180.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:19.106,28.29 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:28.29,34.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:34.8,34.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:34.27,36.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:36.8,38.67 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:38.67,40.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:41.3,43.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:43.17,45.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:46.3,46.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:49.2,53.46 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:56.111,59.49 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:59.49,61.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:63.2,66.26 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:66.26,68.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:68.8,70.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:72.2,72.69 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:72.69,75.26 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:75.26,78.4 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:80.3,81.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:81.17,83.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:84.3,85.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_env.go:88.2,88.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:3.109,6.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:8.134,9.117 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:9.117,12.31 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:12.31,16.4 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:16.9,16.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:16.24,20.12 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:20.12,22.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:23.4,23.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:24.9,24.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:24.24,28.12 4 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:28.12,30.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:31.4,31.50 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:34.3,37.30 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:37.30,39.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:39.9,39.70 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:39.70,41.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:42.3,43.11 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:43.11,45.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:46.3,46.49 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_equals.go:50.112,53.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_error.go:7.108,12.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_error.go:12.16,14.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_error.go:15.2,16.33 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_error.go:16.33,18.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_error.go:19.2,19.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:7.107,10.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:10.16,12.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:14.2,17.131 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:17.131,21.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:21.17,23.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:25.3,25.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:28.2,30.89 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:30.89,31.61 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:31.61,33.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:33.18,35.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:36.4,36.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_eval.go:40.2,40.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_expression.go:7.113,11.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_expression.go:11.16,13.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_expression.go:15.2,15.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_file.go:8.114,13.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_file.go:13.69,17.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_file.go:19.2,19.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_file.go:22.115,27.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_file.go:27.69,31.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_file.go:33.2,33.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_filter.go:7.109,11.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_filter.go:11.69,15.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_filter.go:15.17,17.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_filter.go:18.3,19.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_filter.go:19.17,21.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_filter.go:23.3,25.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_filter.go:25.17,27.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_filter.go:28.3,29.30 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_filter.go:31.2,31.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:11.46,12.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:12.16,14.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:15.2,15.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:15.31,17.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:18.2,21.36 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:21.36,22.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:22.38,24.49 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:24.49,26.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:27.9,29.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:31.2,32.26 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:35.104,40.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:40.69,43.41 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:43.41,45.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:47.3,47.32 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_flatten.go:51.2,51.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:10.140,12.37 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:12.37,15.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:15.17,17.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:19.3,21.34 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:21.34,25.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:27.3,29.14 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:29.14,32.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:33.3,33.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:35.2,35.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:38.102,43.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:43.69,47.41 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:47.41,49.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:51.3,53.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:53.17,55.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:57.3,58.79 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:58.79,61.87 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:61.87,63.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:65.4,65.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:68.3,68.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_group_by.go:72.2,72.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:8.106,15.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:15.16,17.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:19.2,21.34 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:21.34,24.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:26.2,26.69 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:26.69,32.29 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:33.20,35.81 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:35.81,37.31 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:37.31,39.6 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:41.4,41.72 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:42.21,44.29 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:44.29,46.29 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:46.29,48.6 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:49.5,49.52 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:51.4,51.72 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:52.11,53.62 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_has.go:56.2,56.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:8.108,13.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:13.69,17.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:19.2,19.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:22.109,27.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:27.69,30.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:30.27,32.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:35.2,35.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:39.107,44.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:44.69,48.36 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:48.36,50.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:50.9,50.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:50.44,52.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:52.9,54.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:57.3,57.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:60.2,60.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:63.53,65.63 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:65.63,67.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:68.2,68.76 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:71.54,74.34 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:74.34,80.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_keys.go:82.2,82.76 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_length.go:8.109,12.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_length.go:12.69,16.26 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_length.go:17.19,18.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_length.go:18.34,20.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_length.go:20.10,22.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_length.go:23.20,24.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_length.go:25.21,26.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_length.go:27.11,28.14 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_length.go:31.3,32.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_length.go:35.2,35.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_line.go:8.107,13.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_line.go:13.69,17.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_line.go:19.2,19.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:22.58,27.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:27.16,29.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:31.2,31.86 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:34.73,35.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:35.20,37.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:39.2,40.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:40.16,42.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:43.2,46.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:46.16,48.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:50.2,50.26 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:50.26,53.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:53.8,53.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:53.33,57.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:57.8,59.62 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:59.62,61.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:62.3,62.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:66.111,76.69 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:76.69,80.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:80.17,82.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:83.3,83.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:83.39,85.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:86.3,92.29 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:92.29,94.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:94.9,96.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:97.3,97.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:97.17,99.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:101.3,101.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_load.go:105.2,105.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:7.112,9.69 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:9.69,14.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:14.17,16.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:18.3,23.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:23.17,25.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:29.2,29.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:32.106,36.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:36.69,41.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:41.17,43.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:45.3,48.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:48.17,50.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:52.3,54.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:54.17,56.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:57.3,59.30 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_map.go:63.2,63.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:10.109,14.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:16.118,20.25 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:20.25,22.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:24.2,26.54 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:26.54,27.57 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:27.57,29.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:30.8,32.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:34.2,34.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:37.89,41.38 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:41.38,45.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:47.2,47.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:47.44,52.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:52.17,54.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:55.3,56.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:56.17,58.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:59.3,59.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:59.18,61.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:62.3,65.48 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:66.8,66.101 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:66.101,71.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:71.17,73.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:74.3,75.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:75.17,77.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:78.3,79.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:79.18,81.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:81.9,83.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:84.3,84.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:85.8,87.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_modulo.go:88.2,88.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:17.105,18.72 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:18.72,22.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:25.117,29.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:31.111,34.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:36.122,40.55 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:40.55,43.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:45.2,45.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:45.27,47.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:49.2,49.49 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:52.156,53.117 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:53.117,61.26 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:61.26,63.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:65.3,68.54 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:68.54,77.4 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:78.3,78.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:82.86,86.38 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:86.38,90.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:92.2,92.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:92.44,94.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:94.8,94.101 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:94.101,96.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:97.2,97.72 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:100.103,104.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:104.17,106.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:106.8,108.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:110.2,111.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:111.16,113.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:114.2,115.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:115.16,117.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:118.2,119.20 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:122.87,129.16 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:129.16,131.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:132.2,133.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:133.16,135.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:136.2,137.20 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:140.155,149.16 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:149.16,151.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:153.2,154.28 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:154.28,157.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:159.2,159.55 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:159.55,164.33 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:164.33,165.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:168.3,169.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:169.17,171.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:173.3,173.69 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:175.2,175.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:178.166,185.52 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:185.52,188.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:188.8,189.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:189.53,196.3 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:196.8,198.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_multiply.go:199.2,209.12 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_parent.go:5.112,10.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_parent.go:10.69,12.30 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_parent.go:12.30,14.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_parent.go:17.2,17.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:8.64,9.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:10.14,11.76 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:12.10,13.95 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:17.88,18.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:18.31,20.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:22.2,24.41 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:24.41,25.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:25.31,27.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:27.9,27.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:27.38,29.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:29.18,31.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:32.4,32.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:33.9,35.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:38.2,38.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:42.110,45.63 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:45.63,47.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:49.2,51.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:51.16,53.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:55.2,55.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:55.45,57.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:58.2,62.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:62.16,64.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:66.2,70.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:70.69,74.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:74.17,76.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:78.3,78.50 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:78.50,80.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:82.3,92.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:92.17,94.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:97.2,97.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:100.111,105.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:105.16,107.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:108.2,108.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:108.48,110.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:111.2,113.35 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:113.35,115.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:117.2,119.47 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:119.47,121.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:121.27,123.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:124.3,126.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:126.17,128.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:130.3,140.17 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:140.17,142.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:146.2,146.28 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:150.110,155.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:155.69,162.58 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:162.58,165.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:166.3,167.25 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_path.go:170.2,170.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:8.78,11.66 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:11.66,15.22 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:15.22,19.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:22.2,25.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:28.92,31.66 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:31.66,33.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:33.17,35.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:37.3,37.64 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:37.64,39.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:42.2,45.21 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:48.107,53.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:53.16,55.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:56.2,57.50 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:57.50,59.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:61.2,63.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:63.69,68.31 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:68.31,70.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:70.9,70.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:70.39,72.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:72.18,74.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:76.9,78.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:80.3,81.32 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pick.go:84.2,84.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pipe.go:3.107,5.72 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pipe.go:5.72,7.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pipe.go:8.2,9.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pipe.go:9.16,11.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pipe.go:12.2,14.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pipe.go:14.16,16.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_pipe.go:17.2,17.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_recursive_descent.go:12.119,17.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_recursive_descent.go:17.16,19.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_recursive_descent.go:21.2,21.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_recursive_descent.go:24.106,25.69 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_recursive_descent.go:25.69,32.65 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_recursive_descent.go:32.65,36.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_recursive_descent.go:36.18,38.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_recursive_descent.go:39.4,40.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_recursive_descent.go:40.18,42.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_recursive_descent.go:45.2,45.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:8.109,18.72 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:18.72,20.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:20.8,20.70 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:20.70,22.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:24.2,27.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:27.16,29.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:31.2,36.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:36.16,38.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:40.2,43.67 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:43.67,51.17 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:51.17,53.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reduce.go:56.2,56.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reverse.go:8.110,11.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reverse.go:11.69,16.41 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reverse.go:16.41,18.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reverse.go:20.3,23.54 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reverse.go:23.54,25.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reverse.go:26.3,27.32 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_reverse.go:31.2,31.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_select.go:7.109,12.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_select.go:12.69,16.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_select.go:16.17,18.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_select.go:21.3,23.90 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_select.go:23.90,26.21 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_select.go:26.21,27.10 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_select.go:31.3,31.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_select.go:31.20,33.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_select.go:35.2,35.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_self.go:3.107,5.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_shuffle.go:9.110,18.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_shuffle.go:18.69,23.41 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_shuffle.go:23.41,25.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_shuffle.go:27.3,31.41 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_shuffle.go:31.41,31.68 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_shuffle.go:33.3,33.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_shuffle.go:35.2,35.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:8.126,10.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:10.16,12.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:13.2,13.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:13.37,15.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:16.2,16.76 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:19.113,27.69 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:27.69,32.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:32.17,34.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:35.3,36.30 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:36.30,38.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:40.3,41.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:41.17,43.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:45.3,46.31 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:46.31,48.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:48.9,48.57 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:48.57,50.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:52.3,55.63 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:55.63,57.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:59.3,61.35 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_slice.go:67.2,67.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:12.107,16.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:20.109,24.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:24.69,29.41 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:29.41,31.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:33.3,35.54 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:35.54,38.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:38.18,40.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:42.4,42.132 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:46.3,50.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:50.44,52.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:53.3,53.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:55.2,55.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:66.43,66.60 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:67.43,67.70 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:69.48,74.100 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:74.100,80.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:80.17,82.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:82.9,82.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:82.24,84.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:86.3,86.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:88.2,88.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:91.103,95.38 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:95.38,98.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:100.2,100.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:100.38,103.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:105.2,108.49 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:108.49,112.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:114.2,114.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:114.46,116.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:116.8,116.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:116.53,118.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:118.8,118.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:118.53,120.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:120.8,120.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:120.53,122.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:122.8,122.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:122.53,126.29 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:126.29,128.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:128.9,128.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:128.23,130.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:131.3,131.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:132.8,132.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:132.23,134.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:134.17,137.4 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:138.3,139.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:139.17,142.4 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:143.3,143.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:143.29,145.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:145.9,145.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:145.37,147.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:149.3,149.11 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:150.8,150.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:150.51,152.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:152.17,153.14 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:155.3,156.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:156.17,157.14 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:159.3,159.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:160.8,160.101 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:160.101,162.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:162.17,163.14 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:165.3,166.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:166.17,167.14 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:169.3,169.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:169.23,171.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:171.9,171.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:171.29,173.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:175.3,175.11 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort.go:178.2,178.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:7.111,9.69 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:9.69,12.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:12.17,14.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:16.3,16.86 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:16.86,18.32 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:18.32,20.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:21.4,21.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:21.18,23.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:27.2,27.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:30.36,35.59 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:35.59,41.3 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:42.2,44.55 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:44.55,48.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_sort_keys.go:52.2,52.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_split_document.go:3.116,7.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_split_document.go:7.69,12.3 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_split_document.go:14.2,14.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:14.112,16.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:16.69,21.47 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:21.47,23.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:25.3,27.34 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:31.2,31.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:34.113,38.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:38.69,43.47 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:43.47,45.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:47.3,48.24 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:48.24,50.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:50.9,52.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:53.3,55.34 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:59.2,59.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:63.116,68.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:68.16,70.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:71.2,71.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:71.45,73.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:75.2,78.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:78.16,80.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:81.2,81.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:81.51,83.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:85.2,85.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:88.99,91.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:93.119,101.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:101.16,103.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:105.2,106.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:106.16,108.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:110.2,112.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:112.69,116.47 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:116.47,118.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:120.3,121.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:124.2,124.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:128.98,133.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:133.16,138.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:138.8,142.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:144.2,150.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:150.16,155.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:156.2,156.19 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:163.104,167.23 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:167.23,170.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:170.8,173.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:175.2,176.31 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:179.123,185.52 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:185.52,187.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:189.2,189.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:189.37,192.39 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:192.39,196.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:198.3,201.25 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:207.125,213.52 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:213.52,215.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:217.2,217.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:217.37,221.39 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:221.39,228.18 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:228.18,230.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:230.10,232.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:233.4,233.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:236.3,236.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:242.141,248.63 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:248.63,252.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:252.17,254.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:255.3,256.52 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:256.52,258.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:259.3,259.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:259.39,262.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:263.3,263.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:263.39,265.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:266.3,266.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:266.25,268.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:271.2,272.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:272.16,274.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:275.2,277.45 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:277.45,279.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:280.2,282.31 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:285.108,287.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:287.16,289.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:291.2,293.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:293.69,297.47 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:297.47,299.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:301.3,301.59 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:304.2,304.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:307.110,309.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:309.16,311.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:313.2,315.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:315.69,319.47 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:319.47,321.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:322.3,322.61 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:326.2,326.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:329.107,331.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:331.16,333.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:335.2,337.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:337.69,341.47 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:341.47,343.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:344.3,345.72 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:349.2,349.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:352.113,357.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:357.16,359.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:360.2,360.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:360.38,362.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:364.2,366.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:366.69,369.32 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:369.32,371.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:372.3,373.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:376.2,376.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:379.76,381.31 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:381.31,383.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:383.27,385.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:386.3,386.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:389.2,389.66 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:392.114,397.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:397.16,399.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:400.2,400.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:400.38,402.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:404.2,406.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:406.69,409.27 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:409.27,410.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:413.3,413.47 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:413.47,415.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:416.3,419.27 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:422.2,422.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:425.75,428.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:428.17,433.38 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:433.38,435.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_strings.go:438.2,438.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:8.52,9.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:9.29,11.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:11.8,11.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:11.36,13.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:13.8,13.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:13.36,15.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:15.8,15.37 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:15.37,17.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:17.8,17.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:17.36,19.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:19.8,19.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:19.34,21.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:21.8,21.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:21.30,23.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:24.2,24.15 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:27.114,31.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:31.44,33.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:33.17,35.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:37.3,37.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:37.39,39.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:39.18,41.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:45.2,47.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:47.16,49.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:51.2,51.65 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:51.65,54.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:54.44,56.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:56.18,58.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:60.4,60.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:60.40,62.19 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:62.19,64.6 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:68.3,68.26 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:71.2,71.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:74.111,79.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:79.69,82.26 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:83.20,84.20 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:85.26,86.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:87.26,88.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:89.21,90.21 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:91.20,92.20 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:93.18,94.18 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:95.10,96.14 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:97.11,98.23 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:100.3,101.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_style.go:104.2,104.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:10.81,14.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:16.117,18.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:20.111,24.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:26.84,29.66 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:29.66,31.84 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:31.84,32.68 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:32.68,34.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:36.3,36.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:36.20,38.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:41.2,42.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:45.118,51.29 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:51.29,53.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:55.2,57.22 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:58.19,59.67 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:60.20,61.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:61.31,63.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:64.3,64.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:65.18,66.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:66.29,68.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:69.3,71.72 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:71.72,73.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:76.2,76.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:79.108,83.38 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:83.38,87.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:89.2,89.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:89.38,92.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:94.2,96.70 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:96.70,99.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:101.2,101.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:101.16,103.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:103.8,103.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:103.30,105.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:105.8,105.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:105.51,107.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:107.17,109.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:110.3,111.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:111.17,113.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:114.3,116.45 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:117.8,117.101 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:117.101,119.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:119.17,121.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:122.3,123.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:123.17,125.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:126.3,127.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:127.18,129.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:129.9,131.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:132.3,132.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:133.8,135.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:137.2,137.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:140.107,142.39 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:142.39,144.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:144.8,146.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:147.2,149.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:149.16,151.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:153.2,154.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:154.16,156.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_subtract.go:158.2,160.12 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:7.112,12.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:12.44,14.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:14.17,16.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:18.3,18.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:18.39,20.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:23.2,25.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:25.16,27.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:29.2,29.65 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:29.65,32.44 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:32.44,34.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:34.18,36.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:38.4,38.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:38.40,40.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:42.3,42.39 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:45.2,45.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:48.109,53.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:53.69,57.3 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_tag.go:59.2,59.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:18.73,20.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:22.115,26.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:26.69,28.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:28.17,30.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:31.3,31.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:34.2,34.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:37.103,40.88 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:40.88,43.33 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:44.19,46.36 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:47.11,49.35 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:51.3,51.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:54.2,54.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:55.19,57.143 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:59.20,61.93 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:63.17,66.52 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:67.10,68.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:72.116,79.133 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:79.133,81.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:83.2,84.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:84.16,86.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:90.2,92.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:92.16,94.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:95.2,97.49 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:97.49,99.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:100.2,106.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:106.16,108.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:109.2,109.56 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:112.133,114.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:114.69,117.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:117.17,119.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:120.3,120.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:123.2,123.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:126.156,127.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:127.34,133.73 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:133.73,135.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:138.2,138.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:138.36,141.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:141.8,141.46 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:141.46,143.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:143.8,143.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:143.45,145.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:146.2,147.24 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:150.145,151.23 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:151.23,153.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:155.2,157.36 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:157.36,160.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:160.17,162.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:163.3,163.41 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:166.2,166.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:169.130,173.23 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:173.23,176.63 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:176.63,178.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:179.3,179.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:183.2,183.36 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:183.36,186.43 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:186.43,187.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:189.3,189.17 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:189.17,191.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:192.3,194.30 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:194.30,195.26 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:195.26,198.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:200.4,202.37 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:205.3,205.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:205.21,207.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:209.3,209.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:209.21,211.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:213.3,213.48 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:215.2,215.24 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:218.60,220.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:222.147,226.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:226.16,228.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:230.2,230.89 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:230.89,238.37 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:238.37,240.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:242.3,244.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:244.27,246.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:247.3,247.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:247.34,249.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:252.2,254.58 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:254.58,257.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:258.2,258.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:261.139,268.59 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:268.59,273.53 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:273.53,276.18 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:276.18,278.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:279.9,279.49 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:279.49,281.28 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:281.28,284.5 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:285.4,285.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:285.35,288.5 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:292.2,292.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:295.146,296.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:297.17,298.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:298.38,300.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:301.3,301.73 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:302.20,303.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:303.44,305.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:305.18,307.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:310.2,310.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_traverse_path.go:313.115,317.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_union.go:5.108,9.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_union.go:9.16,11.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_union.go:12.2,17.16 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_union.go:17.16,19.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_union.go:20.2,24.65 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_union.go:24.65,27.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_union.go:32.2,32.44 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_union.go:32.44,34.66 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_union.go:34.66,39.4 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_union.go:41.2,42.21 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:10.101,15.2 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:17.103,22.69 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:22.69,26.41 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:26.41,28.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:30.3,31.47 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:31.47,34.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:34.18,36.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:38.4,40.35 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:40.35,44.5 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:46.4,48.15 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:48.15,50.5 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:52.3,53.59 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:53.59,55.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:57.3,57.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_unique.go:60.2,60.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_value.go:5.112,7.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_value.go:9.108,11.38 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_value.go:11.38,14.3 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_value.go:16.2,18.69 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_value.go:18.69,21.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_value.go:23.2,23.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:8.114,12.19 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:12.19,14.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:15.2,15.42 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:22.103,24.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:28.104,32.89 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:32.89,34.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:34.27,35.9 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:38.2,38.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:38.25,40.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:42.2,42.69 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:42.69,44.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:44.17,46.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:47.3,47.45 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:49.2,49.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:52.115,56.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:56.16,58.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:59.2,59.68 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:59.68,61.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:62.2,69.65 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:69.65,72.24 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:72.24,74.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:74.9,77.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:78.3,83.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:83.17,85.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:86.3,87.42 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:91.2,91.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:91.34,93.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_variables.go:95.2,95.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_with.go:5.107,9.63 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_with.go:9.63,11.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_with.go:13.2,17.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_with.go:17.16,19.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_with.go:21.2,23.75 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_with.go:23.75,26.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_with.go:26.17,28.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operator_with.go:32.2,32.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:15.150,17.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:17.16,19.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:27.2,28.66 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:29.25,30.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:31.27,32.68 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:35.2,37.65 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:37.65,47.17 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:47.17,49.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:51.2,51.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:54.108,57.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:61.170,63.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:63.33,65.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:65.17,67.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:67.9,67.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:67.27,70.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:73.2,74.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:74.16,76.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:78.2,78.57 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:78.57,80.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:80.17,82.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:83.3,83.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:83.29,85.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:86.3,86.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:89.2,89.85 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:89.85,91.39 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:91.39,93.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:94.3,95.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:95.17,97.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:98.3,98.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:98.29,100.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:102.2,102.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:113.138,116.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:116.16,118.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:119.2,121.57 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:121.57,123.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:123.17,125.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:128.2,128.65 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:128.65,132.17 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:132.17,134.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:137.2,137.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:140.166,143.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:145.149,149.89 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:149.89,151.27 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:151.27,152.9 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:156.2,156.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:156.25,159.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:161.2,163.89 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:163.89,165.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:165.17,167.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:168.3,168.51 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:171.2,171.43 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:174.78,176.12 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:176.12,178.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:179.2,180.20 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:180.20,183.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:185.2,185.13 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:188.113,189.20 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:189.20,191.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:191.8,191.27 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:191.27,193.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:193.16,195.18 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:195.18,196.15 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:198.4,199.41 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:201.3,201.164 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/operators.go:204.2,208.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:36.73,37.16 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:38.26,39.31 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:40.19,41.31 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:42.34,43.32 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:44.18,45.30 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:46.18,47.30 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:48.18,49.30 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:50.14,51.31 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:52.26,53.41 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:54.10,55.106 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:71.71,79.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:81.61,85.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:87.56,89.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:91.49,93.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:95.81,99.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:101.37,104.54 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:104.54,106.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:106.8,106.63 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:106.63,108.3 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:111.71,114.30 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:114.30,117.3 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:119.2,119.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:119.35,123.17 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:123.17,125.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:126.3,126.40 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:129.2,129.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:129.25,134.3 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:136.2,136.61 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:136.61,142.26 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:142.26,144.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:146.3,149.136 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:149.136,150.67 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:150.67,152.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:155.3,157.21 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:157.21,159.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:161.3,161.94 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:161.94,163.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:165.3,165.61 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:165.61,167.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:169.3,169.21 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:169.21,172.49 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:172.49,176.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:177.4,177.59 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:177.59,179.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:180.4,180.53 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:180.53,182.5 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:185.3,186.40 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:186.40,188.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:189.3,189.38 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:193.2,193.29 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:193.29,195.17 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:195.17,197.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:199.3,202.17 4 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:202.17,204.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:205.3,205.40 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:205.40,207.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer.go:210.2,210.12 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:19.61,23.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:25.86,27.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:36.98,39.16 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:40.24,41.21 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:42.25,43.27 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:46.2,51.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:54.83,62.16 6 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:62.16,64.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:65.2,65.36 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:65.36,67.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:68.2,69.40 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:69.40,71.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:73.2,75.16 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:75.16,77.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/printer_writer.go:78.2,80.32 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:25.43,27.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:29.81,31.16 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:31.16,33.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:34.2,39.25 5 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:39.25,41.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:42.2,42.51 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:45.120,48.16 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:48.16,50.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:52.2,52.37 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:52.37,55.17 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:55.17,57.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:58.3,59.17 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:59.17,61.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:62.3,64.34 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:65.17,66.27 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:70.2,70.27 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:70.27,73.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:75.2,75.12 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:78.141,82.16 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:82.16,84.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:85.2,85.6 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:85.6,88.38 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:88.38,91.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:91.9,91.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:91.33,93.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:94.3,102.26 7 1 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:102.26,104.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:105.3,107.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:107.17,109.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/stream_evaluator.go:110.3,110.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:22.43,26.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:28.119,36.16 5 1 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:36.16,38.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:40.2,44.16 4 1 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:44.16,46.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:47.2,47.6 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:47.6,50.38 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:50.38,53.4 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:53.9,53.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:53.33,55.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:56.3,63.26 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:63.26,65.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:66.3,68.17 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:68.17,70.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/string_evaluator.go:71.3,71.34 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:12.53,14.21 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:14.21,16.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:16.8,20.17 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:20.17,22.4 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:23.3,23.33 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:25.2,25.20 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:29.54,32.2 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:34.107,36.16 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:36.16,38.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:39.2,42.6 3 1 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:42.6,45.38 2 1 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:45.38,46.35 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:47.18,48.28 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:50.4,50.25 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:51.9,51.33 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:51.33,53.4 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/utils.go:54.3,61.34 6 1 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:17.67,20.2 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:22.70,25.16 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:25.16,27.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:28.2,29.16 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:29.16,31.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:32.2,34.16 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:34.16,36.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:38.2,38.47 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:38.47,40.3 1 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:41.2,43.18 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:46.88,49.27 3 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:49.27,52.3 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/write_in_place_handler.go:53.2,55.12 2 0 +github.com/mikefarah/yq/v4/pkg/yqlib/xml.go:15.48,27.2 1 1 +github.com/mikefarah/yq/v4/pkg/yqlib/yaml.go:10.50,17.2 1 1 diff --git a/pkg/yqlib/csv_test.go b/pkg/yqlib/csv_test.go index df2873903f6..66bc5de79dd 100644 --- a/pkg/yqlib/csv_test.go +++ b/pkg/yqlib/csv_test.go @@ -119,6 +119,22 @@ var csvScenarios = []formatScenario{ expected: csvMissing, scenarioType: "roundtrip-csv", }, + { + description: "decode csv key", + skipDoc: true, + input: csvSimple, + expression: ".[0].name | key", + expected: "name\n", + scenarioType: "decode-csv-object", + }, + { + description: "decode csv parent", + skipDoc: true, + input: csvSimple, + expression: ".[0].name | parent | .height", + expected: "168.8\n", + scenarioType: "decode-csv-object", + }, { description: "Parse CSV into an array of objects", subdescription: "First row is assumed to be the header row.", diff --git a/pkg/yqlib/data_tree_navigator.go b/pkg/yqlib/data_tree_navigator.go index 986c129df0e..9a246027ba2 100644 --- a/pkg/yqlib/data_tree_navigator.go +++ b/pkg/yqlib/data_tree_navigator.go @@ -4,7 +4,6 @@ import ( "fmt" logging "gopkg.in/op/go-logging.v1" - yaml "gopkg.in/yaml.v3" ) type DataTreeNavigator interface { @@ -13,7 +12,7 @@ type DataTreeNavigator interface { // a new context of matching candidates GetMatchingNodes(context Context, expressionNode *ExpressionNode) (Context, error) - DeeplyAssign(context Context, path []interface{}, rhsNode *yaml.Node) error + DeeplyAssign(context Context, path []interface{}, rhsNode *CandidateNode) error } type dataTreeNavigator struct { @@ -23,12 +22,7 @@ func NewDataTreeNavigator() DataTreeNavigator { return &dataTreeNavigator{} } -func (d *dataTreeNavigator) DeeplyAssign(context Context, path []interface{}, rhsNode *yaml.Node) error { - - rhsCandidateNode := &CandidateNode{ - Path: path, - Node: rhsNode, - } +func (d *dataTreeNavigator) DeeplyAssign(context Context, path []interface{}, rhsCandidateNode *CandidateNode) error { assignmentOp := &Operation{OperationType: assignOpType, Preferences: assignPreferences{}} @@ -55,7 +49,6 @@ func (d *dataTreeNavigator) GetMatchingNodes(context Context, expressionNode *Ex log.Debug(NodeToString(el.Value.(*CandidateNode))) } } - log.Debug(">>") handler := expressionNode.Operation.OperationType.Handler if handler != nil { return handler(d, context, expressionNode) diff --git a/pkg/yqlib/decoder_base64.go b/pkg/yqlib/decoder_base64.go index f1cace87070..50ed350735c 100644 --- a/pkg/yqlib/decoder_base64.go +++ b/pkg/yqlib/decoder_base64.go @@ -5,8 +5,6 @@ import ( "encoding/base64" "io" "strings" - - yaml "gopkg.in/yaml.v3" ) type base64Padder struct { @@ -70,11 +68,5 @@ func (dec *base64Decoder) Decode() (*CandidateNode, error) { } } dec.readAnything = true - return &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.ScalarNode, - Tag: "!!str", - Value: buf.String(), - }, - }, nil + return createStringScalarNode(buf.String()), nil } diff --git a/pkg/yqlib/decoder_csv_object.go b/pkg/yqlib/decoder_csv_object.go index e8e78023dba..644bbfa1a4a 100644 --- a/pkg/yqlib/decoder_csv_object.go +++ b/pkg/yqlib/decoder_csv_object.go @@ -6,7 +6,6 @@ import ( "io" "github.com/dimchansky/utfbom" - yaml "gopkg.in/yaml.v3" ) type csvObjectDecoder struct { @@ -28,7 +27,7 @@ func (dec *csvObjectDecoder) Init(reader io.Reader) error { return nil } -func (dec *csvObjectDecoder) convertToYamlNode(content string) *yaml.Node { +func (dec *csvObjectDecoder) convertToNode(content string) *CandidateNode { node, err := parseSnippet(content) if err != nil { return createScalarNode(content, content) @@ -36,14 +35,11 @@ func (dec *csvObjectDecoder) convertToYamlNode(content string) *yaml.Node { return node } -func (dec *csvObjectDecoder) createObject(headerRow []string, contentRow []string) *yaml.Node { - objectNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} +func (dec *csvObjectDecoder) createObject(headerRow []string, contentRow []string) *CandidateNode { + objectNode := &CandidateNode{Kind: MappingNode, Tag: "!!map"} for i, header := range headerRow { - objectNode.Content = append( - objectNode.Content, - createScalarNode(header, header), - dec.convertToYamlNode(contentRow[i])) + objectNode.AddKeyValueChild(createScalarNode(header, header), dec.convertToNode(contentRow[i])) } return objectNode } @@ -58,13 +54,13 @@ func (dec *csvObjectDecoder) Decode() (*CandidateNode, error) { return nil, err } - rootArray := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} + rootArray := &CandidateNode{Kind: SequenceNode, Tag: "!!seq"} contentRow, err := dec.reader.Read() for err == nil && len(contentRow) > 0 { log.Debugf("Adding contentRow: %v", contentRow) - rootArray.Content = append(rootArray.Content, dec.createObject(headerRow, contentRow)) + rootArray.AddChild(dec.createObject(headerRow, contentRow)) contentRow, err = dec.reader.Read() log.Debugf("Read next contentRow: %v, %v", contentRow, err) } @@ -72,10 +68,5 @@ func (dec *csvObjectDecoder) Decode() (*CandidateNode, error) { return nil, err } - return &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.DocumentNode, - Content: []*yaml.Node{rootArray}, - }, - }, nil + return rootArray, nil } diff --git a/pkg/yqlib/decoder_goccy_yaml.go b/pkg/yqlib/decoder_goccy_yaml.go new file mode 100644 index 00000000000..7494d7cddf0 --- /dev/null +++ b/pkg/yqlib/decoder_goccy_yaml.go @@ -0,0 +1,42 @@ +//go:build !yq_noyaml + +package yqlib + +import ( + "io" + + yaml "github.com/goccy/go-yaml" + "github.com/goccy/go-yaml/ast" +) + +type goccyYamlDecoder struct { + decoder yaml.Decoder + cm yaml.CommentMap +} + +func NewGoccyYAMLDecoder() Decoder { + return &goccyYamlDecoder{} +} + +func (dec *goccyYamlDecoder) Init(reader io.Reader) error { + dec.cm = yaml.CommentMap{} + dec.decoder = *yaml.NewDecoder(reader, yaml.CommentToMap(dec.cm), yaml.UseOrderedMap()) + return nil +} + +func (dec *goccyYamlDecoder) Decode() (*CandidateNode, error) { + + var ast ast.Node + + err := dec.decoder.Decode(&ast) + if err != nil { + return nil, err + } + + candidateNode := &CandidateNode{} + if err := candidateNode.UnmarshalGoccyYAML(ast, dec.cm); err != nil { + return nil, err + } + + return candidateNode, nil +} diff --git a/pkg/yqlib/decoder_json.go b/pkg/yqlib/decoder_json.go index ea712bfc4fd..16a662a53c9 100644 --- a/pkg/yqlib/decoder_json.go +++ b/pkg/yqlib/decoder_json.go @@ -3,11 +3,9 @@ package yqlib import ( - "fmt" "io" "github.com/goccy/go-json" - yaml "gopkg.in/yaml.v3" ) type jsonDecoder struct { @@ -25,76 +23,11 @@ func (dec *jsonDecoder) Init(reader io.Reader) error { func (dec *jsonDecoder) Decode() (*CandidateNode, error) { - var dataBucket orderedMap - log.Debug("going to decode") + var dataBucket CandidateNode err := dec.decoder.Decode(&dataBucket) if err != nil { return nil, err } - node, err := dec.convertToYamlNode(&dataBucket) - if err != nil { - return nil, err - } - - return &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.DocumentNode, - Content: []*yaml.Node{node}, - }, - }, nil -} - -func (dec *jsonDecoder) convertToYamlNode(data *orderedMap) (*yaml.Node, error) { - if data == nil { - return createScalarNode(nil, "null"), nil - } - if data.kv == nil { - switch rawData := data.altVal.(type) { - case nil: - return createScalarNode(nil, "null"), nil - case float64, float32: - // json decoder returns ints as float.' - intNum := int(rawData.(float64)) - - // if the integer representation is the same as the original - // then its an int. - if float64(intNum) == rawData.(float64) { - return createScalarNode(intNum, fmt.Sprintf("%v", intNum)), nil - } - - return createScalarNode(rawData, fmt.Sprintf("%v", rawData)), nil - case int, int64, int32, string, bool: - return createScalarNode(rawData, fmt.Sprintf("%v", rawData)), nil - case []*orderedMap: - return dec.parseArray(rawData) - default: - return nil, fmt.Errorf("unrecognised type :( %v", rawData) - } - } - - var yamlMap = &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - for i, keyValuePair := range data.kv { - yamlValue, err := dec.convertToYamlNode(&data.kv[i].V) - if err != nil { - return nil, err - } - yamlMap.Content = append(yamlMap.Content, createScalarNode(keyValuePair.K, keyValuePair.K), yamlValue) - } - return yamlMap, nil - -} - -func (dec *jsonDecoder) parseArray(dataArray []*orderedMap) (*yaml.Node, error) { - - var yamlMap = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} - - for _, value := range dataArray { - yamlValue, err := dec.convertToYamlNode(value) - if err != nil { - return nil, err - } - yamlMap.Content = append(yamlMap.Content, yamlValue) - } - return yamlMap, nil + return &dataBucket, nil } diff --git a/pkg/yqlib/decoder_lua.go b/pkg/yqlib/decoder_lua.go index efc04eacc25..b37be846f7a 100644 --- a/pkg/yqlib/decoder_lua.go +++ b/pkg/yqlib/decoder_lua.go @@ -8,7 +8,6 @@ import ( "math" lua "github.com/yuin/gopher-lua" - yaml "gopkg.in/yaml.v3" ) type luaDecoder struct { @@ -28,17 +27,17 @@ func (dec *luaDecoder) Init(reader io.Reader) error { return nil } -func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.Node { +func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *CandidateNode { switch lv.Type() { case lua.LTNil: - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, Tag: "!!null", Value: "", } case lua.LTBool: - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, Tag: "!!bool", Value: lv.String(), } @@ -46,22 +45,22 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No n := float64(lua.LVAsNumber(lv)) // various special case floats if math.IsNaN(n) { - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, Tag: "!!float", Value: ".nan", } } if math.IsInf(n, 1) { - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, Tag: "!!float", Value: ".inf", } } if math.IsInf(n, -1) { - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, Tag: "!!float", Value: "-.inf", } @@ -69,27 +68,27 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No // does it look like an integer? if n == float64(int(n)) { - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, Tag: "!!int", Value: lv.String(), } } - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, Tag: "!!float", Value: lv.String(), } case lua.LTString: - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, Tag: "!!str", Value: lv.String(), } case lua.LTFunction: - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, Tag: "tag:lua.org,2006,function", Value: lv.String(), } @@ -97,12 +96,12 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No // Simultaneously create a sequence and a map, pick which one to return // based on whether all keys were consecutive integers i := 1 - yaml_sequence := &yaml.Node{ - Kind: yaml.SequenceNode, + yaml_sequence := &CandidateNode{ + Kind: SequenceNode, Tag: "!!seq", } - yaml_map := &yaml.Node{ - Kind: yaml.MappingNode, + yaml_map := &CandidateNode{ + Kind: MappingNode, Tag: "!!map", } t := lv.(*lua.LTable) @@ -113,11 +112,13 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No } else { i = 0 } - yaml_map.Content = append(yaml_map.Content, dec.convertToYamlNode(ls, k)) + newKey := dec.convertToYamlNode(ls, k) + yv := dec.convertToYamlNode(ls, v) - yaml_map.Content = append(yaml_map.Content, yv) + yaml_map.AddKeyValueChild(newKey, yv) + if i != 0 { - yaml_sequence.Content = append(yaml_sequence.Content, yv) + yaml_sequence.AddChild(yv) } k, v = ls.Next(t, k) } @@ -126,8 +127,8 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No } return yaml_map default: - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, LineComment: fmt.Sprintf("Unhandled Lua type: %s", lv.Type().String()), Tag: "!!null", Value: lv.String(), @@ -135,7 +136,7 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No } } -func (dec *luaDecoder) decideTopLevelNode(ls *lua.LState) *yaml.Node { +func (dec *luaDecoder) decideTopLevelNode(ls *lua.LState) *CandidateNode { if ls.GetTop() == 0 { // no items were explicitly returned, encode the globals table instead return dec.convertToYamlNode(ls, ls.Get(lua.GlobalsIndex)) @@ -160,10 +161,5 @@ func (dec *luaDecoder) Decode() (*CandidateNode, error) { } firstNode := dec.decideTopLevelNode(ls) dec.finished = true - return &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.DocumentNode, - Content: []*yaml.Node{firstNode}, - }, - }, nil + return firstNode, nil } diff --git a/pkg/yqlib/decoder_properties.go b/pkg/yqlib/decoder_properties.go index e2438ee1803..778ba7eaa08 100644 --- a/pkg/yqlib/decoder_properties.go +++ b/pkg/yqlib/decoder_properties.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/magiconair/properties" - "gopkg.in/yaml.v3" ) type propertiesDecoder struct { @@ -52,16 +51,13 @@ func (dec *propertiesDecoder) applyPropertyComments(context Context, path []inte assignmentOp := &Operation{OperationType: assignOpType, Preferences: assignPreferences{}} rhsCandidateNode := &CandidateNode{ - Path: path, - Node: &yaml.Node{ - Tag: "!!str", - Value: fmt.Sprintf("%v", path[len(path)-1]), - HeadComment: dec.processComment(strings.Join(comments, "\n")), - Kind: yaml.ScalarNode, - }, + Tag: "!!str", + Value: fmt.Sprintf("%v", path[len(path)-1]), + HeadComment: dec.processComment(strings.Join(comments, "\n")), + Kind: ScalarNode, } - rhsCandidateNode.Node.Tag = guessTagFromCustomType(rhsCandidateNode.Node) + rhsCandidateNode.Tag = rhsCandidateNode.guessTagFromCustomType() rhsOp := &Operation{OperationType: referenceOpType, CandidateNode: rhsCandidateNode} @@ -87,13 +83,8 @@ func (dec *propertiesDecoder) applyProperty(context Context, properties *propert } } - rhsNode := &yaml.Node{ - Value: value, - Tag: "!!str", - Kind: yaml.ScalarNode, - } - - rhsNode.Tag = guessTagFromCustomType(rhsNode) + rhsNode := createStringScalarNode(value) + rhsNode.Tag = rhsNode.guessTagFromCustomType() return dec.d.DeeplyAssign(context, path, rhsNode) } @@ -118,10 +109,8 @@ func (dec *propertiesDecoder) Decode() (*CandidateNode, error) { properties.DisableExpansion = true rootMap := &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.MappingNode, - Tag: "!!map", - }, + Kind: MappingNode, + Tag: "!!map", } context := Context{} @@ -135,11 +124,6 @@ func (dec *propertiesDecoder) Decode() (*CandidateNode, error) { } dec.finished = true - return &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.DocumentNode, - Content: []*yaml.Node{rootMap.Node}, - }, - }, nil + return rootMap, nil } diff --git a/pkg/yqlib/decoder_test.go b/pkg/yqlib/decoder_test.go index d14c8a61681..75269cfdbd5 100644 --- a/pkg/yqlib/decoder_test.go +++ b/pkg/yqlib/decoder_test.go @@ -27,11 +27,14 @@ func processFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) ( decoder = NewYamlDecoder(ConfiguredYamlPreferences) } + log.Debugf("reading docs") inputs, err := readDocuments(strings.NewReader(s.input), "sample.yml", 0, decoder) if err != nil { return "", err } + log.Debugf("done reading the documents") + expression := s.expression if expression == "" { expression = "." @@ -45,6 +48,8 @@ func processFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) ( context, err := NewDataTreeNavigator().GetMatchingNodes(Context{MatchingNodes: inputs}, exp) + log.Debugf("Going to print: %v", NodesToString(context.MatchingNodes)) + if err != nil { return "", err } diff --git a/pkg/yqlib/decoder_toml.go b/pkg/yqlib/decoder_toml.go index 166089ce41a..d94d1bf723c 100644 --- a/pkg/yqlib/decoder_toml.go +++ b/pkg/yqlib/decoder_toml.go @@ -11,7 +11,6 @@ import ( "time" toml "github.com/pelletier/go-toml/v2/unstable" - yaml "gopkg.in/yaml.v3" ) type tomlDecoder struct { @@ -37,10 +36,9 @@ func (dec *tomlDecoder) Init(reader io.Reader) error { } dec.parser.Reset(buf.Bytes()) dec.rootMap = &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.MappingNode, - Tag: "!!map", - }} + Kind: MappingNode, + Tag: "!!map", + } return nil } @@ -64,6 +62,7 @@ func (dec *tomlDecoder) processKeyValueIntoMap(rootMap *CandidateNode, tomlNode if err != nil { return err } + context := Context{} context = context.SingleChildContext(rootMap) @@ -95,8 +94,8 @@ func (dec *tomlDecoder) decodeKeyValuesIntoMap(rootMap *CandidateNode, tomlNode return false, nil } -func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*yaml.Node, error) { - content := make([]*yaml.Node, 0) +func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*CandidateNode, error) { + content := make([]*CandidateNode, 0) log.Debug("!! createInlineTableMap") iterator := tomlNode.Children() @@ -107,28 +106,26 @@ func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*yaml.Node, e } keyValues := &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.MappingNode, - Tag: "!!map", - }, + Kind: MappingNode, + Tag: "!!map", } if err := dec.processKeyValueIntoMap(keyValues, child); err != nil { return nil, err } - content = append(content, keyValues.Node.Content...) + content = append(content, keyValues.Content...) } - return &yaml.Node{ - Kind: yaml.MappingNode, + return &CandidateNode{ + Kind: MappingNode, Tag: "!!map", Content: content, }, nil } -func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*yaml.Node, error) { - content := make([]*yaml.Node, 0) +func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*CandidateNode, error) { + content := make([]*CandidateNode, 0) iterator := tomlNode.Children() for iterator.Next() { child := iterator.Node() @@ -139,43 +136,43 @@ func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*yaml.Node, error) { content = append(content, yamlNode) } - return &yaml.Node{ - Kind: yaml.SequenceNode, + return &CandidateNode{ + Kind: SequenceNode, Tag: "!!seq", Content: content, }, nil } -func (dec *tomlDecoder) createStringScalar(tomlNode *toml.Node) (*yaml.Node, error) { +func (dec *tomlDecoder) createStringScalar(tomlNode *toml.Node) (*CandidateNode, error) { content := string(tomlNode.Data) return createScalarNode(content, content), nil } -func (dec *tomlDecoder) createBoolScalar(tomlNode *toml.Node) (*yaml.Node, error) { +func (dec *tomlDecoder) createBoolScalar(tomlNode *toml.Node) (*CandidateNode, error) { content := string(tomlNode.Data) return createScalarNode(content == "true", content), nil } -func (dec *tomlDecoder) createIntegerScalar(tomlNode *toml.Node) (*yaml.Node, error) { +func (dec *tomlDecoder) createIntegerScalar(tomlNode *toml.Node) (*CandidateNode, error) { content := string(tomlNode.Data) _, num, err := parseInt64(content) return createScalarNode(num, content), err } -func (dec *tomlDecoder) createDateTimeScalar(tomlNode *toml.Node) (*yaml.Node, error) { +func (dec *tomlDecoder) createDateTimeScalar(tomlNode *toml.Node) (*CandidateNode, error) { content := string(tomlNode.Data) val, err := parseDateTime(time.RFC3339, content) return createScalarNode(val, content), err } -func (dec *tomlDecoder) createFloatScalar(tomlNode *toml.Node) (*yaml.Node, error) { +func (dec *tomlDecoder) createFloatScalar(tomlNode *toml.Node) (*CandidateNode, error) { content := string(tomlNode.Data) num, err := strconv.ParseFloat(content, 64) return createScalarNode(num, content), err } -func (dec *tomlDecoder) decodeNode(tomlNode *toml.Node) (*yaml.Node, error) { +func (dec *tomlDecoder) decodeNode(tomlNode *toml.Node) (*CandidateNode, error) { switch tomlNode.Kind { case toml.Key, toml.String: return dec.createStringScalar(tomlNode) @@ -241,16 +238,11 @@ func (dec *tomlDecoder) Decode() (*CandidateNode, error) { // must have finished dec.finished = true - if len(dec.rootMap.Node.Content) == 0 { + if len(dec.rootMap.Content) == 0 { return nil, io.EOF } - return &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.DocumentNode, - Content: []*yaml.Node{dec.rootMap.Node}, - }, - }, deferredError + return dec.rootMap, deferredError } @@ -259,9 +251,9 @@ func (dec *tomlDecoder) processTopLevelNode(currentNode *toml.Node) (bool, error var err error log.Debug("!!!!!!!!!!!!Going to process %v state is current %v", currentNode.Kind, NodeToString(dec.rootMap)) if currentNode.Kind == toml.Table { - runAgainstCurrentExp, err = dec.processTable((currentNode)) + runAgainstCurrentExp, err = dec.processTable(currentNode) } else if currentNode.Kind == toml.ArrayTable { - runAgainstCurrentExp, err = dec.processArrayTable((currentNode)) + runAgainstCurrentExp, err = dec.processArrayTable(currentNode) } else { runAgainstCurrentExp, err = dec.decodeKeyValuesIntoMap(dec.rootMap, currentNode) } @@ -281,10 +273,8 @@ func (dec *tomlDecoder) processTable(currentNode *toml.Node) (bool, error) { } tableNodeValue := &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.MappingNode, - Tag: "!!map", - }, + Kind: MappingNode, + Tag: "!!map", } tableValue := dec.parser.Expression() @@ -301,21 +291,18 @@ func (dec *tomlDecoder) processTable(currentNode *toml.Node) (bool, error) { c := Context{} c = c.SingleChildContext(dec.rootMap) - err = dec.d.DeeplyAssign(c, fullPath, tableNodeValue.Node) + err = dec.d.DeeplyAssign(c, fullPath, tableNodeValue) if err != nil { return false, err } return runAgainstCurrentExp, nil } -func (dec *tomlDecoder) arrayAppend(context Context, path []interface{}, rhsNode *yaml.Node) error { +func (dec *tomlDecoder) arrayAppend(context Context, path []interface{}, rhsNode *CandidateNode) error { rhsCandidateNode := &CandidateNode{ - Path: path, - Node: &yaml.Node{ - Kind: yaml.SequenceNode, - Tag: "!!seq", - Content: []*yaml.Node{rhsNode}, - }, + Kind: SequenceNode, + Tag: "!!seq", + Content: []*CandidateNode{rhsNode}, } assignmentOp := &Operation{OperationType: addAssignOpType} @@ -346,10 +333,8 @@ func (dec *tomlDecoder) processArrayTable(currentNode *toml.Node) (bool, error) } tableNodeValue := &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.MappingNode, - Tag: "!!map", - }, + Kind: MappingNode, + Tag: "!!map", } tableValue := dec.parser.Expression() @@ -363,7 +348,7 @@ func (dec *tomlDecoder) processArrayTable(currentNode *toml.Node) (bool, error) c = c.SingleChildContext(dec.rootMap) // += function - err = dec.arrayAppend(c, fullPath, tableNodeValue.Node) + err = dec.arrayAppend(c, fullPath, tableNodeValue) return runAgainstCurrentExp, err } diff --git a/pkg/yqlib/decoder_uri.go b/pkg/yqlib/decoder_uri.go index eabf26beb53..cd08d23c579 100644 --- a/pkg/yqlib/decoder_uri.go +++ b/pkg/yqlib/decoder_uri.go @@ -4,8 +4,6 @@ import ( "bytes" "io" "net/url" - - yaml "gopkg.in/yaml.v3" ) type uriDecoder struct { @@ -50,11 +48,5 @@ func (dec *uriDecoder) Decode() (*CandidateNode, error) { return nil, err } dec.readAnything = true - return &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.ScalarNode, - Tag: "!!str", - Value: newValue, - }, - }, nil + return createStringScalarNode(newValue), nil } diff --git a/pkg/yqlib/decoder_xml.go b/pkg/yqlib/decoder_xml.go index 5c05b97f3f2..c34209e2aa0 100644 --- a/pkg/yqlib/decoder_xml.go +++ b/pkg/yqlib/decoder_xml.go @@ -12,7 +12,6 @@ import ( "unicode" "golang.org/x/net/html/charset" - yaml "gopkg.in/yaml.v3" ) type xmlDecoder struct { @@ -36,14 +35,14 @@ func (dec *xmlDecoder) Init(reader io.Reader) error { return nil } -func (dec *xmlDecoder) createSequence(nodes []*xmlNode) (*yaml.Node, error) { - yamlNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} +func (dec *xmlDecoder) createSequence(nodes []*xmlNode) (*CandidateNode, error) { + yamlNode := &CandidateNode{Kind: SequenceNode, Tag: "!!seq"} for _, child := range nodes { yamlChild, err := dec.convertToYamlNode(child) if err != nil { return nil, err } - yamlNode.Content = append(yamlNode.Content, yamlChild) + yamlNode.AddChild(yamlChild) } return yamlNode, nil @@ -64,9 +63,9 @@ func (dec *xmlDecoder) processComment(c string) string { return replacement } -func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) { +func (dec *xmlDecoder) createMap(n *xmlNode) (*CandidateNode, error) { log.Debug("createMap: headC: %v, lineC: %v, footC: %v", n.HeadComment, n.LineComment, n.FootComment) - yamlNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + yamlNode := &CandidateNode{Kind: MappingNode, Tag: "!!map"} if len(n.Data) > 0 { log.Debugf("creating content node for map: %v", dec.prefs.ContentName) @@ -75,14 +74,14 @@ func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) { labelNode.HeadComment = dec.processComment(n.HeadComment) labelNode.LineComment = dec.processComment(n.LineComment) labelNode.FootComment = dec.processComment(n.FootComment) - yamlNode.Content = append(yamlNode.Content, labelNode, dec.createValueNodeFromData(n.Data)) + yamlNode.AddKeyValueChild(labelNode, dec.createValueNodeFromData(n.Data)) } for i, keyValuePair := range n.Children { label := keyValuePair.K children := keyValuePair.V labelNode := createScalarNode(label, label) - var valueNode *yaml.Node + var valueNode *CandidateNode var err error if i == 0 { @@ -120,32 +119,32 @@ func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) { return nil, err } } - yamlNode.Content = append(yamlNode.Content, labelNode, valueNode) + yamlNode.AddKeyValueChild(labelNode, valueNode) } return yamlNode, nil } -func (dec *xmlDecoder) createValueNodeFromData(values []string) *yaml.Node { +func (dec *xmlDecoder) createValueNodeFromData(values []string) *CandidateNode { switch len(values) { case 0: return createScalarNode(nil, "") case 1: return createScalarNode(values[0], values[0]) default: - content := make([]*yaml.Node, 0) + content := make([]*CandidateNode, 0) for _, value := range values { content = append(content, createScalarNode(value, value)) } - return &yaml.Node{ - Kind: yaml.SequenceNode, + return &CandidateNode{ + Kind: SequenceNode, Tag: "!!seq", Content: content, } } } -func (dec *xmlDecoder) convertToYamlNode(n *xmlNode) (*yaml.Node, error) { +func (dec *xmlDecoder) convertToYamlNode(n *xmlNode) (*CandidateNode, error) { if len(n.Children) > 0 { return dec.createMap(n) } @@ -189,12 +188,7 @@ func (dec *xmlDecoder) Decode() (*CandidateNode, error) { dec.readAnything = true dec.finished = true - return &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.DocumentNode, - Content: []*yaml.Node{firstNode}, - }, - }, nil + return firstNode, nil } type xmlNode struct { diff --git a/pkg/yqlib/decoder_yaml.go b/pkg/yqlib/decoder_yaml.go index c2652744d8a..57eb3eeef06 100644 --- a/pkg/yqlib/decoder_yaml.go +++ b/pkg/yqlib/decoder_yaml.go @@ -20,8 +20,9 @@ type yamlDecoder struct { leadingContent string bufferRead bytes.Buffer - readAnything bool - firstFile bool + readAnything bool + firstFile bool + documentIndex uint } func NewYamlDecoder(prefs YamlPreferences) Decoder { @@ -93,12 +94,14 @@ func (dec *yamlDecoder) Init(reader io.Reader) error { dec.readAnything = false dec.decoder = *yaml.NewDecoder(readerToUse) dec.firstFile = false + dec.documentIndex = 0 return nil } func (dec *yamlDecoder) Decode() (*CandidateNode, error) { - var dataBucket yaml.Node - err := dec.decoder.Decode(&dataBucket) + var yamlNode yaml.Node + err := dec.decoder.Decode(&yamlNode) + if errors.Is(err, io.EOF) && dec.leadingContent != "" && !dec.readAnything { // force returning an empty node with a comment. dec.readAnything = true @@ -116,28 +119,27 @@ func (dec *yamlDecoder) Decode() (*CandidateNode, error) { return nil, err } - candidateNode := &CandidateNode{ - Node: &dataBucket, + candidateNode := CandidateNode{document: dec.documentIndex} + // don't bother with the DocumentNode + err = candidateNode.UnmarshalYAML(yamlNode.Content[0], make(map[string]*CandidateNode)) + if err != nil { + return nil, err } + candidateNode.HeadComment = yamlNode.HeadComment + candidateNode.HeadComment + candidateNode.FootComment = yamlNode.FootComment + candidateNode.FootComment + if dec.leadingContent != "" { candidateNode.LeadingContent = dec.leadingContent dec.leadingContent = "" } dec.readAnything = true - // move document comments into candidate node - // otherwise unwrap drops them. - candidateNode.TrailingContent = dataBucket.FootComment - dataBucket.FootComment = "" - return candidateNode, nil + dec.documentIndex++ + return &candidateNode, nil } func (dec *yamlDecoder) blankNodeWithComment() *CandidateNode { - return &CandidateNode{ - Document: 0, - Filename: "", - Node: &yaml.Node{Kind: yaml.DocumentNode, Content: []*yaml.Node{{Tag: "!!null", Kind: yaml.ScalarNode}}}, - FileIndex: 0, - LeadingContent: dec.leadingContent, - } + node := createScalarNode(nil, "") + node.LeadingContent = dec.leadingContent + return node } diff --git a/pkg/yqlib/doc/operators/comment-operators.md b/pkg/yqlib/doc/operators/comment-operators.md index 89af3b1b970..414fff83658 100644 --- a/pkg/yqlib/doc/operators/comment-operators.md +++ b/pkg/yqlib/doc/operators/comment-operators.md @@ -187,7 +187,6 @@ yq '. head_comment="single"' sample.yml will output ```yaml # single - a: cat ``` diff --git a/pkg/yqlib/doc/operators/create-collect-into-object.md b/pkg/yqlib/doc/operators/create-collect-into-object.md index 2c132bb83d8..ff0c9cbe25d 100644 --- a/pkg/yqlib/doc/operators/create-collect-into-object.md +++ b/pkg/yqlib/doc/operators/create-collect-into-object.md @@ -66,6 +66,7 @@ will output ```yaml Mike: cat Mike: dog +--- Rosey: monkey Rosey: sheep ``` diff --git a/pkg/yqlib/doc/operators/document-index.md b/pkg/yqlib/doc/operators/document-index.md index 619fd3912cf..ebe994e5b65 100644 --- a/pkg/yqlib/doc/operators/document-index.md +++ b/pkg/yqlib/doc/operators/document-index.md @@ -85,6 +85,7 @@ will output ```yaml match: cat doc: 0 +--- match: frog doc: 1 ``` diff --git a/pkg/yqlib/doc/operators/file-operators.md b/pkg/yqlib/doc/operators/file-operators.md index b1dacd78dd1..8c331b83645 100644 --- a/pkg/yqlib/doc/operators/file-operators.md +++ b/pkg/yqlib/doc/operators/file-operators.md @@ -54,7 +54,6 @@ yq eval-all 'file_index' sample.yml another.yml will output ```yaml 0 ---- 1 ``` diff --git a/pkg/yqlib/doc/usage/convert.md b/pkg/yqlib/doc/usage/convert.md index 1f149c11bac..5060f8daaca 100644 --- a/pkg/yqlib/doc/usage/convert.md +++ b/pkg/yqlib/doc/usage/convert.md @@ -14,7 +14,7 @@ Given a sample.json file of: ``` then ```bash -yq -P '.' sample.json +yq -p=json sample.json ``` will output ```yaml @@ -30,16 +30,16 @@ Given a sample.json file of: ``` then ```bash -yq -P '.' sample.json +yq -p=json sample.json ``` will output ```yaml a: Easy! as one two three b: - c: 2 - d: - - 3 - - 4 + c: 2 + d: + - 3 + - 4 ``` ## Encode json: simple diff --git a/pkg/yqlib/doc/usage/xml.md b/pkg/yqlib/doc/usage/xml.md index 2d469450dbf..503f9a7475e 100644 --- a/pkg/yqlib/doc/usage/xml.md +++ b/pkg/yqlib/doc/usage/xml.md @@ -129,15 +129,13 @@ zoo: ``` ## Parse xml: force all as an array -Because of the way yq works, when updating everything you need to update the children before the parents. By default `..` will match parents first, so we reverse that before updating. - Given a sample.xml file of: ```xml boing ``` then ```bash -yq -oy '([..] | reverse | .[]) |= [] + .' sample.xml +yq -oy '.. |= [] + .' sample.xml ``` will output ```yaml diff --git a/pkg/yqlib/encoder.go b/pkg/yqlib/encoder.go index e0ecaccf94a..ee63fd47a2d 100644 --- a/pkg/yqlib/encoder.go +++ b/pkg/yqlib/encoder.go @@ -2,20 +2,18 @@ package yqlib import ( "io" - - yaml "gopkg.in/yaml.v3" ) type Encoder interface { - Encode(writer io.Writer, node *yaml.Node) error + Encode(writer io.Writer, node *CandidateNode) error PrintDocumentSeparator(writer io.Writer) error PrintLeadingContent(writer io.Writer, content string) error CanHandleAliases() bool } -func mapKeysToStrings(node *yaml.Node) { +func mapKeysToStrings(node *CandidateNode) { - if node.Kind == yaml.MappingNode { + if node.Kind == MappingNode { for index, child := range node.Content { if index%2 == 0 { // its a map key child.Tag = "!!str" diff --git a/pkg/yqlib/encoder_base64.go b/pkg/yqlib/encoder_base64.go index 635d27f7b04..9d7f126dcba 100644 --- a/pkg/yqlib/encoder_base64.go +++ b/pkg/yqlib/encoder_base64.go @@ -4,8 +4,6 @@ import ( "encoding/base64" "fmt" "io" - - yaml "gopkg.in/yaml.v3" ) type base64Encoder struct { @@ -28,11 +26,10 @@ func (e *base64Encoder) PrintLeadingContent(writer io.Writer, content string) er return nil } -func (e *base64Encoder) Encode(writer io.Writer, originalNode *yaml.Node) error { - node := unwrapDoc(originalNode) - if guessTagFromCustomType(node) != "!!str" { +func (e *base64Encoder) Encode(writer io.Writer, node *CandidateNode) error { + if node.guessTagFromCustomType() != "!!str" { return fmt.Errorf("cannot encode %v as base64, can only operate on strings. Please first pipe through another encoding operator to convert the value to a string", node.Tag) } - _, err := writer.Write([]byte(e.encoding.EncodeToString([]byte(originalNode.Value)))) + _, err := writer.Write([]byte(e.encoding.EncodeToString([]byte(node.Value)))) return err } diff --git a/pkg/yqlib/encoder_csv.go b/pkg/yqlib/encoder_csv.go index 93466bd918e..7904d728f36 100644 --- a/pkg/yqlib/encoder_csv.go +++ b/pkg/yqlib/encoder_csv.go @@ -4,8 +4,6 @@ import ( "encoding/csv" "fmt" "io" - - yaml "gopkg.in/yaml.v3" ) type csvEncoder struct { @@ -28,12 +26,12 @@ func (e *csvEncoder) PrintLeadingContent(writer io.Writer, content string) error return nil } -func (e *csvEncoder) encodeRow(csvWriter *csv.Writer, contents []*yaml.Node) error { +func (e *csvEncoder) encodeRow(csvWriter *csv.Writer, contents []*CandidateNode) error { stringValues := make([]string, len(contents)) for i, child := range contents { - if child.Kind != yaml.ScalarNode { + if child.Kind != ScalarNode { return fmt.Errorf("csv encoding only works for arrays of scalars (string/numbers/booleans), child[%v] is a %v", i, child.Tag) } stringValues[i] = child.Value @@ -41,10 +39,10 @@ func (e *csvEncoder) encodeRow(csvWriter *csv.Writer, contents []*yaml.Node) err return csvWriter.Write(stringValues) } -func (e *csvEncoder) encodeArrays(csvWriter *csv.Writer, content []*yaml.Node) error { +func (e *csvEncoder) encodeArrays(csvWriter *csv.Writer, content []*CandidateNode) error { for i, child := range content { - if child.Kind != yaml.SequenceNode { + if child.Kind != SequenceNode { return fmt.Errorf("csv encoding only works for arrays of scalars (string/numbers/booleans), child[%v] is a %v", i, child.Tag) } err := e.encodeRow(csvWriter, child.Content) @@ -55,16 +53,16 @@ func (e *csvEncoder) encodeArrays(csvWriter *csv.Writer, content []*yaml.Node) e return nil } -func (e *csvEncoder) extractHeader(child *yaml.Node) ([]*yaml.Node, error) { - if child.Kind != yaml.MappingNode { +func (e *csvEncoder) extractHeader(child *CandidateNode) ([]*CandidateNode, error) { + if child.Kind != MappingNode { return nil, fmt.Errorf("csv object encoding only works for arrays of flat objects (string key => string/numbers/boolean value), child[0] is a %v", child.Tag) } mapKeys := getMapKeys(child) return mapKeys.Content, nil } -func (e *csvEncoder) createChildRow(child *yaml.Node, headers []*yaml.Node) []*yaml.Node { - childRow := make([]*yaml.Node, 0) +func (e *csvEncoder) createChildRow(child *CandidateNode, headers []*CandidateNode) []*CandidateNode { + childRow := make([]*CandidateNode, 0) for _, header := range headers { keyIndex := findKeyInMap(child, header) value := createScalarNode(nil, "") @@ -77,7 +75,7 @@ func (e *csvEncoder) createChildRow(child *yaml.Node, headers []*yaml.Node) []*y } -func (e *csvEncoder) encodeObjects(csvWriter *csv.Writer, content []*yaml.Node) error { +func (e *csvEncoder) encodeObjects(csvWriter *csv.Writer, content []*CandidateNode) error { headers, err := e.extractHeader(content[0]) if err != nil { return nil @@ -89,7 +87,7 @@ func (e *csvEncoder) encodeObjects(csvWriter *csv.Writer, content []*yaml.Node) } for i, child := range content { - if child.Kind != yaml.MappingNode { + if child.Kind != MappingNode { return fmt.Errorf("csv object encoding only works for arrays of flat objects (string key => string/numbers/boolean value), child[%v] is a %v", i, child.Tag) } row := e.createChildRow(child, headers) @@ -102,26 +100,25 @@ func (e *csvEncoder) encodeObjects(csvWriter *csv.Writer, content []*yaml.Node) return nil } -func (e *csvEncoder) Encode(writer io.Writer, originalNode *yaml.Node) error { - if originalNode.Kind == yaml.ScalarNode { - return writeString(writer, originalNode.Value+"\n") +func (e *csvEncoder) Encode(writer io.Writer, node *CandidateNode) error { + if node.Kind == ScalarNode { + return writeString(writer, node.Value+"\n") } csvWriter := csv.NewWriter(writer) csvWriter.Comma = e.separator // node must be a sequence - node := unwrapDoc(originalNode) - if node.Kind != yaml.SequenceNode { + if node.Kind != SequenceNode { return fmt.Errorf("csv encoding only works for arrays, got: %v", node.Tag) } else if len(node.Content) == 0 { return nil } - if node.Content[0].Kind == yaml.ScalarNode { + if node.Content[0].Kind == ScalarNode { return e.encodeRow(csvWriter, node.Content) } - if node.Content[0].Kind == yaml.MappingNode { + if node.Content[0].Kind == MappingNode { return e.encodeObjects(csvWriter, node.Content) } diff --git a/pkg/yqlib/encoder_json.go b/pkg/yqlib/encoder_json.go index 53c6bd061aa..31c7b5804cb 100644 --- a/pkg/yqlib/encoder_json.go +++ b/pkg/yqlib/encoder_json.go @@ -7,7 +7,6 @@ import ( "io" "github.com/goccy/go-json" - yaml "gopkg.in/yaml.v3" ) type jsonEncoder struct { @@ -38,9 +37,11 @@ func (je *jsonEncoder) PrintLeadingContent(writer io.Writer, content string) err return nil } -func (je *jsonEncoder) Encode(writer io.Writer, node *yaml.Node) error { +func (je *jsonEncoder) Encode(writer io.Writer, node *CandidateNode) error { + log.Debugf("I need to encode %v", NodeToString(node)) + log.Debugf("kids %v", len(node.Content)) - if node.Kind == yaml.ScalarNode && je.UnwrapScalar { + if node.Kind == ScalarNode && je.UnwrapScalar { return writeString(writer, node.Value+"\n") } @@ -54,14 +55,7 @@ func (je *jsonEncoder) Encode(writer io.Writer, node *yaml.Node) error { encoder.SetEscapeHTML(false) // do not escape html chars e.g. &, <, > encoder.SetIndent("", je.indentString) - var dataBucket orderedMap - // firstly, convert all map keys to strings - mapKeysToStrings(node) - errorDecoding := node.Decode(&dataBucket) - if errorDecoding != nil { - return errorDecoding - } - err := encoder.Encode(dataBucket) + err := encoder.Encode(node) if err != nil { return err } diff --git a/pkg/yqlib/encoder_lua.go b/pkg/yqlib/encoder_lua.go index c1ac1574d69..b600371d2a0 100644 --- a/pkg/yqlib/encoder_lua.go +++ b/pkg/yqlib/encoder_lua.go @@ -6,8 +6,6 @@ import ( "fmt" "io" "strings" - - yaml "gopkg.in/yaml.v3" ) type luaEncoder struct { @@ -82,10 +80,10 @@ func (le *luaEncoder) PrintLeadingContent(writer io.Writer, content string) erro return nil } -func (le *luaEncoder) encodeString(writer io.Writer, node *yaml.Node) error { +func (le *luaEncoder) encodeString(writer io.Writer, node *CandidateNode) error { quote := "\"" switch node.Style { - case yaml.LiteralStyle, yaml.FoldedStyle, yaml.FlowStyle: + case LiteralStyle, FoldedStyle, FlowStyle: for i := 0; i < 10; i++ { if !strings.Contains(node.Value, "]"+strings.Repeat("=", i)+"]") { err := writeString(writer, "["+strings.Repeat("=", i)+"[\n") @@ -99,7 +97,7 @@ func (le *luaEncoder) encodeString(writer io.Writer, node *yaml.Node) error { return writeString(writer, "]"+strings.Repeat("=", i)+"]") } } - case yaml.SingleQuotedStyle: + case SingleQuotedStyle: quote = "'" // fallthrough to regular ol' string @@ -118,7 +116,7 @@ func (le *luaEncoder) writeIndent(writer io.Writer) error { return writeString(writer, strings.Repeat(le.indentStr, le.indent)) } -func (le *luaEncoder) encodeArray(writer io.Writer, node *yaml.Node) error { +func (le *luaEncoder) encodeArray(writer io.Writer, node *CandidateNode) error { err := writeString(writer, "{") if err != nil { return err @@ -181,7 +179,7 @@ func needsQuoting(s string) bool { return false } -func (le *luaEncoder) encodeMap(writer io.Writer, node *yaml.Node, global bool) error { +func (le *luaEncoder) encodeMap(writer io.Writer, node *CandidateNode, global bool) error { if !global { err := writeString(writer, "{") if err != nil { @@ -263,14 +261,14 @@ func (le *luaEncoder) encodeMap(writer io.Writer, node *yaml.Node, global bool) return writeString(writer, "}") } -func (le *luaEncoder) encodeAny(writer io.Writer, node *yaml.Node) error { +func (le *luaEncoder) encodeAny(writer io.Writer, node *CandidateNode) error { switch node.Kind { - case yaml.SequenceNode: + case SequenceNode: return le.encodeArray(writer, node) - case yaml.MappingNode: + case MappingNode: return le.encodeMap(writer, node, false) - case yaml.ScalarNode: - switch node.ShortTag() { + case ScalarNode: + switch node.Tag { case "!!str": return le.encodeString(writer, node) case "!!null": @@ -282,8 +280,7 @@ func (le *luaEncoder) encodeAny(writer io.Writer, node *yaml.Node) error { return writeString(writer, strings.ToLower(node.Value)) case "!!int": if strings.HasPrefix(node.Value, "0o") { - var octalValue int - err := node.Decode(&octalValue) + _, octalValue, err := parseInt64(node.Value) if err != nil { return err } @@ -302,16 +299,14 @@ func (le *luaEncoder) encodeAny(writer io.Writer, node *yaml.Node) error { return writeString(writer, node.Value) } default: - return fmt.Errorf("Lua encoder NYI -- %s", node.ShortTag()) + return fmt.Errorf("Lua encoder NYI -- %s", node.Tag) } - case yaml.DocumentNode: - return le.encodeAny(writer, node.Content[0]) default: - return fmt.Errorf("Lua encoder NYI -- %s", node.ShortTag()) + return fmt.Errorf("Lua encoder NYI -- %s", node.Tag) } } -func (le *luaEncoder) encodeTopLevel(writer io.Writer, node *yaml.Node) error { +func (le *luaEncoder) encodeTopLevel(writer io.Writer, node *CandidateNode) error { err := writeString(writer, le.docPrefix) if err != nil { return err @@ -323,12 +318,10 @@ func (le *luaEncoder) encodeTopLevel(writer io.Writer, node *yaml.Node) error { return writeString(writer, le.docSuffix) } -func (le *luaEncoder) Encode(writer io.Writer, node *yaml.Node) error { - if node.Kind == yaml.DocumentNode { - return le.Encode(writer, node.Content[0]) - } +func (le *luaEncoder) Encode(writer io.Writer, node *CandidateNode) error { + if le.globals { - if node.Kind != yaml.MappingNode { + if node.Kind != MappingNode { return fmt.Errorf("--lua-global requires a top level MappingNode") } return le.encodeMap(writer, node, true) diff --git a/pkg/yqlib/encoder_properties.go b/pkg/yqlib/encoder_properties.go index 575b4e89a54..0ebfb28a551 100644 --- a/pkg/yqlib/encoder_properties.go +++ b/pkg/yqlib/encoder_properties.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/magiconair/properties" - yaml "gopkg.in/yaml.v3" ) type propertiesEncoder struct { @@ -62,9 +61,9 @@ func (pe *propertiesEncoder) PrintLeadingContent(writer io.Writer, content strin return nil } -func (pe *propertiesEncoder) Encode(writer io.Writer, node *yaml.Node) error { +func (pe *propertiesEncoder) Encode(writer io.Writer, node *CandidateNode) error { - if node.Kind == yaml.ScalarNode { + if node.Kind == ScalarNode { return writeString(writer, node.Value+"\n") } @@ -79,7 +78,7 @@ func (pe *propertiesEncoder) Encode(writer io.Writer, node *yaml.Node) error { return err } -func (pe *propertiesEncoder) doEncode(p *properties.Properties, node *yaml.Node, path string, keyNode *yaml.Node) error { +func (pe *propertiesEncoder) doEncode(p *properties.Properties, node *CandidateNode, path string, keyNode *CandidateNode) error { comments := "" if keyNode != nil { @@ -91,7 +90,7 @@ func (pe *propertiesEncoder) doEncode(p *properties.Properties, node *yaml.Node, p.SetComments(path, strings.Split(commentsWithSpaces, "\n")) switch node.Kind { - case yaml.ScalarNode: + case ScalarNode: var nodeValue string if pe.unwrapScalar || !strings.Contains(node.Value, " ") { nodeValue = node.Value @@ -100,13 +99,11 @@ func (pe *propertiesEncoder) doEncode(p *properties.Properties, node *yaml.Node, } _, _, err := p.Set(path, nodeValue) return err - case yaml.DocumentNode: - return pe.doEncode(p, node.Content[0], path, node) - case yaml.SequenceNode: + case SequenceNode: return pe.encodeArray(p, node.Content, path) - case yaml.MappingNode: + case MappingNode: return pe.encodeMap(p, node.Content, path) - case yaml.AliasNode: + case AliasNode: return pe.doEncode(p, node.Alias, path, nil) default: return fmt.Errorf("Unsupported node %v", node.Tag) @@ -120,7 +117,7 @@ func (pe *propertiesEncoder) appendPath(path string, key interface{}) string { return fmt.Sprintf("%v.%v", path, key) } -func (pe *propertiesEncoder) encodeArray(p *properties.Properties, kids []*yaml.Node, path string) error { +func (pe *propertiesEncoder) encodeArray(p *properties.Properties, kids []*CandidateNode, path string) error { for index, child := range kids { err := pe.doEncode(p, child, pe.appendPath(path, index), nil) if err != nil { @@ -130,7 +127,7 @@ func (pe *propertiesEncoder) encodeArray(p *properties.Properties, kids []*yaml. return nil } -func (pe *propertiesEncoder) encodeMap(p *properties.Properties, kids []*yaml.Node, path string) error { +func (pe *propertiesEncoder) encodeMap(p *properties.Properties, kids []*CandidateNode, path string) error { for index := 0; index < len(kids); index = index + 2 { key := kids[index] value := kids[index+1] diff --git a/pkg/yqlib/encoder_properties_test.go b/pkg/yqlib/encoder_properties_test.go index d1ed5cf6108..70138fe1e82 100644 --- a/pkg/yqlib/encoder_properties_test.go +++ b/pkg/yqlib/encoder_properties_test.go @@ -18,7 +18,7 @@ func yamlToProps(sampleYaml string, unwrapScalar bool) string { if err != nil { panic(err) } - node := inputs.Front().Value.(*CandidateNode).Node + node := inputs.Front().Value.(*CandidateNode) err = propsEncoder.Encode(writer, node) if err != nil { panic(err) diff --git a/pkg/yqlib/encoder_sh.go b/pkg/yqlib/encoder_sh.go index 1cee7fa0bf1..3c54039963b 100644 --- a/pkg/yqlib/encoder_sh.go +++ b/pkg/yqlib/encoder_sh.go @@ -5,8 +5,6 @@ import ( "io" "regexp" "strings" - - yaml "gopkg.in/yaml.v3" ) var unsafeChars = regexp.MustCompile(`[^\w@%+=:,./-]`) @@ -31,13 +29,12 @@ func (e *shEncoder) PrintLeadingContent(writer io.Writer, content string) error return nil } -func (e *shEncoder) Encode(writer io.Writer, originalNode *yaml.Node) error { - node := unwrapDoc(originalNode) - if guessTagFromCustomType(node) != "!!str" { +func (e *shEncoder) Encode(writer io.Writer, node *CandidateNode) error { + if node.guessTagFromCustomType() != "!!str" { return fmt.Errorf("cannot encode %v as URI, can only operate on strings. Please first pipe through another encoding operator to convert the value to a string", node.Tag) } - return writeString(writer, e.encode(originalNode.Value)) + return writeString(writer, e.encode(node.Value)) } // put any (shell-unsafe) characters into a single-quoted block, close the block lazily diff --git a/pkg/yqlib/encoder_shellvariables.go b/pkg/yqlib/encoder_shellvariables.go index 62d6ac8f1be..d725dae3fef 100644 --- a/pkg/yqlib/encoder_shellvariables.go +++ b/pkg/yqlib/encoder_shellvariables.go @@ -7,7 +7,6 @@ import ( "unicode/utf8" "golang.org/x/text/unicode/norm" - yaml "gopkg.in/yaml.v3" ) type shellVariablesEncoder struct { @@ -29,7 +28,7 @@ func (pe *shellVariablesEncoder) PrintLeadingContent(_ io.Writer, _ string) erro return nil } -func (pe *shellVariablesEncoder) Encode(writer io.Writer, node *yaml.Node) error { +func (pe *shellVariablesEncoder) Encode(writer io.Writer, node *CandidateNode) error { mapKeysToStrings(node) err := pe.doEncode(&writer, node, "") @@ -40,12 +39,12 @@ func (pe *shellVariablesEncoder) Encode(writer io.Writer, node *yaml.Node) error return err } -func (pe *shellVariablesEncoder) doEncode(w *io.Writer, node *yaml.Node, path string) error { +func (pe *shellVariablesEncoder) doEncode(w *io.Writer, node *CandidateNode, path string) error { // Note this drops all comments. switch node.Kind { - case yaml.ScalarNode: + case ScalarNode: nonemptyPath := path if path == "" { // We can't assign an empty variable "=somevalue" because that would error out if sourced in a shell, @@ -55,9 +54,7 @@ func (pe *shellVariablesEncoder) doEncode(w *io.Writer, node *yaml.Node, path st } _, err := io.WriteString(*w, nonemptyPath+"="+quoteValue(node.Value)+"\n") return err - case yaml.DocumentNode: - return pe.doEncode(w, node.Content[0], path) - case yaml.SequenceNode: + case SequenceNode: for index, child := range node.Content { err := pe.doEncode(w, child, appendPath(path, index)) if err != nil { @@ -65,7 +62,7 @@ func (pe *shellVariablesEncoder) doEncode(w *io.Writer, node *yaml.Node, path st } } return nil - case yaml.MappingNode: + case MappingNode: for index := 0; index < len(node.Content); index = index + 2 { key := node.Content[index] value := node.Content[index+1] @@ -75,7 +72,7 @@ func (pe *shellVariablesEncoder) doEncode(w *io.Writer, node *yaml.Node, path st } } return nil - case yaml.AliasNode: + case AliasNode: return pe.doEncode(w, node.Alias, path) default: return fmt.Errorf("Unsupported node %v", node.Tag) diff --git a/pkg/yqlib/encoder_shellvariables_test.go b/pkg/yqlib/encoder_shellvariables_test.go index b3259088a8c..3d3d905f07d 100644 --- a/pkg/yqlib/encoder_shellvariables_test.go +++ b/pkg/yqlib/encoder_shellvariables_test.go @@ -18,7 +18,7 @@ func assertEncodesTo(t *testing.T, yaml string, shellvars string) { if err != nil { panic(err) } - node := inputs.Front().Value.(*CandidateNode).Node + node := inputs.Front().Value.(*CandidateNode) err = encoder.Encode(writer, node) if err != nil { panic(err) diff --git a/pkg/yqlib/encoder_test.go b/pkg/yqlib/encoder_test.go index cb384562635..c2fc8628235 100644 --- a/pkg/yqlib/encoder_test.go +++ b/pkg/yqlib/encoder_test.go @@ -11,7 +11,8 @@ import ( "github.com/mikefarah/yq/v4/test" ) -func yamlToJSON(sampleYaml string, indent int) string { +func yamlToJSON(t *testing.T, sampleYaml string, indent int) string { + t.Helper() var output bytes.Buffer writer := bufio.NewWriter(&output) @@ -20,7 +21,10 @@ func yamlToJSON(sampleYaml string, indent int) string { if err != nil { panic(err) } - node := inputs.Front().Value.(*CandidateNode).Node + node := inputs.Front().Value.(*CandidateNode) + log.Debugf("%v", NodeToString(node)) + // log.Debugf("Content[0] %v", NodeToString(node.Content[0])) + err = jsonEncoder.Encode(writer, node) if err != nil { panic(err) @@ -46,31 +50,31 @@ banana: } ] }` - var actualJSON = yamlToJSON(sampleYaml, 2) + var actualJSON = yamlToJSON(t, sampleYaml, 2) test.AssertResult(t, expectedJSON, actualJSON) } func TestJsonNullInArray(t *testing.T) { var sampleYaml = `[null]` - var actualJSON = yamlToJSON(sampleYaml, 0) + var actualJSON = yamlToJSON(t, sampleYaml, 0) test.AssertResult(t, sampleYaml, actualJSON) } func TestJsonNull(t *testing.T) { var sampleYaml = `null` - var actualJSON = yamlToJSON(sampleYaml, 0) + var actualJSON = yamlToJSON(t, sampleYaml, 0) test.AssertResult(t, sampleYaml, actualJSON) } func TestJsonNullInObject(t *testing.T) { var sampleYaml = `{x: null}` - var actualJSON = yamlToJSON(sampleYaml, 0) + var actualJSON = yamlToJSON(t, sampleYaml, 0) test.AssertResult(t, `{"x":null}`, actualJSON) } func TestJsonEncoderDoesNotEscapeHTMLChars(t *testing.T) { var sampleYaml = `build: "( ./lint && ./format && ./compile ) < src.code"` var expectedJSON = `{"build":"( ./lint && ./format && ./compile ) < src.code"}` - var actualJSON = yamlToJSON(sampleYaml, 0) + var actualJSON = yamlToJSON(t, sampleYaml, 0) test.AssertResult(t, expectedJSON, actualJSON) } diff --git a/pkg/yqlib/encoder_toml.go b/pkg/yqlib/encoder_toml.go index 13b4e1e37e0..44e4e8b5971 100644 --- a/pkg/yqlib/encoder_toml.go +++ b/pkg/yqlib/encoder_toml.go @@ -3,8 +3,6 @@ package yqlib import ( "fmt" "io" - - yaml "gopkg.in/yaml.v3" ) type tomlEncoder struct { @@ -14,8 +12,8 @@ func NewTomlEncoder() Encoder { return &tomlEncoder{} } -func (te *tomlEncoder) Encode(writer io.Writer, node *yaml.Node) error { - if node.Kind == yaml.ScalarNode { +func (te *tomlEncoder) Encode(writer io.Writer, node *CandidateNode) error { + if node.Kind == ScalarNode { return writeString(writer, node.Value+"\n") } return fmt.Errorf("only scalars (e.g. strings, numbers, booleans) are supported for TOML output at the moment. Please use yaml output format (-oy) until the encoder has been fully implemented") diff --git a/pkg/yqlib/encoder_uri.go b/pkg/yqlib/encoder_uri.go index fdf58665a83..194350c4544 100644 --- a/pkg/yqlib/encoder_uri.go +++ b/pkg/yqlib/encoder_uri.go @@ -4,8 +4,6 @@ import ( "fmt" "io" "net/url" - - yaml "gopkg.in/yaml.v3" ) type uriEncoder struct { @@ -27,11 +25,10 @@ func (e *uriEncoder) PrintLeadingContent(writer io.Writer, content string) error return nil } -func (e *uriEncoder) Encode(writer io.Writer, originalNode *yaml.Node) error { - node := unwrapDoc(originalNode) - if guessTagFromCustomType(node) != "!!str" { +func (e *uriEncoder) Encode(writer io.Writer, node *CandidateNode) error { + if node.guessTagFromCustomType() != "!!str" { return fmt.Errorf("cannot encode %v as URI, can only operate on strings. Please first pipe through another encoding operator to convert the value to a string", node.Tag) } - _, err := writer.Write([]byte(url.QueryEscape(originalNode.Value))) + _, err := writer.Write([]byte(url.QueryEscape(node.Value))) return err } diff --git a/pkg/yqlib/encoder_xml.go b/pkg/yqlib/encoder_xml.go index 2e48bd99aa1..1d55d902a57 100644 --- a/pkg/yqlib/encoder_xml.go +++ b/pkg/yqlib/encoder_xml.go @@ -8,8 +8,6 @@ import ( "io" "regexp" "strings" - - yaml "gopkg.in/yaml.v3" ) type xmlEncoder struct { @@ -41,19 +39,18 @@ func (e *xmlEncoder) PrintLeadingContent(writer io.Writer, content string) error return nil } -func (e *xmlEncoder) Encode(writer io.Writer, node *yaml.Node) error { +func (e *xmlEncoder) Encode(writer io.Writer, node *CandidateNode) error { encoder := xml.NewEncoder(writer) // hack so we can manually add newlines to procInst and directives e.writer = writer encoder.Indent("", e.indentString) var newLine xml.CharData = []byte("\n") - mapNode := unwrapDoc(node) - if mapNode.Tag == "!!map" { + if node.Tag == "!!map" { // make sure processing instructions are encoded first - for i := 0; i < len(mapNode.Content); i += 2 { - key := mapNode.Content[i] - value := mapNode.Content[i+1] + for i := 0; i < len(node.Content); i += 2 { + key := node.Content[i] + value := node.Content[i+1] if key.Value == (e.prefs.ProcInstPrefix + "xml") { name := strings.Replace(key.Value, e.prefs.ProcInstPrefix, "", 1) @@ -82,29 +79,12 @@ func (e *xmlEncoder) Encode(writer io.Writer, node *yaml.Node) error { } switch node.Kind { - case yaml.MappingNode: + case MappingNode: err := e.encodeTopLevelMap(encoder, node) if err != nil { return err } - case yaml.DocumentNode: - err := e.encodeComment(encoder, headAndLineComment(node)) - if err != nil { - return err - } - unwrappedNode := unwrapDoc(node) - if unwrappedNode.Kind != yaml.MappingNode { - return fmt.Errorf("cannot encode %v to XML - only maps can be encoded", unwrappedNode.Tag) - } - err = e.encodeTopLevelMap(encoder, unwrappedNode) - if err != nil { - return err - } - err = e.encodeComment(encoder, footComment(node)) - if err != nil { - return err - } - case yaml.ScalarNode: + case ScalarNode: var charData xml.CharData = []byte(node.Value) err := encoder.EncodeToken(charData) if err != nil { @@ -112,14 +92,14 @@ func (e *xmlEncoder) Encode(writer io.Writer, node *yaml.Node) error { } return encoder.Flush() default: - return fmt.Errorf("unsupported type %v", node.Tag) + return fmt.Errorf("cannot encode %v to XML - only maps can be encoded", node.Tag) } return encoder.EncodeToken(newLine) } -func (e *xmlEncoder) encodeTopLevelMap(encoder *xml.Encoder, node *yaml.Node) error { +func (e *xmlEncoder) encodeTopLevelMap(encoder *xml.Encoder, node *CandidateNode) error { err := e.encodeComment(encoder, headAndLineComment(node)) if err != nil { return err @@ -178,7 +158,7 @@ func (e *xmlEncoder) encodeTopLevelMap(encoder *xml.Encoder, node *yaml.Node) er return e.encodeComment(encoder, footComment(node)) } -func (e *xmlEncoder) encodeStart(encoder *xml.Encoder, node *yaml.Node, start xml.StartElement) error { +func (e *xmlEncoder) encodeStart(encoder *xml.Encoder, node *CandidateNode, start xml.StartElement) error { err := encoder.EncodeToken(start) if err != nil { return err @@ -186,7 +166,7 @@ func (e *xmlEncoder) encodeStart(encoder *xml.Encoder, node *yaml.Node, start xm return e.encodeComment(encoder, headComment(node)) } -func (e *xmlEncoder) encodeEnd(encoder *xml.Encoder, node *yaml.Node, start xml.StartElement) error { +func (e *xmlEncoder) encodeEnd(encoder *xml.Encoder, node *CandidateNode, start xml.StartElement) error { err := encoder.EncodeToken(start.End()) if err != nil { return err @@ -194,13 +174,13 @@ func (e *xmlEncoder) encodeEnd(encoder *xml.Encoder, node *yaml.Node, start xml. return e.encodeComment(encoder, footComment(node)) } -func (e *xmlEncoder) doEncode(encoder *xml.Encoder, node *yaml.Node, start xml.StartElement) error { +func (e *xmlEncoder) doEncode(encoder *xml.Encoder, node *CandidateNode, start xml.StartElement) error { switch node.Kind { - case yaml.MappingNode: + case MappingNode: return e.encodeMap(encoder, node, start) - case yaml.SequenceNode: + case SequenceNode: return e.encodeArray(encoder, node, start) - case yaml.ScalarNode: + case ScalarNode: err := e.encodeStart(encoder, node, start) if err != nil { return err @@ -258,7 +238,7 @@ func (e *xmlEncoder) encodeComment(encoder *xml.Encoder, commentStr string) erro return nil } -func (e *xmlEncoder) encodeArray(encoder *xml.Encoder, node *yaml.Node, start xml.StartElement) error { +func (e *xmlEncoder) encodeArray(encoder *xml.Encoder, node *CandidateNode, start xml.StartElement) error { if err := e.encodeComment(encoder, headAndLineComment(node)); err != nil { return err @@ -280,7 +260,7 @@ func (e *xmlEncoder) isAttribute(name string) bool { !strings.HasPrefix(name, e.prefs.ProcInstPrefix) } -func (e *xmlEncoder) encodeMap(encoder *xml.Encoder, node *yaml.Node, start xml.StartElement) error { +func (e *xmlEncoder) encodeMap(encoder *xml.Encoder, node *CandidateNode, start xml.StartElement) error { log.Debug("its a map") //first find all the attributes and put them on the start token @@ -289,7 +269,7 @@ func (e *xmlEncoder) encodeMap(encoder *xml.Encoder, node *yaml.Node, start xml. value := node.Content[i+1] if e.isAttribute(key.Value) { - if value.Kind == yaml.ScalarNode { + if value.Kind == ScalarNode { attributeName := strings.Replace(key.Value, e.prefs.AttributePrefix, "", 1) start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: attributeName}, Value: value.Value}) } else { diff --git a/pkg/yqlib/encoder_yaml.go b/pkg/yqlib/encoder_yaml.go index e2a9943cd3b..0d26437ada6 100644 --- a/pkg/yqlib/encoder_yaml.go +++ b/pkg/yqlib/encoder_yaml.go @@ -5,6 +5,7 @@ import ( "bytes" "errors" "io" + "regexp" "strings" yaml "gopkg.in/yaml.v3" @@ -40,6 +41,8 @@ func (ye *yamlEncoder) PrintDocumentSeparator(writer io.Writer) error { func (ye *yamlEncoder) PrintLeadingContent(writer io.Writer, content string) error { reader := bufio.NewReader(strings.NewReader(content)) + var commentLineRegEx = regexp.MustCompile(`^\s*#`) + for { readline, errReading := reader.ReadString('\n') @@ -53,6 +56,9 @@ func (ye *yamlEncoder) PrintLeadingContent(writer io.Writer, content string) err } } else { + if len(readline) > 0 && readline != "\n" && readline[0] != '%' && !commentLineRegEx.MatchString(readline) { + readline = "# " + readline + } if err := writeString(writer, readline); err != nil { return err } @@ -72,10 +78,14 @@ func (ye *yamlEncoder) PrintLeadingContent(writer io.Writer, content string) err return nil } -func (ye *yamlEncoder) Encode(writer io.Writer, node *yaml.Node) error { - - if node.Kind == yaml.ScalarNode && ye.prefs.UnwrapScalar { - return writeString(writer, node.Value+"\n") +func (ye *yamlEncoder) Encode(writer io.Writer, node *CandidateNode) error { + log.Debug("encoderYaml - going to print %v", NodeToString(node)) + if node.Kind == ScalarNode && ye.prefs.UnwrapScalar { + valueToPrint := node.Value + if node.LeadingContent == "" || valueToPrint != "" { + valueToPrint = valueToPrint + "\n" + } + return writeString(writer, valueToPrint) } destination := writer @@ -88,7 +98,20 @@ func (ye *yamlEncoder) Encode(writer io.Writer, node *yaml.Node) error { encoder.SetIndent(ye.indent) - if err := encoder.Encode(node); err != nil { + target, err := node.MarshalYAML() + + if err != nil { + return err + } + + trailingContent := target.FootComment + target.FootComment = "" + + if err := encoder.Encode(target); err != nil { + return err + } + + if err := ye.PrintLeadingContent(destination, trailingContent); err != nil { return err } diff --git a/pkg/yqlib/goccy_yaml_test.go b/pkg/yqlib/goccy_yaml_test.go new file mode 100644 index 00000000000..018a849a9c3 --- /dev/null +++ b/pkg/yqlib/goccy_yaml_test.go @@ -0,0 +1,170 @@ +package yqlib + +import ( + "testing" + + "github.com/mikefarah/yq/v4/test" +) + +var goccyYamlFormatScenarios = []formatScenario{ + { + description: "basic - 3", + skipDoc: true, + input: "3", + expected: "3\n", + }, + { + description: "basic - 3.1", + skipDoc: true, + input: "3.1", + expected: "3.1\n", + }, + { + description: "basic - 3.1", + skipDoc: true, + input: "mike: 3", + expected: "mike: 3\n", + }, + { + description: "basic - 3.1", + skipDoc: true, + input: "{mike: 3}", + expected: "{mike: 3}\n", + }, + { + description: "basic - map multiple entries", + skipDoc: true, + input: "mike: 3\nfred: 12\n", + expected: "mike: 3\nfred: 12\n", + }, + { + description: "basic - 3.1", + skipDoc: true, + input: "{\nmike: 3\n}", + expected: "{mike: 3}\n", + }, + { + description: "basic - 3.1", + skipDoc: true, + input: "mike: !!cat 3", + expected: "mike: !!cat 3\n", + }, + { + description: "basic - 3.1", + skipDoc: true, + input: "- 3", + expected: "- 3\n", + }, + { + description: "basic - 3.1", + skipDoc: true, + input: "[3]", + expected: "[3]\n", + }, + { + description: "basic - plain string", + skipDoc: true, + input: `a: meow`, + expected: "a: meow\n", + }, + { + description: "basic - double quoted string", + skipDoc: true, + input: `a: "meow"`, + expected: "a: \"meow\"\n", + }, + { + description: "basic - single quoted string", + skipDoc: true, + input: `a: 'meow'`, + expected: "a: 'meow'\n", + }, + { + description: "basic - string block", + skipDoc: true, + input: "a: |\n meow\n", + expected: "a: |\n meow\n", + }, + { + description: "basic - long string", + skipDoc: true, + input: "a: the cute cat wrote a long sentence that wasn't wrapped at all.\n", + expected: "a: the cute cat wrote a long sentence that wasn't wrapped at all.\n", + }, + { + description: "basic - string block", + skipDoc: true, + input: "a: |-\n meow\n", + expected: "a: |-\n meow\n", + }, + { + description: "basic - line comment", + skipDoc: true, + input: "a: meow # line comment\n", + expected: "a: meow # line comment\n", + }, + { + description: "basic - line comment", + skipDoc: true, + input: "# head comment\na: #line comment\n meow\n", + expected: "# head comment\na: meow #line comment\n", // go-yaml does this + }, + { + description: "basic - foot comment", + skipDoc: true, + input: "a: meow\n# foot comment\n", + expected: "a: meow\n# foot comment\n", + }, + { + description: "basic - foot comment", + skipDoc: true, + input: "a: meow\nb: woof\n# foot comment\n", + expected: "a: meow\nb: woof\n# foot comment\n", + }, + { + description: "basic - boolean", + skipDoc: true, + input: "true\n", + expected: "true\n", + }, + { + description: "basic - null", + skipDoc: true, + input: "a: null\n", + expected: "a: null\n", + }, + { + description: "basic - ~", + skipDoc: true, + input: "a: ~\n", + expected: "a: ~\n", + }, + // { + // description: "basic - ~", + // skipDoc: true, + // input: "null\n", + // expected: "null\n", + // }, + // { + // skipDoc: true, + // description: "trailing comment", + // input: "test:", + // expected: "test:", + // }, + // { + // skipDoc: true, + // description: "trailing comment", + // input: "test:\n# this comment will be removed", + // expected: "test:\n# this comment will be removed", + // }, +} + +func testGoccyYamlScenario(t *testing.T, s formatScenario) { + test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewGoccyYAMLDecoder(), NewYamlEncoder(2, false, ConfiguredYamlPreferences)), s.description) +} + +func TestGoccyYmlFormatScenarios(t *testing.T) { + for _, tt := range goccyYamlFormatScenarios { + testGoccyYamlScenario(t, tt) + } +} diff --git a/pkg/yqlib/json_test.go b/pkg/yqlib/json_test.go index cda716baab7..ab0c7225b19 100644 --- a/pkg/yqlib/json_test.go +++ b/pkg/yqlib/json_test.go @@ -11,12 +11,12 @@ import ( "github.com/mikefarah/yq/v4/test" ) -const complexExpectYaml = `D0, P[], (!!map)::a: Easy! as one two three +const complexExpectYaml = `a: Easy! as one two three b: - c: 2 - d: - - 3 - - 4 + c: 2 + d: + - 3 + - 4 ` const sampleNdJson = `{"this": "is a multidoc json file"} @@ -99,13 +99,54 @@ var jsonScenarios = []formatScenario{ description: "Parse json: simple", subdescription: "JSON is a subset of yaml, so all you need to do is prettify the output", input: `{"cat": "meow"}`, - expected: "D0, P[], (!!map)::cat: meow\n", + scenarioType: "decode-ndjson", + expected: "cat: meow\n", + }, + { + skipDoc: true, + description: "Parse json: simple: key", + input: `{"cat": "meow"}`, + expression: ".cat | key", + expected: "\"cat\"\n", + scenarioType: "decode", + }, + { + skipDoc: true, + description: "Parse json: simple: parent", + input: `{"cat": "meow"}`, + expression: ".cat | parent", + expected: "{\"cat\":\"meow\"}\n", + scenarioType: "decode", + }, + { + skipDoc: true, + description: "Parse json: simple: path", + input: `{"cat": "meow"}`, + expression: ".cat | path", + expected: "[\"cat\"]\n", + scenarioType: "decode", + }, + { + skipDoc: true, + description: "Parse json: deeper: path", + input: `{"cat": {"noises": "meow"}}`, + expression: ".cat.noises | path", + expected: "[\"cat\",\"noises\"]\n", + scenarioType: "decode", + }, + { + skipDoc: true, + description: "Parse json: array path", + input: `{"cat": {"noises": ["meow"]}}`, + expression: ".cat.noises[0] | path", + expected: "[\"cat\",\"noises\",0]\n", + scenarioType: "decode", }, { description: "bad json", skipDoc: true, - input: `{"a": 1 "b": 2}`, - expectedError: `bad file 'sample.yml': invalid character '"' after object key:value pair`, + input: `{"a": 1 b": 2}`, + expectedError: `bad file 'sample.yml': json: string of object unexpected end of JSON input`, scenarioType: "decode-error", }, { @@ -113,6 +154,7 @@ var jsonScenarios = []formatScenario{ subdescription: "JSON is a subset of yaml, so all you need to do is prettify the output", input: `{"a":"Easy! as one two three","b":{"c":2,"d":[3,4]}}`, expected: complexExpectYaml, + scenarioType: "decode-ndjson", }, { description: "Encode json: simple", @@ -213,7 +255,7 @@ var jsonScenarios = []formatScenario{ description: "empty string", skipDoc: true, input: `""`, - expected: "\"\"\n", + expected: "\n", scenarioType: "decode-ndjson", }, { @@ -316,11 +358,10 @@ func decodeJSON(t *testing.T, jsonString string) *CandidateNode { func testJSONScenario(t *testing.T, s formatScenario) { switch s.scenarioType { - case "encode", "decode": + case "encode": test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewJSONEncoder(s.indent, false, false)), s.description) - case "": - var actual = resultToString(t, decodeJSON(t, s.input)) - test.AssertResultWithContext(t, s.expected, actual, s.description) + case "decode": + test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(s.indent, false, false)), s.description) case "decode-ndjson": test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewYamlEncoder(2, false, ConfiguredYamlPreferences)), s.description) case "roundtrip-ndjson": diff --git a/pkg/yqlib/lexer_participle_test.go b/pkg/yqlib/lexer_participle_test.go index 1df7fec8361..a6244bb32f7 100644 --- a/pkg/yqlib/lexer_participle_test.go +++ b/pkg/yqlib/lexer_participle_test.go @@ -5,7 +5,6 @@ import ( "github.com/alecthomas/repr" "github.com/mikefarah/yq/v4/test" - yaml "gopkg.in/yaml.v3" ) type participleLexerScenario struct { @@ -64,11 +63,9 @@ var participleLexerScenarios = []participleLexerScenario{ Value: 0, StringValue: "0", CandidateNode: &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.ScalarNode, - Tag: "!!int", - Value: "0", - }, + Kind: ScalarNode, + Tag: "!!int", + Value: "0", }, }, }, @@ -87,11 +84,9 @@ var participleLexerScenarios = []participleLexerScenario{ Value: int64(3), StringValue: "3", CandidateNode: &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.Kind(8), - Tag: "!!int", - Value: "3", - }, + Kind: ScalarNode, + Tag: "!!int", + Value: "3", }, }, }, @@ -129,11 +124,9 @@ var participleLexerScenarios = []participleLexerScenario{ Value: int64(-2), StringValue: "-2", CandidateNode: &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.ScalarNode, - Tag: "!!int", - Value: "-2", - }, + Kind: ScalarNode, + Tag: "!!int", + Value: "-2", }, }, }, @@ -654,11 +647,9 @@ var participleLexerScenarios = []participleLexerScenario{ StringValue: "string with a\n", Preferences: nil, CandidateNode: &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.ScalarNode, - Tag: "!!str", - Value: "string with a\n", - }, + Kind: ScalarNode, + Tag: "!!str", + Value: "string with a\n", }, }, }, @@ -675,11 +666,9 @@ var participleLexerScenarios = []participleLexerScenario{ StringValue: `string with a "`, Preferences: nil, CandidateNode: &CandidateNode{ - Node: &yaml.Node{ - Kind: yaml.ScalarNode, - Tag: "!!str", - Value: `string with a "`, - }, + Kind: ScalarNode, + Tag: "!!str", + Value: `string with a "`, }, }, }, diff --git a/pkg/yqlib/lib.go b/pkg/yqlib/lib.go index b88b9e2d5dd..78bd31ba4a1 100644 --- a/pkg/yqlib/lib.go +++ b/pkg/yqlib/lib.go @@ -2,7 +2,6 @@ package yqlib import ( - "bytes" "container/list" "fmt" "math" @@ -10,7 +9,6 @@ import ( "strings" logging "gopkg.in/op/go-logging.v1" - yaml "gopkg.in/yaml.v3" ) var ExpressionParser ExpressionParserInterface @@ -191,7 +189,7 @@ type Operation struct { UpdateAssign bool // used for assign ops, when true it means we evaluate the rhs given the lhs } -func recurseNodeArrayEqual(lhs *yaml.Node, rhs *yaml.Node) bool { +func recurseNodeArrayEqual(lhs *CandidateNode, rhs *CandidateNode) bool { if len(lhs.Content) != len(rhs.Content) { return false } @@ -204,7 +202,7 @@ func recurseNodeArrayEqual(lhs *yaml.Node, rhs *yaml.Node) bool { return true } -func findInArray(array *yaml.Node, item *yaml.Node) int { +func findInArray(array *CandidateNode, item *CandidateNode) int { for index := 0; index < len(array.Content); index = index + 1 { if recursiveNodeEqual(array.Content[index], item) { @@ -214,7 +212,7 @@ func findInArray(array *yaml.Node, item *yaml.Node) int { return -1 } -func findKeyInMap(dataMap *yaml.Node, item *yaml.Node) int { +func findKeyInMap(dataMap *CandidateNode, item *CandidateNode) int { for index := 0; index < len(dataMap.Content); index = index + 2 { if recursiveNodeEqual(dataMap.Content[index], item) { @@ -224,7 +222,7 @@ func findKeyInMap(dataMap *yaml.Node, item *yaml.Node) int { return -1 } -func recurseNodeObjectEqual(lhs *yaml.Node, rhs *yaml.Node) bool { +func recurseNodeObjectEqual(lhs *CandidateNode, rhs *CandidateNode) bool { if len(lhs.Content) != len(rhs.Content) { return false } @@ -242,28 +240,10 @@ func recurseNodeObjectEqual(lhs *yaml.Node, rhs *yaml.Node) bool { return true } -func guessTagFromCustomType(node *yaml.Node) string { - if strings.HasPrefix(node.Tag, "!!") { - return node.Tag - } else if node.Value == "" { - log.Debug("guessTagFromCustomType: node has no value to guess the type with") - return node.Tag - } - dataBucket, errorReading := parseSnippet(node.Value) - - if errorReading != nil { - log.Debug("guessTagFromCustomType: could not guess underlying tag type %v", errorReading) - return node.Tag - } - guessedTag := unwrapDoc(dataBucket).Tag - log.Info("im guessing the tag %v is a %v", node.Tag, guessedTag) - return guessedTag -} - -func parseSnippet(value string) (*yaml.Node, error) { +func parseSnippet(value string) (*CandidateNode, error) { if value == "" { - return &yaml.Node{ - Kind: yaml.ScalarNode, + return &CandidateNode{ + Kind: ScalarNode, Tag: "!!null", }, nil } @@ -272,30 +252,26 @@ func parseSnippet(value string) (*yaml.Node, error) { if err != nil { return nil, err } - parsedNode, err := decoder.Decode() + result, err := decoder.Decode() if err != nil { return nil, err } - if len(parsedNode.Node.Content) == 0 { - return nil, fmt.Errorf("bad data") - } - result := unwrapDoc(parsedNode.Node) result.Line = 0 result.Column = 0 return result, err } -func recursiveNodeEqual(lhs *yaml.Node, rhs *yaml.Node) bool { +func recursiveNodeEqual(lhs *CandidateNode, rhs *CandidateNode) bool { if lhs.Kind != rhs.Kind { return false } - if lhs.Kind == yaml.ScalarNode { + if lhs.Kind == ScalarNode { //process custom tags of scalar nodes. //dont worry about matching tags of maps or arrays. - lhsTag := guessTagFromCustomType(lhs) - rhsTag := guessTagFromCustomType(rhs) + lhsTag := lhs.guessTagFromCustomType() + rhsTag := rhs.guessTagFromCustomType() if lhsTag != rhsTag { return false @@ -305,75 +281,32 @@ func recursiveNodeEqual(lhs *yaml.Node, rhs *yaml.Node) bool { if lhs.Tag == "!!null" { return true - } else if lhs.Kind == yaml.ScalarNode { + } else if lhs.Kind == ScalarNode { return lhs.Value == rhs.Value - } else if lhs.Kind == yaml.SequenceNode { + } else if lhs.Kind == SequenceNode { return recurseNodeArrayEqual(lhs, rhs) - } else if lhs.Kind == yaml.MappingNode { + } else if lhs.Kind == MappingNode { return recurseNodeObjectEqual(lhs, rhs) } return false } -func deepCloneContent(content []*yaml.Node) []*yaml.Node { - clonedContent := make([]*yaml.Node, len(content)) - for i, child := range content { - clonedContent[i] = deepClone(child) - } - return clonedContent -} - -func deepCloneNoContent(node *yaml.Node) *yaml.Node { - return deepCloneWithOptions(node, false) -} -func deepClone(node *yaml.Node) *yaml.Node { - return deepCloneWithOptions(node, true) -} - -func deepCloneWithOptions(node *yaml.Node, cloneContent bool) *yaml.Node { - if node == nil { - return nil - } - var clonedContent []*yaml.Node - if cloneContent { - clonedContent = deepCloneContent(node.Content) - } - return &yaml.Node{ - Content: clonedContent, - Kind: node.Kind, - Style: node.Style, - Tag: node.Tag, - Value: node.Value, - Anchor: node.Anchor, - Alias: node.Alias, - HeadComment: node.HeadComment, - LineComment: node.LineComment, - FootComment: node.FootComment, - Line: node.Line, - Column: node.Column, - } -} - -// yaml numbers can be hex encoded... +// yaml numbers can be hex and octal encoded... func parseInt64(numberString string) (string, int64, error) { if strings.HasPrefix(numberString, "0x") || strings.HasPrefix(numberString, "0X") { num, err := strconv.ParseInt(numberString[2:], 16, 64) return "0x%X", num, err + } else if strings.HasPrefix(numberString, "0o") { + num, err := strconv.ParseInt(numberString[2:], 8, 64) + return "0o%o", num, err } num, err := strconv.ParseInt(numberString, 10, 64) return "%v", num, err } func parseInt(numberString string) (int, error) { - var err error - var parsed int64 - if strings.HasPrefix(numberString, "0x") || - strings.HasPrefix(numberString, "0X") { - parsed, err = strconv.ParseInt(numberString[2:], 16, 64) - } else { - parsed, err = strconv.ParseInt(numberString, 10, 64) - } + _, parsed, err := parseInt64(numberString) if err != nil { return 0, err @@ -384,45 +317,19 @@ func parseInt(numberString string) (int, error) { return int(parsed), err } -func createStringScalarNode(stringValue string) *yaml.Node { - var node = &yaml.Node{Kind: yaml.ScalarNode} - node.Value = stringValue - node.Tag = "!!str" - return node -} - -func createScalarNode(value interface{}, stringValue string) *yaml.Node { - var node = &yaml.Node{Kind: yaml.ScalarNode} - node.Value = stringValue - - switch value.(type) { - case float32, float64: - node.Tag = "!!float" - case int, int64, int32: - node.Tag = "!!int" - case bool: - node.Tag = "!!bool" - case string: - node.Tag = "!!str" - case nil: - node.Tag = "!!null" - } - return node -} - -func headAndLineComment(node *yaml.Node) string { +func headAndLineComment(node *CandidateNode) string { return headComment(node) + lineComment(node) } -func headComment(node *yaml.Node) string { +func headComment(node *CandidateNode) string { return strings.Replace(node.HeadComment, "#", "", 1) } -func lineComment(node *yaml.Node) string { +func lineComment(node *CandidateNode) string { return strings.Replace(node.LineComment, "#", "", 1) } -func footComment(node *yaml.Node) string { +func footComment(node *CandidateNode) string { return strings.Replace(node.FootComment, "#", "", 1) } @@ -434,7 +341,7 @@ func createValueOperation(value interface{}, stringValue string) *Operation { OperationType: valueOpType, Value: value, StringValue: stringValue, - CandidateNode: &CandidateNode{Node: node}, + CandidateNode: node, } } @@ -471,40 +378,46 @@ func NodeToString(node *CandidateNode) string { if !log.IsEnabledFor(logging.DEBUG) { return "" } - value := node.Node - if value == nil { + if node == nil { return "-- nil --" } - buf := new(bytes.Buffer) - encoder := yaml.NewEncoder(buf) - errorEncoding := encoder.Encode(value) - if errorEncoding != nil { - log.Error("Error debugging node, %v", errorEncoding.Error()) + tag := node.Tag + if node.Kind == AliasNode { + tag = "alias" } - errorClosingEncoder := encoder.Close() - if errorClosingEncoder != nil { - log.Error("Error closing encoder: ", errorClosingEncoder.Error()) + valueToUse := node.Value + if valueToUse == "" { + valueToUse = fmt.Sprintf("%v kids", len(node.Content)) } - tag := value.Tag - if value.Kind == yaml.DocumentNode { - tag = "doc" - } else if value.Kind == yaml.AliasNode { - tag = "alias" + return fmt.Sprintf(`D%v, P%v, %v (%v)::%v`, node.GetDocument(), node.GetNicePath(), KindString(node.Kind), tag, valueToUse) +} + +func NodeContentToString(node *CandidateNode, depth int) string { + if !log.IsEnabledFor(logging.DEBUG) { + return "" + } + var sb strings.Builder + for _, child := range node.Content { + for i := 0; i < depth; i++ { + sb.WriteString(" ") + } + sb.WriteString("- ") + sb.WriteString(NodeToString(child)) + sb.WriteString("\n") + sb.WriteString(NodeContentToString(child, depth+1)) } - return fmt.Sprintf(`D%v, P%v, (%v)::%v`, node.Document, node.Path, tag, buf.String()) + return sb.String() } -func KindString(kind yaml.Kind) string { +func KindString(kind Kind) string { switch kind { - case yaml.ScalarNode: + case ScalarNode: return "ScalarNode" - case yaml.SequenceNode: + case SequenceNode: return "SequenceNode" - case yaml.MappingNode: + case MappingNode: return "MappingNode" - case yaml.DocumentNode: - return "DocumentNode" - case yaml.AliasNode: + case AliasNode: return "AliasNode" default: return "unknown!" diff --git a/pkg/yqlib/lib_test.go b/pkg/yqlib/lib_test.go index c3e01009114..ecd541a7eea 100644 --- a/pkg/yqlib/lib_test.go +++ b/pkg/yqlib/lib_test.go @@ -1,10 +1,10 @@ package yqlib import ( + "fmt" "testing" "github.com/mikefarah/yq/v4/test" - yaml "gopkg.in/yaml.v3" ) func TestGetLogger(t *testing.T) { @@ -16,7 +16,7 @@ func TestGetLogger(t *testing.T) { type parseSnippetScenario struct { snippet string - expected *yaml.Node + expected *CandidateNode expectedError string } @@ -27,15 +27,15 @@ var parseSnippetScenarios = []parseSnippetScenario{ }, { snippet: "", - expected: &yaml.Node{ - Kind: yaml.ScalarNode, + expected: &CandidateNode{ + Kind: ScalarNode, Tag: "!!null", }, }, { snippet: "null", - expected: &yaml.Node{ - Kind: yaml.ScalarNode, + expected: &CandidateNode{ + Kind: ScalarNode, Tag: "!!null", Value: "null", Line: 0, @@ -44,8 +44,8 @@ var parseSnippetScenarios = []parseSnippetScenario{ }, { snippet: "3", - expected: &yaml.Node{ - Kind: yaml.ScalarNode, + expected: &CandidateNode{ + Kind: ScalarNode, Tag: "!!int", Value: "3", Line: 0, @@ -54,8 +54,8 @@ var parseSnippetScenarios = []parseSnippetScenario{ }, { snippet: "cat", - expected: &yaml.Node{ - Kind: yaml.ScalarNode, + expected: &CandidateNode{ + Kind: ScalarNode, Tag: "!!str", Value: "cat", Line: 0, @@ -64,8 +64,8 @@ var parseSnippetScenarios = []parseSnippetScenario{ }, { snippet: "3.1", - expected: &yaml.Node{ - Kind: yaml.ScalarNode, + expected: &CandidateNode{ + Kind: ScalarNode, Tag: "!!float", Value: "3.1", Line: 0, @@ -74,8 +74,8 @@ var parseSnippetScenarios = []parseSnippetScenario{ }, { snippet: "true", - expected: &yaml.Node{ - Kind: yaml.ScalarNode, + expected: &CandidateNode{ + Kind: ScalarNode, Tag: "!!bool", Value: "true", Line: 0, @@ -93,7 +93,7 @@ func TestParseSnippet(t *testing.T) { } else { test.AssertResultComplexWithContext(t, tt.expectedError, err.Error(), tt.snippet) } - return + continue } if err != nil { t.Error(tt.snippet) @@ -102,3 +102,37 @@ func TestParseSnippet(t *testing.T) { test.AssertResultComplexWithContext(t, tt.expected, actual, tt.snippet) } } + +type parseInt64Scenario struct { + numberString string + expectedParsedNumber int64 +} + +var parseInt64Scenarios = []parseInt64Scenario{ + { + numberString: "34", + expectedParsedNumber: 34, + }, + { + numberString: "0x10", + expectedParsedNumber: 16, + }, + { + numberString: "0o10", + expectedParsedNumber: 8, + }, +} + +func TestParseInt64(t *testing.T) { + for _, tt := range parseInt64Scenarios { + format, actualNumber, err := parseInt64(tt.numberString) + + if err != nil { + t.Error(tt.numberString) + t.Error(err) + } + test.AssertResultComplexWithContext(t, tt.expectedParsedNumber, actualNumber, tt.numberString) + + test.AssertResultComplexWithContext(t, tt.numberString, fmt.Sprintf(format, actualNumber), fmt.Sprintf("Formatting of: %v", tt.numberString)) + } +} diff --git a/pkg/yqlib/lua_test.go b/pkg/yqlib/lua_test.go index bb36e9cc5ab..6e0bc8b637d 100644 --- a/pkg/yqlib/lua_test.go +++ b/pkg/yqlib/lua_test.go @@ -31,6 +31,38 @@ cities: - Perth `, }, + { + skipDoc: true, + description: "path", + expression: ".cities[2] | path", + input: `return { + ["country"] = "Australia"; -- this place + ["cities"] = { + "Sydney", + "Melbourne", + "Brisbane", + "Perth", + }; +}; +`, + expected: "- cities\n- 2\n", + }, + { + skipDoc: true, + description: "path", + expression: ".cities[2] | key", + input: `return { + ["country"] = "Australia"; -- this place + ["cities"] = { + "Sydney", + "Melbourne", + "Brisbane", + "Perth", + }; +}; +`, + expected: "2\n", + }, { description: "Basic output example", scenarioType: "encode", diff --git a/pkg/yqlib/matchKeyString.go b/pkg/yqlib/matchKeyString.go index bfea235ee29..bdfaa8dc388 100644 --- a/pkg/yqlib/matchKeyString.go +++ b/pkg/yqlib/matchKeyString.go @@ -4,7 +4,6 @@ func matchKey(name string, pattern string) (matched bool) { if pattern == "" { return name == pattern } - log.Debug("pattern: %v", pattern) if pattern == "*" { log.Debug("wild!") return true diff --git a/pkg/yqlib/operator_add.go b/pkg/yqlib/operator_add.go index 5b95c34b363..611dfa205cd 100644 --- a/pkg/yqlib/operator_add.go +++ b/pkg/yqlib/operator_add.go @@ -5,8 +5,6 @@ import ( "strconv" "strings" "time" - - yaml "gopkg.in/yaml.v3" ) func createAddOp(lhs *ExpressionNode, rhs *ExpressionNode) *ExpressionNode { @@ -19,23 +17,21 @@ func addAssignOperator(d *dataTreeNavigator, context Context, expressionNode *Ex return compoundAssignFunction(d, context, expressionNode, createAddOp) } -func toNodes(candidate *CandidateNode, lhs *CandidateNode) ([]*yaml.Node, error) { - if candidate.Node.Tag == "!!null" { - return []*yaml.Node{}, nil - } - clone, err := candidate.Copy() - if err != nil { - return nil, err +func toNodes(candidate *CandidateNode, lhs *CandidateNode) []*CandidateNode { + if candidate.Tag == "!!null" { + return []*CandidateNode{} } - switch candidate.Node.Kind { - case yaml.SequenceNode: - return clone.Node.Content, nil + clone := candidate.Copy() + + switch candidate.Kind { + case SequenceNode: + return clone.Content default: - if len(lhs.Node.Content) > 0 { - clone.Node.Style = lhs.Node.Content[0].Style + if len(lhs.Content) > 0 { + clone.Style = lhs.Content[0].Style } - return []*yaml.Node{clone.Node}, nil + return []*CandidateNode{clone} } } @@ -47,50 +43,42 @@ func addOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi } func add(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - lhs.Node = unwrapDoc(lhs.Node) - rhs.Node = unwrapDoc(rhs.Node) - - lhsNode := lhs.Node + lhsNode := lhs if lhsNode.Tag == "!!null" { - return lhs.CreateReplacement(rhs.Node), nil + return lhs.CopyAsReplacement(rhs), nil } - target := lhs.CreateReplacement(&yaml.Node{ - Anchor: lhs.Node.Anchor, - }) + target := lhs.CopyWithoutContent() switch lhsNode.Kind { - case yaml.MappingNode: - if rhs.Node.Kind != yaml.MappingNode { - return nil, fmt.Errorf("%v (%v) cannot be added to a %v (%v)", rhs.Node.Tag, rhs.GetNicePath(), lhsNode.Tag, lhs.GetNicePath()) + case MappingNode: + if rhs.Kind != MappingNode { + return nil, fmt.Errorf("%v (%v) cannot be added to a %v (%v)", rhs.Tag, rhs.GetNicePath(), lhsNode.Tag, lhs.GetNicePath()) } addMaps(target, lhs, rhs) - case yaml.SequenceNode: - if err := addSequences(target, lhs, rhs); err != nil { - return nil, err - } - - case yaml.ScalarNode: - if rhs.Node.Kind != yaml.ScalarNode { - return nil, fmt.Errorf("%v (%v) cannot be added to a %v (%v)", rhs.Node.Tag, rhs.GetNicePath(), lhsNode.Tag, lhs.GetNicePath()) + case SequenceNode: + addSequences(target, lhs, rhs) + case ScalarNode: + if rhs.Kind != ScalarNode { + return nil, fmt.Errorf("%v (%v) cannot be added to a %v (%v)", rhs.Tag, rhs.GetNicePath(), lhsNode.Tag, lhs.GetNicePath()) } - target.Node.Kind = yaml.ScalarNode - target.Node.Style = lhsNode.Style - if err := addScalars(context, target, lhsNode, rhs.Node); err != nil { + target.Kind = ScalarNode + target.Style = lhsNode.Style + if err := addScalars(context, target, lhsNode, rhs); err != nil { return nil, err } } return target, nil } -func addScalars(context Context, target *CandidateNode, lhs *yaml.Node, rhs *yaml.Node) error { +func addScalars(context Context, target *CandidateNode, lhs *CandidateNode, rhs *CandidateNode) error { lhsTag := lhs.Tag - rhsTag := guessTagFromCustomType(rhs) + rhsTag := rhs.guessTagFromCustomType() lhsIsCustom := false if !strings.HasPrefix(lhsTag, "!!") { // custom tag - we have to have a guess - lhsTag = guessTagFromCustomType(lhs) + lhsTag = lhs.guessTagFromCustomType() lhsIsCustom = true } @@ -106,15 +94,16 @@ func addScalars(context Context, target *CandidateNode, lhs *yaml.Node, rhs *yam return addDateTimes(context.GetDateTimeLayout(), target, lhs, rhs) } else if lhsTag == "!!str" { - target.Node.Tag = lhs.Tag + target.Tag = lhs.Tag if rhsTag == "!!null" { - target.Node.Value = lhs.Value + target.Value = lhs.Value } else { - target.Node.Value = lhs.Value + rhs.Value + target.Value = lhs.Value + rhs.Value } + } else if rhsTag == "!!str" { - target.Node.Tag = rhs.Tag - target.Node.Value = lhs.Value + rhs.Value + target.Tag = rhs.Tag + target.Value = lhs.Value + rhs.Value } else if lhsTag == "!!int" && rhsTag == "!!int" { format, lhsNum, err := parseInt64(lhs.Value) if err != nil { @@ -125,8 +114,8 @@ func addScalars(context Context, target *CandidateNode, lhs *yaml.Node, rhs *yam return err } sum := lhsNum + rhsNum - target.Node.Tag = lhs.Tag - target.Node.Value = fmt.Sprintf(format, sum) + target.Tag = lhs.Tag + target.Value = fmt.Sprintf(format, sum) } else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") { lhsNum, err := strconv.ParseFloat(lhs.Value, 64) if err != nil { @@ -138,18 +127,18 @@ func addScalars(context Context, target *CandidateNode, lhs *yaml.Node, rhs *yam } sum := lhsNum + rhsNum if lhsIsCustom { - target.Node.Tag = lhs.Tag + target.Tag = lhs.Tag } else { - target.Node.Tag = "!!float" + target.Tag = "!!float" } - target.Node.Value = fmt.Sprintf("%v", sum) + target.Value = fmt.Sprintf("%v", sum) } else { return fmt.Errorf("%v cannot be added to %v", lhsTag, rhsTag) } return nil } -func addDateTimes(layout string, target *CandidateNode, lhs *yaml.Node, rhs *yaml.Node) error { +func addDateTimes(layout string, target *CandidateNode, lhs *CandidateNode, rhs *CandidateNode) error { duration, err := time.ParseDuration(rhs.Value) if err != nil { @@ -162,52 +151,57 @@ func addDateTimes(layout string, target *CandidateNode, lhs *yaml.Node, rhs *yam } newTime := currentTime.Add(duration) - target.Node.Value = newTime.Format(layout) + target.Value = newTime.Format(layout) return nil } -func addSequences(target *CandidateNode, lhs *CandidateNode, rhs *CandidateNode) error { - target.Node.Kind = yaml.SequenceNode - if len(lhs.Node.Content) > 0 { - target.Node.Style = lhs.Node.Style - } - target.Node.Tag = lhs.Node.Tag - - extraNodes, err := toNodes(rhs, lhs) - if err != nil { - return err +func addSequences(target *CandidateNode, lhs *CandidateNode, rhs *CandidateNode) { + log.Debugf("adding sequences! target: %v; lhs %v; rhs: %v", NodeToString(target), NodeToString(lhs), NodeToString(rhs)) + target.Kind = SequenceNode + if len(lhs.Content) == 0 { + log.Debugf("dont copy lhs style") + target.Style = 0 } + target.Tag = lhs.Tag - target.Node.Content = append(deepCloneContent(lhs.Node.Content), extraNodes...) - return nil + extraNodes := toNodes(rhs, lhs) + target.AddChildren(lhs.Content) + target.AddChildren(extraNodes) } func addMaps(target *CandidateNode, lhsC *CandidateNode, rhsC *CandidateNode) { - lhs := lhsC.Node - rhs := rhsC.Node + lhs := lhsC + rhs := rhsC + + if len(lhs.Content) == 0 { + log.Debugf("dont copy lhs style") + target.Style = 0 + } - target.Node.Content = make([]*yaml.Node, len(lhs.Content)) - copy(target.Node.Content, lhs.Content) + target.Content = make([]*CandidateNode, 0) + target.AddChildren(lhs.Content) for index := 0; index < len(rhs.Content); index = index + 2 { key := rhs.Content[index] value := rhs.Content[index+1] log.Debug("finding %v", key.Value) - indexInLHS := findKeyInMap(target.Node, key) + indexInLHS := findKeyInMap(target, key) log.Debug("indexInLhs %v", indexInLHS) if indexInLHS < 0 { // not in there, append it - target.Node.Content = append(target.Node.Content, key, value) + target.AddKeyValueChild(key, value) } else { // it's there, replace it - target.Node.Content[indexInLHS+1] = value + oldValue := target.Content[indexInLHS+1] + newValueCopy := oldValue.CopyAsReplacement(value) + target.Content[indexInLHS+1] = newValueCopy } } - target.Node.Kind = yaml.MappingNode + target.Kind = MappingNode if len(lhs.Content) > 0 { - target.Node.Style = lhs.Style + target.Style = lhs.Style } - target.Node.Tag = lhs.Tag + target.Tag = lhs.Tag } diff --git a/pkg/yqlib/operator_add_test.go b/pkg/yqlib/operator_add_test.go index 918d0d39494..3478dbdd1c0 100644 --- a/pkg/yqlib/operator_add_test.go +++ b/pkg/yqlib/operator_add_test.go @@ -36,7 +36,7 @@ var addOperatorScenarios = []expressionScenario{ document: `{}`, expression: "(.a + .b) as $x | .", expected: []string{ - "D0, P[], (doc)::{}\n", + "D0, P[], (!!map)::{}\n", }, }, { @@ -44,7 +44,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: 0`, expression: ".a += .b.c", expected: []string{ - "D0, P[], (doc)::a: 0\n", + "D0, P[], (!!map)::a: 0\n", }, }, @@ -63,7 +63,7 @@ var addOperatorScenarios = []expressionScenario{ dontFormatInputForDoc: true, expression: `.a += .b`, expected: []string{ - "D0, P[], (doc)::a: [1, 2, 3, 4]\nb:\n - 3\n - 4\n", + "D0, P[], (!!map)::a: [1, 2, 3, 4]\nb:\n - 3\n - 4\n", }, }, { @@ -98,7 +98,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: ['dog']`, expression: `.a += "cat"`, expected: []string{ - "D0, P[], (doc)::a: ['dog', 'cat']\n", + "D0, P[], (!!map)::a: ['dog', 'cat']\n", }, }, { @@ -106,7 +106,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: [dog]`, expression: `.a = ["cat"] + .a`, expected: []string{ - "D0, P[], (doc)::a: [cat, dog]\n", + "D0, P[], (!!map)::a: [cat, dog]\n", }, }, { @@ -116,7 +116,7 @@ var addOperatorScenarios = []expressionScenario{ document: `{a: ['dog'], b: cat}`, expression: `.a = .a + .b`, expected: []string{ - "D0, P[], (doc)::{a: ['dog', 'cat'], b: cat}\n", + "D0, P[], (!!map)::{a: ['dog', 'cat'], b: cat}\n", }, }, { @@ -125,7 +125,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: []`, expression: `.a += "cat"`, expected: []string{ - "D0, P[], (doc)::a:\n - cat\n", + "D0, P[], (!!map)::a:\n - cat\n", }, }, { @@ -134,7 +134,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: [dog]`, expression: `.a += "cat"`, expected: []string{ - "D0, P[], (doc)::a: [dog, cat]\n", + "D0, P[], (!!map)::a: [dog, cat]\n", }, }, { @@ -171,7 +171,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: {}`, expression: `.a += {"b": "cat"}`, expected: []string{ - "D0, P[], (doc)::a:\n b: cat\n", + "D0, P[], (!!map)::a:\n b: cat\n", }, }, { @@ -180,7 +180,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: {c: dog}`, expression: `.a += {"b": "cat"}`, expected: []string{ - "D0, P[], (doc)::a: {c: dog, b: cat}\n", + "D0, P[], (!!map)::a: {c: dog, b: cat}\n", }, }, { @@ -196,7 +196,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: { a1: {b: [cat]}, a2: {b: [dog]}, a3: {} }`, expression: `.a[].b += ["mouse"]`, expected: []string{ - "D0, P[], (doc)::a: {a1: {b: [cat, mouse]}, a2: {b: [dog, mouse]}, a3: {b: [mouse]}}\n", + "D0, P[], (!!map)::a: {a1: {b: [cat, mouse]}, a2: {b: [dog, mouse]}, a3: {b: [mouse]}}\n", }, }, { @@ -204,7 +204,7 @@ var addOperatorScenarios = []expressionScenario{ document: `{a: cat, b: meow}`, expression: `.a += .b`, expected: []string{ - "D0, P[], (doc)::{a: catmeow, b: meow}\n", + "D0, P[], (!!map)::{a: catmeow, b: meow}\n", }, }, { @@ -245,7 +245,7 @@ var addOperatorScenarios = []expressionScenario{ document: `{a: 3, b: 4.9}`, expression: `.a = .a + .b`, expected: []string{ - "D0, P[], (doc)::{a: 7.9, b: 4.9}\n", + "D0, P[], (!!map)::{a: 7.9, b: 4.9}\n", }, }, { @@ -254,7 +254,7 @@ var addOperatorScenarios = []expressionScenario{ document: `{a: 3, b: 4}`, expression: `.a = .a + .b`, expected: []string{ - "D0, P[], (doc)::{a: 7, b: 4}\n", + "D0, P[], (!!map)::{a: 7, b: 4}\n", }, }, { @@ -262,7 +262,7 @@ var addOperatorScenarios = []expressionScenario{ document: `{a: 3, b: 5}`, expression: `.[] += 1`, expected: []string{ - "D0, P[], (doc)::{a: 4, b: 6}\n", + "D0, P[], (!!map)::{a: 4, b: 6}\n", }, }, { @@ -271,7 +271,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: 2021-01-01T00:00:00Z`, expression: `.a += "3h10m"`, expected: []string{ - "D0, P[], (doc)::a: 2021-01-01T03:10:00Z\n", + "D0, P[], (!!map)::a: 2021-01-01T03:10:00Z\n", }, }, { @@ -280,7 +280,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: 2021-01-01`, expression: `.a += "24h"`, expected: []string{ - "D0, P[], (doc)::a: 2021-01-02T00:00:00Z\n", + "D0, P[], (!!map)::a: 2021-01-02T00:00:00Z\n", }, }, { @@ -289,7 +289,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: Saturday, 15-Dec-01 at 2:59AM GMT`, expression: `with_dtf("Monday, 02-Jan-06 at 3:04PM MST", .a += "3h1m")`, expected: []string{ - "D0, P[], (doc)::a: Saturday, 15-Dec-01 at 6:00AM GMT\n", + "D0, P[], (!!map)::a: Saturday, 15-Dec-01 at 6:00AM GMT\n", }, }, { @@ -299,7 +299,7 @@ var addOperatorScenarios = []expressionScenario{ document: `a: !cat Saturday, 15-Dec-01 at 2:59AM GMT`, expression: `with_dtf("Monday, 02-Jan-06 at 3:04PM MST", .a += "3h1m")`, expected: []string{ - "D0, P[], (doc)::a: !cat Saturday, 15-Dec-01 at 6:00AM GMT\n", + "D0, P[], (!!map)::a: !cat Saturday, 15-Dec-01 at 6:00AM GMT\n", }, }, { @@ -316,7 +316,7 @@ var addOperatorScenarios = []expressionScenario{ document: "a: {thing: {name: Astuff, value: x}, a1: cool}\nb: {thing: {name: Bstuff, legs: 3}, b1: neat}", expression: `.a += .b`, expected: []string{ - "D0, P[], (doc)::a: {thing: {name: Bstuff, legs: 3}, a1: cool, b1: neat}\nb: {thing: {name: Bstuff, legs: 3}, b1: neat}\n", + "D0, P[], (!!map)::a: {thing: {name: Bstuff, legs: 3}, a1: cool, b1: neat}\nb: {thing: {name: Bstuff, legs: 3}, b1: neat}\n", }, }, { @@ -325,7 +325,7 @@ var addOperatorScenarios = []expressionScenario{ document: "a: !horse cat\nb: !goat _meow", expression: `.a += .b`, expected: []string{ - "D0, P[], (doc)::a: !horse cat_meow\nb: !goat _meow\n", + "D0, P[], (!!map)::a: !horse cat_meow\nb: !goat _meow\n", }, }, { @@ -334,7 +334,7 @@ var addOperatorScenarios = []expressionScenario{ document: "a: !horse 1.2\nb: !goat 2.3", expression: `.a += .b`, expected: []string{ - "D0, P[], (doc)::a: !horse 3.5\nb: !goat 2.3\n", + "D0, P[], (!!map)::a: !horse 3.5\nb: !goat 2.3\n", }, }, { @@ -342,7 +342,7 @@ var addOperatorScenarios = []expressionScenario{ document: "a: !horse 2\nb: !goat 2.3", expression: `.a += .b`, expected: []string{ - "D0, P[], (doc)::a: !horse 4.3\nb: !goat 2.3\n", + "D0, P[], (!!map)::a: !horse 4.3\nb: !goat 2.3\n", }, }, { @@ -350,7 +350,7 @@ var addOperatorScenarios = []expressionScenario{ document: "a: 2\nb: !goat 2.3", expression: `.a += .b`, expected: []string{ - "D0, P[], (doc)::a: 4.3\nb: !goat 2.3\n", + "D0, P[], (!!map)::a: 4.3\nb: !goat 2.3\n", }, }, { @@ -359,7 +359,7 @@ var addOperatorScenarios = []expressionScenario{ document: "a: !horse 2\nb: !goat 3", expression: `.a += .b`, expected: []string{ - "D0, P[], (doc)::a: !horse 5\nb: !goat 3\n", + "D0, P[], (!!map)::a: !horse 5\nb: !goat 3\n", }, }, { @@ -369,7 +369,7 @@ var addOperatorScenarios = []expressionScenario{ document: "a: !horse [a]\nb: !goat [b]", expression: `.a += .b`, expected: []string{ - "D0, P[], (doc)::a: !horse [a, b]\nb: !goat [b]\n", + "D0, P[], (!!map)::a: !horse [a, b]\nb: !goat [b]\n", }, }, { @@ -378,7 +378,7 @@ var addOperatorScenarios = []expressionScenario{ document: "a: &horse [1]", expression: `.a += 2`, expected: []string{ - "D0, P[], (doc)::a: &horse [1, 2]\n", + "D0, P[], (!!map)::a: &horse [1, 2]\n", }, }, { diff --git a/pkg/yqlib/operator_alternative.go b/pkg/yqlib/operator_alternative.go index ca8569fcd82..0069d4ff07d 100644 --- a/pkg/yqlib/operator_alternative.go +++ b/pkg/yqlib/operator_alternative.go @@ -9,10 +9,7 @@ func alternativeOperator(d *dataTreeNavigator, context Context, expressionNode * if lhs == nil { return nil, nil } - truthy, err := isTruthy(lhs) - if err != nil { - return nil, err - } + truthy := isTruthyNode(lhs) if truthy { return lhs, nil } @@ -29,15 +26,9 @@ func alternativeFunc(d *dataTreeNavigator, context Context, lhs *CandidateNode, if rhs == nil { return lhs, nil } - lhs.Node = unwrapDoc(lhs.Node) - rhs.Node = unwrapDoc(rhs.Node) - log.Debugf("Alternative LHS: %v", lhs.Node.Tag) - log.Debugf("- RHS: %v", rhs.Node.Tag) - isTrue, err := isTruthy(lhs) - if err != nil { - return nil, err - } else if isTrue { + isTrue := isTruthyNode(lhs) + if isTrue { return lhs, nil } return rhs, nil diff --git a/pkg/yqlib/operator_alternative_test.go b/pkg/yqlib/operator_alternative_test.go index e70b8b25063..24470e6cf8a 100644 --- a/pkg/yqlib/operator_alternative_test.go +++ b/pkg/yqlib/operator_alternative_test.go @@ -19,7 +19,7 @@ var alternativeOperatorScenarios = []expressionScenario{ expression: `(.b // "hello") as $x | .`, document: `a: bridge`, expected: []string{ - "D0, P[], (doc)::a: bridge\n", + "D0, P[], (!!map)::a: bridge\n", }, }, { @@ -91,7 +91,7 @@ var alternativeOperatorScenarios = []expressionScenario{ expression: "(.a // (.a = 0)) += 1", document: `a: 1`, expected: []string{ - "D0, P[], (doc)::a: 2\n", + "D0, P[], (!!map)::a: 2\n", }, }, { diff --git a/pkg/yqlib/operator_anchors_aliases.go b/pkg/yqlib/operator_anchors_aliases.go index caaf364be9e..d9d73754c38 100644 --- a/pkg/yqlib/operator_anchors_aliases.go +++ b/pkg/yqlib/operator_anchors_aliases.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -18,7 +16,7 @@ func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode * return Context{}, err } if rhs.MatchingNodes.Front() != nil { - aliasName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + aliasName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } } @@ -38,13 +36,13 @@ func assignAliasOperator(d *dataTreeNavigator, context Context, expressionNode * return Context{}, err } if rhs.MatchingNodes.Front() != nil { - aliasName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + aliasName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } } if aliasName != "" { - candidate.Node.Kind = yaml.AliasNode - candidate.Node.Value = aliasName + candidate.Kind = AliasNode + candidate.Value = aliasName } } return context, nil @@ -56,8 +54,7 @@ func getAliasOperator(d *dataTreeNavigator, context Context, expressionNode *Exp for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.ScalarNode, Value: candidate.Node.Value, Tag: "!!str"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement(ScalarNode, "!!str", candidate.Value) results.PushBack(result) } return context.ChildContext(results), nil @@ -75,7 +72,7 @@ func assignAnchorOperator(d *dataTreeNavigator, context Context, expressionNode } if rhs.MatchingNodes.Front() != nil { - anchorName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + anchorName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } } @@ -96,11 +93,11 @@ func assignAnchorOperator(d *dataTreeNavigator, context Context, expressionNode } if rhs.MatchingNodes.Front() != nil { - anchorName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + anchorName = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } } - candidate.Node.Anchor = anchorName + candidate.Anchor = anchorName } return context, nil } @@ -111,9 +108,8 @@ func getAnchorOperator(d *dataTreeNavigator, context Context, expressionNode *Ex for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - anchor := candidate.Node.Anchor - node := &yaml.Node{Kind: yaml.ScalarNode, Value: anchor, Tag: "!!str"} - result := candidate.CreateReplacement(node) + anchor := candidate.Anchor + result := candidate.CreateReplacement(ScalarNode, "!!str", anchor) results.PushBack(result) } return context.ChildContext(results), nil @@ -131,7 +127,7 @@ func explodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expr return Context{}, err } for childEl := rhs.MatchingNodes.Front(); childEl != nil; childEl = childEl.Next() { - err = explodeNode(childEl.Value.(*CandidateNode).Node, context) + err = explodeNode(childEl.Value.(*CandidateNode), context) if err != nil { return Context{}, err } @@ -142,7 +138,7 @@ func explodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expr return context, nil } -func reconstructAliasedMap(node *yaml.Node, context Context) error { +func reconstructAliasedMap(node *CandidateNode, context Context) error { var newContent = list.New() // can I short cut here by prechecking if there's an anchor in the map? // no it needs to recurse in overrideEntry. @@ -157,7 +153,7 @@ func reconstructAliasedMap(node *yaml.Node, context Context) error { return err } } else { - if valueNode.Kind == yaml.SequenceNode { + if valueNode.Kind == SequenceNode { log.Debugf("an alias merge list!") for index := len(valueNode.Content) - 1; index >= 0; index = index - 1 { aliasNode := valueNode.Content[index] @@ -175,39 +171,39 @@ func reconstructAliasedMap(node *yaml.Node, context Context) error { } } } - node.Content = make([]*yaml.Node, newContent.Len()) - index := 0 + node.Content = make([]*CandidateNode, 0) for newEl := newContent.Front(); newEl != nil; newEl = newEl.Next() { - node.Content[index] = newEl.Value.(*yaml.Node) - index++ + node.AddChild(newEl.Value.(*CandidateNode)) } return nil } -func explodeNode(node *yaml.Node, context Context) error { +func explodeNode(node *CandidateNode, context Context) error { + log.Debugf("explodeNode - %v", NodeToString(node)) node.Anchor = "" switch node.Kind { - case yaml.SequenceNode, yaml.DocumentNode: + case SequenceNode: for index, contentNode := range node.Content { - log.Debugf("exploding index %v", index) + log.Debugf("explodeNode - index %v", index) errorInContent := explodeNode(contentNode, context) if errorInContent != nil { return errorInContent } } return nil - case yaml.AliasNode: - log.Debugf("its an alias!") + case AliasNode: + log.Debugf("explodeNode - an alias to %v", NodeToString(node.Alias)) if node.Alias != nil { node.Kind = node.Alias.Kind node.Style = node.Alias.Style node.Tag = node.Alias.Tag - node.Content = deepCloneContent(node.Alias.Content) + node.AddChildren(node.Alias.Content) node.Value = node.Alias.Value node.Alias = nil } + log.Debug("now I'm %v", NodeToString(node)) return nil - case yaml.MappingNode: + case MappingNode: // //check the map has an alias in it hasAlias := false for index := 0; index < len(node.Content); index = index + 2 { @@ -241,11 +237,13 @@ func explodeNode(node *yaml.Node, context Context) error { } } -func applyAlias(node *yaml.Node, alias *yaml.Node, aliasIndex int, newContent Context) error { +func applyAlias(node *CandidateNode, alias *CandidateNode, aliasIndex int, newContent Context) error { + log.Debug("alias is nil ?") if alias == nil { return nil } - if alias.Kind != yaml.MappingNode { + log.Debug("alias: %v", NodeToString(alias)) + if alias.Kind != MappingNode { return fmt.Errorf("merge anchor only supports maps, got %v instead", alias.Tag) } for index := 0; index < len(alias.Content); index = index + 2 { @@ -260,7 +258,7 @@ func applyAlias(node *yaml.Node, alias *yaml.Node, aliasIndex int, newContent Co return nil } -func overrideEntry(node *yaml.Node, key *yaml.Node, value *yaml.Node, startIndex int, newContent Context) error { +func overrideEntry(node *CandidateNode, key *CandidateNode, value *CandidateNode, startIndex int, newContent Context) error { err := explodeNode(value, newContent) @@ -270,8 +268,8 @@ func overrideEntry(node *yaml.Node, key *yaml.Node, value *yaml.Node, startIndex for newEl := newContent.MatchingNodes.Front(); newEl != nil; newEl = newEl.Next() { valueEl := newEl.Next() // move forward twice - keyNode := newEl.Value.(*yaml.Node) - log.Debugf("checking new content %v:%v", keyNode.Value, valueEl.Value.(*yaml.Node).Value) + keyNode := newEl.Value.(*CandidateNode) + log.Debugf("checking new content %v:%v", keyNode.Value, valueEl.Value.(*CandidateNode).Value) if keyNode.Value == key.Value && keyNode.Alias == nil && key.Alias == nil { log.Debugf("overridign new content") valueEl.Value = value diff --git a/pkg/yqlib/operator_anchors_aliases_test.go b/pkg/yqlib/operator_anchors_aliases_test.go index 2db367b6f27..f866aca5d49 100644 --- a/pkg/yqlib/operator_anchors_aliases_test.go +++ b/pkg/yqlib/operator_anchors_aliases_test.go @@ -24,7 +24,7 @@ thingTwo: <<: *item_value ` -var expectedUpdatedArrayRef = `D0, P[], (doc)::item_value: &item_value +var expectedUpdatedArrayRef = `D0, P[], (!!map)::item_value: &item_value value: true thingOne: name: item_1 @@ -34,6 +34,25 @@ thingTwo: !!merge <<: *item_value ` +var explodeMergeAnchorsExpected = `D0, P[], (!!map)::foo: + a: foo_a + thing: foo_thing + c: foo_c +bar: + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: bar_b + thing: foo_thing + c: foobarList_c + a: foo_a +foobar: + c: foo_c + a: foo_a + thing: foobar_thing +` + var anchorOperatorScenarios = []expressionScenario{ { skipDoc: true, @@ -76,7 +95,7 @@ var anchorOperatorScenarios = []expressionScenario{ document: `a: cat`, expression: `.a anchor = "foobar"`, expected: []string{ - "D0, P[], (doc)::a: &foobar cat\n", + "D0, P[], (!!map)::a: &foobar cat\n", }, }, { @@ -84,7 +103,7 @@ var anchorOperatorScenarios = []expressionScenario{ document: `a: {b: cat}`, expression: `.a anchor |= .b`, expected: []string{ - "D0, P[], (doc)::a: &cat {b: cat}\n", + "D0, P[], (!!map)::a: &cat {b: cat}\n", }, }, { @@ -92,7 +111,7 @@ var anchorOperatorScenarios = []expressionScenario{ document: `a: {c: cat}`, expression: `.a anchor |= .b`, expected: []string{ - "D0, P[], (doc)::a: {c: cat}\n", + "D0, P[], (!!map)::a: {c: cat}\n", }, }, { @@ -100,7 +119,7 @@ var anchorOperatorScenarios = []expressionScenario{ document: `a: {c: cat}`, expression: `.a anchor = .b`, expected: []string{ - "D0, P[], (doc)::a: {c: cat}\n", + "D0, P[], (!!map)::a: {c: cat}\n", }, }, { @@ -116,7 +135,7 @@ var anchorOperatorScenarios = []expressionScenario{ document: `{b: &meow purr, a: cat}`, expression: `.a alias = "meow"`, expected: []string{ - "D0, P[], (doc)::{b: &meow purr, a: *meow}\n", + "D0, P[], (!!map)::{b: &meow purr, a: *meow}\n", }, }, { @@ -124,7 +143,7 @@ var anchorOperatorScenarios = []expressionScenario{ document: `{b: &meow purr, a: cat}`, expression: `.a alias = ""`, expected: []string{ - "D0, P[], (doc)::{b: &meow purr, a: cat}\n", + "D0, P[], (!!map)::{b: &meow purr, a: cat}\n", }, }, { @@ -132,7 +151,7 @@ var anchorOperatorScenarios = []expressionScenario{ document: `{b: &meow purr, a: cat}`, expression: `.a alias = .c`, expected: []string{ - "D0, P[], (doc)::{b: &meow purr, a: cat}\n", + "D0, P[], (!!map)::{b: &meow purr, a: cat}\n", }, }, { @@ -140,7 +159,7 @@ var anchorOperatorScenarios = []expressionScenario{ document: `{b: &meow purr, a: cat}`, expression: `.a alias |= .c`, expected: []string{ - "D0, P[], (doc)::{b: &meow purr, a: cat}\n", + "D0, P[], (!!map)::{b: &meow purr, a: cat}\n", }, }, { @@ -148,7 +167,34 @@ var anchorOperatorScenarios = []expressionScenario{ document: `{b: &meow purr, a: {f: meow}}`, expression: `.a alias |= .f`, expected: []string{ - "D0, P[], (doc)::{b: &meow purr, a: *meow}\n", + "D0, P[], (!!map)::{b: &meow purr, a: *meow}\n", + }, + }, + { + description: "Dont explode alias and anchor - check alias parent", + skipDoc: true, + document: `{a: &a [1], b: *a}`, + expression: `.b[]`, + expected: []string{ + "D0, P[a 0], (!!int)::1\n", + }, + }, + { + description: "Explode alias and anchor - check alias parent", + skipDoc: true, + document: `{a: &a cat, b: *a}`, + expression: `explode(.) | .b`, + expected: []string{ + "D0, P[b], (!!str)::cat\n", + }, + }, + { + description: "Explode alias and anchor - check original parent", + skipDoc: true, + document: `{a: &a cat, b: *a}`, + expression: `explode(.) | .a`, + expected: []string{ + "D0, P[a], (!!str)::cat\n", }, }, { @@ -156,7 +202,7 @@ var anchorOperatorScenarios = []expressionScenario{ document: `{f : {a: &a cat, b: *a}}`, expression: `explode(.f)`, expected: []string{ - "D0, P[], (doc)::{f: {a: cat, b: cat}}\n", + "D0, P[], (!!map)::{f: {a: cat, b: cat}}\n", }, }, { @@ -164,7 +210,7 @@ var anchorOperatorScenarios = []expressionScenario{ document: `a: mike`, expression: `explode(.a)`, expected: []string{ - "D0, P[], (doc)::a: mike\n", + "D0, P[], (!!map)::a: mike\n", }, }, { @@ -172,31 +218,14 @@ var anchorOperatorScenarios = []expressionScenario{ document: `{f : {a: &a cat, *a: b}}`, expression: `explode(.f)`, expected: []string{ - "D0, P[], (doc)::{f: {a: cat, cat: b}}\n", + "D0, P[], (!!map)::{f: {a: cat, cat: b}}\n", }, }, { description: "Explode with merge anchors", document: mergeDocSample, expression: `explode(.)`, - expected: []string{`D0, P[], (doc)::foo: - a: foo_a - thing: foo_thing - c: foo_c -bar: - b: bar_b - thing: bar_thing - c: bar_c -foobarList: - b: bar_b - thing: foo_thing - c: foobarList_c - a: foo_a -foobar: - c: foo_c - a: foo_a - thing: foobar_thing -`}, + expected: []string{explodeMergeAnchorsExpected}, }, { skipDoc: true, @@ -220,10 +249,10 @@ foobar: }, { skipDoc: true, - document: `{f : {a: &a cat, b: &b {f: *a}, *a: *b}}`, + document: `{f : {a: &a cat, b: &b {foo: *a}, *a: *b}}`, expression: `explode(.f)`, expected: []string{ - "D0, P[], (doc)::{f: {a: cat, b: {f: cat}, cat: {f: cat}}}\n", + "D0, P[], (!!map)::{f: {a: cat, b: {foo: cat}, cat: {foo: cat}}}\n", }, }, { diff --git a/pkg/yqlib/operator_array_to_map_test.go b/pkg/yqlib/operator_array_to_map_test.go index 406fec1c4f9..27259a5fd17 100644 --- a/pkg/yqlib/operator_array_to_map_test.go +++ b/pkg/yqlib/operator_array_to_map_test.go @@ -10,7 +10,7 @@ var arrayToMapScenarios = []expressionScenario{ document: `cool: [null, null, hello]`, expression: `.cool |= array_to_map`, expected: []string{ - "D0, P[], (doc)::cool:\n 2: hello\n", + "D0, P[], (!!map)::cool:\n 2: hello\n", }, }, } diff --git a/pkg/yqlib/operator_assign.go b/pkg/yqlib/operator_assign.go index f21f4522a5f..834b9f9e10b 100644 --- a/pkg/yqlib/operator_assign.go +++ b/pkg/yqlib/operator_assign.go @@ -8,8 +8,7 @@ type assignPreferences struct { func assignUpdateFunc(prefs assignPreferences) crossFunctionCalculation { return func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - rhs.Node = unwrapDoc(rhs.Node) - if !prefs.OnlyWriteNull || lhs.Node.Tag == "!!null" { + if !prefs.OnlyWriteNull || lhs.Tag == "!!null" { lhs.UpdateFrom(rhs, prefs) } return lhs, nil @@ -46,7 +45,11 @@ func assignUpdateOperator(d *dataTreeNavigator, context Context, expressionNode return context, err } - for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() { + //traverse backwards through the context - + // like delete, we need to run against the children first. + // (e.g. consider when running with expression '.. |= [.]' - we need + // to wrap the children first + for el := lhs.MatchingNodes.Back(); el != nil; el = el.Prev() { candidate := el.Value.(*CandidateNode) rhs, err := d.GetMatchingNodes(context.SingleChildContext(candidate), expressionNode.RHS) @@ -60,7 +63,6 @@ func assignUpdateOperator(d *dataTreeNavigator, context Context, expressionNode if first != nil { rhsCandidate := first.Value.(*CandidateNode) - rhsCandidate.Node = unwrapDoc(rhsCandidate.Node) candidate.UpdateFrom(rhsCandidate, prefs) } } @@ -92,7 +94,7 @@ func assignAttributesOperator(d *dataTreeNavigator, context Context, expressionN if expressionNode.Operation.Preferences != nil { prefs = expressionNode.Operation.Preferences.(assignPreferences) } - if !prefs.OnlyWriteNull || candidate.Node.Tag == "!!null" { + if !prefs.OnlyWriteNull || candidate.Tag == "!!null" { candidate.UpdateAttributesFrom(first.Value.(*CandidateNode), prefs) } } diff --git a/pkg/yqlib/operator_assign_test.go b/pkg/yqlib/operator_assign_test.go index 4fdf6da81ea..601223ae822 100644 --- a/pkg/yqlib/operator_assign_test.go +++ b/pkg/yqlib/operator_assign_test.go @@ -22,7 +22,7 @@ var assignOperatorScenarios = []expressionScenario{ document: "{}", expression: `.a |= .b`, expected: []string{ - "D0, P[], (doc)::a: null\n", + "D0, P[], (!!map)::a: null\n", }, }, { @@ -30,7 +30,7 @@ var assignOperatorScenarios = []expressionScenario{ document: mergeAnchorAssign, expression: `.c = .b | .a.x = "ModifiedValue" | explode(.)`, expected: []string{ - "D0, P[], (doc)::a:\n x: ModifiedValue\nb:\n x: ModifiedValue\nc:\n x: ModifiedValue\n", + "D0, P[], (!!map)::a:\n x: ModifiedValue\nb:\n x: ModifiedValue\nc:\n x: ModifiedValue\n", }, }, { @@ -38,7 +38,7 @@ var assignOperatorScenarios = []expressionScenario{ document: "{}", expression: `.a = .b`, expected: []string{ - "D0, P[], (doc)::a: null\n", + "D0, P[], (!!map)::a: null\n", }, }, { @@ -47,7 +47,7 @@ var assignOperatorScenarios = []expressionScenario{ document: "a: cat", expression: `.a = [.a]`, expected: []string{ - "D0, P[], (doc)::a:\n - cat\n", + "D0, P[], (!!map)::a:\n - cat\n", }, }, { @@ -56,7 +56,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `a: "3"`, expression: `.a = 3`, expected: []string{ - "D0, P[], (doc)::a: 3\n", + "D0, P[], (!!map)::a: 3\n", }, }, { @@ -65,7 +65,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `a: "true"`, expression: `.a = true`, expected: []string{ - "D0, P[], (doc)::a: true\n", + "D0, P[], (!!map)::a: true\n", }, }, { @@ -74,7 +74,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `a: !cat "meow"`, expression: `.a = "woof"`, expected: []string{ - "D0, P[], (doc)::a: !cat \"woof\"\n", + "D0, P[], (!!map)::a: !cat \"woof\"\n", }, }, { @@ -82,7 +82,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{a: {b: {g: foof}}}`, expression: `.a |= .b`, expected: []string{ - "D0, P[], (doc)::{a: {g: foof}}\n", + "D0, P[], (!!map)::{a: {g: foof}}\n", }, }, { @@ -90,7 +90,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `[1,2,3]`, expression: `.[] |= . * 2`, expected: []string{ - "D0, P[], (doc)::[2, 4, 6]\n", + "D0, P[], (!!seq)::[2, 4, 6]\n", }, }, { @@ -100,7 +100,7 @@ var assignOperatorScenarios = []expressionScenario{ document2: "{b: bob}", expression: `select(fileIndex==0).a = select(fileIndex==1) | select(fileIndex==0)`, expected: []string{ - "D0, P[], (doc)::{a: {b: bob}}\n", + "D0, P[], (!!map)::{a: {b: bob}}\n", }, }, { @@ -108,7 +108,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{a: {b: child}, b: sibling}`, expression: `.a = .b`, expected: []string{ - "D0, P[], (doc)::{a: sibling, b: sibling}\n", + "D0, P[], (!!map)::{a: sibling, b: sibling}\n", }, }, { @@ -116,7 +116,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{a: fieldA, b: fieldB, c: fieldC}`, expression: `(.a, .c) = "potato"`, expected: []string{ - "D0, P[], (doc)::{a: potato, b: fieldB, c: potato}\n", + "D0, P[], (!!map)::{a: potato, b: fieldB, c: potato}\n", }, }, { @@ -124,7 +124,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{a: {b: apple}}`, expression: `.a.b = "frog"`, expected: []string{ - "D0, P[], (doc)::{a: {b: frog}}\n", + "D0, P[], (!!map)::{a: {b: frog}}\n", }, }, { @@ -133,7 +133,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{a: {b: apple}}`, expression: `.a.b |= "frog"`, expected: []string{ - "D0, P[], (doc)::{a: {b: frog}}\n", + "D0, P[], (!!map)::{a: {b: frog}}\n", }, }, { @@ -149,7 +149,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{a: {b: apple}}`, expression: `.a.b |= 5`, expected: []string{ - "D0, P[], (doc)::{a: {b: 5}}\n", + "D0, P[], (!!map)::{a: {b: 5}}\n", }, }, { @@ -157,7 +157,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{a: {b: apple}}`, expression: `.a.b |= 3.142`, expected: []string{ - "D0, P[], (doc)::{a: {b: 3.142}}\n", + "D0, P[], (!!map)::{a: {b: 3.142}}\n", }, }, { @@ -166,7 +166,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{a: {b: apple, c: cactus}}`, expression: `(.a[] | select(. == "apple")) = "frog"`, expected: []string{ - "D0, P[], (doc)::{a: {b: frog, c: cactus}}\n", + "D0, P[], (!!map)::{a: {b: frog, c: cactus}}\n", }, }, { @@ -174,7 +174,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{a: {b: apple, c: cactus}}`, expression: `(.a.[] | select(. == "apple")) = "frog"`, expected: []string{ - "D0, P[], (doc)::{a: {b: frog, c: cactus}}\n", + "D0, P[], (!!map)::{a: {b: frog, c: cactus}}\n", }, }, { @@ -182,7 +182,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `[candy, apple, sandy]`, expression: `(.[] | select(. == "*andy")) = "bogs"`, expected: []string{ - "D0, P[], (doc)::[bogs, apple, bogs]\n", + "D0, P[], (!!seq)::[bogs, apple, bogs]\n", }, }, { @@ -191,7 +191,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{}`, expression: `.a.b |= "bogs"`, expected: []string{ - "D0, P[], (doc)::a:\n b: bogs\n", + "D0, P[], (!!map)::a:\n b: bogs\n", }, }, { @@ -201,7 +201,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `a: &cool cat`, expression: `.a = "dog"`, expected: []string{ - "D0, P[], (doc)::a: &cool dog\n", + "D0, P[], (!!map)::a: &cool dog\n", }, }, { @@ -210,7 +210,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{}`, expression: `.a.b.[0] |= "bogs"`, expected: []string{ - "D0, P[], (doc)::a:\n b:\n - bogs\n", + "D0, P[], (!!map)::a:\n b:\n - bogs\n", }, }, { @@ -218,7 +218,7 @@ var assignOperatorScenarios = []expressionScenario{ document: `{}`, expression: `.a.b.[1].c |= "bogs"`, expected: []string{ - "D0, P[], (doc)::a:\n b:\n - null\n - c: bogs\n", + "D0, P[], (!!map)::a:\n b:\n - null\n - c: bogs\n", }, }, { @@ -226,7 +226,7 @@ var assignOperatorScenarios = []expressionScenario{ document: "a: !cat meow\nb: !dog woof", expression: `.a = .b`, expected: []string{ - "D0, P[], (doc)::a: !cat woof\nb: !dog woof\n", + "D0, P[], (!!map)::a: !cat woof\nb: !dog woof\n", }, }, { @@ -235,7 +235,7 @@ var assignOperatorScenarios = []expressionScenario{ document: "a: !cat meow\nb: !dog woof", expression: `.a =c .b`, expected: []string{ - "D0, P[], (doc)::a: !dog woof\nb: !dog woof\n", + "D0, P[], (!!map)::a: !dog woof\nb: !dog woof\n", }, }, } diff --git a/pkg/yqlib/operator_booleans.go b/pkg/yqlib/operator_booleans.go index d919b9a6b3c..07288c421ed 100644 --- a/pkg/yqlib/operator_booleans.go +++ b/pkg/yqlib/operator_booleans.go @@ -3,36 +3,25 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" + "strings" ) -func isTruthyNode(node *yaml.Node) (bool, error) { - value := true +func isTruthyNode(node *CandidateNode) bool { + if node == nil { + return false + } if node.Tag == "!!null" { - return false, nil + return false } - if node.Kind == yaml.ScalarNode && node.Tag == "!!bool" { - errDecoding := node.Decode(&value) - if errDecoding != nil { - return false, errDecoding - } + if node.Kind == ScalarNode && node.Tag == "!!bool" { + // yes/y/true/on + return (strings.EqualFold(node.Value, "y") || + strings.EqualFold(node.Value, "yes") || + strings.EqualFold(node.Value, "on") || + strings.EqualFold(node.Value, "true")) } - return value, nil -} - -func isTruthy(c *CandidateNode) (bool, error) { - node := unwrapDoc(c.Node) - return isTruthyNode(node) -} - -func getBoolean(candidate *CandidateNode) (bool, error) { - if candidate != nil { - candidate.Node = unwrapDoc(candidate.Node) - return isTruthy(candidate) - } - return false, nil + return true } func getOwner(lhs *CandidateNode, rhs *CandidateNode) *CandidateNode { @@ -48,10 +37,7 @@ func getOwner(lhs *CandidateNode, rhs *CandidateNode) *CandidateNode { func returnRhsTruthy(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { owner := getOwner(lhs, rhs) - rhsBool, err := getBoolean(rhs) - if err != nil { - return nil, err - } + rhsBool := isTruthyNode(rhs) return createBooleanCandidate(owner, rhsBool), nil } @@ -61,7 +47,7 @@ func returnLHSWhen(targetBool bool) func(lhs *CandidateNode) (*CandidateNode, er var err error var lhsBool bool - if lhsBool, err = getBoolean(lhs); err != nil || lhsBool != targetBool { + if lhsBool = isTruthyNode(lhs); lhsBool != targetBool { return nil, err } owner := &CandidateNode{} @@ -72,29 +58,24 @@ func returnLHSWhen(targetBool bool) func(lhs *CandidateNode) (*CandidateNode, er } } -func findBoolean(wantBool bool, d *dataTreeNavigator, context Context, expressionNode *ExpressionNode, sequenceNode *yaml.Node) (bool, error) { +func findBoolean(wantBool bool, d *dataTreeNavigator, context Context, expressionNode *ExpressionNode, sequenceNode *CandidateNode) (bool, error) { for _, node := range sequenceNode.Content { if expressionNode != nil { //need to evaluate the expression against the node - candidate := &CandidateNode{Node: node} - rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode) + rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(node), expressionNode) if err != nil { return false, err } if rhs.MatchingNodes.Len() > 0 { - node = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node + node = rhs.MatchingNodes.Front().Value.(*CandidateNode) } else { // no results found, ignore this entry continue } } - truthy, err := isTruthyNode(node) - if err != nil { - return false, err - } - if truthy == wantBool { + if isTruthyNode(node) == wantBool { return true, nil } } @@ -106,11 +87,10 @@ func allOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidateNode := unwrapDoc(candidate.Node) - if candidateNode.Kind != yaml.SequenceNode { - return Context{}, fmt.Errorf("any only supports arrays, was %v", candidateNode.Tag) + if candidate.Kind != SequenceNode { + return Context{}, fmt.Errorf("any only supports arrays, was %v", candidate.Tag) } - booleanResult, err := findBoolean(false, d, context, expressionNode.RHS, candidateNode) + booleanResult, err := findBoolean(false, d, context, expressionNode.RHS, candidate) if err != nil { return Context{}, err } @@ -125,11 +105,10 @@ func anyOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidateNode := unwrapDoc(candidate.Node) - if candidateNode.Kind != yaml.SequenceNode { - return Context{}, fmt.Errorf("any only supports arrays, was %v", candidateNode.Tag) + if candidate.Kind != SequenceNode { + return Context{}, fmt.Errorf("any only supports arrays, was %v", candidate.Tag) } - booleanResult, err := findBoolean(true, d, context, expressionNode.RHS, candidateNode) + booleanResult, err := findBoolean(true, d, context, expressionNode.RHS, candidate) if err != nil { return Context{}, err } @@ -164,10 +143,7 @@ func notOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) log.Debug("notOperation checking %v", candidate) - truthy, errDecoding := isTruthy(candidate) - if errDecoding != nil { - return Context{}, errDecoding - } + truthy := isTruthyNode(candidate) result := createBooleanCandidate(candidate, !truthy) results.PushBack(result) } diff --git a/pkg/yqlib/operator_booleans_test.go b/pkg/yqlib/operator_booleans_test.go index c48c53076ea..c999c635289 100644 --- a/pkg/yqlib/operator_booleans_test.go +++ b/pkg/yqlib/operator_booleans_test.go @@ -43,7 +43,7 @@ var booleanOperatorScenarios = []expressionScenario{ document: "b: hi", expression: `select(.a or .b)`, expected: []string{ - "D0, P[], (doc)::b: hi\n", + "D0, P[], (!!map)::b: hi\n", }, }, { @@ -51,7 +51,7 @@ var booleanOperatorScenarios = []expressionScenario{ document: "b: hi", expression: `select((.a and .b) | not)`, expected: []string{ - "D0, P[], (doc)::b: hi\n", + "D0, P[], (!!map)::b: hi\n", }, }, { @@ -106,7 +106,7 @@ var booleanOperatorScenarios = []expressionScenario{ document: "a: [rad, awesome]\nb: [meh, whatever]", expression: `.[] |= any_c(. == "awesome")`, expected: []string{ - "D0, P[], (doc)::a: true\nb: false\n", + "D0, P[], (!!map)::a: true\nb: false\n", }, }, { @@ -114,7 +114,7 @@ var booleanOperatorScenarios = []expressionScenario{ document: `[{pet: cat}]`, expression: `any_c(.name == "harry") as $c | .`, expected: []string{ - "D0, P[], (doc)::[{pet: cat}]\n", + "D0, P[], (!!seq)::[{pet: cat}]\n", }, }, { @@ -170,7 +170,7 @@ var booleanOperatorScenarios = []expressionScenario{ document: "a: [rad, awesome]\nb: [meh, 12]", expression: `.[] |= all_c(tag == "!!str")`, expected: []string{ - "D0, P[], (doc)::a: true\nb: false\n", + "D0, P[], (!!map)::a: true\nb: false\n", }, }, { @@ -205,7 +205,7 @@ var booleanOperatorScenarios = []expressionScenario{ document: `{}`, expression: `(.a.b or .c) as $x | .`, expected: []string{ - "D0, P[], (doc)::{}\n", + "D0, P[], (!!map)::{}\n", }, }, { @@ -213,7 +213,7 @@ var booleanOperatorScenarios = []expressionScenario{ document: `{}`, expression: `(.a.b and .c) as $x | .`, expected: []string{ - "D0, P[], (doc)::{}\n", + "D0, P[], (!!map)::{}\n", }, }, { diff --git a/pkg/yqlib/operator_collect.go b/pkg/yqlib/operator_collect.go index 2a114592ea1..5828429976e 100644 --- a/pkg/yqlib/operator_collect.go +++ b/pkg/yqlib/operator_collect.go @@ -2,12 +2,10 @@ package yqlib import ( "container/list" - - yaml "gopkg.in/yaml.v3" ) func collectTogether(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (*CandidateNode, error) { - collectedNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} + collectedNode := &CandidateNode{Kind: SequenceNode, Tag: "!!seq"} for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) collectExpResults, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode) @@ -17,10 +15,10 @@ func collectTogether(d *dataTreeNavigator, context Context, expressionNode *Expr for result := collectExpResults.MatchingNodes.Front(); result != nil; result = result.Next() { resultC := result.Value.(*CandidateNode) log.Debugf("found this: %v", NodeToString(resultC)) - collectedNode.Content = append(collectedNode.Content, unwrapDoc(resultC.Node)) + collectedNode.AddChild(resultC) } } - return &CandidateNode{Node: collectedNode}, nil + return collectedNode, nil } func collectOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -28,9 +26,8 @@ func collectOperator(d *dataTreeNavigator, context Context, expressionNode *Expr if context.MatchingNodes.Len() == 0 { log.Debugf("nothing to collect") - node := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq", Value: "[]"} - candidate := &CandidateNode{Node: node} - return context.SingleChildContext(candidate), nil + node := &CandidateNode{Kind: SequenceNode, Tag: "!!seq", Value: "[]"} + return context.SingleChildContext(node), nil } var evaluateAllTogether = true @@ -55,8 +52,7 @@ func collectOperator(d *dataTreeNavigator, context Context, expressionNode *Expr for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - collectedNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} - collectCandidate := candidate.CreateReplacement(collectedNode) + collectCandidate := candidate.CreateReplacement(SequenceNode, "!!seq", "") log.Debugf("collect rhs: %v", expressionNode.RHS.Operation.toString()) @@ -68,7 +64,7 @@ func collectOperator(d *dataTreeNavigator, context Context, expressionNode *Expr for result := collectExpResults.MatchingNodes.Front(); result != nil; result = result.Next() { resultC := result.Value.(*CandidateNode) log.Debugf("found this: %v", NodeToString(resultC)) - collectedNode.Content = append(collectedNode.Content, unwrapDoc(resultC.Node)) + collectCandidate.AddChild(resultC) } log.Debugf("done collect rhs: %v", expressionNode.RHS.Operation.toString()) diff --git a/pkg/yqlib/operator_collect_object.go b/pkg/yqlib/operator_collect_object.go index 59417a623ae..4f2283ac960 100644 --- a/pkg/yqlib/operator_collect_object.go +++ b/pkg/yqlib/operator_collect_object.go @@ -2,8 +2,6 @@ package yqlib import ( "container/list" - - yaml "gopkg.in/yaml.v3" ) /* @@ -23,31 +21,47 @@ func collectObjectOperator(d *dataTreeNavigator, originalContext Context, expres context := originalContext.WritableClone() if context.MatchingNodes.Len() == 0 { - node := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map", Value: "{}"} - candidate := &CandidateNode{Node: node} + candidate := &CandidateNode{Kind: MappingNode, Tag: "!!map", Value: "{}"} + log.Debugf("-- collectObjectOperation - starting with empty map") return context.SingleChildContext(candidate), nil } first := context.MatchingNodes.Front().Value.(*CandidateNode) - var rotated = make([]*list.List, len(first.Node.Content)) + var rotated = make([]*list.List, len(first.Content)) - for i := 0; i < len(first.Node.Content); i++ { + for i := 0; i < len(first.Content); i++ { rotated[i] = list.New() } for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidateNode := el.Value.(*CandidateNode) - for i := 0; i < len(first.Node.Content); i++ { - rotated[i].PushBack(candidateNode.CreateChildInArray(i, candidateNode.Node.Content[i])) + + for i := 0; i < len(first.Content); i++ { + log.Debugf("rotate[%v] = %v", i, NodeToString(candidateNode.Content[i])) + log.Debugf("children:\n%v", NodeContentToString(candidateNode.Content[i], 0)) + rotated[i].PushBack(candidateNode.Content[i]) } } + log.Debugf("-- collectObjectOperation, length of rotated is %v", len(rotated)) newObject := list.New() - for i := 0; i < len(first.Node.Content); i++ { + for i := 0; i < len(first.Content); i++ { additions, err := collect(d, context.ChildContext(list.New()), rotated[i]) if err != nil { return Context{}, err } - newObject.PushBackList(additions.MatchingNodes) + // we should reset the parents and keys of these top level nodes, + // as they are new + for el := additions.MatchingNodes.Front(); el != nil; el = el.Next() { + addition := el.Value.(*CandidateNode) + additionCopy := addition.Copy() + + additionCopy.SetParent(nil) + additionCopy.Key = nil + + log.Debugf("-- collectObjectOperation, adding result %v", NodeToString(additionCopy)) + + newObject.PushBack(additionCopy) + } } return context.ChildContext(newObject), nil @@ -60,19 +74,17 @@ func collect(d *dataTreeNavigator, context Context, remainingMatches *list.List) } candidate := remainingMatches.Remove(remainingMatches.Front()).(*CandidateNode) + log.Debugf("-- collectObjectOperation - collect %v", NodeToString(candidate)) splatted, err := splat(context.SingleChildContext(candidate), traversePreferences{DontFollowAlias: true, IncludeMapKeys: false}) - for splatEl := splatted.MatchingNodes.Front(); splatEl != nil; splatEl = splatEl.Next() { - splatEl.Value.(*CandidateNode).Path = nil - } - if err != nil { return Context{}, err } if context.MatchingNodes.Len() == 0 { + log.Debugf("-- collectObjectOperation - collect context is empty, next") return collect(d, splatted, remainingMatches) } @@ -82,14 +94,12 @@ func collect(d *dataTreeNavigator, context Context, remainingMatches *list.List) aggCandidate := el.Value.(*CandidateNode) for splatEl := splatted.MatchingNodes.Front(); splatEl != nil; splatEl = splatEl.Next() { splatCandidate := splatEl.Value.(*CandidateNode) - newCandidate, err := aggCandidate.Copy() - if err != nil { - return Context{}, err - } - - newCandidate.Path = nil + log.Debugf("-- collectObjectOperation; splatCandidate: %v", NodeToString(splatCandidate)) + newCandidate := aggCandidate.Copy() + log.Debugf("-- collectObjectOperation; aggCandidate: %v", NodeToString(aggCandidate)) newCandidate, err = multiply(multiplyPreferences{AppendArrays: false})(d, context, newCandidate, splatCandidate) + if err != nil { return Context{}, err } diff --git a/pkg/yqlib/operator_collect_object_test.go b/pkg/yqlib/operator_collect_object_test.go index 35fa555b75d..ff82325bf19 100644 --- a/pkg/yqlib/operator_collect_object_test.go +++ b/pkg/yqlib/operator_collect_object_test.go @@ -5,6 +5,20 @@ import ( ) var collectObjectOperatorScenarios = []expressionScenario{ + { + skipDoc: true, + expression: `{"name": "mike"} | .name`, + expected: []string{ + "D0, P[name], (!!str)::mike\n", + }, + }, + { + skipDoc: true, + expression: `{"person": {"names": ["mike"]}} | .person.names[0]`, + expected: []string{ + "D0, P[person names 0], (!!str)::mike\n", + }, + }, { skipDoc: true, document: `[{name: cat}, {name: dog}]`, @@ -26,7 +40,7 @@ var collectObjectOperatorScenarios = []expressionScenario{ document: "a: []", expression: `.a += [{"key": "att2", "value": "val2"}]`, expected: []string{ - "D0, P[], (doc)::a:\n - key: att2\n value: val2\n", + "D0, P[], (!!map)::a:\n - key: att2\n value: val2\n", }, }, { @@ -62,22 +76,24 @@ var collectObjectOperatorScenarios = []expressionScenario{ }, }, { - skipDoc: true, - document: "{name: Mike}\n", - document2: "{name: Bob}\n", - expression: `{"wrap": .}`, + skipDoc: true, + description: "Two documents", + document: "{name: Mike}\n", + document2: "{name: Bob}\n", + expression: `{"wrap": .}`, expected: []string{ "D0, P[], (!!map)::wrap: {name: Mike}\n", "D0, P[], (!!map)::wrap: {name: Bob}\n", }, }, { - skipDoc: true, - document: "{name: Mike}\n---\n{name: Bob}", - expression: `{"wrap": .}`, + skipDoc: true, + description: "two embedded documents", + document: "{name: Mike}\n---\n{name: Bob}", + expression: `{"wrap": .}`, expected: []string{ "D0, P[], (!!map)::wrap: {name: Mike}\n", - "D0, P[], (!!map)::wrap: {name: Bob}\n", + "D1, P[], (!!map)::wrap: {name: Bob}\n", }, }, { @@ -105,8 +121,8 @@ var collectObjectOperatorScenarios = []expressionScenario{ expected: []string{ "D0, P[], (!!map)::Mike: cat\n", "D0, P[], (!!map)::Mike: dog\n", - "D0, P[], (!!map)::Rosey: monkey\n", - "D0, P[], (!!map)::Rosey: sheep\n", + "D1, P[], (!!map)::Rosey: monkey\n", + "D1, P[], (!!map)::Rosey: sheep\n", }, }, { diff --git a/pkg/yqlib/operator_collect_test.go b/pkg/yqlib/operator_collect_test.go index b75f95fa43d..b58c0dea8cd 100644 --- a/pkg/yqlib/operator_collect_test.go +++ b/pkg/yqlib/operator_collect_test.go @@ -5,6 +5,13 @@ import ( ) var collectOperatorScenarios = []expressionScenario{ + { + skipDoc: true, + expression: `["x", "y"] | .[1]`, + expected: []string{ + "D0, P[1], (!!str)::y\n", + }, + }, { skipDoc: true, document: ``, diff --git a/pkg/yqlib/operator_column.go b/pkg/yqlib/operator_column.go index ac7d339c0db..e4e92ba2fda 100644 --- a/pkg/yqlib/operator_column.go +++ b/pkg/yqlib/operator_column.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func columnOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -14,8 +12,7 @@ func columnOperator(d *dataTreeNavigator, context Context, expressionNode *Expre for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", candidate.Node.Column), Tag: "!!int"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement(ScalarNode, "!!int", fmt.Sprintf("%v", candidate.Column)) results.PushBack(result) } diff --git a/pkg/yqlib/operator_comments.go b/pkg/yqlib/operator_comments.go index ecf882af20f..60da4203dae 100644 --- a/pkg/yqlib/operator_comments.go +++ b/pkg/yqlib/operator_comments.go @@ -5,8 +5,6 @@ import ( "bytes" "container/list" "regexp" - - yaml "gopkg.in/yaml.v3" ) type commentOpPreferences struct { @@ -35,13 +33,17 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod } if rhs.MatchingNodes.Front() != nil { - comment = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + comment = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } } + 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 { @@ -49,26 +51,21 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod } if rhs.MatchingNodes.Front() != nil { - comment = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + comment = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } } log.Debugf("Setting comment of : %v", candidate.GetKey()) if preferences.LineComment { - candidate.Node.LineComment = comment + log.Debugf("Setting line comment of : %v to %v", candidate.GetKey(), comment) + candidate.LineComment = comment } if preferences.HeadComment { - candidate.Node.HeadComment = comment + candidate.HeadComment = comment candidate.LeadingContent = "" // clobber the leading content, if there was any. } - if preferences.FootComment && candidate.Node.Kind == yaml.DocumentNode && comment != "" { - candidate.TrailingContent = "# " + comment - } else if preferences.FootComment && candidate.Node.Kind == yaml.DocumentNode { - candidate.TrailingContent = comment - - } else if preferences.FootComment && candidate.Node.Kind != yaml.DocumentNode { - candidate.Node.FootComment = comment - candidate.TrailingContent = "" + if preferences.FootComment { + candidate.FootComment = comment } } @@ -91,7 +88,8 @@ func getCommentsOperator(d *dataTreeNavigator, context Context, expressionNode * candidate := el.Value.(*CandidateNode) comment := "" if preferences.LineComment { - comment = candidate.Node.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$`) var output bytes.Buffer @@ -106,18 +104,18 @@ func getCommentsOperator(d *dataTreeNavigator, context Context, expressionNode * comment = output.String() comment = chompRegexp.ReplaceAllString(comment, "") } else if preferences.HeadComment { - comment = candidate.Node.HeadComment - } else if preferences.FootComment && candidate.Node.Kind == yaml.DocumentNode && candidate.TrailingContent != "" { - comment = candidate.TrailingContent + comment = candidate.HeadComment } else if preferences.FootComment { - comment = candidate.Node.FootComment + comment = candidate.FootComment } comment = startCommentCharacterRegExp.ReplaceAllString(comment, "") comment = subsequentCommentCharacterRegExp.ReplaceAllString(comment, "\n") - node := &yaml.Node{Kind: yaml.ScalarNode, Value: comment, Tag: "!!str"} - result := candidate.CreateReplacement(node) - result.LeadingContent = "" // don't include the leading yaml content when retrieving a comment + result := candidate.CreateReplacement(ScalarNode, "!!str", comment) + if candidate.IsMapKey { + result.IsMapKey = false + result.Key = candidate + } results.PushBack(result) } return context.ChildContext(results), nil diff --git a/pkg/yqlib/operator_comments_test.go b/pkg/yqlib/operator_comments_test.go index ed7fef4835d..5bb357709c8 100644 --- a/pkg/yqlib/operator_comments_test.go +++ b/pkg/yqlib/operator_comments_test.go @@ -60,7 +60,7 @@ var commentOperatorScenarios = []expressionScenario{ document: `a: cat`, expression: `.a line_comment="single"`, expected: []string{ - "D0, P[], (doc)::a: cat # single\n", + "D0, P[], (!!map)::a: cat # single\n", }, }, { @@ -69,7 +69,7 @@ var commentOperatorScenarios = []expressionScenario{ document: "a:\n b: things", expression: `(.a | key) line_comment="single"`, expected: []string{ - "D0, P[], (doc)::a: # single\n b: things\n", + "D0, P[], (!!map)::a: # single\n b: things\n", }, }, { @@ -77,7 +77,7 @@ var commentOperatorScenarios = []expressionScenario{ document: "a: cat\nb: dog", expression: `.a line_comment=.b`, expected: []string{ - "D0, P[], (doc)::a: cat # dog\nb: dog\n", + "D0, P[], (!!map)::a: cat # dog\nb: dog\n", }, }, { @@ -85,8 +85,8 @@ var commentOperatorScenarios = []expressionScenario{ 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", + "D0, P[], (!!map)::a: cat # 0\n", + "D1, P[], (!!map)::a: dog # 1\n", }, }, { @@ -146,7 +146,7 @@ var commentOperatorScenarios = []expressionScenario{ document: `a: cat`, expression: `. head_comment="single"`, expected: []string{ - "D0, P[], (doc)::# single\n\na: cat\n", + "D0, P[], (!!map)::# single\na: cat\n", }, }, { @@ -154,7 +154,7 @@ var commentOperatorScenarios = []expressionScenario{ 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", + "D0, P[], (!!map)::f: foo\n# single\na:\n b: cat\n", }, }, { @@ -162,7 +162,7 @@ var commentOperatorScenarios = []expressionScenario{ document: `a: cat`, expression: `. foot_comment=.a`, expected: []string{ - "D0, P[], (doc)::a: cat\n# cat\n", + "D0, P[], (!!map)::a: cat\n# cat\n", }, }, { @@ -171,7 +171,7 @@ var commentOperatorScenarios = []expressionScenario{ document: "a: cat\n\n# hi", expression: `. foot_comment=""`, expected: []string{ - "D0, P[], (doc)::a: cat\n", + "D0, P[], (!!map)::a: cat\n", }, }, { @@ -179,7 +179,7 @@ var commentOperatorScenarios = []expressionScenario{ document: `a: cat`, expression: `. foot_comment=.b.d`, expected: []string{ - "D0, P[], (doc)::a: cat\n", + "D0, P[], (!!map)::a: cat\n", }, }, { @@ -187,7 +187,7 @@ var commentOperatorScenarios = []expressionScenario{ document: `a: cat`, expression: `. foot_comment|=.b.d`, expected: []string{ - "D0, P[], (doc)::a: cat\n", + "D0, P[], (!!map)::a: cat\n", }, }, { @@ -195,7 +195,7 @@ var commentOperatorScenarios = []expressionScenario{ document: "a: cat # comment\nb: dog # leave this", expression: `.a line_comment=""`, expected: []string{ - "D0, P[], (doc)::a: cat\nb: dog # leave this\n", + "D0, P[], (!!map)::a: cat\nb: dog # leave this\n", }, }, { @@ -260,6 +260,42 @@ var commentOperatorScenarios = []expressionScenario{ "D0, P[], (!!str)::have a great day\nno really\n", }, }, + { + description: "leading spaces", + skipDoc: true, + document: " # hi", + expression: `.`, + expected: []string{ + "D0, P[], (!!null):: # hi\n", + }, + }, + { + description: "string spaces", + skipDoc: true, + document: "# hi\ncat\n", + expression: `.`, + expected: []string{ + "D0, P[], (!!str)::# hi\ncat\n", + }, + }, + { + description: "leading spaces with new line", + skipDoc: true, + document: " # hi\n", + expression: `.`, + expected: []string{ + "D0, P[], (!!null):: # hi\n", + }, + }, + { + description: "directive", + skipDoc: true, + document: "%YAML 1.1\n# hi\n", + expression: `.`, + expected: []string{ + "D0, P[], (!!null)::%YAML 1.1\n# hi\n", + }, + }, } func TestCommentOperatorScenarios(t *testing.T) { diff --git a/pkg/yqlib/operator_compare.go b/pkg/yqlib/operator_compare.go index a33cfecfbfe..5777902b90f 100644 --- a/pkg/yqlib/operator_compare.go +++ b/pkg/yqlib/operator_compare.go @@ -3,8 +3,6 @@ package yqlib import ( "fmt" "strconv" - - yaml "gopkg.in/yaml.v3" ) type compareTypePref struct { @@ -32,27 +30,24 @@ func compare(prefs compareTypePref) func(d *dataTreeNavigator, context Context, return createBooleanCandidate(lhs, false), nil } - lhs.Node = unwrapDoc(lhs.Node) - rhs.Node = unwrapDoc(rhs.Node) - - switch lhs.Node.Kind { - case yaml.MappingNode: + switch lhs.Kind { + case MappingNode: return nil, fmt.Errorf("maps not yet supported for comparison") - case yaml.SequenceNode: + case SequenceNode: return nil, fmt.Errorf("arrays not yet supported for comparison") default: - if rhs.Node.Kind != yaml.ScalarNode { - return nil, fmt.Errorf("%v (%v) cannot be subtracted from %v", rhs.Node.Tag, rhs.Path, lhs.Node.Tag) + if rhs.Kind != ScalarNode { + return nil, fmt.Errorf("%v (%v) cannot be subtracted from %v", rhs.Tag, rhs.GetNicePath(), lhs.Tag) } - target := lhs.CreateReplacement(&yaml.Node{}) - boolV, err := compareScalars(context, prefs, lhs.Node, rhs.Node) + target := lhs.CopyWithoutContent() + boolV, err := compareScalars(context, prefs, lhs, rhs) return createBooleanCandidate(target, boolV), err } } } -func compareDateTime(layout string, prefs compareTypePref, lhs *yaml.Node, rhs *yaml.Node) (bool, error) { +func compareDateTime(layout string, prefs compareTypePref, lhs *CandidateNode, rhs *CandidateNode) (bool, error) { lhsTime, err := parseDateTime(layout, lhs.Value) if err != nil { return false, err @@ -73,9 +68,9 @@ func compareDateTime(layout string, prefs compareTypePref, lhs *yaml.Node, rhs * } -func compareScalars(context Context, prefs compareTypePref, lhs *yaml.Node, rhs *yaml.Node) (bool, error) { - lhsTag := guessTagFromCustomType(lhs) - rhsTag := guessTagFromCustomType(rhs) +func compareScalars(context Context, prefs compareTypePref, lhs *CandidateNode, rhs *CandidateNode) (bool, error) { + lhsTag := lhs.guessTagFromCustomType() + rhsTag := rhs.guessTagFromCustomType() isDateTime := lhs.Tag == "!!timestamp" // if the lhs is a string, it might be a timestamp in a custom format. diff --git a/pkg/yqlib/operator_contains.go b/pkg/yqlib/operator_contains.go index d07a645ed30..aa913d97292 100644 --- a/pkg/yqlib/operator_contains.go +++ b/pkg/yqlib/operator_contains.go @@ -3,15 +3,13 @@ package yqlib import ( "fmt" "strings" - - yaml "gopkg.in/yaml.v3" ) func containsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { return crossFunction(d, context.ReadOnlyClone(), expressionNode, containsWithNodes, false) } -func containsArrayElement(array *yaml.Node, item *yaml.Node) (bool, error) { +func containsArrayElement(array *CandidateNode, item *CandidateNode) (bool, error) { for index := 0; index < len(array.Content); index = index + 1 { containedInArray, err := contains(array.Content[index], item) if err != nil { @@ -24,8 +22,8 @@ func containsArrayElement(array *yaml.Node, item *yaml.Node) (bool, error) { return false, nil } -func containsArray(lhs *yaml.Node, rhs *yaml.Node) (bool, error) { - if rhs.Kind != yaml.SequenceNode { +func containsArray(lhs *CandidateNode, rhs *CandidateNode) (bool, error) { + if rhs.Kind != SequenceNode { return containsArrayElement(lhs, rhs) } for index := 0; index < len(rhs.Content); index = index + 1 { @@ -40,8 +38,8 @@ func containsArray(lhs *yaml.Node, rhs *yaml.Node) (bool, error) { return true, nil } -func containsObject(lhs *yaml.Node, rhs *yaml.Node) (bool, error) { - if rhs.Kind != yaml.MappingNode { +func containsObject(lhs *CandidateNode, rhs *CandidateNode) (bool, error) { + if rhs.Kind != MappingNode { return false, nil } for index := 0; index < len(rhs.Content); index = index + 2 { @@ -68,21 +66,21 @@ func containsObject(lhs *yaml.Node, rhs *yaml.Node) (bool, error) { return true, nil } -func containsScalars(lhs *yaml.Node, rhs *yaml.Node) (bool, error) { +func containsScalars(lhs *CandidateNode, rhs *CandidateNode) (bool, error) { if lhs.Tag == "!!str" { return strings.Contains(lhs.Value, rhs.Value), nil } return lhs.Value == rhs.Value, nil } -func contains(lhs *yaml.Node, rhs *yaml.Node) (bool, error) { +func contains(lhs *CandidateNode, rhs *CandidateNode) (bool, error) { switch lhs.Kind { - case yaml.MappingNode: + case MappingNode: return containsObject(lhs, rhs) - case yaml.SequenceNode: + case SequenceNode: return containsArray(lhs, rhs) - case yaml.ScalarNode: - if rhs.Kind != yaml.ScalarNode || lhs.Tag != rhs.Tag { + case ScalarNode: + if rhs.Kind != ScalarNode || lhs.Tag != rhs.Tag { return false, nil } if lhs.Tag == "!!null" { @@ -95,14 +93,11 @@ func contains(lhs *yaml.Node, rhs *yaml.Node) (bool, error) { } func containsWithNodes(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - lhs.Node = unwrapDoc(lhs.Node) - rhs.Node = unwrapDoc(rhs.Node) - - if lhs.Node.Kind != rhs.Node.Kind { - return nil, fmt.Errorf("%v cannot check contained in %v", rhs.Node.Tag, lhs.Node.Tag) + if lhs.Kind != rhs.Kind { + return nil, fmt.Errorf("%v cannot check contained in %v", rhs.Tag, lhs.Tag) } - result, err := contains(lhs.Node, rhs.Node) + result, err := contains(lhs, rhs) if err != nil { return nil, err } diff --git a/pkg/yqlib/operator_create_map.go b/pkg/yqlib/operator_create_map.go index 84582c9e505..1b36673a73e 100644 --- a/pkg/yqlib/operator_create_map.go +++ b/pkg/yqlib/operator_create_map.go @@ -2,8 +2,6 @@ package yqlib import ( "container/list" - - "gopkg.in/yaml.v3" ) func createMapOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -12,10 +10,6 @@ func createMapOperator(d *dataTreeNavigator, context Context, expressionNode *Ex //each matchingNodes entry should turn into a sequence of keys to create. //then collect object should do a cross function of the same index sequence for all matches. - var path []interface{} - - var document uint - sequences := list.New() if context.MatchingNodes.Len() > 0 { @@ -36,50 +30,62 @@ func createMapOperator(d *dataTreeNavigator, context Context, expressionNode *Ex sequences.PushBack(sequenceNode) } - return context.SingleChildContext(&CandidateNode{Node: listToNodeSeq(sequences), Document: document, Path: path}), nil + node := listToNodeSeq(sequences) + + return context.SingleChildContext(node), nil } func sequenceFor(d *dataTreeNavigator, context Context, matchingNode *CandidateNode, expressionNode *ExpressionNode) (*CandidateNode, error) { - var path []interface{} var document uint + var filename string + var fileIndex int + var matches = list.New() if matchingNode != nil { - path = matchingNode.Path - document = matchingNode.Document + document = matchingNode.GetDocument() + filename = matchingNode.GetFilename() + fileIndex = matchingNode.GetFileIndex() matches.PushBack(matchingNode) } + log.Debugf("**********sequenceFor %v", NodeToString(matchingNode)) + mapPairs, err := crossFunction(d, context.ChildContext(matches), expressionNode, func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - node := yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - log.Debugf("LHS:", NodeToString(lhs)) - log.Debugf("RHS:", NodeToString(rhs)) - node.Content = []*yaml.Node{ - unwrapDoc(lhs.Node), - unwrapDoc(rhs.Node), - } + node := &CandidateNode{Kind: MappingNode, Tag: "!!map"} + + log.Debugf("**********adding key %v and value %v", NodeToString(lhs), NodeToString(rhs)) + + node.AddKeyValueChild(lhs, rhs) + + node.document = document + node.fileIndex = fileIndex + node.filename = filename - return &CandidateNode{Node: &node, Document: document, Path: path}, nil + return node, nil }, false) if err != nil { return nil, err } innerList := listToNodeSeq(mapPairs.MatchingNodes) - innerList.Style = yaml.FlowStyle - return &CandidateNode{Node: innerList, Document: document, Path: path}, nil + innerList.Style = FlowStyle + innerList.document = document + innerList.fileIndex = fileIndex + innerList.filename = filename + return innerList, nil } // NOTE: here the document index gets dropped so we // no longer know where the node originates from. -func listToNodeSeq(list *list.List) *yaml.Node { - node := yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} +func listToNodeSeq(list *list.List) *CandidateNode { + node := CandidateNode{Kind: SequenceNode, Tag: "!!seq"} for entry := list.Front(); entry != nil; entry = entry.Next() { entryCandidate := entry.Value.(*CandidateNode) log.Debugf("Collecting %v into sequence", NodeToString(entryCandidate)) - node.Content = append(node.Content, entryCandidate.Node) + node.AddChild(entryCandidate) } return &node } diff --git a/pkg/yqlib/operator_create_map_test.go b/pkg/yqlib/operator_create_map_test.go index 6a97246761a..02d53317fec 100644 --- a/pkg/yqlib/operator_create_map_test.go +++ b/pkg/yqlib/operator_create_map_test.go @@ -12,6 +12,38 @@ var createMapOperatorScenarios = []expressionScenario{ "D0, P[], (!!seq)::- [{frog: jumps}]\n", }, }, + { + skipDoc: true, + description: "sets key properly", + expression: `("frog": "jumps") | .[0][0] | .frog`, + expected: []string{ + "D0, P[0 0 frog], (!!str)::jumps\n", + }, + }, + { + skipDoc: true, + description: "sets key properly on map", + expression: `{"frog": "jumps"} | .frog`, + expected: []string{ + "D0, P[frog], (!!str)::jumps\n", + }, + }, + { + document: `{name: Mike, pets: [cat, dog]}`, + expression: `(.name: .pets.[]) | .[0][0] | ..`, + expected: []string{ + "D0, P[0 0], (!!map)::Mike: cat\n", + "D0, P[0 0 Mike], (!!str)::cat\n", + }, + }, + { + description: "check path of nested child", + document: "pets:\n cows: value", + expression: `("b":.pets) | .[0][0] | .b.cows`, + expected: []string{ + "D0, P[0 0 b cows], (!!str)::value\n", + }, + }, { document: `{name: Mike, age: 32}`, expression: `.name: .age`, diff --git a/pkg/yqlib/operator_datetime.go b/pkg/yqlib/operator_datetime.go index 03cdf95f734..a5932c01925 100644 --- a/pkg/yqlib/operator_datetime.go +++ b/pkg/yqlib/operator_datetime.go @@ -6,8 +6,6 @@ import ( "fmt" "strconv" "time" - - "gopkg.in/yaml.v3" ) func getStringParameter(parameterName string, d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (string, error) { @@ -19,7 +17,7 @@ func getStringParameter(parameterName string, d *dataTreeNavigator, context Cont return "", fmt.Errorf("could not find %v for format_time", parameterName) } - return result.MatchingNodes.Front().Value.(*CandidateNode).Node.Value, nil + return result.MatchingNodes.Front().Value.(*CandidateNode).Value, nil } func withDateTimeFormat(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -41,13 +39,13 @@ var Now = time.Now func nowOp(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { - node := &yaml.Node{ + node := &CandidateNode{ Tag: "!!timestamp", - Kind: yaml.ScalarNode, + Kind: ScalarNode, Value: Now().Format(time.RFC3339), } - return context.SingleChildContext(&CandidateNode{Node: node}), nil + return context.SingleChildContext(node), nil } @@ -74,7 +72,7 @@ func formatDateTime(d *dataTreeNavigator, context Context, expressionNode *Expre for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - parsedTime, err := parseDateTime(layout, candidate.Node.Value) + parsedTime, err := parseDateTime(layout, candidate.Value) if err != nil { return Context{}, fmt.Errorf("could not parse datetime of [%v]: %w", candidate.GetNicePath(), err) } @@ -83,14 +81,15 @@ func formatDateTime(d *dataTreeNavigator, context Context, expressionNode *Expre node, errorReading := parseSnippet(formattedTimeStr) if errorReading != nil { log.Debugf("could not parse %v - lets just leave it as a string: %w", formattedTimeStr, errorReading) - node = &yaml.Node{ - Kind: yaml.ScalarNode, + node = &CandidateNode{ + Kind: ScalarNode, Tag: "!!str", Value: formattedTimeStr, } } - - results.PushBack(candidate.CreateReplacement(node)) + node.Parent = candidate.Parent + node.Key = candidate.Key + results.PushBack(node) } return context.ChildContext(results), nil @@ -113,19 +112,13 @@ func tzOp(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - parsedTime, err := parseDateTime(layout, candidate.Node.Value) + parsedTime, err := parseDateTime(layout, candidate.Value) if err != nil { return Context{}, fmt.Errorf("could not parse datetime of [%v] using layout [%v]: %w", candidate.GetNicePath(), layout, err) } tzTime := parsedTime.In(timezone) - node := &yaml.Node{ - Kind: yaml.ScalarNode, - Tag: candidate.Node.Tag, - Value: tzTime.Format(layout), - } - - results.PushBack(candidate.CreateReplacement(node)) + results.PushBack(candidate.CreateReplacement(ScalarNode, candidate.Tag, tzTime.Format(layout))) } return context.ChildContext(results), nil @@ -148,24 +141,20 @@ func fromUnixOp(d *dataTreeNavigator, context Context, expressionNode *Expressio for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - actualTag := guessTagFromCustomType(candidate.Node) + actualTag := candidate.guessTagFromCustomType() - if actualTag != "!!int" && guessTagFromCustomType(candidate.Node) != "!!float" { - return Context{}, fmt.Errorf("from_unix only works on numbers, found %v instead", candidate.Node.Tag) + if actualTag != "!!int" && actualTag != "!!float" { + return Context{}, fmt.Errorf("from_unix only works on numbers, found %v instead", candidate.Tag) } - parsedTime, err := parseUnixTime(candidate.Node.Value) + parsedTime, err := parseUnixTime(candidate.Value) if err != nil { return Context{}, err } - node := &yaml.Node{ - Kind: yaml.ScalarNode, - Tag: "!!timestamp", - Value: parsedTime.Format(time.RFC3339), - } + node := candidate.CreateReplacement(ScalarNode, "!!timestamp", parsedTime.Format(time.RFC3339)) - results.PushBack(candidate.CreateReplacement(node)) + results.PushBack(node) } return context.ChildContext(results), nil @@ -180,18 +169,12 @@ func toUnixOp(d *dataTreeNavigator, context Context, expressionNode *ExpressionN for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - parsedTime, err := parseDateTime(layout, candidate.Node.Value) + parsedTime, err := parseDateTime(layout, candidate.Value) if err != nil { return Context{}, fmt.Errorf("could not parse datetime of [%v] using layout [%v]: %w", candidate.GetNicePath(), layout, err) } - node := &yaml.Node{ - Kind: yaml.ScalarNode, - Tag: "!!int", - Value: fmt.Sprintf("%v", parsedTime.Unix()), - } - - results.PushBack(candidate.CreateReplacement(node)) + results.PushBack(candidate.CreateReplacement(ScalarNode, "!!int", fmt.Sprintf("%v", parsedTime.Unix()))) } return context.ChildContext(results), nil diff --git a/pkg/yqlib/operator_datetime_test.go b/pkg/yqlib/operator_datetime_test.go index a2d3ca1778d..f6616302f61 100644 --- a/pkg/yqlib/operator_datetime_test.go +++ b/pkg/yqlib/operator_datetime_test.go @@ -11,7 +11,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: `a: 2001-12-15T02:59:43.1Z`, expression: `.a |= format_datetime("Monday, 02-Jan-06 at 3:04PM")`, expected: []string{ - "D0, P[], (doc)::a: Saturday, 15-Dec-01 at 2:59AM\n", + "D0, P[], (!!map)::a: Saturday, 15-Dec-01 at 2:59AM\n", }, }, { @@ -20,7 +20,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: `a: Saturday, 15-Dec-01 at 2:59AM`, expression: `.a |= with_dtf("Monday, 02-Jan-06 at 3:04PM"; format_datetime("2006-01-02"))`, expected: []string{ - "D0, P[], (doc)::a: 2001-12-15\n", + "D0, P[], (!!map)::a: 2001-12-15\n", }, }, { @@ -36,7 +36,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: "a: cool", expression: `.updated = now`, expected: []string{ - "D0, P[], (doc)::a: cool\nupdated: 2021-05-19T01:02:03Z\n", + "D0, P[], (!!map)::a: cool\nupdated: 2021-05-19T01:02:03Z\n", }, }, { @@ -62,7 +62,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: "a: cool", expression: `.updated = (now | tz("Australia/Sydney"))`, expected: []string{ - "D0, P[], (doc)::a: cool\nupdated: 2021-05-19T11:02:03+10:00\n", + "D0, P[], (!!map)::a: cool\nupdated: 2021-05-19T11:02:03+10:00\n", }, }, { @@ -71,7 +71,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: "a: Saturday, 15-Dec-01 at 2:59AM GMT", expression: `.a |= with_dtf("Monday, 02-Jan-06 at 3:04PM MST"; tz("Australia/Sydney"))`, expected: []string{ - "D0, P[], (doc)::a: Saturday, 15-Dec-01 at 1:59PM AEDT\n", + "D0, P[], (!!map)::a: Saturday, 15-Dec-01 at 1:59PM AEDT\n", }, }, { @@ -80,7 +80,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: "a: Saturday, 15-Dec-01 at 2:59AM GMT", expression: `.a |= with_dtf("Monday, 02-Jan-06 at 3:04PM MST"; tz("Australia/Sydney"))`, expected: []string{ - "D0, P[], (doc)::a: Saturday, 15-Dec-01 at 1:59PM AEDT\n", + "D0, P[], (!!map)::a: Saturday, 15-Dec-01 at 1:59PM AEDT\n", }, }, { @@ -88,7 +88,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: `a: 2021-01-01T00:00:00Z`, expression: `.a += "3h10m"`, expected: []string{ - "D0, P[], (doc)::a: 2021-01-01T03:10:00Z\n", + "D0, P[], (!!map)::a: 2021-01-01T03:10:00Z\n", }, }, { @@ -97,7 +97,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: `a: 2021-01-01T03:10:00Z`, expression: `.a -= "3h10m"`, expected: []string{ - "D0, P[], (doc)::a: 2021-01-01T00:00:00Z\n", + "D0, P[], (!!map)::a: 2021-01-01T00:00:00Z\n", }, }, { @@ -105,7 +105,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: `a: Saturday, 15-Dec-01 at 2:59AM GMT`, expression: `with_dtf("Monday, 02-Jan-06 at 3:04PM MST"; .a += "3h1m")`, expected: []string{ - "D0, P[], (doc)::a: Saturday, 15-Dec-01 at 6:00AM GMT\n", + "D0, P[], (!!map)::a: Saturday, 15-Dec-01 at 6:00AM GMT\n", }, }, { @@ -114,7 +114,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: `a: Saturday, 15-Dec-01 at 2:59AM GMT`, expression: `with_dtf("Monday, 02-Jan-06 at 3:04PM MST"; .a = (.a + "3h1m" | tz("Australia/Perth")))`, expected: []string{ - "D0, P[], (doc)::a: Saturday, 15-Dec-01 at 2:00PM AWST\n", + "D0, P[], (!!map)::a: Saturday, 15-Dec-01 at 2:00PM AWST\n", }, }, { @@ -123,7 +123,7 @@ var dateTimeOperatorScenarios = []expressionScenario{ document: "a: Saturday, 15-Dec-01 at 2:59AM GMT", expression: `.a |= with_dtf("Monday, 02-Jan-06 at 3:04PM MST", tz("Australia/Sydney"))`, expected: []string{ - "D0, P[], (doc)::a: Saturday, 15-Dec-01 at 1:59PM AEDT\n", + "D0, P[], (!!map)::a: Saturday, 15-Dec-01 at 1:59PM AEDT\n", }, }, } diff --git a/pkg/yqlib/operator_delete.go b/pkg/yqlib/operator_delete.go index eb475da50e2..4ca37a83d9a 100644 --- a/pkg/yqlib/operator_delete.go +++ b/pkg/yqlib/operator_delete.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func deleteChildOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -17,54 +15,53 @@ func deleteChildOperator(d *dataTreeNavigator, context Context, expressionNode * for el := nodesToDelete.MatchingNodes.Back(); el != nil; el = el.Prev() { candidate := el.Value.(*CandidateNode) - if candidate.Node.Kind == yaml.DocumentNode { - //need to delete this node from context. - newResults := list.New() - for item := context.MatchingNodes.Front(); item != nil; item = item.Next() { - nodeInContext := item.Value.(*CandidateNode) - if nodeInContext.Node != candidate.Node { - newResults.PushBack(nodeInContext) - } else { - log.Info("Need to delete this %v", NodeToString(nodeInContext)) - } - } - return context.ChildContext(newResults), nil - } else if candidate.Parent == nil { - //problem: context may already be '.a' and then I pass in '.a.a2'. - // should pass in .a2. - log.Info("Could not find parent of %v", NodeToString(candidate)) - return context, nil + if candidate.Parent == nil { + // must be a top level thing, delete it + return removeFromContext(context, candidate) } + log.Debugf("processing deletion of candidate %v", NodeToString(candidate)) + + parentNode := candidate.Parent - parentNode := candidate.Parent.Node - childPath := candidate.Path[len(candidate.Path)-1] + candidatePath := candidate.GetPath() + childPath := candidatePath[len(candidatePath)-1] - if parentNode.Kind == yaml.MappingNode { + if parentNode.Kind == MappingNode { deleteFromMap(candidate.Parent, childPath) - } else if parentNode.Kind == yaml.SequenceNode { + } else if parentNode.Kind == SequenceNode { deleteFromArray(candidate.Parent, childPath) } else { - return Context{}, fmt.Errorf("Cannot delete nodes from parent of tag %v", parentNode.Tag) + return Context{}, fmt.Errorf("cannot delete nodes from parent of tag %v", parentNode.Tag) } } return context, nil } -func deleteFromMap(candidate *CandidateNode, childPath interface{}) { +func removeFromContext(context Context, candidate *CandidateNode) (Context, error) { + newResults := list.New() + for item := context.MatchingNodes.Front(); item != nil; item = item.Next() { + nodeInContext := item.Value.(*CandidateNode) + if nodeInContext != candidate { + newResults.PushBack(nodeInContext) + } else { + log.Info("Need to delete this %v", NodeToString(nodeInContext)) + } + } + return context.ChildContext(newResults), nil +} + +func deleteFromMap(node *CandidateNode, childPath interface{}) { log.Debug("deleteFromMap") - node := unwrapDoc(candidate.Node) contents := node.Content - newContents := make([]*yaml.Node, 0) + newContents := make([]*CandidateNode, 0) for index := 0; index < len(contents); index = index + 2 { key := contents[index] value := contents[index+1] - childCandidate := candidate.CreateChildInMap(key, value) - shouldDelete := key.Value == childPath - log.Debugf("shouldDelete %v ? %v", childCandidate.GetKey(), shouldDelete) + log.Debugf("shouldDelete %v ? %v", NodeToString(value), shouldDelete) if !shouldDelete { newContents = append(newContents, key, value) @@ -73,11 +70,10 @@ func deleteFromMap(candidate *CandidateNode, childPath interface{}) { node.Content = newContents } -func deleteFromArray(candidate *CandidateNode, childPath interface{}) { +func deleteFromArray(node *CandidateNode, childPath interface{}) { log.Debug("deleteFromArray") - node := unwrapDoc(candidate.Node) contents := node.Content - newContents := make([]*yaml.Node, 0) + newContents := make([]*CandidateNode, 0) for index := 0; index < len(contents); index = index + 1 { value := contents[index] diff --git a/pkg/yqlib/operator_delete_test.go b/pkg/yqlib/operator_delete_test.go index afc938c55ed..473b329a39c 100644 --- a/pkg/yqlib/operator_delete_test.go +++ b/pkg/yqlib/operator_delete_test.go @@ -10,7 +10,7 @@ var deleteOperatorScenarios = []expressionScenario{ document: `{a: cat, b: dog}`, expression: `del(.b)`, expected: []string{ - "D0, P[], (doc)::{a: cat}\n", + "D0, P[], (!!map)::{a: cat}\n", }, }, { @@ -18,7 +18,7 @@ var deleteOperatorScenarios = []expressionScenario{ document: `{a: {a1: fred, a2: frood}}`, expression: `del(.a.a1)`, expected: []string{ - "D0, P[], (doc)::{a: {a2: frood}}\n", + "D0, P[], (!!map)::{a: {a2: frood}}\n", }, }, { @@ -36,7 +36,7 @@ var deleteOperatorScenarios = []expressionScenario{ document: `a: fast`, expression: `del(select(.a == "fast"))`, expected: []string{ - "D0, P[], (doc)::a: slow\n", + "D0, P[], (!!map)::a: slow\n", }, }, { @@ -108,7 +108,7 @@ var deleteOperatorScenarios = []expressionScenario{ document: `[1,2,3]`, expression: `del(.[1])`, expected: []string{ - "D0, P[], (doc)::[1, 3]\n", + "D0, P[], (!!seq)::[1, 3]\n", }, }, { @@ -116,7 +116,7 @@ var deleteOperatorScenarios = []expressionScenario{ document: `a: [1,2,3]`, expression: `del(.a[])`, expected: []string{ - "D0, P[], (doc)::a: []\n", + "D0, P[], (!!map)::a: []\n", }, }, { @@ -124,16 +124,20 @@ var deleteOperatorScenarios = []expressionScenario{ document: `a: [10,x,10, 10, x, 10]`, expression: `del(.a[] | select(. == 10))`, expected: []string{ - "D0, P[], (doc)::a: [x, x]\n", + "D0, P[], (!!map)::a: [x, x]\n", }, }, + { + skipDoc: true, + document: `a: null`, + expression: `del(..)`, + expected: []string{}, + }, { skipDoc: true, document: `a: {thing1: yep, thing2: cool, thing3: hi, b: {thing1: cool, great: huh}}`, expression: `del(..)`, - expected: []string{ - "D0, P[], (!!map)::{}\n", - }, + expected: []string{}, }, { skipDoc: true, @@ -148,7 +152,7 @@ var deleteOperatorScenarios = []expressionScenario{ document: `[{a: cat, b: dog}]`, expression: `del(.[0].a)`, expected: []string{ - "D0, P[], (doc)::[{b: dog}]\n", + "D0, P[], (!!seq)::[{b: dog}]\n", }, }, { @@ -156,7 +160,7 @@ var deleteOperatorScenarios = []expressionScenario{ document: `{a: cat, b: dog}`, expression: `del(.c)`, expected: []string{ - "D0, P[], (doc)::{a: cat, b: dog}\n", + "D0, P[], (!!map)::{a: cat, b: dog}\n", }, }, { @@ -164,7 +168,7 @@ var deleteOperatorScenarios = []expressionScenario{ document: `{a: cat, b: dog, c: bat}`, expression: `del( .[] | select(. == "*at") )`, expected: []string{ - "D0, P[], (doc)::{b: dog}\n", + "D0, P[], (!!map)::{b: dog}\n", }, }, { diff --git a/pkg/yqlib/operator_divide.go b/pkg/yqlib/operator_divide.go index c3d5eb23801..5c4121503f4 100644 --- a/pkg/yqlib/operator_divide.go +++ b/pkg/yqlib/operator_divide.go @@ -4,8 +4,6 @@ import ( "fmt" "strconv" "strings" - - yaml "gopkg.in/yaml.v3" ) func divideOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -15,45 +13,40 @@ func divideOperator(d *dataTreeNavigator, context Context, expressionNode *Expre } func divide(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - lhs.Node = unwrapDoc(lhs.Node) - rhs.Node = unwrapDoc(rhs.Node) - - lhsNode := lhs.Node - - if lhsNode.Tag == "!!null" { - return nil, fmt.Errorf("%v (%v) cannot be divided by %v (%v)", lhsNode.Tag, lhs.GetNicePath(), rhs.Node.Tag, rhs.GetNicePath()) + if lhs.Tag == "!!null" { + return nil, fmt.Errorf("%v (%v) cannot be divided by %v (%v)", lhs.Tag, lhs.GetNicePath(), rhs.Tag, rhs.GetNicePath()) } - target := &yaml.Node{} + target := lhs.CopyWithoutContent() - if lhsNode.Kind == yaml.ScalarNode && rhs.Node.Kind == yaml.ScalarNode { - if err := divideScalars(target, lhsNode, rhs.Node); err != nil { + if lhs.Kind == ScalarNode && rhs.Kind == ScalarNode { + if err := divideScalars(target, lhs, rhs); err != nil { return nil, err } } else { - return nil, fmt.Errorf("%v (%v) cannot be divided by %v (%v)", lhsNode.Tag, lhs.GetNicePath(), rhs.Node.Tag, rhs.GetNicePath()) + return nil, fmt.Errorf("%v (%v) cannot be divided by %v (%v)", lhs.Tag, lhs.GetNicePath(), rhs.Tag, rhs.GetNicePath()) } - return lhs.CreateReplacement(target), nil + return target, nil } -func divideScalars(target *yaml.Node, lhs *yaml.Node, rhs *yaml.Node) error { +func divideScalars(target *CandidateNode, lhs *CandidateNode, rhs *CandidateNode) error { lhsTag := lhs.Tag - rhsTag := guessTagFromCustomType(rhs) + rhsTag := rhs.guessTagFromCustomType() lhsIsCustom := false if !strings.HasPrefix(lhsTag, "!!") { // custom tag - we have to have a guess - lhsTag = guessTagFromCustomType(lhs) + lhsTag = lhs.guessTagFromCustomType() lhsIsCustom = true } if lhsTag == "!!str" && rhsTag == "!!str" { - res := split(lhs.Value, rhs.Value) - target.Kind = res.Kind - target.Tag = res.Tag - target.Content = res.Content + tKind, tTag, res := split(lhs.Value, rhs.Value) + target.Kind = tKind + target.Tag = tTag + target.AddChildren(res) } else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") { - target.Kind = yaml.ScalarNode + target.Kind = ScalarNode target.Style = lhs.Style lhsNum, err := strconv.ParseFloat(lhs.Value, 64) diff --git a/pkg/yqlib/operator_divide_test.go b/pkg/yqlib/operator_divide_test.go index fc7297a39de..c0c9cd96ace 100644 --- a/pkg/yqlib/operator_divide_test.go +++ b/pkg/yqlib/operator_divide_test.go @@ -19,7 +19,7 @@ var divideOperatorScenarios = []expressionScenario{ document: `{}`, expression: "(.a / .b) as $x | .", expected: []string{ - "D0, P[], (doc)::{}\n", + "D0, P[], (!!map)::{}\n", }, }, { @@ -27,7 +27,7 @@ var divideOperatorScenarios = []expressionScenario{ document: `{a: cat_meow, b: _}`, expression: `.c = .a / .b`, expected: []string{ - "D0, P[], (doc)::{a: cat_meow, b: _, c: [cat, meow]}\n", + "D0, P[], (!!map)::{a: cat_meow, b: _, c: [cat, meow]}\n", }, }, { @@ -36,7 +36,7 @@ var divideOperatorScenarios = []expressionScenario{ document: `{a: 12, b: 2.5}`, expression: `.a = .a / .b`, expected: []string{ - "D0, P[], (doc)::{a: 4.8, b: 2.5}\n", + "D0, P[], (!!map)::{a: 4.8, b: 2.5}\n", }, }, { @@ -45,7 +45,7 @@ var divideOperatorScenarios = []expressionScenario{ document: `{a: 1, b: -1}`, expression: `.a = .a / 0 | .b = .b / 0`, expected: []string{ - "D0, P[], (doc)::{a: !!float +Inf, b: !!float -Inf}\n", + "D0, P[], (!!map)::{a: !!float +Inf, b: !!float -Inf}\n", }, }, { @@ -54,7 +54,7 @@ var divideOperatorScenarios = []expressionScenario{ document: "a: !horse cat_meow\nb: !goat _", expression: `.a = .a / .b`, expected: []string{ - "D0, P[], (doc)::a: !horse\n - cat\n - meow\nb: !goat _\n", + "D0, P[], (!!map)::a: !horse\n - cat\n - meow\nb: !goat _\n", }, }, { @@ -63,7 +63,7 @@ var divideOperatorScenarios = []expressionScenario{ document: "a: !horse 1.2\nb: !goat 2.3", expression: `.a = .a / .b`, expected: []string{ - "D0, P[], (doc)::a: !horse 0.5217391304347826\nb: !goat 2.3\n", + "D0, P[], (!!map)::a: !horse 0.5217391304347826\nb: !goat 2.3\n", }, }, { @@ -71,7 +71,7 @@ var divideOperatorScenarios = []expressionScenario{ document: "a: 2\nb: !goat 2.3", expression: `.a = .a / .b`, expected: []string{ - "D0, P[], (doc)::a: 0.8695652173913044\nb: !goat 2.3\n", + "D0, P[], (!!map)::a: 0.8695652173913044\nb: !goat 2.3\n", }, }, { @@ -80,7 +80,7 @@ var divideOperatorScenarios = []expressionScenario{ document: "a: !horse 2\nb: !goat 3", expression: `.a = .a / .b`, expected: []string{ - "D0, P[], (doc)::a: !horse 0.6666666666666666\nb: !goat 3\n", + "D0, P[], (!!map)::a: !horse 0.6666666666666666\nb: !goat 3\n", }, }, { @@ -89,7 +89,7 @@ var divideOperatorScenarios = []expressionScenario{ document: "a: &horse [1]", expression: `.a[1] = .a[0] / 2`, expected: []string{ - "D0, P[], (doc)::a: &horse [1, 0.5]\n", + "D0, P[], (!!map)::a: &horse [1, 0.5]\n", }, }, { diff --git a/pkg/yqlib/operator_document_index.go b/pkg/yqlib/operator_document_index.go index 566fe9df7da..0f853d78a15 100644 --- a/pkg/yqlib/operator_document_index.go +++ b/pkg/yqlib/operator_document_index.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - "gopkg.in/yaml.v3" ) func getDocumentIndexOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -12,8 +10,7 @@ func getDocumentIndexOperator(d *dataTreeNavigator, context Context, expressionN for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", candidate.Document), Tag: "!!int"} - scalar := candidate.CreateReplacement(node) + scalar := candidate.CreateReplacement(ScalarNode, "!!int", fmt.Sprintf("%v", candidate.GetDocument())) results.PushBack(scalar) } return context.ChildContext(results), nil diff --git a/pkg/yqlib/operator_document_index_test.go b/pkg/yqlib/operator_document_index_test.go index e0d82686e07..bd5962de1b1 100644 --- a/pkg/yqlib/operator_document_index_test.go +++ b/pkg/yqlib/operator_document_index_test.go @@ -28,7 +28,7 @@ var documentIndexScenarios = []expressionScenario{ document: "a: cat\n---\na: frog\n", expression: `select(document_index == 1)`, expected: []string{ - "D1, P[], (doc)::a: frog\n", + "D1, P[], (!!map)::a: frog\n", }, }, { @@ -36,7 +36,7 @@ var documentIndexScenarios = []expressionScenario{ document: "a: cat\n---\na: frog\n", expression: `select(di == 1)`, expected: []string{ - "D1, P[], (doc)::a: frog\n", + "D1, P[], (!!map)::a: frog\n", }, }, { @@ -45,7 +45,7 @@ var documentIndexScenarios = []expressionScenario{ expression: `.a | ({"match": ., "doc": document_index})`, expected: []string{ "D0, P[], (!!map)::match: cat\ndoc: 0\n", - "D0, P[], (!!map)::match: frog\ndoc: 1\n", + "D1, P[], (!!map)::match: frog\ndoc: 1\n", }, }, } diff --git a/pkg/yqlib/operator_encoder_decoder.go b/pkg/yqlib/operator_encoder_decoder.go index 877a0902f4b..90c0dbef3c1 100644 --- a/pkg/yqlib/operator_encoder_decoder.go +++ b/pkg/yqlib/operator_encoder_decoder.go @@ -7,8 +7,6 @@ import ( "errors" "regexp" "strings" - - "gopkg.in/yaml.v3" ) func configureEncoder(format PrinterOutputFormat, indent int) Encoder { @@ -78,9 +76,8 @@ func encodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expre if originalList != nil && originalList.Len() > 0 && hasOnlyOneNewLine.MatchString(stringValue) { original := originalList.Front().Value.(*CandidateNode) - originalNode := unwrapDoc(original.Node) // original block did not have a newline at the end, get rid of this one too - if !endWithNewLine.MatchString(originalNode.Value) { + if !endWithNewLine.MatchString(original.Value) { stringValue = chomper.ReplaceAllString(stringValue, "") } } @@ -92,8 +89,7 @@ func encodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expre stringValue = chomper.ReplaceAllString(stringValue, "") } - stringContentNode := &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: stringValue} - results.PushBack(candidate.CreateReplacement(stringContentNode)) + results.PushBack(candidate.CreateReplacement(ScalarNode, "!!str", stringValue)) } return context.ChildContext(results), nil } @@ -141,21 +137,21 @@ func decodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expre context.SetVariable("decoded: "+candidate.GetKey(), candidate.AsList()) - log.Debugf("got: [%v]", candidate.Node.Value) + log.Debugf("got: [%v]", candidate.Value) - err := decoder.Init(strings.NewReader(unwrapDoc(candidate.Node).Value)) + err := decoder.Init(strings.NewReader(candidate.Value)) if err != nil { return Context{}, err } - decodedNode, errorReading := decoder.Decode() + node, errorReading := decoder.Decode() if errorReading != nil { return Context{}, errorReading } - //first node is a doc - node := unwrapDoc(decodedNode.Node) + node.Key = candidate.Key + node.Parent = candidate.Parent - results.PushBack(candidate.CreateReplacement(node)) + results.PushBack(node) } return context.ChildContext(results), nil } diff --git a/pkg/yqlib/operator_encoder_decoder_test.go b/pkg/yqlib/operator_encoder_decoder_test.go index a6eaee89436..6280f0cc6f7 100644 --- a/pkg/yqlib/operator_encoder_decoder_test.go +++ b/pkg/yqlib/operator_encoder_decoder_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -var prefix = "D0, P[], (doc)::a:\n cool:\n bob: dylan\n" +var prefix = "D0, P[], (!!map)::a:\n cool:\n bob: dylan\n" var encoderDecoderOperatorScenarios = []expressionScenario{ { @@ -13,7 +13,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `{a: {cool: "thing"}}`, expression: `.b = (.a | to_json)`, expected: []string{ - `D0, P[], (doc)::{a: {cool: "thing"}, b: "{\n \"cool\": \"thing\"\n}\n"} + `D0, P[], (!!map)::{a: {cool: "thing"}, b: "{\n \"cool\": \"thing\"\n}\n"} `, }, }, @@ -24,7 +24,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `{a: {cool: "thing"}}`, expression: `.b = (.a | to_json(0))`, expected: []string{ - `D0, P[], (doc)::{a: {cool: "thing"}, b: '{"cool":"thing"}'} + `D0, P[], (!!map)::{a: {cool: "thing"}, b: '{"cool":"thing"}'} `, }, }, @@ -35,7 +35,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `{a: {cool: "thing"}}`, expression: `.b = (.a | @json)`, expected: []string{ - `D0, P[], (doc)::{a: {cool: "thing"}, b: '{"cool":"thing"}'} + `D0, P[], (!!map)::{a: {cool: "thing"}, b: '{"cool":"thing"}'} `, }, }, @@ -54,7 +54,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `{a: {cool: "thing"}}`, expression: `.b = (.a | to_props)`, expected: []string{ - `D0, P[], (doc)::{a: {cool: "thing"}, b: "cool = thing\n"} + `D0, P[], (!!map)::{a: {cool: "thing"}, b: "cool = thing\n"} `, }, }, @@ -63,7 +63,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `{a: {cool: "thing"}}`, expression: `.b = (.a | @props)`, expected: []string{ - `D0, P[], (doc)::{a: {cool: "thing"}, b: "cool = thing\n"} + `D0, P[], (!!map)::{a: {cool: "thing"}, b: "cool = thing\n"} `, }, }, @@ -72,7 +72,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `a: "cats=great\ndogs=cool as well"`, expression: `.a |= @propsd`, expected: []string{ - "D0, P[], (doc)::a:\n cats: great\n dogs: cool as well\n", + "D0, P[], (!!map)::a:\n cats: great\n dogs: cool as well\n", }, }, { @@ -80,7 +80,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `a: "cats,dogs\ngreat,cool as well"`, expression: `.a |= @csvd`, expected: []string{ - "D0, P[], (doc)::a:\n - cats: great\n dogs: cool as well\n", + "D0, P[], (!!map)::a:\n - cats: great\n dogs: cool as well\n", }, }, { @@ -88,7 +88,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `a: "cats dogs\ngreat cool as well"`, expression: `.a |= @tsvd`, expected: []string{ - "D0, P[], (doc)::a:\n - cats: great\n dogs: cool as well\n", + "D0, P[], (!!map)::a:\n - cats: great\n dogs: cool as well\n", }, }, { @@ -122,7 +122,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `{a: {cool: "thing"}}`, expression: `.b = (.a | to_yaml)`, expected: []string{ - `D0, P[], (doc)::{a: {cool: "thing"}, b: "{cool: \"thing\"}\n"} + `D0, P[], (!!map)::{a: {cool: "thing"}, b: "{cool: \"thing\"}\n"} `, }, }, @@ -131,7 +131,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `a: "foo: bar"`, expression: `.b = (.a | from_yaml)`, expected: []string{ - "D0, P[], (doc)::a: \"foo: bar\"\nb:\n foo: bar\n", + "D0, P[], (!!map)::a: \"foo: bar\"\nb:\n foo: bar\n", }, }, { @@ -140,7 +140,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: "a: |\n foo: bar\n baz: dog\n", expression: `.a |= (from_yaml | .foo = "cat" | to_yaml)`, expected: []string{ - "D0, P[], (doc)::a: |\n foo: cat\n baz: dog\n", + "D0, P[], (!!map)::a: |\n foo: cat\n baz: dog\n", }, }, { @@ -149,7 +149,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: "a: |-\n foo: bar\n baz: dog\n", expression: `.a |= (from_yaml | .foo = "cat" | to_yaml)`, expected: []string{ - "D0, P[], (doc)::a: |-\n foo: cat\n baz: dog\n", + "D0, P[], (!!map)::a: |-\n foo: cat\n baz: dog\n", }, }, { @@ -158,7 +158,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: "a: 'foo: bar'", expression: `.a |= (from_yaml | .foo = "cat" | to_yaml)`, expected: []string{ - "D0, P[], (doc)::a: 'foo: cat'\n", + "D0, P[], (!!map)::a: 'foo: cat'\n", }, }, { @@ -193,7 +193,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: "a: \"foo: bar\"", expression: `.a |= (from_yaml | .foo = {"a": "frog"} | to_yaml)`, expected: []string{ - "D0, P[], (doc)::a: \"foo:\\n a: frog\"\n", + "D0, P[], (!!map)::a: \"foo:\\n a: frog\"\n", }, }, { @@ -229,7 +229,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: `a: "bar"`, expression: `.b = (.a | from_xml)`, expected: []string{ - "D0, P[], (doc)::a: \"bar\"\nb:\n foo: bar\n", + "D0, P[], (!!map)::a: \"bar\"\nb:\n foo: bar\n", }, }, { @@ -299,7 +299,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{ document: "coolData: YTogYXBwbGUK", expression: ".coolData |= (@base64d | from_yaml)", expected: []string{ - "D0, P[], (doc)::coolData:\n a: apple\n", + "D0, P[], (!!map)::coolData:\n a: apple\n", }, }, { diff --git a/pkg/yqlib/operator_entries.go b/pkg/yqlib/operator_entries.go index 2af9fe94a6c..2279d75bd19 100644 --- a/pkg/yqlib/operator_entries.go +++ b/pkg/yqlib/operator_entries.go @@ -3,64 +3,59 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) -func entrySeqFor(key *yaml.Node, value *yaml.Node) *yaml.Node { - var keyKey = &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "key"} - var valueKey = &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "value"} +func entrySeqFor(key *CandidateNode, value *CandidateNode) *CandidateNode { + var keyKey = &CandidateNode{Kind: ScalarNode, Tag: "!!str", Value: "key"} + var valueKey = &CandidateNode{Kind: ScalarNode, Tag: "!!str", Value: "value"} - return &yaml.Node{ - Kind: yaml.MappingNode, + return &CandidateNode{ + Kind: MappingNode, Tag: "!!map", - Content: []*yaml.Node{keyKey, key, valueKey, value}, + Content: []*CandidateNode{keyKey, key, valueKey, value}, } } func toEntriesFromMap(candidateNode *CandidateNode) *CandidateNode { - var sequence = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} - var entriesNode = candidateNode.CreateReplacementWithDocWrappers(sequence) + var sequence = candidateNode.CreateReplacementWithComments(SequenceNode, "!!seq", 0) - var contents = unwrapDoc(candidateNode.Node).Content + var contents = candidateNode.Content for index := 0; index < len(contents); index = index + 2 { key := contents[index] value := contents[index+1] - sequence.Content = append(sequence.Content, entrySeqFor(key, value)) + sequence.AddChild(entrySeqFor(key, value)) } - return entriesNode + return sequence } func toEntriesfromSeq(candidateNode *CandidateNode) *CandidateNode { - var sequence = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} - var entriesNode = candidateNode.CreateReplacementWithDocWrappers(sequence) + var sequence = candidateNode.CreateReplacementWithComments(SequenceNode, "!!seq", 0) - var contents = unwrapDoc(candidateNode.Node).Content + var contents = candidateNode.Content for index := 0; index < len(contents); index = index + 1 { - key := &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!int", Value: fmt.Sprintf("%v", index)} + key := &CandidateNode{Kind: ScalarNode, Tag: "!!int", Value: fmt.Sprintf("%v", index)} value := contents[index] - sequence.Content = append(sequence.Content, entrySeqFor(key, value)) + sequence.AddChild(entrySeqFor(key, value)) } - return entriesNode + return sequence } func toEntriesOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidateNode := unwrapDoc(candidate.Node) - switch candidateNode.Kind { - case yaml.MappingNode: + switch candidate.Kind { + case MappingNode: results.PushBack(toEntriesFromMap(candidate)) - case yaml.SequenceNode: + case SequenceNode: results.PushBack(toEntriesfromSeq(candidate)) default: - if candidateNode.Tag != "!!null" { - return Context{}, fmt.Errorf("%v has no keys", candidate.Node.Tag) + if candidate.Tag != "!!null" { + return Context{}, fmt.Errorf("%v has no keys", candidate.Tag) } } } @@ -68,9 +63,8 @@ func toEntriesOperator(d *dataTreeNavigator, context Context, expressionNode *Ex return context.ChildContext(results), nil } -func parseEntry(entry *yaml.Node, position int) (*yaml.Node, *yaml.Node, error) { +func parseEntry(candidateNode *CandidateNode, position int) (*CandidateNode, *CandidateNode, error) { prefs := traversePreferences{DontAutoCreate: true} - candidateNode := &CandidateNode{Node: entry} keyResults, err := traverseMap(Context{}, candidateNode, createStringScalarNode("key"), prefs, false) @@ -88,15 +82,14 @@ func parseEntry(entry *yaml.Node, position int) (*yaml.Node, *yaml.Node, error) return nil, nil, fmt.Errorf("expected to find one 'value' entry but found %v in position %v", valueResults.Len(), position) } - return keyResults.Front().Value.(*CandidateNode).Node, valueResults.Front().Value.(*CandidateNode).Node, nil + return keyResults.Front().Value.(*CandidateNode), valueResults.Front().Value.(*CandidateNode), nil } func fromEntries(candidateNode *CandidateNode) (*CandidateNode, error) { - var node = &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} - var mapCandidateNode = candidateNode.CreateReplacementWithDocWrappers(node) + var node = candidateNode.CopyWithoutContent() - var contents = unwrapDoc(candidateNode.Node).Content + var contents = candidateNode.Content for index := 0; index < len(contents); index = index + 1 { key, value, err := parseEntry(contents[index], index) @@ -104,19 +97,20 @@ func fromEntries(candidateNode *CandidateNode) (*CandidateNode, error) { return nil, err } - node.Content = append(node.Content, key, value) + node.AddKeyValueChild(key, value) } - return mapCandidateNode, nil + node.Kind = MappingNode + node.Tag = "!!map" + return node, nil } func fromEntriesOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidateNode := unwrapDoc(candidate.Node) - switch candidateNode.Kind { - case yaml.SequenceNode: + switch candidate.Kind { + case SequenceNode: mapResult, err := fromEntries(candidate) if err != nil { return Context{}, err @@ -162,8 +156,13 @@ func withEntriesOperator(d *dataTreeNavigator, context Context, expressionNode * if err != nil { return Context{}, err } + log.Debug("candidate %v", NodeToString(candidate)) + log.Debug("candidate leading content: %v", candidate.LeadingContent) collected.LeadingContent = candidate.LeadingContent - collected.TrailingContent = candidate.TrailingContent + log.Debug("candidate FootComment: [%v]", candidate.FootComment) + + collected.HeadComment = candidate.HeadComment + collected.FootComment = candidate.FootComment log.Debugf("**** collected %v", collected.LeadingContent) diff --git a/pkg/yqlib/operator_env.go b/pkg/yqlib/operator_env.go index ed3f51e277f..3ab10b24a8b 100644 --- a/pkg/yqlib/operator_env.go +++ b/pkg/yqlib/operator_env.go @@ -7,7 +7,6 @@ import ( "strings" parse "github.com/a8m/envsubst/parse" - yaml "gopkg.in/yaml.v3" ) type envOpPreferences struct { @@ -18,39 +17,40 @@ type envOpPreferences struct { } func envOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { - envName := expressionNode.Operation.CandidateNode.Node.Value + envName := expressionNode.Operation.CandidateNode.Value log.Debug("EnvOperator, env name:", envName) rawValue := os.Getenv(envName) preferences := expressionNode.Operation.Preferences.(envOpPreferences) - var node *yaml.Node + var node *CandidateNode if preferences.StringValue { - node = &yaml.Node{ - Kind: yaml.ScalarNode, + node = &CandidateNode{ + Kind: ScalarNode, Tag: "!!str", Value: rawValue, } } else if rawValue == "" { - return Context{}, fmt.Errorf("Value for env variable '%v' not provided in env()", envName) + return Context{}, fmt.Errorf("value for env variable '%v' not provided in env()", envName) } else { - var dataBucket yaml.Node - decoder := yaml.NewDecoder(strings.NewReader(rawValue)) - errorReading := decoder.Decode(&dataBucket) - if errorReading != nil { - return Context{}, errorReading + decoder := NewYamlDecoder(ConfiguredYamlPreferences) + if err := decoder.Init(strings.NewReader(rawValue)); err != nil { + return Context{}, err } - //first node is a doc - node = unwrapDoc(&dataBucket) + var err error + node, err = decoder.Decode() + + if err != nil { + return Context{}, err + } + } log.Debug("ENV tag", node.Tag) log.Debug("ENV value", node.Value) log.Debug("ENV Kind", node.Kind) - target := &CandidateNode{Node: node} - - return context.SingleChildContext(target), nil + return context.SingleChildContext(node), nil } func envsubstOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -70,8 +70,7 @@ func envsubstOperator(d *dataTreeNavigator, context Context, expressionNode *Exp } for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) + node := el.Value.(*CandidateNode) if node.Tag != "!!str" { log.Warning("EnvSubstOperator, env name:", node.Tag, node.Value) return Context{}, fmt.Errorf("cannot substitute with %v, can only substitute strings. Hint: Most often you'll want to use '|=' over '=' for this operation", node.Tag) @@ -81,8 +80,7 @@ func envsubstOperator(d *dataTreeNavigator, context Context, expressionNode *Exp if err != nil { return Context{}, err } - targetNode := &yaml.Node{Kind: yaml.ScalarNode, Value: value, Tag: "!!str"} - result := candidate.CreateReplacement(targetNode) + result := node.CreateReplacement(ScalarNode, "!!str", value) results.PushBack(result) } diff --git a/pkg/yqlib/operator_env_test.go b/pkg/yqlib/operator_env_test.go index 7f403dd7e6a..878c5bcec97 100644 --- a/pkg/yqlib/operator_env_test.go +++ b/pkg/yqlib/operator_env_test.go @@ -60,7 +60,7 @@ var envOperatorScenarios = []expressionScenario{ environmentVariables: map[string]string{"pathEnv": ".a.b[0].name", "valueEnv": "moo"}, expression: `eval(strenv(pathEnv)) = strenv(valueEnv)`, expected: []string{ - "D0, P[], (doc)::{a: {b: [{name: moo}, {name: cat}]}}\n", + "D0, P[], (!!map)::{a: {b: [{name: moo}, {name: cat}]}}\n", }, }, { @@ -136,7 +136,7 @@ var envOperatorScenarios = []expressionScenario{ document: "{v: \"${myenv}\"}", expression: `.v |= envsubst`, expected: []string{ - "D0, P[], (doc)::{v: \"cat meow\"}\n", + "D0, P[], (!!map)::{v: \"cat meow\"}\n", }, }, { diff --git a/pkg/yqlib/operator_equals.go b/pkg/yqlib/operator_equals.go index d8dc788ae6a..9f836c9fc7e 100644 --- a/pkg/yqlib/operator_equals.go +++ b/pkg/yqlib/operator_equals.go @@ -1,7 +1,5 @@ package yqlib -import "gopkg.in/yaml.v3" - func equalsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { log.Debugf("-- equalsOperation") return crossFunction(d, context, expressionNode, isEquals(false), true) @@ -12,33 +10,29 @@ func isEquals(flip bool) func(d *dataTreeNavigator, context Context, lhs *Candid value := false log.Debugf("-- isEquals cross function") if lhs == nil && rhs == nil { + log.Debugf("-- both are nil") owner := &CandidateNode{} return createBooleanCandidate(owner, !flip), nil } else if lhs == nil { log.Debugf("lhs nil, but rhs is not") - rhsNode := unwrapDoc(rhs.Node) - value := rhsNode.Tag == "!!null" + value := rhs.Tag == "!!null" if flip { value = !value } return createBooleanCandidate(rhs, value), nil } else if rhs == nil { log.Debugf("lhs not nil, but rhs is") - lhsNode := unwrapDoc(lhs.Node) - value := lhsNode.Tag == "!!null" + value := lhs.Tag == "!!null" if flip { value = !value } return createBooleanCandidate(lhs, value), nil } - lhsNode := unwrapDoc(lhs.Node) - rhsNode := unwrapDoc(rhs.Node) - - if lhsNode.Tag == "!!null" { - value = (rhsNode.Tag == "!!null") - } else if lhsNode.Kind == yaml.ScalarNode && rhsNode.Kind == yaml.ScalarNode { - value = matchKey(lhsNode.Value, rhsNode.Value) + if lhs.Tag == "!!null" { + value = (rhs.Tag == "!!null") + } else if lhs.Kind == ScalarNode && rhs.Kind == ScalarNode { + value = matchKey(lhs.Value, rhs.Value) } log.Debugf("%v == %v ? %v", NodeToString(lhs), NodeToString(rhs), value) if flip { diff --git a/pkg/yqlib/operator_equals_test.go b/pkg/yqlib/operator_equals_test.go index 7a821647d91..43a2fa86559 100644 --- a/pkg/yqlib/operator_equals_test.go +++ b/pkg/yqlib/operator_equals_test.go @@ -49,7 +49,7 @@ var equalsOperatorScenarios = []expressionScenario{ document: "{}", expression: "(.a == .b) as $x | .", expected: []string{ - "D0, P[], (doc)::{}\n", + "D0, P[], (!!map)::{}\n", }, }, { @@ -65,7 +65,7 @@ var equalsOperatorScenarios = []expressionScenario{ document: "{}", expression: "(.a != .b) as $x | .", expected: []string{ - "D0, P[], (doc)::{}\n", + "D0, P[], (!!map)::{}\n", }, }, { @@ -87,7 +87,7 @@ var equalsOperatorScenarios = []expressionScenario{ document: "{a: {b: 10}}", expression: "select(.d == .c)", expected: []string{ - "D0, P[], (doc)::{a: {b: 10}}\n", + "D0, P[], (!!map)::{a: {b: 10}}\n", }, }, { @@ -95,7 +95,7 @@ var equalsOperatorScenarios = []expressionScenario{ document: "{a: {b: 10}}", expression: "select(null == .c)", expected: []string{ - "D0, P[], (doc)::{a: {b: 10}}\n", + "D0, P[], (!!map)::{a: {b: 10}}\n", }, }, { @@ -176,7 +176,7 @@ var equalsOperatorScenarios = []expressionScenario{ document: "a: frog", expression: `select(.b != "thing")`, expected: []string{ - "D0, P[], (doc)::a: frog\n", + "D0, P[], (!!map)::a: frog\n", }, }, { @@ -184,7 +184,7 @@ var equalsOperatorScenarios = []expressionScenario{ document: "a: frog", expression: `select(.b == .c)`, expected: []string{ - "D0, P[], (doc)::a: frog\n", + "D0, P[], (!!map)::a: frog\n", }, }, } diff --git a/pkg/yqlib/operator_error.go b/pkg/yqlib/operator_error.go index 8b0e3a9fffa..ba66a8a35d4 100644 --- a/pkg/yqlib/operator_error.go +++ b/pkg/yqlib/operator_error.go @@ -14,7 +14,7 @@ func errorOperator(d *dataTreeNavigator, context Context, expressionNode *Expres } errorMessage := "aborted" if rhs.MatchingNodes.Len() > 0 { - errorMessage = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + errorMessage = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } return Context{}, fmt.Errorf(errorMessage) } diff --git a/pkg/yqlib/operator_error_test.go b/pkg/yqlib/operator_error_test.go index 845686d6f6a..3ccbbf2087a 100644 --- a/pkg/yqlib/operator_error_test.go +++ b/pkg/yqlib/operator_error_test.go @@ -27,7 +27,7 @@ var errorOperatorScenarios = []expressionScenario{ document: "name: Bob\nfavouriteAnimal: cat\n", expression: validationExpression, expected: []string{ - "D0, P[], (doc)::name: Bob\nfavouriteAnimal: cat\nnumPets: 3\n", + "D0, P[], (!!map)::name: Bob\nfavouriteAnimal: cat\nnumPets: 3\n", }, }, } diff --git a/pkg/yqlib/operator_eval.go b/pkg/yqlib/operator_eval.go index 78037e97d10..2bba51d2d9a 100644 --- a/pkg/yqlib/operator_eval.go +++ b/pkg/yqlib/operator_eval.go @@ -17,7 +17,7 @@ func evalOperator(d *dataTreeNavigator, context Context, expressionNode *Express for pathExpStrEntry := pathExpStrResults.MatchingNodes.Front(); pathExpStrEntry != nil; pathExpStrEntry = pathExpStrEntry.Next() { expressionStrCandidate := pathExpStrEntry.Value.(*CandidateNode) - expressions[expIndex], err = ExpressionParser.ParseExpression(expressionStrCandidate.Node.Value) + expressions[expIndex], err = ExpressionParser.ParseExpression(expressionStrCandidate.Value) if err != nil { return Context{}, err } diff --git a/pkg/yqlib/operator_eval_test.go b/pkg/yqlib/operator_eval_test.go index 3bff5a12313..6726b75a76b 100644 --- a/pkg/yqlib/operator_eval_test.go +++ b/pkg/yqlib/operator_eval_test.go @@ -21,7 +21,7 @@ var evalOperatorScenarios = []expressionScenario{ environmentVariables: map[string]string{"pathEnv": ".a.b[0].name", "valueEnv": "moo"}, expression: `eval(strenv(pathEnv)) = strenv(valueEnv)`, expected: []string{ - "D0, P[], (doc)::{a: {b: [{name: moo}, {name: cat}]}}\n", + "D0, P[], (!!map)::{a: {b: [{name: moo}, {name: cat}]}}\n", }, }, } diff --git a/pkg/yqlib/operator_file.go b/pkg/yqlib/operator_file.go index c0ffaad89a5..29896719c1f 100644 --- a/pkg/yqlib/operator_file.go +++ b/pkg/yqlib/operator_file.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func getFilenameOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -14,8 +12,7 @@ func getFilenameOperator(d *dataTreeNavigator, context Context, expressionNode * for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.ScalarNode, Value: candidate.Filename, Tag: "!!str"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement(ScalarNode, "!!str", candidate.GetFilename()) results.PushBack(result) } @@ -29,8 +26,7 @@ func getFileIndexOperator(d *dataTreeNavigator, context Context, expressionNode for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", candidate.FileIndex), Tag: "!!int"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement(ScalarNode, "!!int", fmt.Sprintf("%v", candidate.GetFileIndex())) results.PushBack(result) } diff --git a/pkg/yqlib/operator_filter.go b/pkg/yqlib/operator_filter.go index 8cf28303d6f..0bd5ebb0523 100644 --- a/pkg/yqlib/operator_filter.go +++ b/pkg/yqlib/operator_filter.go @@ -25,7 +25,7 @@ func filterOperator(d *dataTreeNavigator, context Context, expressionNode *Expre if err != nil { return Context{}, err } - collected.Node.Style = unwrapDoc(candidate.Node).Style + collected.Style = candidate.Style results.PushBack(collected) } return context.ChildContext(results), nil diff --git a/pkg/yqlib/operator_flatten.go b/pkg/yqlib/operator_flatten.go index e7ccf99ce15..011337e65c2 100644 --- a/pkg/yqlib/operator_flatten.go +++ b/pkg/yqlib/operator_flatten.go @@ -2,26 +2,24 @@ package yqlib import ( "fmt" - - yaml "gopkg.in/yaml.v3" ) type flattenPreferences struct { depth int } -func flatten(node *yaml.Node, depth int) { +func flatten(node *CandidateNode, depth int) { if depth == 0 { return } - if node.Kind != yaml.SequenceNode { + if node.Kind != SequenceNode { return } content := node.Content - newSeq := make([]*yaml.Node, 0) + newSeq := make([]*CandidateNode, 0) for i := 0; i < len(content); i++ { - if content[i].Kind == yaml.SequenceNode { + if content[i].Kind == SequenceNode { flatten(content[i], depth-1) for j := 0; j < len(content[i].Content); j++ { newSeq = append(newSeq, content[i].Content[j]) @@ -30,7 +28,8 @@ func flatten(node *yaml.Node, depth int) { newSeq = append(newSeq, content[i]) } } - node.Content = newSeq + node.Content = make([]*CandidateNode, 0) + node.AddChildren(newSeq) } func flattenOp(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -40,12 +39,11 @@ func flattenOp(d *dataTreeNavigator, context Context, expressionNode *Expression for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidateNode := unwrapDoc(candidate.Node) - if candidateNode.Kind != yaml.SequenceNode { - return Context{}, fmt.Errorf("Only arrays are supported for flatten") + if candidate.Kind != SequenceNode { + return Context{}, fmt.Errorf("only arrays are supported for flatten") } - flatten(candidateNode, depth) + flatten(candidate, depth) } diff --git a/pkg/yqlib/operator_flatten_test.go b/pkg/yqlib/operator_flatten_test.go index add71e1f96c..fc764d302c1 100644 --- a/pkg/yqlib/operator_flatten_test.go +++ b/pkg/yqlib/operator_flatten_test.go @@ -11,7 +11,7 @@ var flattenOperatorScenarios = []expressionScenario{ document: `[1, [2], [[3]]]`, expression: `flatten`, expected: []string{ - "D0, P[], (doc)::[1, 2, 3]\n", + "D0, P[], (!!seq)::[1, 2, 3]\n", }, }, { @@ -19,7 +19,7 @@ var flattenOperatorScenarios = []expressionScenario{ document: `[1, [2], [[3]]]`, expression: `flatten(1)`, expected: []string{ - "D0, P[], (doc)::[1, 2, [3]]\n", + "D0, P[], (!!seq)::[1, 2, [3]]\n", }, }, { @@ -27,7 +27,7 @@ var flattenOperatorScenarios = []expressionScenario{ document: `[[]]`, expression: `flatten`, expected: []string{ - "D0, P[], (doc)::[]\n", + "D0, P[], (!!seq)::[]\n", }, }, { @@ -35,7 +35,7 @@ var flattenOperatorScenarios = []expressionScenario{ document: `[{foo: bar}, [{foo: baz}]]`, expression: `flatten`, expected: []string{ - "D0, P[], (doc)::[{foo: bar}, {foo: baz}]\n", + "D0, P[], (!!seq)::[{foo: bar}, {foo: baz}]\n", }, }, } diff --git a/pkg/yqlib/operator_group_by.go b/pkg/yqlib/operator_group_by.go index 3bb70b50363..779295b1ab9 100644 --- a/pkg/yqlib/operator_group_by.go +++ b/pkg/yqlib/operator_group_by.go @@ -5,13 +5,11 @@ import ( "fmt" "github.com/elliotchance/orderedmap" - yaml "gopkg.in/yaml.v3" ) -func processIntoGroups(d *dataTreeNavigator, context Context, rhsExp *ExpressionNode, node *yaml.Node) (*orderedmap.OrderedMap, error) { +func processIntoGroups(d *dataTreeNavigator, context Context, rhsExp *ExpressionNode, node *CandidateNode) (*orderedmap.OrderedMap, error) { var newMatches = orderedmap.NewOrderedMap() - for _, node := range node.Content { - child := &CandidateNode{Node: node} + for _, child := range node.Content { rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(child), rhsExp) if err != nil { @@ -23,7 +21,7 @@ func processIntoGroups(d *dataTreeNavigator, context Context, rhsExp *Expression if rhs.MatchingNodes.Len() > 0 { first := rhs.MatchingNodes.Front() keyCandidate := first.Value.(*CandidateNode) - keyValue = keyCandidate.Node.Value + keyValue = keyCandidate.Value } groupList, exists := newMatches.Get(keyValue) @@ -32,7 +30,7 @@ func processIntoGroups(d *dataTreeNavigator, context Context, rhsExp *Expression groupList = list.New() newMatches.Set(keyValue, groupList) } - groupList.(*list.List).PushBack(node) + groupList.(*list.List).PushBack(child) } return newMatches, nil } @@ -44,30 +42,29 @@ func groupBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionNo for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidateNode := unwrapDoc(candidate.Node) - if candidateNode.Kind != yaml.SequenceNode { - return Context{}, fmt.Errorf("Only arrays are supported for group by") + if candidate.Kind != SequenceNode { + return Context{}, fmt.Errorf("only arrays are supported for group by") } - newMatches, err := processIntoGroups(d, context, expressionNode.RHS, candidateNode) + newMatches, err := processIntoGroups(d, context, expressionNode.RHS, candidate) if err != nil { return Context{}, err } - resultNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} + resultNode := candidate.CreateReplacement(SequenceNode, "!!seq", "") for groupEl := newMatches.Front(); groupEl != nil; groupEl = groupEl.Next() { - groupResultNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} + groupResultNode := &CandidateNode{Kind: SequenceNode, Tag: "!!seq"} groupList := groupEl.Value.(*list.List) for groupItem := groupList.Front(); groupItem != nil; groupItem = groupItem.Next() { - groupResultNode.Content = append(groupResultNode.Content, groupItem.Value.(*yaml.Node)) + groupResultNode.AddChild(groupItem.Value.(*CandidateNode)) } - resultNode.Content = append(resultNode.Content, groupResultNode) + resultNode.AddChild(groupResultNode) } - results.PushBack(candidate.CreateReplacement(resultNode)) + results.PushBack(resultNode) } diff --git a/pkg/yqlib/operator_has.go b/pkg/yqlib/operator_has.go index 01d7a1fee24..95ab4b6d979 100644 --- a/pkg/yqlib/operator_has.go +++ b/pkg/yqlib/operator_has.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "strconv" - - yaml "gopkg.in/yaml.v3" ) func hasOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -19,20 +17,18 @@ func hasOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi } wantedKey := "null" - wanted := &yaml.Node{Tag: "!!null"} + wanted := &CandidateNode{Tag: "!!null"} if rhs.MatchingNodes.Len() != 0 { - wanted = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node + wanted = rhs.MatchingNodes.Front().Value.(*CandidateNode) wantedKey = wanted.Value } for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - // grab the first value - candidateNode := unwrapDoc(candidate.Node) - var contents = candidateNode.Content - switch candidateNode.Kind { - case yaml.MappingNode: + var contents = candidate.Content + switch candidate.Kind { + case MappingNode: candidateHasKey := false for index := 0; index < len(contents) && !candidateHasKey; index = index + 2 { key := contents[index] @@ -41,7 +37,7 @@ func hasOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi } } results.PushBack(createBooleanCandidate(candidate, candidateHasKey)) - case yaml.SequenceNode: + case SequenceNode: candidateHasKey := false if wanted.Tag == "!!int" { var number, errParsingInt = strconv.ParseInt(wantedKey, 10, 64) diff --git a/pkg/yqlib/operator_has_test.go b/pkg/yqlib/operator_has_test.go index 4750404874a..bed11fcbb8e 100644 --- a/pkg/yqlib/operator_has_test.go +++ b/pkg/yqlib/operator_has_test.go @@ -18,7 +18,7 @@ var hasOperatorScenarios = []expressionScenario{ document: `a: hello`, expression: `has(.b) as $c | .`, expected: []string{ - "D0, P[], (doc)::a: hello\n", + "D0, P[], (!!map)::a: hello\n", }, }, { diff --git a/pkg/yqlib/operator_keys.go b/pkg/yqlib/operator_keys.go index 3ea4b5da141..bbb9a5d803e 100644 --- a/pkg/yqlib/operator_keys.go +++ b/pkg/yqlib/operator_keys.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - "gopkg.in/yaml.v3" ) func isKeyOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -30,7 +28,7 @@ func getKeyOperator(d *dataTreeNavigator, context Context, expressionNode *Expre candidate := el.Value.(*CandidateNode) if candidate.Key != nil { - results.PushBack(candidate.CreateReplacement(candidate.Key)) + results.PushBack(candidate.Key) } } @@ -45,41 +43,40 @@ func keysOperator(d *dataTreeNavigator, context Context, expressionNode *Express for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) - var targetNode *yaml.Node - if node.Kind == yaml.MappingNode { - targetNode = getMapKeys(node) - } else if node.Kind == yaml.SequenceNode { - targetNode = getIndices(node) + + var targetNode *CandidateNode + if candidate.Kind == MappingNode { + targetNode = getMapKeys(candidate) + } else if candidate.Kind == SequenceNode { + targetNode = getIndices(candidate) } else { - return Context{}, fmt.Errorf("Cannot get keys of %v, keys only works for maps and arrays", node.Tag) + return Context{}, fmt.Errorf("Cannot get keys of %v, keys only works for maps and arrays", candidate.Tag) } - result := candidate.CreateReplacement(targetNode) - results.PushBack(result) + results.PushBack(targetNode) } return context.ChildContext(results), nil } -func getMapKeys(node *yaml.Node) *yaml.Node { - contents := make([]*yaml.Node, 0) +func getMapKeys(node *CandidateNode) *CandidateNode { + contents := make([]*CandidateNode, 0) for index := 0; index < len(node.Content); index = index + 2 { contents = append(contents, node.Content[index]) } - return &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq", Content: contents} + return &CandidateNode{Kind: SequenceNode, Tag: "!!seq", Content: contents} } -func getIndices(node *yaml.Node) *yaml.Node { - var contents = make([]*yaml.Node, len(node.Content)) +func getIndices(node *CandidateNode) *CandidateNode { + var contents = make([]*CandidateNode, len(node.Content)) for index := range node.Content { - contents[index] = &yaml.Node{ - Kind: yaml.ScalarNode, + contents[index] = &CandidateNode{ + Kind: ScalarNode, Tag: "!!int", Value: fmt.Sprintf("%v", index), } } - return &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq", Content: contents} + return &CandidateNode{Kind: SequenceNode, Tag: "!!seq", Content: contents} } diff --git a/pkg/yqlib/operator_keys_test.go b/pkg/yqlib/operator_keys_test.go index 3f821b510ef..b0936608413 100644 --- a/pkg/yqlib/operator_keys_test.go +++ b/pkg/yqlib/operator_keys_test.go @@ -90,7 +90,7 @@ var keysOperatorScenarios = []expressionScenario{ 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", + "D0, P[], (!!map)::a:\n meow: 3\n y: 4\n", }, }, { diff --git a/pkg/yqlib/operator_kind.go b/pkg/yqlib/operator_kind.go index da0892c7049..1f15a9cf59e 100644 --- a/pkg/yqlib/operator_kind.go +++ b/pkg/yqlib/operator_kind.go @@ -2,21 +2,17 @@ package yqlib import ( "container/list" - - yaml "gopkg.in/yaml.v3" ) -func kindToText(kind yaml.Kind) string { +func kindToText(kind Kind) string { switch kind { - case yaml.MappingNode: + case MappingNode: return "map" - case yaml.SequenceNode: + case SequenceNode: return "seq" - case yaml.DocumentNode: - return "doc" - case yaml.ScalarNode: + case ScalarNode: return "scalar" - case yaml.AliasNode: + case AliasNode: return "alias" default: return "unknown" @@ -30,8 +26,7 @@ func getKindOperator(d *dataTreeNavigator, context Context, expressionNode *Expr for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.ScalarNode, Value: kindToText(candidate.Node.Kind), Tag: "!!str"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement(ScalarNode, "!!str", kindToText(candidate.Kind)) results.PushBack(result) } diff --git a/pkg/yqlib/operator_length.go b/pkg/yqlib/operator_length.go index 46f1c8c8ac7..57c5377ee98 100644 --- a/pkg/yqlib/operator_length.go +++ b/pkg/yqlib/operator_length.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func lengthOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -13,25 +11,23 @@ func lengthOperator(d *dataTreeNavigator, context Context, expressionNode *Expre for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - targetNode := unwrapDoc(candidate.Node) var length int - switch targetNode.Kind { - case yaml.ScalarNode: - if targetNode.Tag == "!!null" { + switch candidate.Kind { + case ScalarNode: + if candidate.Tag == "!!null" { length = 0 } else { - length = len(targetNode.Value) + length = len(candidate.Value) } - case yaml.MappingNode: - length = len(targetNode.Content) / 2 - case yaml.SequenceNode: - length = len(targetNode.Content) + case MappingNode: + length = len(candidate.Content) / 2 + case SequenceNode: + length = len(candidate.Content) default: length = 0 } - node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", length), Tag: "!!int"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement(ScalarNode, "!!int", fmt.Sprintf("%v", length)) results.PushBack(result) } diff --git a/pkg/yqlib/operator_line.go b/pkg/yqlib/operator_line.go index 1535e059a00..cb19f2218e1 100644 --- a/pkg/yqlib/operator_line.go +++ b/pkg/yqlib/operator_line.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func lineOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -14,8 +12,7 @@ func lineOperator(d *dataTreeNavigator, context Context, expressionNode *Express for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", candidate.Node.Line), Tag: "!!int"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement(ScalarNode, "!!int", fmt.Sprintf("%v", candidate.Line)) results.PushBack(result) } diff --git a/pkg/yqlib/operator_load.go b/pkg/yqlib/operator_load.go index 678854f6660..8eeec3033b8 100644 --- a/pkg/yqlib/operator_load.go +++ b/pkg/yqlib/operator_load.go @@ -5,8 +5,6 @@ import ( "container/list" "fmt" "os" - - "gopkg.in/yaml.v3" ) var LoadYamlPreferences = YamlPreferences{ @@ -30,7 +28,7 @@ func loadString(filename string) (*CandidateNode, error) { return nil, err } - return &CandidateNode{Node: &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: string(filebytes)}}, nil + return &CandidateNode{Kind: ScalarNode, Tag: "!!str", Value: string(filebytes)}, nil } func loadYaml(filename string, decoder Decoder) (*CandidateNode, error) { @@ -51,15 +49,15 @@ func loadYaml(filename string, decoder Decoder) (*CandidateNode, error) { if documents.Len() == 0 { // return null candidate - return &CandidateNode{Node: &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!null"}}, nil + return &CandidateNode{Kind: ScalarNode, Tag: "!!null"}, nil } else if documents.Len() == 1 { candidate := documents.Front().Value.(*CandidateNode) return candidate, nil } else { - sequenceNode := &CandidateNode{Node: &yaml.Node{Kind: yaml.SequenceNode}} + sequenceNode := &CandidateNode{Kind: SequenceNode} for doc := documents.Front(); doc != nil; doc = doc.Next() { - sequenceNode.Node.Content = append(sequenceNode.Node.Content, unwrapDoc(doc.Value.(*CandidateNode).Node)) + sequenceNode.AddChild(doc.Value.(*CandidateNode)) } return sequenceNode, nil } @@ -83,11 +81,11 @@ func loadYamlOperator(d *dataTreeNavigator, context Context, expressionNode *Exp return Context{}, err } if rhs.MatchingNodes.Front() == nil { - return Context{}, fmt.Errorf("Filename expression returned nil") + return Context{}, fmt.Errorf("filename expression returned nil") } nameCandidateNode := rhs.MatchingNodes.Front().Value.(*CandidateNode) - filename := nameCandidateNode.Node.Value + filename := nameCandidateNode.Value var contentsCandidate *CandidateNode diff --git a/pkg/yqlib/operator_load_test.go b/pkg/yqlib/operator_load_test.go index 5bb30321fb3..2b1f96f6b9f 100644 --- a/pkg/yqlib/operator_load_test.go +++ b/pkg/yqlib/operator_load_test.go @@ -10,7 +10,7 @@ var loadScenarios = []expressionScenario{ description: "Load empty file with a comment", expression: `load("../../examples/empty.yaml")`, expected: []string{ - "D0, P[], (doc)::# comment\n\n", + "D0, P[], (!!null)::# comment\n", }, }, { @@ -19,7 +19,7 @@ var loadScenarios = []expressionScenario{ document: `- "../../examples/small.yaml"`, expression: `.[] |= load(.)`, expected: []string{ - "D0, P[], (doc)::- # comment\n # about things\n a: cat\n", + "D0, P[], (!!seq)::- # comment\n # about things\n a: cat\n", }, }, { @@ -43,7 +43,7 @@ var loadScenarios = []expressionScenario{ document: `{myFile: "../../examples/thing.yml"}`, expression: `load(.myFile)`, expected: []string{ - "D0, P[], (doc)::a: apple is included\nb: cool.\n", + "D0, P[], (!!map)::a: apple is included\nb: cool.\n", }, }, { @@ -52,7 +52,7 @@ var loadScenarios = []expressionScenario{ document: `{something: {file: "thing.yml"}}`, expression: `.something |= load("../../examples/" + .file)`, expected: []string{ - "D0, P[], (doc)::{something: {a: apple is included, b: cool.}}\n", + "D0, P[], (!!map)::{something: {a: apple is included, b: cool.}}\n", }, }, { @@ -70,7 +70,7 @@ var loadScenarios = []expressionScenario{ document: `{something: {file: "thing.yml"}}`, expression: `.something |= load_str("../../examples/" + .file)`, expected: []string{ - "D0, P[], (doc)::{something: \"a: apple is included\\nb: cool.\"}\n", + "D0, P[], (!!map)::{something: \"a: apple is included\\nb: cool.\"}\n", }, }, { @@ -79,7 +79,7 @@ var loadScenarios = []expressionScenario{ document: "cool: things", expression: `.more_stuff = load_xml("../../examples/small.xml")`, expected: []string{ - "D0, P[], (doc)::cool: things\nmore_stuff:\n this: is some xml\n", + "D0, P[], (!!map)::cool: things\nmore_stuff:\n this: is some xml\n", }, }, { @@ -87,7 +87,7 @@ var loadScenarios = []expressionScenario{ document: "cool: things", expression: `.more_stuff = load_props("../../examples/small.properties")`, expected: []string{ - "D0, P[], (doc)::cool: things\nmore_stuff:\n this:\n is: a properties file\n", + "D0, P[], (!!map)::cool: things\nmore_stuff:\n this:\n is: a properties file\n", }, }, { @@ -104,7 +104,7 @@ var loadScenarios = []expressionScenario{ document: "cool: things", expression: `.more_stuff = load_base64("../../examples/base64.txt")`, expected: []string{ - "D0, P[], (doc)::cool: things\nmore_stuff: my secret chilli recipe is....\n", + "D0, P[], (!!map)::cool: things\nmore_stuff: my secret chilli recipe is....\n", }, }, } diff --git a/pkg/yqlib/operator_map.go b/pkg/yqlib/operator_map.go index ec1a5ed086a..216d78ae66f 100644 --- a/pkg/yqlib/operator_map.go +++ b/pkg/yqlib/operator_map.go @@ -54,7 +54,7 @@ func mapOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi if err != nil { return Context{}, err } - collected.Node.Style = unwrapDoc(candidate.Node).Style + collected.Style = candidate.Style results.PushBack(collected) diff --git a/pkg/yqlib/operator_map_test.go b/pkg/yqlib/operator_map_test.go index 715df33688c..7ba25b3c9f8 100644 --- a/pkg/yqlib/operator_map_test.go +++ b/pkg/yqlib/operator_map_test.go @@ -29,8 +29,8 @@ var mapOperatorScenarios = []expressionScenario{ document2: `{x: 10, y: 20, z: 30}`, expression: `map_values(. + 1)`, expected: []string{ - "D0, P[], (doc)::{a: 2, b: 3, c: 4}\n", - "D0, P[], (doc)::{x: 11, y: 21, z: 31}\n", + "D0, P[], (!!map)::{a: 2, b: 3, c: 4}\n", + "D0, P[], (!!map)::{x: 11, y: 21, z: 31}\n", }, }, { @@ -38,7 +38,7 @@ var mapOperatorScenarios = []expressionScenario{ document: `{a: 1, b: 2, c: 3}`, expression: `map_values(. + 1)`, expected: []string{ - "D0, P[], (doc)::{a: 2, b: 3, c: 4}\n", + "D0, P[], (!!map)::{a: 2, b: 3, c: 4}\n", }, }, } diff --git a/pkg/yqlib/operator_modulo.go b/pkg/yqlib/operator_modulo.go index ecb9b406951..05d8f821491 100644 --- a/pkg/yqlib/operator_modulo.go +++ b/pkg/yqlib/operator_modulo.go @@ -5,8 +5,6 @@ import ( "math" "strconv" "strings" - - yaml "gopkg.in/yaml.v3" ) func moduloOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -16,40 +14,35 @@ func moduloOperator(d *dataTreeNavigator, context Context, expressionNode *Expre } func modulo(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - lhs.Node = unwrapDoc(lhs.Node) - rhs.Node = unwrapDoc(rhs.Node) - - lhsNode := lhs.Node - - if lhsNode.Tag == "!!null" { - return nil, fmt.Errorf("%v (%v) cannot modulo by %v (%v)", lhsNode.Tag, lhs.GetNicePath(), rhs.Node.Tag, rhs.GetNicePath()) + if lhs.Tag == "!!null" { + return nil, fmt.Errorf("%v (%v) cannot modulo by %v (%v)", lhs.Tag, lhs.GetNicePath(), rhs.Tag, rhs.GetNicePath()) } - target := &yaml.Node{} + target := lhs.CopyWithoutContent() - if lhsNode.Kind == yaml.ScalarNode && rhs.Node.Kind == yaml.ScalarNode { - if err := moduloScalars(target, lhsNode, rhs.Node); err != nil { + if lhs.Kind == ScalarNode && rhs.Kind == ScalarNode { + if err := moduloScalars(target, lhs, rhs); err != nil { return nil, err } } else { - return nil, fmt.Errorf("%v (%v) cannot modulo by %v (%v)", lhsNode.Tag, lhs.GetNicePath(), rhs.Node.Tag, rhs.GetNicePath()) + return nil, fmt.Errorf("%v (%v) cannot modulo by %v (%v)", lhs.Tag, lhs.GetNicePath(), rhs.Tag, rhs.GetNicePath()) } - return lhs.CreateReplacement(target), nil + return target, nil } -func moduloScalars(target *yaml.Node, lhs *yaml.Node, rhs *yaml.Node) error { +func moduloScalars(target *CandidateNode, lhs *CandidateNode, rhs *CandidateNode) error { lhsTag := lhs.Tag - rhsTag := guessTagFromCustomType(rhs) + rhsTag := rhs.guessTagFromCustomType() lhsIsCustom := false if !strings.HasPrefix(lhsTag, "!!") { // custom tag - we have to have a guess - lhsTag = guessTagFromCustomType(lhs) + lhsTag = lhs.guessTagFromCustomType() lhsIsCustom = true } if lhsTag == "!!int" && rhsTag == "!!int" { - target.Kind = yaml.ScalarNode + target.Kind = ScalarNode target.Style = lhs.Style format, lhsNum, err := parseInt64(lhs.Value) @@ -68,7 +61,7 @@ func moduloScalars(target *yaml.Node, lhs *yaml.Node, rhs *yaml.Node) error { target.Tag = lhs.Tag target.Value = fmt.Sprintf(format, remainder) } else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") { - target.Kind = yaml.ScalarNode + target.Kind = ScalarNode target.Style = lhs.Style lhsNum, err := strconv.ParseFloat(lhs.Value, 64) diff --git a/pkg/yqlib/operator_modulo_test.go b/pkg/yqlib/operator_modulo_test.go index ee1c9101b7c..246db23370a 100644 --- a/pkg/yqlib/operator_modulo_test.go +++ b/pkg/yqlib/operator_modulo_test.go @@ -19,7 +19,7 @@ var moduloOperatorScenarios = []expressionScenario{ document: `{}`, expression: "(.a / .b) as $x | .", expected: []string{ - "D0, P[], (doc)::{}\n", + "D0, P[], (!!map)::{}\n", }, }, { @@ -28,7 +28,7 @@ var moduloOperatorScenarios = []expressionScenario{ document: `{a: 13, b: 2}`, expression: `.a = .a % .b`, expected: []string{ - "D0, P[], (doc)::{a: 1, b: 2}\n", + "D0, P[], (!!map)::{a: 1, b: 2}\n", }, }, { @@ -37,7 +37,7 @@ var moduloOperatorScenarios = []expressionScenario{ document: `{a: 12, b: 2.5}`, expression: `.a = .a % .b`, expected: []string{ - "D0, P[], (doc)::{a: !!float 2, b: 2.5}\n", + "D0, P[], (!!map)::{a: !!float 2, b: 2.5}\n", }, }, { @@ -53,7 +53,7 @@ var moduloOperatorScenarios = []expressionScenario{ document: `{a: 1.1, b: 0}`, expression: `.a = .a % .b`, expected: []string{ - "D0, P[], (doc)::{a: !!float NaN, b: 0}\n", + "D0, P[], (!!map)::{a: !!float NaN, b: 0}\n", }, }, { @@ -62,7 +62,7 @@ var moduloOperatorScenarios = []expressionScenario{ document: "a: !horse 333.975\nb: !goat 299.2", expression: `.a = .a % .b`, expected: []string{ - "D0, P[], (doc)::a: !horse 34.775000000000034\nb: !goat 299.2\n", + "D0, P[], (!!map)::a: !horse 34.775000000000034\nb: !goat 299.2\n", }, }, { @@ -70,7 +70,7 @@ var moduloOperatorScenarios = []expressionScenario{ document: "a: 2\nb: !goat 2.3", expression: `.a = .a % .b`, expected: []string{ - "D0, P[], (doc)::a: !!float 2\nb: !goat 2.3\n", + "D0, P[], (!!map)::a: !!float 2\nb: !goat 2.3\n", }, }, { @@ -79,7 +79,7 @@ var moduloOperatorScenarios = []expressionScenario{ document: "a: &horse [1]", expression: `.a[1] = .a[0] % 2`, expected: []string{ - "D0, P[], (doc)::a: &horse [1, 1]\n", + "D0, P[], (!!map)::a: &horse [1, 1]\n", }, }, { diff --git a/pkg/yqlib/operator_multiply.go b/pkg/yqlib/operator_multiply.go index cf63801569a..06b2429ab12 100644 --- a/pkg/yqlib/operator_multiply.go +++ b/pkg/yqlib/operator_multiply.go @@ -5,9 +5,6 @@ import ( "fmt" "strconv" "strings" - - "github.com/jinzhu/copier" - yaml "gopkg.in/yaml.v3" ) type multiplyPreferences struct { @@ -38,16 +35,17 @@ func multiplyOperator(d *dataTreeNavigator, context Context, expressionNode *Exp func getComments(lhs *CandidateNode, rhs *CandidateNode) (leadingContent string, headComment string, footComment string) { leadingContent = rhs.LeadingContent - headComment = rhs.Node.HeadComment - footComment = rhs.Node.FootComment - if lhs.Node.HeadComment != "" || lhs.LeadingContent != "" { - headComment = lhs.Node.HeadComment + headComment = rhs.HeadComment + footComment = rhs.FootComment + if lhs.HeadComment != "" || lhs.LeadingContent != "" { + headComment = lhs.HeadComment leadingContent = lhs.LeadingContent } - if lhs.Node.FootComment != "" { - footComment = lhs.Node.FootComment + if lhs.FootComment != "" { + footComment = lhs.FootComment } + return leadingContent, headComment, footComment } @@ -55,41 +53,37 @@ func multiply(preferences multiplyPreferences) func(d *dataTreeNavigator, contex return func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { // need to do this before unWrapping the potential document node leadingContent, headComment, footComment := getComments(lhs, rhs) - lhs.Node = unwrapDoc(lhs.Node) - rhs.Node = unwrapDoc(rhs.Node) - log.Debugf("Multiplying LHS: %v", lhs.Node.Tag) - log.Debugf("- RHS: %v", rhs.Node.Tag) + log.Debugf("Multiplying LHS: %v", NodeToString(lhs)) + log.Debugf("- RHS: %v", NodeToString(rhs)) - if rhs.Node.Tag == "!!null" { - return lhs.Copy() + if rhs.Tag == "!!null" { + return lhs.Copy(), nil } - if (lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode) || - (lhs.Node.Tag == "!!null" && rhs.Node.Kind == yaml.MappingNode) || - (lhs.Node.Kind == yaml.SequenceNode && rhs.Node.Kind == yaml.SequenceNode) || - (lhs.Node.Tag == "!!null" && rhs.Node.Kind == yaml.SequenceNode) { - var newBlank = CandidateNode{} - err := copier.CopyWithOption(&newBlank, lhs, copier.Option{IgnoreEmpty: true, DeepCopy: true}) - if err != nil { - return nil, err - } + if (lhs.Kind == MappingNode && rhs.Kind == MappingNode) || + (lhs.Tag == "!!null" && rhs.Kind == MappingNode) || + (lhs.Kind == SequenceNode && rhs.Kind == SequenceNode) || + (lhs.Tag == "!!null" && rhs.Kind == SequenceNode) { + + var newBlank = lhs.Copy() + newBlank.LeadingContent = leadingContent - newBlank.Node.HeadComment = headComment - newBlank.Node.FootComment = footComment + newBlank.HeadComment = headComment + newBlank.FootComment = footComment - return mergeObjects(d, context.WritableClone(), &newBlank, rhs, preferences) + return mergeObjects(d, context.WritableClone(), newBlank, rhs, preferences) } return multiplyScalars(lhs, rhs) } } func multiplyScalars(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - lhsTag := lhs.Node.Tag - rhsTag := guessTagFromCustomType(rhs.Node) + lhsTag := lhs.Tag + rhsTag := rhs.guessTagFromCustomType() lhsIsCustom := false if !strings.HasPrefix(lhsTag, "!!") { // custom tag - we have to have a guess - lhsTag = guessTagFromCustomType(lhs.Node) + lhsTag = lhs.guessTagFromCustomType() lhsIsCustom = true } @@ -98,46 +92,46 @@ func multiplyScalars(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, er } else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") { return multiplyFloats(lhs, rhs, lhsIsCustom) } - return nil, fmt.Errorf("Cannot multiply %v with %v", lhs.Node.Tag, rhs.Node.Tag) + return nil, fmt.Errorf("cannot multiply %v with %v", lhs.Tag, rhs.Tag) } func multiplyFloats(lhs *CandidateNode, rhs *CandidateNode, lhsIsCustom bool) (*CandidateNode, error) { - target := lhs.CreateReplacement(&yaml.Node{}) - target.Node.Kind = yaml.ScalarNode - target.Node.Style = lhs.Node.Style + target := lhs.CopyWithoutContent() + target.Kind = ScalarNode + target.Style = lhs.Style if lhsIsCustom { - target.Node.Tag = lhs.Node.Tag + target.Tag = lhs.Tag } else { - target.Node.Tag = "!!float" + target.Tag = "!!float" } - lhsNum, err := strconv.ParseFloat(lhs.Node.Value, 64) + lhsNum, err := strconv.ParseFloat(lhs.Value, 64) if err != nil { return nil, err } - rhsNum, err := strconv.ParseFloat(rhs.Node.Value, 64) + rhsNum, err := strconv.ParseFloat(rhs.Value, 64) if err != nil { return nil, err } - target.Node.Value = fmt.Sprintf("%v", lhsNum*rhsNum) + target.Value = fmt.Sprintf("%v", lhsNum*rhsNum) return target, nil } func multiplyIntegers(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - target := lhs.CreateReplacement(&yaml.Node{}) - target.Node.Kind = yaml.ScalarNode - target.Node.Style = lhs.Node.Style - target.Node.Tag = lhs.Node.Tag + target := lhs.CopyWithoutContent() + target.Kind = ScalarNode + target.Style = lhs.Style + target.Tag = lhs.Tag - format, lhsNum, err := parseInt64(lhs.Node.Value) + format, lhsNum, err := parseInt64(lhs.Value) if err != nil { return nil, err } - _, rhsNum, err := parseInt64(rhs.Node.Value) + _, rhsNum, err := parseInt64(rhs.Value) if err != nil { return nil, err } - target.Node.Value = fmt.Sprintf(format, lhsNum*rhsNum) + target.Value = fmt.Sprintf(format, lhsNum*rhsNum) return target, nil } @@ -156,12 +150,16 @@ func mergeObjects(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs var pathIndexToStartFrom int if results.Front() != nil { - pathIndexToStartFrom = len(results.Front().Value.(*CandidateNode).Path) + pathIndexToStartFrom = len(results.Front().Value.(*CandidateNode).GetPath()) + log.Debugf("pathIndexToStartFrom: %v", pathIndexToStartFrom) } for el := results.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - if candidate.Node.Tag == "!!merge" { + + log.Debugf("*** going to applied assignment to LHS: %v with RHS: %v", NodeToString(lhs), NodeToString(candidate)) + + if candidate.Tag == "!!merge" { continue } @@ -169,28 +167,29 @@ func mergeObjects(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs if err != nil { return nil, err } + + log.Debugf("*** applied assignment to LHS: %v", NodeToString(lhs)) } return lhs, nil } func applyAssignment(d *dataTreeNavigator, context Context, pathIndexToStartFrom int, lhs *CandidateNode, rhs *CandidateNode, preferences multiplyPreferences) error { shouldAppendArrays := preferences.AppendArrays - log.Debugf("merge - applyAssignment lhs %v, rhs: %v", lhs.GetKey(), rhs.GetKey()) - lhsPath := rhs.Path[pathIndexToStartFrom:] + lhsPath := rhs.GetPath()[pathIndexToStartFrom:] log.Debugf("merge - lhsPath %v", lhsPath) assignmentOp := &Operation{OperationType: assignAttributesOpType, Preferences: preferences.AssignPrefs} - if shouldAppendArrays && rhs.Node.Kind == yaml.SequenceNode { + if shouldAppendArrays && rhs.Kind == SequenceNode { assignmentOp.OperationType = addAssignOpType log.Debugf("merge - assignmentOp.OperationType = addAssignOpType") - } else if !preferences.DeepMergeArrays && rhs.Node.Kind == yaml.SequenceNode || - (rhs.Node.Kind == yaml.ScalarNode || rhs.Node.Kind == yaml.AliasNode) { + } else if !preferences.DeepMergeArrays && rhs.Kind == SequenceNode || + (rhs.Kind == ScalarNode || rhs.Kind == AliasNode) { assignmentOp.OperationType = assignOpType assignmentOp.UpdateAssign = false - log.Debugf("merge - rhs.Node.Kind == yaml.SequenceNode: %v", rhs.Node.Kind == yaml.SequenceNode) - log.Debugf("merge - rhs.Node.Kind == yaml.ScalarNode: %v", rhs.Node.Kind == yaml.ScalarNode) - log.Debugf("merge - rhs.Node.Kind == yaml.AliasNode: %v", rhs.Node.Kind == yaml.AliasNode) + log.Debugf("merge - rhs.Kind == SequenceNode: %v", rhs.Kind == SequenceNode) + log.Debugf("merge - rhs.Kind == ScalarNode: %v", rhs.Kind == ScalarNode) + log.Debugf("merge - rhs.Kind == AliasNode: %v", rhs.Kind == AliasNode) log.Debugf("merge - assignmentOp.OperationType = assignOpType, no updateassign") } else { log.Debugf("merge - assignmentOp := &Operation{OperationType: assignAttributesOpType}") diff --git a/pkg/yqlib/operator_multiply_test.go b/pkg/yqlib/operator_multiply_test.go index 0844c7c7c24..c099ddb0291 100644 --- a/pkg/yqlib/operator_multiply_test.go +++ b/pkg/yqlib/operator_multiply_test.go @@ -171,7 +171,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: 3\nb: 4", expression: `.a *= .b`, expected: []string{ - "D0, P[], (doc)::a: 12\nb: 4\n", + "D0, P[], (!!map)::a: 12\nb: 4\n", }, }, { @@ -435,7 +435,7 @@ var multiplyOperatorScenarios = []expressionScenario{ environmentVariables: map[string]string{"originalPath": ".myArray", "otherPath": ".newArray", "idPath": ".a"}, expression: mergeExpression, expected: []string{ - "D0, P[], (doc)::{myArray: [{a: apple, b: appleB2}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB, c: bananaC}, {a: dingo, c: dingoC}], something: else}\n", + "D0, P[], (!!map)::{myArray: [{a: apple, b: appleB2}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB, c: bananaC}, {a: dingo, c: dingoC}], something: else}\n", }, }, { @@ -484,7 +484,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: !horse 2\nb: !goat 3", expression: ".a = .a * .b", expected: []string{ - "D0, P[], (doc)::a: !horse 6\nb: !goat 3\n", + "D0, P[], (!!map)::a: !horse 6\nb: !goat 3\n", }, }, { @@ -493,7 +493,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: !horse 2.5\nb: !goat 3.5", expression: ".a = .a * .b", expected: []string{ - "D0, P[], (doc)::a: !horse 8.75\nb: !goat 3.5\n", + "D0, P[], (!!map)::a: !horse 8.75\nb: !goat 3.5\n", }, }, { @@ -502,7 +502,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: 2\nb: !goat 3.5", expression: ".a = .a * .b", expected: []string{ - "D0, P[], (doc)::a: !!float 7\nb: !goat 3.5\n", + "D0, P[], (!!map)::a: !!float 7\nb: !goat 3.5\n", }, }, { @@ -511,7 +511,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: !horse [1,2]\nb: !goat [3]", expression: ".a = .a * .b", expected: []string{ - "D0, P[], (doc)::a: !horse [3]\nb: !goat [3]\n", + "D0, P[], (!!map)::a: !horse [3]\nb: !goat [3]\n", }, }, { @@ -520,7 +520,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: !horse {cat: meow}\nb: !goat {dog: woof}", expression: ".a = .a * .b", expected: []string{ - "D0, P[], (doc)::a: !horse {cat: meow, dog: woof}\nb: !goat {dog: woof}\n", + "D0, P[], (!!map)::a: !horse {cat: meow, dog: woof}\nb: !goat {dog: woof}\n", }, }, { @@ -529,7 +529,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: !horse {cat: meow}\nb: !goat {dog: woof}", expression: ".a *=c .b", expected: []string{ - "D0, P[], (doc)::a: !goat {cat: meow, dog: woof}\nb: !goat {dog: woof}\n", + "D0, P[], (!!map)::a: !goat {cat: meow, dog: woof}\nb: !goat {dog: woof}\n", }, }, { @@ -539,7 +539,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: !horse {cat: meow}\nb: !goat {dog: woof}", expression: ".a =c .a *c .b", expected: []string{ - "D0, P[], (doc)::a: !goat {cat: meow, dog: woof}\nb: !goat {dog: woof}\n", + "D0, P[], (!!map)::a: !goat {cat: meow, dog: woof}\nb: !goat {dog: woof}\n", }, }, { @@ -549,7 +549,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: !horse {cat: meow}\nb: !goat {dog: woof}", expression: ".a *= .b", expected: []string{ - "D0, P[], (doc)::a: !horse {cat: meow, dog: woof}\nb: !goat {dog: woof}\n", + "D0, P[], (!!map)::a: !horse {cat: meow, dog: woof}\nb: !goat {dog: woof}\n", }, }, { @@ -558,7 +558,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: {cat: !horse meow}\nb: {cat: 5}", expression: ".a = .a * .b", expected: []string{ - "D0, P[], (doc)::a: {cat: !horse 5}\nb: {cat: 5}\n", + "D0, P[], (!!map)::a: {cat: !horse 5}\nb: {cat: 5}\n", }, }, { @@ -567,7 +567,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: {a: original}\n", expression: `.a *=n load("../../examples/thing.yml")`, expected: []string{ - "D0, P[], (doc)::a: {a: original, b: cool.}\n", + "D0, P[], (!!map)::a: {a: original, b: cool.}\n", }, }, { @@ -576,7 +576,7 @@ var multiplyOperatorScenarios = []expressionScenario{ document: "a: {a: original}\n", expression: `.a *= load("../../examples/thing.yml")`, expected: []string{ - "D0, P[], (doc)::a: {a: apple is included, b: cool.}\n", + "D0, P[], (!!map)::a: {a: apple is included, b: cool.}\n", }, }, { diff --git a/pkg/yqlib/operator_path.go b/pkg/yqlib/operator_path.go index cdad7f1b317..88a97fee5cd 100644 --- a/pkg/yqlib/operator_path.go +++ b/pkg/yqlib/operator_path.go @@ -3,21 +3,19 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) -func createPathNodeFor(pathElement interface{}) *yaml.Node { +func createPathNodeFor(pathElement interface{}) *CandidateNode { switch pathElement := pathElement.(type) { case string: - return &yaml.Node{Kind: yaml.ScalarNode, Value: pathElement, Tag: "!!str"} + return &CandidateNode{Kind: ScalarNode, Value: pathElement, Tag: "!!str"} default: - return &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", pathElement), Tag: "!!int"} + return &CandidateNode{Kind: ScalarNode, Value: fmt.Sprintf("%v", pathElement), Tag: "!!int"} } } -func getPathArrayFromNode(funcName string, node *yaml.Node) ([]interface{}, error) { - if node.Kind != yaml.SequenceNode { +func getPathArrayFromNode(funcName string, node *CandidateNode) ([]interface{}, error) { + if node.Kind != SequenceNode { return nil, fmt.Errorf("%v: expected path array, but got %v instead", funcName, node.Tag) } @@ -59,7 +57,7 @@ func setPathOperator(d *dataTreeNavigator, context Context, expressionNode *Expr } lhsValue := lhsPathContext.MatchingNodes.Front().Value.(*CandidateNode) - lhsPath, err := getPathArrayFromNode("SETPATH", lhsValue.Node) + lhsPath, err := getPathArrayFromNode("SETPATH", lhsValue) if err != nil { return Context{}, err @@ -110,7 +108,7 @@ func delPathsOperator(d *dataTreeNavigator, context Context, expressionNode *Exp if pathArraysContext.MatchingNodes.Len() != 1 { return Context{}, fmt.Errorf("DELPATHS: expected single value but found %v", pathArraysContext.MatchingNodes.Len()) } - pathArraysNode := pathArraysContext.MatchingNodes.Front().Value.(*CandidateNode).Node + pathArraysNode := pathArraysContext.MatchingNodes.Front().Value.(*CandidateNode) if pathArraysNode.Tag != "!!seq" { return Context{}, fmt.Errorf("DELPATHS: expected a sequence of sequences, but found %v", pathArraysNode.Tag) @@ -156,16 +154,17 @@ func getPathOperator(d *dataTreeNavigator, context Context, expressionNode *Expr for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} + node := candidate.CreateReplacement(SequenceNode, "!!seq", "") + + path := candidate.GetPath() - content := make([]*yaml.Node, len(candidate.Path)) - for pathIndex := 0; pathIndex < len(candidate.Path); pathIndex++ { - path := candidate.Path[pathIndex] + content := make([]*CandidateNode, len(path)) + for pathIndex := 0; pathIndex < len(path); pathIndex++ { + path := path[pathIndex] content[pathIndex] = createPathNodeFor(path) } - node.Content = content - result := candidate.CreateReplacement(node) - results.PushBack(result) + node.AddChildren(content) + results.PushBack(node) } return context.ChildContext(results), nil diff --git a/pkg/yqlib/operator_path_test.go b/pkg/yqlib/operator_path_test.go index 225d9ac4fa3..bb575aac66d 100644 --- a/pkg/yqlib/operator_path_test.go +++ b/pkg/yqlib/operator_path_test.go @@ -45,7 +45,7 @@ var pathOperatorScenarios = []expressionScenario{ document: `{a: {b: cat}}`, expression: `.a.b | path | .[-1]`, expected: []string{ - "D0, P[a b -1], (!!str)::b\n", + "D0, P[a b 1], (!!str)::b\n", }, }, { @@ -61,7 +61,7 @@ var pathOperatorScenarios = []expressionScenario{ document: `{a: [cat, dog]}`, expression: `.a.[] | select(. == "dog") | path | .[-1]`, expected: []string{ - "D0, P[a 1 -1], (!!int)::1\n", + "D0, P[a 1 1], (!!int)::1\n", }, }, { @@ -78,7 +78,7 @@ var pathOperatorScenarios = []expressionScenario{ document: `{a: {b: cat}}`, expression: `setpath(["a", "b"]; "things")`, expected: []string{ - "D0, P[], (doc)::{a: {b: things}}\n", + "D0, P[], (!!map)::{a: {b: things}}\n", }, }, { @@ -102,7 +102,7 @@ var pathOperatorScenarios = []expressionScenario{ document: `a: [cat, frog]`, expression: `setpath(["a", 0]; "things")`, expected: []string{ - "D0, P[], (doc)::a: [things, frog]\n", + "D0, P[], (!!map)::a: [things, frog]\n", }, }, { @@ -118,7 +118,7 @@ var pathOperatorScenarios = []expressionScenario{ document: `{a: {b: cat, c: dog, d: frog}}`, expression: `delpaths([["a", "c"], ["a", "d"]])`, expected: []string{ - "D0, P[], (doc)::{a: {b: cat}}\n", + "D0, P[], (!!map)::{a: {b: cat}}\n", }, }, { @@ -126,7 +126,7 @@ var pathOperatorScenarios = []expressionScenario{ document: `a: [cat, frog]`, expression: `delpaths([["a", 0]])`, expected: []string{ - "D0, P[], (doc)::a: [frog]\n", + "D0, P[], (!!map)::a: [frog]\n", }, }, { diff --git a/pkg/yqlib/operator_pick.go b/pkg/yqlib/operator_pick.go index 5a6f7d2c1da..2e223ea0e64 100644 --- a/pkg/yqlib/operator_pick.go +++ b/pkg/yqlib/operator_pick.go @@ -3,33 +3,31 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) -func pickMap(original *yaml.Node, indices *yaml.Node) *yaml.Node { +func pickMap(original *CandidateNode, indices *CandidateNode) *CandidateNode { - filteredContent := make([]*yaml.Node, 0) + filteredContent := make([]*CandidateNode, 0) for index := 0; index < len(indices.Content); index = index + 1 { keyToFind := indices.Content[index] indexInMap := findKeyInMap(original, keyToFind) if indexInMap > -1 { - clonedKey := deepClone(original.Content[indexInMap]) - clonedValue := deepClone(original.Content[indexInMap+1]) + clonedKey := original.Content[indexInMap].Copy() + clonedValue := original.Content[indexInMap+1].Copy() filteredContent = append(filteredContent, clonedKey, clonedValue) } } - newNode := deepCloneNoContent(original) - newNode.Content = filteredContent + newNode := original.CopyWithoutContent() + newNode.AddChildren(filteredContent) return newNode } -func pickSequence(original *yaml.Node, indices *yaml.Node) (*yaml.Node, error) { +func pickSequence(original *CandidateNode, indices *CandidateNode) (*CandidateNode, error) { - filteredContent := make([]*yaml.Node, 0) + filteredContent := make([]*CandidateNode, 0) for index := 0; index < len(indices.Content); index = index + 1 { indexInArray, err := parseInt(indices.Content[index].Value) if err != nil { @@ -37,12 +35,12 @@ func pickSequence(original *yaml.Node, indices *yaml.Node) (*yaml.Node, error) { } if indexInArray > -1 && indexInArray < len(original.Content) { - filteredContent = append(filteredContent, deepClone(original.Content[indexInArray])) + filteredContent = append(filteredContent, original.Content[indexInArray].Copy()) } } - newNode := deepCloneNoContent(original) - newNode.Content = filteredContent + newNode := original.CopyWithoutContent() + newNode.AddChildren(filteredContent) return newNode, nil } @@ -55,31 +53,31 @@ func pickOperator(d *dataTreeNavigator, context Context, expressionNode *Express if err != nil { return Context{}, err } - indicesToPick := &yaml.Node{} + indicesToPick := &CandidateNode{} if contextIndicesToPick.MatchingNodes.Len() > 0 { - indicesToPick = contextIndicesToPick.MatchingNodes.Front().Value.(*CandidateNode).Node + indicesToPick = contextIndicesToPick.MatchingNodes.Front().Value.(*CandidateNode) } var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) + node := el.Value.(*CandidateNode) - var replacement *yaml.Node - if node.Kind == yaml.MappingNode { + var replacement *CandidateNode + if node.Kind == MappingNode { replacement = pickMap(node, indicesToPick) - } else if node.Kind == yaml.SequenceNode { + } else if node.Kind == SequenceNode { replacement, err = pickSequence(node, indicesToPick) if err != nil { return Context{}, err } } else { - return Context{}, fmt.Errorf("cannot pick indices from type %v (%v)", node.Tag, candidate.GetNicePath()) + return Context{}, fmt.Errorf("cannot pick indices from type %v (%v)", node.Tag, node.GetNicePath()) } - results.PushBack(candidate.CreateReplacementWithDocWrappers(replacement)) + replacement.LeadingContent = node.LeadingContent + results.PushBack(replacement) } return context.ChildContext(results), nil diff --git a/pkg/yqlib/operator_pick_test.go b/pkg/yqlib/operator_pick_test.go index fe92f3addc2..44565602cde 100644 --- a/pkg/yqlib/operator_pick_test.go +++ b/pkg/yqlib/operator_pick_test.go @@ -11,7 +11,7 @@ var pickOperatorScenarios = []expressionScenario{ document: "myMap: {cat: meow, dog: bark, thing: hamster, hamster: squeak}\n", expression: `.myMap |= pick(["hamster", "cat", "goat"])`, expected: []string{ - "D0, P[], (doc)::myMap: {hamster: squeak, cat: meow}\n", + "D0, P[], (!!map)::myMap: {hamster: squeak, cat: meow}\n", }, }, { @@ -20,7 +20,7 @@ var pickOperatorScenarios = []expressionScenario{ document: "!things myMap: {cat: meow, dog: bark, thing: hamster, hamster: squeak}\n", expression: `.myMap |= pick(["hamster", "cat", "goat"])`, expected: []string{ - "D0, P[], (doc)::!things myMap: {hamster: squeak, cat: meow}\n", + "D0, P[], (!!map)::!things myMap: {hamster: squeak, cat: meow}\n", }, }, { @@ -29,7 +29,7 @@ var pickOperatorScenarios = []expressionScenario{ document: "# abc\nmyMap: {cat: meow, dog: bark, thing: hamster, hamster: squeak}\n# xyz\n", expression: `.myMap |= pick(["hamster", "cat", "goat"])`, expected: []string{ - "D0, P[], (doc)::# abc\nmyMap: {hamster: squeak, cat: meow}\n# xyz\n", + "D0, P[], (!!map)::# abc\nmyMap: {hamster: squeak, cat: meow}\n# xyz\n", }, }, { diff --git a/pkg/yqlib/operator_pipe_test.go b/pkg/yqlib/operator_pipe_test.go index 8d884689820..6196d658f4d 100644 --- a/pkg/yqlib/operator_pipe_test.go +++ b/pkg/yqlib/operator_pipe_test.go @@ -18,7 +18,7 @@ var pipeOperatorScenarios = []expressionScenario{ document: `{a: cow, b: sheep, c: same}`, expression: `.a = "cat" | .b = "dog"`, expected: []string{ - "D0, P[], (doc)::{a: cat, b: dog, c: same}\n", + "D0, P[], (!!map)::{a: cat, b: dog, c: same}\n", }, }, { diff --git a/pkg/yqlib/operator_recursive_descent.go b/pkg/yqlib/operator_recursive_descent.go index bb583840ed6..775bd2a6e9b 100644 --- a/pkg/yqlib/operator_recursive_descent.go +++ b/pkg/yqlib/operator_recursive_descent.go @@ -2,8 +2,6 @@ package yqlib import ( "container/list" - - yaml "gopkg.in/yaml.v3" ) type recursiveDescentPreferences struct { @@ -27,13 +25,11 @@ func recursiveDecent(results *list.List, context Context, preferences recursiveD for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidate.Node = unwrapDoc(candidate.Node) - log.Debugf("Recursive Decent, added %v", NodeToString(candidate)) results.PushBack(candidate) - if candidate.Node.Kind != yaml.AliasNode && len(candidate.Node.Content) > 0 && - (preferences.RecurseArray || candidate.Node.Kind != yaml.SequenceNode) { + if candidate.Kind != AliasNode && len(candidate.Content) > 0 && + (preferences.RecurseArray || candidate.Kind != SequenceNode) { children, err := splat(context.SingleChildContext(candidate), preferences.TraversePreferences) diff --git a/pkg/yqlib/operator_reverse.go b/pkg/yqlib/operator_reverse.go index 1693308f746..ef2e0a456ed 100644 --- a/pkg/yqlib/operator_reverse.go +++ b/pkg/yqlib/operator_reverse.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func reverseOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -13,19 +11,18 @@ func reverseOperator(d *dataTreeNavigator, context Context, expressionNode *Expr for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidateNode := unwrapDoc(candidate.Node) - - if candidateNode.Kind != yaml.SequenceNode { - return context, fmt.Errorf("node at path [%v] is not an array (it's a %v)", candidate.GetNicePath(), candidate.GetNiceTag()) + if candidate.Kind != SequenceNode { + return context, fmt.Errorf("node at path [%v] is not an array (it's a %v)", candidate.GetNicePath(), candidate.Tag) } - reverseList := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq", Style: candidateNode.Style} - reverseList.Content = make([]*yaml.Node, len(candidateNode.Content)) + reverseList := candidate.CreateReplacementWithComments(SequenceNode, "!!seq", candidate.Style) + reverseContent := make([]*CandidateNode, len(candidate.Content)) - for i, originalNode := range candidateNode.Content { - reverseList.Content[len(candidateNode.Content)-i-1] = originalNode + for i, originalNode := range candidate.Content { + reverseContent[len(candidate.Content)-i-1] = originalNode } - results.PushBack(candidate.CreateReplacementWithDocWrappers(reverseList)) + reverseList.AddChildren(reverseContent) + results.PushBack(reverseList) } diff --git a/pkg/yqlib/operator_select.go b/pkg/yqlib/operator_select.go index 57b9e2cee44..7cdb64b6380 100644 --- a/pkg/yqlib/operator_select.go +++ b/pkg/yqlib/operator_select.go @@ -18,16 +18,11 @@ func selectOperator(d *dataTreeNavigator, context Context, expressionNode *Expre } // find any truthy node - var errDecoding error includeResult := false for resultEl := rhs.MatchingNodes.Front(); resultEl != nil; resultEl = resultEl.Next() { result := resultEl.Value.(*CandidateNode) - includeResult, errDecoding = isTruthy(result) - log.Debugf("isTruthy %v", includeResult) - if errDecoding != nil { - return Context{}, errDecoding - } + includeResult = isTruthyNode(result) if includeResult { break } diff --git a/pkg/yqlib/operator_select_test.go b/pkg/yqlib/operator_select_test.go index 02357c2ef23..249e54b488d 100644 --- a/pkg/yqlib/operator_select_test.go +++ b/pkg/yqlib/operator_select_test.go @@ -10,7 +10,7 @@ var selectOperatorScenarios = []expressionScenario{ document: `cat`, expression: `select(false, true)`, expected: []string{ - "D0, P[], (doc)::cat\n", + "D0, P[], (!!str)::cat\n", }, }, { @@ -18,7 +18,7 @@ var selectOperatorScenarios = []expressionScenario{ document: `cat`, expression: `select(true, false)`, expected: []string{ - "D0, P[], (doc)::cat\n", + "D0, P[], (!!str)::cat\n", }, }, { @@ -71,8 +71,8 @@ var selectOperatorScenarios = []expressionScenario{ document2: "b: world", expression: `select(.a == "hello" or .b == "world")`, expected: []string{ - "D0, P[], (doc)::a: hello\n", - "D0, P[], (doc)::b: world\n", + "D0, P[], (!!map)::a: hello\n", + "D0, P[], (!!map)::b: world\n", }, }, { @@ -81,7 +81,7 @@ var selectOperatorScenarios = []expressionScenario{ document: `[{animal: cat, legs: {cool: true}}, {animal: fish}]`, expression: `(.[] | select(.legs.cool == true).canWalk) = true | (.[] | .alive.things) = "yes"`, expected: []string{ - "D0, P[], (doc)::[{animal: cat, legs: {cool: true}, canWalk: true, alive: {things: yes}}, {animal: fish, alive: {things: yes}}]\n", + "D0, P[], (!!seq)::[{animal: cat, legs: {cool: true}, canWalk: true, alive: {things: yes}}, {animal: fish, alive: {things: yes}}]\n", }, }, { @@ -121,7 +121,7 @@ var selectOperatorScenarios = []expressionScenario{ document: `a: { things: cat, bob: goat, horse: dog }`, expression: `(.a.[] | select(. == "cat" or . == "goat")) |= "rabbit"`, expected: []string{ - "D0, P[], (doc)::a: {things: rabbit, bob: rabbit, horse: dog}\n", + "D0, P[], (!!map)::a: {things: rabbit, bob: rabbit, horse: dog}\n", }, }, { diff --git a/pkg/yqlib/operator_shuffle.go b/pkg/yqlib/operator_shuffle.go index 73a76965dc2..15308728cc4 100644 --- a/pkg/yqlib/operator_shuffle.go +++ b/pkg/yqlib/operator_shuffle.go @@ -4,8 +4,6 @@ import ( "container/list" "fmt" "math/rand" - - yaml "gopkg.in/yaml.v3" ) func shuffleOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -20,18 +18,17 @@ func shuffleOperator(d *dataTreeNavigator, context Context, expressionNode *Expr for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidateNode := unwrapDoc(candidate.Node) - - if candidateNode.Kind != yaml.SequenceNode { - return context, fmt.Errorf("node at path [%v] is not an array (it's a %v)", candidate.GetNicePath(), candidate.GetNiceTag()) + if candidate.Kind != SequenceNode { + return context, fmt.Errorf("node at path [%v] is not an array (it's a %v)", candidate.GetNicePath(), candidate.Tag) } - result := deepClone(candidateNode) + result := candidate.Copy() a := result.Content myRand.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] }) - results.PushBack(candidate.CreateReplacement(result)) + + results.PushBack(result) } return context.ChildContext(results), nil } diff --git a/pkg/yqlib/operator_shuffle_test.go b/pkg/yqlib/operator_shuffle_test.go index 23a3748b6cd..c6c30f5f87d 100644 --- a/pkg/yqlib/operator_shuffle_test.go +++ b/pkg/yqlib/operator_shuffle_test.go @@ -17,7 +17,7 @@ var shuffleOperatorScenarios = []expressionScenario{ document: "cool: [1, 2, 3, 4, 5]", expression: `.cool |= shuffle`, expected: []string{ - "D0, P[], (doc)::cool: [5, 2, 4, 1, 3]\n", + "D0, P[], (!!map)::cool: [5, 2, 4, 1, 3]\n", }, }, } diff --git a/pkg/yqlib/operator_slice.go b/pkg/yqlib/operator_slice.go index e496cf9310f..e4c3906c1d3 100644 --- a/pkg/yqlib/operator_slice.go +++ b/pkg/yqlib/operator_slice.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func getSliceNumber(d *dataTreeNavigator, context Context, node *CandidateNode, expressionNode *ExpressionNode) (int, error) { @@ -15,7 +13,7 @@ func getSliceNumber(d *dataTreeNavigator, context Context, node *CandidateNode, if result.MatchingNodes.Len() != 1 { return 0, fmt.Errorf("expected to find 1 number, got %v instead", result.MatchingNodes.Len()) } - return parseInt(result.MatchingNodes.Front().Value.(*CandidateNode).Node.Value) + return parseInt(result.MatchingNodes.Front().Value.(*CandidateNode).Value) } func sliceArrayOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -28,7 +26,6 @@ func sliceArrayOperator(d *dataTreeNavigator, context Context, expressionNode *E for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { lhsNode := el.Value.(*CandidateNode) - original := unwrapDoc(lhsNode.Node) firstNumber, err := getSliceNumber(d, context, lhsNode, expressionNode.LHS) @@ -37,7 +34,7 @@ func sliceArrayOperator(d *dataTreeNavigator, context Context, expressionNode *E } relativeFirstNumber := firstNumber if relativeFirstNumber < 0 { - relativeFirstNumber = len(original.Content) + firstNumber + relativeFirstNumber = len(lhsNode.Content) + firstNumber } secondNumber, err := getSliceNumber(d, context, lhsNode, expressionNode.RHS) @@ -47,24 +44,21 @@ func sliceArrayOperator(d *dataTreeNavigator, context Context, expressionNode *E relativeSecondNumber := secondNumber if relativeSecondNumber < 0 { - relativeSecondNumber = len(original.Content) + secondNumber - } else if relativeSecondNumber > len(original.Content) { - relativeSecondNumber = len(original.Content) + relativeSecondNumber = len(lhsNode.Content) + secondNumber + } else if relativeSecondNumber > len(lhsNode.Content) { + relativeSecondNumber = len(lhsNode.Content) } log.Debug("calculateIndicesToTraverse: slice from %v to %v", relativeFirstNumber, relativeSecondNumber) - var newResults []*yaml.Node + var newResults []*CandidateNode for i := relativeFirstNumber; i < relativeSecondNumber; i++ { - newResults = append(newResults, original.Content[i]) + newResults = append(newResults, lhsNode.Content[i]) } - slicedArrayNode := &yaml.Node{ - Kind: yaml.SequenceNode, - Tag: original.Tag, - Content: newResults, - } - results.PushBack(lhsNode.CreateReplacement(slicedArrayNode)) + sliceArrayNode := lhsNode.CreateReplacement(SequenceNode, lhsNode.Tag, "") + sliceArrayNode.AddChildren(newResults) + results.PushBack(sliceArrayNode) } diff --git a/pkg/yqlib/operator_sort.go b/pkg/yqlib/operator_sort.go index 01070f2d024..106b17ff490 100644 --- a/pkg/yqlib/operator_sort.go +++ b/pkg/yqlib/operator_sort.go @@ -7,8 +7,6 @@ import ( "strconv" "strings" "time" - - yaml "gopkg.in/yaml.v3" ) func sortOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -26,18 +24,15 @@ func sortByOperator(d *dataTreeNavigator, context Context, expressionNode *Expre for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidateNode := unwrapDoc(candidate.Node) - - if candidateNode.Kind != yaml.SequenceNode { - return context, fmt.Errorf("node at path [%v] is not an array (it's a %v)", candidate.GetNicePath(), candidate.GetNiceTag()) + if candidate.Kind != SequenceNode { + return context, fmt.Errorf("node at path [%v] is not an array (it's a %v)", candidate.GetNicePath(), candidate.Tag) } - sortableArray := make(sortableNodeArray, len(candidateNode.Content)) + sortableArray := make(sortableNodeArray, len(candidate.Content)) - for i, originalNode := range candidateNode.Content { + for i, originalNode := range candidate.Content { - childCandidate := candidate.CreateChildInArray(i, originalNode) - compareContext, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(childCandidate), expressionNode.RHS) + compareContext, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(originalNode), expressionNode.RHS) if err != nil { return Context{}, err } @@ -48,19 +43,18 @@ func sortByOperator(d *dataTreeNavigator, context Context, expressionNode *Expre sort.Stable(sortableArray) - sortedList := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq", Style: candidateNode.Style} - sortedList.Content = make([]*yaml.Node, len(candidateNode.Content)) + sortedList := candidate.CreateReplacementWithComments(SequenceNode, "!!seq", candidate.Style) - for i, sortedNode := range sortableArray { - sortedList.Content[i] = sortedNode.Node + for _, sortedNode := range sortableArray { + sortedList.AddChild(sortedNode.Node) } - results.PushBack(candidate.CreateReplacementWithDocWrappers(sortedList)) + results.PushBack(sortedList) } return context.ChildContext(results), nil } type sortableNode struct { - Node *yaml.Node + Node *CandidateNode CompareContext Context dateTimeLayout string } @@ -79,7 +73,7 @@ func (a sortableNodeArray) Less(i, j int) bool { lhs := lhsEl.Value.(*CandidateNode) rhs := rhsEl.Value.(*CandidateNode) - result := a.compare(lhs.Node, rhs.Node, a[i].dateTimeLayout) + result := a.compare(lhs, rhs, a[i].dateTimeLayout) if result < 0 { return true @@ -92,18 +86,18 @@ func (a sortableNodeArray) Less(i, j int) bool { return false } -func (a sortableNodeArray) compare(lhs *yaml.Node, rhs *yaml.Node, dateTimeLayout string) int { +func (a sortableNodeArray) compare(lhs *CandidateNode, rhs *CandidateNode, dateTimeLayout string) int { lhsTag := lhs.Tag rhsTag := rhs.Tag if !strings.HasPrefix(lhsTag, "!!") { // custom tag - we have to have a guess - lhsTag = guessTagFromCustomType(lhs) + lhsTag = lhs.guessTagFromCustomType() } if !strings.HasPrefix(rhsTag, "!!") { // custom tag - we have to have a guess - rhsTag = guessTagFromCustomType(rhs) + rhsTag = rhs.guessTagFromCustomType() } isDateTime := lhsTag == "!!timestamp" && rhsTag == "!!timestamp" @@ -124,15 +118,9 @@ func (a sortableNodeArray) compare(lhs *yaml.Node, rhs *yaml.Node, dateTimeLayou } else if lhsTag != "!!bool" && rhsTag == "!!bool" { return 1 } else if lhsTag == "!!bool" && rhsTag == "!!bool" { - lhsTruthy, err := isTruthyNode(lhs) - if err != nil { - panic(fmt.Errorf("could not parse %v as boolean: %w", lhs.Value, err)) - } + lhsTruthy := isTruthyNode(lhs) - rhsTruthy, err := isTruthyNode(rhs) - if err != nil { - panic(fmt.Errorf("could not parse %v as boolean: %w", rhs.Value, err)) - } + rhsTruthy := isTruthyNode(rhs) if lhsTruthy == rhsTruthy { return 0 } else if lhsTruthy { diff --git a/pkg/yqlib/operator_sort_keys.go b/pkg/yqlib/operator_sort_keys.go index 0ab1a3cb7c8..c10da11eb3c 100644 --- a/pkg/yqlib/operator_sort_keys.go +++ b/pkg/yqlib/operator_sort_keys.go @@ -2,8 +2,6 @@ package yqlib import ( "sort" - - yaml "gopkg.in/yaml.v3" ) func sortKeysOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -16,8 +14,8 @@ func sortKeysOperator(d *dataTreeNavigator, context Context, expressionNode *Exp } for childEl := rhs.MatchingNodes.Front(); childEl != nil; childEl = childEl.Next() { - node := unwrapDoc(childEl.Value.(*CandidateNode).Node) - if node.Kind == yaml.MappingNode { + node := childEl.Value.(*CandidateNode) + if node.Kind == MappingNode { sortKeys(node) } if err != nil { @@ -29,10 +27,10 @@ func sortKeysOperator(d *dataTreeNavigator, context Context, expressionNode *Exp return context, nil } -func sortKeys(node *yaml.Node) { +func sortKeys(node *CandidateNode) { keys := make([]string, len(node.Content)/2) - keyBucket := map[string]*yaml.Node{} - valueBucket := map[string]*yaml.Node{} + keyBucket := map[string]*CandidateNode{} + valueBucket := map[string]*CandidateNode{} var contents = node.Content for index := 0; index < len(contents); index = index + 2 { key := contents[index] @@ -42,11 +40,14 @@ func sortKeys(node *yaml.Node) { valueBucket[key.Value] = value } sort.Strings(keys) - sortedContent := make([]*yaml.Node, len(node.Content)) + sortedContent := make([]*CandidateNode, len(node.Content)) for index := 0; index < len(keys); index = index + 1 { keyString := keys[index] sortedContent[index*2] = keyBucket[keyString] sortedContent[1+(index*2)] = valueBucket[keyString] } + + // re-arranging children, no need to update their parent + // relationship node.Content = sortedContent } diff --git a/pkg/yqlib/operator_sort_keys_test.go b/pkg/yqlib/operator_sort_keys_test.go index 8d421556457..586a1ce8b14 100644 --- a/pkg/yqlib/operator_sort_keys_test.go +++ b/pkg/yqlib/operator_sort_keys_test.go @@ -10,7 +10,7 @@ var sortKeysOperatorScenarios = []expressionScenario{ document: `{c: frog, a: blah, b: bing}`, expression: `sort_keys(.)`, expected: []string{ - "D0, P[], (doc)::{a: blah, b: bing, c: frog}\n", + "D0, P[], (!!map)::{a: blah, b: bing, c: frog}\n", }, }, { @@ -18,7 +18,7 @@ var sortKeysOperatorScenarios = []expressionScenario{ document: `{c: frog}`, expression: `sort_keys(.d)`, expected: []string{ - "D0, P[], (doc)::{c: frog}\n", + "D0, P[], (!!map)::{c: frog}\n", }, }, { diff --git a/pkg/yqlib/operator_sort_test.go b/pkg/yqlib/operator_sort_test.go index 9a8bc84a29e..0b60545e7d3 100644 --- a/pkg/yqlib/operator_sort_test.go +++ b/pkg/yqlib/operator_sort_test.go @@ -51,7 +51,7 @@ var sortByOperatorScenarios = []expressionScenario{ document: "cool: [{a: banana},{a: cat},{a: apple}]", expression: `.cool |= sort_by(.a)`, expected: []string{ - "D0, P[], (doc)::cool: [{a: apple}, {a: banana}, {a: cat}]\n", + "D0, P[], (!!map)::cool: [{a: apple}, {a: banana}, {a: cat}]\n", }, }, { @@ -60,7 +60,7 @@ var sortByOperatorScenarios = []expressionScenario{ document: "cool: [{b: banana},{a: banana},{c: banana}]", expression: `.cool |= sort_by(keys | .[0])`, expected: []string{ - "D0, P[], (doc)::cool: [{a: banana}, {b: banana}, {c: banana}]\n", + "D0, P[], (!!map)::cool: [{a: banana}, {b: banana}, {c: banana}]\n", }, }, { diff --git a/pkg/yqlib/operator_split_document.go b/pkg/yqlib/operator_split_document.go index eba24964cbe..e9fb245ba4a 100644 --- a/pkg/yqlib/operator_split_document.go +++ b/pkg/yqlib/operator_split_document.go @@ -6,7 +6,8 @@ func splitDocumentOperator(d *dataTreeNavigator, context Context, expressionNode var index uint for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidate.Document = index + candidate.SetDocument(index) + candidate.SetParent(nil) index = index + 1 } diff --git a/pkg/yqlib/operator_strings.go b/pkg/yqlib/operator_strings.go index 716620fe61e..7ac6986b182 100644 --- a/pkg/yqlib/operator_strings.go +++ b/pkg/yqlib/operator_strings.go @@ -5,8 +5,6 @@ import ( "fmt" "regexp" "strings" - - "gopkg.in/yaml.v3" ) type changeCasePrefs struct { @@ -16,17 +14,15 @@ type changeCasePrefs struct { func trimSpaceOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { results := list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - candidate := el.Value.(*CandidateNode) - - node := unwrapDoc(candidate.Node) + node := el.Value.(*CandidateNode) - if guessTagFromCustomType(node) != "!!str" { + if node.guessTagFromCustomType() != "!!str" { return Context{}, fmt.Errorf("cannot trim %v, can only operate on strings. ", node.Tag) } - newStringNode := &yaml.Node{Kind: yaml.ScalarNode, Tag: node.Tag, Style: node.Style} - newStringNode.Value = strings.TrimSpace(node.Value) - results.PushBack(candidate.CreateReplacement(newStringNode)) + newStringNode := node.CreateReplacement(ScalarNode, node.Tag, strings.TrimSpace(node.Value)) + newStringNode.Style = node.Style + results.PushBack(newStringNode) } @@ -38,21 +34,21 @@ func changeCaseOperator(d *dataTreeNavigator, context Context, expressionNode *E prefs := expressionNode.Operation.Preferences.(changeCasePrefs) for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - candidate := el.Value.(*CandidateNode) - - node := unwrapDoc(candidate.Node) + node := el.Value.(*CandidateNode) - if guessTagFromCustomType(node) != "!!str" { + if node.guessTagFromCustomType() != "!!str" { return Context{}, fmt.Errorf("cannot change case with %v, can only operate on strings. ", node.Tag) } - newStringNode := &yaml.Node{Kind: yaml.ScalarNode, Tag: node.Tag, Style: node.Style} + value := "" if prefs.ToUpperCase { - newStringNode.Value = strings.ToUpper(node.Value) + value = strings.ToUpper(node.Value) } else { - newStringNode.Value = strings.ToLower(node.Value) + value = strings.ToLower(node.Value) } - results.PushBack(candidate.CreateReplacement(newStringNode)) + newStringNode := node.CreateReplacement(ScalarNode, node.Tag, value) + newStringNode.Style = node.Style + results.PushBack(newStringNode) } @@ -69,7 +65,7 @@ func getSubstituteParameters(d *dataTreeNavigator, block *ExpressionNode, contex return "", "", err } if regExNodes.MatchingNodes.Front() != nil { - regEx = regExNodes.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + regEx = regExNodes.MatchingNodes.Front().Value.(*CandidateNode).Value } log.Debug("regEx %v", regEx) @@ -79,15 +75,15 @@ func getSubstituteParameters(d *dataTreeNavigator, block *ExpressionNode, contex return "", "", err } if replacementNodes.MatchingNodes.Front() != nil { - replacementText = replacementNodes.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + replacementText = replacementNodes.MatchingNodes.Front().Value.(*CandidateNode).Value } return regEx, replacementText, nil } -func substitute(original string, regex *regexp.Regexp, replacement string) *yaml.Node { +func substitute(original string, regex *regexp.Regexp, replacement string) (Kind, string, string) { replacedString := regex.ReplaceAllString(original, replacement) - return &yaml.Node{Kind: yaml.ScalarNode, Value: replacedString, Tag: "!!str"} + return ScalarNode, "!!str", replacedString } func substituteStringOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -110,15 +106,12 @@ func substituteStringOperator(d *dataTreeNavigator, context Context, expressionN var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) - - if guessTagFromCustomType(node) != "!!str" { + node := el.Value.(*CandidateNode) + if node.guessTagFromCustomType() != "!!str" { return Context{}, fmt.Errorf("cannot substitute with %v, can only substitute strings. Hint: Most often you'll want to use '|=' over '=' for this operation", node.Tag) } - targetNode := substitute(node.Value, regEx, replacementText) - result := candidate.CreateReplacement(targetNode) + result := node.CreateReplacement(substitute(node.Value, regEx, replacementText)) results.PushBack(result) } @@ -126,7 +119,7 @@ func substituteStringOperator(d *dataTreeNavigator, context Context, expressionN } -func addMatch(original []*yaml.Node, match string, offset int, name string) []*yaml.Node { +func addMatch(original []*CandidateNode, match string, offset int, name string) []*CandidateNode { newContent := append(original, createScalarNode("string", "string")) @@ -188,21 +181,18 @@ func match(matchPrefs matchPreferences, regEx *regexp.Regexp, candidate *Candida } for i, matches := range allMatches { - capturesListNode := &yaml.Node{Kind: yaml.SequenceNode} + capturesListNode := &CandidateNode{Kind: SequenceNode} match, submatches := matches[0], matches[1:] for j, submatch := range submatches { - captureNode := &yaml.Node{Kind: yaml.MappingNode} - captureNode.Content = addMatch(captureNode.Content, submatch, allIndices[i][2+j*2], subNames[j+1]) - capturesListNode.Content = append(capturesListNode.Content, captureNode) + captureNode := &CandidateNode{Kind: MappingNode} + captureNode.AddChildren(addMatch(captureNode.Content, submatch, allIndices[i][2+j*2], subNames[j+1])) + capturesListNode.AddChild(captureNode) } - node := &yaml.Node{Kind: yaml.MappingNode} - node.Content = addMatch(node.Content, match, allIndices[i][0], "") - node.Content = append(node.Content, - createScalarNode("captures", "captures"), - capturesListNode, - ) - results.PushBack(candidate.CreateReplacement(node)) + node := candidate.CreateReplacement(MappingNode, "!!map", "") + node.AddChildren(addMatch(node.Content, match, allIndices[i][0], "")) + node.AddKeyValueChild(createScalarNode("captures", "captures"), capturesListNode) + results.PushBack(node) } @@ -219,27 +209,25 @@ func capture(matchPrefs matchPreferences, regEx *regexp.Regexp, candidate *Candi } for i, matches := range allMatches { - capturesNode := &yaml.Node{Kind: yaml.MappingNode} + capturesNode := candidate.CreateReplacement(MappingNode, "!!map", "") _, submatches := matches[0], matches[1:] for j, submatch := range submatches { - capturesNode.Content = append(capturesNode.Content, - createScalarNode(subNames[j+1], subNames[j+1])) + + keyNode := createScalarNode(subNames[j+1], subNames[j+1]) + var valueNode *CandidateNode offset := allIndices[i][2+j*2] // offset of -1 means there was no match, force a null value like jq if offset < 0 { - capturesNode.Content = append(capturesNode.Content, - createScalarNode(nil, "null"), - ) + valueNode = createScalarNode(nil, "null") } else { - capturesNode.Content = append(capturesNode.Content, - createScalarNode(submatch, submatch), - ) + valueNode = createScalarNode(submatch, submatch) } + capturesNode.AddKeyValueChild(keyNode, valueNode) } - results.PushBack(candidate.CreateReplacement(capturesNode)) + results.PushBack(capturesNode) } @@ -260,7 +248,7 @@ func extractMatchArguments(d *dataTreeNavigator, context Context, expressionNode } paramText := "" if replacementNodes.MatchingNodes.Front() != nil { - paramText = replacementNodes.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + paramText = replacementNodes.MatchingNodes.Front().Value.(*CandidateNode).Value } if strings.Contains(paramText, "g") { paramText = strings.ReplaceAll(paramText, "g", "") @@ -281,7 +269,7 @@ func extractMatchArguments(d *dataTreeNavigator, context Context, expressionNode log.Debug(NodesToString(regExNodes.MatchingNodes)) regExStr := "" if regExNodes.MatchingNodes.Front() != nil { - regExStr = regExNodes.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + regExStr = regExNodes.MatchingNodes.Front().Value.(*CandidateNode).Value } log.Debug("regEx %v", regExStr) regEx, err := regexp.Compile(regExStr) @@ -297,14 +285,12 @@ func matchOperator(d *dataTreeNavigator, context Context, expressionNode *Expres var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) - - if guessTagFromCustomType(node) != "!!str" { + node := el.Value.(*CandidateNode) + if node.guessTagFromCustomType() != "!!str" { return Context{}, fmt.Errorf("cannot match with %v, can only match strings. Hint: Most often you'll want to use '|=' over '=' for this operation", node.Tag) } - match(matchPrefs, regEx, candidate, node.Value, results) + match(matchPrefs, regEx, node, node.Value, results) } return context.ChildContext(results), nil @@ -319,13 +305,11 @@ func captureOperator(d *dataTreeNavigator, context Context, expressionNode *Expr var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) - - if guessTagFromCustomType(node) != "!!str" { + node := el.Value.(*CandidateNode) + if node.guessTagFromCustomType() != "!!str" { return Context{}, fmt.Errorf("cannot match with %v, can only match strings. Hint: Most often you'll want to use '|=' over '=' for this operation", node.Tag) } - capture(matchPrefs, regEx, candidate, node.Value, results) + capture(matchPrefs, regEx, node, node.Value, results) } @@ -341,14 +325,12 @@ func testOperator(d *dataTreeNavigator, context Context, expressionNode *Express var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) - - if guessTagFromCustomType(node) != "!!str" { + node := el.Value.(*CandidateNode) + if node.guessTagFromCustomType() != "!!str" { return Context{}, fmt.Errorf("cannot match with %v, can only match strings. Hint: Most often you'll want to use '|=' over '=' for this operation", node.Tag) } matches := regEx.FindStringSubmatch(node.Value) - results.PushBack(createBooleanCandidate(candidate, len(matches) > 0)) + results.PushBack(createBooleanCandidate(node, len(matches) > 0)) } @@ -364,26 +346,24 @@ func joinStringOperator(d *dataTreeNavigator, context Context, expressionNode *E return Context{}, err } if rhs.MatchingNodes.Front() != nil { - joinStr = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + joinStr = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) - if node.Kind != yaml.SequenceNode { + node := el.Value.(*CandidateNode) + if node.Kind != SequenceNode { return Context{}, fmt.Errorf("cannot join with %v, can only join arrays of scalars", node.Tag) } - targetNode := join(node.Content, joinStr) - result := candidate.CreateReplacement(targetNode) + result := node.CreateReplacement(join(node.Content, joinStr)) results.PushBack(result) } return context.ChildContext(results), nil } -func join(content []*yaml.Node, joinStr string) *yaml.Node { +func join(content []*CandidateNode, joinStr string) (Kind, string, string) { var stringsToJoin []string for _, node := range content { str := node.Value @@ -393,7 +373,7 @@ func join(content []*yaml.Node, joinStr string) *yaml.Node { stringsToJoin = append(stringsToJoin, str) } - return &yaml.Node{Kind: yaml.ScalarNode, Value: strings.Join(stringsToJoin, joinStr), Tag: "!!str"} + return ScalarNode, "!!str", strings.Join(stringsToJoin, joinStr) } func splitStringOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -405,41 +385,41 @@ func splitStringOperator(d *dataTreeNavigator, context Context, expressionNode * return Context{}, err } if rhs.MatchingNodes.Front() != nil { - splitStr = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + splitStr = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) + node := el.Value.(*CandidateNode) if node.Tag == "!!null" { continue } - if guessTagFromCustomType(node) != "!!str" { - return Context{}, fmt.Errorf("Cannot split %v, can only split strings", node.Tag) + if node.guessTagFromCustomType() != "!!str" { + return Context{}, fmt.Errorf("cannot split %v, can only split strings", node.Tag) } - targetNode := split(node.Value, splitStr) - result := candidate.CreateReplacement(targetNode) + kind, tag, content := split(node.Value, splitStr) + result := node.CreateReplacement(kind, tag, "") + result.AddChildren(content) results.PushBack(result) } return context.ChildContext(results), nil } -func split(value string, spltStr string) *yaml.Node { - var contents []*yaml.Node +func split(value string, spltStr string) (Kind, string, []*CandidateNode) { + var contents []*CandidateNode if value != "" { log.Debug("going to spltStr[%v]", spltStr) var newStrings = strings.Split(value, spltStr) - contents = make([]*yaml.Node, len(newStrings)) + contents = make([]*CandidateNode, len(newStrings)) for index, str := range newStrings { - contents[index] = &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: str} + contents[index] = &CandidateNode{Kind: ScalarNode, Tag: "!!str", Value: str} } } - return &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq", Content: contents} + return SequenceNode, "!!seq", contents } diff --git a/pkg/yqlib/operator_strings_test.go b/pkg/yqlib/operator_strings_test.go index 1cf4268dbab..169bc047685 100644 --- a/pkg/yqlib/operator_strings_test.go +++ b/pkg/yqlib/operator_strings_test.go @@ -71,7 +71,7 @@ var stringsOperatorScenarios = []expressionScenario{ document: `foo bar foo`, expression: `match("foo")`, expected: []string{ - "D0, P[], ()::string: foo\noffset: 0\nlength: 3\ncaptures: []\n", + "D0, P[], (!!map)::string: foo\noffset: 0\nlength: 3\ncaptures: []\n", }, }, { @@ -79,7 +79,7 @@ var stringsOperatorScenarios = []expressionScenario{ document: `!horse foo bar foo`, expression: `match("foo")`, expected: []string{ - "D0, P[], ()::string: foo\noffset: 0\nlength: 3\ncaptures: []\n", + "D0, P[], (!!map)::string: foo\noffset: 0\nlength: 3\ncaptures: []\n", }, }, { @@ -111,7 +111,7 @@ var stringsOperatorScenarios = []expressionScenario{ document: `xyzzy-14`, expression: `capture("(?P[a-z]+)-(?P[0-9]+)")`, expected: []string{ - "D0, P[], ()::a: xyzzy\nn: \"14\"\n", + "D0, P[], (!!map)::a: xyzzy\nn: \"14\"\n", }, }, { @@ -119,7 +119,7 @@ var stringsOperatorScenarios = []expressionScenario{ document: `!horse xyzzy-14`, expression: `capture("(?P[a-z]+)-(?P[0-9]+)")`, expected: []string{ - "D0, P[], ()::a: xyzzy\nn: \"14\"\n", + "D0, P[], (!!map)::a: xyzzy\nn: \"14\"\n", }, }, { @@ -128,7 +128,7 @@ var stringsOperatorScenarios = []expressionScenario{ document: `xyzzy-14`, expression: `capture("(?P[a-z]+)-(?P[0-9]+)(?Pbar)?")`, expected: []string{ - "D0, P[], ()::a: xyzzy\nn: \"14\"\nbar123: null\n", + "D0, P[], (!!map)::a: xyzzy\nn: \"14\"\nbar123: null\n", }, }, { @@ -136,7 +136,7 @@ var stringsOperatorScenarios = []expressionScenario{ document: `cat cat`, expression: `match("cat")`, expected: []string{ - "D0, P[], ()::string: cat\noffset: 0\nlength: 3\ncaptures: []\n", + "D0, P[], (!!map)::string: cat\noffset: 0\nlength: 3\ncaptures: []\n", }, }, { @@ -209,7 +209,7 @@ var stringsOperatorScenarios = []expressionScenario{ document: `a: dogs are great`, expression: `.a |= sub("dogs", "cats")`, expected: []string{ - "D0, P[], (doc)::a: cats are great\n", + "D0, P[], (!!map)::a: cats are great\n", }, }, { @@ -218,7 +218,7 @@ var stringsOperatorScenarios = []expressionScenario{ document: "a: cat\nb: heat", expression: `.[] |= sub("(a)", "${1}r")`, expected: []string{ - "D0, P[], (doc)::a: cart\nb: heart\n", + "D0, P[], (!!map)::a: cart\nb: heart\n", }, }, { @@ -227,7 +227,7 @@ var stringsOperatorScenarios = []expressionScenario{ document: "a: !horse cat\nb: !goat heat", expression: `.[] |= sub("(a)", "${1}r")`, expected: []string{ - "D0, P[], (doc)::a: !horse cart\nb: !goat heart\n", + "D0, P[], (!!map)::a: !horse cart\nb: !goat heart\n", }, }, { diff --git a/pkg/yqlib/operator_style.go b/pkg/yqlib/operator_style.go index ed7f65492bf..2db8cc1648c 100644 --- a/pkg/yqlib/operator_style.go +++ b/pkg/yqlib/operator_style.go @@ -3,23 +3,21 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) -func parseStyle(customStyle string) (yaml.Style, error) { +func parseStyle(customStyle string) (Style, error) { if customStyle == "tagged" { - return yaml.TaggedStyle, nil + return TaggedStyle, nil } else if customStyle == "double" { - return yaml.DoubleQuotedStyle, nil + return DoubleQuotedStyle, nil } else if customStyle == "single" { - return yaml.SingleQuotedStyle, nil + return SingleQuotedStyle, nil } else if customStyle == "literal" { - return yaml.LiteralStyle, nil + return LiteralStyle, nil } else if customStyle == "folded" { - return yaml.FoldedStyle, nil + return FoldedStyle, nil } else if customStyle == "flow" { - return yaml.FlowStyle, nil + return FlowStyle, nil } else if customStyle != "" { return 0, fmt.Errorf("Unknown style %v", customStyle) } @@ -29,7 +27,7 @@ func parseStyle(customStyle string) (yaml.Style, error) { func assignStyleOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { log.Debugf("AssignStyleOperator: %v") - var style yaml.Style + var style Style if !expressionNode.Operation.UpdateAssign { rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.RHS) if err != nil { @@ -37,7 +35,7 @@ func assignStyleOperator(d *dataTreeNavigator, context Context, expressionNode * } if rhs.MatchingNodes.Front() != nil { - style, err = parseStyle(rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value) + style, err = parseStyle(rhs.MatchingNodes.Front().Value.(*CandidateNode).Value) if err != nil { return Context{}, err } @@ -52,7 +50,7 @@ func assignStyleOperator(d *dataTreeNavigator, context Context, expressionNode * for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - log.Debugf("Setting style of : %v", candidate.GetKey()) + log.Debugf("Setting style of : %v", NodeToString(candidate)) if expressionNode.Operation.UpdateAssign { rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(candidate), expressionNode.RHS) if err != nil { @@ -60,14 +58,14 @@ func assignStyleOperator(d *dataTreeNavigator, context Context, expressionNode * } if rhs.MatchingNodes.Front() != nil { - style, err = parseStyle(rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value) + style, err = parseStyle(rhs.MatchingNodes.Front().Value.(*CandidateNode).Value) if err != nil { return Context{}, err } } } - candidate.Node.Style = style + candidate.Style = style } return context, nil @@ -81,26 +79,25 @@ func getStyleOperator(d *dataTreeNavigator, context Context, expressionNode *Exp for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) var style string - switch candidate.Node.Style { - case yaml.TaggedStyle: + switch candidate.Style { + case TaggedStyle: style = "tagged" - case yaml.DoubleQuotedStyle: + case DoubleQuotedStyle: style = "double" - case yaml.SingleQuotedStyle: + case SingleQuotedStyle: style = "single" - case yaml.LiteralStyle: + case LiteralStyle: style = "literal" - case yaml.FoldedStyle: + case FoldedStyle: style = "folded" - case yaml.FlowStyle: + case FlowStyle: style = "flow" case 0: style = "" default: style = "" } - node := &yaml.Node{Kind: yaml.ScalarNode, Value: style, Tag: "!!str"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement(ScalarNode, "!!str", style) results.PushBack(result) } diff --git a/pkg/yqlib/operator_style_test.go b/pkg/yqlib/operator_style_test.go index ce263a7bcbb..9077f9a21fe 100644 --- a/pkg/yqlib/operator_style_test.go +++ b/pkg/yqlib/operator_style_test.go @@ -10,7 +10,7 @@ var styleOperatorScenarios = []expressionScenario{ document: `a: {b: thing, c: something}`, expression: `.a.b = "new" | .a.b style="double"`, expected: []string{ - "D0, P[], (doc)::a: {b: \"new\", c: something}\n", + "D0, P[], (!!map)::a: {b: \"new\", c: something}\n", }, }, { @@ -18,7 +18,7 @@ var styleOperatorScenarios = []expressionScenario{ document: `a: {b: thing, c: something}`, expression: `with(.a.b ; . = "new" | . style="double")`, expected: []string{ - "D0, P[], (doc)::a: {b: \"new\", c: something}\n", + "D0, P[], (!!map)::a: {b: \"new\", c: something}\n", }, }, { @@ -115,7 +115,7 @@ e: >- document: `{a: single, b: double}`, expression: `.[] style |= .`, expected: []string{ - "D0, P[], (doc)::{a: 'single', b: \"double\"}\n", + "D0, P[], (!!map)::{a: 'single', b: \"double\"}\n", }, }, { @@ -123,7 +123,7 @@ e: >- document: `{a: cat, b: double}`, expression: `.a style=.b`, expected: []string{ - "D0, P[], (doc)::{a: \"cat\", b: double}\n", + "D0, P[], (!!map)::{a: \"cat\", b: double}\n", }, }, { diff --git a/pkg/yqlib/operator_subtract.go b/pkg/yqlib/operator_subtract.go index 90867d4838e..260f3cbefba 100644 --- a/pkg/yqlib/operator_subtract.go +++ b/pkg/yqlib/operator_subtract.go @@ -5,8 +5,6 @@ import ( "strconv" "strings" "time" - - "gopkg.in/yaml.v3" ) func createSubtractOp(lhs *ExpressionNode, rhs *ExpressionNode) *ExpressionNode { @@ -26,50 +24,46 @@ func subtractOperator(d *dataTreeNavigator, context Context, expressionNode *Exp } func subtractArray(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - newLHSArray := make([]*yaml.Node, 0) + newLHSArray := make([]*CandidateNode, 0) - for lindex := 0; lindex < len(lhs.Node.Content); lindex = lindex + 1 { + for lindex := 0; lindex < len(lhs.Content); lindex = lindex + 1 { shouldInclude := true - for rindex := 0; rindex < len(rhs.Node.Content) && shouldInclude; rindex = rindex + 1 { - if recursiveNodeEqual(lhs.Node.Content[lindex], rhs.Node.Content[rindex]) { + for rindex := 0; rindex < len(rhs.Content) && shouldInclude; rindex = rindex + 1 { + if recursiveNodeEqual(lhs.Content[lindex], rhs.Content[rindex]) { shouldInclude = false } } if shouldInclude { - newLHSArray = append(newLHSArray, lhs.Node.Content[lindex]) + newLHSArray = append(newLHSArray, lhs.Content[lindex]) } } - lhs.Node.Content = newLHSArray + // removing children from LHS, parent hasn't changed + lhs.Content = newLHSArray return lhs, nil } func subtract(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - lhs.Node = unwrapDoc(lhs.Node) - rhs.Node = unwrapDoc(rhs.Node) - - lhsNode := lhs.Node - - if lhsNode.Tag == "!!null" { - return lhs.CreateReplacement(rhs.Node), nil + if lhs.Tag == "!!null" { + return lhs.CopyAsReplacement(rhs), nil } - target := lhs.CreateReplacement(&yaml.Node{}) + target := lhs.CopyWithoutContent() - switch lhsNode.Kind { - case yaml.MappingNode: + switch lhs.Kind { + case MappingNode: return nil, fmt.Errorf("maps not yet supported for subtraction") - case yaml.SequenceNode: - if rhs.Node.Kind != yaml.SequenceNode { - return nil, fmt.Errorf("%v (%v) cannot be subtracted from %v", rhs.Node.Tag, rhs.Path, lhsNode.Tag) + case SequenceNode: + if rhs.Kind != SequenceNode { + return nil, fmt.Errorf("%v (%v) cannot be subtracted from %v", rhs.Tag, rhs.GetNicePath(), lhs.Tag) } return subtractArray(lhs, rhs) - case yaml.ScalarNode: - if rhs.Node.Kind != yaml.ScalarNode { - return nil, fmt.Errorf("%v (%v) cannot be subtracted from %v", rhs.Node.Tag, rhs.Path, lhsNode.Tag) + case ScalarNode: + if rhs.Kind != ScalarNode { + return nil, fmt.Errorf("%v (%v) cannot be subtracted from %v", rhs.Tag, rhs.GetNicePath(), lhs.Tag) } - target.Node.Kind = yaml.ScalarNode - target.Node.Style = lhsNode.Style - if err := subtractScalars(context, target, lhsNode, rhs.Node); err != nil { + target.Kind = ScalarNode + target.Style = lhs.Style + if err := subtractScalars(context, target, lhs, rhs); err != nil { return nil, err } } @@ -77,19 +71,19 @@ func subtract(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *Ca return target, nil } -func subtractScalars(context Context, target *CandidateNode, lhs *yaml.Node, rhs *yaml.Node) error { +func subtractScalars(context Context, target *CandidateNode, lhs *CandidateNode, rhs *CandidateNode) error { lhsTag := lhs.Tag rhsTag := rhs.Tag lhsIsCustom := false if !strings.HasPrefix(lhsTag, "!!") { // custom tag - we have to have a guess - lhsTag = guessTagFromCustomType(lhs) + lhsTag = lhs.guessTagFromCustomType() lhsIsCustom = true } if !strings.HasPrefix(rhsTag, "!!") { // custom tag - we have to have a guess - rhsTag = guessTagFromCustomType(rhs) + rhsTag = rhs.guessTagFromCustomType() } isDateTime := lhsTag == "!!timestamp" @@ -113,8 +107,8 @@ func subtractScalars(context Context, target *CandidateNode, lhs *yaml.Node, rhs return err } result := lhsNum - rhsNum - target.Node.Tag = lhs.Tag - target.Node.Value = fmt.Sprintf(format, result) + target.Tag = lhs.Tag + target.Value = fmt.Sprintf(format, result) } else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") { lhsNum, err := strconv.ParseFloat(lhs.Value, 64) if err != nil { @@ -126,11 +120,11 @@ func subtractScalars(context Context, target *CandidateNode, lhs *yaml.Node, rhs } result := lhsNum - rhsNum if lhsIsCustom { - target.Node.Tag = lhs.Tag + target.Tag = lhs.Tag } else { - target.Node.Tag = "!!float" + target.Tag = "!!float" } - target.Node.Value = fmt.Sprintf("%v", result) + target.Value = fmt.Sprintf("%v", result) } else { return fmt.Errorf("%v cannot be added to %v", lhs.Tag, rhs.Tag) } @@ -138,7 +132,7 @@ func subtractScalars(context Context, target *CandidateNode, lhs *yaml.Node, rhs return nil } -func subtractDateTime(layout string, target *CandidateNode, lhs *yaml.Node, rhs *yaml.Node) error { +func subtractDateTime(layout string, target *CandidateNode, lhs *CandidateNode, rhs *CandidateNode) error { var durationStr string if strings.HasPrefix(rhs.Value, "-") { durationStr = rhs.Value[1:] @@ -157,6 +151,6 @@ func subtractDateTime(layout string, target *CandidateNode, lhs *yaml.Node, rhs } newTime := currentTime.Add(duration) - target.Node.Value = newTime.Format(layout) + target.Value = newTime.Format(layout) return nil } diff --git a/pkg/yqlib/operator_subtract_test.go b/pkg/yqlib/operator_subtract_test.go index b24474e948a..2b365b4d5e9 100644 --- a/pkg/yqlib/operator_subtract_test.go +++ b/pkg/yqlib/operator_subtract_test.go @@ -10,7 +10,7 @@ var subtractOperatorScenarios = []expressionScenario{ document: `{}`, expression: "(.a - .b) as $x | .", expected: []string{ - "D0, P[], (doc)::{}\n", + "D0, P[], (!!map)::{}\n", }, }, { @@ -64,7 +64,7 @@ var subtractOperatorScenarios = []expressionScenario{ document: `{a: 3, b: 4.5}`, expression: `.a = .a - .b`, expected: []string{ - "D0, P[], (doc)::{a: -1.5, b: 4.5}\n", + "D0, P[], (!!map)::{a: -1.5, b: 4.5}\n", }, }, { @@ -73,7 +73,7 @@ var subtractOperatorScenarios = []expressionScenario{ document: `{a: 3, b: 4}`, expression: `.a = .a - .b`, expected: []string{ - "D0, P[], (doc)::{a: -1, b: 4}\n", + "D0, P[], (!!map)::{a: -1, b: 4}\n", }, }, { @@ -81,7 +81,7 @@ var subtractOperatorScenarios = []expressionScenario{ document: `{a: 3, b: 5}`, expression: `.[] -= 1`, expected: []string{ - "D0, P[], (doc)::{a: 2, b: 4}\n", + "D0, P[], (!!map)::{a: 2, b: 4}\n", }, }, { @@ -90,7 +90,7 @@ var subtractOperatorScenarios = []expressionScenario{ document: `a: 2021-01-01T03:10:00Z`, expression: `.a -= "3h10m"`, expected: []string{ - "D0, P[], (doc)::a: 2021-01-01T00:00:00Z\n", + "D0, P[], (!!map)::a: 2021-01-01T00:00:00Z\n", }, }, { @@ -99,7 +99,7 @@ var subtractOperatorScenarios = []expressionScenario{ document: `a: 2021-01-01`, expression: `.a -= "24h"`, expected: []string{ - "D0, P[], (doc)::a: 2020-12-31T00:00:00Z\n", + "D0, P[], (!!map)::a: 2020-12-31T00:00:00Z\n", }, }, { @@ -108,7 +108,7 @@ var subtractOperatorScenarios = []expressionScenario{ document: `a: Saturday, 15-Dec-01 at 6:00AM GMT`, expression: `with_dtf("Monday, 02-Jan-06 at 3:04PM MST", .a -= "3h1m")`, expected: []string{ - "D0, P[], (doc)::a: Saturday, 15-Dec-01 at 2:59AM GMT\n", + "D0, P[], (!!map)::a: Saturday, 15-Dec-01 at 2:59AM GMT\n", }, }, { @@ -118,7 +118,7 @@ var subtractOperatorScenarios = []expressionScenario{ document: `a: !cat Saturday, 15-Dec-01 at 6:00AM GMT`, expression: `with_dtf("Monday, 02-Jan-06 at 3:04PM MST", .a -= "3h1m")`, expected: []string{ - "D0, P[], (doc)::a: !cat Saturday, 15-Dec-01 at 2:59AM GMT\n", + "D0, P[], (!!map)::a: !cat Saturday, 15-Dec-01 at 2:59AM GMT\n", }, }, { @@ -127,7 +127,7 @@ var subtractOperatorScenarios = []expressionScenario{ document: "a: !horse 2\nb: !goat 1", expression: `.a -= .b`, expected: []string{ - "D0, P[], (doc)::a: !horse 1\nb: !goat 1\n", + "D0, P[], (!!map)::a: !horse 1\nb: !goat 1\n", }, }, { diff --git a/pkg/yqlib/operator_tag.go b/pkg/yqlib/operator_tag.go index 59b07d89a5b..87f82dca5ac 100644 --- a/pkg/yqlib/operator_tag.go +++ b/pkg/yqlib/operator_tag.go @@ -2,8 +2,6 @@ package yqlib import ( "container/list" - - yaml "gopkg.in/yaml.v3" ) func assignTagOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -18,7 +16,7 @@ func assignTagOperator(d *dataTreeNavigator, context Context, expressionNode *Ex } if rhs.MatchingNodes.Front() != nil { - tag = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + tag = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } } @@ -38,10 +36,10 @@ func assignTagOperator(d *dataTreeNavigator, context Context, expressionNode *Ex } if rhs.MatchingNodes.Front() != nil { - tag = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + tag = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } } - unwrapDoc(candidate.Node).Tag = tag + candidate.Tag = tag } return context, nil @@ -54,8 +52,7 @@ func getTagOperator(d *dataTreeNavigator, context Context, expressionNode *Expre for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.ScalarNode, Value: unwrapDoc(candidate.Node).Tag, Tag: "!!str"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement(ScalarNode, "!!str", candidate.Tag) results.PushBack(result) } diff --git a/pkg/yqlib/operator_tag_test.go b/pkg/yqlib/operator_tag_test.go index 0466e5f3931..e000cd882df 100644 --- a/pkg/yqlib/operator_tag_test.go +++ b/pkg/yqlib/operator_tag_test.go @@ -5,6 +5,16 @@ import ( ) var tagOperatorScenarios = []expressionScenario{ + { + description: "tag of key is not a key", + subdescription: "so it should have 'a' as the path", + skipDoc: true, + document: "a: frog\n", + expression: `.a | key | tag`, + expected: []string{ + "D0, P[a], (!!str)::!!str\n", + }, + }, { description: "Get tag", document: `{a: cat, b: 5, c: 3.2, e: true, f: []}`, @@ -44,7 +54,7 @@ var tagOperatorScenarios = []expressionScenario{ document: `32`, expression: `. tag= "!!str"`, expected: []string{ - "D0, P[], (doc)::\"32\"\n", + "D0, P[], (!!str)::32\n", }, }, { @@ -52,7 +62,7 @@ var tagOperatorScenarios = []expressionScenario{ document: `{a: str}`, expression: `.a tag = "!!mikefarah"`, expected: []string{ - "D0, P[], (doc)::{a: !!mikefarah str}\n", + "D0, P[], (!!map)::{a: !!mikefarah str}\n", }, }, { @@ -61,7 +71,7 @@ var tagOperatorScenarios = []expressionScenario{ document: `{a: str}`, expression: `.a type = "!!mikefarah"`, expected: []string{ - "D0, P[], (doc)::{a: !!mikefarah str}\n", + "D0, P[], (!!map)::{a: !!mikefarah str}\n", }, }, { @@ -77,7 +87,7 @@ var tagOperatorScenarios = []expressionScenario{ document: `{a: "!!frog", b: "!!customTag"}`, expression: `.[] tag |= .`, expected: []string{ - "D0, P[], (doc)::{a: !!frog \"!!frog\", b: !!customTag \"!!customTag\"}\n", + "D0, P[], (!!map)::{a: !!frog \"!!frog\", b: !!customTag \"!!customTag\"}\n", }, }, } diff --git a/pkg/yqlib/operator_to_number.go b/pkg/yqlib/operator_to_number.go index 6c97d4ed29a..1b951778b9a 100644 --- a/pkg/yqlib/operator_to_number.go +++ b/pkg/yqlib/operator_to_number.go @@ -4,8 +4,6 @@ import ( "container/list" "fmt" "strconv" - - yaml "gopkg.in/yaml.v3" ) func tryConvertToNumber(value string) (string, bool) { @@ -31,22 +29,20 @@ func toNumberOperator(d *dataTreeNavigator, context Context, expressionNode *Exp for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - if candidate.Node.Kind != yaml.ScalarNode { - return Context{}, fmt.Errorf("cannot convert node at path %v of tag %v to number", candidate.GetNicePath(), candidate.GetNiceTag()) + if candidate.Kind != ScalarNode { + return Context{}, fmt.Errorf("cannot convert node at path %v of tag %v to number", candidate.GetNicePath(), candidate.Tag) } - if candidate.Node.Tag == "!!int" || candidate.Node.Tag == "!!float" { + if candidate.Tag == "!!int" || candidate.Tag == "!!float" { // it already is a number! results.PushBack(candidate) } else { - tag, converted := tryConvertToNumber(candidate.Node.Value) + tag, converted := tryConvertToNumber(candidate.Value) if converted { - node := &yaml.Node{Kind: yaml.ScalarNode, Value: candidate.Node.Value, Tag: tag} - - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement(ScalarNode, tag, candidate.Value) results.PushBack(result) } else { - return Context{}, fmt.Errorf("cannot convert node value [%v] at path %v of tag %v to number", candidate.Node.Value, candidate.GetNicePath(), candidate.GetNiceTag()) + return Context{}, fmt.Errorf("cannot convert node value [%v] at path %v of tag %v to number", candidate.Value, candidate.GetNicePath(), candidate.Tag) } } diff --git a/pkg/yqlib/operator_traverse_path.go b/pkg/yqlib/operator_traverse_path.go index 5af781dbe61..0d2e5f52849 100644 --- a/pkg/yqlib/operator_traverse_path.go +++ b/pkg/yqlib/operator_traverse_path.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/elliotchance/orderedmap" - yaml "gopkg.in/yaml.v3" ) type traversePreferences struct { @@ -17,7 +16,7 @@ type traversePreferences struct { } func splat(context Context, prefs traversePreferences) (Context, error) { - return traverseNodesWithArrayIndices(context, make([]*yaml.Node, 0), prefs) + return traverseNodesWithArrayIndices(context, make([]*CandidateNode, 0), prefs) } func traversePathOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -37,39 +36,34 @@ func traversePathOperator(d *dataTreeNavigator, context Context, expressionNode func traverse(context Context, matchingNode *CandidateNode, operation *Operation) (*list.List, error) { log.Debug("Traversing %v", NodeToString(matchingNode)) - value := matchingNode.Node - if value.Tag == "!!null" && operation.Value != "[]" && !context.DontAutoCreate { + if matchingNode.Tag == "!!null" && operation.Value != "[]" && !context.DontAutoCreate { log.Debugf("Guessing kind") // we must have added this automatically, lets guess what it should be now switch operation.Value.(type) { case int, int64: log.Debugf("probably an array") - value.Kind = yaml.SequenceNode + matchingNode.Kind = SequenceNode default: log.Debugf("probably a map") - value.Kind = yaml.MappingNode + matchingNode.Kind = MappingNode } - value.Tag = "" + matchingNode.Tag = "" } - switch value.Kind { - case yaml.MappingNode: - log.Debug("its a map with %v entries", len(value.Content)/2) + switch matchingNode.Kind { + case MappingNode: + log.Debug("its a map with %v entries", len(matchingNode.Content)/2) return traverseMap(context, matchingNode, createStringScalarNode(operation.StringValue), operation.Preferences.(traversePreferences), false) - case yaml.SequenceNode: - log.Debug("its a sequence of %v things!", len(value.Content)) + case SequenceNode: + log.Debug("its a sequence of %v things!", len(matchingNode.Content)) return traverseArray(matchingNode, operation, operation.Preferences.(traversePreferences)) - case yaml.AliasNode: + case AliasNode: log.Debug("its an alias!") - matchingNode.Node = matchingNode.Node.Alias + matchingNode = matchingNode.Alias return traverse(context, matchingNode, operation) - case yaml.DocumentNode: - log.Debug("digging into doc node") - - return traverse(context, matchingNode.CreateChildInMap(nil, matchingNode.Node.Content[0]), operation) default: return list.New(), nil } @@ -103,7 +97,7 @@ func traverseArrayOperator(d *dataTreeNavigator, context Context, expressionNode if expressionNode.Operation.Preferences != nil { prefs = expressionNode.Operation.Preferences.(traversePreferences) } - var indicesToTraverse = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Content + var indicesToTraverse = rhs.MatchingNodes.Front().Value.(*CandidateNode).Content log.Debugf("indicesToTraverse %v", len(indicesToTraverse)) @@ -115,7 +109,7 @@ func traverseArrayOperator(d *dataTreeNavigator, context Context, expressionNode return context.ChildContext(result.MatchingNodes), nil } -func traverseNodesWithArrayIndices(context Context, indicesToTraverse []*yaml.Node, prefs traversePreferences) (Context, error) { +func traverseNodesWithArrayIndices(context Context, indicesToTraverse []*CandidateNode, prefs traversePreferences) (Context, error) { var matchingNodeMap = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) @@ -129,34 +123,31 @@ func traverseNodesWithArrayIndices(context Context, indicesToTraverse []*yaml.No return context.ChildContext(matchingNodeMap), nil } -func traverseArrayIndices(context Context, matchingNode *CandidateNode, indicesToTraverse []*yaml.Node, prefs traversePreferences) (*list.List, error) { // call this if doc / alias like the other traverse - node := matchingNode.Node - if node.Tag == "!!null" { +func traverseArrayIndices(context Context, matchingNode *CandidateNode, indicesToTraverse []*CandidateNode, prefs traversePreferences) (*list.List, error) { // call this if doc / alias like the other traverse + if matchingNode.Tag == "!!null" { log.Debugf("OperatorArrayTraverse got a null - turning it into an empty array") // auto vivification - node.Tag = "" - node.Kind = yaml.SequenceNode + matchingNode.Tag = "" + matchingNode.Kind = SequenceNode //check that the indices are numeric, if not, then we should create an object if len(indicesToTraverse) != 0 && indicesToTraverse[0].Tag != "!!int" { - node.Kind = yaml.MappingNode + matchingNode.Kind = MappingNode } } - if node.Kind == yaml.AliasNode { - matchingNode.Node = node.Alias + if matchingNode.Kind == AliasNode { + matchingNode = matchingNode.Alias return traverseArrayIndices(context, matchingNode, indicesToTraverse, prefs) - } else if node.Kind == yaml.SequenceNode { + } else if matchingNode.Kind == SequenceNode { return traverseArrayWithIndices(matchingNode, indicesToTraverse, prefs) - } else if node.Kind == yaml.MappingNode { + } else if matchingNode.Kind == MappingNode { return traverseMapWithIndices(context, matchingNode, indicesToTraverse, prefs) - } else if node.Kind == yaml.DocumentNode { - return traverseArrayIndices(context, matchingNode.CreateChildInMap(nil, matchingNode.Node.Content[0]), indicesToTraverse, prefs) } - log.Debugf("OperatorArrayTraverse skipping %v as its a %v", matchingNode, node.Tag) + log.Debugf("OperatorArrayTraverse skipping %v as its a %v", matchingNode, matchingNode.Tag) return list.New(), nil } -func traverseMapWithIndices(context Context, candidate *CandidateNode, indices []*yaml.Node, prefs traversePreferences) (*list.List, error) { +func traverseMapWithIndices(context Context, candidate *CandidateNode, indices []*CandidateNode, prefs traversePreferences) (*list.List, error) { if len(indices) == 0 { return traverseMap(context, candidate, createStringScalarNode(""), prefs, true) } @@ -175,15 +166,14 @@ func traverseMapWithIndices(context Context, candidate *CandidateNode, indices [ return matchingNodeMap, nil } -func traverseArrayWithIndices(candidate *CandidateNode, indices []*yaml.Node, prefs traversePreferences) (*list.List, error) { +func traverseArrayWithIndices(node *CandidateNode, indices []*CandidateNode, prefs traversePreferences) (*list.List, error) { log.Debug("traverseArrayWithIndices") var newMatches = list.New() - node := unwrapDoc(candidate.Node) if len(indices) == 0 { log.Debug("splatting") var index int for index = 0; index < len(node.Content); index = index + 1 { - newMatches.PushBack(candidate.CreateChildInArray(index, node.Content[index])) + newMatches.PushBack(node.Content[index]) } return newMatches, nil @@ -206,7 +196,8 @@ func traverseArrayWithIndices(candidate *CandidateNode, indices []*yaml.Node, pr node.Style = 0 } - node.Content = append(node.Content, &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"}) + valueNode := createScalarNode(nil, "null") + node.AddChild(valueNode) contentLength = len(node.Content) } @@ -218,16 +209,16 @@ func traverseArrayWithIndices(candidate *CandidateNode, indices []*yaml.Node, pr return nil, fmt.Errorf("index [%v] out of range, array size is %v", index, contentLength) } - newMatches.PushBack(candidate.CreateChildInArray(index, node.Content[indexToUse])) + newMatches.PushBack(node.Content[indexToUse]) } return newMatches, nil } -func keyMatches(key *yaml.Node, wantedKey string) bool { +func keyMatches(key *CandidateNode, wantedKey string) bool { return matchKey(key.Value, wantedKey) } -func traverseMap(context Context, matchingNode *CandidateNode, keyNode *yaml.Node, prefs traversePreferences, splat bool) (*list.List, error) { +func traverseMap(context Context, matchingNode *CandidateNode, keyNode *CandidateNode, prefs traversePreferences, splat bool) (*list.List, error) { var newMatches = orderedmap.NewOrderedMap() err := doTraverseMap(newMatches, matchingNode, keyNode.Value, prefs, splat) @@ -236,28 +227,24 @@ func traverseMap(context Context, matchingNode *CandidateNode, keyNode *yaml.Nod } if !splat && !prefs.DontAutoCreate && !context.DontAutoCreate && newMatches.Len() == 0 { - log.Debugf("no matches, creating one") + log.Debugf("no matches, creating one for %v", NodeToString(keyNode)) //no matches, create one automagically - valueNode := &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"} + valueNode := matchingNode.CreateChild() + valueNode.Kind = ScalarNode + valueNode.Tag = "!!null" + valueNode.Value = "null" - node := matchingNode.Node - - if len(node.Content) == 0 { - node.Style = 0 + if len(matchingNode.Content) == 0 { + matchingNode.Style = 0 } - node.Content = append(node.Content, keyNode, valueNode) + keyNode, valueNode = matchingNode.AddKeyValueChild(keyNode, valueNode) if prefs.IncludeMapKeys { - log.Debug("including key") - candidateNode := matchingNode.CreateChildInMap(keyNode, keyNode) - candidateNode.IsMapKey = true - newMatches.Set(fmt.Sprintf("keyOf-%v", candidateNode.GetKey()), candidateNode) + newMatches.Set(keyNode.GetKey(), keyNode) } if !prefs.DontIncludeMapValues { - log.Debug("including value") - candidateNode := matchingNode.CreateChildInMap(keyNode, valueNode) - newMatches.Set(candidateNode.GetKey(), candidateNode) + newMatches.Set(valueNode.GetKey(), valueNode) } } @@ -270,24 +257,21 @@ func traverseMap(context Context, matchingNode *CandidateNode, keyNode *yaml.Nod return results, nil } -func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, wantedKey string, prefs traversePreferences, splat bool) error { +func doTraverseMap(newMatches *orderedmap.OrderedMap, node *CandidateNode, wantedKey string, prefs traversePreferences, splat bool) error { // value.Content is a concatenated array of key, value, // so keys are in the even indices, values in odd. // merge aliases are defined first, but we only want to traverse them // if we don't find a match directly on this node first. - node := candidate.Node - var contents = node.Content for index := 0; index < len(contents); index = index + 2 { key := contents[index] value := contents[index+1] - log.Debug("checking %v (%v)", key.Value, key.Tag) //skip the 'merge' tag, find a direct match first if key.Tag == "!!merge" && !prefs.DontFollowAlias { log.Debug("Merge anchor") - err := traverseMergeAnchor(newMatches, candidate, value, wantedKey, prefs, splat) + err := traverseMergeAnchor(newMatches, value, wantedKey, prefs, splat) if err != nil { return err } @@ -295,14 +279,11 @@ func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, log.Debug("MATCHED") if prefs.IncludeMapKeys { log.Debug("including key") - candidateNode := candidate.CreateChildInMap(key, key) - candidateNode.IsMapKey = true - newMatches.Set(fmt.Sprintf("keyOf-%v", candidateNode.GetKey()), candidateNode) + newMatches.Set(key.GetKey(), key) } if !prefs.DontIncludeMapValues { log.Debug("including value") - candidateNode := candidate.CreateChildInMap(key, value) - newMatches.Set(candidateNode.GetKey(), candidateNode) + newMatches.Set(value.GetKey(), value) } } } @@ -310,17 +291,16 @@ func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, return nil } -func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, originalCandidate *CandidateNode, value *yaml.Node, wantedKey string, prefs traversePreferences, splat bool) error { +func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, value *CandidateNode, wantedKey string, prefs traversePreferences, splat bool) error { switch value.Kind { - case yaml.AliasNode: - if value.Alias.Kind != yaml.MappingNode { + case AliasNode: + if value.Alias.Kind != MappingNode { return fmt.Errorf("can only use merge anchors with maps (!!map), but got %v", value.Alias.Tag) } - candidateNode := originalCandidate.CreateReplacement(value.Alias) - return doTraverseMap(newMatches, candidateNode, wantedKey, prefs, splat) - case yaml.SequenceNode: + return doTraverseMap(newMatches, value.Alias, wantedKey, prefs, splat) + case SequenceNode: for _, childValue := range value.Content { - err := traverseMergeAnchor(newMatches, originalCandidate, childValue, wantedKey, prefs, splat) + err := traverseMergeAnchor(newMatches, childValue, wantedKey, prefs, splat) if err != nil { return err } @@ -331,6 +311,6 @@ func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, originalCandidate *C func traverseArray(candidate *CandidateNode, operation *Operation, prefs traversePreferences) (*list.List, error) { log.Debug("operation Value %v", operation.Value) - indices := []*yaml.Node{{Value: operation.StringValue}} + indices := []*CandidateNode{{Value: operation.StringValue}} return traverseArrayWithIndices(candidate, indices, prefs) } diff --git a/pkg/yqlib/operator_traverse_path_test.go b/pkg/yqlib/operator_traverse_path_test.go index 5d62447c346..55887ee71a2 100644 --- a/pkg/yqlib/operator_traverse_path_test.go +++ b/pkg/yqlib/operator_traverse_path_test.go @@ -35,6 +35,30 @@ steps: ` var traversePathOperatorScenarios = []expressionScenario{ + { + skipDoc: true, + description: "dynamically set parent and key", + expression: `.a.b.c = 3 | .a.b.c`, + expected: []string{ + "D0, P[a b c], (!!int)::3\n", + }, + }, + { + skipDoc: true, + description: "dynamically set parent and key in array", + expression: `.a.b[0] = 3 | .a.b[0]`, + expected: []string{ + "D0, P[a b 0], (!!int)::3\n", + }, + }, + { + skipDoc: true, + description: "dynamically set parent and key", + expression: `.a.b = ["x","y"] | .a.b[1]`, + expected: []string{ + "D0, P[a b 1], (!!str)::y\n", + }, + }, { skipDoc: true, description: "splat empty map", @@ -62,7 +86,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: `blah: {}`, expression: `.blah.cat = "cool"`, expected: []string{ - "D0, P[], (doc)::blah:\n cat: cool\n", + "D0, P[], (!!map)::blah:\n cat: cool\n", }, }, { @@ -70,7 +94,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: `blah: []`, expression: `.blah.0 = "cool"`, expected: []string{ - "D0, P[], (doc)::blah:\n - cool\n", + "D0, P[], (!!map)::blah:\n - cool\n", }, }, { @@ -160,7 +184,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: `c: dog`, expression: `.[.a.b] as $x | .`, expected: []string{ - "D0, P[], (doc)::c: dog\n", + "D0, P[], (!!map)::c: dog\n", }, }, { @@ -278,15 +302,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: `{a: &cat {c: frog}, b: *cat}`, expression: `.b[]`, expected: []string{ - "D0, P[b c], (!!str)::frog\n", - }, - }, - { - skipDoc: true, - document: `{a: &cat {c: frog}, b: *cat}`, - expression: `.b[]`, - expected: []string{ - "D0, P[b c], (!!str)::frog\n", + "D0, P[a c], (!!str)::frog\n", }, }, { @@ -294,7 +310,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: `{a: &cat {c: frog}, b: *cat}`, expression: `.b.c`, expected: []string{ - "D0, P[b c], (!!str)::frog\n", + "D0, P[a c], (!!str)::frog\n", }, }, { @@ -343,7 +359,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: mergeDocSample, expression: `.foobar.a`, expected: []string{ - "D0, P[foobar a], (!!str)::foo_a\n", + "D0, P[foo a], (!!str)::foo_a\n", }, }, { @@ -351,7 +367,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: mergeDocSample, expression: `.foobar.c`, expected: []string{ - "D0, P[foobar c], (!!str)::foo_c\n", + "D0, P[foo c], (!!str)::foo_c\n", }, }, { @@ -367,18 +383,8 @@ var traversePathOperatorScenarios = []expressionScenario{ document: mergeDocSample, 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{ - "D0, P[foobar c], (!!str)::foo_c\n", - "D0, P[foobar a], (!!str)::foo_a\n", + "D0, P[foo c], (!!str)::foo_c\n", + "D0, P[foo a], (!!str)::foo_a\n", "D0, P[foobar thing], (!!str)::foobar_thing\n", }, }, @@ -395,7 +401,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: mergeDocSample, expression: `.foobarList.a`, expected: []string{ - "D0, P[foobarList a], (!!str)::foo_a\n", + "D0, P[foo a], (!!str)::foo_a\n", }, }, { @@ -404,7 +410,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: mergeDocSample, expression: `.foobarList.thing`, expected: []string{ - "D0, P[foobarList thing], (!!str)::bar_thing\n", + "D0, P[bar thing], (!!str)::bar_thing\n", }, }, { @@ -420,7 +426,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: mergeDocSample, expression: `.foobarList.b`, expected: []string{ - "D0, P[foobarList b], (!!str)::bar_b\n", + "D0, P[bar b], (!!str)::bar_b\n", }, }, { @@ -428,20 +434,9 @@ var traversePathOperatorScenarios = []expressionScenario{ document: mergeDocSample, 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{ - "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[bar b], (!!str)::bar_b\n", + "D0, P[foo a], (!!str)::foo_a\n", + "D0, P[bar thing], (!!str)::bar_thing\n", "D0, P[foobarList c], (!!str)::foobarList_c\n", }, }, @@ -494,23 +489,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: `{a: [a,b,c]}`, expression: `.a[-1]`, expected: []string{ - "D0, P[a -1], (!!str)::c\n", - }, - }, - { - skipDoc: true, - document: `{a: [a,b,c]}`, - expression: `.a[-1]`, - expected: []string{ - "D0, P[a -1], (!!str)::c\n", - }, - }, - { - skipDoc: true, - document: `{a: [a,b,c]}`, - expression: `.a[-2]`, - expected: []string{ - "D0, P[a -2], (!!str)::b\n", + "D0, P[a 2], (!!str)::c\n", }, }, { @@ -518,7 +497,7 @@ var traversePathOperatorScenarios = []expressionScenario{ document: `{a: [a,b,c]}`, expression: `.a[-2]`, expected: []string{ - "D0, P[a -2], (!!str)::b\n", + "D0, P[a 1], (!!str)::b\n", }, }, { diff --git a/pkg/yqlib/operator_union.go b/pkg/yqlib/operator_union.go index 310d827e0a4..7190504cc13 100644 --- a/pkg/yqlib/operator_union.go +++ b/pkg/yqlib/operator_union.go @@ -3,22 +3,22 @@ package yqlib import "container/list" func unionOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { - log.Debug("unionOperator") - log.Debug("context: %v", NodesToString(context.MatchingNodes)) + log.Debug("unionOperator--") + log.Debug("unionOperator: context: %v", NodesToString(context.MatchingNodes)) lhs, err := d.GetMatchingNodes(context, expressionNode.LHS) if err != nil { return Context{}, err } - log.Debug("lhs: %v", NodesToString(lhs.MatchingNodes)) - log.Debug("rhs input: %v", NodesToString(context.MatchingNodes)) - log.Debug("rhs: %v", expressionNode.RHS.Operation.toString()) + log.Debug("unionOperator: lhs: %v", NodesToString(lhs.MatchingNodes)) + log.Debug("unionOperator: rhs input: %v", NodesToString(context.MatchingNodes)) + log.Debug("unionOperator: rhs: %v", expressionNode.RHS.Operation.toString()) rhs, err := d.GetMatchingNodes(context, expressionNode.RHS) if err != nil { return Context{}, err } - log.Debug("lhs: %v", lhs.ToString()) - log.Debug("rhs: %v", rhs.ToString()) + log.Debug("unionOperator: lhs: %v", lhs.ToString()) + log.Debug("unionOperator: rhs: %v", rhs.ToString()) results := lhs.ChildContext(list.New()) for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() { @@ -33,12 +33,11 @@ func unionOperator(d *dataTreeNavigator, context Context, expressionNode *Expres for el := rhs.MatchingNodes.Front(); el != nil; el = el.Next() { node := el.Value.(*CandidateNode) - log.Debug("processing %v", NodeToString(node)) + log.Debug("union operator rhs: processing %v", NodeToString(node)) results.MatchingNodes.PushBack(node) } } - log.Debug("and lets print it out") - log.Debug("all together: %v", results.ToString()) + log.Debug("union operator: all together: %v", results.ToString()) return results, nil } diff --git a/pkg/yqlib/operator_union_test.go b/pkg/yqlib/operator_union_test.go index 4b98ac0654a..87247862b4c 100644 --- a/pkg/yqlib/operator_union_test.go +++ b/pkg/yqlib/operator_union_test.go @@ -10,7 +10,7 @@ var unionOperatorScenarios = []expressionScenario{ document: "{}", expression: `(.a, .b.c) as $x | .`, expected: []string{ - "D0, P[], (doc)::{}\n", + "D0, P[], (!!map)::{}\n", }, }, { diff --git a/pkg/yqlib/operator_unique.go b/pkg/yqlib/operator_unique.go index a1c5216ca0f..2ba69ce0f7d 100644 --- a/pkg/yqlib/operator_unique.go +++ b/pkg/yqlib/operator_unique.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/elliotchance/orderedmap" - yaml "gopkg.in/yaml.v3" ) func unique(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -22,15 +21,13 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - candidateNode := unwrapDoc(candidate.Node) - if candidateNode.Kind != yaml.SequenceNode { + if candidate.Kind != SequenceNode { return Context{}, fmt.Errorf("Only arrays are supported for unique") } var newMatches = orderedmap.NewOrderedMap() - for _, node := range candidateNode.Content { - child := &CandidateNode{Node: node} + for _, child := range candidate.Content { rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(child), expressionNode.RHS) if err != nil { @@ -42,21 +39,21 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN if rhs.MatchingNodes.Len() > 0 { first := rhs.MatchingNodes.Front() keyCandidate := first.Value.(*CandidateNode) - keyValue = keyCandidate.Node.Value + keyValue = keyCandidate.Value } _, exists := newMatches.Get(keyValue) if !exists { - newMatches.Set(keyValue, child.Node) + newMatches.Set(keyValue, child) } } - resultNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} + resultNode := candidate.CreateReplacementWithComments(SequenceNode, "!!seq", candidate.Style) for el := newMatches.Front(); el != nil; el = el.Next() { - resultNode.Content = append(resultNode.Content, el.Value.(*yaml.Node)) + resultNode.AddChild(el.Value.(*CandidateNode)) } - results.PushBack(candidate.CreateReplacementWithDocWrappers(resultNode)) + results.PushBack(resultNode) } return context.ChildContext(results), nil diff --git a/pkg/yqlib/operator_unique_test.go b/pkg/yqlib/operator_unique_test.go index f0c44533cfa..fe28de5683e 100644 --- a/pkg/yqlib/operator_unique_test.go +++ b/pkg/yqlib/operator_unique_test.go @@ -11,7 +11,7 @@ var uniqueOperatorScenarios = []expressionScenario{ document: `[2,1,3,2]`, expression: `unique`, expected: []string{ - "D0, P[], (!!seq)::- 2\n- 1\n- 3\n", + "D0, P[], (!!seq)::[2, 1, 3]\n", }, }, { @@ -20,7 +20,7 @@ var uniqueOperatorScenarios = []expressionScenario{ document: `[~,null, ~, null]`, expression: `unique`, expected: []string{ - "D0, P[], (!!seq)::- ~\n- null\n", + "D0, P[], (!!seq)::[~, null]\n", }, }, { @@ -29,7 +29,7 @@ var uniqueOperatorScenarios = []expressionScenario{ document: `[~,null, ~, null]`, expression: `unique_by(tag)`, expected: []string{ - "D0, P[], (!!seq)::- ~\n", + "D0, P[], (!!seq)::[~]\n", }, }, { @@ -37,7 +37,7 @@ var uniqueOperatorScenarios = []expressionScenario{ document: `[{name: harry, pet: cat}, {name: billy, pet: dog}, {name: harry, pet: dog}]`, expression: `unique_by(.name)`, expected: []string{ - "D0, P[], (!!seq)::- {name: harry, pet: cat}\n- {name: billy, pet: dog}\n", + "D0, P[], (!!seq)::[{name: harry, pet: cat}, {name: billy, pet: dog}]\n", }, }, { @@ -45,7 +45,7 @@ var uniqueOperatorScenarios = []expressionScenario{ document: `[{name: harry, pet: cat}, {pet: fish}, {name: harry, pet: dog}]`, expression: `unique_by(.name)`, expected: []string{ - "D0, P[], (!!seq)::- {name: harry, pet: cat}\n- {pet: fish}\n", + "D0, P[], (!!seq)::[{name: harry, pet: cat}, {pet: fish}]\n", }, }, { @@ -53,7 +53,7 @@ var uniqueOperatorScenarios = []expressionScenario{ document: `[{name: harry, pet: cat}, {pet: fish}, {name: harry, pet: dog}]`, expression: `unique_by(.cat.dog)`, expected: []string{ - "D0, P[], (!!seq)::- {name: harry, pet: cat}\n", + "D0, P[], (!!seq)::[{name: harry, pet: cat}]\n", }, }, { @@ -61,7 +61,7 @@ var uniqueOperatorScenarios = []expressionScenario{ document: "# abc\n[{name: harry, pet: cat}, {pet: fish}, {name: harry, pet: dog}]\n# xyz", expression: `unique_by(.name)`, expected: []string{ - "D0, P[], (!!seq)::# abc\n- {name: harry, pet: cat}\n- {pet: fish}\n# xyz\n", + "D0, P[], (!!seq)::# abc\n[{name: harry, pet: cat}, {pet: fish}]\n# xyz\n", }, }, } diff --git a/pkg/yqlib/operator_value.go b/pkg/yqlib/operator_value.go index b4296accc34..740893af29a 100644 --- a/pkg/yqlib/operator_value.go +++ b/pkg/yqlib/operator_value.go @@ -7,22 +7,16 @@ func referenceOperator(d *dataTreeNavigator, context Context, expressionNode *Ex } func valueOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { - log.Debug("value = %v", expressionNode.Operation.CandidateNode.Node.Value) + log.Debug("value = %v", expressionNode.Operation.CandidateNode.Value) if context.MatchingNodes.Len() == 0 { - clone, err := expressionNode.Operation.CandidateNode.Copy() - if err != nil { - return Context{}, err - } + clone := expressionNode.Operation.CandidateNode.Copy() return context.SingleChildContext(clone), nil } var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { - clone, err := expressionNode.Operation.CandidateNode.Copy() - if err != nil { - return Context{}, err - } + clone := expressionNode.Operation.CandidateNode.Copy() results.PushBack(clone) } diff --git a/pkg/yqlib/operator_variables.go b/pkg/yqlib/operator_variables.go index 32248ffc45c..01a946ec429 100644 --- a/pkg/yqlib/operator_variables.go +++ b/pkg/yqlib/operator_variables.go @@ -72,10 +72,7 @@ func variableLoopSingleChild(d *dataTreeNavigator, context Context, originalExp if prefs.IsReference { variableValue.PushBack(el.Value) } else { - candidateCopy, err := el.Value.(*CandidateNode).Copy() - if err != nil { - return Context{}, err - } + candidateCopy := el.Value.(*CandidateNode).Copy() variableValue.PushBack(candidateCopy) } newContext := context.ChildContext(context.MatchingNodes) diff --git a/pkg/yqlib/operator_variables_test.go b/pkg/yqlib/operator_variables_test.go index f1555f28594..bc84f604a78 100644 --- a/pkg/yqlib/operator_variables_test.go +++ b/pkg/yqlib/operator_variables_test.go @@ -10,7 +10,7 @@ var variableOperatorScenarios = []expressionScenario{ document: `{}`, expression: `.a.b as $foo | .`, expected: []string{ - "D0, P[], (doc)::{}\n", + "D0, P[], (!!map)::{}\n", }, }, { @@ -76,7 +76,7 @@ var variableOperatorScenarios = []expressionScenario{ document: "a: a_value\nb: b_value", expression: `.a as $x | .b as $y | .b = $x | .a = $y`, expected: []string{ - "D0, P[], (doc)::a: b_value\nb: a_value\n", + "D0, P[], (!!map)::a: b_value\nb: a_value\n", }, }, { @@ -85,7 +85,7 @@ var variableOperatorScenarios = []expressionScenario{ document: `a: {b: thing, c: something}`, expression: `.a.b ref $x | $x = "new" | $x style="double"`, expected: []string{ - "D0, P[], (doc)::a: {b: \"new\", c: something}\n", + "D0, P[], (!!map)::a: {b: \"new\", c: something}\n", }, }, } diff --git a/pkg/yqlib/operator_with_test.go b/pkg/yqlib/operator_with_test.go index 04f184c23a8..36855df1578 100644 --- a/pkg/yqlib/operator_with_test.go +++ b/pkg/yqlib/operator_with_test.go @@ -8,7 +8,7 @@ var withOperatorScenarios = []expressionScenario{ document: `a: {deeply: {nested: value}}`, expression: `with(.a.deeply.nested; . = "newValue" | . style="single")`, expected: []string{ - "D0, P[], (doc)::a: {deeply: {nested: 'newValue'}}\n", + "D0, P[], (!!map)::a: {deeply: {nested: 'newValue'}}\n", }, }, { @@ -16,7 +16,7 @@ var withOperatorScenarios = []expressionScenario{ document: `a: {deeply: {nested: value, other: thing}}`, expression: `with(.a.deeply; .nested = "newValue" | .other= "newThing")`, expected: []string{ - "D0, P[], (doc)::a: {deeply: {nested: newValue, other: newThing}}\n", + "D0, P[], (!!map)::a: {deeply: {nested: newValue, other: newThing}}\n", }, }, { @@ -25,7 +25,7 @@ var withOperatorScenarios = []expressionScenario{ document: `myArray: [{a: apple},{a: banana}]`, expression: `with(.myArray[]; .b = .a + " yum")`, expected: []string{ - "D0, P[], (doc)::myArray: [{a: apple, b: apple yum}, {a: banana, b: banana yum}]\n", + "D0, P[], (!!map)::myArray: [{a: apple, b: apple yum}, {a: banana, b: banana yum}]\n", }, }, { @@ -35,7 +35,7 @@ var withOperatorScenarios = []expressionScenario{ document: `myArray: [{a: apple},{a: banana}]`, expression: `with(.myArray[]; .a += .a)`, expected: []string{ - "D0, P[], (doc)::myArray: [{a: appleapple}, {a: bananabanana}]\n", + "D0, P[], (!!map)::myArray: [{a: appleapple}, {a: bananabanana}]\n", }, }, } diff --git a/pkg/yqlib/operators.go b/pkg/yqlib/operators.go index ea0574d6fc9..f4f33e55423 100644 --- a/pkg/yqlib/operators.go +++ b/pkg/yqlib/operators.go @@ -6,7 +6,6 @@ import ( "github.com/jinzhu/copier" logging "gopkg.in/op/go-logging.v1" - "gopkg.in/yaml.v3" ) type operatorHandler func(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) @@ -37,10 +36,7 @@ func compoundAssignFunction(d *dataTreeNavigator, context Context, expressionNod for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - clone, err := candidate.Copy() - if err != nil { - return Context{}, err - } + clone := candidate.Copy() valueCopyExp := &ExpressionNode{Operation: &Operation{OperationType: referenceOpType, CandidateNode: clone}} valueExpression := &ExpressionNode{Operation: &Operation{OperationType: referenceOpType, CandidateNode: candidate}} @@ -55,13 +51,6 @@ func compoundAssignFunction(d *dataTreeNavigator, context Context, expressionNod return context, nil } -func unwrapDoc(node *yaml.Node) *yaml.Node { - if node.Kind == yaml.DocumentNode { - return node.Content[0] - } - return node -} - func emptyOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { context.MatchingNodes = list.New() return context, nil @@ -187,8 +176,13 @@ func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode { if !value { valString = "false" } - node := &yaml.Node{Kind: yaml.ScalarNode, Value: valString, Tag: "!!bool"} - return owner.CreateReplacement(node) + 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 { diff --git a/pkg/yqlib/operators_test.go b/pkg/yqlib/operators_test.go index ff6e6f622c9..56340cbb27e 100644 --- a/pkg/yqlib/operators_test.go +++ b/pkg/yqlib/operators_test.go @@ -14,7 +14,6 @@ import ( "github.com/mikefarah/yq/v4/test" logging "gopkg.in/op/go-logging.v1" - yaml "gopkg.in/yaml.v3" ) type expressionScenario struct { @@ -81,10 +80,11 @@ func testScenario(t *testing.T, s *expressionScenario) { } } else { candidateNode := &CandidateNode{ - Document: 0, - Filename: "", - Node: &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode}, - FileIndex: 0, + document: 0, + filename: "", + Tag: "!!null", + Kind: ScalarNode, + fileIndex: 0, } inputs.PushBack(candidateNode) @@ -131,6 +131,7 @@ func testScenario(t *testing.T, s *expressionScenario) { func resultToString(t *testing.T, n *CandidateNode) string { var valueBuffer bytes.Buffer + log.Debugf("printing result %v", NodeToString(n)) printer := NewSimpleYamlPrinter(bufio.NewWriter(&valueBuffer), YamlOutputFormat, true, false, 4, true) err := printer.PrintResults(n.AsList()) @@ -139,13 +140,11 @@ func resultToString(t *testing.T, n *CandidateNode) string { return "" } - tag := n.Node.Tag - if n.Node.Kind == yaml.DocumentNode { - tag = "doc" - } else if n.Node.Kind == yaml.AliasNode { + tag := n.Tag + if n.Kind == AliasNode { tag = "alias" } - return fmt.Sprintf(`D%v, P%v, (%v)::%v`, n.Document, n.Path, tag, valueBuffer.String()) + return fmt.Sprintf(`D%v, P%v, (%v)::%v`, n.GetDocument(), n.GetPath(), tag, valueBuffer.String()) } func resultsToString(t *testing.T, results *list.List) []string { @@ -359,10 +358,11 @@ func documentOutput(t *testing.T, w *bufio.Writer, s expressionScenario, formatt } } else { candidateNode := &CandidateNode{ - Document: 0, - Filename: "", - Node: &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode}, - FileIndex: 0, + document: 0, + filename: "", + Tag: "!!null", + Kind: ScalarNode, + fileIndex: 0, } inputs.PushBack(candidateNode) diff --git a/pkg/yqlib/ordered_map.go b/pkg/yqlib/ordered_map.go deleted file mode 100644 index a783423b3a9..00000000000 --- a/pkg/yqlib/ordered_map.go +++ /dev/null @@ -1,14 +0,0 @@ -package yqlib - -// orderedMap allows to marshal and unmarshal JSON and YAML values keeping the -// order of keys and values in a map or an object. -type orderedMap struct { - // if this is an object, kv != nil. If this is not an object, kv == nil. - kv []orderedMapKV - altVal interface{} -} - -type orderedMapKV struct { - K string - V orderedMap -} diff --git a/pkg/yqlib/ordered_map_json.go b/pkg/yqlib/ordered_map_json.go deleted file mode 100644 index 94a1d780f6e..00000000000 --- a/pkg/yqlib/ordered_map_json.go +++ /dev/null @@ -1,83 +0,0 @@ -package yqlib - -import ( - "bytes" - "encoding/json" - "errors" - "io" -) - -func (o *orderedMap) UnmarshalJSON(data []byte) error { - switch data[0] { - case '{': - // initialise so that even if the object is empty it is not nil - o.kv = []orderedMapKV{} - - // create decoder - dec := json.NewDecoder(bytes.NewReader(data)) - _, err := dec.Token() // open object - if err != nil { - return err - } - - // cycle through k/v - var tok json.Token - for tok, err = dec.Token(); err == nil; tok, err = dec.Token() { - // we can expect two types: string or Delim. Delim automatically means - // that it is the closing bracket of the object, whereas string means - // that there is another key. - if _, ok := tok.(json.Delim); ok { - break - } - kv := orderedMapKV{ - K: tok.(string), - } - if err := dec.Decode(&kv.V); err != nil { - return err - } - o.kv = append(o.kv, kv) - } - // unexpected error - if err != nil && !errors.Is(err, io.EOF) { - return err - } - return nil - case '[': - var res []*orderedMap - if err := json.Unmarshal(data, &res); err != nil { - return err - } - o.altVal = res - o.kv = nil - return nil - } - - return json.Unmarshal(data, &o.altVal) -} - -func (o orderedMap) MarshalJSON() ([]byte, error) { - buf := new(bytes.Buffer) - enc := json.NewEncoder(buf) - enc.SetEscapeHTML(false) // do not escape html chars e.g. &, <, > - if o.kv == nil { - if err := enc.Encode(o.altVal); err != nil { - return nil, err - } - return buf.Bytes(), nil - } - buf.WriteByte('{') - for idx, el := range o.kv { - if err := enc.Encode(el.K); err != nil { - return nil, err - } - buf.WriteByte(':') - if err := enc.Encode(el.V); err != nil { - return nil, err - } - if idx != len(o.kv)-1 { - buf.WriteByte(',') - } - } - buf.WriteByte('}') - return buf.Bytes(), nil -} diff --git a/pkg/yqlib/ordered_map_yaml.go b/pkg/yqlib/ordered_map_yaml.go deleted file mode 100644 index b3c494422e1..00000000000 --- a/pkg/yqlib/ordered_map_yaml.go +++ /dev/null @@ -1,79 +0,0 @@ -package yqlib - -import ( - "fmt" - - yaml "gopkg.in/yaml.v3" -) - -func (o *orderedMap) UnmarshalYAML(node *yaml.Node) error { - switch node.Kind { - case yaml.DocumentNode: - if len(node.Content) == 0 { - return nil - } - return o.UnmarshalYAML(node.Content[0]) - case yaml.AliasNode: - return o.UnmarshalYAML(node.Alias) - case yaml.ScalarNode: - return node.Decode(&o.altVal) - case yaml.MappingNode: - // set kv to non-nil - o.kv = []orderedMapKV{} - for i := 0; i < len(node.Content); i += 2 { - var key string - var val orderedMap - if err := node.Content[i].Decode(&key); err != nil { - return err - } - if err := node.Content[i+1].Decode(&val); err != nil { - return err - } - o.kv = append(o.kv, orderedMapKV{ - K: key, - V: val, - }) - } - return nil - case yaml.SequenceNode: - // note that this has to be a pointer, so that nulls can be represented. - var res []*orderedMap - if err := node.Decode(&res); err != nil { - return err - } - o.altVal = res - o.kv = nil - return nil - case 0: - // null - o.kv = nil - o.altVal = nil - return nil - default: - return fmt.Errorf("orderedMap: invalid yaml node") - } -} - -func (o *orderedMap) MarshalYAML() (interface{}, error) { - // fast path: kv is nil, use altVal - if o.kv == nil { - return o.altVal, nil - } - content := make([]*yaml.Node, 0, len(o.kv)*2) - for _, val := range o.kv { - n := new(yaml.Node) - if err := n.Encode(val.V); err != nil { - return nil, err - } - content = append(content, &yaml.Node{ - Kind: yaml.ScalarNode, - Tag: "!!str", - Value: val.K, - }, n) - } - return &yaml.Node{ - Kind: yaml.MappingNode, - Tag: "!!map", - Content: content, - }, nil -} diff --git a/pkg/yqlib/printer.go b/pkg/yqlib/printer.go index 8388b0d9cd5..decae59c9cb 100644 --- a/pkg/yqlib/printer.go +++ b/pkg/yqlib/printer.go @@ -7,8 +7,6 @@ import ( "fmt" "io" "regexp" - - yaml "gopkg.in/yaml.v3" ) type Printer interface { @@ -97,7 +95,7 @@ func (p *resultsPrinter) PrintedAnything() bool { return p.printedMatches } -func (p *resultsPrinter) printNode(node *yaml.Node, writer io.Writer) error { +func (p *resultsPrinter) printNode(node *CandidateNode, writer io.Writer) error { p.printedMatches = p.printedMatches || (node.Tag != "!!null" && (node.Tag != "!!bool" || node.Value != "false")) return p.encoder.Encode(writer, node) @@ -133,15 +131,15 @@ func (p *resultsPrinter) PrintResults(matchingNodes *list.List) error { if p.firstTimePrinting { node := matchingNodes.Front().Value.(*CandidateNode) - p.previousDocIndex = node.Document - p.previousFileIndex = node.FileIndex + p.previousDocIndex = node.GetDocument() + p.previousFileIndex = node.GetFileIndex() p.firstTimePrinting = false } for el := matchingNodes.Front(); el != nil; el = el.Next() { mappedDoc := el.Value.(*CandidateNode) - log.Debug("-- print sep logic: p.firstTimePrinting: %v, previousDocIndex: %v, mappedDoc.Document: %v", p.firstTimePrinting, p.previousDocIndex, mappedDoc.Document) + log.Debug("-- print sep logic: p.firstTimePrinting: %v, previousDocIndex: %v", p.firstTimePrinting, p.previousDocIndex) log.Debug("%v", NodeToString(mappedDoc)) writer, errorWriting := p.printerWriter.GetWriter(mappedDoc) if errorWriting != nil { @@ -151,7 +149,7 @@ func (p *resultsPrinter) PrintResults(matchingNodes *list.List) error { commentsStartWithSepExp := regexp.MustCompile(`^\$yqDocSeparator\$`) commentStartsWithSeparator := commentsStartWithSepExp.MatchString(mappedDoc.LeadingContent) - if (p.previousDocIndex != mappedDoc.Document || p.previousFileIndex != mappedDoc.FileIndex) && !commentStartsWithSeparator { + if (p.previousDocIndex != mappedDoc.GetDocument() || p.previousFileIndex != mappedDoc.GetFileIndex()) && !commentStartsWithSeparator { if err := p.encoder.PrintDocumentSeparator(writer); err != nil { return err } @@ -167,11 +165,7 @@ func (p *resultsPrinter) PrintResults(matchingNodes *list.List) error { return err } - if err := p.printNode(mappedDoc.Node, destination); err != nil { - return err - } - - if err := p.encoder.PrintLeadingContent(destination, mappedDoc.TrailingContent); err != nil { + if err := p.printNode(mappedDoc, destination); err != nil { return err } @@ -191,7 +185,7 @@ func (p *resultsPrinter) PrintResults(matchingNodes *list.List) error { } } - p.previousDocIndex = mappedDoc.Document + p.previousDocIndex = mappedDoc.GetDocument() if err := writer.Flush(); err != nil { return err } diff --git a/pkg/yqlib/printer_test.go b/pkg/yqlib/printer_test.go index fd6068f7997..75b6e5ff73a 100644 --- a/pkg/yqlib/printer_test.go +++ b/pkg/yqlib/printer_test.go @@ -125,20 +125,20 @@ func TestPrinterMultipleFilesInSequence(t *testing.T) { el := inputs.Front() elNode := el.Value.(*CandidateNode) - elNode.Document = 0 - elNode.FileIndex = 0 + elNode.document = 0 + elNode.fileIndex = 0 sample1 := nodeToList(elNode) el = el.Next() elNode = el.Value.(*CandidateNode) - elNode.Document = 0 - elNode.FileIndex = 1 + elNode.document = 0 + elNode.fileIndex = 1 sample2 := nodeToList(elNode) el = el.Next() elNode = el.Value.(*CandidateNode) - elNode.Document = 0 - elNode.FileIndex = 2 + elNode.document = 0 + elNode.fileIndex = 2 sample3 := nodeToList(elNode) err = printer.PrintResults(sample1) @@ -172,22 +172,22 @@ func TestPrinterMultipleFilesInSequenceWithLeadingContent(t *testing.T) { el := inputs.Front() elNode := el.Value.(*CandidateNode) - elNode.Document = 0 - elNode.FileIndex = 0 + elNode.document = 0 + elNode.fileIndex = 0 elNode.LeadingContent = "# go cats\n$yqDocSeparator$\n" sample1 := nodeToList(elNode) el = el.Next() elNode = el.Value.(*CandidateNode) - elNode.Document = 0 - elNode.FileIndex = 1 + elNode.document = 0 + elNode.fileIndex = 1 elNode.LeadingContent = "$yqDocSeparator$\n" sample2 := nodeToList(elNode) el = el.Next() elNode = el.Value.(*CandidateNode) - elNode.Document = 0 - elNode.FileIndex = 2 + elNode.document = 0 + elNode.fileIndex = 2 elNode.LeadingContent = "$yqDocSeparator$\n# cool\n" sample3 := nodeToList(elNode) diff --git a/pkg/yqlib/printer_writer.go b/pkg/yqlib/printer_writer.go index daa1078e3b9..d1b1e336fc2 100644 --- a/pkg/yqlib/printer_writer.go +++ b/pkg/yqlib/printer_writer.go @@ -6,8 +6,6 @@ import ( "io" "os" "regexp" - - "gopkg.in/yaml.v3" ) type PrinterWriter interface { @@ -56,17 +54,16 @@ func NewMultiPrinterWriter(expression *ExpressionNode, format PrinterOutputForma func (sp *multiPrintWriter) GetWriter(node *CandidateNode) (*bufio.Writer, error) { name := "" - indexVariableNode := yaml.Node{Kind: yaml.ScalarNode, Tag: "!!int", Value: fmt.Sprintf("%v", sp.index)} - indexVariableCandidate := CandidateNode{Node: &indexVariableNode} + indexVariableNode := CandidateNode{Kind: ScalarNode, Tag: "!!int", Value: fmt.Sprintf("%v", sp.index)} context := Context{MatchingNodes: node.AsList()} - context.SetVariable("index", indexVariableCandidate.AsList()) + context.SetVariable("index", indexVariableNode.AsList()) result, err := sp.treeNavigator.GetMatchingNodes(context, sp.nameExpression) if err != nil { return nil, err } if result.MatchingNodes.Len() > 0 { - name = result.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + name = result.MatchingNodes.Front().Value.(*CandidateNode).Value } var extensionRegexp = regexp.MustCompile(`\.[a-zA-Z0-9]+$`) if !extensionRegexp.MatchString(name) { diff --git a/pkg/yqlib/properties_test.go b/pkg/yqlib/properties_test.go index dcae4121b47..8ca996b011e 100644 --- a/pkg/yqlib/properties_test.go +++ b/pkg/yqlib/properties_test.go @@ -98,6 +98,16 @@ const expectedDecodedYaml = `person: - pizza ` +const expectedDecodedPersonYaml = `# block comments come through +# comments on values appear +name: Mike Wazowski +pets: + # comments on array values appear + - cat +food: + - pizza +` + const expectedPropertiesNoComments = `person.name = Mike Wazowski person.pets.0 = cat person.food.0 = pizza @@ -147,6 +157,32 @@ var propertyScenarios = []formatScenario{ expected: expectedDecodedYaml, scenarioType: "decode", }, + + { + skipDoc: true, + description: "Decode properties - keeps key information", + input: expectedPropertiesUnwrapped, + expression: ".person.name | key", + expected: "name\n", + scenarioType: "decode", + }, + { + skipDoc: true, + description: "Decode properties - keeps parent information", + input: expectedPropertiesUnwrapped, + expression: ".person.name | parent", + expected: expectedDecodedPersonYaml, + scenarioType: "decode", + }, + { + skipDoc: true, + description: "Decode properties - keeps path information", + input: expectedPropertiesUnwrapped, + expression: ".person.name | path", + expected: "- person\n- name\n", + scenarioType: "decode", + }, + { description: "Decode properties - array should be a map", subdescription: "If you have a numeric map key in your property files, use array_to_map to convert them to maps.", diff --git a/pkg/yqlib/recipes_test.go b/pkg/yqlib/recipes_test.go index c04fa1de707..2040eecf8dd 100644 --- a/pkg/yqlib/recipes_test.go +++ b/pkg/yqlib/recipes_test.go @@ -33,7 +33,7 @@ var recipes = []expressionScenario{ "See the [assign](https://mikefarah.gitbook.io/yq/operators/assign-update) and [add](https://mikefarah.gitbook.io/yq/operators/add) operators for more information.", }, expected: []string{ - "D0, P[], (doc)::[{name: Foo, numBuckets: 1}, {name: Bar, numBuckets: 0}]\n", + "D0, P[], (!!seq)::[{name: Foo, numBuckets: 1}, {name: Bar, numBuckets: 0}]\n", }, }, { @@ -48,7 +48,7 @@ var recipes = []expressionScenario{ "See the [with](https://mikefarah.gitbook.io/yq/operators/with) operator for more information and examples.", }, expected: []string{ - "D0, P[], (doc)::myArray: [{name: Foo - cat, type: cat}, {name: Bar - dog, type: dog}]\n", + "D0, P[], (!!map)::myArray: [{name: Foo - cat, type: cat}, {name: Bar - dog, type: dog}]\n", }, }, { @@ -61,7 +61,7 @@ var recipes = []expressionScenario{ "So, we use `|=` to update `.myArray`. This is the same as doing `.myArray = (.myArray | sort_by(.numBuckets))`", }, expected: []string{ - "D0, P[], (doc)::myArray: [{name: Bar, numBuckets: 0}, {name: Foo, numBuckets: 1}]\n", + "D0, P[], (!!map)::myArray: [{name: Bar, numBuckets: 0}, {name: Foo, numBuckets: 1}]\n", }, }, { diff --git a/pkg/yqlib/stream_evaluator.go b/pkg/yqlib/stream_evaluator.go index ef78ca982f2..0c9ad6dd4cf 100644 --- a/pkg/yqlib/stream_evaluator.go +++ b/pkg/yqlib/stream_evaluator.go @@ -6,8 +6,6 @@ import ( "fmt" "io" "os" - - yaml "gopkg.in/yaml.v3" ) // A yaml expression evaluator that runs the expression multiple times for each given yaml document. @@ -33,12 +31,7 @@ func (s *streamEvaluator) EvaluateNew(expression string, printer Printer) error if err != nil { return err } - candidateNode := &CandidateNode{ - Document: 0, - Filename: "", - Node: &yaml.Node{Kind: yaml.DocumentNode, Content: []*yaml.Node{{Tag: "!!null", Kind: yaml.ScalarNode}}}, - FileIndex: 0, - } + candidateNode := createScalarNode(nil, "") inputList := list.New() inputList.PushBack(candidateNode) @@ -98,9 +91,9 @@ func (s *streamEvaluator) Evaluate(filename string, reader io.Reader, node *Expr } else if errorReading != nil { return currentIndex, fmt.Errorf("bad file '%v': %w", filename, errorReading) } - candidateNode.Document = currentIndex - candidateNode.Filename = filename - candidateNode.FileIndex = s.fileIndex + candidateNode.document = currentIndex + candidateNode.filename = filename + candidateNode.fileIndex = s.fileIndex inputList := list.New() inputList.PushBack(candidateNode) diff --git a/pkg/yqlib/string_evaluator.go b/pkg/yqlib/string_evaluator.go index 59d451cae11..40970ffefd5 100644 --- a/pkg/yqlib/string_evaluator.go +++ b/pkg/yqlib/string_evaluator.go @@ -53,8 +53,8 @@ func (s *stringEvaluator) Evaluate(expression string, input string, encoder Enco } else if errorReading != nil { return "", fmt.Errorf("bad input '%v': %w", input, errorReading) } - candidateNode.Document = currentIndex - candidateNode.FileIndex = s.fileIndex + candidateNode.document = currentIndex + candidateNode.fileIndex = s.fileIndex inputList := list.New() inputList.PushBack(candidateNode) diff --git a/pkg/yqlib/toml_test.go b/pkg/yqlib/toml_test.go index f55d2fdfff3..2e0765dc020 100644 --- a/pkg/yqlib/toml_test.go +++ b/pkg/yqlib/toml_test.go @@ -94,6 +94,30 @@ var tomlScenarios = []formatScenario{ expected: "person:\n name: hello\n address: 12 cat st\n", scenarioType: "decode", }, + { + skipDoc: true, + description: "Parse: include key information", + input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n", + expression: ".person.name | key", + expected: "name\n", + scenarioType: "roundtrip", + }, + { + skipDoc: true, + description: "Parse: include parent information", + input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n", + expression: ".person.name | parent", + expected: "name: hello\naddress: 12 cat st\n", + scenarioType: "decode", + }, + { + skipDoc: true, + description: "Parse: include path information", + input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n", + expression: ".person.name | path", + expected: "- person\n- name\n", + scenarioType: "decode", + }, { description: "Encode: Scalar", input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n", diff --git a/pkg/yqlib/utils.go b/pkg/yqlib/utils.go index d800e3b110f..3ce2de1235a 100644 --- a/pkg/yqlib/utils.go +++ b/pkg/yqlib/utils.go @@ -51,9 +51,9 @@ func readDocuments(reader io.Reader, filename string, fileIndex int, decoder Dec } else if errorReading != nil { return nil, fmt.Errorf("bad file '%v': %w", filename, errorReading) } - candidateNode.Document = currentIndex - candidateNode.Filename = filename - candidateNode.FileIndex = fileIndex + candidateNode.document = currentIndex + candidateNode.filename = filename + candidateNode.fileIndex = fileIndex candidateNode.EvaluateTogether = true inputList.PushBack(candidateNode) diff --git a/pkg/yqlib/xml_test.go b/pkg/yqlib/xml_test.go index 0f74ab10efa..8194f38cb22 100644 --- a/pkg/yqlib/xml_test.go +++ b/pkg/yqlib/xml_test.go @@ -364,11 +364,10 @@ var xmlScenarios = []formatScenario{ expected: "zoo:\n animal:\n - cat\n", }, { - description: "Parse xml: force all as an array", - subdescription: "Because of the way yq works, when updating everything you need to update the children before the parents. By default `..` will match parents first, so we reverse that before updating.", - input: "boing", - expression: "([..] | reverse | .[]) |= [] + .", - expected: "- zoo:\n - thing:\n - frog:\n - boing\n", + description: "Parse xml: force all as an array", + input: "boing", + expression: ".. |= [] + .", + expected: "- zoo:\n - thing:\n - frog:\n - boing\n", }, { description: "Parse xml: attributes", @@ -537,13 +536,6 @@ var xmlScenarios = []formatScenario{ expectedError: "cannot encode !!seq to XML - only maps can be encoded", scenarioType: "encode-error", }, - { - description: "scalars cannot be encoded", - skipDoc: true, - input: "mike", - expectedError: "cannot encode !!str to XML - only maps can be encoded", - scenarioType: "encode-error", - }, { description: "Encode xml: attributes with content", subdescription: "Fields with the matching xml-content-name is assumed to be content.", diff --git a/pkg/yqlib/yaml_test.go b/pkg/yqlib/yaml_test.go new file mode 100644 index 00000000000..0d75433f3f9 --- /dev/null +++ b/pkg/yqlib/yaml_test.go @@ -0,0 +1,109 @@ +package yqlib + +import ( + "testing" + + "github.com/mikefarah/yq/v4/test" +) + +var yamlFormatScenarios = []formatScenario{ + { + description: "basic - null", + skipDoc: true, + input: "null", + expected: "null\n", + }, + { + description: "basic - ~", + skipDoc: true, + input: "~", + expected: "~\n", + }, + { + description: "octal", + skipDoc: true, + input: "0o30", + expression: "tag", + expected: "!!int\n", + }, + { + description: "basic - [null]", + skipDoc: true, + input: "[null]", + expected: "[null]\n", + }, + { + description: "basic - [~]", + skipDoc: true, + input: "[~]", + expected: "[~]\n", + }, + { + description: "basic - null map value", + skipDoc: true, + input: "a: null", + expected: "a: null\n", + }, + { + description: "basic - number", + skipDoc: true, + input: "3", + expected: "3\n", + }, + { + description: "basic - float", + skipDoc: true, + input: "3.1", + expected: "3.1\n", + }, + { + description: "basic - float", + skipDoc: true, + input: "[1, 2]", + expected: "[1, 2]\n", + }, +} + +var yamlParseScenarios = []expressionScenario{ + { + document: `a: hello # things`, + expected: []string{ + "D0, P[], (!!map)::a: hello # things\n", + }, + }, + { + document: "a: &a apple\nb: *a", + expression: ".b | explode(.)", + expected: []string{ + "D0, P[b], (!!str)::apple\n", + }, + }, + { + document: `a: [1,2]`, + expected: []string{ + "D0, P[], (!!map)::a: [1, 2]\n", + }, + }, + { + document: `a: !horse [a]`, + expected: []string{ + "D0, P[], (!!map)::a: !horse [a]\n", + }, + }, +} + +func testYamlScenario(t *testing.T, s formatScenario) { + test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewYamlDecoder(NewDefaultYamlPreferences()), NewYamlEncoder(2, false, ConfiguredYamlPreferences)), s.description) +} + +func TestYamlParseScenarios(t *testing.T) { + for _, tt := range yamlParseScenarios { + testScenario(t, &tt) + } +} + +func TestYamlFormatScenarios(t *testing.T) { + for _, tt := range yamlFormatScenarios { + testYamlScenario(t, tt) + } +} diff --git a/project-words.txt b/project-words.txt index 2371c1fb124..a68e75424cb 100644 --- a/project-words.txt +++ b/project-words.txt @@ -249,4 +249,5 @@ yamld yqlib yuin zabbix -tonumber \ No newline at end of file +tonumber +noyaml \ No newline at end of file diff --git a/test/utils.go b/test/utils.go index f270c5b3b4b..70454f73074 100644 --- a/test/utils.go +++ b/test/utils.go @@ -4,25 +4,13 @@ import ( "bufio" "bytes" "fmt" - "os" "reflect" "testing" "github.com/pkg/diff" "github.com/pkg/diff/write" - yaml "gopkg.in/yaml.v3" ) -func ParseData(rawData string) yaml.Node { - var parsedData yaml.Node - err := yaml.Unmarshal([]byte(rawData), &parsedData) - if err != nil { - fmt.Printf("Error parsing yaml: %v\n", err) - os.Exit(1) - } - return parsedData -} - func printDifference(t *testing.T, expectedValue interface{}, actualValue interface{}) { opts := []write.Option{write.TerminalColor()} var differenceBuffer bytes.Buffer