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