@ens-rush-resolution/auto-resolve
Version:
Auto-detection and resolution of Ethereum addresses in web pages
1 lines • 7.03 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { resolve, type ResolveOptions } from '@ens-rush-resolution/core';\n\nconst ETHEREUM_ADDRESS_REGEX = /0x[a-fA-F0-9]{40}/g;\n\nexport interface AutoResolveOptions extends ResolveOptions {\n selector?: string;\n onResolve?: (address: string, name: string | null, element: Element) => void;\n}\n\ninterface AddressElement {\n address: string;\n element: Element;\n textNode: Text;\n startIndex: number;\n endIndex: number;\n}\n\nfunction findAddressesInTextNode(textNode: Text): AddressElement[] {\n const text = textNode.textContent || '';\n const addresses: AddressElement[] = [];\n let match;\n\n ETHEREUM_ADDRESS_REGEX.lastIndex = 0;\n \n while ((match = ETHEREUM_ADDRESS_REGEX.exec(text)) !== null) {\n addresses.push({\n address: match[0],\n element: textNode.parentElement!,\n textNode,\n startIndex: match.index,\n endIndex: match.index + match[0].length\n });\n }\n\n return addresses;\n}\n\nfunction findAllAddresses(root: Element = document.body): AddressElement[] {\n const walker = document.createTreeWalker(\n root,\n NodeFilter.SHOW_TEXT,\n {\n acceptNode(node: Text) {\n // Skip nodes inside elements with data-ens-rush=\"false\"\n let parent = node.parentElement;\n while (parent) {\n if (parent.dataset.ensRush === 'false' || parent.dataset.ensRush === 'skip') {\n return NodeFilter.FILTER_REJECT;\n }\n parent = parent.parentElement;\n }\n return NodeFilter.FILTER_ACCEPT;\n }\n }\n );\n\n const allAddresses: AddressElement[] = [];\n let node;\n\n while (node = walker.nextNode()) {\n const textNode = node as Text;\n const addresses = findAddressesInTextNode(textNode);\n allAddresses.push(...addresses);\n }\n\n return allAddresses;\n}\n\nfunction updateAddressInDOM(addressElement: AddressElement, ensName: string | null) {\n const { textNode, startIndex, endIndex, address } = addressElement;\n const text = textNode.textContent || '';\n \n if (!ensName) {\n return;\n }\n\n const beforeText = text.substring(0, startIndex);\n const afterText = text.substring(endIndex);\n \n const ensSpan = document.createElement('span');\n ensSpan.textContent = ensName;\n ensSpan.title = address;\n\n const parentElement = textNode.parentElement!;\n \n if (beforeText) {\n parentElement.insertBefore(document.createTextNode(beforeText), textNode);\n }\n \n parentElement.insertBefore(ensSpan, textNode);\n \n if (afterText) {\n parentElement.insertBefore(document.createTextNode(afterText), textNode);\n }\n \n parentElement.removeChild(textNode);\n}\n\nexport async function autoResolve(options: AutoResolveOptions = {}): Promise<void> {\n const { selector, onResolve, ...resolveOptions } = options;\n \n const root = selector ? document.querySelector(selector) : document.body;\n if (!root) {\n console.warn('Auto-resolve: Root element not found');\n return;\n }\n\n const addressElements = findAllAddresses(root as Element);\n \n if (addressElements.length === 0) {\n console.log('Auto-resolve: No Ethereum addresses found');\n return;\n }\n\n const uniqueAddresses = [...new Set(addressElements.map(ae => ae.address))];\n console.log(`Auto-resolve: Found ${addressElements.length} addresses (${uniqueAddresses.length} unique)`);\n\n try {\n const resolutions = await resolve(uniqueAddresses, resolveOptions);\n const resolutionMap = new Map(resolutions.map(r => [r.address, r.name]));\n\n addressElements.forEach(addressElement => {\n const ensName = resolutionMap.get(addressElement.address);\n \n if (onResolve) {\n onResolve(addressElement.address, ensName || null, addressElement.element);\n }\n \n updateAddressInDOM(addressElement, ensName || null);\n });\n\n const resolvedCount = resolutions.filter(r => r.name).length;\n console.log(`Auto-resolve: Resolved ${resolvedCount}/${uniqueAddresses.length} addresses to ENS names`);\n } catch (error) {\n console.error('Auto-resolve: Failed to resolve addresses', error);\n }\n}\n\n// Auto-initialize when imported in browser\nif (typeof window !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n console.log('Auto-resolve: DOM loaded, starting auto-resolution...');\n autoResolve();\n });\n } else {\n console.log('Auto-resolve: DOM already loaded, starting auto-resolution...');\n autoResolve();\n }\n}"],"mappings":"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","names":["node"]}