path.go raw
1 package yaml
2
3 import (
4 "bytes"
5 "fmt"
6 "io"
7 "strconv"
8 "strings"
9
10 "github.com/goccy/go-yaml/ast"
11 "github.com/goccy/go-yaml/internal/errors"
12 "github.com/goccy/go-yaml/parser"
13 "github.com/goccy/go-yaml/printer"
14 )
15
16 // PathString create Path from string
17 //
18 // YAMLPath rule
19 // $ : the root object/element
20 // . : child operator
21 // .. : recursive descent
22 // [num] : object/element of array by number
23 // [*] : all objects/elements for array.
24 //
25 // If you want to use reserved characters such as `.` and `*` as a key name,
26 // enclose them in single quotation as follows ( $.foo.'bar.baz-*'.hoge ).
27 // If you want to use a single quote with reserved characters, escape it with `\` ( $.foo.'bar.baz\'s value'.hoge ).
28 func PathString(s string) (*Path, error) {
29 buf := []rune(s)
30 length := len(buf)
31 cursor := 0
32 builder := &PathBuilder{}
33 for cursor < length {
34 c := buf[cursor]
35 switch c {
36 case '$':
37 builder = builder.Root()
38 cursor++
39 case '.':
40 b, buf, c, err := parsePathDot(builder, buf, cursor)
41 if err != nil {
42 return nil, errors.Wrapf(err, "failed to parse path of dot")
43 }
44 length = len(buf)
45 builder = b
46 cursor = c
47 case '[':
48 b, buf, c, err := parsePathIndex(builder, buf, cursor)
49 if err != nil {
50 return nil, errors.Wrapf(err, "failed to parse path of index")
51 }
52 length = len(buf)
53 builder = b
54 cursor = c
55 default:
56 return nil, errors.Wrapf(ErrInvalidPathString, "invalid path at %d", cursor)
57 }
58 }
59 return builder.Build(), nil
60 }
61
62 func parsePathRecursive(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
63 length := len(buf)
64 cursor += 2 // skip .. characters
65 start := cursor
66 for ; cursor < length; cursor++ {
67 c := buf[cursor]
68 switch c {
69 case '$':
70 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '$' after '..' character")
71 case '*':
72 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '*' after '..' character")
73 case '.', '[':
74 goto end
75 case ']':
76 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified ']' after '..' character")
77 }
78 }
79 end:
80 if start == cursor {
81 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "not found recursive selector")
82 }
83 return b.Recursive(string(buf[start:cursor])), buf, cursor, nil
84 }
85
86 func parsePathDot(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
87 length := len(buf)
88 if cursor+1 < length && buf[cursor+1] == '.' {
89 b, buf, c, err := parsePathRecursive(b, buf, cursor)
90 if err != nil {
91 return nil, nil, 0, errors.Wrapf(err, "failed to parse path of recursive")
92 }
93 return b, buf, c, nil
94 }
95 cursor++ // skip . character
96 start := cursor
97
98 // if started single quote, looking for end single quote char
99 if cursor < length && buf[cursor] == '\'' {
100 return parseQuotedKey(b, buf, cursor)
101 }
102 for ; cursor < length; cursor++ {
103 c := buf[cursor]
104 switch c {
105 case '$':
106 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '$' after '.' character")
107 case '*':
108 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '*' after '.' character")
109 case '.', '[':
110 goto end
111 case ']':
112 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified ']' after '.' character")
113 }
114 }
115 end:
116 if start == cursor {
117 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "cloud not find by empty key")
118 }
119 return b.child(string(buf[start:cursor])), buf, cursor, nil
120 }
121
122 func parseQuotedKey(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
123 cursor++ // skip single quote
124 start := cursor
125 length := len(buf)
126 var foundEndDelim bool
127 for ; cursor < length; cursor++ {
128 switch buf[cursor] {
129 case '\\':
130 buf = append(append([]rune{}, buf[:cursor]...), buf[cursor+1:]...)
131 length = len(buf)
132 case '\'':
133 foundEndDelim = true
134 goto end
135 }
136 }
137 end:
138 if !foundEndDelim {
139 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "could not find end delimiter for key")
140 }
141 if start == cursor {
142 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "could not find by empty key")
143 }
144 selector := buf[start:cursor]
145 cursor++
146 if cursor < length {
147 switch buf[cursor] {
148 case '$':
149 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '$' after '.' character")
150 case '*':
151 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified '*' after '.' character")
152 case ']':
153 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "specified ']' after '.' character")
154 }
155 }
156 return b.child(string(selector)), buf, cursor, nil
157 }
158
159 func parsePathIndex(b *PathBuilder, buf []rune, cursor int) (*PathBuilder, []rune, int, error) {
160 length := len(buf)
161 cursor++ // skip '[' character
162 if length <= cursor {
163 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "unexpected end of YAML Path")
164 }
165 c := buf[cursor]
166 switch c {
167 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*':
168 start := cursor
169 cursor++
170 for ; cursor < length; cursor++ {
171 c := buf[cursor]
172 switch c {
173 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
174 continue
175 }
176 break
177 }
178 if buf[cursor] != ']' {
179 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "invalid character %s at %d", string(buf[cursor]), cursor)
180 }
181 numOrAll := string(buf[start:cursor])
182 if numOrAll == "*" {
183 return b.IndexAll(), buf, cursor + 1, nil
184 }
185 num, err := strconv.ParseInt(numOrAll, 10, 64)
186 if err != nil {
187 return nil, nil, 0, errors.Wrapf(err, "failed to parse number")
188 }
189 return b.Index(uint(num)), buf, cursor + 1, nil
190 }
191 return nil, nil, 0, errors.Wrapf(ErrInvalidPathString, "invalid character %s at %d", c, cursor)
192 }
193
194 // Path represent YAMLPath ( like a JSONPath ).
195 type Path struct {
196 node pathNode
197 }
198
199 // String path to text.
200 func (p *Path) String() string {
201 return p.node.String()
202 }
203
204 // Read decode from r and set extracted value by YAMLPath to v.
205 func (p *Path) Read(r io.Reader, v interface{}) error {
206 node, err := p.ReadNode(r)
207 if err != nil {
208 return errors.Wrapf(err, "failed to read node")
209 }
210 if err := Unmarshal([]byte(node.String()), v); err != nil {
211 return errors.Wrapf(err, "failed to unmarshal")
212 }
213 return nil
214 }
215
216 // ReadNode create AST from r and extract node by YAMLPath.
217 func (p *Path) ReadNode(r io.Reader) (ast.Node, error) {
218 if p.node == nil {
219 return nil, ErrInvalidPath
220 }
221 var buf bytes.Buffer
222 if _, err := io.Copy(&buf, r); err != nil {
223 return nil, errors.Wrapf(err, "failed to copy from reader")
224 }
225 f, err := parser.ParseBytes(buf.Bytes(), 0)
226 if err != nil {
227 return nil, errors.Wrapf(err, "failed to parse yaml")
228 }
229 node, err := p.FilterFile(f)
230 if err != nil {
231 return nil, errors.Wrapf(err, "failed to filter from ast.File")
232 }
233 return node, nil
234 }
235
236 // Filter filter from target by YAMLPath and set it to v.
237 func (p *Path) Filter(target, v interface{}) error {
238 b, err := Marshal(target)
239 if err != nil {
240 return errors.Wrapf(err, "failed to marshal target value")
241 }
242 if err := p.Read(bytes.NewBuffer(b), v); err != nil {
243 return errors.Wrapf(err, "failed to read")
244 }
245 return nil
246 }
247
248 // FilterFile filter from ast.File by YAMLPath.
249 func (p *Path) FilterFile(f *ast.File) (ast.Node, error) {
250 for _, doc := range f.Docs {
251 node, err := p.FilterNode(doc.Body)
252 if err != nil {
253 return nil, errors.Wrapf(err, "failed to filter node by path ( %s )", p.node)
254 }
255 if node != nil {
256 return node, nil
257 }
258 }
259 return nil, errors.Wrapf(ErrNotFoundNode, "failed to find path ( %s )", p.node)
260 }
261
262 // FilterNode filter from node by YAMLPath.
263 func (p *Path) FilterNode(node ast.Node) (ast.Node, error) {
264 n, err := p.node.filter(node)
265 if err != nil {
266 return nil, errors.Wrapf(err, "failed to filter node by path ( %s )", p.node)
267 }
268 return n, nil
269 }
270
271 // MergeFromReader merge YAML text into ast.File.
272 func (p *Path) MergeFromReader(dst *ast.File, src io.Reader) error {
273 var buf bytes.Buffer
274 if _, err := io.Copy(&buf, src); err != nil {
275 return errors.Wrapf(err, "failed to copy from reader")
276 }
277 file, err := parser.ParseBytes(buf.Bytes(), 0)
278 if err != nil {
279 return errors.Wrapf(err, "failed to parse")
280 }
281 if err := p.MergeFromFile(dst, file); err != nil {
282 return errors.Wrapf(err, "failed to merge file")
283 }
284 return nil
285 }
286
287 // MergeFromFile merge ast.File into ast.File.
288 func (p *Path) MergeFromFile(dst *ast.File, src *ast.File) error {
289 base, err := p.FilterFile(dst)
290 if err != nil {
291 return errors.Wrapf(err, "failed to filter file")
292 }
293 for _, doc := range src.Docs {
294 if err := ast.Merge(base, doc); err != nil {
295 return errors.Wrapf(err, "failed to merge")
296 }
297 }
298 return nil
299 }
300
301 // MergeFromNode merge ast.Node into ast.File.
302 func (p *Path) MergeFromNode(dst *ast.File, src ast.Node) error {
303 base, err := p.FilterFile(dst)
304 if err != nil {
305 return errors.Wrapf(err, "failed to filter file")
306 }
307 if err := ast.Merge(base, src); err != nil {
308 return errors.Wrapf(err, "failed to merge")
309 }
310 return nil
311 }
312
313 // ReplaceWithReader replace ast.File with io.Reader.
314 func (p *Path) ReplaceWithReader(dst *ast.File, src io.Reader) error {
315 var buf bytes.Buffer
316 if _, err := io.Copy(&buf, src); err != nil {
317 return errors.Wrapf(err, "failed to copy from reader")
318 }
319 file, err := parser.ParseBytes(buf.Bytes(), 0)
320 if err != nil {
321 return errors.Wrapf(err, "failed to parse")
322 }
323 if err := p.ReplaceWithFile(dst, file); err != nil {
324 return errors.Wrapf(err, "failed to replace file")
325 }
326 return nil
327 }
328
329 // ReplaceWithFile replace ast.File with ast.File.
330 func (p *Path) ReplaceWithFile(dst *ast.File, src *ast.File) error {
331 for _, doc := range src.Docs {
332 if err := p.ReplaceWithNode(dst, doc); err != nil {
333 return errors.Wrapf(err, "failed to replace file by path ( %s )", p.node)
334 }
335 }
336 return nil
337 }
338
339 // ReplaceNode replace ast.File with ast.Node.
340 func (p *Path) ReplaceWithNode(dst *ast.File, node ast.Node) error {
341 for _, doc := range dst.Docs {
342 if node.Type() == ast.DocumentType {
343 node = node.(*ast.DocumentNode).Body
344 }
345 if err := p.node.replace(doc.Body, node); err != nil {
346 return errors.Wrapf(err, "failed to replace node by path ( %s )", p.node)
347 }
348 }
349 return nil
350 }
351
352 // AnnotateSource add annotation to passed source ( see section 5.1 in README.md ).
353 func (p *Path) AnnotateSource(source []byte, colored bool) ([]byte, error) {
354 file, err := parser.ParseBytes([]byte(source), 0)
355 if err != nil {
356 return nil, err
357 }
358 node, err := p.FilterFile(file)
359 if err != nil {
360 return nil, err
361 }
362 var pp printer.Printer
363 return []byte(pp.PrintErrorToken(node.GetToken(), colored)), nil
364 }
365
366 // PathBuilder represent builder for YAMLPath.
367 type PathBuilder struct {
368 root *rootNode
369 node pathNode
370 }
371
372 // Root add '$' to current path.
373 func (b *PathBuilder) Root() *PathBuilder {
374 root := newRootNode()
375 return &PathBuilder{root: root, node: root}
376 }
377
378 // IndexAll add '[*]' to current path.
379 func (b *PathBuilder) IndexAll() *PathBuilder {
380 b.node = b.node.chain(newIndexAllNode())
381 return b
382 }
383
384 // Recursive add '..selector' to current path.
385 func (b *PathBuilder) Recursive(selector string) *PathBuilder {
386 b.node = b.node.chain(newRecursiveNode(selector))
387 return b
388 }
389
390 func (b *PathBuilder) containsReservedPathCharacters(path string) bool {
391 if strings.Contains(path, ".") {
392 return true
393 }
394 if strings.Contains(path, "*") {
395 return true
396 }
397 return false
398 }
399
400 func (b *PathBuilder) enclosedSingleQuote(name string) bool {
401 return strings.HasPrefix(name, "'") && strings.HasSuffix(name, "'")
402 }
403
404 func (b *PathBuilder) normalizeSelectorName(name string) string {
405 if b.enclosedSingleQuote(name) {
406 // already escaped name
407 return name
408 }
409 if b.containsReservedPathCharacters(name) {
410 escapedName := strings.ReplaceAll(name, `'`, `\'`)
411 return "'" + escapedName + "'"
412 }
413 return name
414 }
415
416 func (b *PathBuilder) child(name string) *PathBuilder {
417 b.node = b.node.chain(newSelectorNode(name))
418 return b
419 }
420
421 // Child add '.name' to current path.
422 func (b *PathBuilder) Child(name string) *PathBuilder {
423 return b.child(b.normalizeSelectorName(name))
424 }
425
426 // Index add '[idx]' to current path.
427 func (b *PathBuilder) Index(idx uint) *PathBuilder {
428 b.node = b.node.chain(newIndexNode(idx))
429 return b
430 }
431
432 // Build build YAMLPath.
433 func (b *PathBuilder) Build() *Path {
434 return &Path{node: b.root}
435 }
436
437 type pathNode interface {
438 fmt.Stringer
439 chain(pathNode) pathNode
440 filter(ast.Node) (ast.Node, error)
441 replace(ast.Node, ast.Node) error
442 }
443
444 type basePathNode struct {
445 child pathNode
446 }
447
448 func (n *basePathNode) chain(node pathNode) pathNode {
449 n.child = node
450 return node
451 }
452
453 type rootNode struct {
454 *basePathNode
455 }
456
457 func newRootNode() *rootNode {
458 return &rootNode{basePathNode: &basePathNode{}}
459 }
460
461 func (n *rootNode) String() string {
462 s := "$"
463 if n.child != nil {
464 s += n.child.String()
465 }
466 return s
467 }
468
469 func (n *rootNode) filter(node ast.Node) (ast.Node, error) {
470 if n.child == nil {
471 return nil, nil
472 }
473 filtered, err := n.child.filter(node)
474 if err != nil {
475 return nil, errors.Wrapf(err, "failed to filter")
476 }
477 return filtered, nil
478 }
479
480 func (n *rootNode) replace(node ast.Node, target ast.Node) error {
481 if n.child == nil {
482 return nil
483 }
484 if err := n.child.replace(node, target); err != nil {
485 return errors.Wrapf(err, "failed to replace")
486 }
487 return nil
488 }
489
490 type selectorNode struct {
491 *basePathNode
492 selector string
493 }
494
495 func newSelectorNode(selector string) *selectorNode {
496 return &selectorNode{
497 basePathNode: &basePathNode{},
498 selector: selector,
499 }
500 }
501
502 func (n *selectorNode) filter(node ast.Node) (ast.Node, error) {
503 switch node.Type() {
504 case ast.MappingType:
505 for _, value := range node.(*ast.MappingNode).Values {
506 key := value.Key.GetToken().Value
507 if key == n.selector {
508 if n.child == nil {
509 return value.Value, nil
510 }
511 filtered, err := n.child.filter(value.Value)
512 if err != nil {
513 return nil, errors.Wrapf(err, "failed to filter")
514 }
515 return filtered, nil
516 }
517 }
518 case ast.MappingValueType:
519 value := node.(*ast.MappingValueNode)
520 key := value.Key.GetToken().Value
521 if key == n.selector {
522 if n.child == nil {
523 return value.Value, nil
524 }
525 filtered, err := n.child.filter(value.Value)
526 if err != nil {
527 return nil, errors.Wrapf(err, "failed to filter")
528 }
529 return filtered, nil
530 }
531 default:
532 return nil, errors.Wrapf(ErrInvalidQuery, "expected node type is map or map value. but got %s", node.Type())
533 }
534 return nil, nil
535 }
536
537 func (n *selectorNode) replaceMapValue(value *ast.MappingValueNode, target ast.Node) error {
538 key := value.Key.GetToken().Value
539 if key != n.selector {
540 return nil
541 }
542 if n.child == nil {
543 if err := value.Replace(target); err != nil {
544 return errors.Wrapf(err, "failed to replace")
545 }
546 } else {
547 if err := n.child.replace(value.Value, target); err != nil {
548 return errors.Wrapf(err, "failed to replace")
549 }
550 }
551 return nil
552 }
553
554 func (n *selectorNode) replace(node ast.Node, target ast.Node) error {
555 switch node.Type() {
556 case ast.MappingType:
557 for _, value := range node.(*ast.MappingNode).Values {
558 if err := n.replaceMapValue(value, target); err != nil {
559 return errors.Wrapf(err, "failed to replace map value")
560 }
561 }
562 case ast.MappingValueType:
563 value := node.(*ast.MappingValueNode)
564 if err := n.replaceMapValue(value, target); err != nil {
565 return errors.Wrapf(err, "failed to replace map value")
566 }
567 default:
568 return errors.Wrapf(ErrInvalidQuery, "expected node type is map or map value. but got %s", node.Type())
569 }
570 return nil
571 }
572
573 func (n *selectorNode) String() string {
574 s := fmt.Sprintf(".%s", n.selector)
575 if n.child != nil {
576 s += n.child.String()
577 }
578 return s
579 }
580
581 type indexNode struct {
582 *basePathNode
583 selector uint
584 }
585
586 func newIndexNode(selector uint) *indexNode {
587 return &indexNode{
588 basePathNode: &basePathNode{},
589 selector: selector,
590 }
591 }
592
593 func (n *indexNode) filter(node ast.Node) (ast.Node, error) {
594 if node.Type() != ast.SequenceType {
595 return nil, errors.Wrapf(ErrInvalidQuery, "expected sequence type node. but got %s", node.Type())
596 }
597 sequence := node.(*ast.SequenceNode)
598 if n.selector >= uint(len(sequence.Values)) {
599 return nil, errors.Wrapf(ErrInvalidQuery, "expected index is %d. but got sequences has %d items", n.selector, sequence.Values)
600 }
601 value := sequence.Values[n.selector]
602 if n.child == nil {
603 return value, nil
604 }
605 filtered, err := n.child.filter(value)
606 if err != nil {
607 return nil, errors.Wrapf(err, "failed to filter")
608 }
609 return filtered, nil
610 }
611
612 func (n *indexNode) replace(node ast.Node, target ast.Node) error {
613 if node.Type() != ast.SequenceType {
614 return errors.Wrapf(ErrInvalidQuery, "expected sequence type node. but got %s", node.Type())
615 }
616 sequence := node.(*ast.SequenceNode)
617 if n.selector >= uint(len(sequence.Values)) {
618 return errors.Wrapf(ErrInvalidQuery, "expected index is %d. but got sequences has %d items", n.selector, sequence.Values)
619 }
620 if n.child == nil {
621 if err := sequence.Replace(int(n.selector), target); err != nil {
622 return errors.Wrapf(err, "failed to replace")
623 }
624 return nil
625 }
626 if err := n.child.replace(sequence.Values[n.selector], target); err != nil {
627 return errors.Wrapf(err, "failed to replace")
628 }
629 return nil
630 }
631
632 func (n *indexNode) String() string {
633 s := fmt.Sprintf("[%d]", n.selector)
634 if n.child != nil {
635 s += n.child.String()
636 }
637 return s
638 }
639
640 type indexAllNode struct {
641 *basePathNode
642 }
643
644 func newIndexAllNode() *indexAllNode {
645 return &indexAllNode{
646 basePathNode: &basePathNode{},
647 }
648 }
649
650 func (n *indexAllNode) String() string {
651 s := "[*]"
652 if n.child != nil {
653 s += n.child.String()
654 }
655 return s
656 }
657
658 func (n *indexAllNode) filter(node ast.Node) (ast.Node, error) {
659 if node.Type() != ast.SequenceType {
660 return nil, errors.Wrapf(ErrInvalidQuery, "expected sequence type node. but got %s", node.Type())
661 }
662 sequence := node.(*ast.SequenceNode)
663 if n.child == nil {
664 return sequence, nil
665 }
666 out := *sequence
667 out.Values = []ast.Node{}
668 for _, value := range sequence.Values {
669 filtered, err := n.child.filter(value)
670 if err != nil {
671 return nil, errors.Wrapf(err, "failed to filter")
672 }
673 out.Values = append(out.Values, filtered)
674 }
675 return &out, nil
676 }
677
678 func (n *indexAllNode) replace(node ast.Node, target ast.Node) error {
679 if node.Type() != ast.SequenceType {
680 return errors.Wrapf(ErrInvalidQuery, "expected sequence type node. but got %s", node.Type())
681 }
682 sequence := node.(*ast.SequenceNode)
683 if n.child == nil {
684 for idx := range sequence.Values {
685 if err := sequence.Replace(idx, target); err != nil {
686 return errors.Wrapf(err, "failed to replace")
687 }
688 }
689 return nil
690 }
691 for _, value := range sequence.Values {
692 if err := n.child.replace(value, target); err != nil {
693 return errors.Wrapf(err, "failed to replace")
694 }
695 }
696 return nil
697 }
698
699 type recursiveNode struct {
700 *basePathNode
701 selector string
702 }
703
704 func newRecursiveNode(selector string) *recursiveNode {
705 return &recursiveNode{
706 basePathNode: &basePathNode{},
707 selector: selector,
708 }
709 }
710
711 func (n *recursiveNode) String() string {
712 s := fmt.Sprintf("..%s", n.selector)
713 if n.child != nil {
714 s += n.child.String()
715 }
716 return s
717 }
718
719 func (n *recursiveNode) filterNode(node ast.Node) (*ast.SequenceNode, error) {
720 sequence := &ast.SequenceNode{BaseNode: &ast.BaseNode{}}
721 switch typedNode := node.(type) {
722 case *ast.MappingNode:
723 for _, value := range typedNode.Values {
724 seq, err := n.filterNode(value)
725 if err != nil {
726 return nil, errors.Wrapf(err, "failed to filter")
727 }
728 sequence.Values = append(sequence.Values, seq.Values...)
729 }
730 case *ast.MappingValueNode:
731 key := typedNode.Key.GetToken().Value
732 if n.selector == key {
733 sequence.Values = append(sequence.Values, typedNode.Value)
734 }
735 seq, err := n.filterNode(typedNode.Value)
736 if err != nil {
737 return nil, errors.Wrapf(err, "failed to filter")
738 }
739 sequence.Values = append(sequence.Values, seq.Values...)
740 case *ast.SequenceNode:
741 for _, value := range typedNode.Values {
742 seq, err := n.filterNode(value)
743 if err != nil {
744 return nil, errors.Wrapf(err, "failed to filter")
745 }
746 sequence.Values = append(sequence.Values, seq.Values...)
747 }
748 }
749 return sequence, nil
750 }
751
752 func (n *recursiveNode) filter(node ast.Node) (ast.Node, error) {
753 sequence, err := n.filterNode(node)
754 if err != nil {
755 return nil, errors.Wrapf(err, "failed to filter")
756 }
757 sequence.Start = node.GetToken()
758 return sequence, nil
759 }
760
761 func (n *recursiveNode) replaceNode(node ast.Node, target ast.Node) error {
762 switch typedNode := node.(type) {
763 case *ast.MappingNode:
764 for _, value := range typedNode.Values {
765 if err := n.replaceNode(value, target); err != nil {
766 return errors.Wrapf(err, "failed to replace")
767 }
768 }
769 case *ast.MappingValueNode:
770 key := typedNode.Key.GetToken().Value
771 if n.selector == key {
772 if err := typedNode.Replace(target); err != nil {
773 return errors.Wrapf(err, "failed to replace")
774 }
775 }
776 if err := n.replaceNode(typedNode.Value, target); err != nil {
777 return errors.Wrapf(err, "failed to replace")
778 }
779 case *ast.SequenceNode:
780 for _, value := range typedNode.Values {
781 if err := n.replaceNode(value, target); err != nil {
782 return errors.Wrapf(err, "failed to replace")
783 }
784 }
785 }
786 return nil
787 }
788
789 func (n *recursiveNode) replace(node ast.Node, target ast.Node) error {
790 if err := n.replaceNode(node, target); err != nil {
791 return errors.Wrapf(err, "failed to replace")
792 }
793 return nil
794 }
795