claude-playwright
Version:
Seamless integration between Claude Code and Playwright MCP for efficient browser automation and testing
1 lines • 44.2 kB
Source Map (JSON)
{"version":3,"sources":["../../src/core/bidirectional-cache.ts","../../src/core/smart-normalizer.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport { SmartNormalizer, NormalizationResult } from './smart-normalizer.js';\nimport crypto from 'crypto';\nimport * as path from 'path';\nimport * as os from 'os';\nimport * as fs from 'fs';\n\ninterface SelectorCacheEntry {\n id?: number;\n selector: string;\n selector_hash: string;\n url: string;\n confidence: number;\n created_at: number;\n last_used: number;\n use_count: number;\n}\n\ninterface InputMappingEntry {\n id?: number;\n selector_hash: string;\n input: string;\n normalized_input: string;\n input_tokens: string; // JSON array\n url: string;\n success_count: number;\n last_used: number;\n confidence: number;\n learned_from: 'direct' | 'inferred' | 'pattern';\n}\n\ninterface CacheOptions {\n maxSizeMB?: number;\n selectorTTL?: number;\n cleanupInterval?: number;\n maxVariationsPerSelector?: number;\n}\n\ninterface LookupResult {\n selector: string;\n confidence: number;\n source: 'exact' | 'normalized' | 'reverse' | 'fuzzy';\n cached: boolean;\n}\n\nexport class BidirectionalCache {\n private db: Database.Database;\n private normalizer: SmartNormalizer;\n private cleanupTimer?: NodeJS.Timeout;\n private options: Required<CacheOptions>;\n private cacheDir: string;\n private stats = {\n hits: { exact: 0, normalized: 0, reverse: 0, fuzzy: 0 },\n misses: 0,\n sets: 0,\n learnings: 0\n };\n\n constructor(options: CacheOptions = {}) {\n this.options = {\n maxSizeMB: options.maxSizeMB ?? 50,\n selectorTTL: options.selectorTTL ?? 300000, // 5 minutes\n cleanupInterval: options.cleanupInterval ?? 60000, // 1 minute\n maxVariationsPerSelector: options.maxVariationsPerSelector ?? 20\n };\n\n this.normalizer = new SmartNormalizer();\n \n // Create cache directory\n this.cacheDir = path.join(os.homedir(), '.claude-playwright', 'cache');\n if (!fs.existsSync(this.cacheDir)) {\n fs.mkdirSync(this.cacheDir, { recursive: true });\n }\n\n // Initialize database\n const dbPath = path.join(this.cacheDir, 'bidirectional-cache.db');\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('synchronous = NORMAL');\n \n this.initializeDatabase();\n this.startCleanupTimer();\n }\n\n private initializeDatabase(): void {\n this.db.exec(`\n -- Enhanced selector cache table\n CREATE TABLE IF NOT EXISTS selector_cache_v2 (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n selector TEXT NOT NULL,\n selector_hash TEXT NOT NULL UNIQUE,\n url TEXT NOT NULL,\n confidence REAL DEFAULT 0.5,\n created_at INTEGER NOT NULL,\n last_used INTEGER NOT NULL,\n use_count INTEGER DEFAULT 1\n );\n\n -- Bidirectional input mappings\n CREATE TABLE IF NOT EXISTS input_mappings (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n selector_hash TEXT NOT NULL,\n input TEXT NOT NULL,\n normalized_input TEXT NOT NULL,\n input_tokens TEXT NOT NULL,\n url TEXT NOT NULL,\n success_count INTEGER DEFAULT 1,\n last_used INTEGER NOT NULL,\n confidence REAL DEFAULT 0.5,\n learned_from TEXT DEFAULT 'direct',\n FOREIGN KEY (selector_hash) REFERENCES selector_cache_v2(selector_hash),\n UNIQUE(selector_hash, normalized_input, url)\n );\n\n -- Performance indices\n CREATE INDEX IF NOT EXISTS idx_selector_hash_v2 ON selector_cache_v2(selector_hash);\n CREATE INDEX IF NOT EXISTS idx_url_v2 ON selector_cache_v2(url);\n CREATE INDEX IF NOT EXISTS idx_input_normalized ON input_mappings(normalized_input, url);\n CREATE INDEX IF NOT EXISTS idx_mapping_selector_hash ON input_mappings(selector_hash);\n CREATE INDEX IF NOT EXISTS idx_url_selector ON input_mappings(url, selector_hash);\n CREATE INDEX IF NOT EXISTS idx_tokens ON input_mappings(input_tokens);\n\n -- Migration: Copy from old cache if exists\n INSERT OR IGNORE INTO selector_cache_v2 (selector, selector_hash, url, confidence, created_at, last_used)\n SELECT data as selector, \n substr(cache_key, 1, 32) as selector_hash,\n url,\n 0.5 as confidence,\n created_at,\n accessed_at as last_used\n FROM cache \n WHERE cache_type = 'selector' \n AND NOT EXISTS (SELECT 1 FROM selector_cache_v2 WHERE selector_hash = substr(cache.cache_key, 1, 32));\n `);\n }\n\n async set(input: string, url: string, selector: string): Promise<void> {\n const now = Date.now();\n const selectorHash = this.createSelectorHash(selector);\n const normalizedResult = this.normalizer.normalize(input);\n\n try {\n // Begin transaction\n const transaction = this.db.transaction(() => {\n // 1. Store/update selector\n const selectorStmt = this.db.prepare(`\n INSERT INTO selector_cache_v2 \n (selector, selector_hash, url, confidence, created_at, last_used, use_count)\n VALUES (?, ?, ?, 0.5, ?, ?, 1)\n ON CONFLICT(selector_hash) DO UPDATE SET\n last_used = excluded.last_used,\n use_count = use_count + 1,\n confidence = MIN(confidence * 1.02, 1.0)\n `);\n \n selectorStmt.run(selector, selectorHash, url, now, now);\n\n // 2. Store input mapping\n const mappingStmt = this.db.prepare(`\n INSERT INTO input_mappings \n (selector_hash, input, normalized_input, input_tokens, url, last_used, learned_from)\n VALUES (?, ?, ?, ?, ?, ?, 'direct')\n ON CONFLICT(selector_hash, normalized_input, url) DO UPDATE SET\n success_count = success_count + 1,\n confidence = MIN(confidence * 1.05, 1.0),\n last_used = excluded.last_used,\n input = CASE \n WHEN length(excluded.input) > length(input) THEN excluded.input \n ELSE input \n END\n `);\n\n mappingStmt.run(\n selectorHash,\n input,\n normalizedResult.normalized,\n JSON.stringify(normalizedResult.tokens),\n url,\n now\n );\n });\n\n transaction();\n this.stats.sets++;\n\n // 3. Learn from related inputs (async, non-blocking)\n setImmediate(() => this.learnRelatedInputs(selectorHash, input, url, normalizedResult));\n\n } catch (error) {\n console.error('[BidirectionalCache] Set error:', error);\n }\n }\n\n async get(input: string, url: string): Promise<LookupResult | null> {\n const normalizedResult = this.normalizer.normalize(input);\n\n // Level 1: Exact Match\n const exactResult = await this.exactMatch(input, url);\n if (exactResult) {\n this.stats.hits.exact++;\n return { ...exactResult, source: 'exact', cached: true };\n }\n\n // Level 2: Normalized Match\n const normalizedMatch = await this.normalizedMatch(normalizedResult.normalized, url);\n if (normalizedMatch) {\n this.stats.hits.normalized++;\n return { ...normalizedMatch, source: 'normalized', cached: true };\n }\n\n // Level 3: Reverse Lookup\n const reverseMatch = await this.reverseLookup(normalizedResult, url);\n if (reverseMatch) {\n this.stats.hits.reverse++;\n return { ...reverseMatch, source: 'reverse', cached: true };\n }\n\n // Level 4: Fuzzy Match (typo tolerance)\n const fuzzyMatch = await this.fuzzyMatch(normalizedResult, url);\n if (fuzzyMatch) {\n this.stats.hits.fuzzy++;\n return { ...fuzzyMatch, source: 'fuzzy', cached: true };\n }\n\n this.stats.misses++;\n return null;\n }\n\n private async exactMatch(input: string, url: string): Promise<{ selector: string; confidence: number } | null> {\n try {\n const stmt = this.db.prepare(`\n SELECT sc.selector, im.confidence\n FROM input_mappings im\n JOIN selector_cache_v2 sc ON sc.selector_hash = im.selector_hash\n WHERE im.input = ? AND im.url = ?\n ORDER BY im.confidence DESC, im.success_count DESC\n LIMIT 1\n `);\n\n const result = stmt.get(input, url) as { selector: string; confidence: number } | undefined;\n if (result) {\n await this.updateUsage(result.selector, url);\n return result;\n }\n } catch (error) {\n console.error('[BidirectionalCache] Exact match error:', error);\n }\n return null;\n }\n\n private async normalizedMatch(normalized: string, url: string): Promise<{ selector: string; confidence: number } | null> {\n try {\n const stmt = this.db.prepare(`\n SELECT sc.selector, im.confidence\n FROM input_mappings im\n JOIN selector_cache_v2 sc ON sc.selector_hash = im.selector_hash\n WHERE im.normalized_input = ? AND im.url = ?\n ORDER BY im.confidence DESC, im.success_count DESC\n LIMIT 1\n `);\n\n const result = stmt.get(normalized, url) as { selector: string; confidence: number } | undefined;\n if (result) {\n await this.updateUsage(result.selector, url);\n return result;\n }\n } catch (error) {\n console.error('[BidirectionalCache] Normalized match error:', error);\n }\n return null;\n }\n\n private async reverseLookup(normalizedResult: NormalizationResult, url: string): Promise<{ selector: string; confidence: number } | null> {\n try {\n // Find selectors with similar token patterns\n const stmt = this.db.prepare(`\n SELECT \n sc.selector,\n im.confidence,\n im.input_tokens,\n im.success_count,\n GROUP_CONCAT(im.input) as all_inputs\n FROM input_mappings im\n JOIN selector_cache_v2 sc ON sc.selector_hash = im.selector_hash\n WHERE im.url = ?\n AND json_array_length(im.input_tokens) > 0\n GROUP BY sc.selector_hash\n ORDER BY im.confidence DESC, im.success_count DESC\n LIMIT 10\n `);\n\n const candidates = stmt.all(url) as Array<{\n selector: string;\n confidence: number;\n input_tokens: string;\n success_count: number;\n all_inputs: string;\n }>;\n\n let bestMatch: { selector: string; confidence: number } | null = null;\n let bestScore = 0;\n\n for (const candidate of candidates) {\n try {\n const candidateTokens = JSON.parse(candidate.input_tokens);\n const similarity = this.calculateJaccardSimilarity(\n normalizedResult.tokens,\n candidateTokens\n );\n\n // Boost score based on success count and confidence\n const boostedScore = similarity * \n (1 + Math.log(1 + candidate.success_count) * 0.1) *\n candidate.confidence;\n\n if (boostedScore > 0.6 && boostedScore > bestScore) {\n bestScore = boostedScore;\n bestMatch = {\n selector: candidate.selector,\n confidence: candidate.confidence * 0.9 // Slight penalty for reverse lookup\n };\n }\n } catch (e) {\n // Skip malformed JSON\n continue;\n }\n }\n\n if (bestMatch) {\n await this.updateUsage(bestMatch.selector, url);\n return bestMatch;\n }\n } catch (error) {\n console.error('[BidirectionalCache] Reverse lookup error:', error);\n }\n return null;\n }\n\n private async fuzzyMatch(normalizedResult: NormalizationResult, url: string): Promise<{ selector: string; confidence: number } | null> {\n try {\n const stmt = this.db.prepare(`\n SELECT sc.selector, im.normalized_input, im.confidence\n FROM input_mappings im\n JOIN selector_cache_v2 sc ON sc.selector_hash = im.selector_hash\n WHERE im.url = ?\n AND im.last_used > ?\n ORDER BY im.confidence DESC, im.success_count DESC\n LIMIT 20\n `);\n\n const candidates = stmt.all(url, Date.now() - 3600000) as Array<{ // Last hour only\n selector: string;\n normalized_input: string;\n confidence: number;\n }>;\n\n for (const candidate of candidates) {\n const distance = this.normalizer.damerauLevenshtein(\n normalizedResult.normalized,\n candidate.normalized_input\n );\n\n const maxDistance = Math.floor(normalizedResult.normalized.length / 8); // 12.5% tolerance\n \n if (distance <= maxDistance && distance > 0) {\n await this.updateUsage(candidate.selector, url);\n return {\n selector: candidate.selector,\n confidence: candidate.confidence * (1 - distance / 10) // Penalty for typos\n };\n }\n }\n } catch (error) {\n console.error('[BidirectionalCache] Fuzzy match error:', error);\n }\n return null;\n }\n\n private calculateJaccardSimilarity(set1: string[], set2: string[]): number {\n const intersection = set1.filter(x => set2.includes(x));\n const union = [...new Set([...set1, ...set2])];\n return intersection.length / union.length;\n }\n\n private createSelectorHash(selector: string): string {\n return crypto.createHash('md5').update(selector).digest('hex');\n }\n\n private async updateUsage(selector: string, url: string): Promise<void> {\n try {\n const now = Date.now();\n const selectorHash = this.createSelectorHash(selector);\n \n const stmt = this.db.prepare(`\n UPDATE selector_cache_v2 \n SET last_used = ?, use_count = use_count + 1\n WHERE selector_hash = ? AND url = ?\n `);\n \n stmt.run(now, selectorHash, url);\n } catch (error) {\n console.error('[BidirectionalCache] Update usage error:', error);\n }\n }\n\n private async learnRelatedInputs(\n selectorHash: string, \n newInput: string, \n url: string, \n normalizedResult: NormalizationResult\n ): Promise<void> {\n try {\n // Find other inputs for the same selector\n const stmt = this.db.prepare(`\n SELECT input, normalized_input, input_tokens, confidence\n FROM input_mappings\n WHERE selector_hash = ? AND url = ? AND input != ?\n AND success_count > 1\n ORDER BY confidence DESC\n LIMIT 5\n `);\n\n const related = stmt.all(selectorHash, url, newInput) as Array<{\n input: string;\n normalized_input: string;\n input_tokens: string;\n confidence: number;\n }>;\n\n for (const rel of related) {\n const pattern = this.findCommonPattern(newInput, rel.input);\n if (pattern && pattern.confidence > 0.7) {\n await this.saveLearnedPattern(pattern, selectorHash, url);\n this.stats.learnings++;\n }\n }\n } catch (error) {\n console.error('[BidirectionalCache] Learn related inputs error:', error);\n }\n }\n\n private findCommonPattern(input1: string, input2: string): { pattern: string; confidence: number } | null {\n // Simple pattern extraction - can be enhanced\n const norm1 = this.normalizer.normalize(input1);\n const norm2 = this.normalizer.normalize(input2);\n \n const commonTokens = norm1.tokens.filter(t => norm2.tokens.includes(t));\n if (commonTokens.length >= 2) {\n return {\n pattern: commonTokens.sort().join(' '),\n confidence: commonTokens.length / Math.max(norm1.tokens.length, norm2.tokens.length)\n };\n }\n \n return null;\n }\n\n private async saveLearnedPattern(\n pattern: { pattern: string; confidence: number },\n selectorHash: string,\n url: string\n ): Promise<void> {\n try {\n const now = Date.now();\n const stmt = this.db.prepare(`\n INSERT OR IGNORE INTO input_mappings\n (selector_hash, input, normalized_input, input_tokens, url, last_used, confidence, learned_from)\n VALUES (?, ?, ?, ?, ?, ?, ?, 'pattern')\n `);\n\n stmt.run(\n selectorHash,\n `Pattern: ${pattern.pattern}`,\n pattern.pattern,\n JSON.stringify(pattern.pattern.split(' ')),\n url,\n now,\n pattern.confidence,\n );\n } catch (error) {\n // Ignore conflicts - pattern might already exist\n }\n }\n\n private startCleanupTimer(): void {\n this.cleanupTimer = setInterval(() => {\n this.cleanup();\n }, this.options.cleanupInterval);\n }\n\n private cleanup(): void {\n try {\n const now = Date.now();\n \n // Remove expired entries\n const expiredStmt = this.db.prepare(`\n DELETE FROM input_mappings \n WHERE (last_used + ?) < ?\n `);\n expiredStmt.run(this.options.selectorTTL, now);\n\n // Limit variations per selector\n const limitStmt = this.db.prepare(`\n DELETE FROM input_mappings\n WHERE id NOT IN (\n SELECT id FROM (\n SELECT id, ROW_NUMBER() OVER (\n PARTITION BY selector_hash, url \n ORDER BY confidence DESC, success_count DESC, last_used DESC\n ) as rn\n FROM input_mappings\n ) WHERE rn <= ?\n )\n `);\n limitStmt.run(this.options.maxVariationsPerSelector);\n\n // Clean orphaned selectors\n const orphanStmt = this.db.prepare(`\n DELETE FROM selector_cache_v2\n WHERE selector_hash NOT IN (\n SELECT DISTINCT selector_hash FROM input_mappings\n )\n `);\n orphanStmt.run();\n\n } catch (error) {\n console.error('[BidirectionalCache] Cleanup error:', error);\n }\n }\n\n async getStats(): Promise<any> {\n try {\n const dbStats = this.db.prepare(`\n SELECT \n COUNT(DISTINCT sc.selector_hash) as unique_selectors,\n COUNT(im.id) as total_mappings,\n AVG(im.success_count) as avg_success_count,\n COUNT(im.id) * 1.0 / COUNT(DISTINCT sc.selector_hash) as avg_inputs_per_selector,\n SUM(CASE WHEN im.learned_from = 'inferred' THEN 1 ELSE 0 END) * 100.0 / COUNT(im.id) as learning_rate\n FROM input_mappings im\n JOIN selector_cache_v2 sc ON sc.selector_hash = im.selector_hash\n `).get();\n\n const hitRate = Object.values(this.stats.hits).reduce((a, b) => a + b, 0) / \n (Object.values(this.stats.hits).reduce((a, b) => a + b, 0) + this.stats.misses);\n\n return {\n performance: {\n hitRate: hitRate || 0,\n hits: this.stats.hits,\n misses: this.stats.misses,\n totalLookups: Object.values(this.stats.hits).reduce((a, b) => a + b, 0) + this.stats.misses\n },\n storage: dbStats,\n operations: {\n sets: this.stats.sets,\n learnings: this.stats.learnings\n }\n };\n } catch (error) {\n console.error('[BidirectionalCache] Get stats error:', error);\n return {};\n }\n }\n\n async clear(): Promise<void> {\n try {\n this.db.exec('DELETE FROM input_mappings');\n this.db.exec('DELETE FROM selector_cache_v2');\n \n // Reset stats\n this.stats = {\n hits: { exact: 0, normalized: 0, reverse: 0, fuzzy: 0 },\n misses: 0,\n sets: 0,\n learnings: 0\n };\n } catch (error) {\n console.error('[BidirectionalCache] Clear error:', error);\n }\n }\n\n close(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n }\n this.db.close();\n }\n}","import crypto from 'crypto';\n\ninterface PositionalKeyword {\n word: string;\n position: number;\n context?: string;\n}\n\ninterface InputFeatures {\n hasId: boolean;\n hasClass: boolean;\n hasQuoted: boolean;\n numbers: string[];\n positions: PositionalKeyword[];\n attributes: string[];\n wordCount: number;\n hasImperative: boolean;\n casePattern: 'lower' | 'upper' | 'mixed' | 'title';\n isNavigation: boolean;\n isFormAction: boolean;\n hasDataTestId: boolean;\n}\n\nexport interface NormalizationResult {\n normalized: string;\n tokens: string[];\n positions: PositionalKeyword[];\n features: InputFeatures;\n hash: string;\n}\n\nexport class SmartNormalizer {\n private readonly POSITION_KEYWORDS = [\n 'before', 'after', 'first', 'last', 'next', 'previous', \n 'above', 'below', 'top', 'bottom', 'left', 'right'\n ];\n \n private readonly RELATION_KEYWORDS = [\n 'in', 'of', 'from', 'to', 'with', 'by', 'for'\n ];\n \n private readonly STOP_WORDS = [\n 'the', 'a', 'an', 'and', 'or', 'but', 'at', 'on'\n ];\n \n private readonly ACTION_SYNONYMS = {\n 'click': ['click', 'press', 'tap', 'hit', 'select', 'choose'],\n 'type': ['type', 'enter', 'input', 'fill', 'write'],\n 'navigate': ['go', 'navigate', 'open', 'visit', 'load'],\n 'hover': ['hover', 'mouseover', 'move']\n };\n\n normalize(input: string): NormalizationResult {\n const original = input.trim();\n const features = this.extractFeatures(original);\n \n // Step 1: Basic cleanup\n let text = original.toLowerCase();\n \n // Step 2: Extract and preserve quoted strings\n const quotedStrings: string[] = [];\n text = text.replace(/([\"'])((?:(?!\\1)[^\\\\]|\\\\.)*)(\\1)/g, (match, quote, content) => {\n quotedStrings.push(content);\n return `QUOTED_${quotedStrings.length - 1}`;\n });\n \n // Step 3: Extract positional information\n const positions = this.extractPositions(text);\n \n // Step 4: Normalize actions to canonical forms\n text = this.normalizeActions(text);\n \n // Step 5: Remove common patterns\n text = this.removeCommonPatterns(text);\n \n // Step 6: Tokenize and filter\n const words = text.split(/\\s+/).filter(word => word.length > 0);\n const tokens = [];\n const preserved = [];\n \n for (let i = 0; i < words.length; i++) {\n const word = words[i];\n \n if (this.POSITION_KEYWORDS.includes(word)) {\n // Preserve positional keywords with context\n preserved.push({\n word,\n position: i,\n context: words[i + 1] || null\n });\n } else if (!this.STOP_WORDS.includes(word) && \n !this.RELATION_KEYWORDS.includes(word) &&\n !['button', 'field', 'element'].includes(word)) {\n tokens.push(word);\n }\n }\n \n // Step 7: Sort tokens for order-invariance (except preserved)\n tokens.sort();\n \n // Step 8: Build normalized string\n let normalized = tokens.join(' ');\n \n // Step 9: Add positional information\n if (preserved.length > 0) {\n const posInfo = preserved.map(p => \n `${p.word}${p.context ? '-' + p.context : ''}`\n ).join(',');\n normalized += ` _pos:${posInfo}`;\n }\n \n // Step 10: Add quoted content back\n if (quotedStrings.length > 0) {\n normalized += ` _quoted:${quotedStrings.join(',')}`;\n }\n \n const hash = crypto.createHash('md5').update(normalized).digest('hex');\n \n return {\n normalized,\n tokens,\n positions,\n features,\n hash\n };\n }\n\n extractFeatures(input: string): InputFeatures {\n const text = input.toLowerCase();\n \n return {\n hasId: /#[\\w-]+/.test(input),\n hasClass: /\\.[\\w-]+/.test(input),\n hasQuoted: /\"[^\"]+\"|'[^']+'/.test(input),\n numbers: (input.match(/\\d+/g) || []),\n positions: this.extractPositions(text),\n attributes: this.extractAttributes(input),\n wordCount: input.split(/\\s+/).length,\n hasImperative: /^(click|press|tap|select|enter|type|fill)/i.test(input),\n casePattern: this.detectCasePattern(input),\n isNavigation: /^(go|navigate|open|visit)/i.test(input),\n isFormAction: /(submit|enter|fill|type|input)/i.test(input),\n hasDataTestId: /data-test|testid|data-cy/i.test(input)\n };\n }\n\n private extractPositions(text: string): PositionalKeyword[] {\n const positions: PositionalKeyword[] = [];\n const words = text.split(/\\s+/);\n \n for (let i = 0; i < words.length; i++) {\n const word = words[i];\n if (this.POSITION_KEYWORDS.includes(word)) {\n positions.push({\n word,\n position: i,\n context: words[i + 1] || words[i - 1] || undefined\n });\n }\n }\n \n return positions;\n }\n\n private extractAttributes(input: string): string[] {\n const attributes = [];\n \n // Extract common attribute patterns\n const patterns = [\n /\\[([^\\]]+)\\]/g, // [attribute=value]\n /data-[\\w-]+/g, // data-testid\n /aria-[\\w-]+/g, // aria-label\n /role=\"[\\w-]+\"/g, // role=\"button\"\n /type=\"[\\w-]+\"/g, // type=\"submit\"\n /placeholder=\"[^\"]+\"/g // placeholder=\"text\"\n ];\n \n for (const pattern of patterns) {\n const matches = input.match(pattern);\n if (matches) {\n attributes.push(...matches);\n }\n }\n \n return attributes;\n }\n\n private detectCasePattern(input: string): 'lower' | 'upper' | 'mixed' | 'title' {\n const hasLower = /[a-z]/.test(input);\n const hasUpper = /[A-Z]/.test(input);\n \n if (!hasLower && hasUpper) return 'upper';\n if (hasLower && !hasUpper) return 'lower';\n \n // Check if it's title case\n const words = input.split(/\\s+/);\n const isTitleCase = words.every(word => \n /^[A-Z][a-z]*$/.test(word) || /^[a-z]+$/.test(word)\n );\n \n return isTitleCase ? 'title' : 'mixed';\n }\n\n private normalizeActions(text: string): string {\n for (const [canonical, synonyms] of Object.entries(this.ACTION_SYNONYMS)) {\n for (const synonym of synonyms) {\n const regex = new RegExp(`\\\\b${synonym}\\\\b`, 'g');\n text = text.replace(regex, canonical);\n }\n }\n return text;\n }\n\n private removeCommonPatterns(text: string): string {\n // Remove common prefixes and suffixes\n text = text.replace(/^(click|press|tap)(\\s+on)?(\\s+the)?/i, 'click');\n text = text.replace(/\\s+(button|element|field)$/i, '');\n text = text.replace(/button\\s+/i, '');\n \n // Remove articles and common words\n text = text.replace(/\\b(the|a|an)\\b/g, '');\n \n // Clean up punctuation\n text = text.replace(/[^\\w\\s#._-]/g, ' ');\n \n // Normalize whitespace\n text = text.replace(/\\s+/g, ' ').trim();\n \n return text;\n }\n\n // Utility methods for similarity\n calculateSimilarity(result1: NormalizationResult, result2: NormalizationResult): number {\n // Token-based Jaccard similarity\n const set1 = new Set(result1.tokens);\n const set2 = new Set(result2.tokens);\n const intersection = new Set([...set1].filter(x => set2.has(x)));\n const union = new Set([...set1, ...set2]);\n \n let similarity = intersection.size / union.size;\n \n // Boost for matching quoted strings\n const quoted1 = result1.normalized.match(/_quoted:([^_]*)/)?.[1] || '';\n const quoted2 = result2.normalized.match(/_quoted:([^_]*)/)?.[1] || '';\n if (quoted1 === quoted2 && quoted1.length > 0) {\n similarity += 0.2;\n }\n \n // Penalty for mismatched positions\n const pos1 = result1.normalized.match(/_pos:([^_]*)/)?.[1] || '';\n const pos2 = result2.normalized.match(/_pos:([^_]*)/)?.[1] || '';\n if (pos1 !== pos2 && (pos1.length > 0 || pos2.length > 0)) {\n similarity -= 0.3;\n }\n \n return Math.max(0, Math.min(1, similarity));\n }\n\n // Fuzzy matching for typo tolerance\n damerauLevenshtein(a: string, b: string): number {\n const da: { [key: string]: number } = {};\n const maxdist = a.length + b.length;\n const H: number[][] = [];\n \n H[-1] = [];\n H[-1][-1] = maxdist;\n \n for (let i = 0; i <= a.length; i++) {\n H[i] = [];\n H[i][-1] = maxdist;\n H[i][0] = i;\n }\n \n for (let j = 0; j <= b.length; j++) {\n H[-1][j] = maxdist;\n H[0][j] = j;\n }\n \n for (let i = 1; i <= a.length; i++) {\n let db = 0;\n for (let j = 1; j <= b.length; j++) {\n const k = da[b[j - 1]] || 0;\n const l = db;\n let cost = 1;\n if (a[i - 1] === b[j - 1]) {\n cost = 0;\n db = j;\n }\n \n H[i][j] = Math.min(\n H[i - 1][j] + 1, // insertion\n H[i][j - 1] + 1, // deletion\n H[i - 1][j - 1] + cost, // substitution\n H[k - 1][l - 1] + (i - k - 1) + 1 + (j - l - 1) // transposition\n );\n }\n da[a[i - 1]] = i;\n }\n \n return H[a.length][b.length];\n }\n\n // Create fuzzy variations for learning\n generateVariations(input: string): string[] {\n const variations = [input];\n const normalized = this.normalize(input);\n \n // Generate common variations\n variations.push(input.toLowerCase());\n variations.push(input.replace(/\\s+/g, ' ').trim());\n variations.push(input.replace(/^(click|press)\\s+/i, 'tap '));\n variations.push(input.replace(/\\s+button$/i, ''));\n \n // Token permutations (limited)\n if (normalized.tokens.length <= 4) {\n const permutations = this.generateTokenPermutations(normalized.tokens);\n variations.push(...permutations.slice(0, 3)); // Limit to 3 permutations\n }\n \n return [...new Set(variations)];\n }\n\n private generateTokenPermutations(tokens: string[]): string[] {\n if (tokens.length <= 1) return tokens;\n if (tokens.length > 4) return []; // Too many combinations\n \n const result: string[] = [];\n const permute = (arr: string[], start = 0) => {\n if (start === arr.length) {\n result.push(arr.join(' '));\n return;\n }\n \n for (let i = start; i < arr.length; i++) {\n [arr[start], arr[i]] = [arr[i], arr[start]];\n permute(arr, start + 1);\n [arr[start], arr[i]] = [arr[i], arr[start]]; // backtrack\n }\n };\n \n permute([...tokens]);\n return result;\n }\n}"],"mappings":"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","names":["crypto","import_crypto","Database","crypto"]}