── JSON path evaluator ─────────────────────────────────────────── jsonPathGet resolves dot-notation paths like "agents[0].email" or "agents.length".
(obj map[string]interface{}, path string)
| 533 | |
| 534 | // jsonPathGet resolves dot-notation paths like "agents[0].email" or "agents.length". |
| 535 | func jsonPathGet(obj map[string]interface{}, path string) (interface{}, bool) { |
| 536 | parts := strings.Split(path, ".") |
| 537 | var current interface{} = obj |
| 538 | |
| 539 | for _, part := range parts { |
| 540 | if part == "length" { |
| 541 | arr, ok := current.([]interface{}) |
| 542 | if !ok { |
| 543 | return nil, false |
| 544 | } |
| 545 | return len(arr), true |
| 546 | } |
| 547 | |
| 548 | if idx := strings.Index(part, "["); idx != -1 { |
| 549 | name := part[:idx] |
| 550 | idxStr := part[idx+1 : len(part)-1] |
| 551 | arrIdx, _ := strconv.Atoi(idxStr) |
| 552 | |
| 553 | m, ok := current.(map[string]interface{}) |
| 554 | if !ok { |
| 555 | return nil, false |
| 556 | } |
| 557 | arr, ok := m[name].([]interface{}) |
| 558 | if !ok || arrIdx >= len(arr) { |
| 559 | return nil, false |
| 560 | } |
| 561 | current = arr[arrIdx] |
| 562 | } else { |
| 563 | m, ok := current.(map[string]interface{}) |
| 564 | if !ok { |
| 565 | return nil, false |
| 566 | } |
| 567 | val, exists := m[part] |
| 568 | if !exists { |
| 569 | return nil, false |
| 570 | } |
| 571 | current = val |
| 572 | } |
| 573 | } |
| 574 | return current, true |
| 575 | } |
| 576 | |
| 577 | // valuesEqual compares a JSON-decoded value with a YAML-decoded expected value, |
| 578 | // handling cross-type numeric comparison (JSON float64 vs YAML int). |