diff --git a/apps/mocksi-lite/universalReplace.ts b/apps/mocksi-lite/universalReplace.ts index b41dcc6b..e9419e5b 100644 --- a/apps/mocksi-lite/universalReplace.ts +++ b/apps/mocksi-lite/universalReplace.ts @@ -28,45 +28,32 @@ class UniversalReplace { seekAndReplace(pattern: RegExp, newText: string) { const body = document.querySelector("body"); if (body) { - // TODO createTreeWalker provides a filter function, see if we can filter chunk textNodes - const treeWalker = document.createTreeWalker( - body, - NodeFilter.SHOW_TEXT, - (node) => { - if ( - node.parentElement instanceof HTMLScriptElement || - node.parentElement instanceof HTMLStyleElement - ) - return NodeFilter.FILTER_REJECT; - return NodeFilter.FILTER_ACCEPT; - }, - ); - let textNode: Node; - const fragmentsToHighlight: Node[] = []; + const fragmentsToHighlight: Node[] = []; const replacements: { nodeToReplace: Node; replacement: Node }[] = []; - do { - textNode = treeWalker.currentNode; - if (textNode.nodeValue === null || !textNode?.textContent?.trim()) - continue; - const matches = [...textNode.nodeValue.matchAll(pattern)]; - if (matches.length > 0) { - const fragmentedTextNode = fragmentTextNode( - fragmentsToHighlight, - matches, - textNode, - newText, - ); - replacements.push({ - nodeToReplace: textNode, - replacement: fragmentedTextNode, - }); - saveModification( - textNode.parentElement as HTMLElement, - newText, - cleanPattern(pattern), - ); - } - } while (treeWalker.nextNode()); + createTreeWalker( + body, + (textNode) => { + //@ts-ignore textNode.nodeValue is not null. + const matches = [...textNode.nodeValue.matchAll(pattern)]; + if (matches.length > 0) { + const fragmentedTextNode = fragmentTextNode( + fragmentsToHighlight, + matches, + textNode, + newText, + ); + replacements.push({ + nodeToReplace: textNode, + replacement: fragmentedTextNode, + }); + saveModification( + textNode.parentElement as HTMLElement, + newText, + cleanPattern(pattern), + ); + } + } + ) //biome-ignore lint/complexity/noForEach: I'll replace later replacements.forEach(({ nodeToReplace, replacement }) => { if (nodeToReplace.parentElement) @@ -86,36 +73,24 @@ class UniversalReplace { for (const mutation of mutations) { if (mutation.addedNodes != null && mutation.addedNodes.length > 0) { for (const node of mutation.addedNodes) { - if ( - node instanceof Text && - node.parentElement && - !(node.parentElement instanceof HTMLScriptElement) && - !(node.parentElement instanceof HTMLStyleElement) && - node.textContent !== null && - !/^\s*$/.test(node.textContent) - ) { - const replace = this.matchReplacePattern(node.textContent); - if (replace) { - const treeWalker = document.createTreeWalker( - node, - NodeFilter.SHOW_TEXT, - ); - let textNode: Node; - do { - textNode = treeWalker.currentNode; - if (textNode.nodeValue === null) continue; - textNode.nodeValue = textNode.nodeValue.replace( - replace.pattern, - replaceFirstLetterCase(replace.replace), - ); - } while (treeWalker.nextNode()); - } - } + createTreeWalker( + node, + (textNode) => { + //@ts-ignore textNode.nodeValue is not null. + const replace = this.matchReplacePattern(textNode.textContent); + if (replace) { + //@ts-ignore textNode.nodeValue is not null. + textNode.nodeValue = textNode.nodeValue.replace( + replace.pattern, + replaceFirstLetterCase(replace.replace), + ); + } + } + ) } } } }); - this.observer.observe(document, { childList: true, subtree: true }); } @@ -135,6 +110,27 @@ class UniversalReplace { const cleanPattern = (pattern: RegExp) => pattern.toString().replaceAll("/", "").replace("gi", ""); +const createTreeWalker = (rootElement: Node, iterator: (textNode: Node) => void) => { + const treeWalker = document.createTreeWalker( + rootElement, + NodeFilter.SHOW_TEXT, + (node) => { + if ( + node.parentElement instanceof HTMLScriptElement || + node.parentElement instanceof HTMLStyleElement + ) + return NodeFilter.FILTER_REJECT; + return NodeFilter.FILTER_ACCEPT; + } + ) + let textNode: Node; + do { + textNode = treeWalker.currentNode; + if (textNode.nodeValue === null || !textNode?.textContent?.trim()) continue; + iterator(textNode) + } while (treeWalker.nextNode()); +} + const replaceFirstLetterCase = (value: string) => { return (match: string) => { // Check if the first letter in the match is uppercase