@domscribe/react 0.1.0

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.
Files changed (59) hide show
  1. package/adapter/react-adapter.d.ts +121 -0
  2. package/adapter/react-adapter.d.ts.map +1 -0
  3. package/adapter/react-adapter.js +486 -0
  4. package/adapter/types.d.ts +131 -0
  5. package/adapter/types.d.ts.map +1 -0
  6. package/adapter/types.js +17 -0
  7. package/auto-init.d.ts +2 -0
  8. package/auto-init.d.ts.map +1 -0
  9. package/auto-init.js +40 -0
  10. package/component/component-name-resolver.d.ts +118 -0
  11. package/component/component-name-resolver.d.ts.map +1 -0
  12. package/component/component-name-resolver.js +361 -0
  13. package/component/props-extractor.d.ts +51 -0
  14. package/component/props-extractor.d.ts.map +1 -0
  15. package/component/props-extractor.js +122 -0
  16. package/component/state-extractor.d.ts +60 -0
  17. package/component/state-extractor.d.ts.map +1 -0
  18. package/component/state-extractor.js +162 -0
  19. package/component/types.d.ts +256 -0
  20. package/component/types.d.ts.map +1 -0
  21. package/component/types.js +5 -0
  22. package/errors/index.d.ts +36 -0
  23. package/errors/index.d.ts.map +1 -0
  24. package/errors/index.js +75 -0
  25. package/fiber/fiber-walker.d.ts +58 -0
  26. package/fiber/fiber-walker.d.ts.map +1 -0
  27. package/fiber/fiber-walker.js +118 -0
  28. package/fiber/types.d.ts +162 -0
  29. package/fiber/types.d.ts.map +1 -0
  30. package/fiber/types.js +32 -0
  31. package/index.d.ts +14 -0
  32. package/index.d.ts.map +1 -0
  33. package/index.js +15 -0
  34. package/package.json +59 -0
  35. package/tsconfig.tsbuildinfo +1 -0
  36. package/utils/constants.d.ts +94 -0
  37. package/utils/constants.d.ts.map +1 -0
  38. package/utils/constants.js +123 -0
  39. package/utils/type-guards.d.ts +31 -0
  40. package/utils/type-guards.d.ts.map +1 -0
  41. package/utils/type-guards.js +89 -0
  42. package/utils/types.d.ts +6 -0
  43. package/utils/types.d.ts.map +1 -0
  44. package/utils/types.js +5 -0
  45. package/vite/index.d.ts +7 -0
  46. package/vite/index.d.ts.map +1 -0
  47. package/vite/index.js +5 -0
  48. package/vite/types.d.ts +56 -0
  49. package/vite/types.d.ts.map +1 -0
  50. package/vite/types.js +10 -0
  51. package/vite/vite-plugin.d.ts +29 -0
  52. package/vite/vite-plugin.d.ts.map +1 -0
  53. package/vite/vite-plugin.js +104 -0
  54. package/webpack/index.d.ts +7 -0
  55. package/webpack/index.d.ts.map +1 -0
  56. package/webpack/index.js +5 -0
  57. package/webpack/webpack-plugin.d.ts +50 -0
  58. package/webpack/webpack-plugin.d.ts.map +1 -0
  59. package/webpack/webpack-plugin.js +63 -0
@@ -0,0 +1,121 @@
1
+ /**
2
+ * ReactAdapter - React framework adapter for Domscribe
3
+ *
4
+ * Implements the FrameworkAdapter interface to provide runtime context capture
5
+ * for React applications. Supports multiple capture strategies:
6
+ * - DevTools: Use React DevTools hook (most reliable, requires DevTools)
7
+ * - Fiber: Direct Fiber tree access (fast, but uses React internal API)
8
+ * - Best-effort: Try multiple strategies in order of reliability
9
+ *
10
+ * @module @domscribe/react/adapter/react-adapter
11
+ */
12
+ import type { ComponentTreeNode } from '@domscribe/runtime';
13
+ import type { ReactAdapterOptions, ReactFrameworkAdapter } from './types.js';
14
+ import { CaptureStrategy } from './types.js';
15
+ import type { Nullable } from '../utils/types.js';
16
+ /**
17
+ * ReactAdapter class implementing FrameworkAdapter interface
18
+ */
19
+ export declare class ReactAdapter implements ReactFrameworkAdapter {
20
+ readonly name = "react";
21
+ readonly version?: string;
22
+ private _version?;
23
+ private state;
24
+ private options;
25
+ private fiberWalker;
26
+ private nameResolver;
27
+ private propsExtractor;
28
+ private stateExtractor;
29
+ constructor(options?: ReactAdapterOptions);
30
+ /**
31
+ * Detect React version from global React object or DevTools
32
+ */
33
+ private detectReactVersion;
34
+ /**
35
+ * Check if React DevTools hook is available
36
+ */
37
+ private checkDevToolsAvailability;
38
+ /**
39
+ * Get the React DevTools hook object
40
+ */
41
+ private getDevToolsHook;
42
+ /**
43
+ * Check if we can access Fiber internals
44
+ */
45
+ private checkFiberAccess;
46
+ /**
47
+ * Get component instance from a DOM element
48
+ *
49
+ * @param element - The DOM element to query
50
+ * @returns Component instance (Fiber node) or null if not found
51
+ */
52
+ getComponentInstance(element: HTMLElement): Nullable<unknown>;
53
+ /**
54
+ * Capture component props
55
+ *
56
+ * @param component - The component instance (Fiber node)
57
+ * @returns Serialized props object or null
58
+ */
59
+ captureProps(component: unknown): Nullable<Record<string, unknown>>;
60
+ /**
61
+ * Capture component state
62
+ *
63
+ * @param component - The component instance (Fiber node)
64
+ * @returns Serialized state object or null
65
+ */
66
+ captureState(component: unknown): Nullable<Record<string, unknown>>;
67
+ /**
68
+ * Get component name
69
+ *
70
+ * @param component - The component instance (Fiber node)
71
+ * @returns Component name or null
72
+ */
73
+ getComponentName(component: unknown): Nullable<string>;
74
+ /**
75
+ * Get component tree
76
+ *
77
+ * @param component - The component instance (Fiber node)
78
+ * @returns Component tree node or null
79
+ */
80
+ getComponentTree(component: unknown): Nullable<ComponentTreeNode>;
81
+ /**
82
+ * Get the active capture strategy
83
+ */
84
+ getActiveStrategy(): CaptureStrategy;
85
+ /**
86
+ * Get the React version
87
+ */
88
+ getReactVersion(): string | null;
89
+ /**
90
+ * Check if React DevTools is available
91
+ */
92
+ hasDevToolsAccess(): boolean;
93
+ /**
94
+ * Resolve component from DOM element using active strategy
95
+ */
96
+ private resolveComponent;
97
+ /**
98
+ * Resolve component via React DevTools hook
99
+ */
100
+ private resolveViaDevTools;
101
+ /**
102
+ * Resolve component via direct Fiber access
103
+ */
104
+ private resolveViaFiber;
105
+ /**
106
+ * Get Fiber node from DOM element using internal React keys
107
+ */
108
+ private getFiberFromElement;
109
+ /**
110
+ * Build component tree from a Fiber node
111
+ */
112
+ private buildComponentTree;
113
+ }
114
+ /**
115
+ * Create a ReactAdapter instance
116
+ *
117
+ * @param options - Adapter options
118
+ * @returns ReactAdapter instance
119
+ */
120
+ export declare function createReactAdapter(options?: ReactAdapterOptions): ReactAdapter;
121
+ //# sourceMappingURL=react-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-adapter.d.ts","sourceRoot":"","sources":["../../../../packages/domscribe-react/src/adapter/react-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,KAAK,EACV,mBAAmB,EAGnB,qBAAqB,EAEtB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAM7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AASlD;;GAEG;AACH,qBAAa,YAAa,YAAW,qBAAqB;IACxD,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAE1B,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,OAAO,CAAgC;IAG/C,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,cAAc,CAAiB;gBAE3B,OAAO,CAAC,EAAE,mBAAmB;IAuDzC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAkC1B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IASjC;;OAEG;IACH,OAAO,CAAC,eAAe;IAgBvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA4BxB;;;;;OAKG;IACH,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC;IAmB7D;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAmBnE;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAmBnE;;;;;OAKG;IACH,gBAAgB,CAAC,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC;IAkBtD;;;;;OAKG;IACH,gBAAgB,CAAC,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC,iBAAiB,CAAC;IAmBjE;;OAEG;IACH,iBAAiB,IAAI,eAAe;IAIpC;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,iBAAiB,IAAI,OAAO;IAQ5B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAgBxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA6C1B;;OAEG;IACH,OAAO,CAAC,eAAe;IAoCvB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAyB3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAuE3B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,YAAY,CAEd"}
@@ -0,0 +1,486 @@
1
+ /**
2
+ * ReactAdapter - React framework adapter for Domscribe
3
+ *
4
+ * Implements the FrameworkAdapter interface to provide runtime context capture
5
+ * for React applications. Supports multiple capture strategies:
6
+ * - DevTools: Use React DevTools hook (most reliable, requires DevTools)
7
+ * - Fiber: Direct Fiber tree access (fast, but uses React internal API)
8
+ * - Best-effort: Try multiple strategies in order of reliability
9
+ *
10
+ * @module @domscribe/react/adapter/react-adapter
11
+ */
12
+ import { CaptureStrategy } from './types.js';
13
+ import { FiberWalker } from '../fiber/fiber-walker.js';
14
+ import { ComponentNameResolver } from '../component/component-name-resolver.js';
15
+ import { PropsExtractor } from '../component/props-extractor.js';
16
+ import { StateExtractor } from '../component/state-extractor.js';
17
+ import { DEVTOOLS_HOOK_KEY, REACT_ELEMENT_KEYS } from '../utils/constants.js';
18
+ import { isReactFiber, hasReactFiberKey, isComponentFiber, isReactDevToolsHook, } from '../utils/type-guards.js';
19
+ import { FiberAccessError, ComponentResolutionError } from '../errors/index.js';
20
+ /**
21
+ * ReactAdapter class implementing FrameworkAdapter interface
22
+ */
23
+ export class ReactAdapter {
24
+ name = 'react';
25
+ version;
26
+ _version;
27
+ state;
28
+ options;
29
+ // Utilities
30
+ fiberWalker;
31
+ nameResolver;
32
+ propsExtractor;
33
+ stateExtractor;
34
+ constructor(options) {
35
+ // Initialize utilities
36
+ this.fiberWalker = new FiberWalker();
37
+ this.nameResolver = new ComponentNameResolver();
38
+ this.propsExtractor = new PropsExtractor();
39
+ this.stateExtractor = new StateExtractor();
40
+ // Normalize options with defaults
41
+ this.options = {
42
+ strategy: options?.strategy ?? CaptureStrategy.BEST_EFFORT,
43
+ maxTreeDepth: options?.maxTreeDepth ?? 50,
44
+ debug: options?.debug ?? false,
45
+ includeWrappers: options?.includeWrappers ?? true,
46
+ hookNameResolvers: options?.hookNameResolvers ?? new Map(),
47
+ };
48
+ // Initialize state
49
+ this.state = {
50
+ initialized: false,
51
+ hasDevTools: false,
52
+ hasFiberAccess: false,
53
+ activeStrategy: this.options.strategy,
54
+ };
55
+ try {
56
+ // Detect React version
57
+ this._version = this.detectReactVersion();
58
+ this.state.version = this._version;
59
+ // Set readonly version property
60
+ Object.defineProperty(this, 'version', {
61
+ value: this._version,
62
+ writable: false,
63
+ configurable: false,
64
+ });
65
+ // Check for DevTools hook
66
+ this.state.hasDevTools = this.checkDevToolsAvailability();
67
+ // Check for Fiber access
68
+ this.state.hasFiberAccess = this.checkFiberAccess();
69
+ this.state.initialized = true;
70
+ if (this.options.debug) {
71
+ console.log('[ReactAdapter] Initialized:', this.state);
72
+ }
73
+ }
74
+ catch (error) {
75
+ if (this.options.debug) {
76
+ console.error('[ReactAdapter] Initialization failed:', error);
77
+ }
78
+ this.state.initialized = false;
79
+ }
80
+ }
81
+ /**
82
+ * Detect React version from global React object or DevTools
83
+ */
84
+ detectReactVersion() {
85
+ // Try React.version
86
+ if (typeof window !== 'undefined' && 'React' in window) {
87
+ const React = window
88
+ .React;
89
+ if (React?.version) {
90
+ return React.version;
91
+ }
92
+ }
93
+ // Try DevTools hook
94
+ if (this.state.hasDevTools) {
95
+ const hook = this.getDevToolsHook();
96
+ if (typeof hook === 'object' &&
97
+ hook !== null &&
98
+ 'rendererInterfaces' in hook) {
99
+ const interfaces = hook.rendererInterfaces;
100
+ const firstRenderer = interfaces.values().next().value;
101
+ if (firstRenderer &&
102
+ typeof firstRenderer === 'object' &&
103
+ firstRenderer !== null &&
104
+ 'version' in firstRenderer) {
105
+ return String(firstRenderer.version);
106
+ }
107
+ }
108
+ }
109
+ return undefined;
110
+ }
111
+ /**
112
+ * Check if React DevTools hook is available
113
+ */
114
+ checkDevToolsAvailability() {
115
+ if (typeof window === 'undefined') {
116
+ return false;
117
+ }
118
+ const hook = this.getDevToolsHook();
119
+ return hook !== null && typeof hook === 'object';
120
+ }
121
+ /**
122
+ * Get the React DevTools hook object
123
+ */
124
+ getDevToolsHook() {
125
+ if (typeof window === 'undefined') {
126
+ return null;
127
+ }
128
+ const hook = window[DEVTOOLS_HOOK_KEY];
129
+ if (isReactDevToolsHook(hook)) {
130
+ return hook;
131
+ }
132
+ return null;
133
+ }
134
+ /**
135
+ * Check if we can access Fiber internals
136
+ */
137
+ checkFiberAccess() {
138
+ // Try to find a React root in the document
139
+ if (typeof document === 'undefined') {
140
+ return false;
141
+ }
142
+ // Look for React root nodes
143
+ const reactRoots = document.querySelectorAll('[data-reactroot]');
144
+ if (reactRoots.length > 0) {
145
+ const rootElement = reactRoots[0];
146
+ return hasReactFiberKey(rootElement);
147
+ }
148
+ // Try finding any element with React Fiber keys
149
+ const allElements = document.querySelectorAll('*');
150
+ for (let i = 0; i < Math.min(allElements.length, 100); i++) {
151
+ if (hasReactFiberKey(allElements[i])) {
152
+ return true;
153
+ }
154
+ }
155
+ return false;
156
+ }
157
+ // ============================================================================
158
+ // FrameworkAdapter Interface Implementation
159
+ // ============================================================================
160
+ /**
161
+ * Get component instance from a DOM element
162
+ *
163
+ * @param element - The DOM element to query
164
+ * @returns Component instance (Fiber node) or null if not found
165
+ */
166
+ getComponentInstance(element) {
167
+ if (!this.state.initialized) {
168
+ return null;
169
+ }
170
+ try {
171
+ const result = this.resolveComponent(element);
172
+ if (result.success && result.component) {
173
+ return result.component;
174
+ }
175
+ return null;
176
+ }
177
+ catch (error) {
178
+ if (this.options.debug) {
179
+ console.error('[ReactAdapter] getComponentInstance failed:', error);
180
+ }
181
+ return null;
182
+ }
183
+ }
184
+ /**
185
+ * Capture component props
186
+ *
187
+ * @param component - The component instance (Fiber node)
188
+ * @returns Serialized props object or null
189
+ */
190
+ captureProps(component) {
191
+ if (!this.state.initialized || !isReactFiber(component)) {
192
+ return null;
193
+ }
194
+ try {
195
+ const result = this.propsExtractor.extract(component);
196
+ if (result.success && result.props) {
197
+ return result.props;
198
+ }
199
+ return null;
200
+ }
201
+ catch (error) {
202
+ if (this.options.debug) {
203
+ console.error('[ReactAdapter] captureProps failed:', error);
204
+ }
205
+ return null;
206
+ }
207
+ }
208
+ /**
209
+ * Capture component state
210
+ *
211
+ * @param component - The component instance (Fiber node)
212
+ * @returns Serialized state object or null
213
+ */
214
+ captureState(component) {
215
+ if (!this.state.initialized || !isReactFiber(component)) {
216
+ return null;
217
+ }
218
+ try {
219
+ const result = this.stateExtractor.extract(component);
220
+ if (result.success && result.state) {
221
+ return result.state;
222
+ }
223
+ return null;
224
+ }
225
+ catch (error) {
226
+ if (this.options.debug) {
227
+ console.error('[ReactAdapter] captureState failed:', error);
228
+ }
229
+ return null;
230
+ }
231
+ }
232
+ /**
233
+ * Get component name
234
+ *
235
+ * @param component - The component instance (Fiber node)
236
+ * @returns Component name or null
237
+ */
238
+ getComponentName(component) {
239
+ if (!this.state.initialized || !isReactFiber(component)) {
240
+ return null;
241
+ }
242
+ try {
243
+ const result = this.nameResolver.resolve(component, {
244
+ includeWrappers: this.options.includeWrappers,
245
+ });
246
+ return result.name || null;
247
+ }
248
+ catch (error) {
249
+ if (this.options.debug) {
250
+ console.error('[ReactAdapter] getComponentName failed:', error);
251
+ }
252
+ return null;
253
+ }
254
+ }
255
+ /**
256
+ * Get component tree
257
+ *
258
+ * @param component - The component instance (Fiber node)
259
+ * @returns Component tree node or null
260
+ */
261
+ getComponentTree(component) {
262
+ if (!this.state.initialized || !isReactFiber(component)) {
263
+ return null;
264
+ }
265
+ try {
266
+ return this.buildComponentTree(component);
267
+ }
268
+ catch (error) {
269
+ if (this.options.debug) {
270
+ console.error('[ReactAdapter] getComponentTree failed:', error);
271
+ }
272
+ return null;
273
+ }
274
+ }
275
+ // ============================================================================
276
+ // React-Specific Methods
277
+ // ============================================================================
278
+ /**
279
+ * Get the active capture strategy
280
+ */
281
+ getActiveStrategy() {
282
+ return this.state.activeStrategy;
283
+ }
284
+ /**
285
+ * Get the React version
286
+ */
287
+ getReactVersion() {
288
+ return this._version ?? null;
289
+ }
290
+ /**
291
+ * Check if React DevTools is available
292
+ */
293
+ hasDevToolsAccess() {
294
+ return this.state.hasDevTools;
295
+ }
296
+ // ============================================================================
297
+ // Private Helper Methods
298
+ // ============================================================================
299
+ /**
300
+ * Resolve component from DOM element using active strategy
301
+ */
302
+ resolveComponent(element) {
303
+ // Try strategies in order based on active strategy
304
+ if (this.state.activeStrategy === CaptureStrategy.DEVTOOLS) {
305
+ return this.resolveViaDevTools(element);
306
+ }
307
+ else if (this.state.activeStrategy === CaptureStrategy.FIBER) {
308
+ return this.resolveViaFiber(element);
309
+ }
310
+ else {
311
+ // Best-effort: try both
312
+ const devToolsResult = this.resolveViaDevTools(element);
313
+ if (devToolsResult.success) {
314
+ return devToolsResult;
315
+ }
316
+ return this.resolveViaFiber(element);
317
+ }
318
+ }
319
+ /**
320
+ * Resolve component via React DevTools hook
321
+ */
322
+ resolveViaDevTools(element) {
323
+ try {
324
+ const hook = this.getDevToolsHook();
325
+ if (!hook) {
326
+ return {
327
+ success: false,
328
+ error: new ComponentResolutionError('DevTools hook not available'),
329
+ };
330
+ }
331
+ for (const renderer of hook.renderers.values()) {
332
+ if (renderer?.findFiberByHostInstance) {
333
+ const fiber = renderer.findFiberByHostInstance(element);
334
+ if (isReactFiber(fiber)) {
335
+ // Find nearest component Fiber (not host Fiber)
336
+ const componentFiber = this.fiberWalker.findNearestComponentFiber(fiber);
337
+ if (componentFiber) {
338
+ return {
339
+ success: true,
340
+ component: componentFiber,
341
+ strategy: CaptureStrategy.DEVTOOLS,
342
+ };
343
+ }
344
+ }
345
+ }
346
+ }
347
+ return {
348
+ success: false,
349
+ error: new ComponentResolutionError('Could not resolve Fiber via DevTools'),
350
+ };
351
+ }
352
+ catch (error) {
353
+ return {
354
+ success: false,
355
+ error: error instanceof Error
356
+ ? error
357
+ : new ComponentResolutionError('DevTools resolution failed'),
358
+ };
359
+ }
360
+ }
361
+ /**
362
+ * Resolve component via direct Fiber access
363
+ */
364
+ resolveViaFiber(element) {
365
+ try {
366
+ // Get Fiber node from element
367
+ const fiber = this.getFiberFromElement(element);
368
+ if (!fiber) {
369
+ return {
370
+ success: false,
371
+ error: new FiberAccessError('Could not find Fiber on element'),
372
+ };
373
+ }
374
+ // Find nearest component Fiber
375
+ const componentFiber = this.fiberWalker.findNearestComponentFiber(fiber);
376
+ if (!componentFiber) {
377
+ return {
378
+ success: false,
379
+ error: new FiberAccessError('Could not find component Fiber'),
380
+ };
381
+ }
382
+ return {
383
+ success: true,
384
+ component: componentFiber,
385
+ strategy: CaptureStrategy.FIBER,
386
+ };
387
+ }
388
+ catch (error) {
389
+ return {
390
+ success: false,
391
+ error: error instanceof Error
392
+ ? error
393
+ : new FiberAccessError('Fiber resolution failed'),
394
+ };
395
+ }
396
+ }
397
+ /**
398
+ * Get Fiber node from DOM element using internal React keys
399
+ */
400
+ getFiberFromElement(element) {
401
+ // React attaches Fiber to DOM elements using internal keys
402
+ // These keys vary by React version:
403
+ // - React 16-17: __reactInternalInstance$...
404
+ // - React 18+: __reactFiber$...
405
+ const keys = Object.keys(element);
406
+ const fiberKey = keys.find((key) => key.startsWith(REACT_ELEMENT_KEYS.FIBER_16) ||
407
+ key.startsWith(REACT_ELEMENT_KEYS.FIBER_17_18));
408
+ if (!fiberKey) {
409
+ return null;
410
+ }
411
+ const fiber = element[fiberKey];
412
+ if (isReactFiber(fiber)) {
413
+ return fiber;
414
+ }
415
+ return null;
416
+ }
417
+ /**
418
+ * Build component tree from a Fiber node
419
+ */
420
+ buildComponentTree(fiber, depth = 0) {
421
+ if (depth >= this.options.maxTreeDepth) {
422
+ return null;
423
+ }
424
+ try {
425
+ const name = this.getComponentName(fiber);
426
+ if (!name) {
427
+ return null;
428
+ }
429
+ const node = {
430
+ name,
431
+ instance: fiber,
432
+ };
433
+ // Add props
434
+ const props = this.captureProps(fiber);
435
+ if (props) {
436
+ node.props = props;
437
+ }
438
+ // Add state
439
+ const state = this.captureState(fiber);
440
+ if (state) {
441
+ node.state = state;
442
+ }
443
+ // Add parent if within depth limit
444
+ if (fiber.return) {
445
+ const parentFiber = this.fiberWalker.findNearestComponentFiber(fiber.return);
446
+ if (parentFiber) {
447
+ const parentNode = this.buildComponentTree(parentFiber, depth + 1);
448
+ if (parentNode) {
449
+ node.parent = parentNode;
450
+ }
451
+ }
452
+ }
453
+ // Add children if within depth limit
454
+ if (depth + 1 < this.options.maxTreeDepth) {
455
+ const allChildren = this.fiberWalker.getChildren(fiber);
456
+ // Filter to only component fibers
457
+ const componentChildren = allChildren.filter((child) => isComponentFiber(child));
458
+ if (componentChildren.length > 0) {
459
+ node.children = [];
460
+ for (const child of componentChildren) {
461
+ const childNode = this.buildComponentTree(child, depth + 1);
462
+ if (childNode) {
463
+ node.children.push(childNode);
464
+ }
465
+ }
466
+ }
467
+ }
468
+ return node;
469
+ }
470
+ catch (error) {
471
+ if (this.options.debug) {
472
+ console.error('[ReactAdapter] buildComponentTree failed:', error);
473
+ }
474
+ return null;
475
+ }
476
+ }
477
+ }
478
+ /**
479
+ * Create a ReactAdapter instance
480
+ *
481
+ * @param options - Adapter options
482
+ * @returns ReactAdapter instance
483
+ */
484
+ export function createReactAdapter(options) {
485
+ return new ReactAdapter(options);
486
+ }