diff --git a/pkg/yqlib/operator_anchors_aliases.go b/pkg/yqlib/operator_anchors_aliases.go index caaf364b..9dbd51c0 100644 --- a/pkg/yqlib/operator_anchors_aliases.go +++ b/pkg/yqlib/operator_anchors_aliases.go @@ -18,7 +18,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 +38,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 +56,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 +74,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 +95,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 +110,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 +129,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 +140,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 +155,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,19 +173,19 @@ func reconstructAliasedMap(node *yaml.Node, context Context) error { } } } - node.Content = make([]*yaml.Node, newContent.Len()) + node.Content = make([]*CandidateNode, newContent.Len()) index := 0 for newEl := newContent.Front(); newEl != nil; newEl = newEl.Next() { - node.Content[index] = newEl.Value.(*yaml.Node) + node.Content[index] = newEl.Value.(*CandidateNode) index++ } return nil } -func explodeNode(node *yaml.Node, context Context) error { +func explodeNode(node *CandidateNode, context Context) error { node.Anchor = "" switch node.Kind { - case yaml.SequenceNode, yaml.DocumentNode: + case SequenceNode, DocumentNode: for index, contentNode := range node.Content { log.Debugf("exploding index %v", index) errorInContent := explodeNode(contentNode, context) @@ -196,18 +194,18 @@ func explodeNode(node *yaml.Node, context Context) error { } } return nil - case yaml.AliasNode: + case AliasNode: log.Debugf("its an 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.Content = node.CopyChildren() node.Value = node.Alias.Value node.Alias = nil } 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 +239,11 @@ 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 { if alias == nil { return nil } - if alias.Kind != yaml.MappingNode { + 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) diff --git a/pkg/yqlib/operator_strings.go b/pkg/yqlib/operator_strings.go index 716620fe..58b0760a 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 { @@ -18,15 +16,15 @@ func trimSpaceOperator(d *dataTreeNavigator, context Context, expressionNode *Ex for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) + node := candidate.unwrapDocument() - 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 := candidate.CreateReplacement(ScalarNode, node.Tag, strings.TrimSpace(node.Value)) + newStringNode.Style = node.Style + results.PushBack(newStringNode) } @@ -40,19 +38,21 @@ func changeCaseOperator(d *dataTreeNavigator, context Context, expressionNode *E for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) + node := candidate.unwrapDocument() - 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 := candidate.CreateReplacement(ScalarNode, node.Tag, value) + newStringNode.Style = node.Style + results.PushBack(newStringNode) } @@ -69,7 +69,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 +79,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) { @@ -111,14 +111,13 @@ func substituteStringOperator(d *dataTreeNavigator, context Context, expressionN for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) + node := candidate.unwrapDocument() - if guessTagFromCustomType(node) != "!!str" { + 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 := candidate.CreateReplacement(substitute(node.Value, regEx, replacementText)) results.PushBack(result) } @@ -126,7 +125,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 +187,21 @@ 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 := &CandidateNode{Kind: MappingNode} captureNode.Content = addMatch(captureNode.Content, submatch, allIndices[i][2+j*2], subNames[j+1]) capturesListNode.Content = append(capturesListNode.Content, captureNode) } - node := &yaml.Node{Kind: yaml.MappingNode} + node := candidate.CreateReplacement(MappingNode, "!!map", "") node.Content = addMatch(node.Content, match, allIndices[i][0], "") node.Content = append(node.Content, createScalarNode("captures", "captures"), capturesListNode, ) - results.PushBack(candidate.CreateReplacement(node)) + results.PushBack(node) } @@ -219,7 +218,7 @@ 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 { @@ -239,7 +238,7 @@ func capture(matchPrefs matchPreferences, regEx *regexp.Regexp, candidate *Candi } } - results.PushBack(candidate.CreateReplacement(capturesNode)) + results.PushBack(capturesNode) } @@ -260,7 +259,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 +280,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) @@ -298,9 +297,9 @@ func matchOperator(d *dataTreeNavigator, context Context, expressionNode *Expres for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) + node := candidate.unwrapDocument() - if guessTagFromCustomType(node) != "!!str" { + 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) } @@ -320,9 +319,9 @@ func captureOperator(d *dataTreeNavigator, context Context, expressionNode *Expr for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) + node := candidate.unwrapDocument() - if guessTagFromCustomType(node) != "!!str" { + 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) @@ -342,9 +341,9 @@ func testOperator(d *dataTreeNavigator, context Context, expressionNode *Express for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) + node := candidate.unwrapDocument() - if guessTagFromCustomType(node) != "!!str" { + 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) @@ -364,26 +363,25 @@ 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 := candidate.unwrapDocument() + 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 := candidate.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 +391,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 +403,42 @@ 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 := candidate.unwrapDocument() if node.Tag == "!!null" { continue } - if guessTagFromCustomType(node) != "!!str" { + 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 := candidate.CreateReplacement(kind, tag, "") + result.Content = 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 }