bippy 0.7.3-dev.ebf9a42 → 0.7.3-dev.fbafc40
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.
- package/LICENSE +0 -1
- package/README.md +2 -2
- package/dist/core.cjs +1 -1
- package/dist/core.js +1 -1
- package/dist/errors.d.cts +2 -2
- package/dist/errors.d.ts +2 -2
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/rdt-hook.cjs +1 -1
- package/dist/rdt-hook.js +1 -1
- package/dist/source.cjs +9 -9
- package/dist/source.d.cts +4 -2
- package/dist/source.d.ts +4 -2
- package/dist/source.js +12 -12
- package/package.json +68 -4
- package/src/core.ts +106 -57
- package/src/index.ts +3 -3
- package/src/install-hook-only.ts +1 -1
- package/src/rdt-hook.ts +43 -30
- package/src/react-internals/current-fiber.ts +2 -2
- package/src/react-internals/generated/react-work-tags.ts +1 -1
- package/src/react-internals/index.ts +8 -8
- package/src/react-internals/types.ts +1 -1
- package/src/react.ts +6 -6
- package/src/source/constants.ts +10 -6
- package/src/source/get-display-name-from-source.ts +5 -5
- package/src/source/get-source.ts +8 -143
- package/src/source/index.ts +9 -9
- package/src/source/inspect-hooks.ts +7 -11
- package/src/source/normalize-file-name.ts +416 -0
- package/src/source/owner-stack.ts +9 -21
- package/src/source/parse-debug-stack.ts +3 -3
- package/src/source/parse-hook-names.ts +2 -2
- package/src/source/renderer-dispatchers.ts +3 -3
- package/src/source/symbolication.ts +67 -38
package/src/core.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// React must remain a type-only import because this module loads immediately after the DevTools hook.
|
|
2
2
|
import type * as React from "react";
|
|
3
|
-
import { callListener } from "./call-listener
|
|
3
|
+
import { callListener } from "./call-listener";
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
6
|
Fiber,
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
HostFiber,
|
|
9
9
|
ReactDevToolsGlobalHook,
|
|
10
10
|
ReactRenderer,
|
|
11
|
-
} from "./react-internals/index
|
|
11
|
+
} from "./react-internals/index";
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
14
|
BIPPY_INSTRUMENTATION_STRING,
|
|
@@ -20,16 +20,16 @@ import {
|
|
|
20
20
|
isRealReactDevtools,
|
|
21
21
|
onRDTHookReplace,
|
|
22
22
|
removeActiveListener,
|
|
23
|
-
} from "./rdt-hook
|
|
24
|
-
import type { ReactDevToolsTarget, Unsubscribe } from "./rdt-hook
|
|
25
|
-
import { getCurrentFiberFromRoot } from "./react-internals/current-fiber
|
|
23
|
+
} from "./rdt-hook";
|
|
24
|
+
import type { ReactDevToolsTarget, Unsubscribe } from "./rdt-hook";
|
|
25
|
+
import { getCurrentFiberFromRoot } from "./react-internals/current-fiber";
|
|
26
26
|
import {
|
|
27
27
|
getReactWorkTagsForFiber,
|
|
28
28
|
ReactBuildType,
|
|
29
29
|
ReactFiberFlags,
|
|
30
30
|
ReactSymbols,
|
|
31
31
|
setReactWorkTagsForFiber,
|
|
32
|
-
} from "./react-internals/index
|
|
32
|
+
} from "./react-internals/index";
|
|
33
33
|
|
|
34
34
|
export {
|
|
35
35
|
BippyError,
|
|
@@ -37,7 +37,7 @@ export {
|
|
|
37
37
|
BippyHookRenderError,
|
|
38
38
|
BippySourceMapError,
|
|
39
39
|
BippyUnsupportedHookError,
|
|
40
|
-
} from "./errors
|
|
40
|
+
} from "./errors";
|
|
41
41
|
|
|
42
42
|
const isComponentType = (value: unknown): value is React.ComponentType<unknown> =>
|
|
43
43
|
typeof value === "function";
|
|
@@ -248,8 +248,15 @@ export const traverseFiber = ((
|
|
|
248
248
|
while (currentFiber) {
|
|
249
249
|
const selectedFiber = currentFiber;
|
|
250
250
|
const selection = selector(selectedFiber);
|
|
251
|
-
|
|
252
|
-
|
|
251
|
+
const then =
|
|
252
|
+
selection !== null && (typeof selection === "object" || typeof selection === "function")
|
|
253
|
+
? selection.then
|
|
254
|
+
: null;
|
|
255
|
+
if (typeof then === "function") {
|
|
256
|
+
return Promise.resolve<boolean | void>({
|
|
257
|
+
// oxlint-disable-next-line unicorn/no-thenable -- Assimilate the captured method without reading the accessor twice.
|
|
258
|
+
then: (resolve, reject) => Reflect.apply(then, selection, [resolve, reject]),
|
|
259
|
+
}).then((didSelectFiber) =>
|
|
253
260
|
didSelectFiber === true ? selectedFiber : visit(getNextFiber(selectedFiber)),
|
|
254
261
|
);
|
|
255
262
|
}
|
|
@@ -261,12 +268,6 @@ export const traverseFiber = ((
|
|
|
261
268
|
return visit(fiber);
|
|
262
269
|
}) as TraverseFiber;
|
|
263
270
|
|
|
264
|
-
const isPromiseLike = <Result>(value: unknown): value is PromiseLike<Result> =>
|
|
265
|
-
(typeof value === "object" || typeof value === "function") &&
|
|
266
|
-
value !== null &&
|
|
267
|
-
"then" in value &&
|
|
268
|
-
typeof value.then === "function";
|
|
269
|
-
|
|
270
271
|
/**
|
|
271
272
|
* Returns `true` if the {@link Fiber} uses React Compiler's memo cache.
|
|
272
273
|
*/
|
|
@@ -330,6 +331,7 @@ export const isInstrumentationActive = (target: ReactDevToolsTarget = globalThis
|
|
|
330
331
|
export const _fiberRoots = new Set<FiberRoot>();
|
|
331
332
|
const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
332
333
|
const rootHooks = new WeakMap<FiberRoot, ReactDevToolsGlobalHook>();
|
|
334
|
+
let currentUnmountingFiber: Fiber | null = null;
|
|
333
335
|
|
|
334
336
|
/**
|
|
335
337
|
* Returns the latest fiber (since it may be double-buffered).
|
|
@@ -338,7 +340,9 @@ export const getLatestFiber = (fiber: Fiber): Fiber => {
|
|
|
338
340
|
const alternate = fiber.alternate;
|
|
339
341
|
if (!alternate) return fiber;
|
|
340
342
|
const currentFiber = getCurrentFiberFromRoot(fiber);
|
|
341
|
-
|
|
343
|
+
const isUnmountingPair = fiber === currentUnmountingFiber || alternate === currentUnmountingFiber;
|
|
344
|
+
if (currentFiber && (!isUnmountingPair || currentFiber === currentUnmountingFiber))
|
|
345
|
+
return currentFiber;
|
|
342
346
|
|
|
343
347
|
let rootFiber = fiber;
|
|
344
348
|
while (rootFiber.return) {
|
|
@@ -350,6 +354,7 @@ export const getLatestFiber = (fiber: Fiber): Fiber => {
|
|
|
350
354
|
});
|
|
351
355
|
if (latestFiber) return latestFiber;
|
|
352
356
|
}
|
|
357
|
+
if (currentFiber) return currentFiber;
|
|
353
358
|
|
|
354
359
|
if (alternate.actualStartTime && fiber.actualStartTime) {
|
|
355
360
|
return alternate.actualStartTime > fiber.actualStartTime ? alternate : fiber;
|
|
@@ -413,14 +418,24 @@ const fiberIdFinalizationRegistry =
|
|
|
413
418
|
const createFiberReference = (fiber: Fiber): FiberReference =>
|
|
414
419
|
typeof WeakRef === "function" ? new WeakRef(fiber) : { deref: () => fiber };
|
|
415
420
|
|
|
416
|
-
|
|
421
|
+
const getNextFiberId = (): number => {
|
|
422
|
+
if (!Number.isSafeInteger(nextFiberId)) throw new RangeError("Fiber ID space exhausted");
|
|
423
|
+
return nextFiberId++;
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
export const setFiberId = (fiber: Fiber, fiberId: number = getNextFiberId()): void => {
|
|
417
427
|
const previousFiberId = fiberIdMap.get(fiber);
|
|
418
|
-
if (
|
|
428
|
+
if (
|
|
429
|
+
previousFiberId !== undefined &&
|
|
430
|
+
previousFiberId !== fiberId &&
|
|
431
|
+
fiberByIdMap.get(previousFiberId)?.deref() === fiber
|
|
432
|
+
) {
|
|
419
433
|
fiberByIdMap.delete(previousFiberId);
|
|
420
434
|
}
|
|
421
435
|
fiberIdMap.set(fiber, fiberId);
|
|
422
436
|
fiberByIdMap.set(fiberId, createFiberReference(fiber));
|
|
423
|
-
fiberIdFinalizationRegistry?.
|
|
437
|
+
if (previousFiberId !== undefined) fiberIdFinalizationRegistry?.unregister(fiber);
|
|
438
|
+
fiberIdFinalizationRegistry?.register(fiber, fiberId, fiber);
|
|
424
439
|
if (Number.isSafeInteger(fiberId) && fiberId >= nextFiberId) {
|
|
425
440
|
nextFiberId = fiberId + 1;
|
|
426
441
|
}
|
|
@@ -430,10 +445,17 @@ export const getFiberId = (fiber: Fiber): number => {
|
|
|
430
445
|
let currentFiberId = fiberIdMap.get(fiber);
|
|
431
446
|
if (currentFiberId === undefined && fiber.alternate) {
|
|
432
447
|
currentFiberId = fiberIdMap.get(fiber.alternate);
|
|
433
|
-
if (currentFiberId !== undefined)
|
|
448
|
+
if (currentFiberId !== undefined) {
|
|
449
|
+
const assignedFiber = fiberByIdMap.get(currentFiberId)?.deref();
|
|
450
|
+
if (assignedFiber && assignedFiber !== fiber.alternate) {
|
|
451
|
+
fiberIdMap.set(fiber, currentFiberId);
|
|
452
|
+
} else {
|
|
453
|
+
setFiberId(fiber, currentFiberId);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
434
456
|
}
|
|
435
457
|
if (currentFiberId === undefined) {
|
|
436
|
-
currentFiberId =
|
|
458
|
+
currentFiberId = getNextFiberId();
|
|
437
459
|
setFiberId(fiber, currentFiberId);
|
|
438
460
|
}
|
|
439
461
|
return currentFiberId;
|
|
@@ -456,6 +478,7 @@ const releaseFiberId = (fiber: Fiber): void => {
|
|
|
456
478
|
const fiberId = fiberIdMap.get(relatedFiber);
|
|
457
479
|
if (fiberId !== undefined) fiberIds.add(fiberId);
|
|
458
480
|
fiberIdMap.delete(relatedFiber);
|
|
481
|
+
fiberIdFinalizationRegistry?.unregister(relatedFiber);
|
|
459
482
|
}
|
|
460
483
|
|
|
461
484
|
for (const fiberId of fiberIds) {
|
|
@@ -532,10 +555,10 @@ const updateFiberTree = (
|
|
|
532
555
|
if (wasTimedOut && isTimedOut) {
|
|
533
556
|
const nextFallback = fiber.child?.sibling;
|
|
534
557
|
const previousFallback = previousFiber.child?.sibling;
|
|
535
|
-
if (nextFallback
|
|
558
|
+
if (nextFallback) {
|
|
536
559
|
pendingUpdates.push({
|
|
537
560
|
fiber: nextFallback,
|
|
538
|
-
previousFiber: previousFallback,
|
|
561
|
+
previousFiber: previousFallback ?? null,
|
|
539
562
|
traverseSiblings: false,
|
|
540
563
|
});
|
|
541
564
|
}
|
|
@@ -606,21 +629,23 @@ const isRootFiberMounted = (fiber: Fiber): boolean => {
|
|
|
606
629
|
*/
|
|
607
630
|
export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: RenderHandler): void => {
|
|
608
631
|
const fiber = "current" in root ? root.current : root;
|
|
632
|
+
const rootKey = "current" in root || !isFiberRoot(root.stateNode) ? root : root.stateNode;
|
|
609
633
|
|
|
610
|
-
let rootInstance = rootInstanceMap.get(
|
|
634
|
+
let rootInstance = rootInstanceMap.get(rootKey);
|
|
611
635
|
|
|
612
636
|
if (!rootInstance) {
|
|
613
637
|
rootInstance = { prevFiber: null };
|
|
614
|
-
rootInstanceMap.set(
|
|
638
|
+
rootInstanceMap.set(rootKey, rootInstance);
|
|
615
639
|
}
|
|
616
640
|
|
|
617
641
|
const { prevFiber } = rootInstance;
|
|
642
|
+
rootInstance.prevFiber = fiber;
|
|
618
643
|
if (!fiber) {
|
|
619
644
|
if (prevFiber) {
|
|
620
645
|
unmountFiber(onRender, prevFiber);
|
|
621
646
|
}
|
|
622
647
|
} else if (prevFiber !== null) {
|
|
623
|
-
const wasMounted = isRootFiberMounted(prevFiber);
|
|
648
|
+
const wasMounted = isRootFiberMounted(fiber.alternate ?? prevFiber);
|
|
624
649
|
const isMounted = isRootFiberMounted(fiber);
|
|
625
650
|
|
|
626
651
|
if (!wasMounted && isMounted) {
|
|
@@ -633,8 +658,6 @@ export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: Render
|
|
|
633
658
|
} else {
|
|
634
659
|
mountFiberTree(onRender, fiber, true);
|
|
635
660
|
}
|
|
636
|
-
|
|
637
|
-
rootInstance.prevFiber = fiber;
|
|
638
661
|
};
|
|
639
662
|
|
|
640
663
|
export interface InstrumentationOptions {
|
|
@@ -690,10 +713,12 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
690
713
|
priority,
|
|
691
714
|
didError,
|
|
692
715
|
) => {
|
|
716
|
+
const isCurrentDispatcher =
|
|
717
|
+
hookDispatchers.get(rdtHook)?.onCommitFiberRoot === dispatchCommitFiberRoot;
|
|
693
718
|
if (prevOnCommitFiberRoot) {
|
|
694
719
|
callListener(prevOnCommitFiberRoot, rdtHook, rendererID, root, priority, didError);
|
|
695
720
|
}
|
|
696
|
-
if (
|
|
721
|
+
if (!isCurrentDispatcher) return;
|
|
697
722
|
setReactWorkTagsForFiber(root.current, rdtHook.renderers.get(rendererID));
|
|
698
723
|
// Custom renderers and test harnesses commit roots without a memoizedState;
|
|
699
724
|
// those must stay tracked, so only explicit unmount evidence removes a root.
|
|
@@ -706,9 +731,14 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
706
731
|
rootRendererIds.set(root, rendererID);
|
|
707
732
|
rootHooks.set(root, rdtHook);
|
|
708
733
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
734
|
+
const subscriptionSnapshot = [...instrumentationSubscriptions];
|
|
735
|
+
for (const subscription of subscriptionSnapshot) {
|
|
736
|
+
const { options, target } = subscription;
|
|
737
|
+
if (instrumentationSubscriptions.has(subscription) && target === hookTargets.get(rdtHook)) {
|
|
738
|
+
callListener(
|
|
739
|
+
() => options.onCommitFiberRoot?.(rendererID, root, priority, didError),
|
|
740
|
+
undefined,
|
|
741
|
+
);
|
|
712
742
|
}
|
|
713
743
|
}
|
|
714
744
|
};
|
|
@@ -725,21 +755,29 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
725
755
|
rendererID,
|
|
726
756
|
fiber,
|
|
727
757
|
) => {
|
|
758
|
+
const isCurrentDispatcher =
|
|
759
|
+
hookDispatchers.get(rdtHook)?.onCommitFiberUnmount === dispatchCommitFiberUnmount;
|
|
728
760
|
setReactWorkTagsForFiber(fiber, rdtHook.renderers.get(rendererID));
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
}
|
|
732
|
-
if (hookDispatchers.get(rdtHook)?.onCommitFiberUnmount !== dispatchCommitFiberUnmount) {
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
761
|
+
const previousUnmountingFiber = currentUnmountingFiber;
|
|
762
|
+
currentUnmountingFiber = fiber;
|
|
735
763
|
try {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
764
|
+
if (prevOnCommitFiberUnmount) {
|
|
765
|
+
callListener(prevOnCommitFiberUnmount, rdtHook, rendererID, fiber);
|
|
766
|
+
}
|
|
767
|
+
if (!isCurrentDispatcher) return;
|
|
768
|
+
const subscriptionSnapshot = [...instrumentationSubscriptions];
|
|
769
|
+
for (const subscription of subscriptionSnapshot) {
|
|
770
|
+
const { options, target } = subscription;
|
|
771
|
+
if (
|
|
772
|
+
instrumentationSubscriptions.has(subscription) &&
|
|
773
|
+
target === hookTargets.get(rdtHook)
|
|
774
|
+
) {
|
|
775
|
+
callListener(() => options.onCommitFiberUnmount?.(rendererID, fiber), undefined);
|
|
739
776
|
}
|
|
740
777
|
}
|
|
741
778
|
} finally {
|
|
742
|
-
|
|
779
|
+
currentUnmountingFiber = previousUnmountingFiber;
|
|
780
|
+
if (isCurrentDispatcher) releaseFiberId(fiber);
|
|
743
781
|
}
|
|
744
782
|
};
|
|
745
783
|
dispatchers.onCommitFiberUnmount = dispatchCommitFiberUnmount;
|
|
@@ -755,15 +793,17 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
755
793
|
rendererID,
|
|
756
794
|
root,
|
|
757
795
|
) => {
|
|
796
|
+
const isCurrentDispatcher =
|
|
797
|
+
hookDispatchers.get(rdtHook)?.onPostCommitFiberRoot === dispatchPostCommitFiberRoot;
|
|
758
798
|
if (prevOnPostCommitFiberRoot) {
|
|
759
799
|
callListener(prevOnPostCommitFiberRoot, rdtHook, rendererID, root);
|
|
760
800
|
}
|
|
761
|
-
if (
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if (target === hookTargets.get(rdtHook)
|
|
766
|
-
callListener(options.onPostCommitFiberRoot
|
|
801
|
+
if (!isCurrentDispatcher) return;
|
|
802
|
+
const subscriptionSnapshot = [...instrumentationSubscriptions];
|
|
803
|
+
for (const subscription of subscriptionSnapshot) {
|
|
804
|
+
const { options, target } = subscription;
|
|
805
|
+
if (instrumentationSubscriptions.has(subscription) && target === hookTargets.get(rdtHook)) {
|
|
806
|
+
callListener(() => options.onPostCommitFiberRoot?.(rendererID, root), undefined);
|
|
767
807
|
}
|
|
768
808
|
}
|
|
769
809
|
};
|
|
@@ -781,13 +821,17 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
781
821
|
root,
|
|
782
822
|
children,
|
|
783
823
|
) => {
|
|
824
|
+
const isCurrentDispatcher =
|
|
825
|
+
hookDispatchers.get(rdtHook)?.onScheduleFiberRoot === dispatchScheduleFiberRoot;
|
|
784
826
|
if (prevOnScheduleFiberRoot) {
|
|
785
827
|
callListener(prevOnScheduleFiberRoot, rdtHook, rendererID, root, children);
|
|
786
828
|
}
|
|
787
|
-
if (
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
829
|
+
if (!isCurrentDispatcher) return;
|
|
830
|
+
const subscriptionSnapshot = [...instrumentationSubscriptions];
|
|
831
|
+
for (const subscription of subscriptionSnapshot) {
|
|
832
|
+
const { options, target } = subscription;
|
|
833
|
+
if (instrumentationSubscriptions.has(subscription) && target === hookTargets.get(rdtHook)) {
|
|
834
|
+
callListener(() => options.onScheduleFiberRoot?.(rendererID, root, children), undefined);
|
|
791
835
|
}
|
|
792
836
|
}
|
|
793
837
|
};
|
|
@@ -843,15 +887,20 @@ try {
|
|
|
843
887
|
*/
|
|
844
888
|
export const instrument = (options: InstrumentationOptions): Unsubscribe => {
|
|
845
889
|
const target = options.target ?? globalThis;
|
|
846
|
-
const
|
|
890
|
+
const activeListener = options.onActive;
|
|
891
|
+
const onActive = activeListener ? () => activeListener() : undefined;
|
|
892
|
+
const existingHook = target.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
893
|
+
if (existingHook) wireHookEventDispatchers(existingHook, target);
|
|
894
|
+
const rdtHook = getRDTHook(undefined, target);
|
|
847
895
|
rdtHook._instrumentationSource = options.name ?? BIPPY_INSTRUMENTATION_STRING;
|
|
848
896
|
|
|
849
897
|
wireHookEventDispatchers(rdtHook, target);
|
|
850
898
|
const subscription: InstrumentationSubscription = { options, target };
|
|
851
899
|
instrumentationSubscriptions.add(subscription);
|
|
900
|
+
if (onActive) getRDTHook(onActive, target);
|
|
852
901
|
|
|
853
902
|
return createUnsubscribe(() => {
|
|
854
|
-
if (
|
|
903
|
+
if (onActive) removeActiveListener(onActive, target);
|
|
855
904
|
instrumentationSubscriptions.delete(subscription);
|
|
856
905
|
});
|
|
857
906
|
};
|
|
@@ -974,6 +1023,6 @@ export {
|
|
|
974
1023
|
onRendererInject,
|
|
975
1024
|
patchRDTHook,
|
|
976
1025
|
version,
|
|
977
|
-
} from "./rdt-hook
|
|
978
|
-
export type { ReactDevToolsTarget, Unsubscribe } from "./rdt-hook
|
|
979
|
-
export * from "./react-internals/index
|
|
1026
|
+
} from "./rdt-hook";
|
|
1027
|
+
export type { ReactDevToolsTarget, Unsubscribe } from "./rdt-hook";
|
|
1028
|
+
export * from "./react-internals/index";
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "./install-hook-only
|
|
1
|
+
import "./install-hook-only";
|
|
2
2
|
|
|
3
|
-
export * from "./core
|
|
4
|
-
export * from "./react
|
|
3
|
+
export * from "./core";
|
|
4
|
+
export * from "./react";
|
package/src/install-hook-only.ts
CHANGED
package/src/rdt-hook.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// This module must load before React so renderers can inject into the hook.
|
|
2
2
|
|
|
3
|
-
import { callListener } from "./call-listener
|
|
4
|
-
import type { FiberRoot, ReactDevToolsGlobalHook, ReactRenderer } from "./react-internals/index
|
|
3
|
+
import { callListener } from "./call-listener";
|
|
4
|
+
import type { FiberRoot, ReactDevToolsGlobalHook, ReactRenderer } from "./react-internals/index";
|
|
5
5
|
|
|
6
6
|
export interface Unsubscribe extends Disposable {
|
|
7
7
|
(): void;
|
|
@@ -24,6 +24,10 @@ interface RDTHookReplaceListener {
|
|
|
24
24
|
(rdtHook: ReactDevToolsGlobalHook, target: ReactDevToolsTarget): void;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
interface RDTHookReplaceSubscription {
|
|
28
|
+
listener: RDTHookReplaceListener;
|
|
29
|
+
}
|
|
30
|
+
|
|
27
31
|
export interface ReactDevToolsTarget {
|
|
28
32
|
__REACT_DEVTOOLS_GLOBAL_HOOK__?: ReactDevToolsGlobalHook;
|
|
29
33
|
}
|
|
@@ -94,7 +98,7 @@ export const _renderers = new Set<ReactRenderer>();
|
|
|
94
98
|
|
|
95
99
|
const activeListenerTargets = new WeakMap<ActiveListener, Set<ReactDevToolsTarget>>();
|
|
96
100
|
const rendererInjectSubscriptions = new Set<RendererInjectSubscription>();
|
|
97
|
-
const
|
|
101
|
+
const rdtHookReplaceSubscriptions = new Set<RDTHookReplaceSubscription>();
|
|
98
102
|
const notifiedRenderersByTarget = new WeakMap<ReactDevToolsTarget, WeakSet<ReactRenderer>>();
|
|
99
103
|
|
|
100
104
|
const addActiveListener = (listener: ActiveListener, target: ReactDevToolsTarget): void => {
|
|
@@ -116,8 +120,11 @@ export const removeActiveListener = (
|
|
|
116
120
|
}
|
|
117
121
|
};
|
|
118
122
|
|
|
119
|
-
const notifyActiveListeners = (
|
|
120
|
-
|
|
123
|
+
const notifyActiveListeners = (
|
|
124
|
+
target: ReactDevToolsTarget,
|
|
125
|
+
pendingListeners = [..._onActiveListeners],
|
|
126
|
+
): void => {
|
|
127
|
+
for (const listener of pendingListeners) {
|
|
121
128
|
if (activeListenerTargets.get(listener)?.has(target)) callListener(listener, undefined);
|
|
122
129
|
}
|
|
123
130
|
};
|
|
@@ -126,8 +133,11 @@ const notifyRendererInjectListeners = (
|
|
|
126
133
|
target: ReactDevToolsTarget,
|
|
127
134
|
renderer: ReactRenderer,
|
|
128
135
|
): void => {
|
|
129
|
-
|
|
130
|
-
|
|
136
|
+
const subscriptionSnapshot = [...rendererInjectSubscriptions];
|
|
137
|
+
for (const subscription of subscriptionSnapshot) {
|
|
138
|
+
if (rendererInjectSubscriptions.has(subscription) && subscription.target === target) {
|
|
139
|
+
callListener(subscription.listener, subscription, renderer);
|
|
140
|
+
}
|
|
131
141
|
}
|
|
132
142
|
};
|
|
133
143
|
|
|
@@ -135,8 +145,11 @@ const notifyRDTHookReplaceListeners = (
|
|
|
135
145
|
rdtHook: ReactDevToolsGlobalHook,
|
|
136
146
|
target: ReactDevToolsTarget,
|
|
137
147
|
): void => {
|
|
138
|
-
|
|
139
|
-
|
|
148
|
+
const subscriptionSnapshot = [...rdtHookReplaceSubscriptions];
|
|
149
|
+
for (const subscription of subscriptionSnapshot) {
|
|
150
|
+
if (rdtHookReplaceSubscriptions.has(subscription)) {
|
|
151
|
+
callListener(subscription.listener, undefined, rdtHook, target);
|
|
152
|
+
}
|
|
140
153
|
}
|
|
141
154
|
};
|
|
142
155
|
|
|
@@ -153,9 +166,10 @@ export const onRendererInject = (
|
|
|
153
166
|
};
|
|
154
167
|
|
|
155
168
|
export const onRDTHookReplace = (listener: RDTHookReplaceListener): Unsubscribe => {
|
|
156
|
-
|
|
169
|
+
const subscription = { listener };
|
|
170
|
+
rdtHookReplaceSubscriptions.add(subscription);
|
|
157
171
|
return createUnsubscribe(() => {
|
|
158
|
-
|
|
172
|
+
rdtHookReplaceSubscriptions.delete(subscription);
|
|
159
173
|
});
|
|
160
174
|
};
|
|
161
175
|
|
|
@@ -243,10 +257,11 @@ export const installRDTHook = (
|
|
|
243
257
|
_renderers.add(renderer);
|
|
244
258
|
nextRenderers.set(rendererId, renderer);
|
|
245
259
|
});
|
|
246
|
-
if (ourRenderers.size > 0 ||
|
|
247
|
-
patchRDTHook(
|
|
260
|
+
if (ourRenderers.size > 0 || rdtHookReplaceSubscriptions.size > 0) {
|
|
261
|
+
patchRDTHook(undefined, target, () => notifyRDTHookReplaceListeners(newHook, target));
|
|
262
|
+
} else {
|
|
263
|
+
notifyRDTHookReplaceListeners(newHook, target);
|
|
248
264
|
}
|
|
249
|
-
notifyRDTHookReplaceListeners(rdtHook, target);
|
|
250
265
|
}
|
|
251
266
|
},
|
|
252
267
|
});
|
|
@@ -288,9 +303,10 @@ export const installRDTHook = (
|
|
|
288
303
|
export const patchRDTHook = (
|
|
289
304
|
onActive?: ActiveListener,
|
|
290
305
|
target: ReactDevToolsTarget = globalThis,
|
|
306
|
+
onReady?: () => void,
|
|
291
307
|
): void => {
|
|
292
308
|
if (onActive) addActiveListener(onActive, target);
|
|
293
|
-
let
|
|
309
|
+
let shouldNotifyActiveListeners = false;
|
|
294
310
|
const rdtHook = getTargetHook(target);
|
|
295
311
|
if (!rdtHook) return;
|
|
296
312
|
const renderers = getRendererMap(rdtHook);
|
|
@@ -306,28 +322,25 @@ export const patchRDTHook = (
|
|
|
306
322
|
if (!isReactDevtools) {
|
|
307
323
|
rdtHook.on = noOp;
|
|
308
324
|
}
|
|
309
|
-
|
|
310
|
-
renderers.forEach((renderer) => _renderers.add(renderer));
|
|
311
|
-
rdtHook._instrumentationIsActive = true;
|
|
312
|
-
notifyActiveListeners(target);
|
|
313
|
-
didNotifyActiveListeners = true;
|
|
314
|
-
} else if (!isReactDevtools && isReactRefresh(rdtHook)) {
|
|
315
|
-
// HACK: react-refresh's stub inject never records renderers, so a React app
|
|
316
|
-
// that injected before bippy loaded is undetectable through the renderers map.
|
|
317
|
-
// A react-refresh hook implies a dev renderer, so activate immediately.
|
|
318
|
-
rdtHook._instrumentationIsActive = true;
|
|
319
|
-
notifyActiveListeners(target);
|
|
320
|
-
didNotifyActiveListeners = true;
|
|
321
|
-
}
|
|
325
|
+
const shouldActivate = renderers.size > 0 || (!isReactDevtools && isReactRefresh(rdtHook));
|
|
322
326
|
const previousInject = rdtHook.inject;
|
|
323
327
|
rdtHook.inject = (renderer) => {
|
|
324
328
|
const rendererId = previousInject.call(rdtHook, renderer);
|
|
325
329
|
trackInjectedRenderer(rdtHook, target, renderers, rendererId, renderer);
|
|
326
330
|
return rendererId;
|
|
327
331
|
};
|
|
332
|
+
if (shouldActivate) {
|
|
333
|
+
renderers.forEach((renderer) => _renderers.add(renderer));
|
|
334
|
+
rdtHook._instrumentationIsActive = true;
|
|
335
|
+
shouldNotifyActiveListeners = true;
|
|
336
|
+
}
|
|
328
337
|
}
|
|
329
|
-
|
|
330
|
-
|
|
338
|
+
const pendingListeners = shouldNotifyActiveListeners ? [..._onActiveListeners] : [];
|
|
339
|
+
onReady?.();
|
|
340
|
+
if (shouldNotifyActiveListeners) {
|
|
341
|
+
notifyActiveListeners(target, pendingListeners);
|
|
342
|
+
} else if (onActive && (renderers.size || rdtHook._instrumentationIsActive)) {
|
|
343
|
+
callListener(onActive, undefined);
|
|
331
344
|
}
|
|
332
345
|
};
|
|
333
346
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Adapted from ReactFiberTreeReflection.js. Copyright (c) Meta Platforms, Inc. and affiliates. MIT licensed.
|
|
2
|
-
import type { Fiber } from "./types
|
|
3
|
-
import { getReactWorkTagsForFiber } from "./index
|
|
2
|
+
import type { Fiber } from "./types";
|
|
3
|
+
import { getReactWorkTagsForFiber } from "./index";
|
|
4
4
|
|
|
5
5
|
export const getCurrentFiberFromRoot = (fiber: Fiber): Fiber | null => {
|
|
6
6
|
const alternate = fiber.alternate;
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { getReactWorkTags, ReactFiberFlags } from "./generated/react-work-tags
|
|
2
|
-
import type { ReactWorkTagMap } from "./generated/react-work-tags
|
|
3
|
-
import { isSemver } from "./semver
|
|
4
|
-
import type { Fiber, ReactRenderer } from "./types
|
|
1
|
+
import { getReactWorkTags, ReactFiberFlags } from "./generated/react-work-tags";
|
|
2
|
+
import type { ReactWorkTagMap } from "./generated/react-work-tags";
|
|
3
|
+
import { isSemver } from "./semver";
|
|
4
|
+
import type { Fiber, ReactRenderer } from "./types";
|
|
5
5
|
|
|
6
|
-
export { compareSemver } from "./semver
|
|
6
|
+
export { compareSemver } from "./semver";
|
|
7
7
|
export {
|
|
8
8
|
getReactWorkTags,
|
|
9
9
|
ReactBuildType,
|
|
10
10
|
ReactFiberFlags,
|
|
11
11
|
ReactSymbols,
|
|
12
|
-
} from "./generated/react-work-tags
|
|
12
|
+
} from "./generated/react-work-tags";
|
|
13
13
|
export type {
|
|
14
14
|
HostWorkTag,
|
|
15
15
|
ReactWorkTag,
|
|
16
16
|
ReactWorkTagMap,
|
|
17
17
|
ReactWorkTagVersion,
|
|
18
|
-
} from "./generated/react-work-tags
|
|
19
|
-
export * from "./types
|
|
18
|
+
} from "./generated/react-work-tags";
|
|
19
|
+
export * from "./types";
|
|
20
20
|
|
|
21
21
|
interface InheritedWorkTags {
|
|
22
22
|
workTags: Readonly<ReactWorkTagMap>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type ReactReconciler from "react-reconciler";
|
|
3
|
-
import type { HostWorkTag, ReactWorkTag } from "./generated/react-work-tags
|
|
3
|
+
import type { HostWorkTag, ReactWorkTag } from "./generated/react-work-tags";
|
|
4
4
|
|
|
5
5
|
export type WorkTag = ReactReconciler.WorkTag | ReactWorkTag;
|
|
6
6
|
|
package/src/react.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import "./install-hook-only
|
|
1
|
+
import "./install-hook-only";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import { isFiber, traverseFiber } from "./core
|
|
4
|
-
import { _renderers } from "./rdt-hook
|
|
5
|
-
import { getCurrentFiberFromRoot } from "./react-internals/current-fiber
|
|
6
|
-
import type { Fiber } from "./react-internals/index
|
|
3
|
+
import { isFiber, traverseFiber } from "./core";
|
|
4
|
+
import { _renderers } from "./rdt-hook";
|
|
5
|
+
import { getCurrentFiberFromRoot } from "./react-internals/current-fiber";
|
|
6
|
+
import type { Fiber } from "./react-internals/index";
|
|
7
7
|
|
|
8
|
-
export type { Fiber } from "./react-internals/index
|
|
8
|
+
export type { Fiber } from "./react-internals/index";
|
|
9
9
|
|
|
10
10
|
interface RenderMarker {
|
|
11
11
|
(state: undefined): undefined;
|
package/src/source/constants.ts
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
export const SCHEME_REGEX = /^[a-zA-Z][a-zA-Z\d+\-.]*:/;
|
|
2
2
|
|
|
3
3
|
export const INTERNAL_SCHEME_PREFIXES = [
|
|
4
|
-
"
|
|
5
|
-
"file:///",
|
|
4
|
+
"rspack-internal://",
|
|
6
5
|
"webpack-internal://",
|
|
7
|
-
"webpack://",
|
|
8
|
-
"node:",
|
|
9
6
|
"turbopack://",
|
|
7
|
+
"webpack://",
|
|
8
|
+
"rspack://",
|
|
9
|
+
"parcel://",
|
|
10
10
|
"metro://",
|
|
11
|
-
"
|
|
11
|
+
"file:///",
|
|
12
|
+
"rsc://",
|
|
13
|
+
"node:",
|
|
14
|
+
"bun:",
|
|
12
15
|
"/(app-pages-browser)/",
|
|
16
|
+
"/app-pages-browser/",
|
|
13
17
|
] as const;
|
|
14
18
|
|
|
15
19
|
export const ABOUT_REACT_PREFIX = "about://React/";
|
|
@@ -21,7 +25,7 @@ export const ANONYMOUS_FILE_PATTERNS = ["<anonymous>", "eval", ""] as const;
|
|
|
21
25
|
export const SOURCE_FILE_EXTENSION_REGEX = /\.(cjs|cts|js|jsx|mdx|mjs|mts|ts|tsx)$/;
|
|
22
26
|
|
|
23
27
|
export const BUNDLED_FILE_PATTERN_REGEX =
|
|
24
|
-
/(\.min|bundle|chunk|vendor|vendors|runtime|polyfill|polyfills)\.(js|mjs|cjs)$|(chunk|bundle|vendor|vendors|runtime|polyfill|polyfills|framework|app|main|index)[-_.][A-Za-z0-9_-]{4,}\.(js|mjs|cjs)$|[\da-f]{8,}\.(js|mjs|cjs)$|[-_.][\da-f]{20,}\.(js|mjs|cjs)$|\/dist\/|\/build\/|\/.next\/|\/out\/|\/node_modules\/|\.webpack\.|\.vite\.|\.turbopack
|
|
28
|
+
/(\.min|bundle|chunk|vendor|vendors|runtime|polyfill|polyfills)\.(js|mjs|cjs)$|(chunk|bundle|vendor|vendors|runtime|polyfill|polyfills|framework|app|main|index)[-_.][A-Za-z0-9_-]{4,}\.(js|mjs|cjs)$|[\da-f]{8,}\.(js|mjs|cjs)$|[-_.][\da-f]{20,}\.(js|mjs|cjs)$|\/dist\/|\/build\/|\/.next\/|\/out\/|\/node_modules\/|\/_next\/|\/_expo\/|\/_nuxt\/|\/@vite\/|\/@react-refresh|\/\.parcel-cache\/|\/\.expo\/|\/\.rsbuild\/|\/\.vite\/|\/\.svelte-kit\/|\/\.astro\/|\/\.nuxt\/|\/\.angular\/|\.webpack\.|\.vite\.|\.turbopack\.|\[root-of-the-server\]/i;
|
|
25
29
|
|
|
26
30
|
export const QUERY_PARAMETER_PATTERN_REGEX = /^\?[\w~.-]+(?:=[^&#]*)?(?:&[\w~.-]+(?:=[^&#]*)?)*$/;
|
|
27
31
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type { Fiber } from "../react-internals/index
|
|
2
|
-
import { getDisplayName } from "../core
|
|
3
|
-
import { getDefinitionFrameFromOwnedChild, getRawParentStack } from "./owner-stack
|
|
1
|
+
import type { Fiber } from "../react-internals/index";
|
|
2
|
+
import { getDisplayName } from "../core";
|
|
3
|
+
import { getDefinitionFrameFromOwnedChild, getRawParentStack } from "./owner-stack";
|
|
4
4
|
import {
|
|
5
5
|
getSourceContentFromSourceMap,
|
|
6
6
|
getSourceFromSourceMap,
|
|
7
7
|
getSourceMap,
|
|
8
8
|
type SourceFetch,
|
|
9
9
|
type SourceMapRequestOptions,
|
|
10
|
-
} from "./symbolication
|
|
11
|
-
import type { StackFrame } from "./parse-stack
|
|
10
|
+
} from "./symbolication";
|
|
11
|
+
import type { StackFrame } from "./parse-stack";
|
|
12
12
|
|
|
13
13
|
const COMPONENT_DECLARATION_PATTERNS = [
|
|
14
14
|
/(?:^|export\s+)(?:const|let|var)\s+(\w+)\s*=/,
|