UNPKG

chromancer

Version:

A powerful command-line interface for automating Chrome browser using Playwright. Perfect for web scraping, automation, testing, and browser workflows.

170 lines (169 loc) 7.06 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.checkMultipleMatches = checkMultipleMatches; exports.formatElementMatches = formatElementMatches; exports.getInteractiveSelection = getInteractiveSelection; /** * Check if a selector matches multiple elements and return disambiguation info */ async function checkMultipleMatches(page, selector) { const count = await page.locator(selector).count(); if (count <= 1) { return { count }; } // Get info about first few matches for disambiguation const elements = []; const limit = Math.min(count, 10); // Show max 10 options for (let i = 0; i < limit; i++) { const locator = page.locator(selector).nth(i); const elementInfo = await locator.evaluate((el, index) => { const rect = el.getBoundingClientRect(); // Generate unique selector for this specific element function getUniqueSelector(element) { // Priority 1: ID if (element.id) { return '#' + element.id; } // Priority 2: Unique class combination if (element.className) { const classes = element.className.split(' ').filter(c => c.trim()); const validClasses = classes.filter(c => /^[a-zA-Z_-][a-zA-Z0-9_-]*$/.test(c)); if (validClasses.length > 0) { const firstClassSelector = '.' + validClasses[0]; if (document.querySelectorAll(firstClassSelector).length === 1) { return firstClassSelector; } // Try combination of classes for (let i = 2; i <= Math.min(validClasses.length, 3); i++) { const classSelector = '.' + validClasses.slice(0, i).join('.'); try { if (document.querySelectorAll(classSelector).length === 1) { return classSelector; } } catch (e) { // Invalid selector, skip } } } } // Priority 3: nth-child based on original selector const parent = element.parentElement; if (parent) { const siblings = Array.from(parent.querySelectorAll(':scope > ' + element.tagName)); const index = siblings.indexOf(element) + 1; return `${element.tagName.toLowerCase()}:nth-child(${index})`; } // Fallback: Use nth-of-type return `${element.tagName.toLowerCase()}:nth-of-type(${index + 1})`; } return { index: index, selector: getUniqueSelector(el), tagName: el.tagName.toLowerCase(), textContent: el.textContent?.trim().substring(0, 50) || '', visible: rect.width > 0 && rect.height > 0, id: el.id || undefined, classes: el.className ? el.className.split(' ').filter((c) => c.trim()) : undefined, position: { top: Math.round(rect.top), left: Math.round(rect.left), width: Math.round(rect.width), height: Math.round(rect.height), }, }; }, i); elements.push(elementInfo); } return { count, elements }; } /** * Format element matches for display */ function formatElementMatches(elements) { const lines = []; lines.push(`Found ${elements.length} elements. Please use a more specific selector:`); lines.push('---'); for (const el of elements) { const visibilityIcon = el.visible ? '✓ visible' : '✗ hidden'; const text = el.textContent ? ` - "${el.textContent}"` : ''; lines.push(`[${el.index}] <${el.tagName}> ${visibilityIcon}`); lines.push(` Suggested selector: ${el.selector}`); if (el.id) { lines.push(` ID: ${el.id}`); } if (el.classes && el.classes.length > 0) { lines.push(` Classes: ${el.classes.join(', ')}`); } if (text) { lines.push(` Text: ${text}`); } lines.push(` Position: ${el.position.left}x${el.position.top}`); lines.push(''); } return lines.join('\n'); } /** * Get interactive selection from user (requires inquirer) */ async function getInteractiveSelection(elements) { try { const inquirer = await Promise.resolve().then(() => __importStar(require('inquirer'))); const choices = elements.map((el) => { const visibilityIcon = el.visible ? '✓' : '✗'; const text = el.textContent ? ` - "${el.textContent}"` : ''; return { name: `[${el.index}] <${el.tagName}> ${visibilityIcon} ${el.selector}${text}`, value: el.selector, short: el.selector, }; }); const { selectedSelector } = await inquirer.default.prompt([ { type: 'list', name: 'selectedSelector', message: 'Multiple elements found. Select one:', choices, pageSize: 10, }, ]); return selectedSelector; } catch (error) { // If interactive mode fails, return null return null; } }