bippy 0.7.2 → 0.7.3-dev.0ac832d
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 +1 -0
- package/README.md +9 -76
- package/dist/core.cjs +1 -1
- package/dist/core.js +1 -1
- package/dist/errors.d.cts +56 -9
- package/dist/errors.d.ts +56 -9
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +14 -38
- package/dist/index.d.ts +18 -42
- package/dist/index.js +1 -1
- package/dist/install-hook-only.cjs +1 -1
- package/dist/install-hook-only.js +1 -1
- package/dist/rdt-hook.cjs +1 -1
- package/dist/rdt-hook.js +1 -1
- package/dist/source.cjs +11 -11
- package/dist/source.d.cts +36 -9
- package/dist/source.d.ts +36 -9
- package/dist/source.js +11 -11
- package/package.json +5 -33
- package/src/call-listener.ts +13 -0
- package/src/core.ts +287 -258
- package/src/rdt-hook.ts +130 -71
- package/src/react-internals/current-fiber.ts +84 -0
- package/src/react-internals/index.ts +38 -11
- package/src/react-internals/types.ts +33 -6
- package/src/react.ts +141 -55
- package/src/source/constants.ts +1 -3
- package/src/source/get-display-name-from-source.ts +10 -3
- package/src/source/get-source.ts +39 -19
- package/src/source/index.ts +17 -3
- package/src/source/inspect-hooks.ts +198 -49
- package/src/source/owner-stack.ts +43 -35
- package/src/source/parse-debug-stack.ts +1 -1
- package/src/source/parse-hook-names.ts +15 -8
- package/src/source/parse-stack.ts +114 -64
- package/src/source/renderer-dispatchers.ts +9 -4
- package/src/source/symbolication.ts +68 -36
package/src/core.ts
CHANGED
|
@@ -1,5 +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.js";
|
|
3
4
|
|
|
4
5
|
import type {
|
|
5
6
|
Fiber,
|
|
@@ -10,19 +11,20 @@ import type {
|
|
|
10
11
|
} from "./react-internals/index.js";
|
|
11
12
|
|
|
12
13
|
import {
|
|
13
|
-
_onActiveListeners,
|
|
14
14
|
BIPPY_INSTRUMENTATION_STRING,
|
|
15
15
|
createUnsubscribe,
|
|
16
16
|
getRDTHook,
|
|
17
17
|
hasRDTHook,
|
|
18
|
+
isFiberRootUnmounted,
|
|
18
19
|
isReactRefresh,
|
|
19
20
|
isRealReactDevtools,
|
|
20
21
|
onRDTHookReplace,
|
|
22
|
+
removeActiveListener,
|
|
21
23
|
} from "./rdt-hook.js";
|
|
22
|
-
import type { Unsubscribe } from "./rdt-hook.js";
|
|
24
|
+
import type { ReactDevToolsTarget, Unsubscribe } from "./rdt-hook.js";
|
|
25
|
+
import { getCurrentFiberFromRoot } from "./react-internals/current-fiber.js";
|
|
23
26
|
import {
|
|
24
27
|
getReactWorkTagsForFiber,
|
|
25
|
-
MutationMask,
|
|
26
28
|
ReactBuildType,
|
|
27
29
|
ReactFiberFlags,
|
|
28
30
|
ReactSymbols,
|
|
@@ -64,8 +66,8 @@ export const isValidElement = (element: unknown): element is React.ReactElement
|
|
|
64
66
|
typeof element === "object" &&
|
|
65
67
|
element !== null &&
|
|
66
68
|
"$$typeof" in element &&
|
|
67
|
-
(
|
|
68
|
-
|
|
69
|
+
(element.$$typeof === Symbol.for("react.element") ||
|
|
70
|
+
element.$$typeof === Symbol.for("react.transitional.element"));
|
|
69
71
|
|
|
70
72
|
/**
|
|
71
73
|
* Returns `true` if object is a React Fiber.
|
|
@@ -78,7 +80,7 @@ export const isFiber = (fiber: unknown): fiber is Fiber =>
|
|
|
78
80
|
"return" in fiber &&
|
|
79
81
|
"child" in fiber &&
|
|
80
82
|
"sibling" in fiber &&
|
|
81
|
-
"flags" in fiber;
|
|
83
|
+
("flags" in fiber || "effectTag" in fiber);
|
|
82
84
|
|
|
83
85
|
const isFiberRoot = (fiberRoot: unknown): fiberRoot is FiberRoot =>
|
|
84
86
|
typeof fiberRoot === "object" &&
|
|
@@ -128,7 +130,7 @@ export const isCompositeFiber = (fiber: Fiber): boolean => {
|
|
|
128
130
|
*/
|
|
129
131
|
export const didFiberRender = (fiber: Fiber): boolean => {
|
|
130
132
|
const nextProps = fiber.memoizedProps;
|
|
131
|
-
const prevProps = fiber.alternate?.memoizedProps
|
|
133
|
+
const prevProps = fiber.alternate?.memoizedProps;
|
|
132
134
|
const flags = fiber.flags ?? fiber.effectTag ?? 0;
|
|
133
135
|
const workTags = getReactWorkTagsForFiber(fiber);
|
|
134
136
|
|
|
@@ -152,16 +154,6 @@ export const didFiberRender = (fiber: Fiber): boolean => {
|
|
|
152
154
|
}
|
|
153
155
|
};
|
|
154
156
|
|
|
155
|
-
/**
|
|
156
|
-
* Returns `true` if the {@link Fiber} has committed. Note that this does not mean the fiber has committed in the current commit, just that it has committed in the past.
|
|
157
|
-
*/
|
|
158
|
-
export const didFiberCommit = (fiber: Fiber): boolean => {
|
|
159
|
-
return Boolean(
|
|
160
|
-
(fiber.flags & (MutationMask | ReactFiberFlags.Cloned)) !== 0 ||
|
|
161
|
-
(fiber.subtreeFlags & (MutationMask | ReactFiberFlags.Cloned)) !== 0,
|
|
162
|
-
);
|
|
163
|
-
};
|
|
164
|
-
|
|
165
157
|
/**
|
|
166
158
|
* Returns `true` if the {@link Fiber} should be filtered out during reconciliation.
|
|
167
159
|
*/
|
|
@@ -210,41 +202,57 @@ const shouldFilterFiber = (fiber: Fiber): boolean => {
|
|
|
210
202
|
}
|
|
211
203
|
};
|
|
212
204
|
|
|
205
|
+
interface TraverseFiber {
|
|
206
|
+
(
|
|
207
|
+
fiber: Fiber | null,
|
|
208
|
+
selector: (node: Fiber) => boolean | void,
|
|
209
|
+
ascending?: boolean,
|
|
210
|
+
): Fiber | null;
|
|
211
|
+
(
|
|
212
|
+
fiber: Fiber | null,
|
|
213
|
+
selector: (node: Fiber) => Promise<boolean | void>,
|
|
214
|
+
ascending?: boolean,
|
|
215
|
+
): Promise<Fiber | null>;
|
|
216
|
+
(
|
|
217
|
+
fiber: Fiber | null,
|
|
218
|
+
selector: FiberSelector,
|
|
219
|
+
ascending?: boolean,
|
|
220
|
+
): Fiber | null | Promise<Fiber | null>;
|
|
221
|
+
}
|
|
222
|
+
|
|
213
223
|
/**
|
|
214
224
|
* Traverses up or down a {@link Fiber}, return `true` to stop and select a node.
|
|
215
225
|
*/
|
|
216
|
-
export
|
|
217
|
-
fiber: Fiber | null,
|
|
218
|
-
selector: (node: Fiber) => boolean | void,
|
|
219
|
-
ascending?: boolean,
|
|
220
|
-
): Fiber | null;
|
|
221
|
-
export function traverseFiber(
|
|
222
|
-
fiber: Fiber | null,
|
|
223
|
-
selector: (node: Fiber) => Promise<boolean | void>,
|
|
224
|
-
ascending?: boolean,
|
|
225
|
-
): Promise<Fiber | null>;
|
|
226
|
-
export function traverseFiber(
|
|
227
|
-
fiber: Fiber | null,
|
|
228
|
-
selector: FiberSelector,
|
|
229
|
-
ascending?: boolean,
|
|
230
|
-
): Fiber | null | Promise<Fiber | null>;
|
|
231
|
-
export function traverseFiber(
|
|
226
|
+
export const traverseFiber = ((
|
|
232
227
|
fiber: Fiber | null,
|
|
233
228
|
selector: FiberSelector,
|
|
234
229
|
ascending = false,
|
|
235
|
-
): Fiber | null | Promise<Fiber | null> {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
230
|
+
): Fiber | null | Promise<Fiber | null> => {
|
|
231
|
+
const pendingSiblings: Fiber[] = [];
|
|
232
|
+
const getNextFiber = (currentFiber: Fiber): Fiber | null => {
|
|
233
|
+
if (ascending) return currentFiber.return;
|
|
234
|
+
if (currentFiber !== fiber && currentFiber.sibling) {
|
|
235
|
+
pendingSiblings.push(currentFiber.sibling);
|
|
236
|
+
}
|
|
237
|
+
return currentFiber.child ?? pendingSiblings.pop() ?? null;
|
|
238
|
+
};
|
|
239
|
+
const visit = (firstFiber: Fiber | null): Fiber | null | Promise<Fiber | null> => {
|
|
240
|
+
let currentFiber = firstFiber;
|
|
241
|
+
while (currentFiber) {
|
|
242
|
+
const selectedFiber = currentFiber;
|
|
243
|
+
const selection = selector(selectedFiber);
|
|
244
|
+
if (isPromiseLike<boolean | void>(selection)) {
|
|
245
|
+
return Promise.resolve(selection).then((didSelectFiber) =>
|
|
246
|
+
didSelectFiber === true ? selectedFiber : visit(getNextFiber(selectedFiber)),
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
if (selection === true) return selectedFiber;
|
|
250
|
+
currentFiber = getNextFiber(selectedFiber);
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
};
|
|
254
|
+
return visit(fiber);
|
|
255
|
+
}) as TraverseFiber;
|
|
248
256
|
|
|
249
257
|
const isPromiseLike = <Result>(value: unknown): value is PromiseLike<Result> =>
|
|
250
258
|
(typeof value === "object" || typeof value === "function") &&
|
|
@@ -252,32 +260,6 @@ const isPromiseLike = <Result>(value: unknown): value is PromiseLike<Result> =>
|
|
|
252
260
|
"then" in value &&
|
|
253
261
|
typeof value.then === "function";
|
|
254
262
|
|
|
255
|
-
const traverseFiberChildren = (
|
|
256
|
-
fiber: Fiber,
|
|
257
|
-
selector: FiberSelector,
|
|
258
|
-
ascending: boolean,
|
|
259
|
-
): Fiber | null | Promise<Fiber | null> => {
|
|
260
|
-
const firstChild = ascending ? fiber.return : fiber.child;
|
|
261
|
-
return traverseFiberSiblings(firstChild, selector, ascending);
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
const traverseFiberSiblings = (
|
|
265
|
-
fiber: Fiber | null,
|
|
266
|
-
selector: FiberSelector,
|
|
267
|
-
ascending: boolean,
|
|
268
|
-
): Fiber | null | Promise<Fiber | null> => {
|
|
269
|
-
if (!fiber) return null;
|
|
270
|
-
|
|
271
|
-
const nextSibling = ascending ? null : fiber.sibling;
|
|
272
|
-
const match = traverseFiber(fiber, selector, ascending);
|
|
273
|
-
if (isPromiseLike<Fiber | null>(match)) {
|
|
274
|
-
return Promise.resolve(match).then(
|
|
275
|
-
(resolvedMatch) => resolvedMatch ?? traverseFiberSiblings(nextSibling, selector, ascending),
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
return match ?? traverseFiberSiblings(nextSibling, selector, ascending);
|
|
279
|
-
};
|
|
280
|
-
|
|
281
263
|
/**
|
|
282
264
|
* Returns `true` if the {@link Fiber} uses React Compiler's memo cache.
|
|
283
265
|
*/
|
|
@@ -291,7 +273,14 @@ export const hasMemoCache = (fiber: Fiber): boolean => {
|
|
|
291
273
|
export const getType = (type: unknown): null | React.ComponentType<unknown> => {
|
|
292
274
|
if (isComponentType(type)) return type;
|
|
293
275
|
if (typeof type !== "object" || type === null) return null;
|
|
294
|
-
|
|
276
|
+
const visitedTypes = new Set<object>();
|
|
277
|
+
let currentType: unknown = type;
|
|
278
|
+
while (typeof currentType === "object" && currentType !== null) {
|
|
279
|
+
if (visitedTypes.has(currentType)) return null;
|
|
280
|
+
visitedTypes.add(currentType);
|
|
281
|
+
currentType = Reflect.get(currentType, "type") ?? Reflect.get(currentType, "render");
|
|
282
|
+
}
|
|
283
|
+
return isComponentType(currentType) ? currentType : null;
|
|
295
284
|
};
|
|
296
285
|
|
|
297
286
|
/**
|
|
@@ -312,10 +301,7 @@ export const getDisplayName = (type: unknown): null | string => {
|
|
|
312
301
|
*/
|
|
313
302
|
export const detectReactBuildType = (renderer: ReactRenderer): "development" | "production" => {
|
|
314
303
|
try {
|
|
315
|
-
if (
|
|
316
|
-
typeof renderer.version === "string" &&
|
|
317
|
-
renderer.bundleType === ReactBuildType.Development
|
|
318
|
-
) {
|
|
304
|
+
if (typeof renderer.version === "string" && renderer.bundleType > ReactBuildType.Production) {
|
|
319
305
|
return "development";
|
|
320
306
|
}
|
|
321
307
|
} catch {}
|
|
@@ -325,8 +311,8 @@ export const detectReactBuildType = (renderer: ReactRenderer): "development" | "
|
|
|
325
311
|
/**
|
|
326
312
|
* Returns `true` if bippy's instrumentation is active.
|
|
327
313
|
*/
|
|
328
|
-
export const isInstrumentationActive = (): boolean => {
|
|
329
|
-
const rdtHook =
|
|
314
|
+
export const isInstrumentationActive = (target: ReactDevToolsTarget = globalThis): boolean => {
|
|
315
|
+
const rdtHook = target.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
330
316
|
return (
|
|
331
317
|
Boolean(rdtHook?._instrumentationIsActive) ||
|
|
332
318
|
isRealReactDevtools(rdtHook) ||
|
|
@@ -336,6 +322,7 @@ export const isInstrumentationActive = (): boolean => {
|
|
|
336
322
|
|
|
337
323
|
export const _fiberRoots = new Set<FiberRoot>();
|
|
338
324
|
const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
325
|
+
const rootHooks = new WeakMap<FiberRoot, ReactDevToolsGlobalHook>();
|
|
339
326
|
|
|
340
327
|
/**
|
|
341
328
|
* Returns the latest fiber (since it may be double-buffered).
|
|
@@ -343,6 +330,8 @@ const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
|
343
330
|
export const getLatestFiber = (fiber: Fiber): Fiber => {
|
|
344
331
|
const alternate = fiber.alternate;
|
|
345
332
|
if (!alternate) return fiber;
|
|
333
|
+
const currentFiber = getCurrentFiberFromRoot(fiber);
|
|
334
|
+
if (currentFiber) return currentFiber;
|
|
346
335
|
|
|
347
336
|
let rootFiber = fiber;
|
|
348
337
|
while (rootFiber.return) {
|
|
@@ -370,29 +359,61 @@ export const getLatestFiber = (fiber: Fiber): Fiber => {
|
|
|
370
359
|
/**
|
|
371
360
|
* Returns the renderer that owns the {@link Fiber}.
|
|
372
361
|
*/
|
|
373
|
-
export const getRenderer = (
|
|
374
|
-
|
|
375
|
-
|
|
362
|
+
export const getRenderer = (
|
|
363
|
+
fiber: Fiber,
|
|
364
|
+
target: ReactDevToolsTarget = globalThis,
|
|
365
|
+
): ReactRenderer | null => {
|
|
376
366
|
let rootFiber = fiber;
|
|
377
|
-
while (rootFiber.return)
|
|
378
|
-
rootFiber = rootFiber.return;
|
|
379
|
-
}
|
|
380
|
-
|
|
367
|
+
while (rootFiber.return) rootFiber = rootFiber.return;
|
|
381
368
|
const fiberRoot = rootFiber.stateNode;
|
|
382
369
|
if (!isFiberRoot(fiberRoot)) return null;
|
|
383
370
|
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
371
|
+
const trackedRendererId = rootRendererIds.get(fiberRoot);
|
|
372
|
+
const trackedHook = rootHooks.get(fiberRoot);
|
|
373
|
+
if (trackedRendererId !== undefined && trackedHook) {
|
|
374
|
+
return trackedHook.renderers.get(trackedRendererId) ?? null;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const rdtHook = target.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
378
|
+
if (!rdtHook?.getFiberRoots) return null;
|
|
379
|
+
for (const [rendererId, renderer] of rdtHook.renderers) {
|
|
380
|
+
if (!rdtHook.getFiberRoots(rendererId).has(fiberRoot)) continue;
|
|
381
|
+
_fiberRoots.add(fiberRoot);
|
|
382
|
+
rootRendererIds.set(fiberRoot, rendererId);
|
|
383
|
+
rootHooks.set(fiberRoot, rdtHook);
|
|
384
|
+
setReactWorkTagsForFiber(fiberRoot.current, renderer);
|
|
385
|
+
return renderer;
|
|
386
|
+
}
|
|
387
|
+
return null;
|
|
387
388
|
};
|
|
388
389
|
|
|
389
390
|
export type RenderPhase = "mount" | "unmount" | "update";
|
|
390
391
|
|
|
392
|
+
interface FiberReference {
|
|
393
|
+
deref: () => Fiber | undefined;
|
|
394
|
+
}
|
|
395
|
+
|
|
391
396
|
let nextFiberId = 0;
|
|
392
397
|
const fiberIdMap = new WeakMap<Fiber, number>();
|
|
398
|
+
const fiberByIdMap = new Map<number, FiberReference>();
|
|
399
|
+
const fiberIdFinalizationRegistry =
|
|
400
|
+
typeof FinalizationRegistry === "function"
|
|
401
|
+
? new FinalizationRegistry<number>((fiberId) => {
|
|
402
|
+
if (!fiberByIdMap.get(fiberId)?.deref()) fiberByIdMap.delete(fiberId);
|
|
403
|
+
})
|
|
404
|
+
: null;
|
|
405
|
+
|
|
406
|
+
const createFiberReference = (fiber: Fiber): FiberReference =>
|
|
407
|
+
typeof WeakRef === "function" ? new WeakRef(fiber) : { deref: () => fiber };
|
|
393
408
|
|
|
394
409
|
export const setFiberId = (fiber: Fiber, fiberId: number = nextFiberId++): void => {
|
|
410
|
+
const previousFiberId = fiberIdMap.get(fiber);
|
|
411
|
+
if (previousFiberId !== undefined && previousFiberId !== fiberId) {
|
|
412
|
+
fiberByIdMap.delete(previousFiberId);
|
|
413
|
+
}
|
|
395
414
|
fiberIdMap.set(fiber, fiberId);
|
|
415
|
+
fiberByIdMap.set(fiberId, createFiberReference(fiber));
|
|
416
|
+
fiberIdFinalizationRegistry?.register(fiber, fiberId);
|
|
396
417
|
if (Number.isSafeInteger(fiberId) && fiberId >= nextFiberId) {
|
|
397
418
|
nextFiberId = fiberId + 1;
|
|
398
419
|
}
|
|
@@ -402,6 +423,7 @@ export const getFiberId = (fiber: Fiber): number => {
|
|
|
402
423
|
let currentFiberId = fiberIdMap.get(fiber);
|
|
403
424
|
if (currentFiberId === undefined && fiber.alternate) {
|
|
404
425
|
currentFiberId = fiberIdMap.get(fiber.alternate);
|
|
426
|
+
if (currentFiberId !== undefined) setFiberId(fiber, currentFiberId);
|
|
405
427
|
}
|
|
406
428
|
if (currentFiberId === undefined) {
|
|
407
429
|
currentFiberId = nextFiberId++;
|
|
@@ -410,131 +432,118 @@ export const getFiberId = (fiber: Fiber): number => {
|
|
|
410
432
|
return currentFiberId;
|
|
411
433
|
};
|
|
412
434
|
|
|
413
|
-
const
|
|
435
|
+
export const getFiberById = (fiberId: number): Fiber | null => {
|
|
436
|
+
const fiber = fiberByIdMap.get(fiberId)?.deref();
|
|
437
|
+
if (!fiber) {
|
|
438
|
+
fiberByIdMap.delete(fiberId);
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
return getLatestFiber(fiber);
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
const releaseFiberId = (fiber: Fiber): void => {
|
|
445
|
+
const relatedFibers = fiber.alternate ? [fiber, fiber.alternate] : [fiber];
|
|
446
|
+
const fiberIds = new Set<number>();
|
|
447
|
+
|
|
448
|
+
for (const relatedFiber of relatedFibers) {
|
|
449
|
+
const fiberId = fiberIdMap.get(relatedFiber);
|
|
450
|
+
if (fiberId !== undefined) fiberIds.add(fiberId);
|
|
451
|
+
fiberIdMap.delete(relatedFiber);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
for (const fiberId of fiberIds) {
|
|
455
|
+
const assignedFiber = fiberByIdMap.get(fiberId)?.deref();
|
|
456
|
+
if (!assignedFiber || relatedFibers.includes(assignedFiber)) {
|
|
457
|
+
fiberByIdMap.delete(fiberId);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
const getRenderedChild = (fiber: Fiber, skipPrimaryWrapper: boolean): Fiber | null => {
|
|
463
|
+
const workTags = getReactWorkTagsForFiber(fiber);
|
|
464
|
+
if (fiber.tag !== workTags.SuspenseComponent) return fiber.child;
|
|
465
|
+
if (fiber.memoizedState !== null) return fiber.child?.sibling?.child ?? null;
|
|
466
|
+
return skipPrimaryWrapper && workTags.OffscreenComponent !== -1
|
|
467
|
+
? (fiber.child?.child ?? null)
|
|
468
|
+
: fiber.child;
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
const mountFiberTree = (
|
|
414
472
|
onRender: RenderHandler,
|
|
415
473
|
firstChild: Fiber,
|
|
416
474
|
traverseSiblings: boolean,
|
|
417
475
|
): void => {
|
|
476
|
+
const pendingSiblings: Fiber[] = [];
|
|
418
477
|
let fiber: Fiber | null = firstChild;
|
|
419
|
-
|
|
420
|
-
while (fiber !== null) {
|
|
478
|
+
while (fiber) {
|
|
421
479
|
getFiberId(fiber);
|
|
422
|
-
|
|
423
|
-
if (
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if (fiber.tag === getReactWorkTagsForFiber(fiber).SuspenseComponent) {
|
|
428
|
-
const isTimedOut = fiber.memoizedState !== null;
|
|
429
|
-
if (isTimedOut) {
|
|
430
|
-
// Special case: if Suspense mounts in a timed-out state,
|
|
431
|
-
// get the fallback child from the inner fragment and mount
|
|
432
|
-
// it as if it was our own child. Updates handle this too.
|
|
433
|
-
const primaryChildFragment = fiber.child;
|
|
434
|
-
const fallbackChildFragment = primaryChildFragment ? primaryChildFragment.sibling : null;
|
|
435
|
-
if (fallbackChildFragment) {
|
|
436
|
-
const fallbackChild = fallbackChildFragment.child;
|
|
437
|
-
if (fallbackChild !== null) {
|
|
438
|
-
mountFiberRecursively(onRender, fallbackChild, false);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
} else {
|
|
442
|
-
const primaryChild = fiber.child?.child ?? null;
|
|
443
|
-
if (primaryChild !== null) {
|
|
444
|
-
mountFiberRecursively(onRender, primaryChild, false);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
} else if (fiber.child !== null) {
|
|
448
|
-
mountFiberRecursively(onRender, fiber.child, true);
|
|
449
|
-
}
|
|
450
|
-
fiber = traverseSiblings ? fiber.sibling : null;
|
|
480
|
+
if (!shouldFilterFiber(fiber) && didFiberRender(fiber)) onRender(fiber, "mount");
|
|
481
|
+
if (traverseSiblings && fiber.sibling) pendingSiblings.push(fiber.sibling);
|
|
482
|
+
fiber = getRenderedChild(fiber, true) ?? pendingSiblings.pop() ?? null;
|
|
483
|
+
traverseSiblings = true;
|
|
451
484
|
}
|
|
452
485
|
};
|
|
453
486
|
|
|
454
|
-
|
|
487
|
+
interface FiberUpdate {
|
|
488
|
+
fiber: Fiber;
|
|
489
|
+
previousFiber: Fiber | null;
|
|
490
|
+
traverseSiblings: boolean;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const updateFiberTree = (
|
|
455
494
|
onRender: RenderHandler,
|
|
456
495
|
nextFiber: Fiber,
|
|
457
496
|
prevFiber: Fiber | null,
|
|
458
497
|
): void => {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
// The easiest fix is to strip out the intermediate Fragment fibers,
|
|
476
|
-
// so the Elements panel and Profiler don't need to special case them.
|
|
477
|
-
// Suspense components only have a non-null memoizedState if they're timed-out.
|
|
478
|
-
const prevDidTimeout = isSuspense && prevFiber.memoizedState !== null;
|
|
479
|
-
const nextDidTimeOut = isSuspense && nextFiber.memoizedState !== null;
|
|
480
|
-
|
|
481
|
-
// The logic below is inspired by the code paths in updateSuspenseComponent()
|
|
482
|
-
// inside ReactFiberBeginWork in the React source code.
|
|
483
|
-
if (prevDidTimeout && nextDidTimeOut) {
|
|
484
|
-
// Fallback -> Fallback:
|
|
485
|
-
// 1. Reconcile fallback set.
|
|
486
|
-
const nextFallbackChildSet = nextFiber.child?.sibling ?? null;
|
|
487
|
-
// Note: We can't use nextFiber.child.sibling.alternate
|
|
488
|
-
// because the set is special and alternate may not exist.
|
|
489
|
-
const prevFallbackChildSet = prevFiber.child?.sibling ?? null;
|
|
490
|
-
|
|
491
|
-
if (nextFallbackChildSet !== null && prevFallbackChildSet !== null) {
|
|
492
|
-
updateFiberRecursively(onRender, nextFallbackChildSet, prevFallbackChildSet);
|
|
493
|
-
}
|
|
494
|
-
} else if (prevDidTimeout && !nextDidTimeOut) {
|
|
495
|
-
// Fallback -> Primary:
|
|
496
|
-
// 1. Unmount fallback set
|
|
497
|
-
// Note: don't emulate fallback unmount because React actually did it.
|
|
498
|
-
// 2. Mount primary set
|
|
499
|
-
const nextPrimaryChildSet = nextFiber.child;
|
|
500
|
-
|
|
501
|
-
if (nextPrimaryChildSet !== null) {
|
|
502
|
-
mountFiberRecursively(onRender, nextPrimaryChildSet, true);
|
|
498
|
+
if (!prevFiber) {
|
|
499
|
+
getFiberId(nextFiber);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
const pendingUpdates: FiberUpdate[] = [
|
|
503
|
+
{ fiber: nextFiber, previousFiber: prevFiber, traverseSiblings: false },
|
|
504
|
+
];
|
|
505
|
+
let update: FiberUpdate | undefined;
|
|
506
|
+
while ((update = pendingUpdates.pop())) {
|
|
507
|
+
const { fiber, previousFiber, traverseSiblings } = update;
|
|
508
|
+
if (traverseSiblings && fiber.sibling) {
|
|
509
|
+
pendingUpdates.push({
|
|
510
|
+
fiber: fiber.sibling,
|
|
511
|
+
previousFiber: fiber.sibling.alternate,
|
|
512
|
+
traverseSiblings: true,
|
|
513
|
+
});
|
|
503
514
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
// This is not a real unmount, so it won't get reported by React.
|
|
508
|
-
// We need to manually walk the previous tree and record unmounts.
|
|
509
|
-
unmountFiberChildrenRecursively(onRender, prevFiber);
|
|
510
|
-
|
|
511
|
-
// 2. Mount fallback set
|
|
512
|
-
const nextFallbackChildSet = nextFiber.child?.sibling ?? null;
|
|
513
|
-
|
|
514
|
-
if (nextFallbackChildSet !== null) {
|
|
515
|
-
mountFiberRecursively(onRender, nextFallbackChildSet, true);
|
|
515
|
+
if (!previousFiber) {
|
|
516
|
+
mountFiberTree(onRender, fiber, false);
|
|
517
|
+
continue;
|
|
516
518
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
} else {
|
|
533
|
-
mountFiberRecursively(onRender, nextChild, false);
|
|
519
|
+
getFiberId(fiber);
|
|
520
|
+
getFiberId(previousFiber);
|
|
521
|
+
if (!shouldFilterFiber(fiber) && didFiberRender(fiber)) onRender(fiber, "update");
|
|
522
|
+
const isSuspense = fiber.tag === getReactWorkTagsForFiber(fiber).SuspenseComponent;
|
|
523
|
+
const wasTimedOut = isSuspense && previousFiber.memoizedState !== null;
|
|
524
|
+
const isTimedOut = isSuspense && fiber.memoizedState !== null;
|
|
525
|
+
if (wasTimedOut && isTimedOut) {
|
|
526
|
+
const nextFallback = fiber.child?.sibling;
|
|
527
|
+
const previousFallback = previousFiber.child?.sibling;
|
|
528
|
+
if (nextFallback && previousFallback) {
|
|
529
|
+
pendingUpdates.push({
|
|
530
|
+
fiber: nextFallback,
|
|
531
|
+
previousFiber: previousFallback,
|
|
532
|
+
traverseSiblings: false,
|
|
533
|
+
});
|
|
534
534
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
535
|
+
} else if (wasTimedOut && !isTimedOut) {
|
|
536
|
+
if (fiber.child) mountFiberTree(onRender, fiber.child, true);
|
|
537
|
+
} else if (!wasTimedOut && isTimedOut) {
|
|
538
|
+
unmountFiberChildren(onRender, previousFiber);
|
|
539
|
+
const fallback = fiber.child?.sibling;
|
|
540
|
+
if (fallback) mountFiberTree(onRender, fallback, true);
|
|
541
|
+
} else if (fiber.child && fiber.child !== previousFiber.child) {
|
|
542
|
+
pendingUpdates.push({
|
|
543
|
+
fiber: fiber.child,
|
|
544
|
+
previousFiber: fiber.child.alternate,
|
|
545
|
+
traverseSiblings: true,
|
|
546
|
+
});
|
|
538
547
|
}
|
|
539
548
|
}
|
|
540
549
|
};
|
|
@@ -547,30 +556,18 @@ const unmountFiber = (onRender: RenderHandler, fiber: Fiber): void => {
|
|
|
547
556
|
}
|
|
548
557
|
};
|
|
549
558
|
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
if (isTimedOutSuspense) {
|
|
557
|
-
// If it's showing fallback tree, let's traverse it instead.
|
|
558
|
-
const primaryChildFragment = fiber.child;
|
|
559
|
-
const fallbackChildFragment = primaryChildFragment?.sibling ?? null;
|
|
560
|
-
|
|
561
|
-
// Skip over to the real Fiber child.
|
|
562
|
-
child = fallbackChildFragment?.child ?? null;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
while (child !== null) {
|
|
566
|
-
// Record simulated unmounts children-first.
|
|
567
|
-
// We skip nodes without return because those are real unmounts.
|
|
559
|
+
const unmountFiberChildren = (onRender: RenderHandler, fiber: Fiber): void => {
|
|
560
|
+
const pendingSiblings: Fiber[] = [];
|
|
561
|
+
let child = getRenderedChild(fiber, false);
|
|
562
|
+
while (child) {
|
|
563
|
+
if (child.sibling) pendingSiblings.push(child.sibling);
|
|
568
564
|
if (child.return !== null) {
|
|
569
565
|
unmountFiber(onRender, child);
|
|
570
|
-
|
|
566
|
+
child = getRenderedChild(child, false);
|
|
567
|
+
} else {
|
|
568
|
+
child = null;
|
|
571
569
|
}
|
|
572
|
-
|
|
573
|
-
child = child.sibling;
|
|
570
|
+
child ??= pendingSiblings.pop() ?? null;
|
|
574
571
|
}
|
|
575
572
|
};
|
|
576
573
|
|
|
@@ -620,14 +617,14 @@ export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: Render
|
|
|
620
617
|
const isMounted = isRootFiberMounted(fiber);
|
|
621
618
|
|
|
622
619
|
if (!wasMounted && isMounted) {
|
|
623
|
-
|
|
620
|
+
mountFiberTree(onRender, fiber, false);
|
|
624
621
|
} else if (wasMounted && isMounted) {
|
|
625
|
-
|
|
622
|
+
updateFiberTree(onRender, fiber, fiber.alternate);
|
|
626
623
|
} else if (wasMounted && !isMounted) {
|
|
627
624
|
unmountFiber(onRender, fiber);
|
|
628
625
|
}
|
|
629
626
|
} else {
|
|
630
|
-
|
|
627
|
+
mountFiberTree(onRender, fiber, true);
|
|
631
628
|
}
|
|
632
629
|
|
|
633
630
|
rootInstance.prevFiber = fiber;
|
|
@@ -635,6 +632,7 @@ export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: Render
|
|
|
635
632
|
|
|
636
633
|
export interface InstrumentationOptions {
|
|
637
634
|
name?: string;
|
|
635
|
+
target?: ReactDevToolsTarget;
|
|
638
636
|
onActive?: () => unknown;
|
|
639
637
|
onCommitFiberRoot?: (
|
|
640
638
|
rendererID: number,
|
|
@@ -649,6 +647,7 @@ export interface InstrumentationOptions {
|
|
|
649
647
|
|
|
650
648
|
interface InstrumentationSubscription {
|
|
651
649
|
options: InstrumentationOptions;
|
|
650
|
+
target: ReactDevToolsTarget;
|
|
652
651
|
}
|
|
653
652
|
|
|
654
653
|
const instrumentationSubscriptions = new Set<InstrumentationSubscription>();
|
|
@@ -661,6 +660,7 @@ interface HookDispatchers {
|
|
|
661
660
|
}
|
|
662
661
|
|
|
663
662
|
const hookDispatchers = new WeakMap<ReactDevToolsGlobalHook, Partial<HookDispatchers>>();
|
|
663
|
+
const hookTargets = new WeakMap<ReactDevToolsGlobalHook, ReactDevToolsTarget>();
|
|
664
664
|
let didSubscribeToHookReplacements = false;
|
|
665
665
|
|
|
666
666
|
// each hook event is dispatched from a single re-installable wrapper. If
|
|
@@ -684,27 +684,24 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
684
684
|
didError,
|
|
685
685
|
) => {
|
|
686
686
|
if (prevOnCommitFiberRoot) {
|
|
687
|
-
prevOnCommitFiberRoot
|
|
687
|
+
callListener(prevOnCommitFiberRoot, rdtHook, rendererID, root, priority, didError);
|
|
688
688
|
}
|
|
689
689
|
if (hookDispatchers.get(rdtHook)?.onCommitFiberRoot !== dispatchCommitFiberRoot) return;
|
|
690
690
|
setReactWorkTagsForFiber(root.current, rdtHook.renderers.get(rendererID));
|
|
691
691
|
// Custom renderers and test harnesses commit roots without a memoizedState;
|
|
692
692
|
// those must stay tracked, so only explicit unmount evidence removes a root.
|
|
693
|
-
|
|
694
|
-
const isUnmounting =
|
|
695
|
-
rootMemoizedState === null ||
|
|
696
|
-
(rootMemoizedState !== undefined &&
|
|
697
|
-
(rootMemoizedState.element === null || rootMemoizedState.element === undefined));
|
|
698
|
-
if (isUnmounting) {
|
|
693
|
+
if (isFiberRootUnmounted(root)) {
|
|
699
694
|
_fiberRoots.delete(root);
|
|
700
695
|
rootRendererIds.delete(root);
|
|
696
|
+
rootHooks.delete(root);
|
|
701
697
|
} else {
|
|
702
698
|
_fiberRoots.add(root);
|
|
703
699
|
rootRendererIds.set(root, rendererID);
|
|
700
|
+
rootHooks.set(root, rdtHook);
|
|
704
701
|
}
|
|
705
|
-
for (const { options } of instrumentationSubscriptions) {
|
|
706
|
-
if (options.onCommitFiberRoot) {
|
|
707
|
-
options.onCommitFiberRoot
|
|
702
|
+
for (const { options, target } of instrumentationSubscriptions) {
|
|
703
|
+
if (target === hookTargets.get(rdtHook) && options.onCommitFiberRoot) {
|
|
704
|
+
callListener(options.onCommitFiberRoot, options, rendererID, root, priority, didError);
|
|
708
705
|
}
|
|
709
706
|
}
|
|
710
707
|
};
|
|
@@ -723,15 +720,19 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
723
720
|
) => {
|
|
724
721
|
setReactWorkTagsForFiber(fiber, rdtHook.renderers.get(rendererID));
|
|
725
722
|
if (prevOnCommitFiberUnmount) {
|
|
726
|
-
prevOnCommitFiberUnmount
|
|
723
|
+
callListener(prevOnCommitFiberUnmount, rdtHook, rendererID, fiber);
|
|
727
724
|
}
|
|
728
725
|
if (hookDispatchers.get(rdtHook)?.onCommitFiberUnmount !== dispatchCommitFiberUnmount) {
|
|
729
726
|
return;
|
|
730
727
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
options.onCommitFiberUnmount
|
|
728
|
+
try {
|
|
729
|
+
for (const { options, target } of instrumentationSubscriptions) {
|
|
730
|
+
if (target === hookTargets.get(rdtHook) && options.onCommitFiberUnmount) {
|
|
731
|
+
callListener(options.onCommitFiberUnmount, options, rendererID, fiber);
|
|
732
|
+
}
|
|
734
733
|
}
|
|
734
|
+
} finally {
|
|
735
|
+
releaseFiberId(fiber);
|
|
735
736
|
}
|
|
736
737
|
};
|
|
737
738
|
dispatchers.onCommitFiberUnmount = dispatchCommitFiberUnmount;
|
|
@@ -748,14 +749,14 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
748
749
|
root,
|
|
749
750
|
) => {
|
|
750
751
|
if (prevOnPostCommitFiberRoot) {
|
|
751
|
-
prevOnPostCommitFiberRoot
|
|
752
|
+
callListener(prevOnPostCommitFiberRoot, rdtHook, rendererID, root);
|
|
752
753
|
}
|
|
753
754
|
if (hookDispatchers.get(rdtHook)?.onPostCommitFiberRoot !== dispatchPostCommitFiberRoot) {
|
|
754
755
|
return;
|
|
755
756
|
}
|
|
756
|
-
for (const { options } of instrumentationSubscriptions) {
|
|
757
|
-
if (options.onPostCommitFiberRoot) {
|
|
758
|
-
options.onPostCommitFiberRoot
|
|
757
|
+
for (const { options, target } of instrumentationSubscriptions) {
|
|
758
|
+
if (target === hookTargets.get(rdtHook) && options.onPostCommitFiberRoot) {
|
|
759
|
+
callListener(options.onPostCommitFiberRoot, options, rendererID, root);
|
|
759
760
|
}
|
|
760
761
|
}
|
|
761
762
|
};
|
|
@@ -774,12 +775,12 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
774
775
|
children,
|
|
775
776
|
) => {
|
|
776
777
|
if (prevOnScheduleFiberRoot) {
|
|
777
|
-
prevOnScheduleFiberRoot
|
|
778
|
+
callListener(prevOnScheduleFiberRoot, rdtHook, rendererID, root, children);
|
|
778
779
|
}
|
|
779
780
|
if (hookDispatchers.get(rdtHook)?.onScheduleFiberRoot !== dispatchScheduleFiberRoot) return;
|
|
780
|
-
for (const { options } of instrumentationSubscriptions) {
|
|
781
|
-
if (options.onScheduleFiberRoot) {
|
|
782
|
-
options.onScheduleFiberRoot
|
|
781
|
+
for (const { options, target } of instrumentationSubscriptions) {
|
|
782
|
+
if (target === hookTargets.get(rdtHook) && options.onScheduleFiberRoot) {
|
|
783
|
+
callListener(options.onScheduleFiberRoot, options, rendererID, root, children);
|
|
783
784
|
}
|
|
784
785
|
}
|
|
785
786
|
};
|
|
@@ -788,11 +789,23 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
788
789
|
}
|
|
789
790
|
};
|
|
790
791
|
|
|
791
|
-
const
|
|
792
|
+
const handleHookReplacement = (
|
|
793
|
+
rdtHook: ReactDevToolsGlobalHook,
|
|
794
|
+
target: ReactDevToolsTarget,
|
|
795
|
+
): void => {
|
|
796
|
+
hookTargets.set(rdtHook, target);
|
|
797
|
+
setHookEventDispatchers(rdtHook);
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
const wireHookEventDispatchers = (
|
|
801
|
+
rdtHook: ReactDevToolsGlobalHook,
|
|
802
|
+
target: ReactDevToolsTarget = globalThis,
|
|
803
|
+
): void => {
|
|
792
804
|
if (!didSubscribeToHookReplacements) {
|
|
793
|
-
onRDTHookReplace(
|
|
805
|
+
onRDTHookReplace(handleHookReplacement);
|
|
794
806
|
didSubscribeToHookReplacements = true;
|
|
795
807
|
}
|
|
808
|
+
hookTargets.set(rdtHook, target);
|
|
796
809
|
setHookEventDispatchers(rdtHook);
|
|
797
810
|
};
|
|
798
811
|
|
|
@@ -822,15 +835,16 @@ try {
|
|
|
822
835
|
* unsubscribe();
|
|
823
836
|
*/
|
|
824
837
|
export const instrument = (options: InstrumentationOptions): Unsubscribe => {
|
|
825
|
-
const
|
|
838
|
+
const target = options.target ?? globalThis;
|
|
839
|
+
const rdtHook = getRDTHook(options.onActive, target);
|
|
826
840
|
rdtHook._instrumentationSource = options.name ?? BIPPY_INSTRUMENTATION_STRING;
|
|
827
841
|
|
|
828
|
-
wireHookEventDispatchers(rdtHook);
|
|
829
|
-
const subscription: InstrumentationSubscription = { options };
|
|
842
|
+
wireHookEventDispatchers(rdtHook, target);
|
|
843
|
+
const subscription: InstrumentationSubscription = { options, target };
|
|
830
844
|
instrumentationSubscriptions.add(subscription);
|
|
831
845
|
|
|
832
846
|
return createUnsubscribe(() => {
|
|
833
|
-
if (options.onActive)
|
|
847
|
+
if (options.onActive) removeActiveListener(options.onActive, target);
|
|
834
848
|
instrumentationSubscriptions.delete(subscription);
|
|
835
849
|
});
|
|
836
850
|
};
|
|
@@ -874,9 +888,12 @@ const getPublicHostInstance = (stateNode: unknown): unknown => {
|
|
|
874
888
|
return typeof nativeTag === "number" ? nativeTag : stateNode;
|
|
875
889
|
};
|
|
876
890
|
|
|
877
|
-
export const getFiber = <
|
|
878
|
-
|
|
879
|
-
|
|
891
|
+
export const getFiber = <HostInstance>(
|
|
892
|
+
hostInstance: HostInstance,
|
|
893
|
+
target: ReactDevToolsTarget = globalThis,
|
|
894
|
+
): Fiber | null => {
|
|
895
|
+
const rdtHook = target.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
896
|
+
if (rdtHook) {
|
|
880
897
|
for (const renderer of rdtHook.renderers.values()) {
|
|
881
898
|
try {
|
|
882
899
|
const fiber = renderer.findFiberByHostInstance?.(hostInstance);
|
|
@@ -899,19 +916,31 @@ export const getFiber = <T>(hostInstance: T): Fiber | null => {
|
|
|
899
916
|
|
|
900
917
|
for (const key of Object.keys(hostInstance)) {
|
|
901
918
|
if (isFiberPropertyKey(key)) {
|
|
902
|
-
knownFiberPropertyKeys.add(key);
|
|
903
919
|
const fiber = Reflect.get(hostInstance, key);
|
|
904
|
-
if (isFiber(fiber))
|
|
920
|
+
if (isFiber(fiber)) {
|
|
921
|
+
knownFiberPropertyKeys.add(key);
|
|
922
|
+
return fiber;
|
|
923
|
+
}
|
|
905
924
|
}
|
|
906
925
|
}
|
|
907
926
|
}
|
|
908
927
|
|
|
909
928
|
if (
|
|
910
929
|
hostInstance !== null &&
|
|
911
|
-
hostInstance !== undefined &&
|
|
912
930
|
(typeof hostInstance === "object" || typeof hostInstance === "number")
|
|
913
931
|
) {
|
|
932
|
+
const targetFiberRoots = new Set<FiberRoot>();
|
|
933
|
+
if (rdtHook?.getFiberRoots) {
|
|
934
|
+
for (const rendererId of rdtHook.renderers.keys()) {
|
|
935
|
+
for (const fiberRoot of rdtHook.getFiberRoots(rendererId)) {
|
|
936
|
+
targetFiberRoots.add(fiberRoot);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
914
940
|
for (const fiberRoot of _fiberRoots) {
|
|
941
|
+
if (rootHooks.get(fiberRoot) === rdtHook) targetFiberRoots.add(fiberRoot);
|
|
942
|
+
}
|
|
943
|
+
for (const fiberRoot of targetFiberRoots) {
|
|
915
944
|
const fiber = traverseFiber(
|
|
916
945
|
fiberRoot.current,
|
|
917
946
|
(candidateFiber) =>
|
|
@@ -928,16 +957,16 @@ export const getFiberFromHostInstance = getFiber;
|
|
|
928
957
|
|
|
929
958
|
export {
|
|
930
959
|
BIPPY_INSTRUMENTATION_STRING,
|
|
931
|
-
_onActiveListeners,
|
|
932
960
|
_renderers,
|
|
933
961
|
getRDTHook,
|
|
934
962
|
hasRDTHook,
|
|
935
963
|
installRDTHook,
|
|
964
|
+
isFiberRootUnmounted,
|
|
936
965
|
isReactRefresh,
|
|
937
966
|
isRealReactDevtools,
|
|
938
967
|
onRendererInject,
|
|
939
968
|
patchRDTHook,
|
|
940
969
|
version,
|
|
941
970
|
} from "./rdt-hook.js";
|
|
942
|
-
export type { Unsubscribe } from "./rdt-hook.js";
|
|
971
|
+
export type { ReactDevToolsTarget, Unsubscribe } from "./rdt-hook.js";
|
|
943
972
|
export * from "./react-internals/index.js";
|