* Recursively search JSXText nodes in an AST subtree for a substring and replace it. * Uses whitespace-flexible matching: the search term (from DOM text) has collapsed * whitespace, but the JSX source may have newlines/indentation. We build a regex * from oldSub that treats each space as \s+ to b
(node: any, oldSub: string, newSub: string, depth = 0)
| 699 | * from oldSub that treats each space as \s+ to bridge this gap. |
| 700 | */ |
| 701 | function replaceInJSXTextRecursive(node: any, oldSub: string, newSub: string, depth = 0): boolean { |
| 702 | const children = node.children; |
| 703 | if (!children) return false; |
| 704 | |
| 705 | // Build a regex that matches oldSub with flexible whitespace |
| 706 | const flexPattern = oldSub.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\s+/g, "\\s+"); |
| 707 | const flexRe = new RegExp(flexPattern); |
| 708 | |
| 709 | for (const child of children) { |
| 710 | if (child.type === "JSXText") { |
| 711 | const trimmed = child.value.trim(); |
| 712 | // Try exact match first, then whitespace-flexible match |
| 713 | if (child.value.includes(oldSub)) { |
| 714 | logger.debug(`[replaceRecursive] d=${depth} FOUND exact "${oldSub.slice(0,30)}" in "${trimmed.slice(0,30)}"`); |
| 715 | child.value = child.value.replace(oldSub, newSub); |
| 716 | return true; |
| 717 | } |
| 718 | const flexMatch = child.value.match(flexRe); |
| 719 | if (flexMatch) { |
| 720 | logger.debug(`[replaceRecursive] d=${depth} FOUND flex "${oldSub.slice(0,30)}" in "${trimmed.slice(0,30)}"`); |
| 721 | child.value = child.value.replace(flexRe, newSub); |
| 722 | return true; |
| 723 | } |
| 724 | } |
| 725 | if (child.type === "JSXExpressionContainer" && child.expression?.type === "StringLiteral") { |
| 726 | if (child.expression.value.includes(oldSub)) { |
| 727 | child.expression.value = child.expression.value.replace(oldSub, newSub); |
| 728 | return true; |
| 729 | } |
| 730 | } |
| 731 | // Recurse into child JSX elements |
| 732 | if (child.type === "JSXElement") { |
| 733 | if (replaceInJSXTextRecursive(child, oldSub, newSub, depth + 1)) return true; |
| 734 | } |
| 735 | } |
| 736 | return false; |
| 737 | } |
| 738 | |
| 739 | /** |
| 740 | * Get the normalized text content of a JSX element recursively. |