diff --git a/pkg/yqlib/candidate_node.go b/pkg/yqlib/candidate_node.go index 9f3c1d92..1edac4f5 100644 --- a/pkg/yqlib/candidate_node.go +++ b/pkg/yqlib/candidate_node.go @@ -239,9 +239,6 @@ func (n *CandidateNode) CreateReplacementWithDocWrappers(kind Kind, tag string, } func (n *CandidateNode) CopyChildren() []*CandidateNode { - log.Debug("n? %v", n) - log.Debug("n.Content %v", n.Content) - log.Debug("n.Content %v", len(n.Content)) clonedKids := make([]*CandidateNode, len(n.Content)) log.Debug("created clone") for i, child := range n.Content { diff --git a/pkg/yqlib/candidate_node_yaml.go b/pkg/yqlib/candidate_node_yaml.go index c1621686..7cd8cc14 100644 --- a/pkg/yqlib/candidate_node_yaml.go +++ b/pkg/yqlib/candidate_node_yaml.go @@ -230,8 +230,6 @@ func (o *CandidateNode) MarshalYAML() (*yaml.Node, error) { if err != nil { return nil, err } - log.Debug("child type %v", child.Tag) - log.Debug("child is doc %v", child.Kind == yaml.DocumentNode) target.Content[i] = child } return target, nil diff --git a/pkg/yqlib/doc/operators/anchor-and-alias-operators.md b/pkg/yqlib/doc/operators/anchor-and-alias-operators.md index bf100c2b..80e22f85 100644 --- a/pkg/yqlib/doc/operators/anchor-and-alias-operators.md +++ b/pkg/yqlib/doc/operators/anchor-and-alias-operators.md @@ -5,299 +5,3 @@ Use the `alias` and `anchor` operators to read and write yaml aliases and anchor `yq` supports merge aliases (like `<<: *blah`) however this is no longer in the standard yaml spec (1.2) and so `yq` will automatically add the `!!merge` tag to these nodes as it is effectively a custom tag. -## Merge one map -see https://yaml.org/type/merge.html - -Given a sample.yml file of: -```yaml -- &CENTER - x: 1 - y: 2 -- &LEFT - x: 0 - y: 2 -- &BIG - r: 10 -- &SMALL - r: 1 -- !!merge <<: *CENTER - r: 10 -``` -then -```bash -yq '.[4] | explode(.)' sample.yml -``` -will output -```yaml -x: 1 -y: 2 -r: 10 -``` - -## Merge multiple maps -see https://yaml.org/type/merge.html - -Given a sample.yml file of: -```yaml -- &CENTER - x: 1 - y: 2 -- &LEFT - x: 0 - y: 2 -- &BIG - r: 10 -- &SMALL - r: 1 -- !!merge <<: - - *CENTER - - *BIG -``` -then -```bash -yq '.[4] | explode(.)' sample.yml -``` -will output -```yaml -r: 10 -x: 1 -y: 2 -``` - -## Override -see https://yaml.org/type/merge.html - -Given a sample.yml file of: -```yaml -- &CENTER - x: 1 - y: 2 -- &LEFT - x: 0 - y: 2 -- &BIG - r: 10 -- &SMALL - r: 1 -- !!merge <<: - - *BIG - - *LEFT - - *SMALL - x: 1 -``` -then -```bash -yq '.[4] | explode(.)' sample.yml -``` -will output -```yaml -r: 10 -x: 1 -y: 2 -``` - -## Get anchor -Given a sample.yml file of: -```yaml -a: &billyBob cat -``` -then -```bash -yq '.a | anchor' sample.yml -``` -will output -```yaml -billyBob -``` - -## Set anchor -Given a sample.yml file of: -```yaml -a: cat -``` -then -```bash -yq '.a anchor = "foobar"' sample.yml -``` -will output -```yaml -a: &foobar cat -``` - -## Set anchor relatively using assign-update -Given a sample.yml file of: -```yaml -a: - b: cat -``` -then -```bash -yq '.a anchor |= .b' sample.yml -``` -will output -```yaml -a: &cat - b: cat -``` - -## Get alias -Given a sample.yml file of: -```yaml -b: &billyBob meow -a: *billyBob -``` -then -```bash -yq '.a | alias' sample.yml -``` -will output -```yaml -billyBob -``` - -## Set alias -Given a sample.yml file of: -```yaml -b: &meow purr -a: cat -``` -then -```bash -yq '.a alias = "meow"' sample.yml -``` -will output -```yaml -b: &meow purr -a: *meow -``` - -## Set alias to blank does nothing -Given a sample.yml file of: -```yaml -b: &meow purr -a: cat -``` -then -```bash -yq '.a alias = ""' sample.yml -``` -will output -```yaml -b: &meow purr -a: cat -``` - -## Set alias relatively using assign-update -Given a sample.yml file of: -```yaml -b: &meow purr -a: - f: meow -``` -then -```bash -yq '.a alias |= .f' sample.yml -``` -will output -```yaml -b: &meow purr -a: *meow -``` - -## Explode alias and anchor -Given a sample.yml file of: -```yaml -f: - a: &a cat - b: *a -``` -then -```bash -yq 'explode(.f)' sample.yml -``` -will output -```yaml -f: - a: cat - b: cat -``` - -## Explode with no aliases or anchors -Given a sample.yml file of: -```yaml -a: mike -``` -then -```bash -yq 'explode(.a)' sample.yml -``` -will output -```yaml -a: mike -``` - -## Explode with alias keys -Given a sample.yml file of: -```yaml -f: - a: &a cat - *a: b -``` -then -```bash -yq 'explode(.f)' sample.yml -``` -will output -```yaml -f: - a: cat - cat: b -``` - -## Explode with merge anchors -Given a sample.yml file of: -```yaml -foo: &foo - a: foo_a - thing: foo_thing - c: foo_c -bar: &bar - b: bar_b - thing: bar_thing - c: bar_c -foobarList: - b: foobarList_b - !!merge <<: - - *foo - - *bar - c: foobarList_c -foobar: - c: foobar_c - !!merge <<: *foo - thing: foobar_thing -``` -then -```bash -yq 'explode(.)' sample.yml -``` -will output -```yaml -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 -``` - diff --git a/pkg/yqlib/encoder_yaml.go b/pkg/yqlib/encoder_yaml.go index bf2e2cd5..64ea9498 100644 --- a/pkg/yqlib/encoder_yaml.go +++ b/pkg/yqlib/encoder_yaml.go @@ -75,7 +75,6 @@ func (ye *yamlEncoder) PrintLeadingContent(writer io.Writer, content string) err func (ye *yamlEncoder) Encode(writer io.Writer, node *CandidateNode) error { log.Debug("encoderYaml - going to print %v", NodeToString(node)) - log.Debug("encoderYaml - going to print u %v", NodeToString(node.unwrapDocument())) if node.Kind == ScalarNode && ye.prefs.UnwrapScalar { return writeString(writer, node.Value+"\n") } diff --git a/pkg/yqlib/lib.go b/pkg/yqlib/lib.go index ba9d9e52..f493870d 100644 --- a/pkg/yqlib/lib.go +++ b/pkg/yqlib/lib.go @@ -440,7 +440,11 @@ func NodeToString(node *CandidateNode) string { } else if node.Kind == AliasNode { tag = "alias" } - return fmt.Sprintf(`D%v, P%v, %v (%v)::%v`, node.Document, node.GetNicePath(), KindString(node.Kind), tag, node.Value) + valueToUse := node.Value + if valueToUse == "" { + valueToUse = fmt.Sprintf("%v kids", len(node.Content)) + } + return fmt.Sprintf(`D%v, P%v, %v (%v)::%v`, node.Document, node.GetNicePath(), KindString(node.Kind), tag, valueToUse) } func KindString(kind Kind) string { switch kind { diff --git a/pkg/yqlib/operator_anchors_aliases.go b/pkg/yqlib/operator_anchors_aliases.go index ddb21520..83c0693f 100644 --- a/pkg/yqlib/operator_anchors_aliases.go +++ b/pkg/yqlib/operator_anchors_aliases.go @@ -181,11 +181,12 @@ func reconstructAliasedMap(node *CandidateNode, context Context) error { } func explodeNode(node *CandidateNode, context Context) error { + log.Debugf("explodeNode - %v", NodeToString(node)) node.Anchor = "" switch node.Kind { case SequenceNode, DocumentNode: 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 @@ -193,15 +194,16 @@ func explodeNode(node *CandidateNode, context Context) error { } return nil case AliasNode: - log.Debugf("its an alias!") + 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 = node.CopyChildren() + node.Content = node.Alias.CopyChildren() node.Value = node.Alias.Value node.Alias = nil } + log.Debug("now I'm %v", NodeToString(node)) return nil case MappingNode: // //check the map has an alias in it diff --git a/pkg/yqlib/operator_anchors_aliases_test.go b/pkg/yqlib/operator_anchors_aliases_test.go index 743bea44..d6d17153 100644 --- a/pkg/yqlib/operator_anchors_aliases_test.go +++ b/pkg/yqlib/operator_anchors_aliases_test.go @@ -35,211 +35,204 @@ thingTwo: ` var anchorOperatorScenarios = []expressionScenario{ - { - skipDoc: true, - description: "merge anchor not map", - document: "a: &a\n - 500\nc:\n <<: [*a]\n", - expectedError: "merge anchor only supports maps, got !!seq instead", - expression: "explode(.)", - }, - { - description: "Merge one map", - subdescription: "see https://yaml.org/type/merge.html", - document: specDocument + "- << : *CENTER\n r: 10\n", - expression: ".[4] | explode(.)", - expected: []string{expectedSpecResult}, - }, - { - description: "Merge multiple maps", - subdescription: "see https://yaml.org/type/merge.html", - document: specDocument + "- << : [ *CENTER, *BIG ]\n", - expression: ".[4] | explode(.)", - expected: []string{"D0, P[4], (!!map)::r: 10\nx: 1\ny: 2\n"}, - }, - { - description: "Override", - subdescription: "see https://yaml.org/type/merge.html", - document: specDocument + "- << : [ *BIG, *LEFT, *SMALL ]\n x: 1\n", - expression: ".[4] | explode(.)", - expected: []string{"D0, P[4], (!!map)::r: 10\nx: 1\ny: 2\n"}, - }, - { - description: "Get anchor", - document: `a: &billyBob cat`, - expression: `.a | anchor`, - expected: []string{ - "D0, P[a], (!!str)::billyBob\n", - }, - }, - { - description: "Set anchor", - document: `a: cat`, - expression: `.a anchor = "foobar"`, - expected: []string{ - "D0, P[], (doc)::a: &foobar cat\n", - }, - }, - { - description: "Set anchor relatively using assign-update", - document: `a: {b: cat}`, - expression: `.a anchor |= .b`, - expected: []string{ - "D0, P[], (doc)::a: &cat {b: cat}\n", - }, - }, - { - skipDoc: true, - document: `a: {c: cat}`, - expression: `.a anchor |= .b`, - expected: []string{ - "D0, P[], (doc)::a: {c: cat}\n", - }, - }, - { - skipDoc: true, - document: `a: {c: cat}`, - expression: `.a anchor = .b`, - expected: []string{ - "D0, P[], (doc)::a: {c: cat}\n", - }, - }, - { - description: "Get alias", - document: `{b: &billyBob meow, a: *billyBob}`, - expression: `.a | alias`, - expected: []string{ - "D0, P[a], (!!str)::billyBob\n", - }, - }, - { - description: "Set alias", - document: `{b: &meow purr, a: cat}`, - expression: `.a alias = "meow"`, - expected: []string{ - "D0, P[], (doc)::{b: &meow purr, a: *meow}\n", - }, - }, - { - description: "Set alias to blank does nothing", - document: `{b: &meow purr, a: cat}`, - expression: `.a alias = ""`, - expected: []string{ - "D0, P[], (doc)::{b: &meow purr, a: cat}\n", - }, - }, - { - skipDoc: true, - document: `{b: &meow purr, a: cat}`, - expression: `.a alias = .c`, - expected: []string{ - "D0, P[], (doc)::{b: &meow purr, a: cat}\n", - }, - }, - { - skipDoc: true, - document: `{b: &meow purr, a: cat}`, - expression: `.a alias |= .c`, - expected: []string{ - "D0, P[], (doc)::{b: &meow purr, a: cat}\n", - }, - }, - { - description: "Set alias relatively using assign-update", - document: `{b: &meow purr, a: {f: meow}}`, - expression: `.a alias |= .f`, - expected: []string{ - "D0, P[], (doc)::{b: &meow purr, a: *meow}\n", - }, - }, - { - description: "Explode alias and anchor", - document: `{f : {a: &a cat, b: *a}}`, - expression: `explode(.f)`, - expected: []string{ - "D0, P[], (doc)::{f: {a: cat, b: cat}}\n", - }, - }, - { - description: "Explode with no aliases or anchors", - document: `a: mike`, - expression: `explode(.a)`, - expected: []string{ - "D0, P[], (doc)::a: mike\n", - }, - }, - { - description: "Explode with alias keys", - document: `{f : {a: &a cat, *a: b}}`, - expression: `explode(.f)`, - expected: []string{ - "D0, P[], (doc)::{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 - - `}, - }, - // { - // skipDoc: true, - // document: mergeDocSample, - // expression: `.foo* | explode(.) | (. style="flow")`, - // expected: []string{ - // "D0, P[foo], (!!map)::{a: foo_a, thing: foo_thing, c: foo_c}\n", - // "D0, P[foobarList], (!!map)::{b: bar_b, thing: foo_thing, c: foobarList_c, a: foo_a}\n", - // "D0, P[foobar], (!!map)::{c: foo_c, a: foo_a, thing: foobar_thing}\n", + // { + // skipDoc: true, + // description: "merge anchor not map", + // document: "a: &a\n - 0\nc:\n <<: [*a]\n", + // expectedError: "merge anchor only supports maps, got !!seq instead", + // expression: "explode(.)", // }, - // }, - // { - // skipDoc: true, - // document: mergeDocSample, - // expression: `.foo* | explode(explode(.)) | (. style="flow")`, - // expected: []string{ - // "D0, P[foo], (!!map)::{a: foo_a, thing: foo_thing, c: foo_c}\n", - // "D0, P[foobarList], (!!map)::{b: bar_b, thing: foo_thing, c: foobarList_c, a: foo_a}\n", - // "D0, P[foobar], (!!map)::{c: foo_c, a: foo_a, thing: foobar_thing}\n", + // { + // description: "Merge one map", + // subdescription: "see https://yaml.org/type/merge.html", + // document: specDocument + "- << : *CENTER\n r: 10\n", + // expression: ".[4] | explode(.)", + // expected: []string{expectedSpecResult}, + // }, + // { + // description: "Merge multiple maps", + // subdescription: "see https://yaml.org/type/merge.html", + // document: specDocument + "- << : [ *CENTER, *BIG ]\n", + // expression: ".[4] | explode(.)", + // expected: []string{"D0, P[4], (!!map)::r: 10\nx: 1\ny: 2\n"}, + // }, + // { + // description: "Override", + // subdescription: "see https://yaml.org/type/merge.html", + // document: specDocument + "- << : [ *BIG, *LEFT, *SMALL ]\n x: 1\n", + // expression: ".[4] | explode(.)", + // expected: []string{"D0, P[4], (!!map)::r: 10\nx: 1\ny: 2\n"}, + // }, + // { + // description: "Get anchor", + // document: `a: &billyBob cat`, + // expression: `.a | anchor`, + // expected: []string{ + // "D0, P[a], (!!str)::billyBob\n", + // }, + // }, + // { + // description: "Set anchor", + // document: `a: cat`, + // expression: `.a anchor = "foobar"`, + // expected: []string{ + // "D0, P[], (doc)::a: &foobar cat\n", + // }, + // }, + // { + // description: "Set anchor relatively using assign-update", + // document: `a: {b: cat}`, + // expression: `.a anchor |= .b`, + // expected: []string{ + // "D0, P[], (doc)::a: &cat {b: cat}\n", + // }, + // }, + // { + // skipDoc: true, + // document: `a: {c: cat}`, + // expression: `.a anchor |= .b`, + // expected: []string{ + // "D0, P[], (doc)::a: {c: cat}\n", + // }, + // }, + // { + // skipDoc: true, + // document: `a: {c: cat}`, + // expression: `.a anchor = .b`, + // expected: []string{ + // "D0, P[], (doc)::a: {c: cat}\n", + // }, + // }, + // { + // description: "Get alias", + // document: `{b: &billyBob meow, a: *billyBob}`, + // expression: `.a | alias`, + // expected: []string{ + // "D0, P[a], (!!str)::billyBob\n", + // }, + // }, + // { + // description: "Set alias", + // document: `{b: &meow purr, a: cat}`, + // expression: `.a alias = "meow"`, + // expected: []string{ + // "D0, P[], (doc)::{b: &meow purr, a: *meow}\n", + // }, + // }, + // { + // description: "Set alias to blank does nothing", + // document: `{b: &meow purr, a: cat}`, + // expression: `.a alias = ""`, + // expected: []string{ + // "D0, P[], (doc)::{b: &meow purr, a: cat}\n", + // }, + // }, + // { + // skipDoc: true, + // document: `{b: &meow purr, a: cat}`, + // expression: `.a alias = .c`, + // expected: []string{ + // "D0, P[], (doc)::{b: &meow purr, a: cat}\n", + // }, + // }, + // { + // skipDoc: true, + // document: `{b: &meow purr, a: cat}`, + // expression: `.a alias |= .c`, + // expected: []string{ + // "D0, P[], (doc)::{b: &meow purr, a: cat}\n", + // }, + // }, + // { + // description: "Set alias relatively using assign-update", + // document: `{b: &meow purr, a: {f: meow}}`, + // expression: `.a alias |= .f`, + // expected: []string{ + // "D0, P[], (doc)::{b: &meow purr, a: *meow}\n", + // }, + // }, + // { + // description: "Explode alias and anchor", + // document: `{f : {a: &a cat, b: *a}}`, + // expression: `explode(.f)`, + // expected: []string{ + // "D0, P[], (doc)::{f: {a: cat, b: cat}}\n", + // }, + // }, + // { + // description: "Explode with no aliases or anchors", + // document: `a: mike`, + // expression: `explode(.a)`, + // expected: []string{ + // "D0, P[], (doc)::a: mike\n", + // }, + // }, + // { + // description: "Explode with alias keys", + // document: `{f : {a: &a cat, *a: b}}`, + // expression: `explode(.f)`, + // expected: []string{ + // "D0, P[], (doc)::{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 + // `}, + // }, + // { + // skipDoc: true, + // document: mergeDocSample, + // expression: `.foo* | explode(.) | (. style="flow")`, + // expected: []string{ + // "D0, P[foo], (!!map)::{a: foo_a, thing: foo_thing, c: foo_c}\n", + // "D0, P[foobarList], (!!map)::{b: bar_b, thing: foo_thing, c: foobarList_c, a: foo_a}\n", + // "D0, P[foobar], (!!map)::{c: foo_c, a: foo_a, thing: foobar_thing}\n", + // }, + // }, + // { + // skipDoc: true, + // document: mergeDocSample, + // expression: `.foo* | explode(explode(.)) | (. style="flow")`, + // expected: []string{ + // "D0, P[foo], (!!map)::{a: foo_a, thing: foo_thing, c: foo_c}\n", + // "D0, P[foobarList], (!!map)::{b: bar_b, thing: foo_thing, c: foobarList_c, a: foo_a}\n", + // "D0, P[foobar], (!!map)::{c: foo_c, a: foo_a, thing: foobar_thing}\n", + // }, // }, - // }, // { // 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[], (doc)::{f: {a: cat, b: {foo: cat}, cat: {foo: cat}}}\n", // }, // }, - // { - // description: "Dereference and update a field", - // subdescription: "Use explode with multiply to dereference an object", - // document: simpleArrayRef, - // expression: `.thingOne |= explode(.) * {"value": false}`, - // expected: []string{expectedUpdatedArrayRef}, - // }, + { + description: "Dereference and update a field", + subdescription: "Use explode with multiply to dereference an object", + document: simpleArrayRef, + expression: `.thingOne |= explode(.) * {"value": false}`, + expected: []string{expectedUpdatedArrayRef}, + }, } func TestAnchorAliasOperatorScenarios(t *testing.T) { diff --git a/pkg/yqlib/operator_traverse_path.go b/pkg/yqlib/operator_traverse_path.go index dd8dfe8e..5748644e 100644 --- a/pkg/yqlib/operator_traverse_path.go +++ b/pkg/yqlib/operator_traverse_path.go @@ -244,11 +244,9 @@ func traverseMap(context Context, matchingNode *CandidateNode, keyNode *Candidat matchingNode.Content = append(matchingNode.Content, keyNode, valueNode) if prefs.IncludeMapKeys { - log.Debug("including key") newMatches.Set(keyNode.GetKey(), keyNode) } if !prefs.DontIncludeMapValues { - log.Debug("including value") newMatches.Set(valueNode.GetKey(), valueNode) } }