@mcp-b/smart-dom-reader 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -68
- package/dist/bundle-string.d.mts +13 -0
- package/dist/bundle-string.d.mts.map +1 -0
- package/dist/bundle-string.mjs +14 -0
- package/dist/bundle-string.mjs.map +1 -0
- package/dist/{index.d.ts → index.d.mts} +2 -3
- package/dist/index.d.mts.map +1 -0
- package/dist/{index.js → index.mjs} +24 -34
- package/dist/index.mjs.map +1 -0
- package/package.json +42 -42
- package/dist/bundle-string.d.ts +0 -13
- package/dist/bundle-string.d.ts.map +0 -1
- package/dist/bundle-string.js +0 -14
- package/dist/bundle-string.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/bundle-string.ts
|
|
2
|
+
/**
|
|
3
|
+
* Auto-generated bundle module for smart-dom-reader
|
|
4
|
+
* DO NOT EDIT - Generated by generate-bundle-module.mjs
|
|
5
|
+
*
|
|
6
|
+
* This module exports the bundled smart-dom-reader library as a string
|
|
7
|
+
* that can be injected into web pages for stateless DOM extraction.
|
|
8
|
+
*/
|
|
9
|
+
const SMART_DOM_READER_BUNDLE = "var SmartDOMReaderBundle = (function(exports) {\n Object.defineProperty(exports, Symbol.toStringTag, { value: \"Module\" });\n //#region \\0rolldown/runtime.js\n var __defProp = Object.defineProperty;\n var __getOwnPropDesc = Object.getOwnPropertyDescriptor;\n var __getOwnPropNames = Object.getOwnPropertyNames;\n var __hasOwnProp = Object.prototype.hasOwnProperty;\n var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);\n var __exportAll = (all, no_symbols) => {\n let target = {};\n for (var name in all) __defProp(target, name, {\n get: all[name],\n enumerable: true\n });\n if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: \"Module\" });\n return target;\n };\n var __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {\n key = keys[i];\n if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {\n get: ((k) => from[k]).bind(null, key),\n enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable\n });\n }\n return to;\n };\n var __toCommonJS = (mod) => __hasOwnProp.call(mod, \"module.exports\") ? mod[\"module.exports\"] : __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n //#endregion\n //#region src/content-detection.ts\n var ContentDetection;\n var init_content_detection = __esmMin((() => {\n ContentDetection = class ContentDetection {\n /**\n * Find the main content area of a page\n * Inspired by dom-to-semantic-markdown's approach\n */\n static findMainContent(doc) {\n const mainElement = doc.querySelector(\"main, [role=\\\"main\\\"]\");\n if (mainElement) return mainElement;\n if (!doc.body) return doc.documentElement;\n return ContentDetection.detectMainContent(doc.body);\n }\n /**\n * Detect main content using scoring algorithm\n */\n static detectMainContent(rootElement) {\n const candidates = [];\n ContentDetection.collectCandidates(rootElement, candidates, 15);\n if (candidates.length === 0) return rootElement;\n candidates.sort((a, b) => ContentDetection.calculateContentScore(b) - ContentDetection.calculateContentScore(a));\n let bestCandidate = candidates[0];\n for (let i = 1; i < candidates.length; i++) {\n const candidate = candidates[i];\n if (!candidates.some((other, j) => j !== i && other.contains(candidate)) && ContentDetection.calculateContentScore(candidate) > ContentDetection.calculateContentScore(bestCandidate)) bestCandidate = candidate;\n }\n return bestCandidate;\n }\n /**\n * Collect content candidates\n */\n static collectCandidates(element, candidates, minScore) {\n if (ContentDetection.calculateContentScore(element) >= minScore) candidates.push(element);\n Array.from(element.children).forEach((child) => {\n ContentDetection.collectCandidates(child, candidates, minScore);\n });\n }\n /**\n * Calculate content score for an element\n */\n static calculateContentScore(element) {\n let score = 0;\n const semanticClasses = [\n \"article\",\n \"content\",\n \"main-container\",\n \"main\",\n \"main-content\",\n \"post\",\n \"entry\"\n ];\n const semanticIds = [\n \"content\",\n \"main\",\n \"article\",\n \"post\",\n \"entry\"\n ];\n semanticClasses.forEach((cls) => {\n if (element.classList.contains(cls)) score += 10;\n });\n semanticIds.forEach((id) => {\n if (element.id?.toLowerCase().includes(id)) score += 10;\n });\n const tag = element.tagName.toLowerCase();\n if ([\n \"article\",\n \"main\",\n \"section\"\n ].includes(tag)) score += 8;\n const paragraphs = element.getElementsByTagName(\"p\").length;\n score += Math.min(paragraphs * 2, 10);\n const headings = element.querySelectorAll(\"h1, h2, h3\").length;\n score += Math.min(headings * 3, 9);\n const textLength = element.textContent?.trim().length || 0;\n if (textLength > 300) score += Math.min(Math.floor(textLength / 300) * 2, 10);\n const linkDensity = ContentDetection.calculateLinkDensity(element);\n if (linkDensity < .3) score += 5;\n else if (linkDensity > .5) score -= 5;\n if (element.hasAttribute(\"data-main\") || element.hasAttribute(\"data-content\") || element.hasAttribute(\"itemprop\")) score += 8;\n const role = element.getAttribute(\"role\");\n if (role === \"main\" || role === \"article\") score += 10;\n if (element.matches(\"aside, nav, header, footer, .sidebar, .navigation, .menu, .ad, .advertisement\")) score -= 10;\n if (element.getElementsByTagName(\"form\").length > 2) score -= 5;\n return Math.max(0, score);\n }\n /**\n * Calculate link density in an element\n */\n static calculateLinkDensity(element) {\n const links = element.getElementsByTagName(\"a\");\n let linkTextLength = 0;\n for (const link of Array.from(links)) linkTextLength += link.textContent?.length || 0;\n const totalTextLength = element.textContent?.length || 1;\n return linkTextLength / totalTextLength;\n }\n /**\n * Check if an element is likely navigation\n */\n static isNavigation(element) {\n if (element.tagName.toLowerCase() === \"nav\" || element.getAttribute(\"role\") === \"navigation\") return true;\n const navPatterns = [\n /nav/i,\n /menu/i,\n /sidebar/i,\n /toolbar/i\n ];\n const classesAndId = `${element.className} ${element.id}`.toLowerCase();\n return navPatterns.some((pattern) => pattern.test(classesAndId));\n }\n /**\n * Check if element is likely supplementary content\n */\n static isSupplementary(element) {\n if (element.tagName.toLowerCase() === \"aside\" || element.getAttribute(\"role\") === \"complementary\") return true;\n const supplementaryPatterns = [\n /sidebar/i,\n /widget/i,\n /related/i,\n /advertisement/i,\n /social/i\n ];\n const classesAndId = `${element.className} ${element.id}`.toLowerCase();\n return supplementaryPatterns.some((pattern) => pattern.test(classesAndId));\n }\n /**\n * Detect page landmarks\n */\n static detectLandmarks(doc) {\n const landmarks = {\n navigation: [],\n main: [],\n complementary: [],\n contentinfo: [],\n banner: [],\n search: [],\n form: [],\n region: []\n };\n for (const [landmark, selector] of Object.entries({\n navigation: \"nav, [role=\\\"navigation\\\"]\",\n main: \"main, [role=\\\"main\\\"]\",\n complementary: \"aside, [role=\\\"complementary\\\"]\",\n contentinfo: \"footer, [role=\\\"contentinfo\\\"]\",\n banner: \"header, [role=\\\"banner\\\"]\",\n search: \"[role=\\\"search\\\"]\",\n form: \"form[aria-label], form[aria-labelledby], [role=\\\"form\\\"]\",\n region: \"section[aria-label], section[aria-labelledby], [role=\\\"region\\\"]\"\n })) {\n const elements = doc.querySelectorAll(selector);\n landmarks[landmark] = Array.from(elements);\n }\n return landmarks;\n }\n };\n }));\n //#endregion\n //#region src/selectors.ts\n var SelectorGenerator;\n var init_selectors = __esmMin((() => {\n SelectorGenerator = class SelectorGenerator {\n /**\n * Generate multiple selector strategies for an element\n */\n static generateSelectors(element) {\n const doc = element.ownerDocument || document;\n const candidates = [];\n if (element.id && SelectorGenerator.isUniqueId(element.id, doc)) candidates.push({\n type: \"id\",\n value: `#${CSS.escape(element.id)}`,\n score: 100\n });\n const testId = SelectorGenerator.getDataTestId(element);\n if (testId) {\n const v = `[data-testid=\"${CSS.escape(testId)}\"]`;\n candidates.push({\n type: \"data-testid\",\n value: v,\n score: 90 + (SelectorGenerator.isUniqueSelectorSafe(v, doc) ? 5 : 0)\n });\n }\n const role = element.getAttribute(\"role\");\n const aria = element.getAttribute(\"aria-label\");\n if (role && aria) {\n const v = `[role=\"${CSS.escape(role)}\"][aria-label=\"${CSS.escape(aria)}\"]`;\n candidates.push({\n type: \"role-aria\",\n value: v,\n score: 85 + (SelectorGenerator.isUniqueSelectorSafe(v, doc) ? 5 : 0)\n });\n }\n const nameAttr = element.getAttribute(\"name\");\n if (nameAttr) {\n const v = `[name=\"${CSS.escape(nameAttr)}\"]`;\n candidates.push({\n type: \"name\",\n value: v,\n score: 78 + (SelectorGenerator.isUniqueSelectorSafe(v, doc) ? 5 : 0)\n });\n }\n const pathCss = SelectorGenerator.generateCSSSelector(element, doc);\n const structuralPenalty = (pathCss.match(/:nth-child\\(/g) || []).length * 10;\n const classBonus = pathCss.includes(\".\") ? 8 : 0;\n const pathScore = Math.max(0, 70 + classBonus - structuralPenalty);\n candidates.push({\n type: \"class-path\",\n value: pathCss,\n score: pathScore\n });\n const xpath = SelectorGenerator.generateXPath(element, doc);\n candidates.push({\n type: \"xpath\",\n value: xpath,\n score: 40\n });\n const textBased = SelectorGenerator.generateTextBasedSelector(element);\n if (textBased) candidates.push({\n type: \"text\",\n value: textBased,\n score: 30\n });\n candidates.sort((a, b) => b.score - a.score);\n const selector = {\n css: candidates.find((c) => c.type !== \"xpath\" && c.type !== \"text\")?.value || pathCss,\n xpath,\n candidates\n };\n if (textBased) selector.textBased = textBased;\n if (testId) selector.dataTestId = testId;\n if (aria) selector.ariaLabel = aria;\n return selector;\n }\n /**\n * Generate a unique CSS selector for an element\n */\n static generateCSSSelector(element, doc) {\n if (element.id && SelectorGenerator.isUniqueId(element.id, doc)) return `#${CSS.escape(element.id)}`;\n const testId = SelectorGenerator.getDataTestId(element);\n if (testId) return `[data-testid=\"${CSS.escape(testId)}\"]`;\n const path = [];\n let current = element;\n while (current && current.nodeType === Node.ELEMENT_NODE) {\n let selector = current.nodeName.toLowerCase();\n if (current.id && SelectorGenerator.isUniqueId(current.id, doc)) {\n selector = `#${CSS.escape(current.id)}`;\n path.unshift(selector);\n break;\n }\n const classes = SelectorGenerator.getMeaningfulClasses(current);\n if (classes.length > 0) selector += `.${classes.map((c) => CSS.escape(c)).join(\".\")}`;\n const siblings = current.parentElement?.children;\n if (siblings && siblings.length > 1) {\n const index = Array.from(siblings).indexOf(current);\n if (index > 0 || !SelectorGenerator.isUniqueSelector(selector, current.parentElement)) selector += `:nth-child(${index + 1})`;\n }\n path.unshift(selector);\n current = current.parentElement;\n }\n return SelectorGenerator.optimizePath(path, element, doc);\n }\n /**\n * Generate XPath for an element\n */\n static generateXPath(element, doc) {\n if (element.id && SelectorGenerator.isUniqueId(element.id, doc)) return `//*[@id=\"${element.id}\"]`;\n const path = [];\n let current = element;\n while (current && current.nodeType === Node.ELEMENT_NODE) {\n const tagName = current.nodeName.toLowerCase();\n if (current.id && SelectorGenerator.isUniqueId(current.id, doc)) {\n path.unshift(`//*[@id=\"${current.id}\"]`);\n break;\n }\n let xpath = tagName;\n const siblings = current.parentElement?.children;\n if (siblings) {\n const sameTagSiblings = Array.from(siblings).filter((s) => s.nodeName.toLowerCase() === tagName);\n if (sameTagSiblings.length > 1) {\n const index = sameTagSiblings.indexOf(current) + 1;\n xpath += `[${index}]`;\n }\n }\n path.unshift(xpath);\n current = current.parentElement;\n }\n return `//${path.join(\"/\")}`;\n }\n /**\n * Generate a text-based selector for buttons and links\n */\n static generateTextBasedSelector(element) {\n const text = element.textContent?.trim();\n if (!text || text.length > 50) return void 0;\n const tag = element.nodeName.toLowerCase();\n if ([\n \"button\",\n \"a\",\n \"label\"\n ].includes(tag)) return `${tag}:contains(\"${text.replace(/['\"\\\\]/g, \"\\\\$&\")}\")`;\n }\n /**\n * Get data-testid or similar attributes\n */\n static getDataTestId(element) {\n return element.getAttribute(\"data-testid\") || element.getAttribute(\"data-test-id\") || element.getAttribute(\"data-test\") || element.getAttribute(\"data-cy\") || void 0;\n }\n /**\n * Check if an ID is unique in the document\n */\n static isUniqueId(id, doc) {\n return doc.querySelectorAll(`#${CSS.escape(id)}`).length === 1;\n }\n /**\n * Check if a selector is unique within a container\n */\n static isUniqueSelector(selector, container) {\n try {\n return container.querySelectorAll(selector).length === 1;\n } catch {\n return false;\n }\n }\n static isUniqueSelectorSafe(selector, doc) {\n try {\n return doc.querySelectorAll(selector).length === 1;\n } catch {\n return false;\n }\n }\n /**\n * Get meaningful classes (filtering out utility classes)\n */\n static getMeaningfulClasses(element) {\n const classes = Array.from(element.classList);\n const utilityPatterns = [\n /^(p|m|w|h|text|bg|border|flex|grid|col|row)-/,\n /^(xs|sm|md|lg|xl|2xl):/,\n /^(hover|focus|active|disabled|checked):/,\n /^js-/,\n /^is-/,\n /^has-/\n ];\n return classes.filter((cls) => {\n if (cls.length < 3) return false;\n return !utilityPatterns.some((pattern) => pattern.test(cls));\n }).slice(0, 2);\n }\n /**\n * Optimize the selector path by removing unnecessary parts\n */\n static optimizePath(path, element, doc) {\n for (let i = 0; i < path.length - 1; i++) {\n const shortPath = path.slice(i).join(\" > \");\n try {\n const matches = doc.querySelectorAll(shortPath);\n if (matches.length === 1 && matches[0] === element) return shortPath;\n } catch {}\n }\n return path.join(\" > \");\n }\n /**\n * Get a human-readable path description\n */\n static getContextPath(element) {\n const path = [];\n let current = element;\n let depth = 0;\n const maxDepth = 5;\n while (current && current !== element.ownerDocument?.body && depth < maxDepth) {\n const tag = current.nodeName.toLowerCase();\n let descriptor = tag;\n if (current.id) descriptor = `${tag}#${current.id}`;\n else if (current.className && typeof current.className === \"string\") {\n const firstClass = current.className.split(\" \")[0];\n if (firstClass) descriptor = `${tag}.${firstClass}`;\n }\n const role = current.getAttribute(\"role\");\n if (role) descriptor += `[role=\"${role}\"]`;\n path.unshift(descriptor);\n current = current.parentElement;\n depth++;\n }\n return path;\n }\n };\n }));\n //#endregion\n //#region src/traversal.ts\n var DOMTraversal;\n var init_traversal = __esmMin((() => {\n init_selectors();\n DOMTraversal = class DOMTraversal {\n static INTERACTIVE_SELECTORS = [\n \"button\",\n \"a[href]\",\n \"input:not([type=\\\"hidden\\\"])\",\n \"textarea\",\n \"select\",\n \"[role=\\\"button\\\"]\",\n \"[onclick]\",\n \"[contenteditable=\\\"true\\\"]\",\n \"summary\",\n \"[tabindex]:not([tabindex=\\\"-1\\\"])\"\n ];\n static SEMANTIC_SELECTORS = [\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"article\",\n \"section\",\n \"nav\",\n \"aside\",\n \"main\",\n \"header\",\n \"footer\",\n \"form\",\n \"table\",\n \"ul\",\n \"ol\",\n \"img[alt]\",\n \"figure\",\n \"video\",\n \"audio\",\n \"[role=\\\"navigation\\\"]\",\n \"[role=\\\"main\\\"]\",\n \"[role=\\\"complementary\\\"]\",\n \"[role=\\\"contentinfo\\\"]\"\n ];\n /**\n * Check if element is visible\n */\n static isVisible(element, computedStyle) {\n const rect = element.getBoundingClientRect();\n const style = computedStyle || element.ownerDocument?.defaultView?.getComputedStyle(element);\n if (!style) return false;\n return !!(rect.width > 0 && rect.height > 0 && style.display !== \"none\" && style.visibility !== \"hidden\" && style.opacity !== \"0\" && element.offsetParent !== null);\n }\n /**\n * Check if element is in viewport\n */\n static isInViewport(element, viewport) {\n const rect = element.getBoundingClientRect();\n const view = viewport || {\n width: element.ownerDocument?.defaultView?.innerWidth || 0,\n height: element.ownerDocument?.defaultView?.innerHeight || 0\n };\n return rect.top < view.height && rect.bottom > 0 && rect.left < view.width && rect.right > 0;\n }\n /**\n * Check if element passes filter criteria\n */\n static passesFilter(element, filter) {\n if (!filter) return true;\n const htmlElement = element;\n if (filter.excludeSelectors?.length) {\n for (const selector of filter.excludeSelectors) if (element.matches(selector)) return false;\n }\n if (filter.includeSelectors?.length) {\n let matches = false;\n for (const selector of filter.includeSelectors) if (element.matches(selector)) {\n matches = true;\n break;\n }\n if (!matches) return false;\n }\n if (filter.tags?.length && !filter.tags.includes(element.tagName.toLowerCase())) return false;\n const textContent = htmlElement.textContent?.toLowerCase() || \"\";\n if (filter.textContains?.length) {\n let hasText = false;\n for (const text of filter.textContains) if (textContent.includes(text.toLowerCase())) {\n hasText = true;\n break;\n }\n if (!hasText) return false;\n }\n if (filter.textMatches?.length) {\n let matches = false;\n for (const pattern of filter.textMatches) if (pattern.test(textContent)) {\n matches = true;\n break;\n }\n if (!matches) return false;\n }\n if (filter.hasAttributes?.length) {\n for (const attr of filter.hasAttributes) if (!element.hasAttribute(attr)) return false;\n }\n if (filter.attributeValues) for (const [attr, value] of Object.entries(filter.attributeValues)) {\n const attrValue = element.getAttribute(attr);\n if (!attrValue) return false;\n if (typeof value === \"string\") {\n if (attrValue !== value) return false;\n } else if (value instanceof RegExp) {\n if (!value.test(attrValue)) return false;\n }\n }\n if (filter.withinSelectors?.length) {\n let isWithin = false;\n for (const selector of filter.withinSelectors) if (element.closest(selector)) {\n isWithin = true;\n break;\n }\n if (!isWithin) return false;\n }\n if (filter.interactionTypes?.length) {\n const interaction = DOMTraversal.getInteractionInfo(element);\n let hasInteraction = false;\n for (const type of filter.interactionTypes) if (interaction[type]) {\n hasInteraction = true;\n break;\n }\n if (!hasInteraction) return false;\n }\n if (filter.nearText) {\n const parent = element.parentElement;\n if (!parent || !parent.textContent?.toLowerCase().includes(filter.nearText.toLowerCase())) return false;\n }\n return true;\n }\n /**\n * Extract element information\n */\n static extractElement(element, options, depth = 0) {\n if (options.maxDepth && depth > options.maxDepth) return null;\n if (!options.includeHidden && !DOMTraversal.isVisible(element)) return null;\n if (options.viewportOnly && !DOMTraversal.isInViewport(element)) return null;\n if (!DOMTraversal.passesFilter(element, options.filter)) return null;\n const htmlElement = element;\n const extracted = {\n tag: element.tagName.toLowerCase(),\n text: DOMTraversal.getElementText(element, options),\n selector: SelectorGenerator.generateSelectors(element),\n attributes: DOMTraversal.getRelevantAttributes(element, options),\n context: DOMTraversal.getElementContext(element),\n interaction: DOMTraversal.getInteractionInfo(element)\n };\n if (options.mode === \"full\" && DOMTraversal.isSemanticContainer(element)) {\n const children = [];\n if (options.includeShadowDOM && htmlElement.shadowRoot) {\n const shadowChildren = DOMTraversal.extractChildren(htmlElement.shadowRoot, options, depth + 1);\n children.push(...shadowChildren);\n }\n const regularChildren = DOMTraversal.extractChildren(element, options, depth + 1);\n children.push(...regularChildren);\n if (children.length > 0) extracted.children = children;\n }\n return extracted;\n }\n /**\n * Extract children elements\n */\n static extractChildren(container, options, depth) {\n const children = [];\n const elements = container.querySelectorAll(\"*\");\n for (const child of Array.from(elements)) {\n if (DOMTraversal.hasExtractedAncestor(child, elements)) continue;\n const extracted = DOMTraversal.extractElement(child, options, depth);\n if (extracted) children.push(extracted);\n }\n return children;\n }\n /**\n * Check if element has an ancestor that was already extracted\n */\n static hasExtractedAncestor(element, extractedElements) {\n let parent = element.parentElement;\n while (parent) {\n if (Array.from(extractedElements).includes(parent)) return true;\n parent = parent.parentElement;\n }\n return false;\n }\n /**\n * Get relevant attributes for an element\n */\n static getRelevantAttributes(element, options) {\n const relevant = [\n \"id\",\n \"class\",\n \"name\",\n \"type\",\n \"value\",\n \"placeholder\",\n \"href\",\n \"src\",\n \"alt\",\n \"title\",\n \"action\",\n \"method\",\n \"aria-label\",\n \"aria-describedby\",\n \"aria-controls\",\n \"role\",\n \"disabled\",\n \"readonly\",\n \"required\",\n \"checked\",\n \"min\",\n \"max\",\n \"pattern\",\n \"step\",\n \"autocomplete\",\n \"data-testid\",\n \"data-test\",\n \"data-cy\"\n ];\n const attributes = {};\n const attrTruncate = options.attributeTruncateLength ?? 100;\n const dataAttrTruncate = options.dataAttributeTruncateLength ?? 50;\n for (const attr of relevant) {\n const value = element.getAttribute(attr);\n if (value) attributes[attr] = value.length > attrTruncate ? `${value.substring(0, attrTruncate)}...` : value;\n }\n for (const attr of element.attributes) if (attr.name.startsWith(\"data-\") && !relevant.includes(attr.name)) attributes[attr.name] = attr.value.length > dataAttrTruncate ? `${attr.value.substring(0, dataAttrTruncate)}...` : attr.value;\n return attributes;\n }\n /**\n * Get element context information\n */\n static getElementContext(element) {\n const context = { parentChain: SelectorGenerator.getContextPath(element) };\n const form = element.closest(\"form\");\n if (form) context.nearestForm = SelectorGenerator.generateSelectors(form).css;\n const section = element.closest(\"section, [role=\\\"region\\\"]\");\n if (section) context.nearestSection = SelectorGenerator.generateSelectors(section).css;\n const main = element.closest(\"main, [role=\\\"main\\\"]\");\n if (main) context.nearestMain = SelectorGenerator.generateSelectors(main).css;\n const nav = element.closest(\"nav, [role=\\\"navigation\\\"]\");\n if (nav) context.nearestNav = SelectorGenerator.generateSelectors(nav).css;\n return context;\n }\n /**\n * Get interaction information for an element (compact format)\n */\n static getInteractionInfo(element) {\n const htmlElement = element;\n const interaction = {};\n if (!!(htmlElement.onclick || element.getAttribute(\"onclick\") || element.matches(\"button, a[href], [role=\\\"button\\\"], [tabindex]:not([tabindex=\\\"-1\\\"])\"))) interaction.click = true;\n if (!!(htmlElement.onchange || element.getAttribute(\"onchange\") || element.matches(\"input, select, textarea\"))) interaction.change = true;\n if (!!(htmlElement.onsubmit || element.getAttribute(\"onsubmit\") || element.matches(\"form\"))) interaction.submit = true;\n if (element.matches(\"a[href], button[type=\\\"submit\\\"]\")) interaction.nav = true;\n if (htmlElement.hasAttribute(\"disabled\") || htmlElement.getAttribute(\"aria-disabled\") === \"true\") interaction.disabled = true;\n if (!DOMTraversal.isVisible(element)) interaction.hidden = true;\n const ariaRole = element.getAttribute(\"role\");\n if (ariaRole) interaction.role = ariaRole;\n if (element.matches(\"input, textarea, select, button\")) {\n const form = element.form || element.closest(\"form\");\n if (form) interaction.form = SelectorGenerator.generateSelectors(form).css;\n }\n return interaction;\n }\n /**\n * Get text content of an element (limited length)\n */\n static getElementText(element, options) {\n if (element.matches(\"input, textarea\")) {\n const input = element;\n return input.value || input.placeholder || \"\";\n }\n if (element.matches(\"img\")) return element.alt || \"\";\n const text = element.textContent?.trim() || \"\";\n const maxLength = options?.textTruncateLength;\n if (maxLength && text.length > maxLength) return `${text.substring(0, maxLength)}...`;\n return text;\n }\n /**\n * Check if element is a semantic container\n */\n static isSemanticContainer(element) {\n return element.matches(\"article, section, nav, aside, main, header, footer, form, table, ul, ol, dl, figure, details, dialog, [role=\\\"region\\\"], [role=\\\"navigation\\\"], [role=\\\"main\\\"], [role=\\\"complementary\\\"]\");\n }\n /**\n * Get interactive elements\n */\n static getInteractiveElements(container, options) {\n const elements = [];\n const selector = DOMTraversal.INTERACTIVE_SELECTORS.join(\", \");\n const found = container.querySelectorAll(selector);\n for (const element of Array.from(found)) {\n const extracted = DOMTraversal.extractElement(element, options);\n if (extracted) elements.push(extracted);\n }\n if (options.customSelectors) for (const customSelector of options.customSelectors) try {\n const customFound = container.querySelectorAll(customSelector);\n for (const element of Array.from(customFound)) {\n const extracted = DOMTraversal.extractElement(element, options);\n if (extracted) elements.push(extracted);\n }\n } catch (_e) {\n console.warn(`Invalid custom selector: ${customSelector}`);\n }\n return elements;\n }\n /**\n * Get semantic elements (for full mode)\n */\n static getSemanticElements(container, options) {\n const elements = [];\n const selector = DOMTraversal.SEMANTIC_SELECTORS.join(\", \");\n const found = container.querySelectorAll(selector);\n for (const element of Array.from(found)) {\n const extracted = DOMTraversal.extractElement(element, options);\n if (extracted) elements.push(extracted);\n }\n return elements;\n }\n };\n }));\n //#endregion\n //#region src/markdown-formatter.ts\n function truncate(text, len) {\n const t = (text ?? \"\").trim();\n if (!len || t.length <= len) return t;\n const keywords = [\n \"login\",\n \"log in\",\n \"sign in\",\n \"sign up\",\n \"submit\",\n \"search\",\n \"filter\",\n \"add to cart\",\n \"next\",\n \"continue\"\n ];\n const lower = t.toLowerCase();\n const hit = keywords.map((k) => ({\n k,\n i: lower.indexOf(k)\n })).find((x) => x.i > -1);\n const head = Math.max(0, Math.floor(len * .66));\n if (hit && hit.i > head) {\n const tailWindow = Math.max(12, len - head - 5);\n const start = Math.max(0, hit.i - Math.floor(tailWindow / 2));\n const end = Math.min(t.length, start + tailWindow);\n return `${t.slice(0, head).trimEnd()} … ${t.slice(start, end).trim()}…`;\n }\n const slice = t.slice(0, len);\n const lastSpace = slice.lastIndexOf(\" \");\n return `${lastSpace > 32 ? slice.slice(0, lastSpace) : slice}…`;\n }\n function bestSelector(el) {\n return el.selector?.css || \"\";\n }\n function hashId(input) {\n let h = 5381;\n for (let i = 0; i < input.length; i++) h = h * 33 ^ input.charCodeAt(i);\n return `sec-${(h >>> 0).toString(36)}`;\n }\n function iconForRegion(key) {\n switch (key) {\n case \"header\": return \"🧭\";\n case \"navigation\": return \"📑\";\n case \"main\": return \"📄\";\n case \"sections\": return \"🗂️\";\n case \"sidebar\": return \"📚\";\n case \"footer\": return \"🔻\";\n case \"modals\": return \"💬\";\n default: return \"🔹\";\n }\n }\n function elementLine(el, opts) {\n const txt = truncate(el.text || el.attributes?.ariaLabel, opts?.maxTextLength ?? 80);\n const sel = bestSelector(el);\n const tag = el.tag.toLowerCase();\n const action = el.interaction?.submit ? \"submit\" : el.interaction?.click ? \"click\" : el.interaction?.change ? \"change\" : void 0;\n const actionText = action ? ` (${action})` : \"\";\n return `- ${tag.toUpperCase()}: ${txt || \"(no text)\"} → \\`${sel}\\`${actionText}`;\n }\n function selectorQualitySummary(inter) {\n const all = [];\n all.push(...inter.buttons.map((e) => e.selector?.css || \"\"));\n all.push(...inter.links.map((e) => e.selector?.css || \"\"));\n all.push(...inter.inputs.map((e) => e.selector?.css || \"\"));\n all.push(...inter.clickable.map((e) => e.selector?.css || \"\"));\n const total = all.length || 1;\n const idCount = all.filter((s) => s.startsWith(\"#\")).length;\n const testIdCount = all.filter((s) => /\\[data-testid=/.test(s)).length;\n const nthCount = all.filter((s) => /:nth-child\\(/.test(s)).length;\n const stable = idCount + testIdCount;\n return `Selector quality: ${Math.round(stable / total * 100)}% stable (ID/data-testid), ${Math.round(nthCount / total * 100)}% structural (:nth-child)`;\n }\n function renderInteractive(inter, opts) {\n const parts = [];\n const limit = (arr) => typeof opts?.maxElements === \"number\" ? arr.slice(0, opts.maxElements) : arr;\n if (inter.buttons.length) {\n parts.push(\"Buttons:\");\n for (const el of limit(inter.buttons)) parts.push(elementLine(el, opts));\n }\n if (inter.links.length) {\n parts.push(\"Links:\");\n for (const el of limit(inter.links)) parts.push(elementLine(el, opts));\n }\n if (inter.inputs.length) {\n parts.push(\"Inputs:\");\n for (const el of limit(inter.inputs)) parts.push(elementLine(el, opts));\n }\n if (inter.clickable.length) {\n parts.push(\"Other Clickable:\");\n for (const el of limit(inter.clickable)) parts.push(elementLine(el, opts));\n }\n if (inter.forms.length) {\n parts.push(\"Forms:\");\n for (const f of limit(inter.forms)) parts.push(`- FORM: action=${f.action ?? \"-\"} method=${f.method ?? \"-\"} → \\`${f.selector}\\``);\n }\n return parts.join(\"\\n\");\n }\n function renderRegionInfo(region) {\n const icon = iconForRegion(\"region\");\n const id = hashId(`${region.selector}|${region.label ?? \"\"}|${region.role ?? \"\"}`);\n const label = region.label ? ` ${region.label}` : \"\";\n const stats = [];\n if (region.buttonCount) stats.push(`${region.buttonCount} buttons`);\n if (region.linkCount) stats.push(`${region.linkCount} links`);\n if (region.inputCount) stats.push(`${region.inputCount} inputs`);\n if (region.textPreview) stats.push(`“${truncate(region.textPreview, 80)}”`);\n const statsLine = stats.length ? ` — ${stats.join(\", \")}` : \"\";\n return `${icon} ${label} → \\`${region.selector}\\` [${id}]${statsLine}`;\n }\n function wrapXml(body, meta, type = \"section\") {\n return `<page ${[meta?.title ? `title=\"${escapeXml(meta?.title)}\"` : null, meta?.url ? `url=\"${escapeXml(meta?.url)}\"` : null].filter(Boolean).join(\" \")}>\\n <${type}><![CDATA[\\n${body}\\n]]></${type}>\\n</page>`;\n }\n function escapeXml(s) {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n }\n function capitalize(s) {\n return s.charAt(0).toUpperCase() + s.slice(1);\n }\n var MarkdownFormatter;\n var init_markdown_formatter = __esmMin((() => {\n MarkdownFormatter = class {\n static structure(overview, _opts = {}, meta) {\n const lines = [];\n lines.push(\"# Page Outline\");\n if (meta?.title || meta?.url) {\n lines.push(`Title: ${meta?.title ?? \"\"}`.trim());\n lines.push(`URL: ${meta?.url ?? \"\"}`.trim());\n }\n lines.push(\"\");\n const regions = overview.regions;\n const entries = [\n [\"header\", regions.header],\n [\"navigation\", regions.navigation],\n [\"main\", regions.main],\n [\"sections\", regions.sections],\n [\"sidebar\", regions.sidebar],\n [\"footer\", regions.footer],\n [\"modals\", regions.modals]\n ];\n for (const [key, value] of entries) {\n if (!value) continue;\n const icon = iconForRegion(key);\n if (Array.isArray(value)) {\n if (!value.length) continue;\n lines.push(`## ${icon} ${capitalize(key)}`);\n for (const region of value) lines.push(renderRegionInfo(region));\n } else {\n lines.push(`## ${icon} ${capitalize(key)}`);\n lines.push(renderRegionInfo(value));\n }\n lines.push(\"\");\n }\n if (overview.suggestions?.length) {\n lines.push(\"## Suggestions\");\n for (const s of overview.suggestions) lines.push(`- ${s}`);\n lines.push(\"\");\n }\n lines.push(\"Next: choose a region (by selector or [sectionId]) and call dom_extract_region for actionable details.\");\n return wrapXml(lines.join(\"\\n\"), meta, \"outline\");\n }\n static region(result, opts = {}, meta) {\n const lines = [];\n lines.push(\"# Region Details\");\n if (meta?.title || meta?.url) {\n lines.push(`Title: ${meta?.title ?? \"\"}`.trim());\n lines.push(`URL: ${meta?.url ?? \"\"}`.trim());\n }\n lines.push(\"\");\n const inter = result.interactive;\n if (result.page) {\n const ps = [\n result.page.hasErrors ? \"errors: yes\" : \"errors: no\",\n result.page.isLoading ? \"loading: yes\" : \"loading: no\",\n result.page.hasModals ? \"modals: yes\" : \"modals: no\"\n ];\n lines.push(`Page state: ${ps.join(\", \")}`);\n }\n const summary = [];\n const count = (arr) => arr ? arr.length : 0;\n summary.push(`${count(inter.buttons)} buttons`);\n summary.push(`${count(inter.links)} links`);\n summary.push(`${count(inter.inputs)} inputs`);\n if (inter.forms?.length) summary.push(`${count(inter.forms)} forms`);\n lines.push(`Summary: ${summary.join(\", \")}`);\n lines.push(selectorQualitySummary(inter));\n lines.push(\"\");\n lines.push(renderInteractive(inter, opts));\n lines.push(\"\");\n lines.push(\"Next: write a script using the most stable selectors above. If selectors look unstable, rerun dom_extract_region with higher detail or call dom_extract_content for text context.\");\n return wrapXml(lines.join(\"\\n\"), meta, \"section\");\n }\n static content(content, opts = {}, meta) {\n const lines = [];\n lines.push(\"# Content\");\n lines.push(`Selector: \\`${content.selector}\\``);\n lines.push(\"\");\n if (content.text.headings?.length) {\n lines.push(\"Headings:\");\n for (const h of content.text.headings) lines.push(`- H${h.level}: ${truncate(h.text, opts.maxTextLength ?? 120)}`);\n lines.push(\"\");\n }\n if (content.text.paragraphs?.length) {\n const limit = typeof opts.maxElements === \"number\" ? opts.maxElements : content.text.paragraphs.length;\n lines.push(\"Paragraphs:\");\n for (const p of content.text.paragraphs.slice(0, limit)) lines.push(`- ${truncate(p, opts.maxTextLength ?? 200)}`);\n lines.push(\"\");\n }\n if (content.text.lists?.length) {\n lines.push(\"Lists:\");\n for (const list of content.text.lists) {\n lines.push(`- ${list.type.toUpperCase()}:`);\n const limit = typeof opts.maxElements === \"number\" ? opts.maxElements : list.items.length;\n for (const item of list.items.slice(0, limit)) lines.push(` - ${truncate(item, opts.maxTextLength ?? 120)}`);\n }\n lines.push(\"\");\n }\n if (content.tables?.length) {\n lines.push(\"Tables:\");\n for (const t of content.tables) {\n lines.push(`- Headers: ${t.headers.join(\" | \")}`);\n const limit = typeof opts.maxElements === \"number\" ? opts.maxElements : t.rows.length;\n for (const row of t.rows.slice(0, limit)) lines.push(` - ${row.join(\" | \")}`);\n }\n lines.push(\"\");\n }\n if (content.media?.length) {\n lines.push(\"Media:\");\n const limit = typeof opts.maxElements === \"number\" ? opts.maxElements : content.media.length;\n for (const m of content.media.slice(0, limit)) lines.push(`- ${m.type.toUpperCase()}: ${m.alt ?? \"\"} ${m.src ? `→ ${m.src}` : \"\"}`.trim());\n lines.push(\"\");\n }\n lines.push(\"Next: if text is insufficient for targeting, call dom_extract_region for interactive selectors.\");\n return wrapXml(lines.join(\"\\n\"), meta, \"content\");\n }\n };\n }));\n //#endregion\n //#region src/progressive.ts\n function resolveSmartDomReader() {\n if (typeof window !== \"undefined\") {\n const globalWindow = window;\n const direct = globalWindow.SmartDOMReader;\n if (typeof direct === \"function\") return direct;\n const namespace = globalWindow.SmartDOMReaderNamespace;\n if (namespace && typeof namespace.SmartDOMReader === \"function\") return namespace.SmartDOMReader;\n }\n try {\n if (typeof require === \"function\") {\n const moduleExports = (init_src(), __toCommonJS(src_exports));\n if (moduleExports && typeof moduleExports.SmartDOMReader === \"function\") return moduleExports.SmartDOMReader;\n if (moduleExports && typeof moduleExports.default === \"function\") return moduleExports.default;\n }\n } catch {}\n }\n var ProgressiveExtractor;\n var init_progressive = __esmMin((() => {\n init_content_detection();\n init_selectors();\n init_traversal();\n ProgressiveExtractor = class ProgressiveExtractor {\n /**\n * Step 1: Extract high-level structural overview\n * This provides a \"map\" of the page for the AI to understand structure\n */\n static extractStructure(root) {\n const regions = {};\n const header = root.querySelector(\"header, [role=\\\"banner\\\"], .header, #header\");\n if (header) regions.header = ProgressiveExtractor.analyzeRegion(header);\n const navs = root.querySelectorAll(\"nav, [role=\\\"navigation\\\"], .nav, .navigation\");\n if (navs.length > 0) regions.navigation = Array.from(navs).map((nav) => ProgressiveExtractor.analyzeRegion(nav));\n if (root instanceof Document) {\n const main = ContentDetection.findMainContent(root);\n if (main) {\n regions.main = ProgressiveExtractor.analyzeRegion(main);\n const sections = main.querySelectorAll(\"section, article, [role=\\\"region\\\"]\");\n if (sections.length > 0) regions.sections = Array.from(sections).filter((section) => !section.closest(\"nav, header, footer\")).map((section) => ProgressiveExtractor.analyzeRegion(section));\n }\n } else {\n regions.main = ProgressiveExtractor.analyzeRegion(root);\n const sections = root.querySelectorAll(\"section, article, [role=\\\"region\\\"]\");\n if (sections.length > 0) regions.sections = Array.from(sections).filter((section) => !section.closest(\"nav, header, footer\")).map((section) => ProgressiveExtractor.analyzeRegion(section));\n }\n const sidebars = root.querySelectorAll(\"aside, [role=\\\"complementary\\\"], .sidebar, #sidebar\");\n if (sidebars.length > 0) regions.sidebar = Array.from(sidebars).map((sidebar) => ProgressiveExtractor.analyzeRegion(sidebar));\n const footer = root.querySelector(\"footer, [role=\\\"contentinfo\\\"], .footer, #footer\");\n if (footer) regions.footer = ProgressiveExtractor.analyzeRegion(footer);\n const modals = root.querySelectorAll(\"[role=\\\"dialog\\\"], .modal, .popup, .overlay\");\n const visibleModals = Array.from(modals).filter((modal) => DOMTraversal.isVisible(modal));\n if (visibleModals.length > 0) regions.modals = visibleModals.map((modal) => ProgressiveExtractor.analyzeRegion(modal));\n const forms = ProgressiveExtractor.extractFormOverview(root);\n const summary = ProgressiveExtractor.calculateSummary(root, regions, forms);\n return {\n regions,\n forms,\n summary,\n suggestions: ProgressiveExtractor.generateSuggestions(regions, summary)\n };\n }\n /**\n * Step 2: Extract detailed information from a specific region\n */\n static extractRegion(selector, doc, options = {}, smartDomReaderCtor) {\n const element = doc.querySelector(selector);\n if (!element) return null;\n const SmartDOMReaderCtor = smartDomReaderCtor ?? resolveSmartDomReader();\n if (!SmartDOMReaderCtor) throw new Error(\"SmartDOMReader is unavailable. Ensure the Smart DOM Reader module is loaded before calling extractRegion.\");\n return new SmartDOMReaderCtor(options).extract(element, options);\n }\n /**\n * Step 3: Extract readable content from a region\n */\n static extractContent(selector, doc, options = {}) {\n const element = doc.querySelector(selector);\n if (!element) return null;\n const result = {\n selector,\n text: {},\n metadata: {\n wordCount: 0,\n hasInteractive: false\n }\n };\n if (options.includeHeadings !== false) {\n const headings = element.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\n result.text.headings = Array.from(headings).map((h) => ({\n level: Number.parseInt(h.tagName[1], 10),\n text: ProgressiveExtractor.getTextContent(h, options.maxTextLength)\n }));\n }\n const paragraphs = element.querySelectorAll(\"p\");\n if (paragraphs.length > 0) result.text.paragraphs = Array.from(paragraphs).map((p) => ProgressiveExtractor.getTextContent(p, options.maxTextLength)).filter((text) => text.length > 0);\n if (options.includeLists !== false) {\n const lists = element.querySelectorAll(\"ul, ol\");\n result.text.lists = Array.from(lists).map((list) => ({\n type: list.tagName.toLowerCase(),\n items: Array.from(list.querySelectorAll(\"li\")).map((li) => ProgressiveExtractor.getTextContent(li, options.maxTextLength))\n }));\n }\n if (options.includeTables !== false) {\n const tables = element.querySelectorAll(\"table\");\n result.tables = Array.from(tables).map((table) => {\n return {\n headers: Array.from(table.querySelectorAll(\"th\")).map((th) => ProgressiveExtractor.getTextContent(th)),\n rows: Array.from(table.querySelectorAll(\"tr\")).filter((tr) => tr.querySelector(\"td\")).map((tr) => Array.from(tr.querySelectorAll(\"td\")).map((td) => ProgressiveExtractor.getTextContent(td)))\n };\n });\n }\n if (options.includeMedia !== false) {\n const images = element.querySelectorAll(\"img\");\n const videos = element.querySelectorAll(\"video\");\n const audios = element.querySelectorAll(\"audio\");\n result.media = [\n ...Array.from(images).map((img) => {\n const item = { type: \"img\" };\n const alt = img.getAttribute(\"alt\");\n const src = img.getAttribute(\"src\");\n if (alt) item.alt = alt;\n if (src) item.src = src;\n return item;\n }),\n ...Array.from(videos).map((video) => {\n const item = { type: \"video\" };\n const src = video.getAttribute(\"src\");\n if (src) item.src = src;\n return item;\n }),\n ...Array.from(audios).map((audio) => {\n const item = { type: \"audio\" };\n const src = audio.getAttribute(\"src\");\n if (src) item.src = src;\n return item;\n })\n ];\n }\n const allText = element.textContent || \"\";\n result.metadata.wordCount = allText.trim().split(/\\s+/).length;\n result.metadata.hasInteractive = element.querySelectorAll(\"button, a, input, textarea, select\").length > 0;\n return result;\n }\n /**\n * Analyze a region and extract summary information\n */\n static analyzeRegion(element) {\n const selector = SelectorGenerator.generateSelectors(element).css;\n const buttons = element.querySelectorAll(\"button, [role=\\\"button\\\"]\");\n const links = element.querySelectorAll(\"a[href]\");\n const inputs = element.querySelectorAll(\"input, textarea, select\");\n const forms = element.querySelectorAll(\"form\");\n const lists = element.querySelectorAll(\"ul, ol\");\n const tables = element.querySelectorAll(\"table\");\n const media = element.querySelectorAll(\"img, video, audio\");\n const interactiveCount = buttons.length + links.length + inputs.length;\n let label;\n const ariaLabel = element.getAttribute(\"aria-label\");\n if (ariaLabel) label = ariaLabel;\n else if (element.getAttribute(\"aria-labelledby\")) {\n const labelId = element.getAttribute(\"aria-labelledby\");\n if (labelId) {\n const labelElement = element.ownerDocument?.getElementById(labelId);\n if (labelElement) label = labelElement.textContent?.trim();\n }\n } else {\n const heading = element.querySelector(\"h1, h2, h3\");\n if (heading) label = heading.textContent?.trim();\n }\n const textContent = element.textContent?.trim() || \"\";\n const textPreview = textContent.length > 50 ? `${textContent.substring(0, 50)}...` : textContent;\n const regionInfo = {\n selector,\n interactiveCount,\n hasForm: forms.length > 0,\n hasList: lists.length > 0,\n hasTable: tables.length > 0,\n hasMedia: media.length > 0\n };\n if (label) regionInfo.label = label;\n const role = element.getAttribute(\"role\");\n if (role) regionInfo.role = role;\n if (buttons.length > 0) regionInfo.buttonCount = buttons.length;\n if (links.length > 0) regionInfo.linkCount = links.length;\n if (inputs.length > 0) regionInfo.inputCount = inputs.length;\n if (textPreview.length > 0) regionInfo.textPreview = textPreview;\n return regionInfo;\n }\n /**\n * Extract overview of forms on the page\n */\n static extractFormOverview(root) {\n const forms = root.querySelectorAll(\"form\");\n return Array.from(forms).map((form) => {\n const inputs = form.querySelectorAll(\"input, textarea, select\");\n const selector = SelectorGenerator.generateSelectors(form).css;\n let location = \"unknown\";\n if (form.closest(\"header, [role=\\\"banner\\\"]\")) location = \"header\";\n else if (form.closest(\"nav, [role=\\\"navigation\\\"]\")) location = \"navigation\";\n else if (form.closest(\"main, [role=\\\"main\\\"]\")) location = \"main\";\n else if (form.closest(\"aside, [role=\\\"complementary\\\"]\")) location = \"sidebar\";\n else if (form.closest(\"footer, [role=\\\"contentinfo\\\"]\")) location = \"footer\";\n let purpose;\n const formId = form.getAttribute(\"id\")?.toLowerCase();\n const formClass = form.getAttribute(\"class\")?.toLowerCase();\n const formAction = form.getAttribute(\"action\")?.toLowerCase();\n const hasEmail = form.querySelector(\"input[type=\\\"email\\\"]\");\n const hasPassword = form.querySelector(\"input[type=\\\"password\\\"]\");\n if (form.querySelector(\"input[type=\\\"search\\\"]\") || formId?.includes(\"search\") || formClass?.includes(\"search\")) purpose = \"search\";\n else if (hasPassword && hasEmail) purpose = \"login\";\n else if (hasPassword) purpose = \"authentication\";\n else if (formId?.includes(\"contact\") || formClass?.includes(\"contact\")) purpose = \"contact\";\n else if (formId?.includes(\"subscribe\") || formClass?.includes(\"subscribe\")) purpose = \"subscription\";\n else if (formAction?.includes(\"checkout\") || formClass?.includes(\"checkout\")) purpose = \"checkout\";\n const formOverview = {\n selector,\n location,\n inputCount: inputs.length\n };\n if (purpose) formOverview.purpose = purpose;\n return formOverview;\n });\n }\n /**\n * Calculate summary statistics\n */\n static calculateSummary(root, regions, forms) {\n const allInteractive = root.querySelectorAll(\"button, a[href], input, textarea, select\");\n const allSections = root.querySelectorAll(\"section, article, [role=\\\"region\\\"]\");\n const hasModals = (regions.modals?.length || 0) > 0;\n const hasErrors = [\n \".error\",\n \".alert-danger\",\n \"[role=\\\"alert\\\"]\"\n ].some((sel) => {\n const element = root.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n const isLoading = [\n \".loading\",\n \".spinner\",\n \"[aria-busy=\\\"true\\\"]\"\n ].some((sel) => {\n const element = root.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n const summary = {\n totalInteractive: allInteractive.length,\n totalForms: forms.length,\n totalSections: allSections.length,\n hasModals,\n hasErrors,\n isLoading\n };\n const mainContentSelector = regions.main?.selector;\n if (mainContentSelector) summary.mainContentSelector = mainContentSelector;\n return summary;\n }\n /**\n * Generate AI-friendly suggestions\n */\n static generateSuggestions(regions, summary) {\n const suggestions = [];\n if (summary.hasErrors) suggestions.push(\"Page has error indicators - check error messages before interacting\");\n if (summary.isLoading) suggestions.push(\"Page appears to be loading - wait or check loading state\");\n if (summary.hasModals) suggestions.push(\"Modal/dialog is open - may need to interact with or close it first\");\n if (regions.main && regions.main.interactiveCount > 10) suggestions.push(`Main content has ${regions.main.interactiveCount} interactive elements - consider filtering`);\n if (summary.totalForms > 0) suggestions.push(`Found ${summary.totalForms} form(s) on the page`);\n if (!regions.main) suggestions.push(\"No clear main content area detected - may need to explore regions\");\n return suggestions;\n }\n /**\n * Get text content with optional truncation\n */\n static getTextContent(element, maxLength) {\n const text = element.textContent?.trim() || \"\";\n if (maxLength && text.length > maxLength) return `${text.substring(0, maxLength)}...`;\n return text;\n }\n };\n }));\n //#endregion\n //#region src/types.ts\n var init_types = __esmMin((() => {}));\n //#endregion\n //#region src/index.ts\n var src_exports = /* @__PURE__ */ __exportAll({\n ContentDetection: () => ContentDetection,\n MarkdownFormatter: () => MarkdownFormatter,\n ProgressiveExtractor: () => ProgressiveExtractor,\n SelectorGenerator: () => SelectorGenerator,\n SmartDOMReader: () => SmartDOMReader,\n default: () => SmartDOMReader\n });\n var SmartDOMReader;\n var init_src = __esmMin((() => {\n init_content_detection();\n init_selectors();\n init_traversal();\n init_markdown_formatter();\n init_progressive();\n init_types();\n SmartDOMReader = class SmartDOMReader {\n options;\n constructor(options = {}) {\n this.options = {\n mode: options.mode || \"interactive\",\n maxDepth: options.maxDepth || 5,\n includeHidden: options.includeHidden || false,\n includeShadowDOM: options.includeShadowDOM ?? true,\n includeIframes: options.includeIframes || false,\n viewportOnly: options.viewportOnly || false,\n mainContentOnly: options.mainContentOnly || false,\n customSelectors: options.customSelectors || [],\n ...options.attributeTruncateLength !== void 0 && { attributeTruncateLength: options.attributeTruncateLength },\n ...options.dataAttributeTruncateLength !== void 0 && { dataAttributeTruncateLength: options.dataAttributeTruncateLength },\n ...options.textTruncateLength !== void 0 && { textTruncateLength: options.textTruncateLength },\n ...options.filter !== void 0 && { filter: options.filter }\n };\n }\n /**\n * Main extraction method - extracts all data in one pass\n * @param rootElement The document or element to extract from\n * @param runtimeOptions Options to override constructor options\n */\n extract(rootElement = document, runtimeOptions) {\n const startTime = Date.now();\n const doc = rootElement instanceof Document ? rootElement : rootElement.ownerDocument;\n const options = {\n ...this.options,\n ...runtimeOptions\n };\n let container = rootElement instanceof Document ? doc : rootElement;\n if (options.mainContentOnly && rootElement instanceof Document) container = ContentDetection.findMainContent(doc);\n const pageState = this.extractPageState(doc);\n const landmarks = this.extractLandmarks(doc);\n const interactive = this.extractInteractiveElements(container, options);\n const result = {\n mode: options.mode,\n timestamp: startTime,\n page: pageState,\n landmarks,\n interactive\n };\n if (options.mode === \"full\") {\n const semantic = this.extractSemanticElements(container, options);\n const metadata = this.extractMetadata(doc, container, options);\n return {\n ...result,\n semantic,\n metadata\n };\n }\n return result;\n }\n /**\n * Extract page state information\n */\n extractPageState(doc) {\n const hasFocus = this.getFocusedElement(doc);\n return {\n url: doc.location?.href || \"\",\n title: doc.title || \"\",\n hasErrors: this.detectErrors(doc),\n isLoading: this.detectLoading(doc),\n hasModals: this.detectModals(doc),\n ...hasFocus !== void 0 && { hasFocus }\n };\n }\n /**\n * Extract page landmarks\n */\n extractLandmarks(doc) {\n const detected = ContentDetection.detectLandmarks(doc);\n return {\n navigation: this.elementsToSelectors(detected.navigation || []),\n main: this.elementsToSelectors(detected.main || []),\n forms: this.elementsToSelectors(detected.form || []),\n headers: this.elementsToSelectors(detected.banner || []),\n footers: this.elementsToSelectors(detected.contentinfo || []),\n articles: this.elementsToSelectors(detected.region || []),\n sections: this.elementsToSelectors(detected.region || [])\n };\n }\n /**\n * Convert elements to selector strings\n */\n elementsToSelectors(elements) {\n return elements.map((el) => SelectorGenerator.generateSelectors(el).css);\n }\n /**\n * Extract interactive elements\n */\n extractInteractiveElements(container, options) {\n const buttons = [];\n const links = [];\n const inputs = [];\n const clickable = [];\n container.querySelectorAll(\"button, [role=\\\"button\\\"], input[type=\\\"button\\\"], input[type=\\\"submit\\\"]\").forEach((el) => {\n if (this.shouldIncludeElement(el, options)) {\n const extracted = DOMTraversal.extractElement(el, options);\n if (extracted) buttons.push(extracted);\n }\n });\n container.querySelectorAll(\"a[href]\").forEach((el) => {\n if (this.shouldIncludeElement(el, options)) {\n const extracted = DOMTraversal.extractElement(el, options);\n if (extracted) links.push(extracted);\n }\n });\n container.querySelectorAll(\"input:not([type=\\\"button\\\"]):not([type=\\\"submit\\\"]), textarea, select\").forEach((el) => {\n if (this.shouldIncludeElement(el, options)) {\n const extracted = DOMTraversal.extractElement(el, options);\n if (extracted) inputs.push(extracted);\n }\n });\n if (options.customSelectors) options.customSelectors.forEach((selector) => {\n container.querySelectorAll(selector).forEach((el) => {\n if (this.shouldIncludeElement(el, options)) {\n const extracted = DOMTraversal.extractElement(el, options);\n if (extracted) clickable.push(extracted);\n }\n });\n });\n return {\n buttons,\n links,\n inputs,\n forms: this.extractForms(container, options),\n clickable\n };\n }\n /**\n * Extract form information\n */\n extractForms(container, options) {\n const forms = [];\n container.querySelectorAll(\"form\").forEach((form) => {\n if (!this.shouldIncludeElement(form, options)) return;\n const formInputs = [];\n const formButtons = [];\n form.querySelectorAll(\"input:not([type=\\\"button\\\"]):not([type=\\\"submit\\\"]), textarea, select\").forEach((input) => {\n const extracted = DOMTraversal.extractElement(input, options);\n if (extracted) formInputs.push(extracted);\n });\n form.querySelectorAll(\"button, input[type=\\\"button\\\"], input[type=\\\"submit\\\"]\").forEach((button) => {\n const extracted = DOMTraversal.extractElement(button, options);\n if (extracted) formButtons.push(extracted);\n });\n const action = form.getAttribute(\"action\");\n const method = form.getAttribute(\"method\");\n const formInfo = {\n selector: SelectorGenerator.generateSelectors(form).css,\n inputs: formInputs,\n buttons: formButtons\n };\n if (action) formInfo.action = action;\n if (method) formInfo.method = method;\n forms.push(formInfo);\n });\n return forms;\n }\n /**\n * Extract semantic elements (full mode only)\n */\n extractSemanticElements(container, options) {\n const headings = [];\n const images = [];\n const tables = [];\n const lists = [];\n const articles = [];\n container.querySelectorAll(\"h1, h2, h3, h4, h5, h6\").forEach((el) => {\n if (this.shouldIncludeElement(el, options)) {\n const extracted = DOMTraversal.extractElement(el, options);\n if (extracted) headings.push(extracted);\n }\n });\n container.querySelectorAll(\"img\").forEach((el) => {\n if (this.shouldIncludeElement(el, options)) {\n const extracted = DOMTraversal.extractElement(el, options);\n if (extracted) images.push(extracted);\n }\n });\n container.querySelectorAll(\"table\").forEach((el) => {\n if (this.shouldIncludeElement(el, options)) {\n const extracted = DOMTraversal.extractElement(el, options);\n if (extracted) tables.push(extracted);\n }\n });\n container.querySelectorAll(\"ul, ol\").forEach((el) => {\n if (this.shouldIncludeElement(el, options)) {\n const extracted = DOMTraversal.extractElement(el, options);\n if (extracted) lists.push(extracted);\n }\n });\n container.querySelectorAll(\"article, [role=\\\"article\\\"]\").forEach((el) => {\n if (this.shouldIncludeElement(el, options)) {\n const extracted = DOMTraversal.extractElement(el, options);\n if (extracted) articles.push(extracted);\n }\n });\n return {\n headings,\n images,\n tables,\n lists,\n articles\n };\n }\n /**\n * Extract metadata\n */\n extractMetadata(doc, container, options) {\n const allElements = container.querySelectorAll(\"*\");\n const extractedElements = container.querySelectorAll(\"button, a, input, textarea, select, h1, h2, h3, h4, h5, h6, img, table, ul, ol, article\").length;\n const metadata = {\n totalElements: allElements.length,\n extractedElements\n };\n if (options.mainContentOnly && container instanceof Element) metadata.mainContent = SelectorGenerator.generateSelectors(container).css;\n const language = doc.documentElement.getAttribute(\"lang\");\n if (language) metadata.language = language;\n return metadata;\n }\n /**\n * Check if element should be included based on options\n */\n shouldIncludeElement(element, options) {\n if (!options.includeHidden && !DOMTraversal.isVisible(element)) return false;\n if (options.viewportOnly && !DOMTraversal.isInViewport(element)) return false;\n if (options.filter && !DOMTraversal.passesFilter(element, options.filter)) return false;\n return true;\n }\n /**\n * Detect errors on the page\n */\n detectErrors(doc) {\n return [\n \".error\",\n \".alert-danger\",\n \"[role=\\\"alert\\\"]\",\n \".error-message\"\n ].some((sel) => {\n const element = doc.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n }\n /**\n * Detect if page is loading\n */\n detectLoading(doc) {\n return [\n \".loading\",\n \".spinner\",\n \"[aria-busy=\\\"true\\\"]\",\n \".loader\"\n ].some((sel) => {\n const element = doc.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n }\n /**\n * Detect modal dialogs\n */\n detectModals(doc) {\n return [\n \"[role=\\\"dialog\\\"]\",\n \".modal\",\n \".popup\",\n \".overlay\"\n ].some((sel) => {\n const element = doc.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n }\n /**\n * Get currently focused element\n */\n getFocusedElement(doc) {\n const focused = doc.activeElement;\n if (focused && focused !== doc.body) return SelectorGenerator.generateSelectors(focused).css;\n }\n /**\n * Quick extraction for interactive elements only\n * @param doc The document to extract from\n * @param options Extraction options\n */\n static extractInteractive(doc, options = {}) {\n return new SmartDOMReader({\n ...options,\n mode: \"interactive\"\n }).extract(doc);\n }\n /**\n * Quick extraction for full content\n * @param doc The document to extract from\n * @param options Extraction options\n */\n static extractFull(doc, options = {}) {\n return new SmartDOMReader({\n ...options,\n mode: \"full\"\n }).extract(doc);\n }\n /**\n * Extract from a specific element\n * @param element The element to extract from\n * @param mode The extraction mode\n * @param options Additional options\n */\n static extractFromElement(element, mode = \"interactive\", options = {}) {\n return new SmartDOMReader({\n ...options,\n mode\n }).extract(element);\n }\n };\n }));\n //#endregion\n //#region src/bundle-entry.ts\n init_src();\n init_markdown_formatter();\n init_progressive();\n function executeExtraction(method, args) {\n try {\n let result;\n switch (method) {\n case \"extractStructure\": {\n const { selector, frameSelector, formatOptions } = args;\n let doc = document;\n if (frameSelector) {\n const iframe = document.querySelector(frameSelector);\n if (!iframe || !(iframe instanceof HTMLIFrameElement) || !iframe.contentDocument) return { error: `Cannot access iframe: ${frameSelector}` };\n doc = iframe.contentDocument;\n }\n const target = selector ? doc.querySelector(selector) ?? doc : doc;\n const overview = ProgressiveExtractor.extractStructure(target);\n const meta = {\n title: document.title,\n url: location.href\n };\n result = MarkdownFormatter.structure(overview, formatOptions ?? { detail: \"summary\" }, meta);\n break;\n }\n case \"extractRegion\": {\n const { selector, mode, frameSelector, options, formatOptions } = args;\n let doc = document;\n if (frameSelector) {\n const iframe = document.querySelector(frameSelector);\n if (!iframe || !(iframe instanceof HTMLIFrameElement) || !iframe.contentDocument) return { error: `Cannot access iframe: ${frameSelector}` };\n doc = iframe.contentDocument;\n }\n const extractOptions = {\n ...options || {},\n mode: mode || \"interactive\"\n };\n const extractResult = ProgressiveExtractor.extractRegion(selector, doc, extractOptions, SmartDOMReader);\n if (!extractResult) return { error: `No element found matching selector: ${selector}` };\n const meta = {\n title: document.title,\n url: location.href\n };\n result = MarkdownFormatter.region(extractResult, formatOptions ?? { detail: \"region\" }, meta);\n break;\n }\n case \"extractContent\": {\n const { selector, frameSelector, options, formatOptions } = args;\n let doc = document;\n if (frameSelector) {\n const iframe = document.querySelector(frameSelector);\n if (!iframe || !(iframe instanceof HTMLIFrameElement) || !iframe.contentDocument) return { error: `Cannot access iframe: ${frameSelector}` };\n doc = iframe.contentDocument;\n }\n const extractOptions = options || {};\n const extractResult = ProgressiveExtractor.extractContent(selector, doc, extractOptions);\n if (!extractResult) return { error: `No element found matching selector: ${selector}` };\n const meta = {\n title: document.title,\n url: location.href\n };\n result = MarkdownFormatter.content(extractResult, formatOptions ?? { detail: \"region\" }, meta);\n break;\n }\n case \"extractInteractive\": {\n const { selector, frameSelector, options, formatOptions } = args;\n let doc = document;\n if (frameSelector) {\n const iframe = document.querySelector(frameSelector);\n if (!iframe || !(iframe instanceof HTMLIFrameElement) || !iframe.contentDocument) return { error: `Cannot access iframe: ${frameSelector}` };\n doc = iframe.contentDocument;\n }\n const extractResult = selector ? SmartDOMReader.extractFromElement(doc.querySelector(selector), \"interactive\", options || {}) : SmartDOMReader.extractInteractive(doc, options || {});\n const meta = {\n title: document.title,\n url: location.href\n };\n result = MarkdownFormatter.region(extractResult, formatOptions ?? { detail: \"region\" }, meta);\n break;\n }\n case \"extractFull\": {\n const { selector, frameSelector, options, formatOptions } = args;\n let doc = document;\n if (frameSelector) {\n const iframe = document.querySelector(frameSelector);\n if (!iframe || !(iframe instanceof HTMLIFrameElement) || !iframe.contentDocument) return { error: `Cannot access iframe: ${frameSelector}` };\n doc = iframe.contentDocument;\n }\n const extractResult = selector ? SmartDOMReader.extractFromElement(doc.querySelector(selector), \"full\", options || {}) : SmartDOMReader.extractFull(doc, options || {});\n const meta = {\n title: document.title,\n url: location.href\n };\n result = MarkdownFormatter.region(extractResult, formatOptions ?? { detail: \"deep\" }, meta);\n break;\n }\n default: return { error: `Unknown method: ${method}` };\n }\n return result;\n } catch (error) {\n return { error: error instanceof Error ? error.message : String(error) };\n }\n }\n //#endregion\n exports.SmartDOMReaderBundle = { executeExtraction };\n exports.executeExtraction = executeExtraction;\n return exports;\n})({});\n";
|
|
10
|
+
const SMART_DOM_READER_VERSION = "1.0.0";
|
|
11
|
+
//#endregion
|
|
12
|
+
export { SMART_DOM_READER_BUNDLE, SMART_DOM_READER_VERSION };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=bundle-string.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle-string.mjs","names":[],"sources":["../src/bundle-string.ts"],"sourcesContent":["/**\n * Auto-generated bundle module for smart-dom-reader\n * DO NOT EDIT - Generated by generate-bundle-module.mjs\n *\n * This module exports the bundled smart-dom-reader library as a string\n * that can be injected into web pages for stateless DOM extraction.\n */\n\nexport const SMART_DOM_READER_BUNDLE = \"var SmartDOMReaderBundle = (function(exports) {\\n\\tObject.defineProperty(exports, Symbol.toStringTag, { value: \\\"Module\\\" });\\n\\t//#region \\\\0rolldown/runtime.js\\n\\tvar __defProp = Object.defineProperty;\\n\\tvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\\n\\tvar __getOwnPropNames = Object.getOwnPropertyNames;\\n\\tvar __hasOwnProp = Object.prototype.hasOwnProperty;\\n\\tvar __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);\\n\\tvar __exportAll = (all, no_symbols) => {\\n\\t\\tlet target = {};\\n\\t\\tfor (var name in all) __defProp(target, name, {\\n\\t\\t\\tget: all[name],\\n\\t\\t\\tenumerable: true\\n\\t\\t});\\n\\t\\tif (!no_symbols) __defProp(target, Symbol.toStringTag, { value: \\\"Module\\\" });\\n\\t\\treturn target;\\n\\t};\\n\\tvar __copyProps = (to, from, except, desc) => {\\n\\t\\tif (from && typeof from === \\\"object\\\" || typeof from === \\\"function\\\") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {\\n\\t\\t\\tkey = keys[i];\\n\\t\\t\\tif (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {\\n\\t\\t\\t\\tget: ((k) => from[k]).bind(null, key),\\n\\t\\t\\t\\tenumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable\\n\\t\\t\\t});\\n\\t\\t}\\n\\t\\treturn to;\\n\\t};\\n\\tvar __toCommonJS = (mod) => __hasOwnProp.call(mod, \\\"module.exports\\\") ? mod[\\\"module.exports\\\"] : __copyProps(__defProp({}, \\\"__esModule\\\", { value: true }), mod);\\n\\t//#endregion\\n\\t//#region src/content-detection.ts\\n\\tvar ContentDetection;\\n\\tvar init_content_detection = __esmMin((() => {\\n\\t\\tContentDetection = class ContentDetection {\\n\\t\\t\\t/**\\n\\t\\t\\t* Find the main content area of a page\\n\\t\\t\\t* Inspired by dom-to-semantic-markdown's approach\\n\\t\\t\\t*/\\n\\t\\t\\tstatic findMainContent(doc) {\\n\\t\\t\\t\\tconst mainElement = doc.querySelector(\\\"main, [role=\\\\\\\"main\\\\\\\"]\\\");\\n\\t\\t\\t\\tif (mainElement) return mainElement;\\n\\t\\t\\t\\tif (!doc.body) return doc.documentElement;\\n\\t\\t\\t\\treturn ContentDetection.detectMainContent(doc.body);\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Detect main content using scoring algorithm\\n\\t\\t\\t*/\\n\\t\\t\\tstatic detectMainContent(rootElement) {\\n\\t\\t\\t\\tconst candidates = [];\\n\\t\\t\\t\\tContentDetection.collectCandidates(rootElement, candidates, 15);\\n\\t\\t\\t\\tif (candidates.length === 0) return rootElement;\\n\\t\\t\\t\\tcandidates.sort((a, b) => ContentDetection.calculateContentScore(b) - ContentDetection.calculateContentScore(a));\\n\\t\\t\\t\\tlet bestCandidate = candidates[0];\\n\\t\\t\\t\\tfor (let i = 1; i < candidates.length; i++) {\\n\\t\\t\\t\\t\\tconst candidate = candidates[i];\\n\\t\\t\\t\\t\\tif (!candidates.some((other, j) => j !== i && other.contains(candidate)) && ContentDetection.calculateContentScore(candidate) > ContentDetection.calculateContentScore(bestCandidate)) bestCandidate = candidate;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn bestCandidate;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Collect content candidates\\n\\t\\t\\t*/\\n\\t\\t\\tstatic collectCandidates(element, candidates, minScore) {\\n\\t\\t\\t\\tif (ContentDetection.calculateContentScore(element) >= minScore) candidates.push(element);\\n\\t\\t\\t\\tArray.from(element.children).forEach((child) => {\\n\\t\\t\\t\\t\\tContentDetection.collectCandidates(child, candidates, minScore);\\n\\t\\t\\t\\t});\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Calculate content score for an element\\n\\t\\t\\t*/\\n\\t\\t\\tstatic calculateContentScore(element) {\\n\\t\\t\\t\\tlet score = 0;\\n\\t\\t\\t\\tconst semanticClasses = [\\n\\t\\t\\t\\t\\t\\\"article\\\",\\n\\t\\t\\t\\t\\t\\\"content\\\",\\n\\t\\t\\t\\t\\t\\\"main-container\\\",\\n\\t\\t\\t\\t\\t\\\"main\\\",\\n\\t\\t\\t\\t\\t\\\"main-content\\\",\\n\\t\\t\\t\\t\\t\\\"post\\\",\\n\\t\\t\\t\\t\\t\\\"entry\\\"\\n\\t\\t\\t\\t];\\n\\t\\t\\t\\tconst semanticIds = [\\n\\t\\t\\t\\t\\t\\\"content\\\",\\n\\t\\t\\t\\t\\t\\\"main\\\",\\n\\t\\t\\t\\t\\t\\\"article\\\",\\n\\t\\t\\t\\t\\t\\\"post\\\",\\n\\t\\t\\t\\t\\t\\\"entry\\\"\\n\\t\\t\\t\\t];\\n\\t\\t\\t\\tsemanticClasses.forEach((cls) => {\\n\\t\\t\\t\\t\\tif (element.classList.contains(cls)) score += 10;\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tsemanticIds.forEach((id) => {\\n\\t\\t\\t\\t\\tif (element.id?.toLowerCase().includes(id)) score += 10;\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tconst tag = element.tagName.toLowerCase();\\n\\t\\t\\t\\tif ([\\n\\t\\t\\t\\t\\t\\\"article\\\",\\n\\t\\t\\t\\t\\t\\\"main\\\",\\n\\t\\t\\t\\t\\t\\\"section\\\"\\n\\t\\t\\t\\t].includes(tag)) score += 8;\\n\\t\\t\\t\\tconst paragraphs = element.getElementsByTagName(\\\"p\\\").length;\\n\\t\\t\\t\\tscore += Math.min(paragraphs * 2, 10);\\n\\t\\t\\t\\tconst headings = element.querySelectorAll(\\\"h1, h2, h3\\\").length;\\n\\t\\t\\t\\tscore += Math.min(headings * 3, 9);\\n\\t\\t\\t\\tconst textLength = element.textContent?.trim().length || 0;\\n\\t\\t\\t\\tif (textLength > 300) score += Math.min(Math.floor(textLength / 300) * 2, 10);\\n\\t\\t\\t\\tconst linkDensity = ContentDetection.calculateLinkDensity(element);\\n\\t\\t\\t\\tif (linkDensity < .3) score += 5;\\n\\t\\t\\t\\telse if (linkDensity > .5) score -= 5;\\n\\t\\t\\t\\tif (element.hasAttribute(\\\"data-main\\\") || element.hasAttribute(\\\"data-content\\\") || element.hasAttribute(\\\"itemprop\\\")) score += 8;\\n\\t\\t\\t\\tconst role = element.getAttribute(\\\"role\\\");\\n\\t\\t\\t\\tif (role === \\\"main\\\" || role === \\\"article\\\") score += 10;\\n\\t\\t\\t\\tif (element.matches(\\\"aside, nav, header, footer, .sidebar, .navigation, .menu, .ad, .advertisement\\\")) score -= 10;\\n\\t\\t\\t\\tif (element.getElementsByTagName(\\\"form\\\").length > 2) score -= 5;\\n\\t\\t\\t\\treturn Math.max(0, score);\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Calculate link density in an element\\n\\t\\t\\t*/\\n\\t\\t\\tstatic calculateLinkDensity(element) {\\n\\t\\t\\t\\tconst links = element.getElementsByTagName(\\\"a\\\");\\n\\t\\t\\t\\tlet linkTextLength = 0;\\n\\t\\t\\t\\tfor (const link of Array.from(links)) linkTextLength += link.textContent?.length || 0;\\n\\t\\t\\t\\tconst totalTextLength = element.textContent?.length || 1;\\n\\t\\t\\t\\treturn linkTextLength / totalTextLength;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Check if an element is likely navigation\\n\\t\\t\\t*/\\n\\t\\t\\tstatic isNavigation(element) {\\n\\t\\t\\t\\tif (element.tagName.toLowerCase() === \\\"nav\\\" || element.getAttribute(\\\"role\\\") === \\\"navigation\\\") return true;\\n\\t\\t\\t\\tconst navPatterns = [\\n\\t\\t\\t\\t\\t/nav/i,\\n\\t\\t\\t\\t\\t/menu/i,\\n\\t\\t\\t\\t\\t/sidebar/i,\\n\\t\\t\\t\\t\\t/toolbar/i\\n\\t\\t\\t\\t];\\n\\t\\t\\t\\tconst classesAndId = `${element.className} ${element.id}`.toLowerCase();\\n\\t\\t\\t\\treturn navPatterns.some((pattern) => pattern.test(classesAndId));\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Check if element is likely supplementary content\\n\\t\\t\\t*/\\n\\t\\t\\tstatic isSupplementary(element) {\\n\\t\\t\\t\\tif (element.tagName.toLowerCase() === \\\"aside\\\" || element.getAttribute(\\\"role\\\") === \\\"complementary\\\") return true;\\n\\t\\t\\t\\tconst supplementaryPatterns = [\\n\\t\\t\\t\\t\\t/sidebar/i,\\n\\t\\t\\t\\t\\t/widget/i,\\n\\t\\t\\t\\t\\t/related/i,\\n\\t\\t\\t\\t\\t/advertisement/i,\\n\\t\\t\\t\\t\\t/social/i\\n\\t\\t\\t\\t];\\n\\t\\t\\t\\tconst classesAndId = `${element.className} ${element.id}`.toLowerCase();\\n\\t\\t\\t\\treturn supplementaryPatterns.some((pattern) => pattern.test(classesAndId));\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Detect page landmarks\\n\\t\\t\\t*/\\n\\t\\t\\tstatic detectLandmarks(doc) {\\n\\t\\t\\t\\tconst landmarks = {\\n\\t\\t\\t\\t\\tnavigation: [],\\n\\t\\t\\t\\t\\tmain: [],\\n\\t\\t\\t\\t\\tcomplementary: [],\\n\\t\\t\\t\\t\\tcontentinfo: [],\\n\\t\\t\\t\\t\\tbanner: [],\\n\\t\\t\\t\\t\\tsearch: [],\\n\\t\\t\\t\\t\\tform: [],\\n\\t\\t\\t\\t\\tregion: []\\n\\t\\t\\t\\t};\\n\\t\\t\\t\\tfor (const [landmark, selector] of Object.entries({\\n\\t\\t\\t\\t\\tnavigation: \\\"nav, [role=\\\\\\\"navigation\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\tmain: \\\"main, [role=\\\\\\\"main\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\tcomplementary: \\\"aside, [role=\\\\\\\"complementary\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\tcontentinfo: \\\"footer, [role=\\\\\\\"contentinfo\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\tbanner: \\\"header, [role=\\\\\\\"banner\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\tsearch: \\\"[role=\\\\\\\"search\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\tform: \\\"form[aria-label], form[aria-labelledby], [role=\\\\\\\"form\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\tregion: \\\"section[aria-label], section[aria-labelledby], [role=\\\\\\\"region\\\\\\\"]\\\"\\n\\t\\t\\t\\t})) {\\n\\t\\t\\t\\t\\tconst elements = doc.querySelectorAll(selector);\\n\\t\\t\\t\\t\\tlandmarks[landmark] = Array.from(elements);\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn landmarks;\\n\\t\\t\\t}\\n\\t\\t};\\n\\t}));\\n\\t//#endregion\\n\\t//#region src/selectors.ts\\n\\tvar SelectorGenerator;\\n\\tvar init_selectors = __esmMin((() => {\\n\\t\\tSelectorGenerator = class SelectorGenerator {\\n\\t\\t\\t/**\\n\\t\\t\\t* Generate multiple selector strategies for an element\\n\\t\\t\\t*/\\n\\t\\t\\tstatic generateSelectors(element) {\\n\\t\\t\\t\\tconst doc = element.ownerDocument || document;\\n\\t\\t\\t\\tconst candidates = [];\\n\\t\\t\\t\\tif (element.id && SelectorGenerator.isUniqueId(element.id, doc)) candidates.push({\\n\\t\\t\\t\\t\\ttype: \\\"id\\\",\\n\\t\\t\\t\\t\\tvalue: `#${CSS.escape(element.id)}`,\\n\\t\\t\\t\\t\\tscore: 100\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tconst testId = SelectorGenerator.getDataTestId(element);\\n\\t\\t\\t\\tif (testId) {\\n\\t\\t\\t\\t\\tconst v = `[data-testid=\\\"${CSS.escape(testId)}\\\"]`;\\n\\t\\t\\t\\t\\tcandidates.push({\\n\\t\\t\\t\\t\\t\\ttype: \\\"data-testid\\\",\\n\\t\\t\\t\\t\\t\\tvalue: v,\\n\\t\\t\\t\\t\\t\\tscore: 90 + (SelectorGenerator.isUniqueSelectorSafe(v, doc) ? 5 : 0)\\n\\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tconst role = element.getAttribute(\\\"role\\\");\\n\\t\\t\\t\\tconst aria = element.getAttribute(\\\"aria-label\\\");\\n\\t\\t\\t\\tif (role && aria) {\\n\\t\\t\\t\\t\\tconst v = `[role=\\\"${CSS.escape(role)}\\\"][aria-label=\\\"${CSS.escape(aria)}\\\"]`;\\n\\t\\t\\t\\t\\tcandidates.push({\\n\\t\\t\\t\\t\\t\\ttype: \\\"role-aria\\\",\\n\\t\\t\\t\\t\\t\\tvalue: v,\\n\\t\\t\\t\\t\\t\\tscore: 85 + (SelectorGenerator.isUniqueSelectorSafe(v, doc) ? 5 : 0)\\n\\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tconst nameAttr = element.getAttribute(\\\"name\\\");\\n\\t\\t\\t\\tif (nameAttr) {\\n\\t\\t\\t\\t\\tconst v = `[name=\\\"${CSS.escape(nameAttr)}\\\"]`;\\n\\t\\t\\t\\t\\tcandidates.push({\\n\\t\\t\\t\\t\\t\\ttype: \\\"name\\\",\\n\\t\\t\\t\\t\\t\\tvalue: v,\\n\\t\\t\\t\\t\\t\\tscore: 78 + (SelectorGenerator.isUniqueSelectorSafe(v, doc) ? 5 : 0)\\n\\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tconst pathCss = SelectorGenerator.generateCSSSelector(element, doc);\\n\\t\\t\\t\\tconst structuralPenalty = (pathCss.match(/:nth-child\\\\(/g) || []).length * 10;\\n\\t\\t\\t\\tconst classBonus = pathCss.includes(\\\".\\\") ? 8 : 0;\\n\\t\\t\\t\\tconst pathScore = Math.max(0, 70 + classBonus - structuralPenalty);\\n\\t\\t\\t\\tcandidates.push({\\n\\t\\t\\t\\t\\ttype: \\\"class-path\\\",\\n\\t\\t\\t\\t\\tvalue: pathCss,\\n\\t\\t\\t\\t\\tscore: pathScore\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tconst xpath = SelectorGenerator.generateXPath(element, doc);\\n\\t\\t\\t\\tcandidates.push({\\n\\t\\t\\t\\t\\ttype: \\\"xpath\\\",\\n\\t\\t\\t\\t\\tvalue: xpath,\\n\\t\\t\\t\\t\\tscore: 40\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tconst textBased = SelectorGenerator.generateTextBasedSelector(element);\\n\\t\\t\\t\\tif (textBased) candidates.push({\\n\\t\\t\\t\\t\\ttype: \\\"text\\\",\\n\\t\\t\\t\\t\\tvalue: textBased,\\n\\t\\t\\t\\t\\tscore: 30\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tcandidates.sort((a, b) => b.score - a.score);\\n\\t\\t\\t\\tconst selector = {\\n\\t\\t\\t\\t\\tcss: candidates.find((c) => c.type !== \\\"xpath\\\" && c.type !== \\\"text\\\")?.value || pathCss,\\n\\t\\t\\t\\t\\txpath,\\n\\t\\t\\t\\t\\tcandidates\\n\\t\\t\\t\\t};\\n\\t\\t\\t\\tif (textBased) selector.textBased = textBased;\\n\\t\\t\\t\\tif (testId) selector.dataTestId = testId;\\n\\t\\t\\t\\tif (aria) selector.ariaLabel = aria;\\n\\t\\t\\t\\treturn selector;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Generate a unique CSS selector for an element\\n\\t\\t\\t*/\\n\\t\\t\\tstatic generateCSSSelector(element, doc) {\\n\\t\\t\\t\\tif (element.id && SelectorGenerator.isUniqueId(element.id, doc)) return `#${CSS.escape(element.id)}`;\\n\\t\\t\\t\\tconst testId = SelectorGenerator.getDataTestId(element);\\n\\t\\t\\t\\tif (testId) return `[data-testid=\\\"${CSS.escape(testId)}\\\"]`;\\n\\t\\t\\t\\tconst path = [];\\n\\t\\t\\t\\tlet current = element;\\n\\t\\t\\t\\twhile (current && current.nodeType === Node.ELEMENT_NODE) {\\n\\t\\t\\t\\t\\tlet selector = current.nodeName.toLowerCase();\\n\\t\\t\\t\\t\\tif (current.id && SelectorGenerator.isUniqueId(current.id, doc)) {\\n\\t\\t\\t\\t\\t\\tselector = `#${CSS.escape(current.id)}`;\\n\\t\\t\\t\\t\\t\\tpath.unshift(selector);\\n\\t\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tconst classes = SelectorGenerator.getMeaningfulClasses(current);\\n\\t\\t\\t\\t\\tif (classes.length > 0) selector += `.${classes.map((c) => CSS.escape(c)).join(\\\".\\\")}`;\\n\\t\\t\\t\\t\\tconst siblings = current.parentElement?.children;\\n\\t\\t\\t\\t\\tif (siblings && siblings.length > 1) {\\n\\t\\t\\t\\t\\t\\tconst index = Array.from(siblings).indexOf(current);\\n\\t\\t\\t\\t\\t\\tif (index > 0 || !SelectorGenerator.isUniqueSelector(selector, current.parentElement)) selector += `:nth-child(${index + 1})`;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tpath.unshift(selector);\\n\\t\\t\\t\\t\\tcurrent = current.parentElement;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn SelectorGenerator.optimizePath(path, element, doc);\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Generate XPath for an element\\n\\t\\t\\t*/\\n\\t\\t\\tstatic generateXPath(element, doc) {\\n\\t\\t\\t\\tif (element.id && SelectorGenerator.isUniqueId(element.id, doc)) return `//*[@id=\\\"${element.id}\\\"]`;\\n\\t\\t\\t\\tconst path = [];\\n\\t\\t\\t\\tlet current = element;\\n\\t\\t\\t\\twhile (current && current.nodeType === Node.ELEMENT_NODE) {\\n\\t\\t\\t\\t\\tconst tagName = current.nodeName.toLowerCase();\\n\\t\\t\\t\\t\\tif (current.id && SelectorGenerator.isUniqueId(current.id, doc)) {\\n\\t\\t\\t\\t\\t\\tpath.unshift(`//*[@id=\\\"${current.id}\\\"]`);\\n\\t\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tlet xpath = tagName;\\n\\t\\t\\t\\t\\tconst siblings = current.parentElement?.children;\\n\\t\\t\\t\\t\\tif (siblings) {\\n\\t\\t\\t\\t\\t\\tconst sameTagSiblings = Array.from(siblings).filter((s) => s.nodeName.toLowerCase() === tagName);\\n\\t\\t\\t\\t\\t\\tif (sameTagSiblings.length > 1) {\\n\\t\\t\\t\\t\\t\\t\\tconst index = sameTagSiblings.indexOf(current) + 1;\\n\\t\\t\\t\\t\\t\\t\\txpath += `[${index}]`;\\n\\t\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tpath.unshift(xpath);\\n\\t\\t\\t\\t\\tcurrent = current.parentElement;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn `//${path.join(\\\"/\\\")}`;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Generate a text-based selector for buttons and links\\n\\t\\t\\t*/\\n\\t\\t\\tstatic generateTextBasedSelector(element) {\\n\\t\\t\\t\\tconst text = element.textContent?.trim();\\n\\t\\t\\t\\tif (!text || text.length > 50) return void 0;\\n\\t\\t\\t\\tconst tag = element.nodeName.toLowerCase();\\n\\t\\t\\t\\tif ([\\n\\t\\t\\t\\t\\t\\\"button\\\",\\n\\t\\t\\t\\t\\t\\\"a\\\",\\n\\t\\t\\t\\t\\t\\\"label\\\"\\n\\t\\t\\t\\t].includes(tag)) return `${tag}:contains(\\\"${text.replace(/['\\\"\\\\\\\\]/g, \\\"\\\\\\\\$&\\\")}\\\")`;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get data-testid or similar attributes\\n\\t\\t\\t*/\\n\\t\\t\\tstatic getDataTestId(element) {\\n\\t\\t\\t\\treturn element.getAttribute(\\\"data-testid\\\") || element.getAttribute(\\\"data-test-id\\\") || element.getAttribute(\\\"data-test\\\") || element.getAttribute(\\\"data-cy\\\") || void 0;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Check if an ID is unique in the document\\n\\t\\t\\t*/\\n\\t\\t\\tstatic isUniqueId(id, doc) {\\n\\t\\t\\t\\treturn doc.querySelectorAll(`#${CSS.escape(id)}`).length === 1;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Check if a selector is unique within a container\\n\\t\\t\\t*/\\n\\t\\t\\tstatic isUniqueSelector(selector, container) {\\n\\t\\t\\t\\ttry {\\n\\t\\t\\t\\t\\treturn container.querySelectorAll(selector).length === 1;\\n\\t\\t\\t\\t} catch {\\n\\t\\t\\t\\t\\treturn false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\tstatic isUniqueSelectorSafe(selector, doc) {\\n\\t\\t\\t\\ttry {\\n\\t\\t\\t\\t\\treturn doc.querySelectorAll(selector).length === 1;\\n\\t\\t\\t\\t} catch {\\n\\t\\t\\t\\t\\treturn false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get meaningful classes (filtering out utility classes)\\n\\t\\t\\t*/\\n\\t\\t\\tstatic getMeaningfulClasses(element) {\\n\\t\\t\\t\\tconst classes = Array.from(element.classList);\\n\\t\\t\\t\\tconst utilityPatterns = [\\n\\t\\t\\t\\t\\t/^(p|m|w|h|text|bg|border|flex|grid|col|row)-/,\\n\\t\\t\\t\\t\\t/^(xs|sm|md|lg|xl|2xl):/,\\n\\t\\t\\t\\t\\t/^(hover|focus|active|disabled|checked):/,\\n\\t\\t\\t\\t\\t/^js-/,\\n\\t\\t\\t\\t\\t/^is-/,\\n\\t\\t\\t\\t\\t/^has-/\\n\\t\\t\\t\\t];\\n\\t\\t\\t\\treturn classes.filter((cls) => {\\n\\t\\t\\t\\t\\tif (cls.length < 3) return false;\\n\\t\\t\\t\\t\\treturn !utilityPatterns.some((pattern) => pattern.test(cls));\\n\\t\\t\\t\\t}).slice(0, 2);\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Optimize the selector path by removing unnecessary parts\\n\\t\\t\\t*/\\n\\t\\t\\tstatic optimizePath(path, element, doc) {\\n\\t\\t\\t\\tfor (let i = 0; i < path.length - 1; i++) {\\n\\t\\t\\t\\t\\tconst shortPath = path.slice(i).join(\\\" > \\\");\\n\\t\\t\\t\\t\\ttry {\\n\\t\\t\\t\\t\\t\\tconst matches = doc.querySelectorAll(shortPath);\\n\\t\\t\\t\\t\\t\\tif (matches.length === 1 && matches[0] === element) return shortPath;\\n\\t\\t\\t\\t\\t} catch {}\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn path.join(\\\" > \\\");\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get a human-readable path description\\n\\t\\t\\t*/\\n\\t\\t\\tstatic getContextPath(element) {\\n\\t\\t\\t\\tconst path = [];\\n\\t\\t\\t\\tlet current = element;\\n\\t\\t\\t\\tlet depth = 0;\\n\\t\\t\\t\\tconst maxDepth = 5;\\n\\t\\t\\t\\twhile (current && current !== element.ownerDocument?.body && depth < maxDepth) {\\n\\t\\t\\t\\t\\tconst tag = current.nodeName.toLowerCase();\\n\\t\\t\\t\\t\\tlet descriptor = tag;\\n\\t\\t\\t\\t\\tif (current.id) descriptor = `${tag}#${current.id}`;\\n\\t\\t\\t\\t\\telse if (current.className && typeof current.className === \\\"string\\\") {\\n\\t\\t\\t\\t\\t\\tconst firstClass = current.className.split(\\\" \\\")[0];\\n\\t\\t\\t\\t\\t\\tif (firstClass) descriptor = `${tag}.${firstClass}`;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tconst role = current.getAttribute(\\\"role\\\");\\n\\t\\t\\t\\t\\tif (role) descriptor += `[role=\\\"${role}\\\"]`;\\n\\t\\t\\t\\t\\tpath.unshift(descriptor);\\n\\t\\t\\t\\t\\tcurrent = current.parentElement;\\n\\t\\t\\t\\t\\tdepth++;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn path;\\n\\t\\t\\t}\\n\\t\\t};\\n\\t}));\\n\\t//#endregion\\n\\t//#region src/traversal.ts\\n\\tvar DOMTraversal;\\n\\tvar init_traversal = __esmMin((() => {\\n\\t\\tinit_selectors();\\n\\t\\tDOMTraversal = class DOMTraversal {\\n\\t\\t\\tstatic INTERACTIVE_SELECTORS = [\\n\\t\\t\\t\\t\\\"button\\\",\\n\\t\\t\\t\\t\\\"a[href]\\\",\\n\\t\\t\\t\\t\\\"input:not([type=\\\\\\\"hidden\\\\\\\"])\\\",\\n\\t\\t\\t\\t\\\"textarea\\\",\\n\\t\\t\\t\\t\\\"select\\\",\\n\\t\\t\\t\\t\\\"[role=\\\\\\\"button\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\\"[onclick]\\\",\\n\\t\\t\\t\\t\\\"[contenteditable=\\\\\\\"true\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\\"summary\\\",\\n\\t\\t\\t\\t\\\"[tabindex]:not([tabindex=\\\\\\\"-1\\\\\\\"])\\\"\\n\\t\\t\\t];\\n\\t\\t\\tstatic SEMANTIC_SELECTORS = [\\n\\t\\t\\t\\t\\\"h1\\\",\\n\\t\\t\\t\\t\\\"h2\\\",\\n\\t\\t\\t\\t\\\"h3\\\",\\n\\t\\t\\t\\t\\\"h4\\\",\\n\\t\\t\\t\\t\\\"h5\\\",\\n\\t\\t\\t\\t\\\"h6\\\",\\n\\t\\t\\t\\t\\\"article\\\",\\n\\t\\t\\t\\t\\\"section\\\",\\n\\t\\t\\t\\t\\\"nav\\\",\\n\\t\\t\\t\\t\\\"aside\\\",\\n\\t\\t\\t\\t\\\"main\\\",\\n\\t\\t\\t\\t\\\"header\\\",\\n\\t\\t\\t\\t\\\"footer\\\",\\n\\t\\t\\t\\t\\\"form\\\",\\n\\t\\t\\t\\t\\\"table\\\",\\n\\t\\t\\t\\t\\\"ul\\\",\\n\\t\\t\\t\\t\\\"ol\\\",\\n\\t\\t\\t\\t\\\"img[alt]\\\",\\n\\t\\t\\t\\t\\\"figure\\\",\\n\\t\\t\\t\\t\\\"video\\\",\\n\\t\\t\\t\\t\\\"audio\\\",\\n\\t\\t\\t\\t\\\"[role=\\\\\\\"navigation\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\\"[role=\\\\\\\"main\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\\"[role=\\\\\\\"complementary\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\\"[role=\\\\\\\"contentinfo\\\\\\\"]\\\"\\n\\t\\t\\t];\\n\\t\\t\\t/**\\n\\t\\t\\t* Check if element is visible\\n\\t\\t\\t*/\\n\\t\\t\\tstatic isVisible(element, computedStyle) {\\n\\t\\t\\t\\tconst rect = element.getBoundingClientRect();\\n\\t\\t\\t\\tconst style = computedStyle || element.ownerDocument?.defaultView?.getComputedStyle(element);\\n\\t\\t\\t\\tif (!style) return false;\\n\\t\\t\\t\\treturn !!(rect.width > 0 && rect.height > 0 && style.display !== \\\"none\\\" && style.visibility !== \\\"hidden\\\" && style.opacity !== \\\"0\\\" && element.offsetParent !== null);\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Check if element is in viewport\\n\\t\\t\\t*/\\n\\t\\t\\tstatic isInViewport(element, viewport) {\\n\\t\\t\\t\\tconst rect = element.getBoundingClientRect();\\n\\t\\t\\t\\tconst view = viewport || {\\n\\t\\t\\t\\t\\twidth: element.ownerDocument?.defaultView?.innerWidth || 0,\\n\\t\\t\\t\\t\\theight: element.ownerDocument?.defaultView?.innerHeight || 0\\n\\t\\t\\t\\t};\\n\\t\\t\\t\\treturn rect.top < view.height && rect.bottom > 0 && rect.left < view.width && rect.right > 0;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Check if element passes filter criteria\\n\\t\\t\\t*/\\n\\t\\t\\tstatic passesFilter(element, filter) {\\n\\t\\t\\t\\tif (!filter) return true;\\n\\t\\t\\t\\tconst htmlElement = element;\\n\\t\\t\\t\\tif (filter.excludeSelectors?.length) {\\n\\t\\t\\t\\t\\tfor (const selector of filter.excludeSelectors) if (element.matches(selector)) return false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (filter.includeSelectors?.length) {\\n\\t\\t\\t\\t\\tlet matches = false;\\n\\t\\t\\t\\t\\tfor (const selector of filter.includeSelectors) if (element.matches(selector)) {\\n\\t\\t\\t\\t\\t\\tmatches = true;\\n\\t\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tif (!matches) return false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (filter.tags?.length && !filter.tags.includes(element.tagName.toLowerCase())) return false;\\n\\t\\t\\t\\tconst textContent = htmlElement.textContent?.toLowerCase() || \\\"\\\";\\n\\t\\t\\t\\tif (filter.textContains?.length) {\\n\\t\\t\\t\\t\\tlet hasText = false;\\n\\t\\t\\t\\t\\tfor (const text of filter.textContains) if (textContent.includes(text.toLowerCase())) {\\n\\t\\t\\t\\t\\t\\thasText = true;\\n\\t\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tif (!hasText) return false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (filter.textMatches?.length) {\\n\\t\\t\\t\\t\\tlet matches = false;\\n\\t\\t\\t\\t\\tfor (const pattern of filter.textMatches) if (pattern.test(textContent)) {\\n\\t\\t\\t\\t\\t\\tmatches = true;\\n\\t\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tif (!matches) return false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (filter.hasAttributes?.length) {\\n\\t\\t\\t\\t\\tfor (const attr of filter.hasAttributes) if (!element.hasAttribute(attr)) return false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (filter.attributeValues) for (const [attr, value] of Object.entries(filter.attributeValues)) {\\n\\t\\t\\t\\t\\tconst attrValue = element.getAttribute(attr);\\n\\t\\t\\t\\t\\tif (!attrValue) return false;\\n\\t\\t\\t\\t\\tif (typeof value === \\\"string\\\") {\\n\\t\\t\\t\\t\\t\\tif (attrValue !== value) return false;\\n\\t\\t\\t\\t\\t} else if (value instanceof RegExp) {\\n\\t\\t\\t\\t\\t\\tif (!value.test(attrValue)) return false;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (filter.withinSelectors?.length) {\\n\\t\\t\\t\\t\\tlet isWithin = false;\\n\\t\\t\\t\\t\\tfor (const selector of filter.withinSelectors) if (element.closest(selector)) {\\n\\t\\t\\t\\t\\t\\tisWithin = true;\\n\\t\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tif (!isWithin) return false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (filter.interactionTypes?.length) {\\n\\t\\t\\t\\t\\tconst interaction = DOMTraversal.getInteractionInfo(element);\\n\\t\\t\\t\\t\\tlet hasInteraction = false;\\n\\t\\t\\t\\t\\tfor (const type of filter.interactionTypes) if (interaction[type]) {\\n\\t\\t\\t\\t\\t\\thasInteraction = true;\\n\\t\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tif (!hasInteraction) return false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (filter.nearText) {\\n\\t\\t\\t\\t\\tconst parent = element.parentElement;\\n\\t\\t\\t\\t\\tif (!parent || !parent.textContent?.toLowerCase().includes(filter.nearText.toLowerCase())) return false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn true;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Extract element information\\n\\t\\t\\t*/\\n\\t\\t\\tstatic extractElement(element, options, depth = 0) {\\n\\t\\t\\t\\tif (options.maxDepth && depth > options.maxDepth) return null;\\n\\t\\t\\t\\tif (!options.includeHidden && !DOMTraversal.isVisible(element)) return null;\\n\\t\\t\\t\\tif (options.viewportOnly && !DOMTraversal.isInViewport(element)) return null;\\n\\t\\t\\t\\tif (!DOMTraversal.passesFilter(element, options.filter)) return null;\\n\\t\\t\\t\\tconst htmlElement = element;\\n\\t\\t\\t\\tconst extracted = {\\n\\t\\t\\t\\t\\ttag: element.tagName.toLowerCase(),\\n\\t\\t\\t\\t\\ttext: DOMTraversal.getElementText(element, options),\\n\\t\\t\\t\\t\\tselector: SelectorGenerator.generateSelectors(element),\\n\\t\\t\\t\\t\\tattributes: DOMTraversal.getRelevantAttributes(element, options),\\n\\t\\t\\t\\t\\tcontext: DOMTraversal.getElementContext(element),\\n\\t\\t\\t\\t\\tinteraction: DOMTraversal.getInteractionInfo(element)\\n\\t\\t\\t\\t};\\n\\t\\t\\t\\tif (options.mode === \\\"full\\\" && DOMTraversal.isSemanticContainer(element)) {\\n\\t\\t\\t\\t\\tconst children = [];\\n\\t\\t\\t\\t\\tif (options.includeShadowDOM && htmlElement.shadowRoot) {\\n\\t\\t\\t\\t\\t\\tconst shadowChildren = DOMTraversal.extractChildren(htmlElement.shadowRoot, options, depth + 1);\\n\\t\\t\\t\\t\\t\\tchildren.push(...shadowChildren);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tconst regularChildren = DOMTraversal.extractChildren(element, options, depth + 1);\\n\\t\\t\\t\\t\\tchildren.push(...regularChildren);\\n\\t\\t\\t\\t\\tif (children.length > 0) extracted.children = children;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn extracted;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Extract children elements\\n\\t\\t\\t*/\\n\\t\\t\\tstatic extractChildren(container, options, depth) {\\n\\t\\t\\t\\tconst children = [];\\n\\t\\t\\t\\tconst elements = container.querySelectorAll(\\\"*\\\");\\n\\t\\t\\t\\tfor (const child of Array.from(elements)) {\\n\\t\\t\\t\\t\\tif (DOMTraversal.hasExtractedAncestor(child, elements)) continue;\\n\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(child, options, depth);\\n\\t\\t\\t\\t\\tif (extracted) children.push(extracted);\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn children;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Check if element has an ancestor that was already extracted\\n\\t\\t\\t*/\\n\\t\\t\\tstatic hasExtractedAncestor(element, extractedElements) {\\n\\t\\t\\t\\tlet parent = element.parentElement;\\n\\t\\t\\t\\twhile (parent) {\\n\\t\\t\\t\\t\\tif (Array.from(extractedElements).includes(parent)) return true;\\n\\t\\t\\t\\t\\tparent = parent.parentElement;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn false;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get relevant attributes for an element\\n\\t\\t\\t*/\\n\\t\\t\\tstatic getRelevantAttributes(element, options) {\\n\\t\\t\\t\\tconst relevant = [\\n\\t\\t\\t\\t\\t\\\"id\\\",\\n\\t\\t\\t\\t\\t\\\"class\\\",\\n\\t\\t\\t\\t\\t\\\"name\\\",\\n\\t\\t\\t\\t\\t\\\"type\\\",\\n\\t\\t\\t\\t\\t\\\"value\\\",\\n\\t\\t\\t\\t\\t\\\"placeholder\\\",\\n\\t\\t\\t\\t\\t\\\"href\\\",\\n\\t\\t\\t\\t\\t\\\"src\\\",\\n\\t\\t\\t\\t\\t\\\"alt\\\",\\n\\t\\t\\t\\t\\t\\\"title\\\",\\n\\t\\t\\t\\t\\t\\\"action\\\",\\n\\t\\t\\t\\t\\t\\\"method\\\",\\n\\t\\t\\t\\t\\t\\\"aria-label\\\",\\n\\t\\t\\t\\t\\t\\\"aria-describedby\\\",\\n\\t\\t\\t\\t\\t\\\"aria-controls\\\",\\n\\t\\t\\t\\t\\t\\\"role\\\",\\n\\t\\t\\t\\t\\t\\\"disabled\\\",\\n\\t\\t\\t\\t\\t\\\"readonly\\\",\\n\\t\\t\\t\\t\\t\\\"required\\\",\\n\\t\\t\\t\\t\\t\\\"checked\\\",\\n\\t\\t\\t\\t\\t\\\"min\\\",\\n\\t\\t\\t\\t\\t\\\"max\\\",\\n\\t\\t\\t\\t\\t\\\"pattern\\\",\\n\\t\\t\\t\\t\\t\\\"step\\\",\\n\\t\\t\\t\\t\\t\\\"autocomplete\\\",\\n\\t\\t\\t\\t\\t\\\"data-testid\\\",\\n\\t\\t\\t\\t\\t\\\"data-test\\\",\\n\\t\\t\\t\\t\\t\\\"data-cy\\\"\\n\\t\\t\\t\\t];\\n\\t\\t\\t\\tconst attributes = {};\\n\\t\\t\\t\\tconst attrTruncate = options.attributeTruncateLength ?? 100;\\n\\t\\t\\t\\tconst dataAttrTruncate = options.dataAttributeTruncateLength ?? 50;\\n\\t\\t\\t\\tfor (const attr of relevant) {\\n\\t\\t\\t\\t\\tconst value = element.getAttribute(attr);\\n\\t\\t\\t\\t\\tif (value) attributes[attr] = value.length > attrTruncate ? `${value.substring(0, attrTruncate)}...` : value;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tfor (const attr of element.attributes) if (attr.name.startsWith(\\\"data-\\\") && !relevant.includes(attr.name)) attributes[attr.name] = attr.value.length > dataAttrTruncate ? `${attr.value.substring(0, dataAttrTruncate)}...` : attr.value;\\n\\t\\t\\t\\treturn attributes;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get element context information\\n\\t\\t\\t*/\\n\\t\\t\\tstatic getElementContext(element) {\\n\\t\\t\\t\\tconst context = { parentChain: SelectorGenerator.getContextPath(element) };\\n\\t\\t\\t\\tconst form = element.closest(\\\"form\\\");\\n\\t\\t\\t\\tif (form) context.nearestForm = SelectorGenerator.generateSelectors(form).css;\\n\\t\\t\\t\\tconst section = element.closest(\\\"section, [role=\\\\\\\"region\\\\\\\"]\\\");\\n\\t\\t\\t\\tif (section) context.nearestSection = SelectorGenerator.generateSelectors(section).css;\\n\\t\\t\\t\\tconst main = element.closest(\\\"main, [role=\\\\\\\"main\\\\\\\"]\\\");\\n\\t\\t\\t\\tif (main) context.nearestMain = SelectorGenerator.generateSelectors(main).css;\\n\\t\\t\\t\\tconst nav = element.closest(\\\"nav, [role=\\\\\\\"navigation\\\\\\\"]\\\");\\n\\t\\t\\t\\tif (nav) context.nearestNav = SelectorGenerator.generateSelectors(nav).css;\\n\\t\\t\\t\\treturn context;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get interaction information for an element (compact format)\\n\\t\\t\\t*/\\n\\t\\t\\tstatic getInteractionInfo(element) {\\n\\t\\t\\t\\tconst htmlElement = element;\\n\\t\\t\\t\\tconst interaction = {};\\n\\t\\t\\t\\tif (!!(htmlElement.onclick || element.getAttribute(\\\"onclick\\\") || element.matches(\\\"button, a[href], [role=\\\\\\\"button\\\\\\\"], [tabindex]:not([tabindex=\\\\\\\"-1\\\\\\\"])\\\"))) interaction.click = true;\\n\\t\\t\\t\\tif (!!(htmlElement.onchange || element.getAttribute(\\\"onchange\\\") || element.matches(\\\"input, select, textarea\\\"))) interaction.change = true;\\n\\t\\t\\t\\tif (!!(htmlElement.onsubmit || element.getAttribute(\\\"onsubmit\\\") || element.matches(\\\"form\\\"))) interaction.submit = true;\\n\\t\\t\\t\\tif (element.matches(\\\"a[href], button[type=\\\\\\\"submit\\\\\\\"]\\\")) interaction.nav = true;\\n\\t\\t\\t\\tif (htmlElement.hasAttribute(\\\"disabled\\\") || htmlElement.getAttribute(\\\"aria-disabled\\\") === \\\"true\\\") interaction.disabled = true;\\n\\t\\t\\t\\tif (!DOMTraversal.isVisible(element)) interaction.hidden = true;\\n\\t\\t\\t\\tconst ariaRole = element.getAttribute(\\\"role\\\");\\n\\t\\t\\t\\tif (ariaRole) interaction.role = ariaRole;\\n\\t\\t\\t\\tif (element.matches(\\\"input, textarea, select, button\\\")) {\\n\\t\\t\\t\\t\\tconst form = element.form || element.closest(\\\"form\\\");\\n\\t\\t\\t\\t\\tif (form) interaction.form = SelectorGenerator.generateSelectors(form).css;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn interaction;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get text content of an element (limited length)\\n\\t\\t\\t*/\\n\\t\\t\\tstatic getElementText(element, options) {\\n\\t\\t\\t\\tif (element.matches(\\\"input, textarea\\\")) {\\n\\t\\t\\t\\t\\tconst input = element;\\n\\t\\t\\t\\t\\treturn input.value || input.placeholder || \\\"\\\";\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (element.matches(\\\"img\\\")) return element.alt || \\\"\\\";\\n\\t\\t\\t\\tconst text = element.textContent?.trim() || \\\"\\\";\\n\\t\\t\\t\\tconst maxLength = options?.textTruncateLength;\\n\\t\\t\\t\\tif (maxLength && text.length > maxLength) return `${text.substring(0, maxLength)}...`;\\n\\t\\t\\t\\treturn text;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Check if element is a semantic container\\n\\t\\t\\t*/\\n\\t\\t\\tstatic isSemanticContainer(element) {\\n\\t\\t\\t\\treturn element.matches(\\\"article, section, nav, aside, main, header, footer, form, table, ul, ol, dl, figure, details, dialog, [role=\\\\\\\"region\\\\\\\"], [role=\\\\\\\"navigation\\\\\\\"], [role=\\\\\\\"main\\\\\\\"], [role=\\\\\\\"complementary\\\\\\\"]\\\");\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get interactive elements\\n\\t\\t\\t*/\\n\\t\\t\\tstatic getInteractiveElements(container, options) {\\n\\t\\t\\t\\tconst elements = [];\\n\\t\\t\\t\\tconst selector = DOMTraversal.INTERACTIVE_SELECTORS.join(\\\", \\\");\\n\\t\\t\\t\\tconst found = container.querySelectorAll(selector);\\n\\t\\t\\t\\tfor (const element of Array.from(found)) {\\n\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(element, options);\\n\\t\\t\\t\\t\\tif (extracted) elements.push(extracted);\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (options.customSelectors) for (const customSelector of options.customSelectors) try {\\n\\t\\t\\t\\t\\tconst customFound = container.querySelectorAll(customSelector);\\n\\t\\t\\t\\t\\tfor (const element of Array.from(customFound)) {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(element, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) elements.push(extracted);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t} catch (_e) {\\n\\t\\t\\t\\t\\tconsole.warn(`Invalid custom selector: ${customSelector}`);\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn elements;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get semantic elements (for full mode)\\n\\t\\t\\t*/\\n\\t\\t\\tstatic getSemanticElements(container, options) {\\n\\t\\t\\t\\tconst elements = [];\\n\\t\\t\\t\\tconst selector = DOMTraversal.SEMANTIC_SELECTORS.join(\\\", \\\");\\n\\t\\t\\t\\tconst found = container.querySelectorAll(selector);\\n\\t\\t\\t\\tfor (const element of Array.from(found)) {\\n\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(element, options);\\n\\t\\t\\t\\t\\tif (extracted) elements.push(extracted);\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn elements;\\n\\t\\t\\t}\\n\\t\\t};\\n\\t}));\\n\\t//#endregion\\n\\t//#region src/markdown-formatter.ts\\n\\tfunction truncate(text, len) {\\n\\t\\tconst t = (text ?? \\\"\\\").trim();\\n\\t\\tif (!len || t.length <= len) return t;\\n\\t\\tconst keywords = [\\n\\t\\t\\t\\\"login\\\",\\n\\t\\t\\t\\\"log in\\\",\\n\\t\\t\\t\\\"sign in\\\",\\n\\t\\t\\t\\\"sign up\\\",\\n\\t\\t\\t\\\"submit\\\",\\n\\t\\t\\t\\\"search\\\",\\n\\t\\t\\t\\\"filter\\\",\\n\\t\\t\\t\\\"add to cart\\\",\\n\\t\\t\\t\\\"next\\\",\\n\\t\\t\\t\\\"continue\\\"\\n\\t\\t];\\n\\t\\tconst lower = t.toLowerCase();\\n\\t\\tconst hit = keywords.map((k) => ({\\n\\t\\t\\tk,\\n\\t\\t\\ti: lower.indexOf(k)\\n\\t\\t})).find((x) => x.i > -1);\\n\\t\\tconst head = Math.max(0, Math.floor(len * .66));\\n\\t\\tif (hit && hit.i > head) {\\n\\t\\t\\tconst tailWindow = Math.max(12, len - head - 5);\\n\\t\\t\\tconst start = Math.max(0, hit.i - Math.floor(tailWindow / 2));\\n\\t\\t\\tconst end = Math.min(t.length, start + tailWindow);\\n\\t\\t\\treturn `${t.slice(0, head).trimEnd()} … ${t.slice(start, end).trim()}…`;\\n\\t\\t}\\n\\t\\tconst slice = t.slice(0, len);\\n\\t\\tconst lastSpace = slice.lastIndexOf(\\\" \\\");\\n\\t\\treturn `${lastSpace > 32 ? slice.slice(0, lastSpace) : slice}…`;\\n\\t}\\n\\tfunction bestSelector(el) {\\n\\t\\treturn el.selector?.css || \\\"\\\";\\n\\t}\\n\\tfunction hashId(input) {\\n\\t\\tlet h = 5381;\\n\\t\\tfor (let i = 0; i < input.length; i++) h = h * 33 ^ input.charCodeAt(i);\\n\\t\\treturn `sec-${(h >>> 0).toString(36)}`;\\n\\t}\\n\\tfunction iconForRegion(key) {\\n\\t\\tswitch (key) {\\n\\t\\t\\tcase \\\"header\\\": return \\\"🧭\\\";\\n\\t\\t\\tcase \\\"navigation\\\": return \\\"📑\\\";\\n\\t\\t\\tcase \\\"main\\\": return \\\"📄\\\";\\n\\t\\t\\tcase \\\"sections\\\": return \\\"🗂️\\\";\\n\\t\\t\\tcase \\\"sidebar\\\": return \\\"📚\\\";\\n\\t\\t\\tcase \\\"footer\\\": return \\\"🔻\\\";\\n\\t\\t\\tcase \\\"modals\\\": return \\\"💬\\\";\\n\\t\\t\\tdefault: return \\\"🔹\\\";\\n\\t\\t}\\n\\t}\\n\\tfunction elementLine(el, opts) {\\n\\t\\tconst txt = truncate(el.text || el.attributes?.ariaLabel, opts?.maxTextLength ?? 80);\\n\\t\\tconst sel = bestSelector(el);\\n\\t\\tconst tag = el.tag.toLowerCase();\\n\\t\\tconst action = el.interaction?.submit ? \\\"submit\\\" : el.interaction?.click ? \\\"click\\\" : el.interaction?.change ? \\\"change\\\" : void 0;\\n\\t\\tconst actionText = action ? ` (${action})` : \\\"\\\";\\n\\t\\treturn `- ${tag.toUpperCase()}: ${txt || \\\"(no text)\\\"} → \\\\`${sel}\\\\`${actionText}`;\\n\\t}\\n\\tfunction selectorQualitySummary(inter) {\\n\\t\\tconst all = [];\\n\\t\\tall.push(...inter.buttons.map((e) => e.selector?.css || \\\"\\\"));\\n\\t\\tall.push(...inter.links.map((e) => e.selector?.css || \\\"\\\"));\\n\\t\\tall.push(...inter.inputs.map((e) => e.selector?.css || \\\"\\\"));\\n\\t\\tall.push(...inter.clickable.map((e) => e.selector?.css || \\\"\\\"));\\n\\t\\tconst total = all.length || 1;\\n\\t\\tconst idCount = all.filter((s) => s.startsWith(\\\"#\\\")).length;\\n\\t\\tconst testIdCount = all.filter((s) => /\\\\[data-testid=/.test(s)).length;\\n\\t\\tconst nthCount = all.filter((s) => /:nth-child\\\\(/.test(s)).length;\\n\\t\\tconst stable = idCount + testIdCount;\\n\\t\\treturn `Selector quality: ${Math.round(stable / total * 100)}% stable (ID/data-testid), ${Math.round(nthCount / total * 100)}% structural (:nth-child)`;\\n\\t}\\n\\tfunction renderInteractive(inter, opts) {\\n\\t\\tconst parts = [];\\n\\t\\tconst limit = (arr) => typeof opts?.maxElements === \\\"number\\\" ? arr.slice(0, opts.maxElements) : arr;\\n\\t\\tif (inter.buttons.length) {\\n\\t\\t\\tparts.push(\\\"Buttons:\\\");\\n\\t\\t\\tfor (const el of limit(inter.buttons)) parts.push(elementLine(el, opts));\\n\\t\\t}\\n\\t\\tif (inter.links.length) {\\n\\t\\t\\tparts.push(\\\"Links:\\\");\\n\\t\\t\\tfor (const el of limit(inter.links)) parts.push(elementLine(el, opts));\\n\\t\\t}\\n\\t\\tif (inter.inputs.length) {\\n\\t\\t\\tparts.push(\\\"Inputs:\\\");\\n\\t\\t\\tfor (const el of limit(inter.inputs)) parts.push(elementLine(el, opts));\\n\\t\\t}\\n\\t\\tif (inter.clickable.length) {\\n\\t\\t\\tparts.push(\\\"Other Clickable:\\\");\\n\\t\\t\\tfor (const el of limit(inter.clickable)) parts.push(elementLine(el, opts));\\n\\t\\t}\\n\\t\\tif (inter.forms.length) {\\n\\t\\t\\tparts.push(\\\"Forms:\\\");\\n\\t\\t\\tfor (const f of limit(inter.forms)) parts.push(`- FORM: action=${f.action ?? \\\"-\\\"} method=${f.method ?? \\\"-\\\"} → \\\\`${f.selector}\\\\``);\\n\\t\\t}\\n\\t\\treturn parts.join(\\\"\\\\n\\\");\\n\\t}\\n\\tfunction renderRegionInfo(region) {\\n\\t\\tconst icon = iconForRegion(\\\"region\\\");\\n\\t\\tconst id = hashId(`${region.selector}|${region.label ?? \\\"\\\"}|${region.role ?? \\\"\\\"}`);\\n\\t\\tconst label = region.label ? ` ${region.label}` : \\\"\\\";\\n\\t\\tconst stats = [];\\n\\t\\tif (region.buttonCount) stats.push(`${region.buttonCount} buttons`);\\n\\t\\tif (region.linkCount) stats.push(`${region.linkCount} links`);\\n\\t\\tif (region.inputCount) stats.push(`${region.inputCount} inputs`);\\n\\t\\tif (region.textPreview) stats.push(`“${truncate(region.textPreview, 80)}”`);\\n\\t\\tconst statsLine = stats.length ? ` — ${stats.join(\\\", \\\")}` : \\\"\\\";\\n\\t\\treturn `${icon} ${label} → \\\\`${region.selector}\\\\` [${id}]${statsLine}`;\\n\\t}\\n\\tfunction wrapXml(body, meta, type = \\\"section\\\") {\\n\\t\\treturn `<page ${[meta?.title ? `title=\\\"${escapeXml(meta?.title)}\\\"` : null, meta?.url ? `url=\\\"${escapeXml(meta?.url)}\\\"` : null].filter(Boolean).join(\\\" \\\")}>\\\\n <${type}><![CDATA[\\\\n${body}\\\\n]]></${type}>\\\\n</page>`;\\n\\t}\\n\\tfunction escapeXml(s) {\\n\\t\\treturn s.replace(/&/g, \\\"&\\\").replace(/</g, \\\"<\\\").replace(/>/g, \\\">\\\").replace(/\\\"/g, \\\""\\\");\\n\\t}\\n\\tfunction capitalize(s) {\\n\\t\\treturn s.charAt(0).toUpperCase() + s.slice(1);\\n\\t}\\n\\tvar MarkdownFormatter;\\n\\tvar init_markdown_formatter = __esmMin((() => {\\n\\t\\tMarkdownFormatter = class {\\n\\t\\t\\tstatic structure(overview, _opts = {}, meta) {\\n\\t\\t\\t\\tconst lines = [];\\n\\t\\t\\t\\tlines.push(\\\"# Page Outline\\\");\\n\\t\\t\\t\\tif (meta?.title || meta?.url) {\\n\\t\\t\\t\\t\\tlines.push(`Title: ${meta?.title ?? \\\"\\\"}`.trim());\\n\\t\\t\\t\\t\\tlines.push(`URL: ${meta?.url ?? \\\"\\\"}`.trim());\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\tconst regions = overview.regions;\\n\\t\\t\\t\\tconst entries = [\\n\\t\\t\\t\\t\\t[\\\"header\\\", regions.header],\\n\\t\\t\\t\\t\\t[\\\"navigation\\\", regions.navigation],\\n\\t\\t\\t\\t\\t[\\\"main\\\", regions.main],\\n\\t\\t\\t\\t\\t[\\\"sections\\\", regions.sections],\\n\\t\\t\\t\\t\\t[\\\"sidebar\\\", regions.sidebar],\\n\\t\\t\\t\\t\\t[\\\"footer\\\", regions.footer],\\n\\t\\t\\t\\t\\t[\\\"modals\\\", regions.modals]\\n\\t\\t\\t\\t];\\n\\t\\t\\t\\tfor (const [key, value] of entries) {\\n\\t\\t\\t\\t\\tif (!value) continue;\\n\\t\\t\\t\\t\\tconst icon = iconForRegion(key);\\n\\t\\t\\t\\t\\tif (Array.isArray(value)) {\\n\\t\\t\\t\\t\\t\\tif (!value.length) continue;\\n\\t\\t\\t\\t\\t\\tlines.push(`## ${icon} ${capitalize(key)}`);\\n\\t\\t\\t\\t\\t\\tfor (const region of value) lines.push(renderRegionInfo(region));\\n\\t\\t\\t\\t\\t} else {\\n\\t\\t\\t\\t\\t\\tlines.push(`## ${icon} ${capitalize(key)}`);\\n\\t\\t\\t\\t\\t\\tlines.push(renderRegionInfo(value));\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (overview.suggestions?.length) {\\n\\t\\t\\t\\t\\tlines.push(\\\"## Suggestions\\\");\\n\\t\\t\\t\\t\\tfor (const s of overview.suggestions) lines.push(`- ${s}`);\\n\\t\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tlines.push(\\\"Next: choose a region (by selector or [sectionId]) and call dom_extract_region for actionable details.\\\");\\n\\t\\t\\t\\treturn wrapXml(lines.join(\\\"\\\\n\\\"), meta, \\\"outline\\\");\\n\\t\\t\\t}\\n\\t\\t\\tstatic region(result, opts = {}, meta) {\\n\\t\\t\\t\\tconst lines = [];\\n\\t\\t\\t\\tlines.push(\\\"# Region Details\\\");\\n\\t\\t\\t\\tif (meta?.title || meta?.url) {\\n\\t\\t\\t\\t\\tlines.push(`Title: ${meta?.title ?? \\\"\\\"}`.trim());\\n\\t\\t\\t\\t\\tlines.push(`URL: ${meta?.url ?? \\\"\\\"}`.trim());\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\tconst inter = result.interactive;\\n\\t\\t\\t\\tif (result.page) {\\n\\t\\t\\t\\t\\tconst ps = [\\n\\t\\t\\t\\t\\t\\tresult.page.hasErrors ? \\\"errors: yes\\\" : \\\"errors: no\\\",\\n\\t\\t\\t\\t\\t\\tresult.page.isLoading ? \\\"loading: yes\\\" : \\\"loading: no\\\",\\n\\t\\t\\t\\t\\t\\tresult.page.hasModals ? \\\"modals: yes\\\" : \\\"modals: no\\\"\\n\\t\\t\\t\\t\\t];\\n\\t\\t\\t\\t\\tlines.push(`Page state: ${ps.join(\\\", \\\")}`);\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tconst summary = [];\\n\\t\\t\\t\\tconst count = (arr) => arr ? arr.length : 0;\\n\\t\\t\\t\\tsummary.push(`${count(inter.buttons)} buttons`);\\n\\t\\t\\t\\tsummary.push(`${count(inter.links)} links`);\\n\\t\\t\\t\\tsummary.push(`${count(inter.inputs)} inputs`);\\n\\t\\t\\t\\tif (inter.forms?.length) summary.push(`${count(inter.forms)} forms`);\\n\\t\\t\\t\\tlines.push(`Summary: ${summary.join(\\\", \\\")}`);\\n\\t\\t\\t\\tlines.push(selectorQualitySummary(inter));\\n\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\tlines.push(renderInteractive(inter, opts));\\n\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\tlines.push(\\\"Next: write a script using the most stable selectors above. If selectors look unstable, rerun dom_extract_region with higher detail or call dom_extract_content for text context.\\\");\\n\\t\\t\\t\\treturn wrapXml(lines.join(\\\"\\\\n\\\"), meta, \\\"section\\\");\\n\\t\\t\\t}\\n\\t\\t\\tstatic content(content, opts = {}, meta) {\\n\\t\\t\\t\\tconst lines = [];\\n\\t\\t\\t\\tlines.push(\\\"# Content\\\");\\n\\t\\t\\t\\tlines.push(`Selector: \\\\`${content.selector}\\\\``);\\n\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\tif (content.text.headings?.length) {\\n\\t\\t\\t\\t\\tlines.push(\\\"Headings:\\\");\\n\\t\\t\\t\\t\\tfor (const h of content.text.headings) lines.push(`- H${h.level}: ${truncate(h.text, opts.maxTextLength ?? 120)}`);\\n\\t\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (content.text.paragraphs?.length) {\\n\\t\\t\\t\\t\\tconst limit = typeof opts.maxElements === \\\"number\\\" ? opts.maxElements : content.text.paragraphs.length;\\n\\t\\t\\t\\t\\tlines.push(\\\"Paragraphs:\\\");\\n\\t\\t\\t\\t\\tfor (const p of content.text.paragraphs.slice(0, limit)) lines.push(`- ${truncate(p, opts.maxTextLength ?? 200)}`);\\n\\t\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (content.text.lists?.length) {\\n\\t\\t\\t\\t\\tlines.push(\\\"Lists:\\\");\\n\\t\\t\\t\\t\\tfor (const list of content.text.lists) {\\n\\t\\t\\t\\t\\t\\tlines.push(`- ${list.type.toUpperCase()}:`);\\n\\t\\t\\t\\t\\t\\tconst limit = typeof opts.maxElements === \\\"number\\\" ? opts.maxElements : list.items.length;\\n\\t\\t\\t\\t\\t\\tfor (const item of list.items.slice(0, limit)) lines.push(` - ${truncate(item, opts.maxTextLength ?? 120)}`);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (content.tables?.length) {\\n\\t\\t\\t\\t\\tlines.push(\\\"Tables:\\\");\\n\\t\\t\\t\\t\\tfor (const t of content.tables) {\\n\\t\\t\\t\\t\\t\\tlines.push(`- Headers: ${t.headers.join(\\\" | \\\")}`);\\n\\t\\t\\t\\t\\t\\tconst limit = typeof opts.maxElements === \\\"number\\\" ? opts.maxElements : t.rows.length;\\n\\t\\t\\t\\t\\t\\tfor (const row of t.rows.slice(0, limit)) lines.push(` - ${row.join(\\\" | \\\")}`);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (content.media?.length) {\\n\\t\\t\\t\\t\\tlines.push(\\\"Media:\\\");\\n\\t\\t\\t\\t\\tconst limit = typeof opts.maxElements === \\\"number\\\" ? opts.maxElements : content.media.length;\\n\\t\\t\\t\\t\\tfor (const m of content.media.slice(0, limit)) lines.push(`- ${m.type.toUpperCase()}: ${m.alt ?? \\\"\\\"} ${m.src ? `→ ${m.src}` : \\\"\\\"}`.trim());\\n\\t\\t\\t\\t\\tlines.push(\\\"\\\");\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tlines.push(\\\"Next: if text is insufficient for targeting, call dom_extract_region for interactive selectors.\\\");\\n\\t\\t\\t\\treturn wrapXml(lines.join(\\\"\\\\n\\\"), meta, \\\"content\\\");\\n\\t\\t\\t}\\n\\t\\t};\\n\\t}));\\n\\t//#endregion\\n\\t//#region src/progressive.ts\\n\\tfunction resolveSmartDomReader() {\\n\\t\\tif (typeof window !== \\\"undefined\\\") {\\n\\t\\t\\tconst globalWindow = window;\\n\\t\\t\\tconst direct = globalWindow.SmartDOMReader;\\n\\t\\t\\tif (typeof direct === \\\"function\\\") return direct;\\n\\t\\t\\tconst namespace = globalWindow.SmartDOMReaderNamespace;\\n\\t\\t\\tif (namespace && typeof namespace.SmartDOMReader === \\\"function\\\") return namespace.SmartDOMReader;\\n\\t\\t}\\n\\t\\ttry {\\n\\t\\t\\tif (typeof require === \\\"function\\\") {\\n\\t\\t\\t\\tconst moduleExports = (init_src(), __toCommonJS(src_exports));\\n\\t\\t\\t\\tif (moduleExports && typeof moduleExports.SmartDOMReader === \\\"function\\\") return moduleExports.SmartDOMReader;\\n\\t\\t\\t\\tif (moduleExports && typeof moduleExports.default === \\\"function\\\") return moduleExports.default;\\n\\t\\t\\t}\\n\\t\\t} catch {}\\n\\t}\\n\\tvar ProgressiveExtractor;\\n\\tvar init_progressive = __esmMin((() => {\\n\\t\\tinit_content_detection();\\n\\t\\tinit_selectors();\\n\\t\\tinit_traversal();\\n\\t\\tProgressiveExtractor = class ProgressiveExtractor {\\n\\t\\t\\t/**\\n\\t\\t\\t* Step 1: Extract high-level structural overview\\n\\t\\t\\t* This provides a \\\"map\\\" of the page for the AI to understand structure\\n\\t\\t\\t*/\\n\\t\\t\\tstatic extractStructure(root) {\\n\\t\\t\\t\\tconst regions = {};\\n\\t\\t\\t\\tconst header = root.querySelector(\\\"header, [role=\\\\\\\"banner\\\\\\\"], .header, #header\\\");\\n\\t\\t\\t\\tif (header) regions.header = ProgressiveExtractor.analyzeRegion(header);\\n\\t\\t\\t\\tconst navs = root.querySelectorAll(\\\"nav, [role=\\\\\\\"navigation\\\\\\\"], .nav, .navigation\\\");\\n\\t\\t\\t\\tif (navs.length > 0) regions.navigation = Array.from(navs).map((nav) => ProgressiveExtractor.analyzeRegion(nav));\\n\\t\\t\\t\\tif (root instanceof Document) {\\n\\t\\t\\t\\t\\tconst main = ContentDetection.findMainContent(root);\\n\\t\\t\\t\\t\\tif (main) {\\n\\t\\t\\t\\t\\t\\tregions.main = ProgressiveExtractor.analyzeRegion(main);\\n\\t\\t\\t\\t\\t\\tconst sections = main.querySelectorAll(\\\"section, article, [role=\\\\\\\"region\\\\\\\"]\\\");\\n\\t\\t\\t\\t\\t\\tif (sections.length > 0) regions.sections = Array.from(sections).filter((section) => !section.closest(\\\"nav, header, footer\\\")).map((section) => ProgressiveExtractor.analyzeRegion(section));\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t} else {\\n\\t\\t\\t\\t\\tregions.main = ProgressiveExtractor.analyzeRegion(root);\\n\\t\\t\\t\\t\\tconst sections = root.querySelectorAll(\\\"section, article, [role=\\\\\\\"region\\\\\\\"]\\\");\\n\\t\\t\\t\\t\\tif (sections.length > 0) regions.sections = Array.from(sections).filter((section) => !section.closest(\\\"nav, header, footer\\\")).map((section) => ProgressiveExtractor.analyzeRegion(section));\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tconst sidebars = root.querySelectorAll(\\\"aside, [role=\\\\\\\"complementary\\\\\\\"], .sidebar, #sidebar\\\");\\n\\t\\t\\t\\tif (sidebars.length > 0) regions.sidebar = Array.from(sidebars).map((sidebar) => ProgressiveExtractor.analyzeRegion(sidebar));\\n\\t\\t\\t\\tconst footer = root.querySelector(\\\"footer, [role=\\\\\\\"contentinfo\\\\\\\"], .footer, #footer\\\");\\n\\t\\t\\t\\tif (footer) regions.footer = ProgressiveExtractor.analyzeRegion(footer);\\n\\t\\t\\t\\tconst modals = root.querySelectorAll(\\\"[role=\\\\\\\"dialog\\\\\\\"], .modal, .popup, .overlay\\\");\\n\\t\\t\\t\\tconst visibleModals = Array.from(modals).filter((modal) => DOMTraversal.isVisible(modal));\\n\\t\\t\\t\\tif (visibleModals.length > 0) regions.modals = visibleModals.map((modal) => ProgressiveExtractor.analyzeRegion(modal));\\n\\t\\t\\t\\tconst forms = ProgressiveExtractor.extractFormOverview(root);\\n\\t\\t\\t\\tconst summary = ProgressiveExtractor.calculateSummary(root, regions, forms);\\n\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\tregions,\\n\\t\\t\\t\\t\\tforms,\\n\\t\\t\\t\\t\\tsummary,\\n\\t\\t\\t\\t\\tsuggestions: ProgressiveExtractor.generateSuggestions(regions, summary)\\n\\t\\t\\t\\t};\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Step 2: Extract detailed information from a specific region\\n\\t\\t\\t*/\\n\\t\\t\\tstatic extractRegion(selector, doc, options = {}, smartDomReaderCtor) {\\n\\t\\t\\t\\tconst element = doc.querySelector(selector);\\n\\t\\t\\t\\tif (!element) return null;\\n\\t\\t\\t\\tconst SmartDOMReaderCtor = smartDomReaderCtor ?? resolveSmartDomReader();\\n\\t\\t\\t\\tif (!SmartDOMReaderCtor) throw new Error(\\\"SmartDOMReader is unavailable. Ensure the Smart DOM Reader module is loaded before calling extractRegion.\\\");\\n\\t\\t\\t\\treturn new SmartDOMReaderCtor(options).extract(element, options);\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Step 3: Extract readable content from a region\\n\\t\\t\\t*/\\n\\t\\t\\tstatic extractContent(selector, doc, options = {}) {\\n\\t\\t\\t\\tconst element = doc.querySelector(selector);\\n\\t\\t\\t\\tif (!element) return null;\\n\\t\\t\\t\\tconst result = {\\n\\t\\t\\t\\t\\tselector,\\n\\t\\t\\t\\t\\ttext: {},\\n\\t\\t\\t\\t\\tmetadata: {\\n\\t\\t\\t\\t\\t\\twordCount: 0,\\n\\t\\t\\t\\t\\t\\thasInteractive: false\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t};\\n\\t\\t\\t\\tif (options.includeHeadings !== false) {\\n\\t\\t\\t\\t\\tconst headings = element.querySelectorAll(\\\"h1, h2, h3, h4, h5, h6\\\");\\n\\t\\t\\t\\t\\tresult.text.headings = Array.from(headings).map((h) => ({\\n\\t\\t\\t\\t\\t\\tlevel: Number.parseInt(h.tagName[1], 10),\\n\\t\\t\\t\\t\\t\\ttext: ProgressiveExtractor.getTextContent(h, options.maxTextLength)\\n\\t\\t\\t\\t\\t}));\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tconst paragraphs = element.querySelectorAll(\\\"p\\\");\\n\\t\\t\\t\\tif (paragraphs.length > 0) result.text.paragraphs = Array.from(paragraphs).map((p) => ProgressiveExtractor.getTextContent(p, options.maxTextLength)).filter((text) => text.length > 0);\\n\\t\\t\\t\\tif (options.includeLists !== false) {\\n\\t\\t\\t\\t\\tconst lists = element.querySelectorAll(\\\"ul, ol\\\");\\n\\t\\t\\t\\t\\tresult.text.lists = Array.from(lists).map((list) => ({\\n\\t\\t\\t\\t\\t\\ttype: list.tagName.toLowerCase(),\\n\\t\\t\\t\\t\\t\\titems: Array.from(list.querySelectorAll(\\\"li\\\")).map((li) => ProgressiveExtractor.getTextContent(li, options.maxTextLength))\\n\\t\\t\\t\\t\\t}));\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (options.includeTables !== false) {\\n\\t\\t\\t\\t\\tconst tables = element.querySelectorAll(\\\"table\\\");\\n\\t\\t\\t\\t\\tresult.tables = Array.from(tables).map((table) => {\\n\\t\\t\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\t\\t\\theaders: Array.from(table.querySelectorAll(\\\"th\\\")).map((th) => ProgressiveExtractor.getTextContent(th)),\\n\\t\\t\\t\\t\\t\\t\\trows: Array.from(table.querySelectorAll(\\\"tr\\\")).filter((tr) => tr.querySelector(\\\"td\\\")).map((tr) => Array.from(tr.querySelectorAll(\\\"td\\\")).map((td) => ProgressiveExtractor.getTextContent(td)))\\n\\t\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (options.includeMedia !== false) {\\n\\t\\t\\t\\t\\tconst images = element.querySelectorAll(\\\"img\\\");\\n\\t\\t\\t\\t\\tconst videos = element.querySelectorAll(\\\"video\\\");\\n\\t\\t\\t\\t\\tconst audios = element.querySelectorAll(\\\"audio\\\");\\n\\t\\t\\t\\t\\tresult.media = [\\n\\t\\t\\t\\t\\t\\t...Array.from(images).map((img) => {\\n\\t\\t\\t\\t\\t\\t\\tconst item = { type: \\\"img\\\" };\\n\\t\\t\\t\\t\\t\\t\\tconst alt = img.getAttribute(\\\"alt\\\");\\n\\t\\t\\t\\t\\t\\t\\tconst src = img.getAttribute(\\\"src\\\");\\n\\t\\t\\t\\t\\t\\t\\tif (alt) item.alt = alt;\\n\\t\\t\\t\\t\\t\\t\\tif (src) item.src = src;\\n\\t\\t\\t\\t\\t\\t\\treturn item;\\n\\t\\t\\t\\t\\t\\t}),\\n\\t\\t\\t\\t\\t\\t...Array.from(videos).map((video) => {\\n\\t\\t\\t\\t\\t\\t\\tconst item = { type: \\\"video\\\" };\\n\\t\\t\\t\\t\\t\\t\\tconst src = video.getAttribute(\\\"src\\\");\\n\\t\\t\\t\\t\\t\\t\\tif (src) item.src = src;\\n\\t\\t\\t\\t\\t\\t\\treturn item;\\n\\t\\t\\t\\t\\t\\t}),\\n\\t\\t\\t\\t\\t\\t...Array.from(audios).map((audio) => {\\n\\t\\t\\t\\t\\t\\t\\tconst item = { type: \\\"audio\\\" };\\n\\t\\t\\t\\t\\t\\t\\tconst src = audio.getAttribute(\\\"src\\\");\\n\\t\\t\\t\\t\\t\\t\\tif (src) item.src = src;\\n\\t\\t\\t\\t\\t\\t\\treturn item;\\n\\t\\t\\t\\t\\t\\t})\\n\\t\\t\\t\\t\\t];\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tconst allText = element.textContent || \\\"\\\";\\n\\t\\t\\t\\tresult.metadata.wordCount = allText.trim().split(/\\\\s+/).length;\\n\\t\\t\\t\\tresult.metadata.hasInteractive = element.querySelectorAll(\\\"button, a, input, textarea, select\\\").length > 0;\\n\\t\\t\\t\\treturn result;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Analyze a region and extract summary information\\n\\t\\t\\t*/\\n\\t\\t\\tstatic analyzeRegion(element) {\\n\\t\\t\\t\\tconst selector = SelectorGenerator.generateSelectors(element).css;\\n\\t\\t\\t\\tconst buttons = element.querySelectorAll(\\\"button, [role=\\\\\\\"button\\\\\\\"]\\\");\\n\\t\\t\\t\\tconst links = element.querySelectorAll(\\\"a[href]\\\");\\n\\t\\t\\t\\tconst inputs = element.querySelectorAll(\\\"input, textarea, select\\\");\\n\\t\\t\\t\\tconst forms = element.querySelectorAll(\\\"form\\\");\\n\\t\\t\\t\\tconst lists = element.querySelectorAll(\\\"ul, ol\\\");\\n\\t\\t\\t\\tconst tables = element.querySelectorAll(\\\"table\\\");\\n\\t\\t\\t\\tconst media = element.querySelectorAll(\\\"img, video, audio\\\");\\n\\t\\t\\t\\tconst interactiveCount = buttons.length + links.length + inputs.length;\\n\\t\\t\\t\\tlet label;\\n\\t\\t\\t\\tconst ariaLabel = element.getAttribute(\\\"aria-label\\\");\\n\\t\\t\\t\\tif (ariaLabel) label = ariaLabel;\\n\\t\\t\\t\\telse if (element.getAttribute(\\\"aria-labelledby\\\")) {\\n\\t\\t\\t\\t\\tconst labelId = element.getAttribute(\\\"aria-labelledby\\\");\\n\\t\\t\\t\\t\\tif (labelId) {\\n\\t\\t\\t\\t\\t\\tconst labelElement = element.ownerDocument?.getElementById(labelId);\\n\\t\\t\\t\\t\\t\\tif (labelElement) label = labelElement.textContent?.trim();\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t} else {\\n\\t\\t\\t\\t\\tconst heading = element.querySelector(\\\"h1, h2, h3\\\");\\n\\t\\t\\t\\t\\tif (heading) label = heading.textContent?.trim();\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tconst textContent = element.textContent?.trim() || \\\"\\\";\\n\\t\\t\\t\\tconst textPreview = textContent.length > 50 ? `${textContent.substring(0, 50)}...` : textContent;\\n\\t\\t\\t\\tconst regionInfo = {\\n\\t\\t\\t\\t\\tselector,\\n\\t\\t\\t\\t\\tinteractiveCount,\\n\\t\\t\\t\\t\\thasForm: forms.length > 0,\\n\\t\\t\\t\\t\\thasList: lists.length > 0,\\n\\t\\t\\t\\t\\thasTable: tables.length > 0,\\n\\t\\t\\t\\t\\thasMedia: media.length > 0\\n\\t\\t\\t\\t};\\n\\t\\t\\t\\tif (label) regionInfo.label = label;\\n\\t\\t\\t\\tconst role = element.getAttribute(\\\"role\\\");\\n\\t\\t\\t\\tif (role) regionInfo.role = role;\\n\\t\\t\\t\\tif (buttons.length > 0) regionInfo.buttonCount = buttons.length;\\n\\t\\t\\t\\tif (links.length > 0) regionInfo.linkCount = links.length;\\n\\t\\t\\t\\tif (inputs.length > 0) regionInfo.inputCount = inputs.length;\\n\\t\\t\\t\\tif (textPreview.length > 0) regionInfo.textPreview = textPreview;\\n\\t\\t\\t\\treturn regionInfo;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Extract overview of forms on the page\\n\\t\\t\\t*/\\n\\t\\t\\tstatic extractFormOverview(root) {\\n\\t\\t\\t\\tconst forms = root.querySelectorAll(\\\"form\\\");\\n\\t\\t\\t\\treturn Array.from(forms).map((form) => {\\n\\t\\t\\t\\t\\tconst inputs = form.querySelectorAll(\\\"input, textarea, select\\\");\\n\\t\\t\\t\\t\\tconst selector = SelectorGenerator.generateSelectors(form).css;\\n\\t\\t\\t\\t\\tlet location = \\\"unknown\\\";\\n\\t\\t\\t\\t\\tif (form.closest(\\\"header, [role=\\\\\\\"banner\\\\\\\"]\\\")) location = \\\"header\\\";\\n\\t\\t\\t\\t\\telse if (form.closest(\\\"nav, [role=\\\\\\\"navigation\\\\\\\"]\\\")) location = \\\"navigation\\\";\\n\\t\\t\\t\\t\\telse if (form.closest(\\\"main, [role=\\\\\\\"main\\\\\\\"]\\\")) location = \\\"main\\\";\\n\\t\\t\\t\\t\\telse if (form.closest(\\\"aside, [role=\\\\\\\"complementary\\\\\\\"]\\\")) location = \\\"sidebar\\\";\\n\\t\\t\\t\\t\\telse if (form.closest(\\\"footer, [role=\\\\\\\"contentinfo\\\\\\\"]\\\")) location = \\\"footer\\\";\\n\\t\\t\\t\\t\\tlet purpose;\\n\\t\\t\\t\\t\\tconst formId = form.getAttribute(\\\"id\\\")?.toLowerCase();\\n\\t\\t\\t\\t\\tconst formClass = form.getAttribute(\\\"class\\\")?.toLowerCase();\\n\\t\\t\\t\\t\\tconst formAction = form.getAttribute(\\\"action\\\")?.toLowerCase();\\n\\t\\t\\t\\t\\tconst hasEmail = form.querySelector(\\\"input[type=\\\\\\\"email\\\\\\\"]\\\");\\n\\t\\t\\t\\t\\tconst hasPassword = form.querySelector(\\\"input[type=\\\\\\\"password\\\\\\\"]\\\");\\n\\t\\t\\t\\t\\tif (form.querySelector(\\\"input[type=\\\\\\\"search\\\\\\\"]\\\") || formId?.includes(\\\"search\\\") || formClass?.includes(\\\"search\\\")) purpose = \\\"search\\\";\\n\\t\\t\\t\\t\\telse if (hasPassword && hasEmail) purpose = \\\"login\\\";\\n\\t\\t\\t\\t\\telse if (hasPassword) purpose = \\\"authentication\\\";\\n\\t\\t\\t\\t\\telse if (formId?.includes(\\\"contact\\\") || formClass?.includes(\\\"contact\\\")) purpose = \\\"contact\\\";\\n\\t\\t\\t\\t\\telse if (formId?.includes(\\\"subscribe\\\") || formClass?.includes(\\\"subscribe\\\")) purpose = \\\"subscription\\\";\\n\\t\\t\\t\\t\\telse if (formAction?.includes(\\\"checkout\\\") || formClass?.includes(\\\"checkout\\\")) purpose = \\\"checkout\\\";\\n\\t\\t\\t\\t\\tconst formOverview = {\\n\\t\\t\\t\\t\\t\\tselector,\\n\\t\\t\\t\\t\\t\\tlocation,\\n\\t\\t\\t\\t\\t\\tinputCount: inputs.length\\n\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\tif (purpose) formOverview.purpose = purpose;\\n\\t\\t\\t\\t\\treturn formOverview;\\n\\t\\t\\t\\t});\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Calculate summary statistics\\n\\t\\t\\t*/\\n\\t\\t\\tstatic calculateSummary(root, regions, forms) {\\n\\t\\t\\t\\tconst allInteractive = root.querySelectorAll(\\\"button, a[href], input, textarea, select\\\");\\n\\t\\t\\t\\tconst allSections = root.querySelectorAll(\\\"section, article, [role=\\\\\\\"region\\\\\\\"]\\\");\\n\\t\\t\\t\\tconst hasModals = (regions.modals?.length || 0) > 0;\\n\\t\\t\\t\\tconst hasErrors = [\\n\\t\\t\\t\\t\\t\\\".error\\\",\\n\\t\\t\\t\\t\\t\\\".alert-danger\\\",\\n\\t\\t\\t\\t\\t\\\"[role=\\\\\\\"alert\\\\\\\"]\\\"\\n\\t\\t\\t\\t].some((sel) => {\\n\\t\\t\\t\\t\\tconst element = root.querySelector(sel);\\n\\t\\t\\t\\t\\treturn element ? DOMTraversal.isVisible(element) : false;\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tconst isLoading = [\\n\\t\\t\\t\\t\\t\\\".loading\\\",\\n\\t\\t\\t\\t\\t\\\".spinner\\\",\\n\\t\\t\\t\\t\\t\\\"[aria-busy=\\\\\\\"true\\\\\\\"]\\\"\\n\\t\\t\\t\\t].some((sel) => {\\n\\t\\t\\t\\t\\tconst element = root.querySelector(sel);\\n\\t\\t\\t\\t\\treturn element ? DOMTraversal.isVisible(element) : false;\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tconst summary = {\\n\\t\\t\\t\\t\\ttotalInteractive: allInteractive.length,\\n\\t\\t\\t\\t\\ttotalForms: forms.length,\\n\\t\\t\\t\\t\\ttotalSections: allSections.length,\\n\\t\\t\\t\\t\\thasModals,\\n\\t\\t\\t\\t\\thasErrors,\\n\\t\\t\\t\\t\\tisLoading\\n\\t\\t\\t\\t};\\n\\t\\t\\t\\tconst mainContentSelector = regions.main?.selector;\\n\\t\\t\\t\\tif (mainContentSelector) summary.mainContentSelector = mainContentSelector;\\n\\t\\t\\t\\treturn summary;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Generate AI-friendly suggestions\\n\\t\\t\\t*/\\n\\t\\t\\tstatic generateSuggestions(regions, summary) {\\n\\t\\t\\t\\tconst suggestions = [];\\n\\t\\t\\t\\tif (summary.hasErrors) suggestions.push(\\\"Page has error indicators - check error messages before interacting\\\");\\n\\t\\t\\t\\tif (summary.isLoading) suggestions.push(\\\"Page appears to be loading - wait or check loading state\\\");\\n\\t\\t\\t\\tif (summary.hasModals) suggestions.push(\\\"Modal/dialog is open - may need to interact with or close it first\\\");\\n\\t\\t\\t\\tif (regions.main && regions.main.interactiveCount > 10) suggestions.push(`Main content has ${regions.main.interactiveCount} interactive elements - consider filtering`);\\n\\t\\t\\t\\tif (summary.totalForms > 0) suggestions.push(`Found ${summary.totalForms} form(s) on the page`);\\n\\t\\t\\t\\tif (!regions.main) suggestions.push(\\\"No clear main content area detected - may need to explore regions\\\");\\n\\t\\t\\t\\treturn suggestions;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get text content with optional truncation\\n\\t\\t\\t*/\\n\\t\\t\\tstatic getTextContent(element, maxLength) {\\n\\t\\t\\t\\tconst text = element.textContent?.trim() || \\\"\\\";\\n\\t\\t\\t\\tif (maxLength && text.length > maxLength) return `${text.substring(0, maxLength)}...`;\\n\\t\\t\\t\\treturn text;\\n\\t\\t\\t}\\n\\t\\t};\\n\\t}));\\n\\t//#endregion\\n\\t//#region src/types.ts\\n\\tvar init_types = __esmMin((() => {}));\\n\\t//#endregion\\n\\t//#region src/index.ts\\n\\tvar src_exports = /* @__PURE__ */ __exportAll({\\n\\t\\tContentDetection: () => ContentDetection,\\n\\t\\tMarkdownFormatter: () => MarkdownFormatter,\\n\\t\\tProgressiveExtractor: () => ProgressiveExtractor,\\n\\t\\tSelectorGenerator: () => SelectorGenerator,\\n\\t\\tSmartDOMReader: () => SmartDOMReader,\\n\\t\\tdefault: () => SmartDOMReader\\n\\t});\\n\\tvar SmartDOMReader;\\n\\tvar init_src = __esmMin((() => {\\n\\t\\tinit_content_detection();\\n\\t\\tinit_selectors();\\n\\t\\tinit_traversal();\\n\\t\\tinit_markdown_formatter();\\n\\t\\tinit_progressive();\\n\\t\\tinit_types();\\n\\t\\tSmartDOMReader = class SmartDOMReader {\\n\\t\\t\\toptions;\\n\\t\\t\\tconstructor(options = {}) {\\n\\t\\t\\t\\tthis.options = {\\n\\t\\t\\t\\t\\tmode: options.mode || \\\"interactive\\\",\\n\\t\\t\\t\\t\\tmaxDepth: options.maxDepth || 5,\\n\\t\\t\\t\\t\\tincludeHidden: options.includeHidden || false,\\n\\t\\t\\t\\t\\tincludeShadowDOM: options.includeShadowDOM ?? true,\\n\\t\\t\\t\\t\\tincludeIframes: options.includeIframes || false,\\n\\t\\t\\t\\t\\tviewportOnly: options.viewportOnly || false,\\n\\t\\t\\t\\t\\tmainContentOnly: options.mainContentOnly || false,\\n\\t\\t\\t\\t\\tcustomSelectors: options.customSelectors || [],\\n\\t\\t\\t\\t\\t...options.attributeTruncateLength !== void 0 && { attributeTruncateLength: options.attributeTruncateLength },\\n\\t\\t\\t\\t\\t...options.dataAttributeTruncateLength !== void 0 && { dataAttributeTruncateLength: options.dataAttributeTruncateLength },\\n\\t\\t\\t\\t\\t...options.textTruncateLength !== void 0 && { textTruncateLength: options.textTruncateLength },\\n\\t\\t\\t\\t\\t...options.filter !== void 0 && { filter: options.filter }\\n\\t\\t\\t\\t};\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Main extraction method - extracts all data in one pass\\n\\t\\t\\t* @param rootElement The document or element to extract from\\n\\t\\t\\t* @param runtimeOptions Options to override constructor options\\n\\t\\t\\t*/\\n\\t\\t\\textract(rootElement = document, runtimeOptions) {\\n\\t\\t\\t\\tconst startTime = Date.now();\\n\\t\\t\\t\\tconst doc = rootElement instanceof Document ? rootElement : rootElement.ownerDocument;\\n\\t\\t\\t\\tconst options = {\\n\\t\\t\\t\\t\\t...this.options,\\n\\t\\t\\t\\t\\t...runtimeOptions\\n\\t\\t\\t\\t};\\n\\t\\t\\t\\tlet container = rootElement instanceof Document ? doc : rootElement;\\n\\t\\t\\t\\tif (options.mainContentOnly && rootElement instanceof Document) container = ContentDetection.findMainContent(doc);\\n\\t\\t\\t\\tconst pageState = this.extractPageState(doc);\\n\\t\\t\\t\\tconst landmarks = this.extractLandmarks(doc);\\n\\t\\t\\t\\tconst interactive = this.extractInteractiveElements(container, options);\\n\\t\\t\\t\\tconst result = {\\n\\t\\t\\t\\t\\tmode: options.mode,\\n\\t\\t\\t\\t\\ttimestamp: startTime,\\n\\t\\t\\t\\t\\tpage: pageState,\\n\\t\\t\\t\\t\\tlandmarks,\\n\\t\\t\\t\\t\\tinteractive\\n\\t\\t\\t\\t};\\n\\t\\t\\t\\tif (options.mode === \\\"full\\\") {\\n\\t\\t\\t\\t\\tconst semantic = this.extractSemanticElements(container, options);\\n\\t\\t\\t\\t\\tconst metadata = this.extractMetadata(doc, container, options);\\n\\t\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\t\\t...result,\\n\\t\\t\\t\\t\\t\\tsemantic,\\n\\t\\t\\t\\t\\t\\tmetadata\\n\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn result;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Extract page state information\\n\\t\\t\\t*/\\n\\t\\t\\textractPageState(doc) {\\n\\t\\t\\t\\tconst hasFocus = this.getFocusedElement(doc);\\n\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\turl: doc.location?.href || \\\"\\\",\\n\\t\\t\\t\\t\\ttitle: doc.title || \\\"\\\",\\n\\t\\t\\t\\t\\thasErrors: this.detectErrors(doc),\\n\\t\\t\\t\\t\\tisLoading: this.detectLoading(doc),\\n\\t\\t\\t\\t\\thasModals: this.detectModals(doc),\\n\\t\\t\\t\\t\\t...hasFocus !== void 0 && { hasFocus }\\n\\t\\t\\t\\t};\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Extract page landmarks\\n\\t\\t\\t*/\\n\\t\\t\\textractLandmarks(doc) {\\n\\t\\t\\t\\tconst detected = ContentDetection.detectLandmarks(doc);\\n\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\tnavigation: this.elementsToSelectors(detected.navigation || []),\\n\\t\\t\\t\\t\\tmain: this.elementsToSelectors(detected.main || []),\\n\\t\\t\\t\\t\\tforms: this.elementsToSelectors(detected.form || []),\\n\\t\\t\\t\\t\\theaders: this.elementsToSelectors(detected.banner || []),\\n\\t\\t\\t\\t\\tfooters: this.elementsToSelectors(detected.contentinfo || []),\\n\\t\\t\\t\\t\\tarticles: this.elementsToSelectors(detected.region || []),\\n\\t\\t\\t\\t\\tsections: this.elementsToSelectors(detected.region || [])\\n\\t\\t\\t\\t};\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Convert elements to selector strings\\n\\t\\t\\t*/\\n\\t\\t\\telementsToSelectors(elements) {\\n\\t\\t\\t\\treturn elements.map((el) => SelectorGenerator.generateSelectors(el).css);\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Extract interactive elements\\n\\t\\t\\t*/\\n\\t\\t\\textractInteractiveElements(container, options) {\\n\\t\\t\\t\\tconst buttons = [];\\n\\t\\t\\t\\tconst links = [];\\n\\t\\t\\t\\tconst inputs = [];\\n\\t\\t\\t\\tconst clickable = [];\\n\\t\\t\\t\\tcontainer.querySelectorAll(\\\"button, [role=\\\\\\\"button\\\\\\\"], input[type=\\\\\\\"button\\\\\\\"], input[type=\\\\\\\"submit\\\\\\\"]\\\").forEach((el) => {\\n\\t\\t\\t\\t\\tif (this.shouldIncludeElement(el, options)) {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(el, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) buttons.push(extracted);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tcontainer.querySelectorAll(\\\"a[href]\\\").forEach((el) => {\\n\\t\\t\\t\\t\\tif (this.shouldIncludeElement(el, options)) {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(el, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) links.push(extracted);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tcontainer.querySelectorAll(\\\"input:not([type=\\\\\\\"button\\\\\\\"]):not([type=\\\\\\\"submit\\\\\\\"]), textarea, select\\\").forEach((el) => {\\n\\t\\t\\t\\t\\tif (this.shouldIncludeElement(el, options)) {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(el, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) inputs.push(extracted);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tif (options.customSelectors) options.customSelectors.forEach((selector) => {\\n\\t\\t\\t\\t\\tcontainer.querySelectorAll(selector).forEach((el) => {\\n\\t\\t\\t\\t\\t\\tif (this.shouldIncludeElement(el, options)) {\\n\\t\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(el, options);\\n\\t\\t\\t\\t\\t\\t\\tif (extracted) clickable.push(extracted);\\n\\t\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\tbuttons,\\n\\t\\t\\t\\t\\tlinks,\\n\\t\\t\\t\\t\\tinputs,\\n\\t\\t\\t\\t\\tforms: this.extractForms(container, options),\\n\\t\\t\\t\\t\\tclickable\\n\\t\\t\\t\\t};\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Extract form information\\n\\t\\t\\t*/\\n\\t\\t\\textractForms(container, options) {\\n\\t\\t\\t\\tconst forms = [];\\n\\t\\t\\t\\tcontainer.querySelectorAll(\\\"form\\\").forEach((form) => {\\n\\t\\t\\t\\t\\tif (!this.shouldIncludeElement(form, options)) return;\\n\\t\\t\\t\\t\\tconst formInputs = [];\\n\\t\\t\\t\\t\\tconst formButtons = [];\\n\\t\\t\\t\\t\\tform.querySelectorAll(\\\"input:not([type=\\\\\\\"button\\\\\\\"]):not([type=\\\\\\\"submit\\\\\\\"]), textarea, select\\\").forEach((input) => {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(input, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) formInputs.push(extracted);\\n\\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t\\tform.querySelectorAll(\\\"button, input[type=\\\\\\\"button\\\\\\\"], input[type=\\\\\\\"submit\\\\\\\"]\\\").forEach((button) => {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(button, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) formButtons.push(extracted);\\n\\t\\t\\t\\t\\t});\\n\\t\\t\\t\\t\\tconst action = form.getAttribute(\\\"action\\\");\\n\\t\\t\\t\\t\\tconst method = form.getAttribute(\\\"method\\\");\\n\\t\\t\\t\\t\\tconst formInfo = {\\n\\t\\t\\t\\t\\t\\tselector: SelectorGenerator.generateSelectors(form).css,\\n\\t\\t\\t\\t\\t\\tinputs: formInputs,\\n\\t\\t\\t\\t\\t\\tbuttons: formButtons\\n\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\tif (action) formInfo.action = action;\\n\\t\\t\\t\\t\\tif (method) formInfo.method = method;\\n\\t\\t\\t\\t\\tforms.push(formInfo);\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\treturn forms;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Extract semantic elements (full mode only)\\n\\t\\t\\t*/\\n\\t\\t\\textractSemanticElements(container, options) {\\n\\t\\t\\t\\tconst headings = [];\\n\\t\\t\\t\\tconst images = [];\\n\\t\\t\\t\\tconst tables = [];\\n\\t\\t\\t\\tconst lists = [];\\n\\t\\t\\t\\tconst articles = [];\\n\\t\\t\\t\\tcontainer.querySelectorAll(\\\"h1, h2, h3, h4, h5, h6\\\").forEach((el) => {\\n\\t\\t\\t\\t\\tif (this.shouldIncludeElement(el, options)) {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(el, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) headings.push(extracted);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tcontainer.querySelectorAll(\\\"img\\\").forEach((el) => {\\n\\t\\t\\t\\t\\tif (this.shouldIncludeElement(el, options)) {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(el, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) images.push(extracted);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tcontainer.querySelectorAll(\\\"table\\\").forEach((el) => {\\n\\t\\t\\t\\t\\tif (this.shouldIncludeElement(el, options)) {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(el, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) tables.push(extracted);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tcontainer.querySelectorAll(\\\"ul, ol\\\").forEach((el) => {\\n\\t\\t\\t\\t\\tif (this.shouldIncludeElement(el, options)) {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(el, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) lists.push(extracted);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\tcontainer.querySelectorAll(\\\"article, [role=\\\\\\\"article\\\\\\\"]\\\").forEach((el) => {\\n\\t\\t\\t\\t\\tif (this.shouldIncludeElement(el, options)) {\\n\\t\\t\\t\\t\\t\\tconst extracted = DOMTraversal.extractElement(el, options);\\n\\t\\t\\t\\t\\t\\tif (extracted) articles.push(extracted);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t});\\n\\t\\t\\t\\treturn {\\n\\t\\t\\t\\t\\theadings,\\n\\t\\t\\t\\t\\timages,\\n\\t\\t\\t\\t\\ttables,\\n\\t\\t\\t\\t\\tlists,\\n\\t\\t\\t\\t\\tarticles\\n\\t\\t\\t\\t};\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Extract metadata\\n\\t\\t\\t*/\\n\\t\\t\\textractMetadata(doc, container, options) {\\n\\t\\t\\t\\tconst allElements = container.querySelectorAll(\\\"*\\\");\\n\\t\\t\\t\\tconst extractedElements = container.querySelectorAll(\\\"button, a, input, textarea, select, h1, h2, h3, h4, h5, h6, img, table, ul, ol, article\\\").length;\\n\\t\\t\\t\\tconst metadata = {\\n\\t\\t\\t\\t\\ttotalElements: allElements.length,\\n\\t\\t\\t\\t\\textractedElements\\n\\t\\t\\t\\t};\\n\\t\\t\\t\\tif (options.mainContentOnly && container instanceof Element) metadata.mainContent = SelectorGenerator.generateSelectors(container).css;\\n\\t\\t\\t\\tconst language = doc.documentElement.getAttribute(\\\"lang\\\");\\n\\t\\t\\t\\tif (language) metadata.language = language;\\n\\t\\t\\t\\treturn metadata;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Check if element should be included based on options\\n\\t\\t\\t*/\\n\\t\\t\\tshouldIncludeElement(element, options) {\\n\\t\\t\\t\\tif (!options.includeHidden && !DOMTraversal.isVisible(element)) return false;\\n\\t\\t\\t\\tif (options.viewportOnly && !DOMTraversal.isInViewport(element)) return false;\\n\\t\\t\\t\\tif (options.filter && !DOMTraversal.passesFilter(element, options.filter)) return false;\\n\\t\\t\\t\\treturn true;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Detect errors on the page\\n\\t\\t\\t*/\\n\\t\\t\\tdetectErrors(doc) {\\n\\t\\t\\t\\treturn [\\n\\t\\t\\t\\t\\t\\\".error\\\",\\n\\t\\t\\t\\t\\t\\\".alert-danger\\\",\\n\\t\\t\\t\\t\\t\\\"[role=\\\\\\\"alert\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\t\\\".error-message\\\"\\n\\t\\t\\t\\t].some((sel) => {\\n\\t\\t\\t\\t\\tconst element = doc.querySelector(sel);\\n\\t\\t\\t\\t\\treturn element ? DOMTraversal.isVisible(element) : false;\\n\\t\\t\\t\\t});\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Detect if page is loading\\n\\t\\t\\t*/\\n\\t\\t\\tdetectLoading(doc) {\\n\\t\\t\\t\\treturn [\\n\\t\\t\\t\\t\\t\\\".loading\\\",\\n\\t\\t\\t\\t\\t\\\".spinner\\\",\\n\\t\\t\\t\\t\\t\\\"[aria-busy=\\\\\\\"true\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\t\\\".loader\\\"\\n\\t\\t\\t\\t].some((sel) => {\\n\\t\\t\\t\\t\\tconst element = doc.querySelector(sel);\\n\\t\\t\\t\\t\\treturn element ? DOMTraversal.isVisible(element) : false;\\n\\t\\t\\t\\t});\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Detect modal dialogs\\n\\t\\t\\t*/\\n\\t\\t\\tdetectModals(doc) {\\n\\t\\t\\t\\treturn [\\n\\t\\t\\t\\t\\t\\\"[role=\\\\\\\"dialog\\\\\\\"]\\\",\\n\\t\\t\\t\\t\\t\\\".modal\\\",\\n\\t\\t\\t\\t\\t\\\".popup\\\",\\n\\t\\t\\t\\t\\t\\\".overlay\\\"\\n\\t\\t\\t\\t].some((sel) => {\\n\\t\\t\\t\\t\\tconst element = doc.querySelector(sel);\\n\\t\\t\\t\\t\\treturn element ? DOMTraversal.isVisible(element) : false;\\n\\t\\t\\t\\t});\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Get currently focused element\\n\\t\\t\\t*/\\n\\t\\t\\tgetFocusedElement(doc) {\\n\\t\\t\\t\\tconst focused = doc.activeElement;\\n\\t\\t\\t\\tif (focused && focused !== doc.body) return SelectorGenerator.generateSelectors(focused).css;\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Quick extraction for interactive elements only\\n\\t\\t\\t* @param doc The document to extract from\\n\\t\\t\\t* @param options Extraction options\\n\\t\\t\\t*/\\n\\t\\t\\tstatic extractInteractive(doc, options = {}) {\\n\\t\\t\\t\\treturn new SmartDOMReader({\\n\\t\\t\\t\\t\\t...options,\\n\\t\\t\\t\\t\\tmode: \\\"interactive\\\"\\n\\t\\t\\t\\t}).extract(doc);\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Quick extraction for full content\\n\\t\\t\\t* @param doc The document to extract from\\n\\t\\t\\t* @param options Extraction options\\n\\t\\t\\t*/\\n\\t\\t\\tstatic extractFull(doc, options = {}) {\\n\\t\\t\\t\\treturn new SmartDOMReader({\\n\\t\\t\\t\\t\\t...options,\\n\\t\\t\\t\\t\\tmode: \\\"full\\\"\\n\\t\\t\\t\\t}).extract(doc);\\n\\t\\t\\t}\\n\\t\\t\\t/**\\n\\t\\t\\t* Extract from a specific element\\n\\t\\t\\t* @param element The element to extract from\\n\\t\\t\\t* @param mode The extraction mode\\n\\t\\t\\t* @param options Additional options\\n\\t\\t\\t*/\\n\\t\\t\\tstatic extractFromElement(element, mode = \\\"interactive\\\", options = {}) {\\n\\t\\t\\t\\treturn new SmartDOMReader({\\n\\t\\t\\t\\t\\t...options,\\n\\t\\t\\t\\t\\tmode\\n\\t\\t\\t\\t}).extract(element);\\n\\t\\t\\t}\\n\\t\\t};\\n\\t}));\\n\\t//#endregion\\n\\t//#region src/bundle-entry.ts\\n\\tinit_src();\\n\\tinit_markdown_formatter();\\n\\tinit_progressive();\\n\\tfunction executeExtraction(method, args) {\\n\\t\\ttry {\\n\\t\\t\\tlet result;\\n\\t\\t\\tswitch (method) {\\n\\t\\t\\t\\tcase \\\"extractStructure\\\": {\\n\\t\\t\\t\\t\\tconst { selector, frameSelector, formatOptions } = args;\\n\\t\\t\\t\\t\\tlet doc = document;\\n\\t\\t\\t\\t\\tif (frameSelector) {\\n\\t\\t\\t\\t\\t\\tconst iframe = document.querySelector(frameSelector);\\n\\t\\t\\t\\t\\t\\tif (!iframe || !(iframe instanceof HTMLIFrameElement) || !iframe.contentDocument) return { error: `Cannot access iframe: ${frameSelector}` };\\n\\t\\t\\t\\t\\t\\tdoc = iframe.contentDocument;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tconst target = selector ? doc.querySelector(selector) ?? doc : doc;\\n\\t\\t\\t\\t\\tconst overview = ProgressiveExtractor.extractStructure(target);\\n\\t\\t\\t\\t\\tconst meta = {\\n\\t\\t\\t\\t\\t\\ttitle: document.title,\\n\\t\\t\\t\\t\\t\\turl: location.href\\n\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\tresult = MarkdownFormatter.structure(overview, formatOptions ?? { detail: \\\"summary\\\" }, meta);\\n\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tcase \\\"extractRegion\\\": {\\n\\t\\t\\t\\t\\tconst { selector, mode, frameSelector, options, formatOptions } = args;\\n\\t\\t\\t\\t\\tlet doc = document;\\n\\t\\t\\t\\t\\tif (frameSelector) {\\n\\t\\t\\t\\t\\t\\tconst iframe = document.querySelector(frameSelector);\\n\\t\\t\\t\\t\\t\\tif (!iframe || !(iframe instanceof HTMLIFrameElement) || !iframe.contentDocument) return { error: `Cannot access iframe: ${frameSelector}` };\\n\\t\\t\\t\\t\\t\\tdoc = iframe.contentDocument;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tconst extractOptions = {\\n\\t\\t\\t\\t\\t\\t...options || {},\\n\\t\\t\\t\\t\\t\\tmode: mode || \\\"interactive\\\"\\n\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\tconst extractResult = ProgressiveExtractor.extractRegion(selector, doc, extractOptions, SmartDOMReader);\\n\\t\\t\\t\\t\\tif (!extractResult) return { error: `No element found matching selector: ${selector}` };\\n\\t\\t\\t\\t\\tconst meta = {\\n\\t\\t\\t\\t\\t\\ttitle: document.title,\\n\\t\\t\\t\\t\\t\\turl: location.href\\n\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\tresult = MarkdownFormatter.region(extractResult, formatOptions ?? { detail: \\\"region\\\" }, meta);\\n\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tcase \\\"extractContent\\\": {\\n\\t\\t\\t\\t\\tconst { selector, frameSelector, options, formatOptions } = args;\\n\\t\\t\\t\\t\\tlet doc = document;\\n\\t\\t\\t\\t\\tif (frameSelector) {\\n\\t\\t\\t\\t\\t\\tconst iframe = document.querySelector(frameSelector);\\n\\t\\t\\t\\t\\t\\tif (!iframe || !(iframe instanceof HTMLIFrameElement) || !iframe.contentDocument) return { error: `Cannot access iframe: ${frameSelector}` };\\n\\t\\t\\t\\t\\t\\tdoc = iframe.contentDocument;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tconst extractOptions = options || {};\\n\\t\\t\\t\\t\\tconst extractResult = ProgressiveExtractor.extractContent(selector, doc, extractOptions);\\n\\t\\t\\t\\t\\tif (!extractResult) return { error: `No element found matching selector: ${selector}` };\\n\\t\\t\\t\\t\\tconst meta = {\\n\\t\\t\\t\\t\\t\\ttitle: document.title,\\n\\t\\t\\t\\t\\t\\turl: location.href\\n\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\tresult = MarkdownFormatter.content(extractResult, formatOptions ?? { detail: \\\"region\\\" }, meta);\\n\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tcase \\\"extractInteractive\\\": {\\n\\t\\t\\t\\t\\tconst { selector, frameSelector, options, formatOptions } = args;\\n\\t\\t\\t\\t\\tlet doc = document;\\n\\t\\t\\t\\t\\tif (frameSelector) {\\n\\t\\t\\t\\t\\t\\tconst iframe = document.querySelector(frameSelector);\\n\\t\\t\\t\\t\\t\\tif (!iframe || !(iframe instanceof HTMLIFrameElement) || !iframe.contentDocument) return { error: `Cannot access iframe: ${frameSelector}` };\\n\\t\\t\\t\\t\\t\\tdoc = iframe.contentDocument;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tconst extractResult = selector ? SmartDOMReader.extractFromElement(doc.querySelector(selector), \\\"interactive\\\", options || {}) : SmartDOMReader.extractInteractive(doc, options || {});\\n\\t\\t\\t\\t\\tconst meta = {\\n\\t\\t\\t\\t\\t\\ttitle: document.title,\\n\\t\\t\\t\\t\\t\\turl: location.href\\n\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\tresult = MarkdownFormatter.region(extractResult, formatOptions ?? { detail: \\\"region\\\" }, meta);\\n\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tcase \\\"extractFull\\\": {\\n\\t\\t\\t\\t\\tconst { selector, frameSelector, options, formatOptions } = args;\\n\\t\\t\\t\\t\\tlet doc = document;\\n\\t\\t\\t\\t\\tif (frameSelector) {\\n\\t\\t\\t\\t\\t\\tconst iframe = document.querySelector(frameSelector);\\n\\t\\t\\t\\t\\t\\tif (!iframe || !(iframe instanceof HTMLIFrameElement) || !iframe.contentDocument) return { error: `Cannot access iframe: ${frameSelector}` };\\n\\t\\t\\t\\t\\t\\tdoc = iframe.contentDocument;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\tconst extractResult = selector ? SmartDOMReader.extractFromElement(doc.querySelector(selector), \\\"full\\\", options || {}) : SmartDOMReader.extractFull(doc, options || {});\\n\\t\\t\\t\\t\\tconst meta = {\\n\\t\\t\\t\\t\\t\\ttitle: document.title,\\n\\t\\t\\t\\t\\t\\turl: location.href\\n\\t\\t\\t\\t\\t};\\n\\t\\t\\t\\t\\tresult = MarkdownFormatter.region(extractResult, formatOptions ?? { detail: \\\"deep\\\" }, meta);\\n\\t\\t\\t\\t\\tbreak;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tdefault: return { error: `Unknown method: ${method}` };\\n\\t\\t\\t}\\n\\t\\t\\treturn result;\\n\\t\\t} catch (error) {\\n\\t\\t\\treturn { error: error instanceof Error ? error.message : String(error) };\\n\\t\\t}\\n\\t}\\n\\t//#endregion\\n\\texports.SmartDOMReaderBundle = { executeExtraction };\\n\\texports.executeExtraction = executeExtraction;\\n\\treturn exports;\\n})({});\\n\";\n\nexport const SMART_DOM_READER_VERSION = '1.0.0';\n"],"mappings":";;;;;;;;AAQA,MAAa,0BAA0B;AAEvC,MAAa,2BAA2B"}
|
|
@@ -253,8 +253,7 @@ declare global {
|
|
|
253
253
|
interface Window {
|
|
254
254
|
SmartDOMReaderBundle: SmartDOMReaderBundle;
|
|
255
255
|
}
|
|
256
|
-
}
|
|
257
|
-
//# sourceMappingURL=bundle-types.d.ts.map
|
|
256
|
+
} //# sourceMappingURL=bundle-types.d.ts.map
|
|
258
257
|
//#endregion
|
|
259
258
|
//#region src/content-detection.d.ts
|
|
260
259
|
declare class ContentDetection {
|
|
@@ -469,4 +468,4 @@ declare class SmartDOMReader {
|
|
|
469
468
|
}
|
|
470
469
|
//#endregion
|
|
471
470
|
export { ContentDetection, ContentExtractionOptions, ElementContext, ElementInteraction, ElementSelector, ElementSelectorCandidate, type ExtractContentArgs, type ExtractFullArgs, type ExtractInteractiveArgs, type ExtractRegionArgs, type ExtractStructureArgs, ExtractedContent, ExtractedElement, type ExtractionArgs, type ExtractionMethod, ExtractionMode, ExtractionOptions, type ExtractionResult, FilterOptions, FormInfo, type MarkdownFormatOptions, MarkdownFormatter, PageLandmarks, PageState, ProgressiveExtractor, RegionInfo, SelectorGenerator, SmartDOMReader, SmartDOMReader as default, SmartDOMResult, StructuralOverview };
|
|
472
|
-
//# sourceMappingURL=index.d.
|
|
471
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/markdown-formatter.ts","../src/bundle-types.ts","../src/content-detection.ts","../src/progressive.ts","../src/selectors.ts","../src/index.ts"],"mappings":";KAAY,cAAA;AAAA,UAEK,eAAA;EACf,GAAA;EACA,KAAA;EACA,SAAA;EACA,UAAA;EACA,SAAA;EAEA,UAAA,GAAa,wBAAA;AAAA;AAAA,UAGE,wBAAA;EACf,IAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,UAGe,cAAA;EACf,WAAA;EACA,cAAA;EACA,WAAA;EACA,UAAA;EACA,WAAA;AAAA;AAAA,UAGe,kBAAA;EAEf,KAAA;EACA,MAAA;EACA,MAAA;EACA,GAAA;EACA,QAAA;EACA,MAAA;EACA,IAAA;EACA,IAAA;AAAA;AAAA,UAGe,gBAAA;EACf,GAAA;EACA,IAAA;EACA,QAAA,EAAU,eAAA;EACV,UAAA,EAAY,MAAA;EACZ,OAAA,EAAS,cAAA;EACT,WAAA,EAAa,kBAAA;EAEb,QAAA,GAAW,gBAAA;AAAA;AAAA,UAGI,QAAA;EACf,QAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA,EAAQ,gBAAA;EACR,OAAA,EAAS,gBAAA;AAAA;AAAA,UAGM,aAAA;EACf,UAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA;EACA,OAAA;EACA,QAAA;EACA,QAAA;AAAA;AAAA,UAGe,SAAA;EACf,GAAA;EACA,KAAA;EACA,SAAA;EACA,SAAA;EACA,SAAA;EACA,QAAA;AAAA;AAAA,UAGe,cAAA;EACf,IAAA,EAAM,cAAA;EACN,SAAA;EACA,IAAA,EAAM,SAAA;EACN,SAAA,EAAW,aAAA;EACX,WAAA;IACE,OAAA,EAAS,gBAAA;IACT,KAAA,EAAO,gBAAA;IACP,MAAA,EAAQ,gBAAA;IACR,KAAA,EAAO,QAAA;IACP,SAAA,EAAW,gBAAA;EAAA;EAEb,QAAA;IACE,QAAA,EAAU,gBAAA;IACV,MAAA,EAAQ,gBAAA;IACR,MAAA,EAAQ,gBAAA;IACR,KAAA,EAAO,gBAAA;IACP,QAAA,EAAU,gBAAA;EAAA;EAEZ,QAAA;IACE,aAAA;IACA,iBAAA;IACA,WAAA;IACA,QAAA;EAAA;AAAA;AAAA,UAIa,aAAA;EAEf,gBAAA;EACA,gBAAA;EAGA,YAAA;EACA,WAAA,GAAc,MAAA;EAGd,aAAA;EACA,eAAA,GAAkB,MAAA,kBAAwB,MAAA;EAG1C,IAAA;EACA,gBAAA,GAAmB,KAAA,OAAY,kBAAA;EAG/B,eAAA;EACA,QAAA;AAAA;AAAA,UAGe,iBAAA;EACf,IAAA,EAAM,cAAA;EACN,QAAA;EACA,aAAA;EACA,gBAAA;EACA,cAAA;EACA,YAAA;EACA,eAAA;EACA,eAAA;EAGA,uBAAA;EACA,2BAAA;EACA,kBAAA;EAGA,MAAA,GAAS,aAAA;AAAA;AAAA,UAKM,UAAA;EACf,QAAA;EACA,KAAA;EACA,IAAA;EACA,gBAAA;EACA,OAAA;EACA,OAAA;EACA,QAAA;EACA,QAAA;EACA,WAAA;EACA,SAAA;EACA,UAAA;EACA,WAAA;AAAA;AAAA,UAGe,kBAAA;EACf,OAAA;IACE,MAAA,GAAS,UAAA;IACT,UAAA,GAAa,UAAA;IACb,IAAA,GAAO,UAAA;IACP,OAAA,GAAU,UAAA;IACV,MAAA,GAAS,UAAA;IACT,MAAA,GAAS,UAAA;IACT,QAAA,GAAW,UAAA;EAAA;EAEb,KAAA,EAAO,KAAA;IACL,QAAA;IACA,QAAA;IACA,UAAA;IACA,OAAA;EAAA;EAEF,OAAA;IACE,gBAAA;IACA,UAAA;IACA,aAAA;IACA,SAAA;IACA,SAAA;IACA,SAAA;IACA,mBAAA;EAAA;EAEF,WAAA;AAAA;AAAA,UAGe,wBAAA;EACf,eAAA;EACA,YAAA;EACA,aAAA;EACA,YAAA;EACA,kBAAA;EACA,aAAA;AAAA;AAAA,UAGe,gBAAA;EACf,QAAA;EACA,IAAA;IACE,QAAA,GAAW,KAAA;MAAQ,KAAA;MAAe,IAAA;IAAA;IAClC,UAAA;IACA,KAAA,GAAQ,KAAA;MAAQ,IAAA;MAAmB,KAAA;IAAA;EAAA;EAErC,MAAA,GAAS,KAAA;IACP,OAAA;IACA,IAAA;EAAA;EAEF,KAAA,GAAQ,KAAA;IACN,IAAA;IACA,GAAA;IACA,GAAA;EAAA;EAEF,QAAA;IACE,SAAA;IACA,cAAA;EAAA;AAAA;;;KChNQ,mBAAA;AAAA,UAEK,qBAAA;EACf,MAAA,GAAS,mBAAA;EACT,aAAA;EACA,WAAA;AAAA;AAAA,KAGG,QAAA;EAAa,KAAA;EAAgB,GAAA;AAAA;AAAA,cAqKrB,iBAAA;EAAA,OACJ,SAAA,CACL,QAAA,EAAU,kBAAA,EACV,KAAA,GAAO,qBAAA,EACP,IAAA,GAAO,QAAA;EAAA,OAkDF,MAAA,CAAO,MAAA,EAAQ,cAAA,EAAgB,IAAA,GAAM,qBAAA,EAA4B,IAAA,GAAO,QAAA;EAAA,OAwCxE,OAAA,CACL,OAAA,EAAS,gBAAA,EACT,IAAA,GAAM,qBAAA,EACN,IAAA,GAAO,QAAA;AAAA;;;KC/QC,gBAAA;AAAA,UAOK,kBAAA;EACf,aAAA;EACA,aAAA,GAAgB,qBAAA;AAAA;AAAA,UAGD,oBAAA,SAA6B,kBAAA;EAC5C,QAAA;AAAA;AAAA,UAGe,iBAAA,SAA0B,kBAAA;EACzC,QAAA;EACA,IAAA;EACA,OAAA,GAAU,OAAA,CAAQ,iBAAA;AAAA;AAAA,UAGH,kBAAA,SAA2B,kBAAA;EAC1C,QAAA;EACA,OAAA,GAAU,wBAAA;AAAA;AAAA,UAGK,sBAAA,SAA+B,kBAAA;EAC9C,QAAA;EACA,OAAA,GAAU,OAAA,CAAQ,iBAAA;AAAA;AAAA,UAGH,eAAA,SAAwB,kBAAA;EACvC,QAAA;EACA,OAAA,GAAU,OAAA,CAAQ,iBAAA;AAAA;AAAA,KAGR,cAAA;EACV,gBAAA,EAAkB,oBAAA;EAClB,aAAA,EAAe,iBAAA;EACf,cAAA,EAAgB,kBAAA;EAChB,kBAAA,EAAoB,sBAAA;EACpB,WAAA,EAAa,eAAA;AAAA;AAAA,UAGE,eAAA;EACf,KAAA;AAAA;AAAA,KAGU,gBAAA,YAA4B,eAAA;AAAA,UAEvB,oBAAA;EACf,iBAAA,WAA4B,gBAAA,EAC1B,MAAA,EAAQ,CAAA,EACR,IAAA,EAAM,cAAA,CAAe,CAAA,IACpB,gBAAA;AAAA;AAAA,QAGG,MAAA;EAAA,UACI,MAAA;IACR,oBAAA,EAAsB,oBAAA;EAAA;AAAA;;;cCnEb,gBAAA;EHAD;;;;EAAA,OGKH,eAAA,CAAgB,GAAA,EAAK,QAAA,GAAW,OAAA;EHHxB;;;EAAA,eGqBA,iBAAA;EHpBf;;;EAAA,eG0De,iBAAA;EHtDf;;;EAAA,OGyEO,qBAAA,CAAsB,OAAA,EAAS,OAAA;EHvED;AAGvC;;EAHuC,eGqKtB,oBAAA;EHlKwB;;;EAAA,OGiLhC,YAAA,CAAa,OAAA,EAAS,OAAA;EH9KxB;;AAGP;EAHO,OGgME,eAAA,CAAgB,OAAA,EAAS,OAAA;;;;SAkBzB,eAAA,CAAgB,GAAA,EAAK,QAAA,GAAW,MAAA,SAAe,OAAA;AAAA;;;KCnNnD,kBAAA,QAA0B,OAAA,GAAU,OAAA,CAAQ,iBAAA,MAAuB,cAAA;AAAA,cAuC3D,oBAAA;EJrDa;;AAE1B;;EAF0B,OI0DjB,gBAAA,CAAiB,IAAA,EAAM,QAAA,GAAW,OAAA,GAAU,kBAAA;EJjDd;;;EAAA,OI4H9B,aAAA,CACL,QAAA,UACA,GAAA,EAAK,QAAA,EACL,OAAA,GAAS,OAAA,CAAQ,iBAAA,GACjB,kBAAA,GAAqB,kBAAA,GACpB,cAAA;EJpIH;;;EAAA,OIuJO,cAAA,CACL,QAAA,UACA,GAAA,EAAK,QAAA,EACL,OAAA,GAAS,wBAAA,GACR,gBAAA;EJxJkC;;AAGvC;EAHuC,eI6PtB,aAAA;;;;iBA8DA,mBAAA;EJrTf;;;EAAA,eIoXe,gBAAA;EJjXc;;;EAAA,eI4Zd,mBAAA;EJ1Zf;;;EAAA,eIgce,cAAA;AAAA;;;cCldJ,iBAAA;ELFa;;;EAAA,OKMjB,iBAAA,CAAkB,OAAA,EAAS,OAAA,GAAU,eAAA;ELJ7B;;;EAAA,eKoFA,mBAAA;ELnFf;;;EAAA,eKsIe,aAAA;ELlIf;;;EAAA,eK0Ke,yBAAA;ELxKsB;AAGvC;;EAHuC,eKyLtB,aAAA;ELtLwB;;;EAAA,eKmMxB,UAAA;ELhMV;;AAGP;EAHO,eKuMU,gBAAA;EAAA,eAQA,oBAAA;EL5Mc;;;EAAA,eKuNd,oBAAA;ELnNf;;;EAAA,eK4Oe,YAAA;ELxOA;;;EAAA,OK4PR,cAAA,CAAe,OAAA,EAAS,OAAA;AAAA;;;;;;;;;;;;;;;AL1QjC;cM+Ba,cAAA;EAAA,QACH,OAAA;cAEI,OAAA,GAAS,OAAA,CAAQ,iBAAA;ENjC7B;;;;;EM6DA,OAAA,CACE,WAAA,GAAa,QAAA,GAAW,OAAA,EACxB,cAAA,GAAiB,OAAA,CAAQ,iBAAA,IACxB,cAAA;EN3D0B;;;EAAA,QMgHrB,gBAAA;EN9GR;;;EAAA,QM6HQ,gBAAA;EN1HG;;AAGb;EAHa,QM0IH,mBAAA;;;;UAOA,0BAAA;EN1IR;;;EAAA,QM8MQ,YAAA;EN1MR;;;EAAA,QMsPQ,uBAAA;ENlPO;;;EAAA,QMgTP,eAAA;EN5SI;;;EAAA,QM0UJ,oBAAA;ENtUmB;;;EAAA,QM4VnB,YAAA;ENjWR;;;EAAA,QM4WQ,aAAA;EN1WR;;;EAAA,QMqXQ,YAAA;ENlXR;;;EAAA,QM6XQ,iBAAA;EN1XO;;;;;EAAA,OMyYR,kBAAA,CACL,GAAA,EAAK,QAAA,EACL,OAAA,GAAS,OAAA,CAAQ,iBAAA,IAChB,cAAA;ENzYH;;;;;EAAA,OMsZO,WAAA,CAAY,GAAA,EAAK,QAAA,EAAU,OAAA,GAAS,OAAA,CAAQ,iBAAA,IAA0B,cAAA;ENpZpD;AAG3B;;;;;EAH2B,OMkalB,kBAAA,CACL,OAAA,EAAS,OAAA,EACT,IAAA,GAAM,cAAA,EACN,OAAA,GAAS,OAAA,CAAQ,iBAAA,IAChB,cAAA;AAAA"}
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
|
|
3
|
-
//#region rolldown:runtime
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
4
3
|
var __defProp = Object.defineProperty;
|
|
5
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
var __export = (all) => {
|
|
7
|
+
var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
8
|
+
var __exportAll = (all, no_symbols) => {
|
|
12
9
|
let target = {};
|
|
13
10
|
for (var name in all) __defProp(target, name, {
|
|
14
11
|
get: all[name],
|
|
15
12
|
enumerable: true
|
|
16
13
|
});
|
|
14
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
17
15
|
return target;
|
|
18
16
|
};
|
|
19
17
|
var __copyProps = (to, from, except, desc) => {
|
|
@@ -26,13 +24,12 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
26
24
|
}
|
|
27
25
|
return to;
|
|
28
26
|
};
|
|
29
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
28
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
31
|
-
|
|
32
29
|
//#endregion
|
|
33
30
|
//#region src/content-detection.ts
|
|
34
31
|
var ContentDetection;
|
|
35
|
-
var init_content_detection =
|
|
32
|
+
var init_content_detection = __esmMin((() => {
|
|
36
33
|
ContentDetection = class ContentDetection {
|
|
37
34
|
/**
|
|
38
35
|
* Find the main content area of a page
|
|
@@ -186,12 +183,11 @@ var init_content_detection = __esm({ "src/content-detection.ts": (() => {
|
|
|
186
183
|
return landmarks;
|
|
187
184
|
}
|
|
188
185
|
};
|
|
189
|
-
})
|
|
190
|
-
|
|
186
|
+
}));
|
|
191
187
|
//#endregion
|
|
192
188
|
//#region src/selectors.ts
|
|
193
189
|
var SelectorGenerator;
|
|
194
|
-
var init_selectors =
|
|
190
|
+
var init_selectors = __esmMin((() => {
|
|
195
191
|
SelectorGenerator = class SelectorGenerator {
|
|
196
192
|
/**
|
|
197
193
|
* Generate multiple selector strategies for an element
|
|
@@ -417,12 +413,11 @@ var init_selectors = __esm({ "src/selectors.ts": (() => {
|
|
|
417
413
|
return path;
|
|
418
414
|
}
|
|
419
415
|
};
|
|
420
|
-
})
|
|
421
|
-
|
|
416
|
+
}));
|
|
422
417
|
//#endregion
|
|
423
418
|
//#region src/traversal.ts
|
|
424
419
|
var DOMTraversal;
|
|
425
|
-
var init_traversal =
|
|
420
|
+
var init_traversal = __esmMin((() => {
|
|
426
421
|
init_selectors();
|
|
427
422
|
DOMTraversal = class DOMTraversal {
|
|
428
423
|
static INTERACTIVE_SELECTORS = [
|
|
@@ -742,8 +737,7 @@ var init_traversal = __esm({ "src/traversal.ts": (() => {
|
|
|
742
737
|
return elements;
|
|
743
738
|
}
|
|
744
739
|
};
|
|
745
|
-
})
|
|
746
|
-
|
|
740
|
+
}));
|
|
747
741
|
//#endregion
|
|
748
742
|
//#region src/markdown-formatter.ts
|
|
749
743
|
function truncate(text, len) {
|
|
@@ -865,7 +859,7 @@ function capitalize(s) {
|
|
|
865
859
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
866
860
|
}
|
|
867
861
|
var MarkdownFormatter;
|
|
868
|
-
var init_markdown_formatter =
|
|
862
|
+
var init_markdown_formatter = __esmMin((() => {
|
|
869
863
|
MarkdownFormatter = class {
|
|
870
864
|
static structure(overview, _opts = {}, meta) {
|
|
871
865
|
const lines = [];
|
|
@@ -981,8 +975,7 @@ var init_markdown_formatter = __esm({ "src/markdown-formatter.ts": (() => {
|
|
|
981
975
|
return wrapXml(lines.join("\n"), meta, "content");
|
|
982
976
|
}
|
|
983
977
|
};
|
|
984
|
-
})
|
|
985
|
-
|
|
978
|
+
}));
|
|
986
979
|
//#endregion
|
|
987
980
|
//#region src/progressive.ts
|
|
988
981
|
function resolveSmartDomReader() {
|
|
@@ -1002,7 +995,7 @@ function resolveSmartDomReader() {
|
|
|
1002
995
|
} catch {}
|
|
1003
996
|
}
|
|
1004
997
|
var ProgressiveExtractor;
|
|
1005
|
-
var init_progressive =
|
|
998
|
+
var init_progressive = __esmMin((() => {
|
|
1006
999
|
init_content_detection();
|
|
1007
1000
|
init_selectors();
|
|
1008
1001
|
init_traversal();
|
|
@@ -1263,24 +1256,22 @@ var init_progressive = __esm({ "src/progressive.ts": (() => {
|
|
|
1263
1256
|
return text;
|
|
1264
1257
|
}
|
|
1265
1258
|
};
|
|
1266
|
-
})
|
|
1267
|
-
|
|
1259
|
+
}));
|
|
1268
1260
|
//#endregion
|
|
1269
1261
|
//#region src/types.ts
|
|
1270
|
-
var init_types =
|
|
1271
|
-
|
|
1262
|
+
var init_types = __esmMin((() => {}));
|
|
1272
1263
|
//#endregion
|
|
1273
1264
|
//#region src/index.ts
|
|
1274
|
-
var src_exports = /* @__PURE__ */
|
|
1265
|
+
var src_exports = /* @__PURE__ */ __exportAll({
|
|
1275
1266
|
ContentDetection: () => ContentDetection,
|
|
1276
1267
|
MarkdownFormatter: () => MarkdownFormatter,
|
|
1277
1268
|
ProgressiveExtractor: () => ProgressiveExtractor,
|
|
1278
1269
|
SelectorGenerator: () => SelectorGenerator,
|
|
1279
1270
|
SmartDOMReader: () => SmartDOMReader,
|
|
1280
|
-
default: () =>
|
|
1271
|
+
default: () => SmartDOMReader
|
|
1281
1272
|
});
|
|
1282
|
-
var SmartDOMReader
|
|
1283
|
-
var init_src =
|
|
1273
|
+
var SmartDOMReader;
|
|
1274
|
+
var init_src = __esmMin((() => {
|
|
1284
1275
|
init_content_detection();
|
|
1285
1276
|
init_selectors();
|
|
1286
1277
|
init_traversal();
|
|
@@ -1602,10 +1593,9 @@ var init_src = __esm({ "src/index.ts": (() => {
|
|
|
1602
1593
|
}).extract(element);
|
|
1603
1594
|
}
|
|
1604
1595
|
};
|
|
1605
|
-
|
|
1606
|
-
}) });
|
|
1607
|
-
|
|
1596
|
+
}));
|
|
1608
1597
|
//#endregion
|
|
1609
1598
|
init_src();
|
|
1610
|
-
export { ContentDetection, MarkdownFormatter, ProgressiveExtractor, SelectorGenerator, SmartDOMReader,
|
|
1611
|
-
|
|
1599
|
+
export { ContentDetection, MarkdownFormatter, ProgressiveExtractor, SelectorGenerator, SmartDOMReader, SmartDOMReader as default };
|
|
1600
|
+
|
|
1601
|
+
//# sourceMappingURL=index.mjs.map
|