* Probe a single fiber's component function by invoking it with a * throwing hooks dispatcher and parsing the resulting error stack.
(fiber: ReactFiber)
| 571 | * throwing hooks dispatcher and parsing the resulting error stack. |
| 572 | */ |
| 573 | function probeComponentSource(fiber: ReactFiber): SourceLocation | null { |
| 574 | const fn = unwrapComponentType(fiber); |
| 575 | if (!fn) return null; |
| 576 | |
| 577 | // Check cache |
| 578 | if (sourceProbeCache.has(fn)) { |
| 579 | return sourceProbeCache.get(fn)!; |
| 580 | } |
| 581 | |
| 582 | const dispatcher = getReactDispatcher(); |
| 583 | if (!dispatcher) { |
| 584 | sourceProbeCache.set(fn, null); |
| 585 | return null; |
| 586 | } |
| 587 | |
| 588 | const original = dispatcher.get(); |
| 589 | let result: SourceLocation | null = null; |
| 590 | |
| 591 | try { |
| 592 | // Install a proxy dispatcher that throws an Error (with stack) on any hook access. |
| 593 | // When the component calls useState/useEffect/etc., the proxy's get trap fires, |
| 594 | // creating an Error whose stack trace includes the component's source location. |
| 595 | const stackCapturingDispatcher = new Proxy( |
| 596 | {}, |
| 597 | { |
| 598 | get() { |
| 599 | throw new Error("probe"); |
| 600 | }, |
| 601 | } |
| 602 | ); |
| 603 | dispatcher.set(stackCapturingDispatcher); |
| 604 | |
| 605 | try { |
| 606 | // Invoke the component — it will either: |
| 607 | // 1. Call a hook → throws Error with stack (ideal case) |
| 608 | // 2. Have no hooks → runs to completion (harmless, discarded), no stack to parse |
| 609 | fn({}); |
| 610 | } catch (e) { |
| 611 | if (e instanceof Error && e.message === "probe" && e.stack) { |
| 612 | const frame = parseComponentFrame(e.stack); |
| 613 | if (frame) { |
| 614 | const cleaned = cleanSourcePath(frame.fileName); |
| 615 | result = { |
| 616 | fileName: cleaned, |
| 617 | lineNumber: frame.line, |
| 618 | columnNumber: frame.column, |
| 619 | componentName: getComponentName(fiber) || undefined, |
| 620 | }; |
| 621 | } |
| 622 | } |
| 623 | } |
| 624 | } finally { |
| 625 | dispatcher.set(original); |
| 626 | } |
| 627 | |
| 628 | sourceProbeCache.set(fn, result); |
| 629 | return result; |
| 630 | } |
no test coverage detected
searching dependent graphs…