UNPKG

@useviber/plugin

Version:

Universal Viber Plugin - Works with any framework (React, Vue, Angular, Svelte, Vanilla)

970 lines (969 loc) 319 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ViberPlugin = {})); })(this, (function (exports) { 'use strict'; // Remove DeepFrameworkInfo types - use shared types instead class FrameworkDetector { static detectFramework() { if (this.isReact()) return 'react'; if (this.isVue()) return 'vue'; if (this.isAngular()) return 'angular'; if (this.isSvelte()) return 'svelte'; return 'vanilla'; } static isReact() { // Check for React global objects const hasReactGlobal = !!(window.React || window.ReactDOM || window.__REACT_DEVTOOLS_GLOBAL_HOOK__); // Check for React elements in DOM const hasReactElements = !!(document.querySelector('[data-reactroot]') || document.querySelector('[data-reactid]') || document.querySelector('[data-react-checksum]')); // Check for React-specific classes const hasReactClasses = !!(document.querySelector('.react-') || document.querySelector('[class*="react-"]') || document.querySelector('[class*="React"]')); // Check for React scripts const hasReactScripts = !!(document.querySelector('script[src*="react"]') || document.querySelector('script[src*="React"]')); return hasReactGlobal || hasReactElements || hasReactClasses || hasReactScripts; } static isVue() { return !!(window.Vue || window.__VUE__ || document.querySelector('[data-v-]') || document.querySelector('.v-application')); } static isAngular() { return !!(window.angular || window.ng || document.querySelector('[ng-version]') || document.querySelector('[ng-controller]')); } static isSvelte() { return !!(window.svelte || document.querySelector('[class*="svelte-"]') || document.querySelector('[data-svelte]')); } static isVanilla() { return !this.isReact() && !this.isVue() && !this.isAngular() && !this.isSvelte(); } // Main method to create unified component data static createUnifiedComponentData(element, currentPath) { var _a; console.log('🔍 [FrameworkDetector] Creating UnifiedComponentData for element:', element.tagName); console.log('🔍 [FrameworkDetector] Current path:', currentPath); const frameworkType = this.detectElementFramework(element); console.log('🔍 [FrameworkDetector] Detected framework type:', frameworkType); const baseInfo = { element: { tagName: element.tagName.toLowerCase(), className: element.className, id: element.id, innerText: ((_a = element.innerText) === null || _a === void 0 ? void 0 : _a.trim()) || '', attributes: this.getElementAttributes(element), boundingBox: element.getBoundingClientRect(), computedStyles: this.getComputedStyles(element), }, context: { currentPath, timestamp: new Date().toISOString(), url: window.location.href, }, }; console.log('🔍 [FrameworkDetector] Base info created, switching to framework-specific creation...'); let result; switch (frameworkType) { case 'react': console.log('🔍 [FrameworkDetector] Creating React unified data...'); result = this.createReactUnifiedData(element, baseInfo); break; case 'vue': console.log('🔍 [FrameworkDetector] Creating Vue unified data...'); result = this.createVueUnifiedData(element, baseInfo); break; case 'angular': console.log('🔍 [FrameworkDetector] Creating Angular unified data...'); result = this.createAngularUnifiedData(element, baseInfo); break; case 'svelte': console.log('🔍 [FrameworkDetector] Creating Svelte unified data...'); result = this.createSvelteUnifiedData(element, baseInfo); break; default: console.log('🔍 [FrameworkDetector] Creating Vanilla unified data...'); result = this.createVanillaUnifiedData(element, baseInfo); } console.log('🔍 [FrameworkDetector] Final UnifiedComponentData:', { frameworkType: result.framework.type, componentName: result.component.name, actualPath: result.file.actualPath, componentPath: result.file.componentPath, currentPath: baseInfo.context.currentPath }); return result; } // Framework-specific data creation methods static createReactUnifiedData(element, baseInfo) { const reactInfo = this.extractReactInfo(element); return { ...baseInfo, component: { name: reactInfo.componentName || element.tagName.toLowerCase(), displayName: reactInfo.componentName || element.tagName.toLowerCase(), type: 'react', }, framework: { type: 'react', reactInfo, }, file: { actualPath: reactInfo.componentFile || baseInfo.context.currentPath, componentPath: baseInfo.context.currentPath, extension: this.getFileExtension(reactInfo.componentFile), hasFileContent: !!reactInfo.componentFile, }, }; } static createVueUnifiedData(element, baseInfo) { const vueInfo = this.extractVueInfo(element); return { ...baseInfo, component: { name: vueInfo.componentName || element.tagName.toLowerCase(), displayName: vueInfo.componentName || element.tagName.toLowerCase(), type: 'vue', }, framework: { type: 'vue', vueInfo, }, file: { actualPath: vueInfo.componentFile || baseInfo.context.currentPath, componentPath: baseInfo.context.currentPath, extension: this.getFileExtension(vueInfo.componentFile), hasFileContent: !!vueInfo.componentFile, }, }; } static createAngularUnifiedData(element, baseInfo) { const angularInfo = this.extractAngularInfo(element); return { ...baseInfo, component: { name: angularInfo.componentName || element.tagName.toLowerCase(), displayName: angularInfo.componentName || element.tagName.toLowerCase(), type: 'angular', }, framework: { type: 'angular', angularInfo, }, file: { actualPath: angularInfo.componentFile || baseInfo.context.currentPath, componentPath: baseInfo.context.currentPath, extension: this.getFileExtension(angularInfo.componentFile), hasFileContent: !!angularInfo.componentFile, }, }; } static createSvelteUnifiedData(element, baseInfo) { const svelteInfo = this.extractSvelteInfo(element); return { ...baseInfo, component: { name: svelteInfo.componentName || element.tagName.toLowerCase(), displayName: svelteInfo.componentName || element.tagName.toLowerCase(), type: 'svelte', }, framework: { type: 'svelte', svelteInfo, }, file: { actualPath: svelteInfo.componentFile || baseInfo.context.currentPath, componentPath: baseInfo.context.currentPath, extension: this.getFileExtension(svelteInfo.componentFile), hasFileContent: !!svelteInfo.componentFile, }, }; } static createVanillaUnifiedData(element, baseInfo) { const vanillaInfo = this.extractVanillaInfo(element); return { ...baseInfo, component: { name: vanillaInfo.componentName || element.tagName.toLowerCase(), displayName: vanillaInfo.componentName || element.tagName.toLowerCase(), type: 'vanilla', }, framework: { type: 'vanilla', vanillaInfo, }, file: { actualPath: vanillaInfo.componentFile || baseInfo.context.currentPath, componentPath: baseInfo.context.currentPath, extension: this.getFileExtension(vanillaInfo.componentFile), hasFileContent: !!vanillaInfo.componentFile, }, }; } // Legacy method for backward compatibility - now returns UnifiedComponentData static analyzeElement(element) { const unifiedData = this.createUnifiedComponentData(element, window.location.pathname); const frameworkType = unifiedData.framework.type; return { type: frameworkType, element, componentName: unifiedData.component.displayName, componentPath: unifiedData.file.actualPath, hasState: this.hasState(element, frameworkType), stateKeys: this.getStateKeys(element, frameworkType), eventHandlers: this.getEventHandlers(element), ...this.getFrameworkSpecificProps(element, frameworkType), }; } // Remove analyzeElementDeep method - use createUnifiedComponentData instead // Helper methods static detectElementFramework(element) { console.log('🔍 [FrameworkDetector] Starting framework detection for element:', element.tagName); // Check React first const isReact = this.isReactElement(element); console.log('🔍 [FrameworkDetector] React detection result:', isReact); if (isReact) { console.log('✅ [FrameworkDetector] Detected as REACT'); return 'react'; } // Check Vue const isVue = this.isVueElement(element); console.log('🔍 [FrameworkDetector] Vue detection result:', isVue); if (isVue) { console.log('✅ [FrameworkDetector] Detected as VUE'); return 'vue'; } // Check Angular const isAngular = this.isAngularElement(element); console.log('🔍 [FrameworkDetector] Angular detection result:', isAngular); if (isAngular) { console.log('✅ [FrameworkDetector] Detected as ANGULAR'); return 'angular'; } // Check Svelte const isSvelte = this.isSvelteElement(element); console.log('🔍 [FrameworkDetector] Svelte detection result:', isSvelte); if (isSvelte) { console.log('✅ [FrameworkDetector] Detected as SVELTE'); return 'svelte'; } console.log('⚠️ [FrameworkDetector] No framework detected, defaulting to VANILLA'); return 'vanilla'; } static isReactElement(element) { console.log('🔍 [FrameworkDetector] Checking if element is React...'); const reactElement = element; // React 16-17 detection (same as React web client) console.log('🔍 [FrameworkDetector] Checking React 16-17 properties...'); console.log(' - _reactInternalFiber:', !!reactElement._reactInternalFiber); console.log(' - _reactEventPriority:', reactElement._reactEventPriority !== undefined); console.log(' - _reactLanes:', reactElement._reactLanes !== undefined); console.log(' - _reactProps:', !!reactElement._reactProps); console.log(' - _reactInternalInstance:', !!reactElement._reactInternalInstance); if (reactElement._reactInternalFiber || reactElement._reactEventPriority !== undefined || reactElement._reactLanes !== undefined || reactElement._reactProps || reactElement._reactInternalInstance || this.hasReactFiberKey(element)) { console.log('✅ [FrameworkDetector] React 16-17 properties found!'); return true; } // React 18+ detection - check for new internal properties (same as React web client) console.log('🔍 [FrameworkDetector] Checking React 18+ properties...'); const ownProps = Object.getOwnPropertyNames(element); console.log(' - Element own properties:', ownProps); const hasReact18Props = ownProps.some(key => key.startsWith('__reactProps$') || key.startsWith('__reactEvents$') || key.startsWith('__reactFiber$') || key.includes('react')); console.log(' - Has React 18+ properties:', hasReact18Props); if (hasReact18Props) { console.log('✅ [FrameworkDetector] React 18+ properties found!'); return true; } // Check for React attributes console.log('🔍 [FrameworkDetector] Checking React attributes...'); const hasReactAttributes = !!(element.hasAttribute('data-reactroot') || element.hasAttribute('data-reactid') || element.hasAttribute('data-react-checksum')); console.log(' - Has React attributes:', hasReactAttributes); // Check for React classes (common in development) console.log('🔍 [FrameworkDetector] Checking React classes...'); const hasReactClasses = !!(element.className.includes('react-') || element.className.includes('React') || element.classList.contains('react-component')); console.log(' - Has React classes:', hasReactClasses); console.log(' - Element className:', element.className); // Check if any parent has React properties console.log('🔍 [FrameworkDetector] Checking React parent...'); const hasReactParent = this.hasReactParent(element); console.log(' - Has React parent:', hasReactParent); // Check global React context console.log('🔍 [FrameworkDetector] Checking global React context...'); const hasGlobalReact = !!(window.React || window.__REACT_DEVTOOLS_GLOBAL_HOOK__ || window.ReactDOM); console.log(' - Has global React:', hasGlobalReact); console.log(' - window.React:', !!window.React); console.log(' - window.__REACT_DEVTOOLS_GLOBAL_HOOK__:', !!window.__REACT_DEVTOOLS_GLOBAL_HOOK__); console.log(' - window.ReactDOM:', !!window.ReactDOM); const finalResult = hasReactAttributes || hasReactClasses || hasReactParent || hasGlobalReact; console.log('🔍 [FrameworkDetector] Final React detection result:', finalResult); return finalResult; } /** * Check if element has React Fiber keys (same as React web client) */ static hasReactFiberKey(element) { const propertyNames = Object.getOwnPropertyNames(element); return propertyNames.some((key) => key.startsWith('__reactFiber$') || key.startsWith('__reactInternalInstance$') || key.startsWith('__reactProps$') || key.startsWith('__reactEvents$')); } static hasReactParent(element) { let parent = element.parentElement; let depth = 0; const maxDepth = 5; // Check up to 5 levels up while (parent && depth < maxDepth) { if (parent._reactInternalFiber || parent.__reactProps$ || parent.hasAttribute('data-reactroot')) { return true; } parent = parent.parentElement; depth++; } return false; } static isVueElement(element) { console.log('🔍 [FrameworkDetector] Checking if element is Vue...'); // Check for Vue 2 internal property const hasVue2 = !!element.__vue__; console.log(' - Has Vue 2 __vue__:', hasVue2); // Check for Vue 3 scoped CSS attributes (data-v-*) const hasVue3Scoped = element.hasAttribute('data-v-'); console.log(' - Has Vue 3 scoped CSS (data-v-):', hasVue3Scoped); // Check all data-v-* attributes const dataVAttributes = Array.from(element.attributes) .filter(attr => attr.name.startsWith('data-v-')) .map(attr => attr.name); console.log(' - All data-v-* attributes:', dataVAttributes); // Check for Vuetify classes const hasVuetify = element.classList.contains('v-application'); console.log(' - Has Vuetify class:', hasVuetify); // Check for Vue 3 internal properties const hasVue3Internal = !!element.__vnode || !!element.__vueParentComponent; console.log(' - Has Vue 3 internal properties:', hasVue3Internal); const isVue = hasVue2 || hasVue3Scoped || hasVuetify || hasVue3Internal; console.log(' - Final Vue detection result:', isVue); return isVue; } static isAngularElement(element) { return (!!element.__ngContext__ || element.hasAttribute('ng-version') || element.hasAttribute('ng-controller')); } static isSvelteElement(element) { return (!!element._svelte || element.classList.contains('svelte-') || element.hasAttribute('data-svelte')); } static getElementAttributes(element) { const attributes = {}; Array.from(element.attributes).forEach(attr => { attributes[attr.name] = attr.value; }); return attributes; } static getComputedStyles(element) { const styles = window.getComputedStyle(element); const computedStyles = {}; // Get common CSS properties const cssProperties = [ 'color', 'background-color', 'font-size', 'font-weight', 'padding', 'margin', 'border', 'border-radius', 'display', 'position', 'width', 'height', ]; cssProperties.forEach(prop => { computedStyles[prop] = styles.getPropertyValue(prop); }); return computedStyles; } static getFileExtension(filePath) { if (!filePath) return ''; const lastDotIndex = filePath.lastIndexOf('.'); return lastDotIndex > -1 ? filePath.substring(lastDotIndex + 1) : ''; } static hasState(element, frameworkType) { var _a, _b, _c, _d, _e; switch (frameworkType) { case 'react': return !!((_a = element._reactInternalFiber) === null || _a === void 0 ? void 0 : _a.memoizedState); case 'vue': return !!((_b = element.__vue__) === null || _b === void 0 ? void 0 : _b.$data); case 'angular': return !!((_c = element.__ngContext__) === null || _c === void 0 ? void 0 : _c.componentInstance); case 'svelte': return !!((_e = (_d = element._svelte) === null || _d === void 0 ? void 0 : _d.$$) === null || _e === void 0 ? void 0 : _e.dirty); default: return false; } } static getStateKeys(element, frameworkType) { var _a, _b, _c, _d, _e; switch (frameworkType) { case 'react': const reactState = (_a = element._reactInternalFiber) === null || _a === void 0 ? void 0 : _a.memoizedState; return reactState ? Object.keys(reactState) : []; case 'vue': const vueData = (_b = element.__vue__) === null || _b === void 0 ? void 0 : _b.$data; return vueData ? Object.keys(vueData) : []; case 'angular': const angularInstance = (_c = element.__ngContext__) === null || _c === void 0 ? void 0 : _c.componentInstance; return angularInstance ? Object.keys(angularInstance) : []; case 'svelte': const svelteStores = (_e = (_d = element._svelte) === null || _d === void 0 ? void 0 : _d.$$) === null || _e === void 0 ? void 0 : _e.stores; return svelteStores ? Object.keys(svelteStores) : []; default: return []; } } static getEventHandlers(element) { const eventHandlers = []; const eventTypes = [ 'click', 'change', 'input', 'submit', 'keydown', 'keyup', 'mouseover', 'mouseout', ]; eventTypes.forEach(eventType => { if (element[`on${eventType}`]) { eventHandlers.push(eventType); } }); return eventHandlers; } static getFrameworkSpecificProps(element, frameworkType) { switch (frameworkType) { case 'react': return { reactProps: this.extractReactProps(element) }; case 'vue': return { vueProps: this.extractVueProps(element) }; case 'angular': return { angularProps: this.extractAngularProps(element) }; case 'svelte': return { svelteProps: this.extractSvelteProps(element) }; default: return {}; } } // Framework-specific extraction methods static extractReactInfo(element) { console.log('🔍 [FrameworkDetector] Extracting React info from element:', element.tagName); const reactElement = element; const fiber = reactElement._reactInternalFiber; console.log('🔍 [FrameworkDetector] React fiber found:', !!fiber); const componentName = this.extractComponentNameFromElement(element) || element.tagName.toLowerCase(); console.log('🔍 [FrameworkDetector] Component name extracted:', componentName); const componentFile = this.getReactComponentFile(element); console.log('🔍 [FrameworkDetector] Component file extracted:', componentFile); const result = { componentName: componentName, componentFile: componentFile, props: this.extractReactProps(element), state: this.extractReactState(element), hierarchy: this.extractReactHierarchy(element), fiber: fiber ? { tag: fiber.tag, key: fiber.key, elementType: fiber.elementType, type: fiber.type, stateNode: fiber.stateNode, return: fiber.return, child: fiber.child, sibling: fiber.sibling, index: fiber.index, ref: fiber.ref, pendingProps: fiber.pendingProps, memoizedProps: fiber.memoizedProps, memoizedState: fiber.memoizedState, updateQueue: fiber.updateQueue, contextDependencies: fiber.contextDependencies, mode: fiber.mode, flags: fiber.flags, subtreeFlags: fiber.subtreeFlags, deletions: fiber.deletions, lanes: fiber.lanes, childLanes: fiber.childLanes, alternate: fiber.alternate, } : undefined, }; console.log('🔍 [FrameworkDetector] React info extraction result:', { componentName: result.componentName, componentFile: result.componentFile, hasFiber: !!result.fiber }); return result; } // Vue lifecycle extraction static extractVueInfo(element) { const vueElement = element; const instance = vueElement.__vue__; return { componentName: this.extractComponentNameFromElement(element) || element.tagName.toLowerCase(), componentFile: this.getVueComponentFile(element), props: this.extractVueProps(element), data: this.extractVueState(element), instance: instance ? { $el: instance.$el, $options: instance.$options, $props: instance.$props, $data: instance.$data, $refs: instance.$refs, $slots: instance.$slots, $scopedSlots: instance.$scopedSlots, $children: instance.$children, } : undefined, lifecycle: instance ? { mounted: instance.$mounted, destroyed: instance.$destroyed, } : undefined, }; } // Angular metadata extraction static extractAngularInfo(element) { const angularElement = element; const ngContext = angularElement.__ngContext__; return { componentName: this.extractComponentNameFromElement(element) || element.tagName.toLowerCase(), componentFile: this.getAngularComponentFile(element), context: ngContext ? { injector: ngContext.injector, changeDetectorRef: ngContext.changeDetectorRef, elementRef: ngContext.elementRef, viewContainerRef: ngContext.viewContainerRef, templateRef: ngContext.templateRef, renderer2: ngContext.renderer2, sanitizer: ngContext.sanitizer, constructor: ngContext.constructor, } : undefined, metadata: ngContext ? { selector: ngContext.selector, templateUrl: ngContext.templateUrl, template: ngContext.template, styleUrls: ngContext.styleUrls, styles: ngContext.styles, encapsulation: ngContext.encapsulation, changeDetection: ngContext.changeDetection, } : undefined, }; } static extractSvelteInfo(element) { var _a, _b; const svelteElement = element; const instance = svelteElement._svelte; return { componentName: this.extractComponentNameFromElement(element) || element.tagName.toLowerCase(), componentFile: this.getSvelteComponentFile(element), props: this.extractSvelteProps(element), state: this.extractSvelteState(element), instance: instance ? { $$: instance.$$, } : undefined, stores: ((_a = instance === null || instance === void 0 ? void 0 : instance.$$) === null || _a === void 0 ? void 0 : _a.stores) ? Object.keys(instance.$$.stores).map(key => { var _a; return ({ name: key, value: instance.$$.stores[key], subscribe: (_a = instance.$$.stores[key]) === null || _a === void 0 ? void 0 : _a.subscribe, }); }) : [], actions: ((_b = instance === null || instance === void 0 ? void 0 : instance.$$) === null || _b === void 0 ? void 0 : _b.actions) || [], }; } static extractVanillaInfo(element) { return { componentName: this.extractComponentNameFromElement(element) || element.tagName.toLowerCase(), componentFile: this.getVanillaComponentFile(element), state: this.extractVanillaState(element), customElement: element.tagName.includes('-') ? { tagName: element.tagName, observedAttributes: element.constructor.observedAttributes || [], lifecycleCallbacks: { connectedCallback: !!element.connectedCallback, disconnectedCallback: !!element.disconnectedCallback, adoptedCallback: !!element.adoptedCallback, attributeChangedCallback: !!element.attributeChangedCallback, }, } : undefined, dataAttributes: this.extractDataAttributes(element), customProperties: this.extractCustomProperties(element), eventHandlers: this.extractEventHandlers(element), }; } // Component file extraction methods static getReactComponentFile(element) { var _a, _b, _c, _d, _e; console.log('🔍 [FrameworkDetector] Getting React component file for element:', element.tagName); // Method 1: Try to get from the element itself (React 16-17) const reactElement = element; let fiber = reactElement._reactInternalFiber; console.log('🔍 [FrameworkDetector] Direct React fiber exists:', !!fiber); // Method 2: If no direct fiber, try to find it in parent React components if (!fiber) { console.log('🔍 [FrameworkDetector] No direct fiber, searching parent components...'); fiber = this.findReactFiberInParents(element); console.log('🔍 [FrameworkDetector] Found fiber in parents:', !!fiber); } // Method 3: Try to get from React DevTools source info (development only) if ((_b = (_a = fiber === null || fiber === void 0 ? void 0 : fiber.type) === null || _a === void 0 ? void 0 : _a.__source) === null || _b === void 0 ? void 0 : _b.fileName) { console.log('✅ [FrameworkDetector] Found fileName from fiber.type.__source:', fiber.type.__source.fileName); return fiber.type.__source.fileName; } console.log('🔍 [FrameworkDetector] No fileName from fiber.type.__source'); // Method 4: Try to get from elementType (alternative path) if ((_d = (_c = fiber === null || fiber === void 0 ? void 0 : fiber.elementType) === null || _c === void 0 ? void 0 : _c.__source) === null || _d === void 0 ? void 0 : _d.fileName) { console.log('✅ [FrameworkDetector] Found fileName from fiber.elementType.__source:', fiber.elementType.__source.fileName); return fiber.elementType.__source.fileName; } console.log('🔍 [FrameworkDetector] No fileName from fiber.elementType.__source'); // Method 5: Try to get from webpack module if ((_e = fiber === null || fiber === void 0 ? void 0 : fiber.elementType) === null || _e === void 0 ? void 0 : _e.__webpack_module__) { const webpackPath = `webpack://${fiber.elementType.__webpack_module__.id}`; console.log('✅ [FrameworkDetector] Found webpack module path:', webpackPath); return webpackPath; } console.log('🔍 [FrameworkDetector] No webpack module found'); // Method 6: Try to get component name from React DevTools if available if (typeof window !== 'undefined' && window.__REACT_DEVTOOLS_GLOBAL_HOOK__) { console.log('🔍 [FrameworkDetector] React DevTools available, trying to get component info...'); const devToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; if (devToolsHook.renderers && devToolsHook.renderers.size > 0) { const renderer = devToolsHook.renderers.get(1); // Get first renderer if (renderer && renderer.getFiberRoots) { console.log('✅ [FrameworkDetector] Found React renderer, attempting to get component info'); // This is complex, but we can try to get component info } } } // Method 7: Smart approach - return component name for IndexingAgent to find // This is the same approach used by the React web client const componentName = this.extractComponentNameFromElement(element); console.log('🔍 [FrameworkDetector] Extracted component name:', componentName); console.log('🔍 [FrameworkDetector] Element tag name:', element.tagName.toLowerCase()); if (componentName && componentName !== element.tagName.toLowerCase()) { // Return component name - IndexingAgent will search for the actual file console.log('✅ [FrameworkDetector] Returning component name for IndexingAgent search:', componentName); return componentName; } // Method 8: Try to get a meaningful component name from the element const meaningfulName = this.extractMeaningfulComponentName(element); if (meaningfulName) { console.log('✅ [FrameworkDetector] Returning meaningful component name:', meaningfulName); return meaningfulName; } // Only return real file paths, don't generate fake ones // If no source info is available, return undefined console.log('⚠️ [FrameworkDetector] No source info available, returning undefined'); return undefined; } /** * Find React fiber in parent components (for React 18+) */ static findReactFiberInParents(element) { let current = element; let depth = 0; const maxDepth = 10; // Check up to 10 levels up while (current && depth < maxDepth) { // Check if current element has React fiber const fiber = current._reactInternalFiber; if (fiber) { console.log(`✅ [FrameworkDetector] Found React fiber at depth ${depth} in element:`, current.tagName); return fiber; } // Check if current element has React 18+ properties const ownProps = Object.getOwnPropertyNames(current); const hasReactProps = ownProps.some(key => key.startsWith('__reactContainer$') || key.startsWith('_reactListening')); if (hasReactProps) { console.log(`🔍 [FrameworkDetector] Found React 18+ properties at depth ${depth} in element:`, current.tagName); // Try to find the React component instance const reactInstance = this.findReactInstanceFromElement(current); if (reactInstance) { console.log(`✅ [FrameworkDetector] Found React instance from element:`, current.tagName); return reactInstance; } } current = current.parentElement; depth++; } console.log('🔍 [FrameworkDetector] No React fiber found in parents up to depth:', maxDepth); return undefined; } /** * Find React instance from element with React 18+ properties */ static findReactInstanceFromElement(element) { // For React 18+, try to find the React component instance // This is a more complex approach that might work in some cases const ownProps = Object.getOwnPropertyNames(element); for (const prop of ownProps) { if (prop.startsWith('__reactContainer$')) { console.log(`🔍 [FrameworkDetector] Found React container property: ${prop}`); // Try to access the React instance const container = element[prop]; console.log(`🔍 [FrameworkDetector] Container object:`, container); if (container) { // Try multiple paths to find React fiber if (container._reactInternalFiber) { console.log('✅ [FrameworkDetector] Found React fiber in container._reactInternalFiber'); return container._reactInternalFiber; } if (container._reactInternalInstance) { console.log('✅ [FrameworkDetector] Found React instance in container._reactInternalInstance'); return container._reactInternalInstance; } // Check if container has fiber properties directly if (container.tag || container.type || container.elementType) { console.log('✅ [FrameworkDetector] Found React fiber properties directly in container'); return container; } // Try to find fiber in container's own properties const containerProps = Object.getOwnPropertyNames(container); console.log(`🔍 [FrameworkDetector] Container properties:`, containerProps); for (const containerProp of containerProps) { if (containerProp.includes('fiber') || containerProp.includes('react') || containerProp.includes('instance')) { console.log(`🔍 [FrameworkDetector] Checking container property: ${containerProp}`); const value = container[containerProp]; if (value && (value.tag || value.type || value.elementType)) { console.log(`✅ [FrameworkDetector] Found React fiber in container.${containerProp}`); return value; } } } } } } return undefined; } /** * Extract a meaningful component name from the element */ static extractMeaningfulComponentName(element) { // Try to get component name from data attributes if (element.dataset.component) { return element.dataset.component; } // Try to get from aria-label if (element.getAttribute('aria-label')) { return element.getAttribute('aria-label'); } // Try to get from title attribute if (element.getAttribute('title')) { return element.getAttribute('title'); } // Try to get from class names that look like component names if (element.className) { const classNames = element.className.split(' '); for (const className of classNames) { // Look for classes that might be component names (PascalCase, camelCase) if (className.length > 2 && (className[0] === className[0].toUpperCase() || className.includes('Component') || className.includes('Button') || className.includes('Input') || className.includes('Form'))) { return className; } } } // Try to get from parent elements let parent = element.parentElement; let depth = 0; const maxDepth = 3; while (parent && depth < maxDepth) { if (parent.dataset.component) { return parent.dataset.component; } if (parent.className) { const classNames = parent.className.split(' '); for (const className of classNames) { if (className.length > 2 && className[0] === className[0].toUpperCase() && !className.includes('css') && !className.includes('scss')) { return className; } } } parent = parent.parentElement; depth++; } console.log('⚠️ [FrameworkDetector] No clean component name found'); return undefined; } /** * Find component fiber from React root fiber */ static findComponentFiberFromRoot(rootFiber) { var _a, _b, _c, _d; console.log('🔍 [FrameworkDetector] Traversing React fiber tree from root...'); // Try multiple ways to access the current fiber let currentFiber = rootFiber.current || rootFiber.currentFiber || rootFiber._currentFiber; if (!currentFiber) { console.log('🔍 [FrameworkDetector] No current fiber in root, trying alternative access...'); // Try to find any fiber in the root object const rootProps = Object.getOwnPropertyNames(rootFiber); console.log('🔍 [FrameworkDetector] Root fiber properties:', rootProps); for (const prop of rootProps) { if (prop.includes('fiber') || prop.includes('current') || prop.includes('child')) { const value = rootFiber[prop]; if (value && typeof value === 'object' && (value.tag || value.type)) { console.log(`🔍 [FrameworkDetector] Found potential fiber in root.${prop}:`, value); currentFiber = value; break; } } } } if (!currentFiber) { console.log('🔍 [FrameworkDetector] Still no current fiber found'); return undefined; } // Traverse down to find component fibers let depth = 0; const maxDepth = 20; // Prevent infinite loops while (currentFiber && depth < maxDepth) { console.log(`🔍 [FrameworkDetector] Fiber at depth ${depth}:`, { tag: currentFiber.tag, type: currentFiber.type, elementType: currentFiber.elementType }); // Check if this fiber has source file information if ((_b = (_a = currentFiber.type) === null || _a === void 0 ? void 0 : _a.__source) === null || _b === void 0 ? void 0 : _b.fileName) { console.log('✅ [FrameworkDetector] Found component fiber with source file:', currentFiber.type.__source.fileName); return currentFiber; } if ((_d = (_c = currentFiber.elementType) === null || _c === void 0 ? void 0 : _c.__source) === null || _d === void 0 ? void 0 : _d.fileName) { console.log('✅ [FrameworkDetector] Found component fiber with source file in elementType:', currentFiber.elementType.__source.fileName); return currentFiber; } // Check if this is a component fiber (tag: 1 = FunctionComponent, 2 = ClassComponent) if (currentFiber.tag === 1 || currentFiber.tag === 2) { console.log('🔍 [FrameworkDetector] Found component fiber, checking for source...'); // This is a component, but might not have source info } // Move to child fiber if (currentFiber.child) { currentFiber = currentFiber.child; } else if (currentFiber.sibling) { currentFiber = currentFiber.sibling; } else { // Go back up and try siblings while (currentFiber && !currentFiber.sibling && currentFiber.return) { currentFiber = currentFiber.return; } if (currentFiber && currentFiber.sibling) { currentFiber = currentFiber.sibling; } else { break; // No more fibers to traverse } } depth++; } console.log('🔍 [FrameworkDetector] No component fiber with source file found in tree'); return undefined; } static getVueComponentFile(element) { var _a, _b; const vueElement = element; const instance = vueElement.__vue__; if ((_a = instance === null || instance === void 0 ? void 0 : instance.$options) === null || _a === void 0 ? void 0 : _a.__file) { return instance.$options.__file; } if ((_b = instance === null || instance === void 0 ? void 0 : instance.$options) === null || _b === void 0 ? void 0 : _b.name) { return `${instance.$options.name}.vue`; } return undefined; } static getAngularComponentFile(element) { var _a, _b; const angularElement = element; const ngContext = angularElement.__ngContext__; if ((_a = ngContext === null || ngContext === void 0 ? void 0 : ngContext.componentType) === null || _a === void 0 ? void 0 : _a.__file) { return ngContext.componentType.__file; } if ((_b = ngContext === null || ngContext === void 0 ? void 0 : ngContext.componentType) === null || _b === void 0 ? void 0 : _b.name) { return `${ngContext.componentType.name}.ts`; } return undefined; } static getSvelteComponentFile(element) { var _a, _b, _c; const svelteElement = element; const instance = svelteElement._svelte; if ((_c = (_b = (_a = instance === null || instance === void 0 ? void 0 : instance.$$) === null || _a === void 0 ? void 0 : _a.component) === null || _b === void 0 ? void 0 : _b.$$render) === null || _c === void 0 ? void 0 : _c.name) { return `${instance.$$.component.$$render.name}.svelte`; } return undefined; } static getVanillaComponentFile(element) { // For vanilla JS, try to get from data attributes or class names if (element.dataset.component) { return `${element.dataset.component}.js`; } if (element.className) { const classNames = element.className.split(' '); for (const className of classNames) { if (className.includes('component') || className.includes('widget')) { return `${cl