@mcp-b/smart-dom-reader 5.0.2 → 5.0.3
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/dist/bundle-string.d.mts +2 -2
- package/dist/bundle-string.mjs +2 -2
- package/dist/bundle-string.mjs.map +1 -1
- package/dist/index.d.mts +0 -1
- package/dist/index.mjs +29 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/content-detection.ts","../src/markdown-formatter.ts","../src/selectors.ts","../src/traversal.ts","../src/smart-dom-reader.ts","../src/progressive.ts"],"sourcesContent":["export 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: Document): Element {\n // First, check for explicit main element\n const mainElement = doc.querySelector('main, [role=\"main\"]');\n if (mainElement) {\n return mainElement;\n }\n\n // If no explicit main, detect it\n if (!doc.body) {\n return doc.documentElement;\n }\n\n return ContentDetection.detectMainContent(doc.body);\n }\n\n /**\n * Detect main content using scoring algorithm\n */\n private static detectMainContent(rootElement: Element): Element {\n const candidates: Element[] = [];\n const minScore = 15;\n\n ContentDetection.collectCandidates(rootElement, candidates, minScore);\n\n if (candidates.length === 0) {\n return rootElement;\n }\n\n // Sort by score\n candidates.sort(\n (a, b) =>\n ContentDetection.calculateContentScore(b) - ContentDetection.calculateContentScore(a)\n );\n\n // Find best independent candidate\n let bestCandidate = candidates[0]!;\n for (let i = 1; i < candidates.length; i++) {\n const candidate = candidates[i]!;\n // Check if this candidate is not contained in any other\n const isIndependent = !candidates.some((other, j) => j !== i && other.contains(candidate));\n\n if (\n isIndependent &&\n ContentDetection.calculateContentScore(candidate) >\n ContentDetection.calculateContentScore(bestCandidate)\n ) {\n bestCandidate = candidate;\n }\n }\n\n return bestCandidate;\n }\n\n /**\n * Collect content candidates\n */\n private static collectCandidates(\n element: Element,\n candidates: Element[],\n minScore: number\n ): void {\n const score = ContentDetection.calculateContentScore(element);\n if (score >= minScore) {\n candidates.push(element);\n }\n\n // Recursively check children\n Array.from(element.children).forEach((child) => {\n ContentDetection.collectCandidates(child, candidates, minScore);\n });\n }\n\n /**\n * Calculate content score for an element\n */\n static calculateContentScore(element: Element): number {\n let score = 0;\n\n // High impact semantic indicators\n const semanticClasses = [\n 'article',\n 'content',\n 'main-container',\n 'main',\n 'main-content',\n 'post',\n 'entry',\n ];\n const semanticIds = ['content', 'main', 'article', 'post', 'entry'];\n\n // Check classes\n semanticClasses.forEach((cls) => {\n if (element.classList.contains(cls)) {\n score += 10;\n }\n });\n\n // Check ID\n semanticIds.forEach((id) => {\n if (element.id?.toLowerCase().includes(id)) {\n score += 10;\n }\n });\n\n // High value tags\n const tag = element.tagName.toLowerCase();\n const highValueTags = ['article', 'main', 'section'];\n if (highValueTags.includes(tag)) {\n score += 8;\n }\n\n // Paragraph density\n const paragraphs = element.getElementsByTagName('p').length;\n score += Math.min(paragraphs * 2, 10);\n\n // Heading presence\n const headings = element.querySelectorAll('h1, h2, h3').length;\n score += Math.min(headings * 3, 9);\n\n // Text content length\n const textLength = element.textContent?.trim().length || 0;\n if (textLength > 300) {\n score += Math.min(Math.floor(textLength / 300) * 2, 10);\n }\n\n // Link density (lower is better for content)\n const linkDensity = ContentDetection.calculateLinkDensity(element);\n if (linkDensity < 0.3) {\n score += 5;\n } else if (linkDensity > 0.5) {\n score -= 5;\n }\n\n // Data attributes\n if (\n element.hasAttribute('data-main') ||\n element.hasAttribute('data-content') ||\n element.hasAttribute('itemprop')\n ) {\n score += 8;\n }\n\n // ARIA landmarks\n const role = element.getAttribute('role');\n if (role === 'main' || role === 'article') {\n score += 10;\n }\n\n // Penalize certain elements\n if (\n element.matches(\n 'aside, nav, header, footer, .sidebar, .navigation, .menu, .ad, .advertisement'\n )\n ) {\n score -= 10;\n }\n\n // Check for form density (forms are usually not main content)\n const forms = element.getElementsByTagName('form').length;\n if (forms > 2) {\n score -= 5;\n }\n\n return Math.max(0, score);\n }\n\n /**\n * Calculate link density in an element\n */\n private static calculateLinkDensity(element: Element): number {\n const links = element.getElementsByTagName('a');\n let linkTextLength = 0;\n\n for (const link of Array.from(links)) {\n linkTextLength += link.textContent?.length || 0;\n }\n\n const totalTextLength = element.textContent?.length || 1;\n return linkTextLength / totalTextLength;\n }\n\n /**\n * Check if an element is likely navigation\n */\n static isNavigation(element: Element): boolean {\n const tag = element.tagName.toLowerCase();\n\n // Explicit navigation elements\n if (tag === 'nav' || element.getAttribute('role') === 'navigation') {\n return true;\n }\n\n // Check for navigation patterns\n const navPatterns = [/nav/i, /menu/i, /sidebar/i, /toolbar/i];\n\n const classesAndId = `${element.className} ${element.id}`.toLowerCase();\n return navPatterns.some((pattern) => pattern.test(classesAndId));\n }\n\n /**\n * Check if element is likely supplementary content\n */\n static isSupplementary(element: Element): boolean {\n const tag = element.tagName.toLowerCase();\n\n // Explicit supplementary elements\n if (tag === 'aside' || element.getAttribute('role') === 'complementary') {\n return true;\n }\n\n // Check for supplementary patterns\n const supplementaryPatterns = [/sidebar/i, /widget/i, /related/i, /advertisement/i, /social/i];\n\n const classesAndId = `${element.className} ${element.id}`.toLowerCase();\n return supplementaryPatterns.some((pattern) => pattern.test(classesAndId));\n }\n\n /**\n * Detect page landmarks\n */\n static detectLandmarks(doc: Document): Record<string, Element[]> {\n const landmarks: Record<string, Element[]> = {\n navigation: [],\n main: [],\n complementary: [],\n contentinfo: [],\n banner: [],\n search: [],\n form: [],\n region: [],\n };\n\n // Find explicit landmarks\n const landmarkSelectors = {\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\n for (const [landmark, selector] of Object.entries(landmarkSelectors)) {\n const elements = doc.querySelectorAll(selector);\n landmarks[landmark] = Array.from(elements);\n }\n\n return landmarks;\n }\n}\n","import type {\n ExtractedContent,\n ExtractedElement,\n RegionInfo,\n SmartDOMResult,\n StructuralOverview,\n} from './types';\n\nexport type MarkdownDetailLevel = 'summary' | 'region' | 'deep';\n\nexport interface MarkdownFormatOptions {\n detail?: MarkdownDetailLevel;\n maxTextLength?: number;\n maxElements?: number;\n}\n\ntype PageMeta = { title?: string; url?: string };\n\nfunction truncate(text: string | undefined, len?: number): string {\n const t = (text ?? '').trim();\n if (!len || t.length <= len) return t;\n\n // Smart truncation: keep start and preserve key action words if present\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) => ({ k, i: lower.indexOf(k) })).find((x) => x.i > -1);\n const head = Math.max(0, Math.floor(len * 0.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 // Default: simple head truncation on word boundary\n const slice = t.slice(0, len);\n const lastSpace = slice.lastIndexOf(' ');\n return `${lastSpace > 32 ? slice.slice(0, lastSpace) : slice}…`;\n}\n\nfunction hashId(input: string): string {\n let h = 5381;\n for (let i = 0; i < input.length; i++) h = (h * 33) ^ input.charCodeAt(i);\n // Convert to unsigned and base36 for compactness\n return `sec-${(h >>> 0).toString(36)}`;\n}\n\nfunction iconForRegion(key: string): string {\n switch (key) {\n case 'header':\n return '🧭';\n case 'navigation':\n return '📑';\n case 'main':\n return '📄';\n case 'sections':\n return '🗂️';\n case 'sidebar':\n return '📚';\n case 'footer':\n return '🔻';\n case 'modals':\n return '💬';\n default:\n return '🔹';\n }\n}\n\nfunction elementLine(el: ExtractedElement, opts?: MarkdownFormatOptions): string {\n const txt = truncate(el.text || el.attributes?.ariaLabel, opts?.maxTextLength ?? 80);\n const sel = el.selector?.css || '';\n const tag = el.tag.toLowerCase();\n const action = el.interaction?.submit\n ? 'submit'\n : el.interaction?.click\n ? 'click'\n : el.interaction?.change\n ? 'change'\n : undefined;\n const actionText = action ? ` (${action})` : '';\n return `- ${tag.toUpperCase()}: ${txt || '(no text)'} → \\`${sel}\\`${actionText}`;\n}\n\nfunction selectorQualitySummary(inter: SmartDOMResult['interactive']): string {\n const all: string[] = [];\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 const stablePct = Math.round((stable / total) * 100);\n const nthPct = Math.round((nthCount / total) * 100);\n return `Selector quality: ${stablePct}% stable (ID/data-testid), ${nthPct}% structural (:nth-child)`;\n}\n\nfunction renderInteractive(\n inter: SmartDOMResult['interactive'],\n opts?: MarkdownFormatOptions\n): string {\n const parts: string[] = [];\n\n const limit = <T>(arr: T[]) =>\n typeof opts?.maxElements === 'number' ? arr.slice(0, opts.maxElements) : arr;\n\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)) {\n parts.push(`- FORM: action=${f.action ?? '-'} method=${f.method ?? '-'} → \\`${f.selector}\\``);\n }\n }\n\n return parts.join('\\n');\n}\n\nfunction renderRegionInfo(region: RegionInfo): string {\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: string[] = [];\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\nfunction wrapXml(body: string, meta?: PageMeta, type = 'section'): string {\n const attrs = [\n meta?.title ? `title=\"${escapeXml(meta.title)}\"` : null,\n meta?.url ? `url=\"${escapeXml(meta.url)}\"` : null,\n ]\n .filter(Boolean)\n .join(' ');\n return `<page ${attrs}>\\n <${type}><![CDATA[\\n${body}\\n]]></${type}>\\n</page>`;\n}\n\nfunction escapeXml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nexport class MarkdownFormatter {\n static structure(\n overview: StructuralOverview,\n _opts: MarkdownFormatOptions = {},\n meta?: PageMeta\n ): string {\n const lines: string[] = [];\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\n const regions = overview.regions;\n const entries: Array<[string, RegionInfo | RegionInfo[] | undefined]> = [\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\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\n // Suggestions\n if (overview.suggestions?.length) {\n lines.push('## Suggestions');\n for (const s of overview.suggestions) lines.push(`- ${s}`);\n lines.push('');\n }\n\n lines.push(\n 'Next: choose a region (by selector or [sectionId]) and call dom_extract_region for actionable details.'\n );\n\n const body = lines.join('\\n');\n return wrapXml(body, meta, 'outline');\n }\n\n static region(result: SmartDOMResult, opts: MarkdownFormatOptions = {}, meta?: PageMeta): string {\n const lines: string[] = [];\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\n const inter = result.interactive;\n // Page state diagnostics if available\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\n const summary: string[] = [];\n const count = (arr: unknown[]) => (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\n lines.push(renderInteractive(inter, opts));\n lines.push('');\n lines.push(\n '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 );\n\n const body = lines.join('\\n');\n return wrapXml(body, meta, 'section');\n }\n\n static content(\n content: ExtractedContent,\n opts: MarkdownFormatOptions = {},\n meta?: PageMeta\n ): string {\n const lines: string[] = [];\n lines.push('# Content');\n lines.push(`Selector: \\`${content.selector}\\``);\n lines.push('');\n\n if (content.text.headings?.length) {\n lines.push('Headings:');\n for (const h of content.text.headings)\n lines.push(`- H${h.level}: ${truncate(h.text, opts.maxTextLength ?? 120)}`);\n lines.push('');\n }\n if (content.text.paragraphs?.length) {\n const limit =\n 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))\n 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))\n lines.push(` - ${truncate(item, opts.maxTextLength ?? 120)}`);\n }\n lines.push('');\n }\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\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)) {\n lines.push(`- ${m.type.toUpperCase()}: ${m.alt ?? ''} ${m.src ? `→ ${m.src}` : ''}`.trim());\n }\n lines.push('');\n }\n\n lines.push(\n 'Next: if text is insufficient for targeting, call dom_extract_region for interactive selectors.'\n );\n\n const body = lines.join('\\n');\n return wrapXml(body, meta, 'content');\n }\n}\n\nfunction capitalize(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n","import type { ElementSelector, ElementSelectorCandidate } from './types';\n\nexport class SelectorGenerator {\n /**\n * Generate multiple selector strategies for an element\n */\n static generateSelectors(element: Element): ElementSelector {\n const doc = element.ownerDocument || document;\n const candidates: ElementSelectorCandidate[] = [];\n\n // 1) Unique ID\n if (element.id && SelectorGenerator.isUniqueId(element.id, doc)) {\n candidates.push({ type: 'id', value: `#${CSS.escape(element.id)}`, score: 100 });\n }\n\n // 2) data-testid variants\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\n // 3) role + aria-label\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\n // 4) name attribute (useful for inputs)\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\n // 5) Class-based CSS path (try to avoid structural :nth-child when possible)\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({ type: 'class-path', value: pathCss, score: pathScore });\n\n // 6) XPath (fallback)\n const xpath = SelectorGenerator.generateXPath(element, doc);\n candidates.push({ type: 'xpath', value: xpath, score: 40 });\n\n // 7) Text-based (only for hints)\n const textBased = SelectorGenerator.generateTextBasedSelector(element);\n if (textBased) candidates.push({ type: 'text', value: textBased, score: 30 });\n\n // Rank candidates by score (desc)\n candidates.sort((a, b) => b.score - a.score);\n\n const bestCss =\n candidates.find((c) => c.type !== 'xpath' && c.type !== 'text')?.value || pathCss;\n\n const selector: ElementSelector = {\n css: bestCss,\n xpath,\n candidates,\n };\n\n if (textBased) selector.textBased = textBased;\n if (testId) selector.dataTestId = testId;\n if (aria) selector.ariaLabel = aria;\n\n return selector;\n }\n\n /**\n * Generate a unique CSS selector for an element\n */\n private static generateCSSSelector(element: Element, doc: Document): string {\n // If element has a unique ID, use it\n if (element.id && SelectorGenerator.isUniqueId(element.id, doc)) {\n return `#${CSS.escape(element.id)}`;\n }\n\n // Try data-testid or data-test-id\n const testId = SelectorGenerator.getDataTestId(element);\n if (testId) {\n return `[data-testid=\"${CSS.escape(testId)}\"]`;\n }\n\n // Build a path from the element to the root\n const path: string[] = [];\n let current: Element | null = element;\n\n while (current && current.nodeType === Node.ELEMENT_NODE) {\n let selector = current.nodeName.toLowerCase();\n\n if (current.id && SelectorGenerator.isUniqueId(current.id, doc)) {\n selector = `#${CSS.escape(current.id)}`;\n path.unshift(selector);\n break;\n }\n\n // Add classes if they exist and are meaningful\n const classes = SelectorGenerator.getMeaningfulClasses(current);\n if (classes.length > 0) {\n selector += `.${classes.map((c) => CSS.escape(c)).join('.')}`;\n }\n\n // Add position if needed for uniqueness\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!)) {\n selector += `:nth-child(${index + 1})`;\n }\n }\n\n path.unshift(selector);\n current = current.parentElement;\n }\n\n // Optimize the path\n return SelectorGenerator.optimizePath(path, element, doc);\n }\n\n /**\n * Generate XPath for an element\n */\n private static generateXPath(element: Element, doc: Document): string {\n if (element.id && SelectorGenerator.isUniqueId(element.id, doc)) {\n return `//*[@id=\"${element.id}\"]`;\n }\n\n const path: string[] = [];\n let current: Element | null = element;\n\n while (current && current.nodeType === Node.ELEMENT_NODE) {\n const tagName = current.nodeName.toLowerCase();\n\n if (current.id && SelectorGenerator.isUniqueId(current.id, doc)) {\n path.unshift(`//*[@id=\"${current.id}\"]`);\n break;\n }\n\n let xpath = tagName;\n\n // Add index if there are siblings with same tag\n const siblings = current.parentElement?.children;\n if (siblings) {\n const sameTagSiblings = Array.from(siblings).filter(\n (s) => s.nodeName.toLowerCase() === tagName\n );\n if (sameTagSiblings.length > 1) {\n const index = sameTagSiblings.indexOf(current) + 1;\n xpath += `[${index}]`;\n }\n }\n\n path.unshift(xpath);\n current = current.parentElement;\n }\n\n return `//${path.join('/')}`;\n }\n\n /**\n * Generate a text-based selector for buttons and links\n */\n private static generateTextBasedSelector(element: Element): string | undefined {\n const text = element.textContent?.trim();\n if (!text || text.length > 50) return undefined;\n\n const tag = element.nodeName.toLowerCase();\n if (['button', 'a', 'label'].includes(tag)) {\n // Escape special characters in text\n const escapedText = text.replace(/['\"\\\\]/g, '\\\\$&');\n return `${tag}:contains(\"${escapedText}\")`;\n }\n\n return undefined;\n }\n\n /**\n * Get data-testid or similar attributes\n */\n private static getDataTestId(element: Element): string | undefined {\n return (\n element.getAttribute('data-testid') ||\n element.getAttribute('data-test-id') ||\n element.getAttribute('data-test') ||\n element.getAttribute('data-cy') ||\n undefined\n );\n }\n\n /**\n * Check if an ID is unique in the document\n */\n private static isUniqueId(id: string, doc: Document): boolean {\n return doc.querySelectorAll(`#${CSS.escape(id)}`).length === 1;\n }\n\n /**\n * Check if a selector is unique within a container\n */\n private static isUniqueSelector(selector: string, container: Element): boolean {\n try {\n return container.querySelectorAll(selector).length === 1;\n } catch {\n return false;\n }\n }\n\n private static isUniqueSelectorSafe(selector: string, doc: Document): boolean {\n try {\n return doc.querySelectorAll(selector).length === 1;\n } catch {\n return false;\n }\n }\n\n /**\n * Get meaningful classes (filtering out utility classes)\n */\n private static getMeaningfulClasses(element: Element): string[] {\n const classes = Array.from(element.classList);\n\n // Filter out common utility classes\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\n return classes\n .filter((cls) => {\n // Keep semantic classes\n if (cls.length < 3) return false;\n return !utilityPatterns.some((pattern) => pattern.test(cls));\n })\n .slice(0, 2); // Limit to 2 most meaningful classes\n }\n\n /**\n * Optimize the selector path by removing unnecessary parts\n */\n private static optimizePath(path: string[], element: Element, doc: Document): string {\n // Try progressively shorter paths\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) {\n return shortPath;\n }\n } catch {\n // Invalid selector, continue\n }\n }\n\n return path.join(' > ');\n }\n\n /**\n * Get a human-readable path description\n */\n static getContextPath(element: Element): string[] {\n const path: string[] = [];\n let current: Element | null = element;\n let depth = 0;\n const maxDepth = 5;\n\n while (current && current !== element.ownerDocument?.body && depth < maxDepth) {\n const tag = current.nodeName.toLowerCase();\n let descriptor = tag;\n\n // Add semantic information\n if (current.id) {\n descriptor = `${tag}#${current.id}`;\n } else if (current.className && typeof current.className === 'string') {\n const firstClass = current.className.split(' ')[0];\n if (firstClass) {\n descriptor = `${tag}.${firstClass}`;\n }\n }\n\n // Add role information\n const role = current.getAttribute('role');\n if (role) {\n descriptor += `[role=\"${role}\"]`;\n }\n\n path.unshift(descriptor);\n current = current.parentElement;\n depth++;\n }\n\n return path;\n }\n}\n","import { SelectorGenerator } from './selectors';\nimport type {\n ElementContext,\n ElementInteraction,\n ExtractedElement,\n ExtractionOptions,\n FilterOptions,\n} from './types';\n\nexport class DOMTraversal {\n /**\n * Check if a node is a Document.\n *\n * `instanceof Document` tests the *calling* realm's constructor, so a\n * document reached through an iframe (frameSelector) always fails it.\n * nodeType is realm-independent — use this everywhere instead.\n */\n static isDocument(node: Document | Element): node is Document {\n return node.nodeType === Node.DOCUMENT_NODE;\n }\n\n /**\n * Check if element is visible\n */\n static isVisible(element: Element): boolean {\n const rect = element.getBoundingClientRect();\n const style = element.ownerDocument?.defaultView?.getComputedStyle(element);\n\n if (!style) return false;\n\n return !!(\n rect.width > 0 &&\n rect.height > 0 &&\n style.display !== 'none' &&\n style.visibility !== 'hidden' &&\n style.opacity !== '0'\n );\n }\n\n /**\n * Check if element is in viewport\n */\n static isInViewport(element: Element): boolean {\n const rect = element.getBoundingClientRect();\n const view = {\n width: element.ownerDocument?.defaultView?.innerWidth || 0,\n height: element.ownerDocument?.defaultView?.innerHeight || 0,\n };\n\n return rect.top < view.height && rect.bottom > 0 && rect.left < view.width && rect.right > 0;\n }\n\n /**\n * Check if element passes filter criteria\n */\n static passesFilter(element: Element, filter: FilterOptions | undefined): boolean {\n if (!filter) return true;\n\n // Check exclude selectors first\n if (filter.excludeSelectors?.length) {\n for (const selector of filter.excludeSelectors) {\n if (element.matches(selector)) return false;\n }\n }\n\n // Check include selectors\n if (filter.includeSelectors?.length) {\n let matches = false;\n for (const selector of filter.includeSelectors) {\n if (element.matches(selector)) {\n matches = true;\n break;\n }\n }\n if (!matches) return false;\n }\n\n // Check tag filters\n if (filter.tags?.length && !filter.tags.includes(element.tagName.toLowerCase())) {\n return false;\n }\n\n // Check text content filters\n const textContent = element.textContent?.toLowerCase() || '';\n if (filter.textContains?.length) {\n let hasText = false;\n for (const text of filter.textContains) {\n if (textContent.includes(text.toLowerCase())) {\n hasText = true;\n break;\n }\n }\n if (!hasText) return false;\n }\n\n // Check text regex patterns\n if (filter.textMatches?.length) {\n let matches = false;\n for (const pattern of filter.textMatches) {\n if (pattern.test(textContent)) {\n matches = true;\n break;\n }\n }\n if (!matches) return false;\n }\n\n // Check required attributes\n if (filter.hasAttributes?.length) {\n for (const attr of filter.hasAttributes) {\n if (!element.hasAttribute(attr)) return false;\n }\n }\n\n // Check attribute values\n if (filter.attributeValues) {\n for (const [attr, value] of Object.entries(filter.attributeValues)) {\n const attrValue = element.getAttribute(attr);\n if (!attrValue) return false;\n\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 }\n\n // Check within selectors\n if (filter.withinSelectors?.length) {\n let isWithin = false;\n for (const selector of filter.withinSelectors) {\n if (element.closest(selector)) {\n isWithin = true;\n break;\n }\n }\n if (!isWithin) return false;\n }\n\n // Check interaction types\n if (filter.interactionTypes?.length) {\n const interaction = DOMTraversal.getInteractionInfo(element);\n let hasInteraction = false;\n for (const type of filter.interactionTypes) {\n if (interaction[type]) {\n hasInteraction = true;\n break;\n }\n }\n if (!hasInteraction) return false;\n }\n\n // Check nearText\n if (filter.nearText) {\n const parent = element.parentElement;\n if (!parent || !parent.textContent?.toLowerCase().includes(filter.nearText.toLowerCase())) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Extract element information\n */\n static extractElement(\n element: Element,\n options: ExtractionOptions,\n depth = 0\n ): ExtractedElement | null {\n // Check depth limit\n if (options.maxDepth && depth > options.maxDepth) {\n return null;\n }\n\n // Check visibility\n if (!options.includeHidden && !DOMTraversal.isVisible(element)) {\n return null;\n }\n\n // Check viewport\n if (options.viewportOnly && !DOMTraversal.isInViewport(element)) {\n return null;\n }\n\n // Apply filters\n if (!DOMTraversal.passesFilter(element, options.filter)) {\n return null;\n }\n\n const extracted: ExtractedElement = {\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 // bounds removed to save tokens\n };\n\n // Extract children for semantic elements in full mode\n if (options.mode === 'full' && DOMTraversal.isSemanticContainer(element)) {\n const children: ExtractedElement[] = [];\n\n // Handle shadow DOM\n if (options.includeShadowDOM && element.shadowRoot) {\n const shadowChildren = DOMTraversal.extractChildren(element.shadowRoot, options, depth + 1);\n children.push(...shadowChildren);\n }\n\n // Handle regular children\n const regularChildren = DOMTraversal.extractChildren(element, options, depth + 1);\n children.push(...regularChildren);\n\n if (children.length > 0) {\n extracted.children = children;\n }\n }\n\n return extracted;\n }\n\n /**\n * Extract children elements\n */\n private static extractChildren(\n container: Element | ShadowRoot,\n options: ExtractionOptions,\n depth: number\n ): ExtractedElement[] {\n const children: ExtractedElement[] = [];\n const elements = container.querySelectorAll('*');\n\n for (const child of Array.from(elements)) {\n // Skip if element is nested inside another extracted element\n if (DOMTraversal.hasExtractedAncestor(child, elements)) {\n continue;\n }\n\n const extracted = DOMTraversal.extractElement(child, options, depth);\n if (extracted) {\n children.push(extracted);\n }\n }\n\n return children;\n }\n\n /**\n * Check if element has an ancestor that was already extracted\n */\n private static hasExtractedAncestor(\n element: Element,\n extractedElements: NodeListOf<Element>\n ): boolean {\n let parent = element.parentElement;\n while (parent) {\n if (Array.from(extractedElements).includes(parent)) {\n return true;\n }\n parent = parent.parentElement;\n }\n return false;\n }\n\n /**\n * Get relevant attributes for an element\n */\n private static getRelevantAttributes(\n element: Element,\n options: ExtractionOptions\n ): Record<string, string> {\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\n const attributes: Record<string, string> = {};\n const attrTruncate = options.attributeTruncateLength ?? 100;\n const dataAttrTruncate = options.dataAttributeTruncateLength ?? 50;\n\n for (const attr of relevant) {\n const value = element.getAttribute(attr);\n if (value) {\n // Truncate long values based on options\n attributes[attr] =\n value.length > attrTruncate ? `${value.substring(0, attrTruncate)}...` : value;\n }\n }\n\n // Include data attributes\n for (const attr of element.attributes) {\n if (attr.name.startsWith('data-') && !relevant.includes(attr.name)) {\n attributes[attr.name] =\n attr.value.length > dataAttrTruncate\n ? `${attr.value.substring(0, dataAttrTruncate)}...`\n : attr.value;\n }\n }\n\n return attributes;\n }\n\n /**\n * Get element context information\n */\n private static getElementContext(element: Element): ElementContext {\n const context: ElementContext = {\n parentChain: SelectorGenerator.getContextPath(element),\n };\n\n // Find nearest semantic containers\n const form = element.closest('form');\n if (form) {\n context.nearestForm = SelectorGenerator.generateSelectors(form).css;\n }\n\n const section = element.closest('section, [role=\"region\"]');\n if (section) {\n context.nearestSection = SelectorGenerator.generateSelectors(section).css;\n }\n\n const main = element.closest('main, [role=\"main\"]');\n if (main) {\n context.nearestMain = SelectorGenerator.generateSelectors(main).css;\n }\n\n const nav = element.closest('nav, [role=\"navigation\"]');\n if (nav) {\n context.nearestNav = SelectorGenerator.generateSelectors(nav).css;\n }\n\n return context;\n }\n\n /**\n * Get interaction information for an element (compact format)\n */\n private static getInteractionInfo(element: Element): ElementInteraction {\n // Element has no inline on* handlers in lib.dom; they live on GlobalEventHandlers.\n const htmlElement = element as HTMLElement;\n const interaction: ElementInteraction = {};\n\n // Only include true values to reduce token usage\n if (\n htmlElement.onclick ||\n element.getAttribute('onclick') ||\n element.matches('button, a[href], [role=\"button\"], [tabindex]:not([tabindex=\"-1\"])')\n )\n interaction.click = true;\n\n if (\n htmlElement.onchange ||\n element.getAttribute('onchange') ||\n element.matches('input, select, textarea')\n )\n interaction.change = true;\n\n if (htmlElement.onsubmit || element.getAttribute('onsubmit') || element.matches('form'))\n interaction.submit = true;\n\n const triggersNavigation = element.matches('a[href], button[type=\"submit\"]');\n if (triggersNavigation) interaction.nav = true;\n\n const isDisabled =\n element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true';\n if (isDisabled) interaction.disabled = true;\n\n const isHidden = !DOMTraversal.isVisible(element);\n if (isHidden) interaction.hidden = true;\n\n const ariaRole = element.getAttribute('role');\n if (ariaRole) interaction.role = ariaRole;\n\n // Check form association\n if (element.matches('input, textarea, select, button')) {\n // matches() cannot narrow, and instanceof is unsafe here (elements may come\n // from an iframe realm). All four tags carry .form.\n const form = (element as HTMLInputElement).form || element.closest('form');\n if (form) {\n interaction.form = SelectorGenerator.generateSelectors(form).css;\n }\n }\n\n return interaction;\n }\n\n /**\n * Get text content of an element (limited length)\n */\n private static getElementText(element: Element, options?: ExtractionOptions): string {\n // For input elements, get value or placeholder\n if (element.matches('input, textarea')) {\n const input = element as HTMLInputElement;\n return input.value || input.placeholder || '';\n }\n\n // For images, get alt text\n if (element.matches('img')) {\n return (element as HTMLImageElement).alt || '';\n }\n\n // Get text content, but limit length based on options\n const text = element.textContent?.trim() || '';\n const maxLength = options?.textTruncateLength;\n\n if (maxLength && text.length > maxLength) {\n return `${text.substring(0, maxLength)}...`;\n }\n\n return text;\n }\n\n /**\n * Check if element is a semantic container\n */\n private static isSemanticContainer(element: Element): boolean {\n return element.matches(\n 'article, section, nav, aside, main, header, footer, form, ' +\n 'table, ul, ol, dl, figure, details, dialog, [role=\"region\"], ' +\n '[role=\"navigation\"], [role=\"main\"], [role=\"complementary\"]'\n );\n }\n}\n","import { ContentDetection } from './content-detection';\nimport { SelectorGenerator } from './selectors';\nimport { DOMTraversal } from './traversal';\nimport type {\n ExtractedElement,\n ExtractionMode,\n ExtractionOptions,\n FormInfo,\n PageLandmarks,\n PageState,\n SmartDOMResult,\n} from './types';\n\n/**\n * Smart DOM Reader - Full Extraction Approach\n *\n * This class provides complete DOM extraction in a single pass.\n * Use this when you need all information upfront and have sufficient\n * token budget for processing the complete output.\n *\n * Features:\n * - Single-pass extraction of all elements\n * - Two modes: 'interactive' (UI elements) or 'full' (includes content)\n * - Efficient for automation and testing scenarios\n * - Returns complete structured data immediately\n */\nexport class SmartDOMReader {\n private options: ExtractionOptions;\n\n constructor(options: Partial<ExtractionOptions> = {}) {\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 !== undefined && {\n attributeTruncateLength: options.attributeTruncateLength,\n }),\n ...(options.dataAttributeTruncateLength !== undefined && {\n dataAttributeTruncateLength: options.dataAttributeTruncateLength,\n }),\n ...(options.textTruncateLength !== undefined && {\n textTruncateLength: options.textTruncateLength,\n }),\n ...(options.filter !== undefined && { filter: options.filter }),\n };\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(\n rootElement: Document | Element = document,\n runtimeOptions?: Partial<ExtractionOptions>\n ): SmartDOMResult {\n const startTime = Date.now();\n const rootIsDocument = DOMTraversal.isDocument(rootElement);\n const doc = rootIsDocument ? rootElement : rootElement.ownerDocument!;\n\n // Merge runtime options with constructor options\n const options: ExtractionOptions = { ...this.options, ...runtimeOptions };\n\n // Determine the container to search\n // IMPORTANT: Respect the provided rootElement when it's an Element.\n // Previous behavior incorrectly defaulted to the whole document, causing\n // region-scoped extractions to include page-wide data.\n let container: Element | Document = rootIsDocument ? doc : rootElement;\n // Only override container with detected main content when starting from the document.\n if (options.mainContentOnly && rootIsDocument) {\n container = ContentDetection.findMainContent(doc);\n }\n\n // Extract page state\n const pageState = this.extractPageState(doc);\n\n // Extract landmarks\n const landmarks = this.extractLandmarks(doc);\n\n // Extract interactive elements\n const interactive = this.extractInteractiveElements(container, options);\n\n // Build result\n const result: SmartDOMResult = {\n mode: options.mode,\n timestamp: startTime,\n page: pageState,\n landmarks,\n interactive,\n };\n\n // Add semantic elements in full mode\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\n return result;\n }\n\n /**\n * Extract page state information\n */\n private extractPageState(doc: Document): PageState {\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 !== undefined && { hasFocus }),\n };\n }\n\n /**\n * Extract page landmarks\n */\n private extractLandmarks(doc: Document): PageLandmarks {\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 /**\n * Convert elements to selector strings\n */\n private elementsToSelectors(elements: Element[]): string[] {\n return elements.map((el) => SelectorGenerator.generateSelectors(el).css);\n }\n\n private querySelectorAll(\n container: Document | Element | ShadowRoot,\n selector: string,\n includeShadowDOM?: boolean\n ): Element[] {\n const matches = [...container.querySelectorAll(selector)];\n if (!includeShadowDOM) return matches;\n\n for (const element of container.querySelectorAll('*')) {\n if (element.shadowRoot) {\n matches.push(...this.querySelectorAll(element.shadowRoot, selector, true));\n }\n }\n return matches;\n }\n\n /**\n * Extract every element matching a selector.\n *\n * DOMTraversal.extractElement already applies the visibility, viewport and\n * filter guards, so pre-filtering here would just repeat its\n * getBoundingClientRect/getComputedStyle work for every element.\n */\n private extractAll(\n container: Element | Document,\n selector: string,\n options: ExtractionOptions\n ): ExtractedElement[] {\n const extracted: ExtractedElement[] = [];\n for (const el of this.querySelectorAll(container, selector, options.includeShadowDOM)) {\n const element = DOMTraversal.extractElement(el, options);\n if (element) extracted.push(element);\n }\n return extracted;\n }\n\n /**\n * Extract interactive elements\n */\n private extractInteractiveElements(\n container: Element | Document,\n options: ExtractionOptions\n ): SmartDOMResult['interactive'] {\n const clickable: ExtractedElement[] = [];\n for (const selector of options.customSelectors ?? []) {\n clickable.push(...this.extractAll(container, selector, options));\n }\n\n return {\n buttons: this.extractAll(\n container,\n 'button, [role=\"button\"], input[type=\"button\"], input[type=\"submit\"]',\n options\n ),\n links: this.extractAll(container, 'a[href]', options),\n inputs: this.extractAll(\n container,\n 'input:not([type=\"button\"]):not([type=\"submit\"]), textarea, select',\n options\n ),\n forms: this.extractForms(container, options),\n clickable,\n };\n }\n\n /**\n * Extract form information\n */\n private extractForms(container: Element | Document, options: ExtractionOptions): FormInfo[] {\n const forms: FormInfo[] = [];\n const formElements = this.querySelectorAll(container, 'form', options.includeShadowDOM);\n\n formElements.forEach((form) => {\n // The form itself never reaches extractElement, so it needs the guard here.\n if (!this.shouldIncludeElement(form, options)) return;\n\n const action = form.getAttribute('action');\n const method = form.getAttribute('method');\n const formInfo: FormInfo = {\n selector: SelectorGenerator.generateSelectors(form).css,\n inputs: this.extractAll(\n form,\n 'input:not([type=\"button\"]):not([type=\"submit\"]), textarea, select',\n options\n ),\n buttons: this.extractAll(\n form,\n 'button, input[type=\"button\"], input[type=\"submit\"]',\n options\n ),\n };\n if (action) formInfo.action = action;\n if (method) formInfo.method = method;\n forms.push(formInfo);\n });\n\n return forms;\n }\n\n /**\n * Extract semantic elements (full mode only)\n */\n private extractSemanticElements(\n container: Element | Document,\n options: ExtractionOptions\n ): NonNullable<SmartDOMResult['semantic']> {\n return {\n headings: this.extractAll(container, 'h1, h2, h3, h4, h5, h6', options),\n images: this.extractAll(container, 'img', options),\n tables: this.extractAll(container, 'table', options),\n lists: this.extractAll(container, 'ul, ol', options),\n articles: this.extractAll(container, 'article, [role=\"article\"]', options),\n };\n }\n\n /**\n * Extract metadata\n */\n private extractMetadata(\n doc: Document,\n container: Element | Document,\n options: ExtractionOptions\n ): NonNullable<SmartDOMResult['metadata']> {\n const allElements = this.querySelectorAll(container, '*', options.includeShadowDOM);\n const extractedElements = this.querySelectorAll(\n container,\n 'button, a, input, textarea, select, h1, h2, h3, h4, h5, h6, img, table, ul, ol, article',\n options.includeShadowDOM\n ).length;\n\n const metadata: NonNullable<SmartDOMResult['metadata']> = {\n totalElements: allElements.length,\n extractedElements,\n };\n\n if (options.mainContentOnly && !DOMTraversal.isDocument(container)) {\n metadata.mainContent = SelectorGenerator.generateSelectors(container).css;\n }\n\n const language = doc.documentElement.getAttribute('lang');\n if (language) {\n metadata.language = language;\n }\n\n return metadata;\n }\n\n /**\n * Check if element should be included based on options\n */\n private shouldIncludeElement(element: Element, options: ExtractionOptions): boolean {\n // Check visibility\n if (!options.includeHidden && !DOMTraversal.isVisible(element)) {\n return false;\n }\n\n // Check viewport\n if (options.viewportOnly && !DOMTraversal.isInViewport(element)) {\n return false;\n }\n\n // Check custom filter\n if (options.filter && !DOMTraversal.passesFilter(element, options.filter)) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Detect errors on the page\n */\n private detectErrors(doc: Document): boolean {\n const errorSelectors = ['.error', '.alert-danger', '[role=\"alert\"]', '.error-message'];\n return errorSelectors.some((sel) => {\n const element = doc.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n }\n\n /**\n * Detect if page is loading\n */\n private detectLoading(doc: Document): boolean {\n const loadingSelectors = ['.loading', '.spinner', '[aria-busy=\"true\"]', '.loader'];\n return loadingSelectors.some((sel) => {\n const element = doc.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n }\n\n /**\n * Detect modal dialogs\n */\n private detectModals(doc: Document): boolean {\n const modalSelectors = ['[role=\"dialog\"]', '.modal', '.popup', '.overlay'];\n return modalSelectors.some((sel) => {\n const element = doc.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n }\n\n /**\n * Get currently focused element\n */\n private getFocusedElement(doc: Document): string | undefined {\n const focused = doc.activeElement;\n if (focused && focused !== doc.body) {\n return SelectorGenerator.generateSelectors(focused).css;\n }\n return undefined;\n }\n\n // ===== Static convenience methods =====\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(\n doc: Document,\n options: Omit<ExtractionOptions, 'mode'> = {}\n ): SmartDOMResult {\n const reader = new SmartDOMReader({\n ...options,\n mode: 'interactive',\n });\n return reader.extract(doc);\n }\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: Document, options: Omit<ExtractionOptions, 'mode'> = {}): SmartDOMResult {\n const reader = new SmartDOMReader({\n ...options,\n mode: 'full',\n });\n return reader.extract(doc);\n }\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(\n element: Element,\n mode: ExtractionMode = 'interactive',\n options: Omit<ExtractionOptions, 'mode'> = {}\n ): SmartDOMResult {\n const reader = new SmartDOMReader({\n ...options,\n mode,\n });\n return reader.extract(element);\n }\n}\n","import { ContentDetection } from './content-detection';\nimport { SmartDOMReader } from './smart-dom-reader';\nimport { SelectorGenerator } from './selectors';\nimport { DOMTraversal } from './traversal';\nimport type {\n ContentExtractionOptions,\n ExtractedContent,\n ExtractionOptions,\n RegionInfo,\n SmartDOMResult,\n StructuralOverview,\n} from './types';\n\nexport 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: Document | Element): StructuralOverview {\n const regions: StructuralOverview['regions'] = {};\n\n // Find header (scoped to root)\n const header = root.querySelector('header, [role=\"banner\"], .header, #header');\n if (header) {\n regions.header = ProgressiveExtractor.analyzeRegion(header);\n }\n\n // Find navigation areas (scoped to root)\n const navs = root.querySelectorAll('nav, [role=\"navigation\"], .nav, .navigation');\n if (navs.length > 0) {\n regions.navigation = Array.from(navs).map((nav) => ProgressiveExtractor.analyzeRegion(nav));\n }\n\n // Find main content\n if (DOMTraversal.isDocument(root)) {\n const main = ContentDetection.findMainContent(root);\n if (main) {\n regions.main = ProgressiveExtractor.analyzeRegion(main);\n // Find sections within main\n const sections = main.querySelectorAll('section, article, [role=\"region\"]');\n if (sections.length > 0) {\n regions.sections = Array.from(sections)\n .filter((section) => !section.closest('nav, header, footer'))\n .map((section) => ProgressiveExtractor.analyzeRegion(section));\n }\n }\n } else {\n // When scoped to an Element, treat the element itself as the main region\n regions.main = ProgressiveExtractor.analyzeRegion(root);\n const sections = root.querySelectorAll('section, article, [role=\"region\"]');\n if (sections.length > 0) {\n regions.sections = Array.from(sections)\n .filter((section) => !section.closest('nav, header, footer'))\n .map((section) => ProgressiveExtractor.analyzeRegion(section));\n }\n }\n\n // Find sidebars (scoped)\n const sidebars = root.querySelectorAll('aside, [role=\"complementary\"], .sidebar, #sidebar');\n if (sidebars.length > 0) {\n regions.sidebar = Array.from(sidebars).map((sidebar) =>\n ProgressiveExtractor.analyzeRegion(sidebar)\n );\n }\n\n // Find footer (scoped)\n const footer = root.querySelector('footer, [role=\"contentinfo\"], .footer, #footer');\n if (footer) {\n regions.footer = ProgressiveExtractor.analyzeRegion(footer);\n }\n\n // Find modals/dialogs (scoped)\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) {\n regions.modals = visibleModals.map((modal) => ProgressiveExtractor.analyzeRegion(modal));\n }\n\n // Extract form information (scoped)\n const forms = ProgressiveExtractor.extractFormOverview(root);\n\n // Calculate summary statistics (scoped)\n const summary = ProgressiveExtractor.calculateSummary(root, regions, forms);\n\n // Generate AI-friendly suggestions\n const suggestions = ProgressiveExtractor.generateSuggestions(regions, summary);\n\n return { regions, forms, summary, suggestions };\n }\n\n /**\n * Step 2: Extract detailed information from a specific region\n */\n static extractRegion(\n selector: string,\n doc: Document,\n options: Partial<ExtractionOptions> = {}\n ): SmartDOMResult | null {\n const element = doc.querySelector(selector);\n if (!element) return null;\n\n const reader = new SmartDOMReader(options);\n\n // Extract from the specific element/region\n return reader.extract(element, options);\n }\n\n /**\n * Step 3: Extract readable content from a region\n */\n static extractContent(\n selector: string,\n doc: Document,\n options: ContentExtractionOptions = {}\n ): ExtractedContent | null {\n const element = doc.querySelector(selector);\n if (!element) return null;\n\n const result: ExtractedContent = {\n selector,\n text: {},\n metadata: {\n wordCount: 0,\n hasInteractive: false,\n },\n };\n\n // Extract headings\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\n // Extract paragraphs\n const paragraphs = element.querySelectorAll('p');\n if (paragraphs.length > 0) {\n result.text.paragraphs = Array.from(paragraphs)\n .map((p) => ProgressiveExtractor.getTextContent(p, options.maxTextLength))\n .filter((text) => text.length > 0);\n }\n\n // Extract lists\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() as 'ul' | 'ol',\n items: Array.from(list.querySelectorAll('li')).map((li) =>\n ProgressiveExtractor.getTextContent(li, options.maxTextLength)\n ),\n }));\n }\n\n // Extract tables\n if (options.includeTables !== false) {\n const tables = element.querySelectorAll('table');\n result.tables = Array.from(tables).map((table) => {\n const headers = Array.from(table.querySelectorAll('th')).map((th) =>\n ProgressiveExtractor.getTextContent(th)\n );\n const rows = Array.from(table.querySelectorAll('tr'))\n .filter((tr) => tr.querySelector('td'))\n .map((tr) =>\n Array.from(tr.querySelectorAll('td')).map((td) =>\n ProgressiveExtractor.getTextContent(td)\n )\n );\n return { headers, rows };\n });\n }\n\n // Extract media\n if (options.includeMedia !== false) {\n const images = element.querySelectorAll('img');\n const videos = element.querySelectorAll('video');\n const audios = element.querySelectorAll('audio');\n\n result.media = [\n ...Array.from(images).map((img) => {\n const item: { type: 'img'; alt?: string; src?: string } = { 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'; src?: string } = { 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'; src?: string } = { type: 'audio' };\n const src = audio.getAttribute('src');\n if (src) item.src = src;\n return item;\n }),\n ];\n }\n\n // Calculate metadata\n const allText = element.textContent || '';\n result.metadata.wordCount = allText.trim().split(/\\s+/).length;\n result.metadata.hasInteractive =\n element.querySelectorAll('button, a, input, textarea, select').length > 0;\n\n return result;\n }\n\n /**\n * Analyze a region and extract summary information\n */\n private static analyzeRegion(element: Element): RegionInfo {\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\n const interactiveCount = buttons.length + links.length + inputs.length;\n\n // Get label from aria-label, aria-labelledby, or heading\n let label: string | undefined;\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel) {\n 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) {\n label = labelElement.textContent?.trim();\n }\n }\n } else {\n const heading = element.querySelector('h1, h2, h3');\n if (heading) {\n label = heading.textContent?.trim();\n }\n }\n\n // Get text preview\n const textContent = element.textContent?.trim() || '';\n const textPreview =\n textContent.length > 50 ? `${textContent.substring(0, 50)}...` : textContent;\n\n const regionInfo: 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\n if (label) regionInfo.label = label;\n\n const role = element.getAttribute('role');\n if (role) regionInfo.role = role;\n\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\n return regionInfo;\n }\n\n /**\n * Extract overview of forms on the page\n */\n private static extractFormOverview(root: Document | Element): StructuralOverview['forms'] {\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\n // Determine which region the form is in\n let location = 'unknown';\n if (form.closest('header, [role=\"banner\"]')) {\n location = 'header';\n } else if (form.closest('nav, [role=\"navigation\"]')) {\n location = 'navigation';\n } else if (form.closest('main, [role=\"main\"]')) {\n location = 'main';\n } else if (form.closest('aside, [role=\"complementary\"]')) {\n location = 'sidebar';\n } else if (form.closest('footer, [role=\"contentinfo\"]')) {\n location = 'footer';\n }\n\n // Infer purpose from form attributes and content\n let purpose: string | undefined;\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 const hasSearch = form.querySelector('input[type=\"search\"]');\n\n if (hasSearch || formId?.includes('search') || formClass?.includes('search')) {\n purpose = 'search';\n } else if (hasPassword && hasEmail) {\n purpose = 'login';\n } else if (hasPassword) {\n purpose = 'authentication';\n } else if (formId?.includes('contact') || formClass?.includes('contact')) {\n purpose = 'contact';\n } else if (formId?.includes('subscribe') || formClass?.includes('subscribe')) {\n purpose = 'subscription';\n } else if (formAction?.includes('checkout') || formClass?.includes('checkout')) {\n purpose = 'checkout';\n }\n\n const formOverview: {\n selector: string;\n location: string;\n inputCount: number;\n purpose?: string;\n } = {\n selector,\n location,\n inputCount: inputs.length,\n };\n\n if (purpose) formOverview.purpose = purpose;\n\n return formOverview;\n });\n }\n\n /**\n * Calculate summary statistics\n */\n private static calculateSummary(\n root: Document | Element,\n regions: StructuralOverview['regions'],\n forms: StructuralOverview['forms']\n ): StructuralOverview['summary'] {\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\n // Check for errors\n const errorSelectors = ['.error', '.alert-danger', '[role=\"alert\"]'];\n const hasErrors = errorSelectors.some((sel) => {\n const element = root.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n\n // Check for loading\n const loadingSelectors = ['.loading', '.spinner', '[aria-busy=\"true\"]'];\n const isLoading = loadingSelectors.some((sel) => {\n const element = root.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n\n const summary: StructuralOverview['summary'] = {\n totalInteractive: allInteractive.length,\n totalForms: forms.length,\n totalSections: allSections.length,\n hasModals,\n hasErrors,\n isLoading,\n };\n\n const mainContentSelector = regions.main?.selector;\n if (mainContentSelector) {\n summary.mainContentSelector = mainContentSelector;\n }\n\n return summary;\n }\n\n /**\n * Generate AI-friendly suggestions\n */\n private static generateSuggestions(\n regions: StructuralOverview['regions'],\n summary: StructuralOverview['summary']\n ): string[] {\n const suggestions: string[] = [];\n\n if (summary.hasErrors) {\n suggestions.push('Page has error indicators - check error messages before interacting');\n }\n\n if (summary.isLoading) {\n suggestions.push('Page appears to be loading - wait or check loading state');\n }\n\n if (summary.hasModals) {\n suggestions.push('Modal/dialog is open - may need to interact with or close it first');\n }\n\n if (regions.main && regions.main.interactiveCount > 10) {\n suggestions.push(\n `Main content has ${regions.main.interactiveCount} interactive elements - consider filtering`\n );\n }\n\n if (summary.totalForms > 0) {\n suggestions.push(`Found ${summary.totalForms} form(s) on the page`);\n }\n\n if (!regions.main) {\n suggestions.push('No clear main content area detected - may need to explore regions');\n }\n\n return suggestions;\n }\n\n /**\n * Get text content with optional truncation\n */\n private static getTextContent(element: Element, maxLength?: number): string {\n const text = element.textContent?.trim() || '';\n if (maxLength && text.length > maxLength) {\n return `${text.substring(0, maxLength)}...`;\n }\n return text;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/content-detection.ts","../src/markdown-formatter.ts","../src/selectors.ts","../src/traversal.ts","../src/smart-dom-reader.ts","../src/progressive.ts"],"sourcesContent":["export 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: Document): Element {\n // First, check for explicit main element\n const mainElement = doc.querySelector('main, [role=\"main\"]');\n if (mainElement) {\n return mainElement;\n }\n\n // If no explicit main, detect it\n if (!doc.body) {\n return doc.documentElement;\n }\n\n return ContentDetection.detectMainContent(doc.body);\n }\n\n /**\n * Detect main content using scoring algorithm\n */\n private static detectMainContent(rootElement: Element): Element {\n const candidates: Element[] = [];\n const minScore = 15;\n\n ContentDetection.collectCandidates(rootElement, candidates, minScore);\n\n if (candidates.length === 0) {\n return rootElement;\n }\n\n // Sort by score\n candidates.sort(\n (a, b) =>\n ContentDetection.calculateContentScore(b) - ContentDetection.calculateContentScore(a)\n );\n\n // Find best independent candidate\n let bestCandidate = candidates[0]!;\n for (let i = 1; i < candidates.length; i++) {\n const candidate = candidates[i]!;\n // Check if this candidate is not contained in any other\n const isIndependent = !candidates.some((other, j) => j !== i && other.contains(candidate));\n\n if (\n isIndependent &&\n ContentDetection.calculateContentScore(candidate) >\n ContentDetection.calculateContentScore(bestCandidate)\n ) {\n bestCandidate = candidate;\n }\n }\n\n return bestCandidate;\n }\n\n /**\n * Collect content candidates\n */\n private static collectCandidates(\n element: Element,\n candidates: Element[],\n minScore: number\n ): void {\n const score = ContentDetection.calculateContentScore(element);\n if (score >= minScore) {\n candidates.push(element);\n }\n\n // Recursively check children\n Array.from(element.children).forEach((child) => {\n ContentDetection.collectCandidates(child, candidates, minScore);\n });\n }\n\n /**\n * Calculate content score for an element\n */\n static calculateContentScore(element: Element): number {\n let score = 0;\n\n // High impact semantic indicators\n const semanticClasses = [\n 'article',\n 'content',\n 'main-container',\n 'main',\n 'main-content',\n 'post',\n 'entry',\n ];\n const semanticIds = ['content', 'main', 'article', 'post', 'entry'];\n\n // Check classes\n semanticClasses.forEach((cls) => {\n if (element.classList.contains(cls)) {\n score += 10;\n }\n });\n\n // Check ID\n semanticIds.forEach((id) => {\n if (element.id?.toLowerCase().includes(id)) {\n score += 10;\n }\n });\n\n // High value tags\n const tag = element.tagName.toLowerCase();\n const highValueTags = ['article', 'main', 'section'];\n if (highValueTags.includes(tag)) {\n score += 8;\n }\n\n // Paragraph density\n const paragraphs = element.getElementsByTagName('p').length;\n score += Math.min(paragraphs * 2, 10);\n\n // Heading presence\n const headings = element.querySelectorAll('h1, h2, h3').length;\n score += Math.min(headings * 3, 9);\n\n // Text content length\n const textLength = element.textContent?.trim().length || 0;\n if (textLength > 300) {\n score += Math.min(Math.floor(textLength / 300) * 2, 10);\n }\n\n // Link density (lower is better for content)\n const linkDensity = ContentDetection.calculateLinkDensity(element);\n if (linkDensity < 0.3) {\n score += 5;\n } else if (linkDensity > 0.5) {\n score -= 5;\n }\n\n // Data attributes\n if (\n element.hasAttribute('data-main') ||\n element.hasAttribute('data-content') ||\n element.hasAttribute('itemprop')\n ) {\n score += 8;\n }\n\n // ARIA landmarks\n const role = element.getAttribute('role');\n if (role === 'main' || role === 'article') {\n score += 10;\n }\n\n // Penalize certain elements\n if (\n element.matches(\n 'aside, nav, header, footer, .sidebar, .navigation, .menu, .ad, .advertisement'\n )\n ) {\n score -= 10;\n }\n\n // Check for form density (forms are usually not main content)\n const forms = element.getElementsByTagName('form').length;\n if (forms > 2) {\n score -= 5;\n }\n\n return Math.max(0, score);\n }\n\n /**\n * Calculate link density in an element\n */\n private static calculateLinkDensity(element: Element): number {\n const links = element.getElementsByTagName('a');\n let linkTextLength = 0;\n\n for (const link of Array.from(links)) {\n linkTextLength += link.textContent?.length || 0;\n }\n\n const totalTextLength = element.textContent?.length || 1;\n return linkTextLength / totalTextLength;\n }\n\n /**\n * Check if an element is likely navigation\n */\n static isNavigation(element: Element): boolean {\n const tag = element.tagName.toLowerCase();\n\n // Explicit navigation elements\n if (tag === 'nav' || element.getAttribute('role') === 'navigation') {\n return true;\n }\n\n // Check for navigation patterns\n const navPatterns = [/nav/i, /menu/i, /sidebar/i, /toolbar/i];\n\n const classesAndId = `${element.className} ${element.id}`.toLowerCase();\n return navPatterns.some((pattern) => pattern.test(classesAndId));\n }\n\n /**\n * Check if element is likely supplementary content\n */\n static isSupplementary(element: Element): boolean {\n const tag = element.tagName.toLowerCase();\n\n // Explicit supplementary elements\n if (tag === 'aside' || element.getAttribute('role') === 'complementary') {\n return true;\n }\n\n // Check for supplementary patterns\n const supplementaryPatterns = [/sidebar/i, /widget/i, /related/i, /advertisement/i, /social/i];\n\n const classesAndId = `${element.className} ${element.id}`.toLowerCase();\n return supplementaryPatterns.some((pattern) => pattern.test(classesAndId));\n }\n\n /**\n * Detect page landmarks\n */\n static detectLandmarks(doc: Document): Record<string, Element[]> {\n const landmarks: Record<string, Element[]> = {\n navigation: [],\n main: [],\n complementary: [],\n contentinfo: [],\n banner: [],\n search: [],\n form: [],\n region: [],\n };\n\n // Find explicit landmarks\n const landmarkSelectors = {\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\n for (const [landmark, selector] of Object.entries(landmarkSelectors)) {\n const elements = doc.querySelectorAll(selector);\n landmarks[landmark] = Array.from(elements);\n }\n\n return landmarks;\n }\n}\n","import type {\n ExtractedContent,\n ExtractedElement,\n RegionInfo,\n SmartDOMResult,\n StructuralOverview,\n} from './types';\n\nexport type MarkdownDetailLevel = 'summary' | 'region' | 'deep';\n\nexport interface MarkdownFormatOptions {\n detail?: MarkdownDetailLevel;\n maxTextLength?: number;\n maxElements?: number;\n}\n\ntype PageMeta = { title?: string; url?: string };\n\nfunction truncate(text: string | undefined, len?: number): string {\n const t = (text ?? '').trim();\n if (!len || t.length <= len) return t;\n\n // Smart truncation: keep start and preserve key action words if present\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) => ({ k, i: lower.indexOf(k) })).find((x) => x.i > -1);\n const head = Math.max(0, Math.floor(len * 0.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 // Default: simple head truncation on word boundary\n const slice = t.slice(0, len);\n const lastSpace = slice.lastIndexOf(' ');\n return `${lastSpace > 32 ? slice.slice(0, lastSpace) : slice}…`;\n}\n\nfunction hashId(input: string): string {\n let h = 5381;\n for (let i = 0; i < input.length; i++) h = (h * 33) ^ input.charCodeAt(i);\n // Convert to unsigned and base36 for compactness\n return `sec-${(h >>> 0).toString(36)}`;\n}\n\nfunction iconForRegion(key: string): string {\n switch (key) {\n case 'header':\n return '🧭';\n case 'navigation':\n return '📑';\n case 'main':\n return '📄';\n case 'sections':\n return '🗂️';\n case 'sidebar':\n return '📚';\n case 'footer':\n return '🔻';\n case 'modals':\n return '💬';\n default:\n return '🔹';\n }\n}\n\nfunction elementLine(el: ExtractedElement, opts?: MarkdownFormatOptions): string {\n const txt = truncate(el.text || el.attributes?.ariaLabel, opts?.maxTextLength ?? 80);\n const sel = el.selector?.css || '';\n const tag = el.tag.toLowerCase();\n const action = el.interaction?.submit\n ? 'submit'\n : el.interaction?.click\n ? 'click'\n : el.interaction?.change\n ? 'change'\n : undefined;\n const actionText = action ? ` (${action})` : '';\n return `- ${tag.toUpperCase()}: ${txt || '(no text)'} → \\`${sel}\\`${actionText}`;\n}\n\nfunction selectorQualitySummary(inter: SmartDOMResult['interactive']): string {\n const all: string[] = [];\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 const stablePct = Math.round((stable / total) * 100);\n const nthPct = Math.round((nthCount / total) * 100);\n return `Selector quality: ${stablePct}% stable (ID/data-testid), ${nthPct}% structural (:nth-child)`;\n}\n\nfunction renderInteractive(\n inter: SmartDOMResult['interactive'],\n opts?: MarkdownFormatOptions\n): string {\n const parts: string[] = [];\n\n const limit = <T>(arr: T[]) =>\n typeof opts?.maxElements === 'number' ? arr.slice(0, opts.maxElements) : arr;\n\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)) {\n parts.push(`- FORM: action=${f.action ?? '-'} method=${f.method ?? '-'} → \\`${f.selector}\\``);\n }\n }\n\n return parts.join('\\n');\n}\n\nfunction renderRegionInfo(region: RegionInfo): string {\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: string[] = [];\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\nfunction wrapXml(body: string, meta?: PageMeta, type = 'section'): string {\n const attrs = [\n meta?.title ? `title=\"${escapeXml(meta.title)}\"` : null,\n meta?.url ? `url=\"${escapeXml(meta.url)}\"` : null,\n ]\n .filter(Boolean)\n .join(' ');\n return `<page ${attrs}>\\n <${type}><![CDATA[\\n${body}\\n]]></${type}>\\n</page>`;\n}\n\nfunction escapeXml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nexport class MarkdownFormatter {\n static structure(\n overview: StructuralOverview,\n _opts: MarkdownFormatOptions = {},\n meta?: PageMeta\n ): string {\n const lines: string[] = [];\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\n const regions = overview.regions;\n const entries: Array<[string, RegionInfo | RegionInfo[] | undefined]> = [\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\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\n // Suggestions\n if (overview.suggestions?.length) {\n lines.push('## Suggestions');\n for (const s of overview.suggestions) lines.push(`- ${s}`);\n lines.push('');\n }\n\n lines.push(\n 'Next: choose a region (by selector or [sectionId]) and call dom_extract_region for actionable details.'\n );\n\n const body = lines.join('\\n');\n return wrapXml(body, meta, 'outline');\n }\n\n static region(result: SmartDOMResult, opts: MarkdownFormatOptions = {}, meta?: PageMeta): string {\n const lines: string[] = [];\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\n const inter = result.interactive;\n // Page state diagnostics if available\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\n const summary: string[] = [];\n const count = (arr: unknown[]) => (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\n lines.push(renderInteractive(inter, opts));\n lines.push('');\n lines.push(\n '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 );\n\n const body = lines.join('\\n');\n return wrapXml(body, meta, 'section');\n }\n\n static content(\n content: ExtractedContent,\n opts: MarkdownFormatOptions = {},\n meta?: PageMeta\n ): string {\n const lines: string[] = [];\n lines.push('# Content');\n lines.push(`Selector: \\`${content.selector}\\``);\n lines.push('');\n\n if (content.text.headings?.length) {\n lines.push('Headings:');\n for (const h of content.text.headings)\n lines.push(`- H${h.level}: ${truncate(h.text, opts.maxTextLength ?? 120)}`);\n lines.push('');\n }\n if (content.text.paragraphs?.length) {\n const limit =\n 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))\n 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))\n lines.push(` - ${truncate(item, opts.maxTextLength ?? 120)}`);\n }\n lines.push('');\n }\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\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)) {\n lines.push(`- ${m.type.toUpperCase()}: ${m.alt ?? ''} ${m.src ? `→ ${m.src}` : ''}`.trim());\n }\n lines.push('');\n }\n\n lines.push(\n 'Next: if text is insufficient for targeting, call dom_extract_region for interactive selectors.'\n );\n\n const body = lines.join('\\n');\n return wrapXml(body, meta, 'content');\n }\n}\n\nfunction capitalize(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n","import type { ElementSelector, ElementSelectorCandidate } from './types';\n\nexport class SelectorGenerator {\n /**\n * Generate multiple selector strategies for an element\n */\n static generateSelectors(element: Element): ElementSelector {\n const doc = element.ownerDocument || document;\n const candidates: ElementSelectorCandidate[] = [];\n\n // 1) Unique ID\n if (element.id && SelectorGenerator.isUniqueId(element.id, doc)) {\n candidates.push({ type: 'id', value: `#${CSS.escape(element.id)}`, score: 100 });\n }\n\n // 2) data-testid variants\n const testId = SelectorGenerator.getDataTestId(element);\n if (testId) {\n const v = `[${testId.name}=\"${CSS.escape(testId.value)}\"]`;\n candidates.push({\n type: 'data-testid',\n value: v,\n score: 90 + (SelectorGenerator.isUniqueSelector(v, doc) ? 5 : 0),\n });\n }\n\n // 3) role + aria-label\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.isUniqueSelector(v, doc) ? 5 : 0),\n });\n }\n\n // 4) name attribute (useful for inputs)\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.isUniqueSelector(v, doc) ? 5 : 0),\n });\n }\n\n // 5) Class-based CSS path (try to avoid structural :nth-child when possible)\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({ type: 'class-path', value: pathCss, score: pathScore });\n\n // 6) XPath (fallback)\n const xpath = SelectorGenerator.generateXPath(element, doc);\n candidates.push({ type: 'xpath', value: xpath, score: 40 });\n\n // 7) Text-based (only for hints)\n const textBased = SelectorGenerator.generateTextBasedSelector(element);\n if (textBased) candidates.push({ type: 'text', value: textBased, score: 30 });\n\n // Rank candidates by score (desc)\n candidates.sort((a, b) => b.score - a.score);\n\n const bestCss =\n candidates.find(\n (c) =>\n c.type !== 'xpath' &&\n c.type !== 'text' &&\n SelectorGenerator.isUniqueSelector(c.value, doc, element)\n )?.value || pathCss;\n\n const selector: ElementSelector = {\n css: bestCss,\n xpath,\n candidates,\n };\n\n if (textBased) selector.textBased = textBased;\n if (testId) selector.dataTestId = testId.value;\n if (aria) selector.ariaLabel = aria;\n\n return selector;\n }\n\n /**\n * Generate a unique CSS selector for an element\n */\n private static generateCSSSelector(element: Element, doc: Document): string {\n // If element has a unique ID, use it\n if (element.id && SelectorGenerator.isUniqueId(element.id, doc)) {\n return `#${CSS.escape(element.id)}`;\n }\n\n // A repeated test ID still needs the structural fallback.\n const testId = SelectorGenerator.getDataTestId(element);\n if (testId) {\n const selector = `[${testId.name}=\"${CSS.escape(testId.value)}\"]`;\n if (SelectorGenerator.isUniqueSelector(selector, doc, element)) return selector;\n }\n\n // Build a path from the element to the root\n const path: string[] = [];\n let current: Element | null = element;\n\n while (current && current.nodeType === Node.ELEMENT_NODE) {\n let selector = current.nodeName.toLowerCase();\n\n if (current.id && SelectorGenerator.isUniqueId(current.id, doc)) {\n selector = `#${CSS.escape(current.id)}`;\n path.unshift(selector);\n break;\n }\n\n // Add classes if they exist and are meaningful\n const classes = SelectorGenerator.getMeaningfulClasses(current);\n if (classes.length > 0) {\n selector += `.${classes.map((c) => CSS.escape(c)).join('.')}`;\n }\n\n // Add position if needed for uniqueness\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!)) {\n selector += `:nth-child(${index + 1})`;\n }\n }\n\n path.unshift(selector);\n current = current.parentElement;\n }\n\n // Optimize the path\n return SelectorGenerator.optimizePath(path, element, doc);\n }\n\n /**\n * Generate XPath for an element\n */\n private static generateXPath(element: Element, doc: Document): string {\n const path: string[] = [];\n let current: Element | null = element;\n\n while (current && current.nodeType === Node.ELEMENT_NODE) {\n const tagName = current.nodeName.toLowerCase();\n\n if (\n current.id &&\n !current.id.includes('\"') &&\n SelectorGenerator.isUniqueId(current.id, doc)\n ) {\n path.unshift(`*[@id=\"${current.id}\"]`);\n break;\n }\n\n let xpath = tagName;\n\n // Add index if there are siblings with same tag\n const siblings = current.parentElement?.children;\n if (siblings) {\n const sameTagSiblings = Array.from(siblings).filter(\n (s) => s.nodeName.toLowerCase() === tagName\n );\n if (sameTagSiblings.length > 1) {\n const index = sameTagSiblings.indexOf(current) + 1;\n xpath += `[${index}]`;\n }\n }\n\n path.unshift(xpath);\n current = current.parentElement;\n }\n\n return `//${path.join('/')}`;\n }\n\n /**\n * Generate a text-based selector for buttons and links\n */\n private static generateTextBasedSelector(element: Element): string | undefined {\n const text = element.textContent?.trim();\n if (!text || text.length > 50) return undefined;\n\n const tag = element.nodeName.toLowerCase();\n if (['button', 'a', 'label'].includes(tag)) {\n // Escape special characters in text\n const escapedText = text.replace(/['\"\\\\]/g, '\\\\$&');\n return `${tag}:contains(\"${escapedText}\")`;\n }\n\n return undefined;\n }\n\n /**\n * Get data-testid or similar attributes\n */\n private static getDataTestId(element: Element): Attr | undefined {\n for (const name of ['data-testid', 'data-test-id', 'data-test', 'data-cy']) {\n const attribute = element.getAttributeNode(name);\n if (attribute?.value) return attribute;\n }\n return undefined;\n }\n\n /**\n * Check if an ID is unique in the document\n */\n private static isUniqueId(id: string, doc: Document): boolean {\n return doc.querySelectorAll(`#${CSS.escape(id)}`).length === 1;\n }\n\n /**\n * Check if a selector is unique within a container\n */\n private static isUniqueSelector(\n selector: string,\n container: ParentNode,\n element?: Element\n ): boolean {\n try {\n const matches = container.querySelectorAll(selector);\n return matches.length === 1 && (element === undefined || matches[0] === element);\n } catch {\n return false;\n }\n }\n\n /**\n * Get meaningful classes (filtering out utility classes)\n */\n private static getMeaningfulClasses(element: Element): string[] {\n const classes = Array.from(element.classList);\n\n // Filter out common utility classes\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\n return classes\n .filter((cls) => {\n // Keep semantic classes\n if (cls.length < 3) return false;\n return !utilityPatterns.some((pattern) => pattern.test(cls));\n })\n .slice(0, 2); // Limit to 2 most meaningful classes\n }\n\n /**\n * Optimize the selector path by removing unnecessary parts\n */\n private static optimizePath(path: string[], element: Element, doc: Document): string {\n // Try progressively shorter paths\n for (let i = path.length - 1; i >= 0; i--) {\n const shortPath = path.slice(i).join(' > ');\n try {\n const matches = doc.querySelectorAll(shortPath);\n if (matches.length === 1 && matches[0] === element) {\n return shortPath;\n }\n } catch {\n // Invalid selector, continue\n }\n }\n\n return path.join(' > ');\n }\n\n /**\n * Get a human-readable path description\n */\n static getContextPath(element: Element): string[] {\n const path: string[] = [];\n let current: Element | null = element;\n let depth = 0;\n const maxDepth = 5;\n\n while (current && current !== element.ownerDocument?.body && depth < maxDepth) {\n const tag = current.nodeName.toLowerCase();\n let descriptor = tag;\n\n // Add semantic information\n if (current.id) {\n descriptor = `${tag}#${current.id}`;\n } else if (current.className && typeof current.className === 'string') {\n const firstClass = current.className.split(' ')[0];\n if (firstClass) {\n descriptor = `${tag}.${firstClass}`;\n }\n }\n\n // Add role information\n const role = current.getAttribute('role');\n if (role) {\n descriptor += `[role=\"${role}\"]`;\n }\n\n path.unshift(descriptor);\n current = current.parentElement;\n depth++;\n }\n\n return path;\n }\n}\n","import { SelectorGenerator } from './selectors';\nimport type {\n ElementContext,\n ElementInteraction,\n ExtractedElement,\n ExtractionOptions,\n FilterOptions,\n} from './types';\n\nexport class DOMTraversal {\n /**\n * Check if a node is a Document.\n *\n * `instanceof Document` tests the *calling* realm's constructor, so a\n * document reached through an iframe (frameSelector) always fails it.\n * nodeType is realm-independent — use this everywhere instead.\n */\n static isDocument(node: Document | Element): node is Document {\n return node.nodeType === Node.DOCUMENT_NODE;\n }\n\n /**\n * Check if element is visible\n */\n static isVisible(element: Element): boolean {\n const rect = element.getBoundingClientRect();\n const style = element.ownerDocument?.defaultView?.getComputedStyle(element);\n\n if (!style) return false;\n\n return !!(\n rect.width > 0 &&\n rect.height > 0 &&\n style.display !== 'none' &&\n style.visibility !== 'hidden' &&\n style.opacity !== '0'\n );\n }\n\n /**\n * Check if element is in viewport\n */\n static isInViewport(element: Element): boolean {\n const rect = element.getBoundingClientRect();\n const view = {\n width: element.ownerDocument?.defaultView?.innerWidth || 0,\n height: element.ownerDocument?.defaultView?.innerHeight || 0,\n };\n\n return rect.top < view.height && rect.bottom > 0 && rect.left < view.width && rect.right > 0;\n }\n\n /**\n * Check if element passes filter criteria\n */\n static passesFilter(element: Element, filter: FilterOptions | undefined): boolean {\n if (!filter) return true;\n\n // Check exclude selectors first\n if (filter.excludeSelectors?.length) {\n for (const selector of filter.excludeSelectors) {\n if (element.matches(selector)) return false;\n }\n }\n\n // Check include selectors\n if (filter.includeSelectors?.length) {\n let matches = false;\n for (const selector of filter.includeSelectors) {\n if (element.matches(selector)) {\n matches = true;\n break;\n }\n }\n if (!matches) return false;\n }\n\n // Check tag filters\n if (filter.tags?.length && !filter.tags.includes(element.tagName.toLowerCase())) {\n return false;\n }\n\n // Check text content filters\n const textContent = element.textContent?.toLowerCase() || '';\n if (filter.textContains?.length) {\n let hasText = false;\n for (const text of filter.textContains) {\n if (textContent.includes(text.toLowerCase())) {\n hasText = true;\n break;\n }\n }\n if (!hasText) return false;\n }\n\n // Check text regex patterns\n if (filter.textMatches?.length) {\n let matches = false;\n for (const pattern of filter.textMatches) {\n if (pattern.test(textContent)) {\n matches = true;\n break;\n }\n }\n if (!matches) return false;\n }\n\n // Check required attributes\n if (filter.hasAttributes?.length) {\n for (const attr of filter.hasAttributes) {\n if (!element.hasAttribute(attr)) return false;\n }\n }\n\n // Check attribute values\n if (filter.attributeValues) {\n for (const [attr, value] of Object.entries(filter.attributeValues)) {\n const attrValue = element.getAttribute(attr);\n if (!attrValue) return false;\n\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 }\n\n // Check within selectors\n if (filter.withinSelectors?.length) {\n let isWithin = false;\n for (const selector of filter.withinSelectors) {\n if (element.closest(selector)) {\n isWithin = true;\n break;\n }\n }\n if (!isWithin) return false;\n }\n\n // Check interaction types\n if (filter.interactionTypes?.length) {\n const interaction = DOMTraversal.getInteractionInfo(element);\n let hasInteraction = false;\n for (const type of filter.interactionTypes) {\n if (interaction[type]) {\n hasInteraction = true;\n break;\n }\n }\n if (!hasInteraction) return false;\n }\n\n // Check nearText\n if (filter.nearText) {\n const parent = element.parentElement;\n if (!parent || !parent.textContent?.toLowerCase().includes(filter.nearText.toLowerCase())) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Extract element information\n */\n static extractElement(\n element: Element,\n options: ExtractionOptions,\n depth = 0\n ): ExtractedElement | null {\n // Check depth limit\n if (options.maxDepth !== undefined && depth > options.maxDepth) {\n return null;\n }\n\n // Check visibility\n if (!options.includeHidden && !DOMTraversal.isVisible(element)) {\n return null;\n }\n\n // Check viewport\n if (options.viewportOnly && !DOMTraversal.isInViewport(element)) {\n return null;\n }\n\n // Apply filters\n if (!DOMTraversal.passesFilter(element, options.filter)) {\n return null;\n }\n\n const extracted: ExtractedElement = {\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 // bounds removed to save tokens\n };\n\n // Extract children for semantic elements in full mode\n if (options.mode === 'full' && DOMTraversal.isSemanticContainer(element)) {\n const children: ExtractedElement[] = [];\n\n // Handle shadow DOM\n if (options.includeShadowDOM && element.shadowRoot) {\n const shadowChildren = DOMTraversal.extractChildren(element.shadowRoot, options, depth + 1);\n children.push(...shadowChildren);\n }\n\n // Handle regular children\n const regularChildren = DOMTraversal.extractChildren(element, options, depth + 1);\n children.push(...regularChildren);\n\n if (children.length > 0) {\n extracted.children = children;\n }\n }\n\n return extracted;\n }\n\n /**\n * Extract children elements\n */\n private static extractChildren(\n container: Element | ShadowRoot,\n options: ExtractionOptions,\n depth: number\n ): ExtractedElement[] {\n const children: ExtractedElement[] = [];\n for (const child of Array.from(container.children)) {\n const extracted = DOMTraversal.extractElement(child, options, depth);\n if (extracted) {\n children.push(extracted);\n }\n }\n\n return children;\n }\n\n /**\n * Get relevant attributes for an element\n */\n private static getRelevantAttributes(\n element: Element,\n options: ExtractionOptions\n ): Record<string, string> {\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\n const attributes: Record<string, string> = {};\n const attrTruncate = options.attributeTruncateLength ?? 100;\n const dataAttrTruncate = options.dataAttributeTruncateLength ?? 50;\n\n for (const attr of relevant) {\n const value = element.getAttribute(attr);\n if (value) {\n // Truncate long values based on options\n attributes[attr] =\n value.length > attrTruncate ? `${value.substring(0, attrTruncate)}...` : value;\n }\n }\n\n // Include data attributes\n for (const attr of element.attributes) {\n if (attr.name.startsWith('data-') && !relevant.includes(attr.name)) {\n attributes[attr.name] =\n attr.value.length > dataAttrTruncate\n ? `${attr.value.substring(0, dataAttrTruncate)}...`\n : attr.value;\n }\n }\n\n return attributes;\n }\n\n /**\n * Get element context information\n */\n private static getElementContext(element: Element): ElementContext {\n const context: ElementContext = {\n parentChain: SelectorGenerator.getContextPath(element),\n };\n\n // Find nearest semantic containers\n const form = element.closest('form');\n if (form) {\n context.nearestForm = SelectorGenerator.generateSelectors(form).css;\n }\n\n const section = element.closest('section, [role=\"region\"]');\n if (section) {\n context.nearestSection = SelectorGenerator.generateSelectors(section).css;\n }\n\n const main = element.closest('main, [role=\"main\"]');\n if (main) {\n context.nearestMain = SelectorGenerator.generateSelectors(main).css;\n }\n\n const nav = element.closest('nav, [role=\"navigation\"]');\n if (nav) {\n context.nearestNav = SelectorGenerator.generateSelectors(nav).css;\n }\n\n return context;\n }\n\n /**\n * Get interaction information for an element (compact format)\n */\n private static getInteractionInfo(element: Element): ElementInteraction {\n // Element has no inline on* handlers in lib.dom; they live on GlobalEventHandlers.\n const htmlElement = element as HTMLElement;\n const interaction: ElementInteraction = {};\n\n // Only include true values to reduce token usage\n if (\n htmlElement.onclick ||\n element.getAttribute('onclick') ||\n element.matches('button, a[href], [role=\"button\"], [tabindex]:not([tabindex=\"-1\"])')\n )\n interaction.click = true;\n\n if (\n htmlElement.onchange ||\n element.getAttribute('onchange') ||\n element.matches('input, select, textarea')\n )\n interaction.change = true;\n\n if (htmlElement.onsubmit || element.getAttribute('onsubmit') || element.matches('form'))\n interaction.submit = true;\n\n const triggersNavigation = element.matches('a[href], button[type=\"submit\"]');\n if (triggersNavigation) interaction.nav = true;\n\n const isDisabled =\n element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true';\n if (isDisabled) interaction.disabled = true;\n\n const isHidden = !DOMTraversal.isVisible(element);\n if (isHidden) interaction.hidden = true;\n\n const ariaRole = element.getAttribute('role');\n if (ariaRole) interaction.role = ariaRole;\n\n // Check form association\n if (element.matches('input, textarea, select, button')) {\n // matches() cannot narrow, and instanceof is unsafe here (elements may come\n // from an iframe realm). All four tags carry .form.\n const form = (element as HTMLInputElement).form || element.closest('form');\n if (form) {\n interaction.form = SelectorGenerator.generateSelectors(form).css;\n }\n }\n\n return interaction;\n }\n\n /**\n * Get text content of an element (limited length)\n */\n private static getElementText(element: Element, options?: ExtractionOptions): string {\n // For input elements, get value or placeholder\n if (element.matches('input, textarea')) {\n const input = element as HTMLInputElement;\n return input.value || input.placeholder || '';\n }\n\n // For images, get alt text\n if (element.matches('img')) {\n return (element as HTMLImageElement).alt || '';\n }\n\n // Get text content, but limit length based on options\n const text = element.textContent?.trim() || '';\n const maxLength = options?.textTruncateLength;\n\n if (maxLength && text.length > maxLength) {\n return `${text.substring(0, maxLength)}...`;\n }\n\n return text;\n }\n\n /**\n * Check if element is a semantic container\n */\n private static isSemanticContainer(element: Element): boolean {\n return element.matches(\n 'article, section, nav, aside, main, header, footer, form, ' +\n 'table, ul, ol, dl, figure, details, dialog, [role=\"region\"], ' +\n '[role=\"navigation\"], [role=\"main\"], [role=\"complementary\"]'\n );\n }\n}\n","import { ContentDetection } from './content-detection';\nimport { SelectorGenerator } from './selectors';\nimport { DOMTraversal } from './traversal';\nimport type {\n ExtractedElement,\n ExtractionMode,\n ExtractionOptions,\n FormInfo,\n PageLandmarks,\n PageState,\n SmartDOMResult,\n} from './types';\n\n/**\n * Smart DOM Reader - Full Extraction Approach\n *\n * This class provides complete DOM extraction in a single pass.\n * Use this when you need all information upfront and have sufficient\n * token budget for processing the complete output.\n *\n * Features:\n * - Single-pass extraction of all elements\n * - Two modes: 'interactive' (UI elements) or 'full' (includes content)\n * - Efficient for automation and testing scenarios\n * - Returns complete structured data immediately\n */\nexport class SmartDOMReader {\n private options: ExtractionOptions;\n\n constructor(options: Partial<ExtractionOptions> = {}) {\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 !== undefined && {\n attributeTruncateLength: options.attributeTruncateLength,\n }),\n ...(options.dataAttributeTruncateLength !== undefined && {\n dataAttributeTruncateLength: options.dataAttributeTruncateLength,\n }),\n ...(options.textTruncateLength !== undefined && {\n textTruncateLength: options.textTruncateLength,\n }),\n ...(options.filter !== undefined && { filter: options.filter }),\n };\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(\n rootElement: Document | Element = document,\n runtimeOptions?: Partial<ExtractionOptions>\n ): SmartDOMResult {\n const startTime = Date.now();\n const rootIsDocument = DOMTraversal.isDocument(rootElement);\n const doc = rootIsDocument ? rootElement : rootElement.ownerDocument!;\n\n // Merge runtime options with constructor options\n const options: ExtractionOptions = { ...this.options, ...runtimeOptions };\n\n // Determine the container to search\n // IMPORTANT: Respect the provided rootElement when it's an Element.\n // Previous behavior incorrectly defaulted to the whole document, causing\n // region-scoped extractions to include page-wide data.\n let container: Element | Document = rootIsDocument ? doc : rootElement;\n // Only override container with detected main content when starting from the document.\n if (options.mainContentOnly && rootIsDocument) {\n container = ContentDetection.findMainContent(doc);\n }\n\n // Extract page state\n const pageState = this.extractPageState(doc);\n\n // Extract landmarks\n const landmarks = this.extractLandmarks(doc);\n\n // Extract interactive elements\n const interactive = this.extractInteractiveElements(container, options);\n\n // Build result\n const result: SmartDOMResult = {\n mode: options.mode,\n timestamp: startTime,\n page: pageState,\n landmarks,\n interactive,\n };\n\n // Add semantic elements in full mode\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\n return result;\n }\n\n /**\n * Extract page state information\n */\n private extractPageState(doc: Document): PageState {\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 !== undefined && { hasFocus }),\n };\n }\n\n /**\n * Extract page landmarks\n */\n private extractLandmarks(doc: Document): PageLandmarks {\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 /**\n * Convert elements to selector strings\n */\n private elementsToSelectors(elements: Element[]): string[] {\n return elements.map((el) => SelectorGenerator.generateSelectors(el).css);\n }\n\n private querySelectorAll(\n container: Document | Element | ShadowRoot,\n selector: string,\n includeShadowDOM?: boolean\n ): Element[] {\n const matches = [...container.querySelectorAll(selector)];\n if (!includeShadowDOM) return matches;\n\n if ('shadowRoot' in container && container.shadowRoot) {\n matches.push(...this.querySelectorAll(container.shadowRoot, selector, true));\n }\n\n for (const element of container.querySelectorAll('*')) {\n if (element.shadowRoot) {\n matches.push(...this.querySelectorAll(element.shadowRoot, selector, true));\n }\n }\n return matches;\n }\n\n /**\n * Extract every element matching a selector.\n *\n * DOMTraversal.extractElement already applies the visibility, viewport and\n * filter guards, so pre-filtering here would just repeat its\n * getBoundingClientRect/getComputedStyle work for every element.\n */\n private extractAll(\n container: Element | Document,\n selector: string,\n options: ExtractionOptions\n ): ExtractedElement[] {\n const extracted: ExtractedElement[] = [];\n for (const el of this.querySelectorAll(container, selector, options.includeShadowDOM)) {\n const element = DOMTraversal.extractElement(el, options);\n if (element) extracted.push(element);\n }\n return extracted;\n }\n\n /**\n * Extract interactive elements\n */\n private extractInteractiveElements(\n container: Element | Document,\n options: ExtractionOptions\n ): SmartDOMResult['interactive'] {\n const clickable: ExtractedElement[] = [];\n for (const selector of options.customSelectors ?? []) {\n clickable.push(...this.extractAll(container, selector, options));\n }\n\n return {\n buttons: this.extractAll(\n container,\n 'button, [role=\"button\"], input[type=\"button\"], input[type=\"submit\"]',\n options\n ),\n links: this.extractAll(container, 'a[href]', options),\n inputs: this.extractAll(\n container,\n 'input:not([type=\"button\"]):not([type=\"submit\"]), textarea, select',\n options\n ),\n forms: this.extractForms(container, options),\n clickable,\n };\n }\n\n /**\n * Extract form information\n */\n private extractForms(container: Element | Document, options: ExtractionOptions): FormInfo[] {\n const forms: FormInfo[] = [];\n const formElements = this.querySelectorAll(container, 'form', options.includeShadowDOM);\n\n formElements.forEach((form) => {\n // The form itself never reaches extractElement, so it needs the guard here.\n if (!this.shouldIncludeElement(form, options)) return;\n\n const action = form.getAttribute('action');\n const method = form.getAttribute('method');\n const formInfo: FormInfo = {\n selector: SelectorGenerator.generateSelectors(form).css,\n inputs: this.extractAll(\n form,\n 'input:not([type=\"button\"]):not([type=\"submit\"]), textarea, select',\n options\n ),\n buttons: this.extractAll(\n form,\n 'button, input[type=\"button\"], input[type=\"submit\"]',\n options\n ),\n };\n if (action) formInfo.action = action;\n if (method) formInfo.method = method;\n forms.push(formInfo);\n });\n\n return forms;\n }\n\n /**\n * Extract semantic elements (full mode only)\n */\n private extractSemanticElements(\n container: Element | Document,\n options: ExtractionOptions\n ): NonNullable<SmartDOMResult['semantic']> {\n return {\n headings: this.extractAll(container, 'h1, h2, h3, h4, h5, h6', options),\n images: this.extractAll(container, 'img', options),\n tables: this.extractAll(container, 'table', options),\n lists: this.extractAll(container, 'ul, ol', options),\n articles: this.extractAll(container, 'article, [role=\"article\"]', options),\n };\n }\n\n /**\n * Extract metadata\n */\n private extractMetadata(\n doc: Document,\n container: Element | Document,\n options: ExtractionOptions\n ): NonNullable<SmartDOMResult['metadata']> {\n const allElements = this.querySelectorAll(container, '*', options.includeShadowDOM);\n const extractedElements = this.querySelectorAll(\n container,\n 'button, a, input, textarea, select, h1, h2, h3, h4, h5, h6, img, table, ul, ol, article',\n options.includeShadowDOM\n ).length;\n\n const metadata: NonNullable<SmartDOMResult['metadata']> = {\n totalElements: allElements.length,\n extractedElements,\n };\n\n if (options.mainContentOnly && !DOMTraversal.isDocument(container)) {\n metadata.mainContent = SelectorGenerator.generateSelectors(container).css;\n }\n\n const language = doc.documentElement.getAttribute('lang');\n if (language) {\n metadata.language = language;\n }\n\n return metadata;\n }\n\n /**\n * Check if element should be included based on options\n */\n private shouldIncludeElement(element: Element, options: ExtractionOptions): boolean {\n // Check visibility\n if (!options.includeHidden && !DOMTraversal.isVisible(element)) {\n return false;\n }\n\n // Check viewport\n if (options.viewportOnly && !DOMTraversal.isInViewport(element)) {\n return false;\n }\n\n // Check custom filter\n if (options.filter && !DOMTraversal.passesFilter(element, options.filter)) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Detect errors on the page\n */\n private detectErrors(doc: Document): boolean {\n const errorSelectors = ['.error', '.alert-danger', '[role=\"alert\"]', '.error-message'];\n return errorSelectors.some((sel) => {\n const element = doc.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n }\n\n /**\n * Detect if page is loading\n */\n private detectLoading(doc: Document): boolean {\n const loadingSelectors = ['.loading', '.spinner', '[aria-busy=\"true\"]', '.loader'];\n return loadingSelectors.some((sel) => {\n const element = doc.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n }\n\n /**\n * Detect modal dialogs\n */\n private detectModals(doc: Document): boolean {\n const modalSelectors = ['[role=\"dialog\"]', '.modal', '.popup', '.overlay'];\n return modalSelectors.some((sel) => {\n const element = doc.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n }\n\n /**\n * Get currently focused element\n */\n private getFocusedElement(doc: Document): string | undefined {\n const focused = doc.activeElement;\n if (focused && focused !== doc.body) {\n return SelectorGenerator.generateSelectors(focused).css;\n }\n return undefined;\n }\n\n // ===== Static convenience methods =====\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(\n doc: Document,\n options: Omit<ExtractionOptions, 'mode'> = {}\n ): SmartDOMResult {\n const reader = new SmartDOMReader({\n ...options,\n mode: 'interactive',\n });\n return reader.extract(doc);\n }\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: Document, options: Omit<ExtractionOptions, 'mode'> = {}): SmartDOMResult {\n const reader = new SmartDOMReader({\n ...options,\n mode: 'full',\n });\n return reader.extract(doc);\n }\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(\n element: Element,\n mode: ExtractionMode = 'interactive',\n options: Omit<ExtractionOptions, 'mode'> = {}\n ): SmartDOMResult {\n const reader = new SmartDOMReader({\n ...options,\n mode,\n });\n return reader.extract(element);\n }\n}\n","import { ContentDetection } from './content-detection';\nimport { SmartDOMReader } from './smart-dom-reader';\nimport { SelectorGenerator } from './selectors';\nimport { DOMTraversal } from './traversal';\nimport type {\n ContentExtractionOptions,\n ExtractedContent,\n ExtractionOptions,\n RegionInfo,\n SmartDOMResult,\n StructuralOverview,\n} from './types';\n\nexport 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: Document | Element): StructuralOverview {\n const regions: StructuralOverview['regions'] = {};\n\n // Find header (scoped to root)\n const header = root.querySelector('header, [role=\"banner\"], .header, #header');\n if (header) {\n regions.header = ProgressiveExtractor.analyzeRegion(header);\n }\n\n // Find navigation areas (scoped to root)\n const navs = root.querySelectorAll('nav, [role=\"navigation\"], .nav, .navigation');\n if (navs.length > 0) {\n regions.navigation = Array.from(navs).map((nav) => ProgressiveExtractor.analyzeRegion(nav));\n }\n\n // Find main content\n if (DOMTraversal.isDocument(root)) {\n const main = ContentDetection.findMainContent(root);\n if (main) {\n regions.main = ProgressiveExtractor.analyzeRegion(main);\n // Find sections within main\n const sections = main.querySelectorAll('section, article, [role=\"region\"]');\n if (sections.length > 0) {\n regions.sections = Array.from(sections)\n .filter((section) => !section.closest('nav, header, footer'))\n .map((section) => ProgressiveExtractor.analyzeRegion(section));\n }\n }\n } else {\n // When scoped to an Element, treat the element itself as the main region\n regions.main = ProgressiveExtractor.analyzeRegion(root);\n const sections = root.querySelectorAll('section, article, [role=\"region\"]');\n if (sections.length > 0) {\n regions.sections = Array.from(sections)\n .filter((section) => !section.closest('nav, header, footer'))\n .map((section) => ProgressiveExtractor.analyzeRegion(section));\n }\n }\n\n // Find sidebars (scoped)\n const sidebars = root.querySelectorAll('aside, [role=\"complementary\"], .sidebar, #sidebar');\n if (sidebars.length > 0) {\n regions.sidebar = Array.from(sidebars).map((sidebar) =>\n ProgressiveExtractor.analyzeRegion(sidebar)\n );\n }\n\n // Find footer (scoped)\n const footer = root.querySelector('footer, [role=\"contentinfo\"], .footer, #footer');\n if (footer) {\n regions.footer = ProgressiveExtractor.analyzeRegion(footer);\n }\n\n // Find modals/dialogs (scoped)\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) {\n regions.modals = visibleModals.map((modal) => ProgressiveExtractor.analyzeRegion(modal));\n }\n\n // Extract form information (scoped)\n const forms = ProgressiveExtractor.extractFormOverview(root);\n\n // Calculate summary statistics (scoped)\n const summary = ProgressiveExtractor.calculateSummary(root, regions, forms);\n\n // Generate AI-friendly suggestions\n const suggestions = ProgressiveExtractor.generateSuggestions(regions, summary);\n\n return { regions, forms, summary, suggestions };\n }\n\n /**\n * Step 2: Extract detailed information from a specific region\n */\n static extractRegion(\n selector: string,\n doc: Document,\n options: Partial<ExtractionOptions> = {}\n ): SmartDOMResult | null {\n const element = doc.querySelector(selector);\n if (!element) return null;\n\n const reader = new SmartDOMReader(options);\n\n // Extract from the specific element/region\n return reader.extract(element, options);\n }\n\n /**\n * Step 3: Extract readable content from a region\n */\n static extractContent(\n selector: string,\n doc: Document,\n options: ContentExtractionOptions = {}\n ): ExtractedContent | null {\n const element = doc.querySelector(selector);\n if (!element) return null;\n\n const result: ExtractedContent = {\n selector,\n text: {},\n metadata: {\n wordCount: 0,\n hasInteractive: false,\n },\n };\n\n // Extract headings\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\n // Extract paragraphs\n const paragraphs = element.querySelectorAll('p');\n if (paragraphs.length > 0) {\n result.text.paragraphs = Array.from(paragraphs)\n .map((p) => ProgressiveExtractor.getTextContent(p, options.maxTextLength))\n .filter((text) => text.length > 0);\n }\n\n // Extract lists\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() as 'ul' | 'ol',\n items: Array.from(list.querySelectorAll('li')).map((li) =>\n ProgressiveExtractor.getTextContent(li, options.maxTextLength)\n ),\n }));\n }\n\n // Extract tables\n if (options.includeTables !== false) {\n const tables = element.querySelectorAll('table');\n result.tables = Array.from(tables).map((table) => {\n const headers = Array.from(table.querySelectorAll('th')).map((th) =>\n ProgressiveExtractor.getTextContent(th)\n );\n const rows = Array.from(table.querySelectorAll('tr'))\n .filter((tr) => tr.querySelector('td'))\n .map((tr) =>\n Array.from(tr.querySelectorAll('td')).map((td) =>\n ProgressiveExtractor.getTextContent(td)\n )\n );\n return { headers, rows };\n });\n }\n\n // Extract media\n if (options.includeMedia !== false) {\n const images = element.querySelectorAll('img');\n const videos = element.querySelectorAll('video');\n const audios = element.querySelectorAll('audio');\n\n result.media = [\n ...Array.from(images).map((img) => {\n const item: { type: 'img'; alt?: string; src?: string } = { 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'; src?: string } = { 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'; src?: string } = { type: 'audio' };\n const src = audio.getAttribute('src');\n if (src) item.src = src;\n return item;\n }),\n ];\n }\n\n // Calculate metadata\n const allText = element.textContent || '';\n result.metadata.wordCount = allText.trim().split(/\\s+/).length;\n result.metadata.hasInteractive =\n element.querySelectorAll('button, a, input, textarea, select').length > 0;\n\n return result;\n }\n\n /**\n * Analyze a region and extract summary information\n */\n private static analyzeRegion(element: Element): RegionInfo {\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\n const interactiveCount = buttons.length + links.length + inputs.length;\n\n // Get label from aria-label, aria-labelledby, or heading\n let label: string | undefined;\n const ariaLabel = element.getAttribute('aria-label');\n if (ariaLabel) {\n 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) {\n label = labelElement.textContent?.trim();\n }\n }\n } else {\n const heading = element.querySelector('h1, h2, h3');\n if (heading) {\n label = heading.textContent?.trim();\n }\n }\n\n // Get text preview\n const textContent = element.textContent?.trim() || '';\n const textPreview =\n textContent.length > 50 ? `${textContent.substring(0, 50)}...` : textContent;\n\n const regionInfo: 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\n if (label) regionInfo.label = label;\n\n const role = element.getAttribute('role');\n if (role) regionInfo.role = role;\n\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\n return regionInfo;\n }\n\n /**\n * Extract overview of forms on the page\n */\n private static extractFormOverview(root: Document | Element): StructuralOverview['forms'] {\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\n // Determine which region the form is in\n let location = 'unknown';\n if (form.closest('header, [role=\"banner\"]')) {\n location = 'header';\n } else if (form.closest('nav, [role=\"navigation\"]')) {\n location = 'navigation';\n } else if (form.closest('main, [role=\"main\"]')) {\n location = 'main';\n } else if (form.closest('aside, [role=\"complementary\"]')) {\n location = 'sidebar';\n } else if (form.closest('footer, [role=\"contentinfo\"]')) {\n location = 'footer';\n }\n\n // Infer purpose from form attributes and content\n let purpose: string | undefined;\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 const hasSearch = form.querySelector('input[type=\"search\"]');\n\n if (hasSearch || formId?.includes('search') || formClass?.includes('search')) {\n purpose = 'search';\n } else if (hasPassword && hasEmail) {\n purpose = 'login';\n } else if (hasPassword) {\n purpose = 'authentication';\n } else if (formId?.includes('contact') || formClass?.includes('contact')) {\n purpose = 'contact';\n } else if (formId?.includes('subscribe') || formClass?.includes('subscribe')) {\n purpose = 'subscription';\n } else if (formAction?.includes('checkout') || formClass?.includes('checkout')) {\n purpose = 'checkout';\n }\n\n const formOverview: {\n selector: string;\n location: string;\n inputCount: number;\n purpose?: string;\n } = {\n selector,\n location,\n inputCount: inputs.length,\n };\n\n if (purpose) formOverview.purpose = purpose;\n\n return formOverview;\n });\n }\n\n /**\n * Calculate summary statistics\n */\n private static calculateSummary(\n root: Document | Element,\n regions: StructuralOverview['regions'],\n forms: StructuralOverview['forms']\n ): StructuralOverview['summary'] {\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\n // Check for errors\n const errorSelectors = ['.error', '.alert-danger', '[role=\"alert\"]'];\n const hasErrors = errorSelectors.some((sel) => {\n const element = root.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n\n // Check for loading\n const loadingSelectors = ['.loading', '.spinner', '[aria-busy=\"true\"]'];\n const isLoading = loadingSelectors.some((sel) => {\n const element = root.querySelector(sel);\n return element ? DOMTraversal.isVisible(element) : false;\n });\n\n const summary: StructuralOverview['summary'] = {\n totalInteractive: allInteractive.length,\n totalForms: forms.length,\n totalSections: allSections.length,\n hasModals,\n hasErrors,\n isLoading,\n };\n\n const mainContentSelector = regions.main?.selector;\n if (mainContentSelector) {\n summary.mainContentSelector = mainContentSelector;\n }\n\n return summary;\n }\n\n /**\n * Generate AI-friendly suggestions\n */\n private static generateSuggestions(\n regions: StructuralOverview['regions'],\n summary: StructuralOverview['summary']\n ): string[] {\n const suggestions: string[] = [];\n\n if (summary.hasErrors) {\n suggestions.push('Page has error indicators - check error messages before interacting');\n }\n\n if (summary.isLoading) {\n suggestions.push('Page appears to be loading - wait or check loading state');\n }\n\n if (summary.hasModals) {\n suggestions.push('Modal/dialog is open - may need to interact with or close it first');\n }\n\n if (regions.main && regions.main.interactiveCount > 10) {\n suggestions.push(\n `Main content has ${regions.main.interactiveCount} interactive elements - consider filtering`\n );\n }\n\n if (summary.totalForms > 0) {\n suggestions.push(`Found ${summary.totalForms} form(s) on the page`);\n }\n\n if (!regions.main) {\n suggestions.push('No clear main content area detected - may need to explore regions');\n }\n\n return suggestions;\n }\n\n /**\n * Get text content with optional truncation\n */\n private static getTextContent(element: Element, maxLength?: number): string {\n const text = element.textContent?.trim() || '';\n if (maxLength && text.length > maxLength) {\n return `${text.substring(0, maxLength)}...`;\n }\n return text;\n }\n}\n"],"mappings":";AAAA,IAAa,mBAAb,MAAa,iBAAiB;;;;;CAK5B,OAAO,gBAAgB,KAAwB;EAE7C,MAAM,cAAc,IAAI,cAAc,wBAAsB;EAC5D,IAAI,aACF,OAAO;EAIT,IAAI,CAAC,IAAI,MACP,OAAO,IAAI;EAGb,OAAO,iBAAiB,kBAAkB,IAAI,KAAK;;;;;CAMrD,OAAe,kBAAkB,aAA+B;EAC9D,MAAM,aAAwB,EAAE;EAGhC,iBAAiB,kBAAkB,aAAa,YAAY,GAAS;EAErE,IAAI,WAAW,WAAW,GACxB,OAAO;EAIT,WAAW,MACR,GAAG,MACF,iBAAiB,sBAAsB,EAAE,GAAG,iBAAiB,sBAAsB,EAAE,CACxF;EAGD,IAAI,gBAAgB,WAAW;EAC/B,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;GAC1C,MAAM,YAAY,WAAW;GAI7B,IACE,CAHqB,WAAW,MAAM,OAAO,MAAM,MAAM,KAAK,MAAM,SAAS,UAAU,CAAC,IAIxF,iBAAiB,sBAAsB,UAAU,GAC/C,iBAAiB,sBAAsB,cAAc,EAEvD,gBAAgB;;EAIpB,OAAO;;;;;CAMT,OAAe,kBACb,SACA,YACA,UACM;EAEN,IADc,iBAAiB,sBAAsB,QAC5C,IAAI,UACX,WAAW,KAAK,QAAQ;EAI1B,MAAM,KAAK,QAAQ,SAAS,CAAC,SAAS,UAAU;GAC9C,iBAAiB,kBAAkB,OAAO,YAAY,SAAS;IAC/D;;;;;CAMJ,OAAO,sBAAsB,SAA0B;EACrD,IAAI,QAAQ;EAGZ,MAAM,kBAAkB;GACtB;GACA;GACA;GACA;GACA;GACA;GACA;GACD;EACD,MAAM,cAAc;GAAC;GAAW;GAAQ;GAAW;GAAQ;GAAQ;EAGnE,gBAAgB,SAAS,QAAQ;GAC/B,IAAI,QAAQ,UAAU,SAAS,IAAI,EACjC,SAAS;IAEX;EAGF,YAAY,SAAS,OAAO;GAC1B,IAAI,QAAQ,IAAI,aAAa,CAAC,SAAS,GAAG,EACxC,SAAS;IAEX;EAGF,MAAM,MAAM,QAAQ,QAAQ,aAAa;EAEzC,IAAI;GADmB;GAAW;GAAQ;GACzB,CAAC,SAAS,IAAI,EAC7B,SAAS;EAIX,MAAM,aAAa,QAAQ,qBAAqB,IAAI,CAAC;EACrD,SAAS,KAAK,IAAI,aAAa,GAAG,GAAG;EAGrC,MAAM,WAAW,QAAQ,iBAAiB,aAAa,CAAC;EACxD,SAAS,KAAK,IAAI,WAAW,GAAG,EAAE;EAGlC,MAAM,aAAa,QAAQ,aAAa,MAAM,CAAC,UAAU;EACzD,IAAI,aAAa,KACf,SAAS,KAAK,IAAI,KAAK,MAAM,aAAa,IAAI,GAAG,GAAG,GAAG;EAIzD,MAAM,cAAc,iBAAiB,qBAAqB,QAAQ;EAClE,IAAI,cAAc,IAChB,SAAS;OACJ,IAAI,cAAc,IACvB,SAAS;EAIX,IACE,QAAQ,aAAa,YAAY,IACjC,QAAQ,aAAa,eAAe,IACpC,QAAQ,aAAa,WAAW,EAEhC,SAAS;EAIX,MAAM,OAAO,QAAQ,aAAa,OAAO;EACzC,IAAI,SAAS,UAAU,SAAS,WAC9B,SAAS;EAIX,IACE,QAAQ,QACN,gFACD,EAED,SAAS;EAKX,IADc,QAAQ,qBAAqB,OAAO,CAAC,SACvC,GACV,SAAS;EAGX,OAAO,KAAK,IAAI,GAAG,MAAM;;;;;CAM3B,OAAe,qBAAqB,SAA0B;EAC5D,MAAM,QAAQ,QAAQ,qBAAqB,IAAI;EAC/C,IAAI,iBAAiB;EAErB,KAAK,MAAM,QAAQ,MAAM,KAAK,MAAM,EAClC,kBAAkB,KAAK,aAAa,UAAU;EAGhD,MAAM,kBAAkB,QAAQ,aAAa,UAAU;EACvD,OAAO,iBAAiB;;;;;CAM1B,OAAO,aAAa,SAA2B;EAI7C,IAHY,QAAQ,QAAQ,aAGrB,KAAK,SAAS,QAAQ,aAAa,OAAO,KAAK,cACpD,OAAO;EAIT,MAAM,cAAc;GAAC;GAAQ;GAAS;GAAY;GAAW;EAE7D,MAAM,eAAe,GAAG,QAAQ,UAAU,GAAG,QAAQ,KAAK,aAAa;EACvE,OAAO,YAAY,MAAM,YAAY,QAAQ,KAAK,aAAa,CAAC;;;;;CAMlE,OAAO,gBAAgB,SAA2B;EAIhD,IAHY,QAAQ,QAAQ,aAGrB,KAAK,WAAW,QAAQ,aAAa,OAAO,KAAK,iBACtD,OAAO;EAIT,MAAM,wBAAwB;GAAC;GAAY;GAAW;GAAY;GAAkB;GAAU;EAE9F,MAAM,eAAe,GAAG,QAAQ,UAAU,GAAG,QAAQ,KAAK,aAAa;EACvE,OAAO,sBAAsB,MAAM,YAAY,QAAQ,KAAK,aAAa,CAAC;;;;;CAM5E,OAAO,gBAAgB,KAA0C;EAC/D,MAAM,YAAuC;GAC3C,YAAY,EAAE;GACd,MAAM,EAAE;GACR,eAAe,EAAE;GACjB,aAAa,EAAE;GACf,QAAQ,EAAE;GACV,QAAQ,EAAE;GACV,MAAM,EAAE;GACR,QAAQ,EAAE;GACX;EAcD,KAAK,MAAM,CAAC,UAAU,aAAa,OAAO,QAAQ;GAVhD,YAAY;GACZ,MAAM;GACN,eAAe;GACf,aAAa;GACb,QAAQ;GACR,QAAQ;GACR,MAAM;GACN,QAAQ;GAGyD,CAAC,EAAE;GACpE,MAAM,WAAW,IAAI,iBAAiB,SAAS;GAC/C,UAAU,YAAY,MAAM,KAAK,SAAS;;EAG5C,OAAO;;;;;AC5OX,SAAS,SAAS,MAA0B,KAAsB;CAChE,MAAM,KAAK,QAAQ,IAAI,MAAM;CAC7B,IAAI,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO;CAGpC,MAAM,WAAW;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;CACD,MAAM,QAAQ,EAAE,aAAa;CAC7B,MAAM,MAAM,SAAS,KAAK,OAAO;EAAE;EAAG,GAAG,MAAM,QAAQ,EAAE;EAAE,EAAE,CAAC,MAAM,MAAM,EAAE,IAAI,GAAG;CACnF,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,IAAK,CAAC;CAChD,IAAI,OAAO,IAAI,IAAI,MAAM;EACvB,MAAM,aAAa,KAAK,IAAI,IAAI,MAAM,OAAO,EAAE;EAC/C,MAAM,QAAQ,KAAK,IAAI,GAAG,IAAI,IAAI,KAAK,MAAM,aAAa,EAAE,CAAC;EAC7D,MAAM,MAAM,KAAK,IAAI,EAAE,QAAQ,QAAQ,WAAW;EAClD,OAAO,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC;;CAGvE,MAAM,QAAQ,EAAE,MAAM,GAAG,IAAI;CAC7B,MAAM,YAAY,MAAM,YAAY,IAAI;CACxC,OAAO,GAAG,YAAY,KAAK,MAAM,MAAM,GAAG,UAAU,GAAG,MAAM;;AAG/D,SAAS,OAAO,OAAuB;CACrC,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,IAAK,IAAI,KAAM,MAAM,WAAW,EAAE;CAEzE,OAAO,QAAQ,MAAM,GAAG,SAAS,GAAG;;AAGtC,SAAS,cAAc,KAAqB;CAC1C,QAAQ,KAAR;EACE,KAAK,UACH,OAAO;EACT,KAAK,cACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,YACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,SACE,OAAO;;;AAIb,SAAS,YAAY,IAAsB,MAAsC;CAC/E,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,YAAY,WAAW,MAAM,iBAAiB,GAAG;CACpF,MAAM,MAAM,GAAG,UAAU,OAAO;CAChC,MAAM,MAAM,GAAG,IAAI,aAAa;CAChC,MAAM,SAAS,GAAG,aAAa,SAC3B,WACA,GAAG,aAAa,QACd,UACA,GAAG,aAAa,SACd,WACA,KAAA;CACR,MAAM,aAAa,SAAS,KAAK,OAAO,KAAK;CAC7C,OAAO,KAAK,IAAI,aAAa,CAAC,IAAI,OAAO,YAAY,OAAO,IAAI,IAAI;;AAGtE,SAAS,uBAAuB,OAA8C;CAC5E,MAAM,MAAgB,EAAE;CACxB,IAAI,KAAK,GAAG,MAAM,QAAQ,KAAK,MAAM,EAAE,UAAU,OAAO,GAAG,CAAC;CAC5D,IAAI,KAAK,GAAG,MAAM,MAAM,KAAK,MAAM,EAAE,UAAU,OAAO,GAAG,CAAC;CAC1D,IAAI,KAAK,GAAG,MAAM,OAAO,KAAK,MAAM,EAAE,UAAU,OAAO,GAAG,CAAC;CAC3D,IAAI,KAAK,GAAG,MAAM,UAAU,KAAK,MAAM,EAAE,UAAU,OAAO,GAAG,CAAC;CAC9D,MAAM,QAAQ,IAAI,UAAU;CAC5B,MAAM,UAAU,IAAI,QAAQ,MAAM,EAAE,WAAW,IAAI,CAAC,CAAC;CACrD,MAAM,cAAc,IAAI,QAAQ,MAAM,iBAAiB,KAAK,EAAE,CAAC,CAAC;CAChE,MAAM,WAAW,IAAI,QAAQ,MAAM,eAAe,KAAK,EAAE,CAAC,CAAC;CAC3D,MAAM,SAAS,UAAU;CAGzB,OAAO,qBAFW,KAAK,MAAO,SAAS,QAAS,IAEX,CAAC,6BADvB,KAAK,MAAO,WAAW,QAAS,IAC0B,CAAC;;AAG5E,SAAS,kBACP,OACA,MACQ;CACR,MAAM,QAAkB,EAAE;CAE1B,MAAM,SAAY,QAChB,OAAO,MAAM,gBAAgB,WAAW,IAAI,MAAM,GAAG,KAAK,YAAY,GAAG;CAE3E,IAAI,MAAM,QAAQ,QAAQ;EACxB,MAAM,KAAK,WAAW;EACtB,KAAK,MAAM,MAAM,MAAM,MAAM,QAAQ,EAAE,MAAM,KAAK,YAAY,IAAI,KAAK,CAAC;;CAE1E,IAAI,MAAM,MAAM,QAAQ;EACtB,MAAM,KAAK,SAAS;EACpB,KAAK,MAAM,MAAM,MAAM,MAAM,MAAM,EAAE,MAAM,KAAK,YAAY,IAAI,KAAK,CAAC;;CAExE,IAAI,MAAM,OAAO,QAAQ;EACvB,MAAM,KAAK,UAAU;EACrB,KAAK,MAAM,MAAM,MAAM,MAAM,OAAO,EAAE,MAAM,KAAK,YAAY,IAAI,KAAK,CAAC;;CAEzE,IAAI,MAAM,UAAU,QAAQ;EAC1B,MAAM,KAAK,mBAAmB;EAC9B,KAAK,MAAM,MAAM,MAAM,MAAM,UAAU,EAAE,MAAM,KAAK,YAAY,IAAI,KAAK,CAAC;;CAE5E,IAAI,MAAM,MAAM,QAAQ;EACtB,MAAM,KAAK,SAAS;EACpB,KAAK,MAAM,KAAK,MAAM,MAAM,MAAM,EAChC,MAAM,KAAK,kBAAkB,EAAE,UAAU,IAAI,UAAU,EAAE,UAAU,IAAI,OAAO,EAAE,SAAS,IAAI;;CAIjG,OAAO,MAAM,KAAK,KAAK;;AAGzB,SAAS,iBAAiB,QAA4B;CACpD,MAAM,OAAO,cAAc,SAAS;CACpC,MAAM,KAAK,OAAO,GAAG,OAAO,SAAS,GAAG,OAAO,SAAS,GAAG,GAAG,OAAO,QAAQ,KAAK;CAClF,MAAM,QAAQ,OAAO,QAAQ,IAAI,OAAO,UAAU;CAClD,MAAM,QAAkB,EAAE;CAC1B,IAAI,OAAO,aAAa,MAAM,KAAK,GAAG,OAAO,YAAY,UAAU;CACnE,IAAI,OAAO,WAAW,MAAM,KAAK,GAAG,OAAO,UAAU,QAAQ;CAC7D,IAAI,OAAO,YAAY,MAAM,KAAK,GAAG,OAAO,WAAW,SAAS;CAChE,IAAI,OAAO,aAAa,MAAM,KAAK,IAAI,SAAS,OAAO,aAAa,GAAG,CAAC,GAAG;CAC3E,MAAM,YAAY,MAAM,SAAS,MAAM,MAAM,KAAK,KAAK,KAAK;CAC5D,OAAO,GAAG,KAAK,GAAG,MAAM,OAAO,OAAO,SAAS,MAAM,GAAG,GAAG;;AAG7D,SAAS,QAAQ,MAAc,MAAiB,OAAO,WAAmB;CAOxE,OAAO,SANO,CACZ,MAAM,QAAQ,UAAU,UAAU,KAAK,MAAM,CAAC,KAAK,MACnD,MAAM,MAAM,QAAQ,UAAU,KAAK,IAAI,CAAC,KAAK,KAC9C,CACE,OAAO,QAAQ,CACf,KAAK,IACa,CAAC,QAAQ,KAAK,cAAc,KAAK,SAAS,KAAK;;AAGtE,SAAS,UAAU,GAAmB;CACpC,OAAO,EACJ,QAAQ,MAAM,QAAQ,CACtB,QAAQ,MAAM,OAAO,CACrB,QAAQ,MAAM,OAAO,CACrB,QAAQ,MAAM,SAAS;;AAG5B,IAAa,oBAAb,MAA+B;CAC7B,OAAO,UACL,UACA,QAA+B,EAAE,EACjC,MACQ;EACR,MAAM,QAAkB,EAAE;EAC1B,MAAM,KAAK,iBAAiB;EAC5B,IAAI,MAAM,SAAS,MAAM,KAAK;GAC5B,MAAM,KAAK,UAAU,MAAM,SAAS,KAAK,MAAM,CAAC;GAChD,MAAM,KAAK,QAAQ,MAAM,OAAO,KAAK,MAAM,CAAC;;EAE9C,MAAM,KAAK,GAAG;EAEd,MAAM,UAAU,SAAS;EACzB,MAAM,UAAkE;GACtE,CAAC,UAAU,QAAQ,OAAO;GAC1B,CAAC,cAAc,QAAQ,WAAW;GAClC,CAAC,QAAQ,QAAQ,KAAK;GACtB,CAAC,YAAY,QAAQ,SAAS;GAC9B,CAAC,WAAW,QAAQ,QAAQ;GAC5B,CAAC,UAAU,QAAQ,OAAO;GAC1B,CAAC,UAAU,QAAQ,OAAO;GAC3B;EAED,KAAK,MAAM,CAAC,KAAK,UAAU,SAAS;GAClC,IAAI,CAAC,OAAO;GACZ,MAAM,OAAO,cAAc,IAAI;GAC/B,IAAI,MAAM,QAAQ,MAAM,EAAE;IACxB,IAAI,CAAC,MAAM,QAAQ;IACnB,MAAM,KAAK,MAAM,KAAK,GAAG,WAAW,IAAI,GAAG;IAC3C,KAAK,MAAM,UAAU,OAAO,MAAM,KAAK,iBAAiB,OAAO,CAAC;UAC3D;IACL,MAAM,KAAK,MAAM,KAAK,GAAG,WAAW,IAAI,GAAG;IAC3C,MAAM,KAAK,iBAAiB,MAAM,CAAC;;GAErC,MAAM,KAAK,GAAG;;EAIhB,IAAI,SAAS,aAAa,QAAQ;GAChC,MAAM,KAAK,iBAAiB;GAC5B,KAAK,MAAM,KAAK,SAAS,aAAa,MAAM,KAAK,KAAK,IAAI;GAC1D,MAAM,KAAK,GAAG;;EAGhB,MAAM,KACJ,yGACD;EAGD,OAAO,QADM,MAAM,KAAK,KACL,EAAE,MAAM,UAAU;;CAGvC,OAAO,OAAO,QAAwB,OAA8B,EAAE,EAAE,MAAyB;EAC/F,MAAM,QAAkB,EAAE;EAC1B,MAAM,KAAK,mBAAmB;EAC9B,IAAI,MAAM,SAAS,MAAM,KAAK;GAC5B,MAAM,KAAK,UAAU,MAAM,SAAS,KAAK,MAAM,CAAC;GAChD,MAAM,KAAK,QAAQ,MAAM,OAAO,KAAK,MAAM,CAAC;;EAE9C,MAAM,KAAK,GAAG;EAEd,MAAM,QAAQ,OAAO;EAErB,IAAI,OAAO,MAAM;GACf,MAAM,KAAK;IACT,OAAO,KAAK,YAAY,gBAAgB;IACxC,OAAO,KAAK,YAAY,iBAAiB;IACzC,OAAO,KAAK,YAAY,gBAAgB;IACzC;GACD,MAAM,KAAK,eAAe,GAAG,KAAK,KAAK,GAAG;;EAG5C,MAAM,UAAoB,EAAE;EAC5B,MAAM,SAAS,QAAoB,MAAM,IAAI,SAAS;EACtD,QAAQ,KAAK,GAAG,MAAM,MAAM,QAAQ,CAAC,UAAU;EAC/C,QAAQ,KAAK,GAAG,MAAM,MAAM,MAAM,CAAC,QAAQ;EAC3C,QAAQ,KAAK,GAAG,MAAM,MAAM,OAAO,CAAC,SAAS;EAC7C,IAAI,MAAM,OAAO,QAAQ,QAAQ,KAAK,GAAG,MAAM,MAAM,MAAM,CAAC,QAAQ;EACpE,MAAM,KAAK,YAAY,QAAQ,KAAK,KAAK,GAAG;EAC5C,MAAM,KAAK,uBAAuB,MAAM,CAAC;EACzC,MAAM,KAAK,GAAG;EAEd,MAAM,KAAK,kBAAkB,OAAO,KAAK,CAAC;EAC1C,MAAM,KAAK,GAAG;EACd,MAAM,KACJ,oLACD;EAGD,OAAO,QADM,MAAM,KAAK,KACL,EAAE,MAAM,UAAU;;CAGvC,OAAO,QACL,SACA,OAA8B,EAAE,EAChC,MACQ;EACR,MAAM,QAAkB,EAAE;EAC1B,MAAM,KAAK,YAAY;EACvB,MAAM,KAAK,eAAe,QAAQ,SAAS,IAAI;EAC/C,MAAM,KAAK,GAAG;EAEd,IAAI,QAAQ,KAAK,UAAU,QAAQ;GACjC,MAAM,KAAK,YAAY;GACvB,KAAK,MAAM,KAAK,QAAQ,KAAK,UAC3B,MAAM,KAAK,MAAM,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,KAAK,iBAAiB,IAAI,GAAG;GAC7E,MAAM,KAAK,GAAG;;EAEhB,IAAI,QAAQ,KAAK,YAAY,QAAQ;GACnC,MAAM,QACJ,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc,QAAQ,KAAK,WAAW;GACpF,MAAM,KAAK,cAAc;GACzB,KAAK,MAAM,KAAK,QAAQ,KAAK,WAAW,MAAM,GAAG,MAAM,EACrD,MAAM,KAAK,KAAK,SAAS,GAAG,KAAK,iBAAiB,IAAI,GAAG;GAC3D,MAAM,KAAK,GAAG;;EAEhB,IAAI,QAAQ,KAAK,OAAO,QAAQ;GAC9B,MAAM,KAAK,SAAS;GACpB,KAAK,MAAM,QAAQ,QAAQ,KAAK,OAAO;IACrC,MAAM,KAAK,KAAK,KAAK,KAAK,aAAa,CAAC,GAAG;IAC3C,MAAM,QAAQ,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc,KAAK,MAAM;IACnF,KAAK,MAAM,QAAQ,KAAK,MAAM,MAAM,GAAG,MAAM,EAC3C,MAAM,KAAK,OAAO,SAAS,MAAM,KAAK,iBAAiB,IAAI,GAAG;;GAElE,MAAM,KAAK,GAAG;;EAGhB,IAAI,QAAQ,QAAQ,QAAQ;GAC1B,MAAM,KAAK,UAAU;GACrB,KAAK,MAAM,KAAK,QAAQ,QAAQ;IAC9B,MAAM,KAAK,cAAc,EAAE,QAAQ,KAAK,MAAM,GAAG;IACjD,MAAM,QAAQ,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc,EAAE,KAAK;IAC/E,KAAK,MAAM,OAAO,EAAE,KAAK,MAAM,GAAG,MAAM,EAAE,MAAM,KAAK,OAAO,IAAI,KAAK,MAAM,GAAG;;GAEhF,MAAM,KAAK,GAAG;;EAGhB,IAAI,QAAQ,OAAO,QAAQ;GACzB,MAAM,KAAK,SAAS;GACpB,MAAM,QAAQ,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc,QAAQ,MAAM;GACtF,KAAK,MAAM,KAAK,QAAQ,MAAM,MAAM,GAAG,MAAM,EAC3C,MAAM,KAAK,KAAK,EAAE,KAAK,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,GAAG,EAAE,MAAM,KAAK,EAAE,QAAQ,KAAK,MAAM,CAAC;GAE7F,MAAM,KAAK,GAAG;;EAGhB,MAAM,KACJ,kGACD;EAGD,OAAO,QADM,MAAM,KAAK,KACL,EAAE,MAAM,UAAU;;;AAIzC,SAAS,WAAW,GAAmB;CACrC,OAAO,EAAE,OAAO,EAAE,CAAC,aAAa,GAAG,EAAE,MAAM,EAAE;;;;AC3U/C,IAAa,oBAAb,MAAa,kBAAkB;;;;CAI7B,OAAO,kBAAkB,SAAmC;EAC1D,MAAM,MAAM,QAAQ,iBAAiB;EACrC,MAAM,aAAyC,EAAE;EAGjD,IAAI,QAAQ,MAAM,kBAAkB,WAAW,QAAQ,IAAI,IAAI,EAC7D,WAAW,KAAK;GAAE,MAAM;GAAM,OAAO,IAAI,IAAI,OAAO,QAAQ,GAAG;GAAI,OAAO;GAAK,CAAC;EAIlF,MAAM,SAAS,kBAAkB,cAAc,QAAQ;EACvD,IAAI,QAAQ;GACV,MAAM,IAAI,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,MAAM,CAAC;GACvD,WAAW,KAAK;IACd,MAAM;IACN,OAAO;IACP,OAAO,MAAM,kBAAkB,iBAAiB,GAAG,IAAI,GAAG,IAAI;IAC/D,CAAC;;EAIJ,MAAM,OAAO,QAAQ,aAAa,OAAO;EACzC,MAAM,OAAO,QAAQ,aAAa,aAAa;EAC/C,IAAI,QAAQ,MAAM;GAChB,MAAM,IAAI,UAAU,IAAI,OAAO,KAAK,CAAC,iBAAiB,IAAI,OAAO,KAAK,CAAC;GACvE,WAAW,KAAK;IACd,MAAM;IACN,OAAO;IACP,OAAO,MAAM,kBAAkB,iBAAiB,GAAG,IAAI,GAAG,IAAI;IAC/D,CAAC;;EAIJ,MAAM,WAAW,QAAQ,aAAa,OAAO;EAC7C,IAAI,UAAU;GACZ,MAAM,IAAI,UAAU,IAAI,OAAO,SAAS,CAAC;GACzC,WAAW,KAAK;IACd,MAAM;IACN,OAAO;IACP,OAAO,MAAM,kBAAkB,iBAAiB,GAAG,IAAI,GAAG,IAAI;IAC/D,CAAC;;EAIJ,MAAM,UAAU,kBAAkB,oBAAoB,SAAS,IAAI;EACnE,MAAM,qBAAqB,QAAQ,MAAM,gBAAgB,IAAI,EAAE,EAAE,SAAS;EAC1E,MAAM,aAAa,QAAQ,SAAS,IAAI,GAAG,IAAI;EAC/C,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,aAAa,kBAAkB;EAClE,WAAW,KAAK;GAAE,MAAM;GAAc,OAAO;GAAS,OAAO;GAAW,CAAC;EAGzE,MAAM,QAAQ,kBAAkB,cAAc,SAAS,IAAI;EAC3D,WAAW,KAAK;GAAE,MAAM;GAAS,OAAO;GAAO,OAAO;GAAI,CAAC;EAG3D,MAAM,YAAY,kBAAkB,0BAA0B,QAAQ;EACtE,IAAI,WAAW,WAAW,KAAK;GAAE,MAAM;GAAQ,OAAO;GAAW,OAAO;GAAI,CAAC;EAG7E,WAAW,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;EAU5C,MAAM,WAA4B;GAChC,KARA,WAAW,MACR,MACC,EAAE,SAAS,WACX,EAAE,SAAS,UACX,kBAAkB,iBAAiB,EAAE,OAAO,KAAK,QAAQ,CAC5D,EAAE,SAAS;GAIZ;GACA;GACD;EAED,IAAI,WAAW,SAAS,YAAY;EACpC,IAAI,QAAQ,SAAS,aAAa,OAAO;EACzC,IAAI,MAAM,SAAS,YAAY;EAE/B,OAAO;;;;;CAMT,OAAe,oBAAoB,SAAkB,KAAuB;EAE1E,IAAI,QAAQ,MAAM,kBAAkB,WAAW,QAAQ,IAAI,IAAI,EAC7D,OAAO,IAAI,IAAI,OAAO,QAAQ,GAAG;EAInC,MAAM,SAAS,kBAAkB,cAAc,QAAQ;EACvD,IAAI,QAAQ;GACV,MAAM,WAAW,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,MAAM,CAAC;GAC9D,IAAI,kBAAkB,iBAAiB,UAAU,KAAK,QAAQ,EAAE,OAAO;;EAIzE,MAAM,OAAiB,EAAE;EACzB,IAAI,UAA0B;EAE9B,OAAO,WAAW,QAAQ,aAAa,KAAK,cAAc;GACxD,IAAI,WAAW,QAAQ,SAAS,aAAa;GAE7C,IAAI,QAAQ,MAAM,kBAAkB,WAAW,QAAQ,IAAI,IAAI,EAAE;IAC/D,WAAW,IAAI,IAAI,OAAO,QAAQ,GAAG;IACrC,KAAK,QAAQ,SAAS;IACtB;;GAIF,MAAM,UAAU,kBAAkB,qBAAqB,QAAQ;GAC/D,IAAI,QAAQ,SAAS,GACnB,YAAY,IAAI,QAAQ,KAAK,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC,KAAK,IAAI;GAI7D,MAAM,WAAW,QAAQ,eAAe;GACxC,IAAI,YAAY,SAAS,SAAS,GAAG;IACnC,MAAM,QAAQ,MAAM,KAAK,SAAS,CAAC,QAAQ,QAAQ;IACnD,IAAI,QAAQ,KAAK,CAAC,kBAAkB,iBAAiB,UAAU,QAAQ,cAAe,EACpF,YAAY,cAAc,QAAQ,EAAE;;GAIxC,KAAK,QAAQ,SAAS;GACtB,UAAU,QAAQ;;EAIpB,OAAO,kBAAkB,aAAa,MAAM,SAAS,IAAI;;;;;CAM3D,OAAe,cAAc,SAAkB,KAAuB;EACpE,MAAM,OAAiB,EAAE;EACzB,IAAI,UAA0B;EAE9B,OAAO,WAAW,QAAQ,aAAa,KAAK,cAAc;GACxD,MAAM,UAAU,QAAQ,SAAS,aAAa;GAE9C,IACE,QAAQ,MACR,CAAC,QAAQ,GAAG,SAAS,KAAI,IACzB,kBAAkB,WAAW,QAAQ,IAAI,IAAI,EAC7C;IACA,KAAK,QAAQ,UAAU,QAAQ,GAAG,IAAI;IACtC;;GAGF,IAAI,QAAQ;GAGZ,MAAM,WAAW,QAAQ,eAAe;GACxC,IAAI,UAAU;IACZ,MAAM,kBAAkB,MAAM,KAAK,SAAS,CAAC,QAC1C,MAAM,EAAE,SAAS,aAAa,KAAK,QACrC;IACD,IAAI,gBAAgB,SAAS,GAAG;KAC9B,MAAM,QAAQ,gBAAgB,QAAQ,QAAQ,GAAG;KACjD,SAAS,IAAI,MAAM;;;GAIvB,KAAK,QAAQ,MAAM;GACnB,UAAU,QAAQ;;EAGpB,OAAO,KAAK,KAAK,KAAK,IAAI;;;;;CAM5B,OAAe,0BAA0B,SAAsC;EAC7E,MAAM,OAAO,QAAQ,aAAa,MAAM;EACxC,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,KAAA;EAEtC,MAAM,MAAM,QAAQ,SAAS,aAAa;EAC1C,IAAI;GAAC;GAAU;GAAK;GAAQ,CAAC,SAAS,IAAI,EAGxC,OAAO,GAAG,IAAI,aADM,KAAK,QAAQ,WAAW,OACN,CAAC;;;;;CAS3C,OAAe,cAAc,SAAoC;EAC/D,KAAK,MAAM,QAAQ;GAAC;GAAe;GAAgB;GAAa;GAAU,EAAE;GAC1E,MAAM,YAAY,QAAQ,iBAAiB,KAAK;GAChD,IAAI,WAAW,OAAO,OAAO;;;;;;CAQjC,OAAe,WAAW,IAAY,KAAwB;EAC5D,OAAO,IAAI,iBAAiB,IAAI,IAAI,OAAO,GAAG,GAAG,CAAC,WAAW;;;;;CAM/D,OAAe,iBACb,UACA,WACA,SACS;EACT,IAAI;GACF,MAAM,UAAU,UAAU,iBAAiB,SAAS;GACpD,OAAO,QAAQ,WAAW,MAAM,YAAY,KAAA,KAAa,QAAQ,OAAO;UAClE;GACN,OAAO;;;;;;CAOX,OAAe,qBAAqB,SAA4B;EAC9D,MAAM,UAAU,MAAM,KAAK,QAAQ,UAAU;EAG7C,MAAM,kBAAkB;GACtB;GACA;GACA;GACA;GACA;GACA;GACD;EAED,OAAO,QACJ,QAAQ,QAAQ;GAEf,IAAI,IAAI,SAAS,GAAG,OAAO;GAC3B,OAAO,CAAC,gBAAgB,MAAM,YAAY,QAAQ,KAAK,IAAI,CAAC;IAC5D,CACD,MAAM,GAAG,EAAE;;;;;CAMhB,OAAe,aAAa,MAAgB,SAAkB,KAAuB;EAEnF,KAAK,IAAI,IAAI,KAAK,SAAS,GAAG,KAAK,GAAG,KAAK;GACzC,MAAM,YAAY,KAAK,MAAM,EAAE,CAAC,KAAK,MAAM;GAC3C,IAAI;IACF,MAAM,UAAU,IAAI,iBAAiB,UAAU;IAC/C,IAAI,QAAQ,WAAW,KAAK,QAAQ,OAAO,SACzC,OAAO;WAEH;;EAKV,OAAO,KAAK,KAAK,MAAM;;;;;CAMzB,OAAO,eAAe,SAA4B;EAChD,MAAM,OAAiB,EAAE;EACzB,IAAI,UAA0B;EAC9B,IAAI,QAAQ;EACZ,MAAM,WAAW;EAEjB,OAAO,WAAW,YAAY,QAAQ,eAAe,QAAQ,QAAQ,UAAU;GAC7E,MAAM,MAAM,QAAQ,SAAS,aAAa;GAC1C,IAAI,aAAa;GAGjB,IAAI,QAAQ,IACV,aAAa,GAAG,IAAI,GAAG,QAAQ;QAC1B,IAAI,QAAQ,aAAa,OAAO,QAAQ,cAAc,UAAU;IACrE,MAAM,aAAa,QAAQ,UAAU,MAAM,IAAI,CAAC;IAChD,IAAI,YACF,aAAa,GAAG,IAAI,GAAG;;GAK3B,MAAM,OAAO,QAAQ,aAAa,OAAO;GACzC,IAAI,MACF,cAAc,UAAU,KAAK;GAG/B,KAAK,QAAQ,WAAW;GACxB,UAAU,QAAQ;GAClB;;EAGF,OAAO;;;;;AC7SX,IAAa,eAAb,MAAa,aAAa;;;;;;;;CAQxB,OAAO,WAAW,MAA4C;EAC5D,OAAO,KAAK,aAAa,KAAK;;;;;CAMhC,OAAO,UAAU,SAA2B;EAC1C,MAAM,OAAO,QAAQ,uBAAuB;EAC5C,MAAM,QAAQ,QAAQ,eAAe,aAAa,iBAAiB,QAAQ;EAE3E,IAAI,CAAC,OAAO,OAAO;EAEnB,OAAO,CAAC,EACN,KAAK,QAAQ,KACb,KAAK,SAAS,KACd,MAAM,YAAY,UAClB,MAAM,eAAe,YACrB,MAAM,YAAY;;;;;CAOtB,OAAO,aAAa,SAA2B;EAC7C,MAAM,OAAO,QAAQ,uBAAuB;EAC5C,MAAM,OAAO;GACX,OAAO,QAAQ,eAAe,aAAa,cAAc;GACzD,QAAQ,QAAQ,eAAe,aAAa,eAAe;GAC5D;EAED,OAAO,KAAK,MAAM,KAAK,UAAU,KAAK,SAAS,KAAK,KAAK,OAAO,KAAK,SAAS,KAAK,QAAQ;;;;;CAM7F,OAAO,aAAa,SAAkB,QAA4C;EAChF,IAAI,CAAC,QAAQ,OAAO;EAGpB,IAAI,OAAO,kBAAkB;QACtB,MAAM,YAAY,OAAO,kBAC5B,IAAI,QAAQ,QAAQ,SAAS,EAAE,OAAO;;EAK1C,IAAI,OAAO,kBAAkB,QAAQ;GACnC,IAAI,UAAU;GACd,KAAK,MAAM,YAAY,OAAO,kBAC5B,IAAI,QAAQ,QAAQ,SAAS,EAAE;IAC7B,UAAU;IACV;;GAGJ,IAAI,CAAC,SAAS,OAAO;;EAIvB,IAAI,OAAO,MAAM,UAAU,CAAC,OAAO,KAAK,SAAS,QAAQ,QAAQ,aAAa,CAAC,EAC7E,OAAO;EAIT,MAAM,cAAc,QAAQ,aAAa,aAAa,IAAI;EAC1D,IAAI,OAAO,cAAc,QAAQ;GAC/B,IAAI,UAAU;GACd,KAAK,MAAM,QAAQ,OAAO,cACxB,IAAI,YAAY,SAAS,KAAK,aAAa,CAAC,EAAE;IAC5C,UAAU;IACV;;GAGJ,IAAI,CAAC,SAAS,OAAO;;EAIvB,IAAI,OAAO,aAAa,QAAQ;GAC9B,IAAI,UAAU;GACd,KAAK,MAAM,WAAW,OAAO,aAC3B,IAAI,QAAQ,KAAK,YAAY,EAAE;IAC7B,UAAU;IACV;;GAGJ,IAAI,CAAC,SAAS,OAAO;;EAIvB,IAAI,OAAO,eAAe;QACnB,MAAM,QAAQ,OAAO,eACxB,IAAI,CAAC,QAAQ,aAAa,KAAK,EAAE,OAAO;;EAK5C,IAAI,OAAO,iBACT,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,OAAO,gBAAgB,EAAE;GAClE,MAAM,YAAY,QAAQ,aAAa,KAAK;GAC5C,IAAI,CAAC,WAAW,OAAO;GAEvB,IAAI,OAAO,UAAU;QACf,cAAc,OAAO,OAAO;UAC3B,IAAI,iBAAiB;QACtB,CAAC,MAAM,KAAK,UAAU,EAAE,OAAO;;;EAMzC,IAAI,OAAO,iBAAiB,QAAQ;GAClC,IAAI,WAAW;GACf,KAAK,MAAM,YAAY,OAAO,iBAC5B,IAAI,QAAQ,QAAQ,SAAS,EAAE;IAC7B,WAAW;IACX;;GAGJ,IAAI,CAAC,UAAU,OAAO;;EAIxB,IAAI,OAAO,kBAAkB,QAAQ;GACnC,MAAM,cAAc,aAAa,mBAAmB,QAAQ;GAC5D,IAAI,iBAAiB;GACrB,KAAK,MAAM,QAAQ,OAAO,kBACxB,IAAI,YAAY,OAAO;IACrB,iBAAiB;IACjB;;GAGJ,IAAI,CAAC,gBAAgB,OAAO;;EAI9B,IAAI,OAAO,UAAU;GACnB,MAAM,SAAS,QAAQ;GACvB,IAAI,CAAC,UAAU,CAAC,OAAO,aAAa,aAAa,CAAC,SAAS,OAAO,SAAS,aAAa,CAAC,EACvF,OAAO;;EAIX,OAAO;;;;;CAMT,OAAO,eACL,SACA,SACA,QAAQ,GACiB;EAEzB,IAAI,QAAQ,aAAa,KAAA,KAAa,QAAQ,QAAQ,UACpD,OAAO;EAIT,IAAI,CAAC,QAAQ,iBAAiB,CAAC,aAAa,UAAU,QAAQ,EAC5D,OAAO;EAIT,IAAI,QAAQ,gBAAgB,CAAC,aAAa,aAAa,QAAQ,EAC7D,OAAO;EAIT,IAAI,CAAC,aAAa,aAAa,SAAS,QAAQ,OAAO,EACrD,OAAO;EAGT,MAAM,YAA8B;GAClC,KAAK,QAAQ,QAAQ,aAAa;GAClC,MAAM,aAAa,eAAe,SAAS,QAAQ;GACnD,UAAU,kBAAkB,kBAAkB,QAAQ;GACtD,YAAY,aAAa,sBAAsB,SAAS,QAAQ;GAChE,SAAS,aAAa,kBAAkB,QAAQ;GAChD,aAAa,aAAa,mBAAmB,QAAQ;GAEtD;EAGD,IAAI,QAAQ,SAAS,UAAU,aAAa,oBAAoB,QAAQ,EAAE;GACxE,MAAM,WAA+B,EAAE;GAGvC,IAAI,QAAQ,oBAAoB,QAAQ,YAAY;IAClD,MAAM,iBAAiB,aAAa,gBAAgB,QAAQ,YAAY,SAAS,QAAQ,EAAE;IAC3F,SAAS,KAAK,GAAG,eAAe;;GAIlC,MAAM,kBAAkB,aAAa,gBAAgB,SAAS,SAAS,QAAQ,EAAE;GACjF,SAAS,KAAK,GAAG,gBAAgB;GAEjC,IAAI,SAAS,SAAS,GACpB,UAAU,WAAW;;EAIzB,OAAO;;;;;CAMT,OAAe,gBACb,WACA,SACA,OACoB;EACpB,MAAM,WAA+B,EAAE;EACvC,KAAK,MAAM,SAAS,MAAM,KAAK,UAAU,SAAS,EAAE;GAClD,MAAM,YAAY,aAAa,eAAe,OAAO,SAAS,MAAM;GACpE,IAAI,WACF,SAAS,KAAK,UAAU;;EAI5B,OAAO;;;;;CAMT,OAAe,sBACb,SACA,SACwB;EACxB,MAAM,WAAW;GACf;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD;EAED,MAAM,aAAqC,EAAE;EAC7C,MAAM,eAAe,QAAQ,2BAA2B;EACxD,MAAM,mBAAmB,QAAQ,+BAA+B;EAEhE,KAAK,MAAM,QAAQ,UAAU;GAC3B,MAAM,QAAQ,QAAQ,aAAa,KAAK;GACxC,IAAI,OAEF,WAAW,QACT,MAAM,SAAS,eAAe,GAAG,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO;;EAK/E,KAAK,MAAM,QAAQ,QAAQ,YACzB,IAAI,KAAK,KAAK,WAAW,QAAQ,IAAI,CAAC,SAAS,SAAS,KAAK,KAAK,EAChE,WAAW,KAAK,QACd,KAAK,MAAM,SAAS,mBAChB,GAAG,KAAK,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAC7C,KAAK;EAIf,OAAO;;;;;CAMT,OAAe,kBAAkB,SAAkC;EACjE,MAAM,UAA0B,EAC9B,aAAa,kBAAkB,eAAe,QAAQ,EACvD;EAGD,MAAM,OAAO,QAAQ,QAAQ,OAAO;EACpC,IAAI,MACF,QAAQ,cAAc,kBAAkB,kBAAkB,KAAK,CAAC;EAGlE,MAAM,UAAU,QAAQ,QAAQ,6BAA2B;EAC3D,IAAI,SACF,QAAQ,iBAAiB,kBAAkB,kBAAkB,QAAQ,CAAC;EAGxE,MAAM,OAAO,QAAQ,QAAQ,wBAAsB;EACnD,IAAI,MACF,QAAQ,cAAc,kBAAkB,kBAAkB,KAAK,CAAC;EAGlE,MAAM,MAAM,QAAQ,QAAQ,6BAA2B;EACvD,IAAI,KACF,QAAQ,aAAa,kBAAkB,kBAAkB,IAAI,CAAC;EAGhE,OAAO;;;;;CAMT,OAAe,mBAAmB,SAAsC;EAEtE,MAAM,cAAc;EACpB,MAAM,cAAkC,EAAE;EAG1C,IACE,YAAY,WACZ,QAAQ,aAAa,UAAU,IAC/B,QAAQ,QAAQ,wEAAoE,EAEpF,YAAY,QAAQ;EAEtB,IACE,YAAY,YACZ,QAAQ,aAAa,WAAW,IAChC,QAAQ,QAAQ,0BAA0B,EAE1C,YAAY,SAAS;EAEvB,IAAI,YAAY,YAAY,QAAQ,aAAa,WAAW,IAAI,QAAQ,QAAQ,OAAO,EACrF,YAAY,SAAS;EAGvB,IAD2B,QAAQ,QAAQ,mCACrB,EAAE,YAAY,MAAM;EAI1C,IADE,QAAQ,aAAa,WAAW,IAAI,QAAQ,aAAa,gBAAgB,KAAK,QAChE,YAAY,WAAW;EAGvC,IAAI,CADc,aAAa,UAAU,QAAQ,EACnC,YAAY,SAAS;EAEnC,MAAM,WAAW,QAAQ,aAAa,OAAO;EAC7C,IAAI,UAAU,YAAY,OAAO;EAGjC,IAAI,QAAQ,QAAQ,kCAAkC,EAAE;GAGtD,MAAM,OAAQ,QAA6B,QAAQ,QAAQ,QAAQ,OAAO;GAC1E,IAAI,MACF,YAAY,OAAO,kBAAkB,kBAAkB,KAAK,CAAC;;EAIjE,OAAO;;;;;CAMT,OAAe,eAAe,SAAkB,SAAqC;EAEnF,IAAI,QAAQ,QAAQ,kBAAkB,EAAE;GACtC,MAAM,QAAQ;GACd,OAAO,MAAM,SAAS,MAAM,eAAe;;EAI7C,IAAI,QAAQ,QAAQ,MAAM,EACxB,OAAQ,QAA6B,OAAO;EAI9C,MAAM,OAAO,QAAQ,aAAa,MAAM,IAAI;EAC5C,MAAM,YAAY,SAAS;EAE3B,IAAI,aAAa,KAAK,SAAS,WAC7B,OAAO,GAAG,KAAK,UAAU,GAAG,UAAU,CAAC;EAGzC,OAAO;;;;;CAMT,OAAe,oBAAoB,SAA2B;EAC5D,OAAO,QAAQ,QACb,4LAGD;;;;;;;;;;;;;;;;;;AC/YL,IAAa,iBAAb,MAAa,eAAe;CAC1B;CAEA,YAAY,UAAsC,EAAE,EAAE;EACpD,KAAK,UAAU;GACb,MAAM,QAAQ,QAAQ;GACtB,UAAU,QAAQ,YAAY;GAC9B,eAAe,QAAQ,iBAAiB;GACxC,kBAAkB,QAAQ,oBAAoB;GAC9C,gBAAgB,QAAQ,kBAAkB;GAC1C,cAAc,QAAQ,gBAAgB;GACtC,iBAAiB,QAAQ,mBAAmB;GAC5C,iBAAiB,QAAQ,mBAAmB,EAAE;GAC9C,GAAI,QAAQ,4BAA4B,KAAA,KAAa,EACnD,yBAAyB,QAAQ,yBAClC;GACD,GAAI,QAAQ,gCAAgC,KAAA,KAAa,EACvD,6BAA6B,QAAQ,6BACtC;GACD,GAAI,QAAQ,uBAAuB,KAAA,KAAa,EAC9C,oBAAoB,QAAQ,oBAC7B;GACD,GAAI,QAAQ,WAAW,KAAA,KAAa,EAAE,QAAQ,QAAQ,QAAQ;GAC/D;;;;;;;CAQH,QACE,cAAkC,UAClC,gBACgB;EAChB,MAAM,YAAY,KAAK,KAAK;EAC5B,MAAM,iBAAiB,aAAa,WAAW,YAAY;EAC3D,MAAM,MAAM,iBAAiB,cAAc,YAAY;EAGvD,MAAM,UAA6B;GAAE,GAAG,KAAK;GAAS,GAAG;GAAgB;EAMzE,IAAI,YAAgC,iBAAiB,MAAM;EAE3D,IAAI,QAAQ,mBAAmB,gBAC7B,YAAY,iBAAiB,gBAAgB,IAAI;EAInD,MAAM,YAAY,KAAK,iBAAiB,IAAI;EAG5C,MAAM,YAAY,KAAK,iBAAiB,IAAI;EAG5C,MAAM,cAAc,KAAK,2BAA2B,WAAW,QAAQ;EAGvE,MAAM,SAAyB;GAC7B,MAAM,QAAQ;GACd,WAAW;GACX,MAAM;GACN;GACA;GACD;EAGD,IAAI,QAAQ,SAAS,QAAQ;GAC3B,MAAM,WAAW,KAAK,wBAAwB,WAAW,QAAQ;GACjE,MAAM,WAAW,KAAK,gBAAgB,KAAK,WAAW,QAAQ;GAC9D,OAAO;IACL,GAAG;IACH;IACA;IACD;;EAGH,OAAO;;;;;CAMT,iBAAyB,KAA0B;EACjD,MAAM,WAAW,KAAK,kBAAkB,IAAI;EAC5C,OAAO;GACL,KAAK,IAAI,UAAU,QAAQ;GAC3B,OAAO,IAAI,SAAS;GACpB,WAAW,KAAK,aAAa,IAAI;GACjC,WAAW,KAAK,cAAc,IAAI;GAClC,WAAW,KAAK,aAAa,IAAI;GACjC,GAAI,aAAa,KAAA,KAAa,EAAE,UAAU;GAC3C;;;;;CAMH,iBAAyB,KAA8B;EACrD,MAAM,WAAW,iBAAiB,gBAAgB,IAAI;EACtD,OAAO;GACL,YAAY,KAAK,oBAAoB,SAAS,cAAc,EAAE,CAAC;GAC/D,MAAM,KAAK,oBAAoB,SAAS,QAAQ,EAAE,CAAC;GACnD,OAAO,KAAK,oBAAoB,SAAS,QAAQ,EAAE,CAAC;GACpD,SAAS,KAAK,oBAAoB,SAAS,UAAU,EAAE,CAAC;GACxD,SAAS,KAAK,oBAAoB,SAAS,eAAe,EAAE,CAAC;GAC7D,UAAU,KAAK,oBAAoB,SAAS,UAAU,EAAE,CAAC;GACzD,UAAU,KAAK,oBAAoB,SAAS,UAAU,EAAE,CAAC;GAC1D;;;;;CAMH,oBAA4B,UAA+B;EACzD,OAAO,SAAS,KAAK,OAAO,kBAAkB,kBAAkB,GAAG,CAAC,IAAI;;CAG1E,iBACE,WACA,UACA,kBACW;EACX,MAAM,UAAU,CAAC,GAAG,UAAU,iBAAiB,SAAS,CAAC;EACzD,IAAI,CAAC,kBAAkB,OAAO;EAE9B,IAAI,gBAAgB,aAAa,UAAU,YACzC,QAAQ,KAAK,GAAG,KAAK,iBAAiB,UAAU,YAAY,UAAU,KAAK,CAAC;EAG9E,KAAK,MAAM,WAAW,UAAU,iBAAiB,IAAI,EACnD,IAAI,QAAQ,YACV,QAAQ,KAAK,GAAG,KAAK,iBAAiB,QAAQ,YAAY,UAAU,KAAK,CAAC;EAG9E,OAAO;;;;;;;;;CAUT,WACE,WACA,UACA,SACoB;EACpB,MAAM,YAAgC,EAAE;EACxC,KAAK,MAAM,MAAM,KAAK,iBAAiB,WAAW,UAAU,QAAQ,iBAAiB,EAAE;GACrF,MAAM,UAAU,aAAa,eAAe,IAAI,QAAQ;GACxD,IAAI,SAAS,UAAU,KAAK,QAAQ;;EAEtC,OAAO;;;;;CAMT,2BACE,WACA,SAC+B;EAC/B,MAAM,YAAgC,EAAE;EACxC,KAAK,MAAM,YAAY,QAAQ,mBAAmB,EAAE,EAClD,UAAU,KAAK,GAAG,KAAK,WAAW,WAAW,UAAU,QAAQ,CAAC;EAGlE,OAAO;GACL,SAAS,KAAK,WACZ,WACA,6EACA,QACD;GACD,OAAO,KAAK,WAAW,WAAW,WAAW,QAAQ;GACrD,QAAQ,KAAK,WACX,WACA,yEACA,QACD;GACD,OAAO,KAAK,aAAa,WAAW,QAAQ;GAC5C;GACD;;;;;CAMH,aAAqB,WAA+B,SAAwC;EAC1F,MAAM,QAAoB,EAAE;EAG5B,KAF0B,iBAAiB,WAAW,QAAQ,QAAQ,iBAE1D,CAAC,SAAS,SAAS;GAE7B,IAAI,CAAC,KAAK,qBAAqB,MAAM,QAAQ,EAAE;GAE/C,MAAM,SAAS,KAAK,aAAa,SAAS;GAC1C,MAAM,SAAS,KAAK,aAAa,SAAS;GAC1C,MAAM,WAAqB;IACzB,UAAU,kBAAkB,kBAAkB,KAAK,CAAC;IACpD,QAAQ,KAAK,WACX,MACA,yEACA,QACD;IACD,SAAS,KAAK,WACZ,MACA,0DACA,QACD;IACF;GACD,IAAI,QAAQ,SAAS,SAAS;GAC9B,IAAI,QAAQ,SAAS,SAAS;GAC9B,MAAM,KAAK,SAAS;IACpB;EAEF,OAAO;;;;;CAMT,wBACE,WACA,SACyC;EACzC,OAAO;GACL,UAAU,KAAK,WAAW,WAAW,0BAA0B,QAAQ;GACvE,QAAQ,KAAK,WAAW,WAAW,OAAO,QAAQ;GAClD,QAAQ,KAAK,WAAW,WAAW,SAAS,QAAQ;GACpD,OAAO,KAAK,WAAW,WAAW,UAAU,QAAQ;GACpD,UAAU,KAAK,WAAW,WAAW,+BAA6B,QAAQ;GAC3E;;;;;CAMH,gBACE,KACA,WACA,SACyC;EACzC,MAAM,cAAc,KAAK,iBAAiB,WAAW,KAAK,QAAQ,iBAAiB;EACnF,MAAM,oBAAoB,KAAK,iBAC7B,WACA,2FACA,QAAQ,iBACT,CAAC;EAEF,MAAM,WAAoD;GACxD,eAAe,YAAY;GAC3B;GACD;EAED,IAAI,QAAQ,mBAAmB,CAAC,aAAa,WAAW,UAAU,EAChE,SAAS,cAAc,kBAAkB,kBAAkB,UAAU,CAAC;EAGxE,MAAM,WAAW,IAAI,gBAAgB,aAAa,OAAO;EACzD,IAAI,UACF,SAAS,WAAW;EAGtB,OAAO;;;;;CAMT,qBAA6B,SAAkB,SAAqC;EAElF,IAAI,CAAC,QAAQ,iBAAiB,CAAC,aAAa,UAAU,QAAQ,EAC5D,OAAO;EAIT,IAAI,QAAQ,gBAAgB,CAAC,aAAa,aAAa,QAAQ,EAC7D,OAAO;EAIT,IAAI,QAAQ,UAAU,CAAC,aAAa,aAAa,SAAS,QAAQ,OAAO,EACvE,OAAO;EAGT,OAAO;;;;;CAMT,aAAqB,KAAwB;EAE3C,OAAO;GADiB;GAAU;GAAiB;GAAkB;GAChD,CAAC,MAAM,QAAQ;GAClC,MAAM,UAAU,IAAI,cAAc,IAAI;GACtC,OAAO,UAAU,aAAa,UAAU,QAAQ,GAAG;IACnD;;;;;CAMJ,cAAsB,KAAwB;EAE5C,OAAO;GADmB;GAAY;GAAY;GAAsB;GACjD,CAAC,MAAM,QAAQ;GACpC,MAAM,UAAU,IAAI,cAAc,IAAI;GACtC,OAAO,UAAU,aAAa,UAAU,QAAQ,GAAG;IACnD;;;;;CAMJ,aAAqB,KAAwB;EAE3C,OAAO;GADiB;GAAmB;GAAU;GAAU;GAC1C,CAAC,MAAM,QAAQ;GAClC,MAAM,UAAU,IAAI,cAAc,IAAI;GACtC,OAAO,UAAU,aAAa,UAAU,QAAQ,GAAG;IACnD;;;;;CAMJ,kBAA0B,KAAmC;EAC3D,MAAM,UAAU,IAAI;EACpB,IAAI,WAAW,YAAY,IAAI,MAC7B,OAAO,kBAAkB,kBAAkB,QAAQ,CAAC;;;;;;;CAYxD,OAAO,mBACL,KACA,UAA2C,EAAE,EAC7B;EAKhB,OAAO,IAJY,eAAe;GAChC,GAAG;GACH,MAAM;GACP,CACY,CAAC,QAAQ,IAAI;;;;;;;CAQ5B,OAAO,YAAY,KAAe,UAA2C,EAAE,EAAkB;EAK/F,OAAO,IAJY,eAAe;GAChC,GAAG;GACH,MAAM;GACP,CACY,CAAC,QAAQ,IAAI;;;;;;;;CAS5B,OAAO,mBACL,SACA,OAAuB,eACvB,UAA2C,EAAE,EAC7B;EAKhB,OAAO,IAJY,eAAe;GAChC,GAAG;GACH;GACD,CACY,CAAC,QAAQ,QAAQ;;;;;AC9YlC,IAAa,uBAAb,MAAa,qBAAqB;;;;;CAKhC,OAAO,iBAAiB,MAA8C;EACpE,MAAM,UAAyC,EAAE;EAGjD,MAAM,SAAS,KAAK,cAAc,8CAA4C;EAC9E,IAAI,QACF,QAAQ,SAAS,qBAAqB,cAAc,OAAO;EAI7D,MAAM,OAAO,KAAK,iBAAiB,gDAA8C;EACjF,IAAI,KAAK,SAAS,GAChB,QAAQ,aAAa,MAAM,KAAK,KAAK,CAAC,KAAK,QAAQ,qBAAqB,cAAc,IAAI,CAAC;EAI7F,IAAI,aAAa,WAAW,KAAK,EAAE;GACjC,MAAM,OAAO,iBAAiB,gBAAgB,KAAK;GACnD,IAAI,MAAM;IACR,QAAQ,OAAO,qBAAqB,cAAc,KAAK;IAEvD,MAAM,WAAW,KAAK,iBAAiB,sCAAoC;IAC3E,IAAI,SAAS,SAAS,GACpB,QAAQ,WAAW,MAAM,KAAK,SAAS,CACpC,QAAQ,YAAY,CAAC,QAAQ,QAAQ,sBAAsB,CAAC,CAC5D,KAAK,YAAY,qBAAqB,cAAc,QAAQ,CAAC;;SAG/D;GAEL,QAAQ,OAAO,qBAAqB,cAAc,KAAK;GACvD,MAAM,WAAW,KAAK,iBAAiB,sCAAoC;GAC3E,IAAI,SAAS,SAAS,GACpB,QAAQ,WAAW,MAAM,KAAK,SAAS,CACpC,QAAQ,YAAY,CAAC,QAAQ,QAAQ,sBAAsB,CAAC,CAC5D,KAAK,YAAY,qBAAqB,cAAc,QAAQ,CAAC;;EAKpE,MAAM,WAAW,KAAK,iBAAiB,sDAAoD;EAC3F,IAAI,SAAS,SAAS,GACpB,QAAQ,UAAU,MAAM,KAAK,SAAS,CAAC,KAAK,YAC1C,qBAAqB,cAAc,QAAQ,CAC5C;EAIH,MAAM,SAAS,KAAK,cAAc,mDAAiD;EACnF,IAAI,QACF,QAAQ,SAAS,qBAAqB,cAAc,OAAO;EAI7D,MAAM,SAAS,KAAK,iBAAiB,8CAA4C;EACjF,MAAM,gBAAgB,MAAM,KAAK,OAAO,CAAC,QAAQ,UAAU,aAAa,UAAU,MAAM,CAAC;EACzF,IAAI,cAAc,SAAS,GACzB,QAAQ,SAAS,cAAc,KAAK,UAAU,qBAAqB,cAAc,MAAM,CAAC;EAI1F,MAAM,QAAQ,qBAAqB,oBAAoB,KAAK;EAG5D,MAAM,UAAU,qBAAqB,iBAAiB,MAAM,SAAS,MAAM;EAK3E,OAAO;GAAE;GAAS;GAAO;GAAS,aAFd,qBAAqB,oBAAoB,SAAS,QAEzB;GAAE;;;;;CAMjD,OAAO,cACL,UACA,KACA,UAAsC,EAAE,EACjB;EACvB,MAAM,UAAU,IAAI,cAAc,SAAS;EAC3C,IAAI,CAAC,SAAS,OAAO;EAKrB,OAAO,IAHY,eAAe,QAGrB,CAAC,QAAQ,SAAS,QAAQ;;;;;CAMzC,OAAO,eACL,UACA,KACA,UAAoC,EAAE,EACb;EACzB,MAAM,UAAU,IAAI,cAAc,SAAS;EAC3C,IAAI,CAAC,SAAS,OAAO;EAErB,MAAM,SAA2B;GAC/B;GACA,MAAM,EAAE;GACR,UAAU;IACR,WAAW;IACX,gBAAgB;IACjB;GACF;EAGD,IAAI,QAAQ,oBAAoB,OAAO;GACrC,MAAM,WAAW,QAAQ,iBAAiB,yBAAyB;GACnE,OAAO,KAAK,WAAW,MAAM,KAAK,SAAS,CAAC,KAAK,OAAO;IACtD,OAAO,OAAO,SAAS,EAAE,QAAQ,IAAK,GAAG;IACzC,MAAM,qBAAqB,eAAe,GAAG,QAAQ,cAAc;IACpE,EAAE;;EAIL,MAAM,aAAa,QAAQ,iBAAiB,IAAI;EAChD,IAAI,WAAW,SAAS,GACtB,OAAO,KAAK,aAAa,MAAM,KAAK,WAAW,CAC5C,KAAK,MAAM,qBAAqB,eAAe,GAAG,QAAQ,cAAc,CAAC,CACzE,QAAQ,SAAS,KAAK,SAAS,EAAE;EAItC,IAAI,QAAQ,iBAAiB,OAAO;GAClC,MAAM,QAAQ,QAAQ,iBAAiB,SAAS;GAChD,OAAO,KAAK,QAAQ,MAAM,KAAK,MAAM,CAAC,KAAK,UAAU;IACnD,MAAM,KAAK,QAAQ,aAAa;IAChC,OAAO,MAAM,KAAK,KAAK,iBAAiB,KAAK,CAAC,CAAC,KAAK,OAClD,qBAAqB,eAAe,IAAI,QAAQ,cAAc,CAC/D;IACF,EAAE;;EAIL,IAAI,QAAQ,kBAAkB,OAAO;GACnC,MAAM,SAAS,QAAQ,iBAAiB,QAAQ;GAChD,OAAO,SAAS,MAAM,KAAK,OAAO,CAAC,KAAK,UAAU;IAWhD,OAAO;KAAE,SAVO,MAAM,KAAK,MAAM,iBAAiB,KAAK,CAAC,CAAC,KAAK,OAC5D,qBAAqB,eAAe,GAAG,CASzB;KAAE,MAPL,MAAM,KAAK,MAAM,iBAAiB,KAAK,CAAC,CAClD,QAAQ,OAAO,GAAG,cAAc,KAAK,CAAC,CACtC,KAAK,OACJ,MAAM,KAAK,GAAG,iBAAiB,KAAK,CAAC,CAAC,KAAK,OACzC,qBAAqB,eAAe,GAAG,CACxC,CAEiB;KAAE;KACxB;;EAIJ,IAAI,QAAQ,iBAAiB,OAAO;GAClC,MAAM,SAAS,QAAQ,iBAAiB,MAAM;GAC9C,MAAM,SAAS,QAAQ,iBAAiB,QAAQ;GAChD,MAAM,SAAS,QAAQ,iBAAiB,QAAQ;GAEhD,OAAO,QAAQ;IACb,GAAG,MAAM,KAAK,OAAO,CAAC,KAAK,QAAQ;KACjC,MAAM,OAAoD,EAAE,MAAM,OAAO;KACzE,MAAM,MAAM,IAAI,aAAa,MAAM;KACnC,MAAM,MAAM,IAAI,aAAa,MAAM;KACnC,IAAI,KAAK,KAAK,MAAM;KACpB,IAAI,KAAK,KAAK,MAAM;KACpB,OAAO;MACP;IACF,GAAG,MAAM,KAAK,OAAO,CAAC,KAAK,UAAU;KACnC,MAAM,OAAwC,EAAE,MAAM,SAAS;KAC/D,MAAM,MAAM,MAAM,aAAa,MAAM;KACrC,IAAI,KAAK,KAAK,MAAM;KACpB,OAAO;MACP;IACF,GAAG,MAAM,KAAK,OAAO,CAAC,KAAK,UAAU;KACnC,MAAM,OAAwC,EAAE,MAAM,SAAS;KAC/D,MAAM,MAAM,MAAM,aAAa,MAAM;KACrC,IAAI,KAAK,KAAK,MAAM;KACpB,OAAO;MACP;IACH;;EAIH,MAAM,UAAU,QAAQ,eAAe;EACvC,OAAO,SAAS,YAAY,QAAQ,MAAM,CAAC,MAAM,MAAM,CAAC;EACxD,OAAO,SAAS,iBACd,QAAQ,iBAAiB,qCAAqC,CAAC,SAAS;EAE1E,OAAO;;;;;CAMT,OAAe,cAAc,SAA8B;EACzD,MAAM,WAAW,kBAAkB,kBAAkB,QAAQ,CAAC;EAC9D,MAAM,UAAU,QAAQ,iBAAiB,4BAA0B;EACnE,MAAM,QAAQ,QAAQ,iBAAiB,UAAU;EACjD,MAAM,SAAS,QAAQ,iBAAiB,0BAA0B;EAClE,MAAM,QAAQ,QAAQ,iBAAiB,OAAO;EAC9C,MAAM,QAAQ,QAAQ,iBAAiB,SAAS;EAChD,MAAM,SAAS,QAAQ,iBAAiB,QAAQ;EAChD,MAAM,QAAQ,QAAQ,iBAAiB,oBAAoB;EAE3D,MAAM,mBAAmB,QAAQ,SAAS,MAAM,SAAS,OAAO;EAGhE,IAAI;EACJ,MAAM,YAAY,QAAQ,aAAa,aAAa;EACpD,IAAI,WACF,QAAQ;OACH,IAAI,QAAQ,aAAa,kBAAkB,EAAE;GAClD,MAAM,UAAU,QAAQ,aAAa,kBAAkB;GACvD,IAAI,SAAS;IACX,MAAM,eAAe,QAAQ,eAAe,eAAe,QAAQ;IACnE,IAAI,cACF,QAAQ,aAAa,aAAa,MAAM;;SAGvC;GACL,MAAM,UAAU,QAAQ,cAAc,aAAa;GACnD,IAAI,SACF,QAAQ,QAAQ,aAAa,MAAM;;EAKvC,MAAM,cAAc,QAAQ,aAAa,MAAM,IAAI;EACnD,MAAM,cACJ,YAAY,SAAS,KAAK,GAAG,YAAY,UAAU,GAAG,GAAG,CAAC,OAAO;EAEnE,MAAM,aAAyB;GAC7B;GACA;GACA,SAAS,MAAM,SAAS;GACxB,SAAS,MAAM,SAAS;GACxB,UAAU,OAAO,SAAS;GAC1B,UAAU,MAAM,SAAS;GAC1B;EAED,IAAI,OAAO,WAAW,QAAQ;EAE9B,MAAM,OAAO,QAAQ,aAAa,OAAO;EACzC,IAAI,MAAM,WAAW,OAAO;EAE5B,IAAI,QAAQ,SAAS,GAAG,WAAW,cAAc,QAAQ;EACzD,IAAI,MAAM,SAAS,GAAG,WAAW,YAAY,MAAM;EACnD,IAAI,OAAO,SAAS,GAAG,WAAW,aAAa,OAAO;EACtD,IAAI,YAAY,SAAS,GAAG,WAAW,cAAc;EAErD,OAAO;;;;;CAMT,OAAe,oBAAoB,MAAuD;EACxF,MAAM,QAAQ,KAAK,iBAAiB,OAAO;EAC3C,OAAO,MAAM,KAAK,MAAM,CAAC,KAAK,SAAS;GACrC,MAAM,SAAS,KAAK,iBAAiB,0BAA0B;GAC/D,MAAM,WAAW,kBAAkB,kBAAkB,KAAK,CAAC;GAG3D,IAAI,WAAW;GACf,IAAI,KAAK,QAAQ,4BAA0B,EACzC,WAAW;QACN,IAAI,KAAK,QAAQ,6BAA2B,EACjD,WAAW;QACN,IAAI,KAAK,QAAQ,wBAAsB,EAC5C,WAAW;QACN,IAAI,KAAK,QAAQ,kCAAgC,EACtD,WAAW;QACN,IAAI,KAAK,QAAQ,iCAA+B,EACrD,WAAW;GAIb,IAAI;GACJ,MAAM,SAAS,KAAK,aAAa,KAAK,EAAE,aAAa;GACrD,MAAM,YAAY,KAAK,aAAa,QAAQ,EAAE,aAAa;GAC3D,MAAM,aAAa,KAAK,aAAa,SAAS,EAAE,aAAa;GAC7D,MAAM,WAAW,KAAK,cAAc,wBAAsB;GAC1D,MAAM,cAAc,KAAK,cAAc,2BAAyB;GAGhE,IAFkB,KAAK,cAAc,yBAExB,IAAI,QAAQ,SAAS,SAAS,IAAI,WAAW,SAAS,SAAS,EAC1E,UAAU;QACL,IAAI,eAAe,UACxB,UAAU;QACL,IAAI,aACT,UAAU;QACL,IAAI,QAAQ,SAAS,UAAU,IAAI,WAAW,SAAS,UAAU,EACtE,UAAU;QACL,IAAI,QAAQ,SAAS,YAAY,IAAI,WAAW,SAAS,YAAY,EAC1E,UAAU;QACL,IAAI,YAAY,SAAS,WAAW,IAAI,WAAW,SAAS,WAAW,EAC5E,UAAU;GAGZ,MAAM,eAKF;IACF;IACA;IACA,YAAY,OAAO;IACpB;GAED,IAAI,SAAS,aAAa,UAAU;GAEpC,OAAO;IACP;;;;;CAMJ,OAAe,iBACb,MACA,SACA,OAC+B;EAC/B,MAAM,iBAAiB,KAAK,iBAAiB,2CAA2C;EACxF,MAAM,cAAc,KAAK,iBAAiB,sCAAoC;EAC9E,MAAM,aAAa,QAAQ,QAAQ,UAAU,KAAK;EAIlD,MAAM,YAAY;GADM;GAAU;GAAiB;GACnB,CAAC,MAAM,QAAQ;GAC7C,MAAM,UAAU,KAAK,cAAc,IAAI;GACvC,OAAO,UAAU,aAAa,UAAU,QAAQ,GAAG;IACnD;EAIF,MAAM,YAAY;GADQ;GAAY;GAAY;GAChB,CAAC,MAAM,QAAQ;GAC/C,MAAM,UAAU,KAAK,cAAc,IAAI;GACvC,OAAO,UAAU,aAAa,UAAU,QAAQ,GAAG;IACnD;EAEF,MAAM,UAAyC;GAC7C,kBAAkB,eAAe;GACjC,YAAY,MAAM;GAClB,eAAe,YAAY;GAC3B;GACA;GACA;GACD;EAED,MAAM,sBAAsB,QAAQ,MAAM;EAC1C,IAAI,qBACF,QAAQ,sBAAsB;EAGhC,OAAO;;;;;CAMT,OAAe,oBACb,SACA,SACU;EACV,MAAM,cAAwB,EAAE;EAEhC,IAAI,QAAQ,WACV,YAAY,KAAK,sEAAsE;EAGzF,IAAI,QAAQ,WACV,YAAY,KAAK,2DAA2D;EAG9E,IAAI,QAAQ,WACV,YAAY,KAAK,qEAAqE;EAGxF,IAAI,QAAQ,QAAQ,QAAQ,KAAK,mBAAmB,IAClD,YAAY,KACV,oBAAoB,QAAQ,KAAK,iBAAiB,4CACnD;EAGH,IAAI,QAAQ,aAAa,GACvB,YAAY,KAAK,SAAS,QAAQ,WAAW,sBAAsB;EAGrE,IAAI,CAAC,QAAQ,MACX,YAAY,KAAK,oEAAoE;EAGvF,OAAO;;;;;CAMT,OAAe,eAAe,SAAkB,WAA4B;EAC1E,MAAM,OAAO,QAAQ,aAAa,MAAM,IAAI;EAC5C,IAAI,aAAa,KAAK,SAAS,WAC7B,OAAO,GAAG,KAAK,UAAU,GAAG,UAAU,CAAC;EAEzC,OAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-b/smart-dom-reader",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.3",
|
|
4
4
|
"description": "Token-efficient DOM extraction for AI agents - Extract interactive elements, semantic structure, and stable CSS selectors for LLM-powered browser automation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -68,8 +68,8 @@
|
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@types/node": "22.17.2",
|
|
70
70
|
"typescript": "^5.8.3",
|
|
71
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@
|
|
72
|
-
"vite-plus": "
|
|
71
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@0.1.22",
|
|
72
|
+
"vite-plus": "0.1.22"
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
|
75
75
|
"node": ">=20"
|