UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

213 lines • 7.55 kB
/** * Coordinates DOM element inspection functionality * Extracted from LocalDebugEngine for better separation of concerns and testability * * Handles: * - Single and multiple element inspection * - Element existence and visibility checks * - Element property and style extraction * - Element bounds and positioning */ export class ElementInspectionCoordinator { page = null; /** * Attach to a page for element inspection */ async attachToPage(page) { this.page = page; } /** * Inspect a specific element and capture its state */ async inspectElement(selector) { if (!this.page) { throw new Error('No page attached'); } return await this.page.evaluate((sel) => { const element = document.querySelector(sel); if (!element) { return { exists: false }; } const rect = element.getBoundingClientRect(); const styles = window.getComputedStyle(element); const computedStyles = {}; // Get key computed styles ['display', 'visibility', 'opacity', 'position', 'top', 'left', 'width', 'height'].forEach(prop => { computedStyles[prop] = styles.getPropertyValue(prop); }); return { exists: true, visible: rect.width > 0 && rect.height > 0 && styles.display !== 'none' && styles.visibility !== 'hidden', properties: { tagName: element.tagName, id: element.id, className: element.className, textContent: element.textContent?.trim(), innerHTML: element.innerHTML.substring(0, 200), rect: { top: rect.top, left: rect.left, width: rect.width, height: rect.height } }, computedStyles }; }, selector); } /** * Inspect multiple elements in a single evaluation for efficiency */ async inspectMultipleElements(selectors) { if (!this.page) { throw new Error('No page attached'); } return await this.page.evaluate((sels) => { return sels.map(sel => { const element = document.querySelector(sel); if (!element) { return { selector: sel, exists: false }; } const rect = element.getBoundingClientRect(); const styles = window.getComputedStyle(element); const computedStyles = {}; ['display', 'visibility', 'opacity', 'position'].forEach(prop => { computedStyles[prop] = styles.getPropertyValue(prop); }); return { selector: sel, exists: true, visible: rect.width > 0 && rect.height > 0 && styles.display !== 'none' && styles.visibility !== 'hidden', properties: { tagName: element.tagName, id: element.id, className: element.className, textContent: element.textContent?.trim() }, computedStyles }; }); }, selectors); } /** * Find all elements matching a selector */ async findAllElements(selector) { if (!this.page) { throw new Error('No page attached'); } return await this.page.evaluate((sel) => { const elements = document.querySelectorAll(sel); return Array.from(elements).map(element => ({ tagName: element.tagName, id: element.id, className: element.className })); }, selector); } /** * Check if an element exists */ async elementExists(selector) { if (!this.page) { throw new Error('No page attached'); } return await this.page.evaluate((sel) => { return document.querySelector(sel) !== null; }, selector); } /** * Check if an element is visible */ async isElementVisible(selector) { if (!this.page) { throw new Error('No page attached'); } return await this.page.evaluate((sel) => { const element = document.querySelector(sel); if (!element) return false; const rect = element.getBoundingClientRect(); const styles = window.getComputedStyle(element); return rect.width > 0 && rect.height > 0 && styles.display !== 'none' && styles.visibility !== 'hidden' && styles.opacity !== '0'; }, selector); } /** * Get the count of elements matching a selector */ async getElementCount(selector) { if (!this.page) { throw new Error('No page attached'); } return await this.page.evaluate((sel) => { return document.querySelectorAll(sel).length; }, selector); } /** * Get all attributes of an element */ async getElementAttributes(selector) { if (!this.page) { throw new Error('No page attached'); } return await this.page.evaluate((sel) => { const element = document.querySelector(sel); if (!element) return null; const attributes = {}; for (const attr of Array.from(element.attributes)) { attributes[attr.name] = attr.value; } return attributes; }, selector); } /** * Get computed styles for an element */ async getComputedStyles(selector, properties) { if (!this.page) { throw new Error('No page attached'); } const propertiesToGet = properties || [ 'display', 'visibility', 'opacity', 'position', 'top', 'left', 'width', 'height', 'color', 'backgroundColor', 'fontSize', 'fontFamily' ]; return await this.page.evaluate((data) => { const element = document.querySelector(data.selector); if (!element) return null; const styles = window.getComputedStyle(element); const computedStyles = {}; data.properties.forEach((prop) => { computedStyles[prop] = styles.getPropertyValue(prop); }); return computedStyles; }, { selector, properties: propertiesToGet }); } /** * Get element bounds (getBoundingClientRect) */ async getElementBounds(selector) { if (!this.page) { throw new Error('No page attached'); } return await this.page.evaluate((sel) => { const element = document.querySelector(sel); if (!element) return null; const rect = element.getBoundingClientRect(); return { top: rect.top, left: rect.left, width: rect.width, height: rect.height, right: rect.right, bottom: rect.bottom }; }, selector); } } //# sourceMappingURL=element-inspection-coordinator.js.map