bippy 0.6.1-dev.b88fcb4 → 0.6.1-dev.f9a65c0
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/README.md +211 -445
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +9 -59
- package/dist/core.d.ts +9 -59
- package/dist/core.js +1 -1
- package/dist/core2.cjs +1 -1
- package/dist/core2.d.cts +3 -3
- package/dist/core2.d.ts +3 -3
- package/dist/core2.js +1 -1
- package/dist/errors.d.cts +2 -57
- package/dist/errors.d.ts +2 -57
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- 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 +12 -13
- package/dist/source.d.cts +77 -78
- package/dist/source.d.ts +77 -78
- package/dist/source.js +12 -13
- package/package.json +6 -3
- package/src/core.ts +106 -545
- package/src/errors.ts +0 -65
- package/src/index.ts +1 -0
- package/src/install-hook-only.ts +2 -2
- package/src/rdt-hook.ts +30 -43
- package/src/react-internals/generated/react-work-tags.ts +6 -2
- package/src/react-internals/index.ts +4 -4
- package/src/react-internals/semver.ts +2 -0
- package/src/react-internals/types.ts +0 -83
- package/src/react.ts +76 -0
- package/src/source/get-display-name-from-source.ts +44 -40
- package/src/source/get-source.ts +40 -24
- package/src/source/index.ts +2 -0
- package/src/source/inspect-hooks.ts +70 -91
- package/src/source/owner-stack.ts +60 -89
- package/src/source/parse-hook-names.ts +14 -53
- package/src/source/parse-stack.ts +14 -31
- package/src/source/renderer-dispatchers.ts +30 -0
- package/src/source/symbolication.ts +312 -111
- package/dist/index.iife.js +0 -9
- package/dist/install-hook-only.iife.js +0 -9
package/src/core.ts
CHANGED
|
@@ -3,17 +3,13 @@
|
|
|
3
3
|
import type * as React from "react";
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
|
-
ContextDependency,
|
|
7
6
|
Fiber,
|
|
8
7
|
FiberRoot,
|
|
9
8
|
HostFiber,
|
|
10
|
-
MemoizedState,
|
|
11
9
|
ReactDevToolsGlobalHook,
|
|
12
10
|
ReactRenderer,
|
|
13
11
|
} from "./react-internals/index.js";
|
|
14
12
|
|
|
15
|
-
import { BippyInstrumentationError, BippyReactDevToolsError, runWithBippyError } from "./errors.js";
|
|
16
|
-
|
|
17
13
|
import {
|
|
18
14
|
_onActiveListeners,
|
|
19
15
|
BIPPY_INSTRUMENTATION_STRING,
|
|
@@ -22,7 +18,6 @@ import {
|
|
|
22
18
|
hasRDTHook,
|
|
23
19
|
isRealReactDevtools,
|
|
24
20
|
onRDTHookReplace,
|
|
25
|
-
onRendererInject,
|
|
26
21
|
} from "./rdt-hook.js";
|
|
27
22
|
import type { Unsubscribe } from "./rdt-hook.js";
|
|
28
23
|
import {
|
|
@@ -34,44 +29,21 @@ import {
|
|
|
34
29
|
setReactWorkTagsForFiber,
|
|
35
30
|
} from "./react-internals/index.js";
|
|
36
31
|
|
|
37
|
-
export { getReactWorkTags, ReactSymbols } from "./react-internals/index.js";
|
|
38
|
-
export type { ReactWorkTagMap, ReactWorkTagVersion } from "./react-internals/index.js";
|
|
39
32
|
export {
|
|
40
33
|
BippyError,
|
|
41
|
-
BippyHookInstallationError,
|
|
42
34
|
BippyHookInspectionError,
|
|
43
|
-
BippyHookListenerError,
|
|
44
35
|
BippyHookRenderError,
|
|
45
|
-
BippyInstrumentationError,
|
|
46
|
-
BippyReactBuildError,
|
|
47
|
-
BippyReactDevToolsError,
|
|
48
36
|
BippySourceMapError,
|
|
49
37
|
BippyUnsupportedHookError,
|
|
50
38
|
} from "./errors.js";
|
|
51
39
|
|
|
52
|
-
const isObjectRecord = (value: unknown): value is Record<string, unknown> =>
|
|
53
|
-
typeof value === "object" && value !== null;
|
|
54
|
-
|
|
55
40
|
const isComponentType = (value: unknown): value is React.ComponentType<unknown> =>
|
|
56
41
|
typeof value === "function";
|
|
57
42
|
|
|
58
|
-
const getPropertyValue = (value: object, key: PropertyKey): unknown => {
|
|
59
|
-
let currentValue: object | null = value;
|
|
60
|
-
while (currentValue) {
|
|
61
|
-
const descriptor = Object.getOwnPropertyDescriptor(currentValue, key);
|
|
62
|
-
if (descriptor) {
|
|
63
|
-
if ("value" in descriptor) return descriptor.value;
|
|
64
|
-
return descriptor.get?.call(value);
|
|
65
|
-
}
|
|
66
|
-
currentValue = Object.getPrototypeOf(currentValue);
|
|
67
|
-
}
|
|
68
|
-
return undefined;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
43
|
const getTypeName = (value: object): string | null => {
|
|
72
|
-
const displayName =
|
|
44
|
+
const displayName = "displayName" in value ? value.displayName : null;
|
|
73
45
|
if (typeof displayName === "string" && displayName) return displayName;
|
|
74
|
-
const name =
|
|
46
|
+
const name = "name" in value ? value.name : null;
|
|
75
47
|
return typeof name === "string" && name ? name : null;
|
|
76
48
|
};
|
|
77
49
|
|
|
@@ -79,18 +51,8 @@ interface FiberSelector {
|
|
|
79
51
|
(node: Fiber): boolean | Promise<boolean | void> | void;
|
|
80
52
|
}
|
|
81
53
|
|
|
82
|
-
export interface FiberTimings {
|
|
83
|
-
selfTime: number;
|
|
84
|
-
totalTime: number;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
54
|
export interface RenderHandler {
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
interface ValueWrite {
|
|
92
|
-
path: string[];
|
|
93
|
-
value: unknown;
|
|
55
|
+
(fiber: Fiber, phase: RenderPhase): unknown;
|
|
94
56
|
}
|
|
95
57
|
|
|
96
58
|
/**
|
|
@@ -108,7 +70,7 @@ export const isValidElement = (element: unknown): element is React.ReactElement
|
|
|
108
70
|
/**
|
|
109
71
|
* Returns `true` if object is a React Fiber.
|
|
110
72
|
*/
|
|
111
|
-
export const
|
|
73
|
+
export const isFiber = (fiber: unknown): fiber is Fiber =>
|
|
112
74
|
typeof fiber === "object" &&
|
|
113
75
|
fiber !== null &&
|
|
114
76
|
"tag" in fiber &&
|
|
@@ -119,7 +81,10 @@ export const isValidFiber = (fiber: unknown): fiber is Fiber =>
|
|
|
119
81
|
"flags" in fiber;
|
|
120
82
|
|
|
121
83
|
const isFiberRoot = (fiberRoot: unknown): fiberRoot is FiberRoot =>
|
|
122
|
-
|
|
84
|
+
typeof fiberRoot === "object" &&
|
|
85
|
+
fiberRoot !== null &&
|
|
86
|
+
"current" in fiberRoot &&
|
|
87
|
+
isFiber(fiberRoot.current);
|
|
123
88
|
|
|
124
89
|
/**
|
|
125
90
|
* Returns `true` if fiber is a host fiber. Host fibers are DOM nodes in react-dom, `View` in react-native, etc.
|
|
@@ -158,100 +123,6 @@ export const isCompositeFiber = (fiber: Fiber): boolean => {
|
|
|
158
123
|
}
|
|
159
124
|
};
|
|
160
125
|
|
|
161
|
-
/**
|
|
162
|
-
* Returns `true` if the object is a {@link Fiber}
|
|
163
|
-
*/
|
|
164
|
-
export const isFiber = (maybeFiber: unknown): maybeFiber is Fiber => {
|
|
165
|
-
if (!maybeFiber || typeof maybeFiber !== "object") return false;
|
|
166
|
-
// this is a fast check. pendingProps will ALWAYS exist in fiber
|
|
167
|
-
// `containerInfo` is in FiberRootNode, not FiberNode
|
|
168
|
-
return "pendingProps" in maybeFiber && !("containerInfo" in maybeFiber);
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Traverses up or down a {@link Fiber}'s contexts, return `true` to stop and select the current and previous context value.
|
|
173
|
-
*/
|
|
174
|
-
export const traverseContexts = (
|
|
175
|
-
fiber: Fiber,
|
|
176
|
-
selector: (
|
|
177
|
-
nextValue: ContextDependency<unknown> | null | undefined,
|
|
178
|
-
prevValue: ContextDependency<unknown> | null | undefined,
|
|
179
|
-
) => boolean | void,
|
|
180
|
-
): boolean => {
|
|
181
|
-
try {
|
|
182
|
-
const nextDependencies = fiber.dependencies;
|
|
183
|
-
const prevDependencies = fiber.alternate?.dependencies;
|
|
184
|
-
|
|
185
|
-
if (!nextDependencies || !prevDependencies) return false;
|
|
186
|
-
if (
|
|
187
|
-
typeof nextDependencies !== "object" ||
|
|
188
|
-
!("firstContext" in nextDependencies) ||
|
|
189
|
-
typeof prevDependencies !== "object" ||
|
|
190
|
-
!("firstContext" in prevDependencies)
|
|
191
|
-
) {
|
|
192
|
-
return false;
|
|
193
|
-
}
|
|
194
|
-
let nextContext: ContextDependency<unknown> | null | undefined = nextDependencies.firstContext;
|
|
195
|
-
let prevContext: ContextDependency<unknown> | null | undefined = prevDependencies.firstContext;
|
|
196
|
-
while (
|
|
197
|
-
(nextContext && typeof nextContext === "object" && "memoizedValue" in nextContext) ||
|
|
198
|
-
(prevContext && typeof prevContext === "object" && "memoizedValue" in prevContext)
|
|
199
|
-
) {
|
|
200
|
-
if (selector(nextContext, prevContext) === true) return true;
|
|
201
|
-
|
|
202
|
-
nextContext = nextContext?.next;
|
|
203
|
-
prevContext = prevContext?.next;
|
|
204
|
-
}
|
|
205
|
-
} catch {}
|
|
206
|
-
return false;
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Traverses up or down a {@link Fiber}'s states, return `true` to stop and select the current and previous state value. This stores both state values and effects.
|
|
211
|
-
*/
|
|
212
|
-
export const traverseState = (
|
|
213
|
-
fiber: Fiber,
|
|
214
|
-
selector: (
|
|
215
|
-
nextValue: MemoizedState | null | undefined,
|
|
216
|
-
prevValue: MemoizedState | null | undefined,
|
|
217
|
-
) => boolean | void,
|
|
218
|
-
): boolean => {
|
|
219
|
-
try {
|
|
220
|
-
let nextState: MemoizedState | null | undefined = fiber.memoizedState;
|
|
221
|
-
let prevState: MemoizedState | null | undefined = fiber.alternate?.memoizedState;
|
|
222
|
-
|
|
223
|
-
while (nextState || prevState) {
|
|
224
|
-
if (selector(nextState, prevState) === true) return true;
|
|
225
|
-
|
|
226
|
-
nextState = nextState?.next;
|
|
227
|
-
prevState = prevState?.next;
|
|
228
|
-
}
|
|
229
|
-
} catch {}
|
|
230
|
-
return false;
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Traverses up or down a {@link Fiber}'s props, return `true` to stop and select the current and previous props value.
|
|
235
|
-
*/
|
|
236
|
-
export const traverseProps = (
|
|
237
|
-
fiber: Fiber,
|
|
238
|
-
selector: (propName: string, nextValue: unknown, prevValue: unknown) => boolean | void,
|
|
239
|
-
): boolean => {
|
|
240
|
-
try {
|
|
241
|
-
const nextProps = fiber.memoizedProps;
|
|
242
|
-
const prevProps = fiber.alternate?.memoizedProps || {};
|
|
243
|
-
|
|
244
|
-
for (const propName of Object.keys(nextProps)) {
|
|
245
|
-
if (selector(propName, nextProps[propName], prevProps[propName]) === true) return true;
|
|
246
|
-
}
|
|
247
|
-
for (const propName of Object.keys(prevProps)) {
|
|
248
|
-
if (propName in nextProps) continue;
|
|
249
|
-
if (selector(propName, nextProps[propName], prevProps[propName]) === true) return true;
|
|
250
|
-
}
|
|
251
|
-
} catch {}
|
|
252
|
-
return false;
|
|
253
|
-
};
|
|
254
|
-
|
|
255
126
|
/**
|
|
256
127
|
* Returns `true` if the {@link Fiber} has rendered. Note that this does not mean the fiber has rendered in the current commit, just that it has rendered in the past.
|
|
257
128
|
*/
|
|
@@ -291,47 +162,6 @@ export const didFiberCommit = (fiber: Fiber): boolean => {
|
|
|
291
162
|
);
|
|
292
163
|
};
|
|
293
164
|
|
|
294
|
-
/**
|
|
295
|
-
* Returns all host {@link Fiber}s that have committed and rendered.
|
|
296
|
-
*/
|
|
297
|
-
export const getMutatedHostFibers = (fiber: Fiber): Fiber[] => {
|
|
298
|
-
const mutations: Fiber[] = [];
|
|
299
|
-
const stack: Fiber[] = [fiber];
|
|
300
|
-
|
|
301
|
-
while (stack.length) {
|
|
302
|
-
const node = stack.pop();
|
|
303
|
-
if (!node) continue;
|
|
304
|
-
|
|
305
|
-
if (isHostFiber(node) && didFiberCommit(node) && didFiberRender(node)) {
|
|
306
|
-
mutations.push(node);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (node.child) stack.push(node.child);
|
|
310
|
-
if (node.sibling) stack.push(node.sibling);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return mutations;
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Returns the stack of {@link Fiber}s from the current fiber to the root fiber.
|
|
318
|
-
*
|
|
319
|
-
* @example
|
|
320
|
-
* ```ts
|
|
321
|
-
* [fiber, fiber.return, fiber.return.return, ...]
|
|
322
|
-
* ```
|
|
323
|
-
*/
|
|
324
|
-
export const getFiberStack = (fiber: Fiber): Fiber[] => {
|
|
325
|
-
const stack: Fiber[] = [];
|
|
326
|
-
let currentFiber = fiber;
|
|
327
|
-
while (currentFiber.return) {
|
|
328
|
-
stack.push(currentFiber);
|
|
329
|
-
const parentFiber = currentFiber.return;
|
|
330
|
-
currentFiber = parentFiber;
|
|
331
|
-
}
|
|
332
|
-
return stack;
|
|
333
|
-
};
|
|
334
|
-
|
|
335
165
|
/**
|
|
336
166
|
* Returns `true` if the {@link Fiber} should be filtered out during reconciliation.
|
|
337
167
|
*/
|
|
@@ -380,47 +210,6 @@ const shouldFilterFiber = (fiber: Fiber): boolean => {
|
|
|
380
210
|
}
|
|
381
211
|
};
|
|
382
212
|
|
|
383
|
-
/**
|
|
384
|
-
* Returns the nearest host {@link Fiber} to the current {@link Fiber}.
|
|
385
|
-
*/
|
|
386
|
-
export const getNearestHostFiber = (fiber: Fiber, ascending = false): Fiber | null => {
|
|
387
|
-
let hostFiber = traverseFiber(fiber, isHostFiber, ascending);
|
|
388
|
-
if (!hostFiber) {
|
|
389
|
-
hostFiber = traverseFiber(fiber, isHostFiber, !ascending);
|
|
390
|
-
}
|
|
391
|
-
return hostFiber;
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Returns all host {@link Fiber}s in the tree that are associated with the current {@link Fiber}.
|
|
396
|
-
*/
|
|
397
|
-
export const getNearestHostFibers = (fiber: Fiber): Fiber[] => {
|
|
398
|
-
const hostFibers: Fiber[] = [];
|
|
399
|
-
const stack: Fiber[] = [];
|
|
400
|
-
|
|
401
|
-
if (isHostFiber(fiber)) {
|
|
402
|
-
hostFibers.push(fiber);
|
|
403
|
-
} else if (fiber.child) {
|
|
404
|
-
stack.push(fiber.child);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
while (stack.length) {
|
|
408
|
-
const currentNode = stack.pop();
|
|
409
|
-
if (!currentNode) break;
|
|
410
|
-
if (isHostFiber(currentNode)) {
|
|
411
|
-
hostFibers.push(currentNode);
|
|
412
|
-
} else if (currentNode.child) {
|
|
413
|
-
stack.push(currentNode.child);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (currentNode.sibling) {
|
|
417
|
-
stack.push(currentNode.sibling);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
return hostFibers;
|
|
422
|
-
};
|
|
423
|
-
|
|
424
213
|
/**
|
|
425
214
|
* Traverses up or down a {@link Fiber}, return `true` to stop and select a node.
|
|
426
215
|
*/
|
|
@@ -444,7 +233,17 @@ export function traverseFiber(
|
|
|
444
233
|
selector: FiberSelector,
|
|
445
234
|
ascending = false,
|
|
446
235
|
): Fiber | null | Promise<Fiber | null> {
|
|
447
|
-
|
|
236
|
+
if (!fiber) return null;
|
|
237
|
+
|
|
238
|
+
const selection = selector(fiber);
|
|
239
|
+
if (isPromiseLike<boolean | void>(selection)) {
|
|
240
|
+
return Promise.resolve(selection).then((didSelectFiber) =>
|
|
241
|
+
didSelectFiber === true ? fiber : traverseFiberChildren(fiber, selector, ascending),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
if (selection === true) return fiber;
|
|
245
|
+
|
|
246
|
+
return traverseFiberChildren(fiber, selector, ascending);
|
|
448
247
|
}
|
|
449
248
|
|
|
450
249
|
const isPromiseLike = <Result>(value: unknown): value is PromiseLike<Result> =>
|
|
@@ -470,7 +269,7 @@ const traverseFiberSiblings = (
|
|
|
470
269
|
if (!fiber) return null;
|
|
471
270
|
|
|
472
271
|
const nextSibling = ascending ? null : fiber.sibling;
|
|
473
|
-
const match =
|
|
272
|
+
const match = traverseFiber(fiber, selector, ascending);
|
|
474
273
|
if (isPromiseLike<Fiber | null>(match)) {
|
|
475
274
|
return Promise.resolve(match).then(
|
|
476
275
|
(resolvedMatch) => resolvedMatch ?? traverseFiberSiblings(nextSibling, selector, ascending),
|
|
@@ -479,45 +278,6 @@ const traverseFiberSiblings = (
|
|
|
479
278
|
return match ?? traverseFiberSiblings(nextSibling, selector, ascending);
|
|
480
279
|
};
|
|
481
280
|
|
|
482
|
-
const traverseFiberInternal = (
|
|
483
|
-
fiber: Fiber | null,
|
|
484
|
-
selector: FiberSelector,
|
|
485
|
-
ascending: boolean,
|
|
486
|
-
): Fiber | null | Promise<Fiber | null> => {
|
|
487
|
-
if (!fiber) return null;
|
|
488
|
-
|
|
489
|
-
const selection = selector(fiber);
|
|
490
|
-
if (isPromiseLike<boolean | void>(selection)) {
|
|
491
|
-
return Promise.resolve(selection).then((didSelectFiber) =>
|
|
492
|
-
didSelectFiber === true ? fiber : traverseFiberChildren(fiber, selector, ascending),
|
|
493
|
-
);
|
|
494
|
-
}
|
|
495
|
-
if (selection === true) return fiber;
|
|
496
|
-
|
|
497
|
-
return traverseFiberChildren(fiber, selector, ascending);
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
/**
|
|
501
|
-
* Returns the timings of the {@link Fiber}.
|
|
502
|
-
*
|
|
503
|
-
* @example
|
|
504
|
-
* ```ts
|
|
505
|
-
* const { selfTime, totalTime } = getTimings(fiber);
|
|
506
|
-
* console.log(selfTime, totalTime);
|
|
507
|
-
* ```
|
|
508
|
-
*/
|
|
509
|
-
export const getTimings = (fiber?: Fiber | null): FiberTimings => {
|
|
510
|
-
const totalTime = fiber?.actualDuration ?? 0;
|
|
511
|
-
let selfTime = totalTime;
|
|
512
|
-
// TODO: calculate a DOM time, which is just host component summed up
|
|
513
|
-
let child = fiber?.child ?? null;
|
|
514
|
-
while (totalTime > 0 && child !== null) {
|
|
515
|
-
selfTime -= child.actualDuration ?? 0;
|
|
516
|
-
child = child.sibling;
|
|
517
|
-
}
|
|
518
|
-
return { selfTime, totalTime };
|
|
519
|
-
};
|
|
520
|
-
|
|
521
281
|
/**
|
|
522
282
|
* Returns `true` if the {@link Fiber} uses React Compiler's memo cache.
|
|
523
283
|
*/
|
|
@@ -530,8 +290,8 @@ export const hasMemoCache = (fiber: Fiber): boolean => {
|
|
|
530
290
|
*/
|
|
531
291
|
export const getType = (type: unknown): null | React.ComponentType<unknown> => {
|
|
532
292
|
if (isComponentType(type)) return type;
|
|
533
|
-
if (
|
|
534
|
-
return getType(
|
|
293
|
+
if (typeof type !== "object" || type === null) return null;
|
|
294
|
+
return getType(Reflect.get(type, "type") ?? Reflect.get(type, "render"));
|
|
535
295
|
};
|
|
536
296
|
|
|
537
297
|
/**
|
|
@@ -571,6 +331,7 @@ export const isInstrumentationActive = (): boolean => {
|
|
|
571
331
|
};
|
|
572
332
|
|
|
573
333
|
export const _fiberRoots = new Set<FiberRoot>();
|
|
334
|
+
const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
574
335
|
|
|
575
336
|
/**
|
|
576
337
|
* Returns the latest fiber (since it may be double-buffered).
|
|
@@ -590,6 +351,25 @@ export const getLatestFiber = (fiber: Fiber): Fiber => {
|
|
|
590
351
|
return fiber;
|
|
591
352
|
};
|
|
592
353
|
|
|
354
|
+
/**
|
|
355
|
+
* Returns the renderer that owns the {@link Fiber}.
|
|
356
|
+
*/
|
|
357
|
+
export const getRenderer = (fiber: Fiber): ReactRenderer | null => {
|
|
358
|
+
if (!hasRDTHook()) return null;
|
|
359
|
+
|
|
360
|
+
let rootFiber = fiber;
|
|
361
|
+
while (rootFiber.return) {
|
|
362
|
+
rootFiber = rootFiber.return;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const fiberRoot = rootFiber.stateNode;
|
|
366
|
+
if (!isFiberRoot(fiberRoot)) return null;
|
|
367
|
+
|
|
368
|
+
const rendererID = rootRendererIds.get(fiberRoot);
|
|
369
|
+
if (rendererID === undefined) return null;
|
|
370
|
+
return getRDTHook().renderers.get(rendererID) ?? null;
|
|
371
|
+
};
|
|
372
|
+
|
|
593
373
|
export type RenderPhase = "mount" | "unmount" | "update";
|
|
594
374
|
|
|
595
375
|
let nextFiberId = 0;
|
|
@@ -622,9 +402,7 @@ const mountFiberRecursively = (
|
|
|
622
402
|
let fiber: Fiber | null = firstChild;
|
|
623
403
|
|
|
624
404
|
while (fiber !== null) {
|
|
625
|
-
|
|
626
|
-
getFiberId(fiber);
|
|
627
|
-
}
|
|
405
|
+
getFiberId(fiber);
|
|
628
406
|
const shouldIncludeInTree = !shouldFilterFiber(fiber);
|
|
629
407
|
if (shouldIncludeInTree && didFiberRender(fiber)) {
|
|
630
408
|
onRender(fiber, "mount");
|
|
@@ -661,15 +439,10 @@ const updateFiberRecursively = (
|
|
|
661
439
|
onRender: RenderHandler,
|
|
662
440
|
nextFiber: Fiber,
|
|
663
441
|
prevFiber: Fiber | null,
|
|
664
|
-
parentFiber: Fiber | null,
|
|
665
442
|
): void => {
|
|
666
|
-
|
|
667
|
-
getFiberId(nextFiber);
|
|
668
|
-
}
|
|
443
|
+
getFiberId(nextFiber);
|
|
669
444
|
if (!prevFiber) return;
|
|
670
|
-
|
|
671
|
-
getFiberId(prevFiber);
|
|
672
|
-
}
|
|
445
|
+
getFiberId(prevFiber);
|
|
673
446
|
|
|
674
447
|
const isSuspense = nextFiber.tag === getReactWorkTagsForFiber(nextFiber).SuspenseComponent;
|
|
675
448
|
|
|
@@ -700,7 +473,7 @@ const updateFiberRecursively = (
|
|
|
700
473
|
const prevFallbackChildSet = prevFiber.child?.sibling ?? null;
|
|
701
474
|
|
|
702
475
|
if (nextFallbackChildSet !== null && prevFallbackChildSet !== null) {
|
|
703
|
-
updateFiberRecursively(onRender, nextFallbackChildSet, prevFallbackChildSet
|
|
476
|
+
updateFiberRecursively(onRender, nextFallbackChildSet, prevFallbackChildSet);
|
|
704
477
|
}
|
|
705
478
|
} else if (prevDidTimeout && !nextDidTimeOut) {
|
|
706
479
|
// Fallback -> Primary:
|
|
@@ -739,14 +512,7 @@ const updateFiberRecursively = (
|
|
|
739
512
|
// Schedule updates and mounts depending on whether alternates exist.
|
|
740
513
|
// We don't track deletions here because they are reported separately.
|
|
741
514
|
if (nextChild.alternate) {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
updateFiberRecursively(
|
|
745
|
-
onRender,
|
|
746
|
-
nextChild,
|
|
747
|
-
prevChild,
|
|
748
|
-
shouldIncludeInTree ? nextFiber : parentFiber,
|
|
749
|
-
);
|
|
515
|
+
updateFiberRecursively(onRender, nextChild, nextChild.alternate);
|
|
750
516
|
} else {
|
|
751
517
|
mountFiberRecursively(onRender, nextChild, false);
|
|
752
518
|
}
|
|
@@ -792,11 +558,9 @@ const unmountFiberChildrenRecursively = (onRender: RenderHandler, fiber: Fiber):
|
|
|
792
558
|
}
|
|
793
559
|
};
|
|
794
560
|
|
|
795
|
-
let commitId = 0;
|
|
796
561
|
const rootInstanceMap = new WeakMap<
|
|
797
562
|
Fiber | FiberRoot,
|
|
798
563
|
{
|
|
799
|
-
id: number;
|
|
800
564
|
prevFiber: Fiber | null;
|
|
801
565
|
}
|
|
802
566
|
>();
|
|
@@ -814,17 +578,17 @@ export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: Render
|
|
|
814
578
|
let rootInstance = rootInstanceMap.get(root);
|
|
815
579
|
|
|
816
580
|
if (!rootInstance) {
|
|
817
|
-
rootInstance = {
|
|
581
|
+
rootInstance = { prevFiber: null };
|
|
818
582
|
rootInstanceMap.set(root, rootInstance);
|
|
819
583
|
}
|
|
820
584
|
|
|
821
585
|
const { prevFiber } = rootInstance;
|
|
822
|
-
// if fiberRoot don't have current instance, means it's been unmounted
|
|
823
586
|
if (!fiber) {
|
|
824
|
-
|
|
587
|
+
if (prevFiber) {
|
|
588
|
+
unmountFiber(onRender, prevFiber);
|
|
589
|
+
}
|
|
825
590
|
} else if (prevFiber !== null) {
|
|
826
591
|
const wasMounted =
|
|
827
|
-
prevFiber &&
|
|
828
592
|
prevFiber.memoizedState !== null &&
|
|
829
593
|
prevFiber.memoizedState.element !== null &&
|
|
830
594
|
prevFiber.memoizedState.element !== undefined &&
|
|
@@ -840,7 +604,7 @@ export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: Render
|
|
|
840
604
|
if (!wasMounted && isMounted) {
|
|
841
605
|
mountFiberRecursively(onRender, fiber, false);
|
|
842
606
|
} else if (wasMounted && isMounted) {
|
|
843
|
-
updateFiberRecursively(onRender, fiber, fiber.alternate
|
|
607
|
+
updateFiberRecursively(onRender, fiber, fiber.alternate);
|
|
844
608
|
} else if (wasMounted && !isMounted) {
|
|
845
609
|
unmountFiber(onRender, fiber);
|
|
846
610
|
}
|
|
@@ -851,171 +615,6 @@ export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: Render
|
|
|
851
615
|
rootInstance.prevFiber = fiber;
|
|
852
616
|
};
|
|
853
617
|
|
|
854
|
-
const overrideRenderers = new Set<ReactRenderer>();
|
|
855
|
-
let areOverrideRenderersWired = false;
|
|
856
|
-
|
|
857
|
-
const wireOverrideRenderers = (): void => {
|
|
858
|
-
if (!hasRDTHook()) return;
|
|
859
|
-
const rdtHook = getRDTHook();
|
|
860
|
-
|
|
861
|
-
setHookEventDispatchers(rdtHook);
|
|
862
|
-
for (const renderer of rdtHook.renderers.values()) {
|
|
863
|
-
overrideRenderers.add(renderer);
|
|
864
|
-
}
|
|
865
|
-
if (areOverrideRenderersWired) return;
|
|
866
|
-
areOverrideRenderersWired = true;
|
|
867
|
-
onRendererInject((renderer) => {
|
|
868
|
-
overrideRenderers.add(renderer);
|
|
869
|
-
});
|
|
870
|
-
};
|
|
871
|
-
|
|
872
|
-
const getRootRenderer = (fiber: Fiber): ReactRenderer | null => {
|
|
873
|
-
if (!hasRDTHook()) return null;
|
|
874
|
-
let hostRootFiber = fiber;
|
|
875
|
-
while (hostRootFiber.return) {
|
|
876
|
-
hostRootFiber = hostRootFiber.return;
|
|
877
|
-
}
|
|
878
|
-
const fiberRoot = hostRootFiber.stateNode;
|
|
879
|
-
if (!isFiberRoot(fiberRoot)) return null;
|
|
880
|
-
const rendererId = rootRendererIds.get(fiberRoot);
|
|
881
|
-
if (rendererId === undefined) return null;
|
|
882
|
-
return getRDTHook().renderers.get(rendererId) ?? null;
|
|
883
|
-
};
|
|
884
|
-
|
|
885
|
-
const resolveOverrideRenderers = (fiber: Fiber): ReactRenderer[] => {
|
|
886
|
-
wireOverrideRenderers();
|
|
887
|
-
const rootRenderer = getRootRenderer(fiber);
|
|
888
|
-
if (rootRenderer) return [rootRenderer];
|
|
889
|
-
return Array.from(overrideRenderers);
|
|
890
|
-
};
|
|
891
|
-
|
|
892
|
-
const applyPropsOverride = (
|
|
893
|
-
renderers: ReactRenderer[],
|
|
894
|
-
fiber: Fiber,
|
|
895
|
-
path: string[],
|
|
896
|
-
value: unknown,
|
|
897
|
-
): void => {
|
|
898
|
-
for (const renderer of renderers) {
|
|
899
|
-
try {
|
|
900
|
-
renderer.overrideProps?.(fiber, path, value);
|
|
901
|
-
} catch {}
|
|
902
|
-
}
|
|
903
|
-
};
|
|
904
|
-
|
|
905
|
-
const getHookStateDispatch = (
|
|
906
|
-
fiber: Fiber,
|
|
907
|
-
hookIndex: number,
|
|
908
|
-
): ((value: unknown) => void) | null => {
|
|
909
|
-
let hookState = fiber.memoizedState;
|
|
910
|
-
for (let currentHookIndex = 0; currentHookIndex < hookIndex; currentHookIndex++) {
|
|
911
|
-
if (!hookState?.next) return null;
|
|
912
|
-
hookState = hookState.next;
|
|
913
|
-
}
|
|
914
|
-
const queue = hookState?.queue;
|
|
915
|
-
if (!isPOJO(queue)) return null;
|
|
916
|
-
const dispatch = queue.dispatch;
|
|
917
|
-
return typeof dispatch === "function" ? (value) => dispatch(value) : null;
|
|
918
|
-
};
|
|
919
|
-
|
|
920
|
-
const findContextProviderFiber = (fiber: Fiber, contextType: unknown): Fiber | null => {
|
|
921
|
-
let currentFiber: Fiber | null = fiber;
|
|
922
|
-
while (currentFiber) {
|
|
923
|
-
const fiberType = currentFiber.type;
|
|
924
|
-
if (fiberType === contextType || fiberType?.Provider === contextType) {
|
|
925
|
-
return currentFiber;
|
|
926
|
-
}
|
|
927
|
-
currentFiber = currentFiber.return;
|
|
928
|
-
}
|
|
929
|
-
return null;
|
|
930
|
-
};
|
|
931
|
-
|
|
932
|
-
const isPOJO = (maybePOJO: unknown): maybePOJO is Record<string, unknown> => {
|
|
933
|
-
return (
|
|
934
|
-
Object.prototype.toString.call(maybePOJO) === "[object Object]" &&
|
|
935
|
-
(Object.getPrototypeOf(maybePOJO) === Object.prototype ||
|
|
936
|
-
Object.getPrototypeOf(maybePOJO) === null)
|
|
937
|
-
);
|
|
938
|
-
};
|
|
939
|
-
|
|
940
|
-
const buildPathsFromValue = (
|
|
941
|
-
maybePOJO: Record<string, unknown>,
|
|
942
|
-
basePath: string[] = [],
|
|
943
|
-
ancestors = new WeakSet<object>(),
|
|
944
|
-
): ValueWrite[] => {
|
|
945
|
-
if (!isPOJO(maybePOJO)) {
|
|
946
|
-
return [{ path: basePath, value: maybePOJO }];
|
|
947
|
-
}
|
|
948
|
-
if (ancestors.has(maybePOJO)) {
|
|
949
|
-
return [{ path: basePath, value: maybePOJO }];
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
ancestors.add(maybePOJO);
|
|
953
|
-
const paths: ValueWrite[] = [];
|
|
954
|
-
|
|
955
|
-
for (const [key, value] of Object.entries(maybePOJO)) {
|
|
956
|
-
const path = basePath.concat(key);
|
|
957
|
-
|
|
958
|
-
if (isPOJO(value)) {
|
|
959
|
-
paths.push(...buildPathsFromValue(value, path, ancestors));
|
|
960
|
-
} else {
|
|
961
|
-
paths.push({ path, value });
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
ancestors.delete(maybePOJO);
|
|
966
|
-
return paths;
|
|
967
|
-
};
|
|
968
|
-
|
|
969
|
-
const buildValueWrites = (partialValue: unknown): ValueWrite[] =>
|
|
970
|
-
isPOJO(partialValue) ? buildPathsFromValue(partialValue) : [{ path: [], value: partialValue }];
|
|
971
|
-
|
|
972
|
-
export const overrideProps = (fiber: Fiber, partialValue: Record<string, unknown>) => {
|
|
973
|
-
const renderers = resolveOverrideRenderers(fiber);
|
|
974
|
-
for (const { path, value } of buildValueWrites(partialValue)) {
|
|
975
|
-
applyPropsOverride(renderers, fiber, path, value);
|
|
976
|
-
}
|
|
977
|
-
};
|
|
978
|
-
|
|
979
|
-
export const overrideHookState = (fiber: Fiber, id: number, partialValue: unknown) => {
|
|
980
|
-
const renderers = resolveOverrideRenderers(fiber).filter((renderer) =>
|
|
981
|
-
Boolean(renderer.overrideHookState),
|
|
982
|
-
);
|
|
983
|
-
const writes = buildValueWrites(partialValue);
|
|
984
|
-
|
|
985
|
-
if (renderers.length > 0) {
|
|
986
|
-
for (const renderer of renderers) {
|
|
987
|
-
for (const { path, value } of writes) {
|
|
988
|
-
try {
|
|
989
|
-
renderer.overrideHookState?.(fiber, id, path, value);
|
|
990
|
-
} catch {}
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
return;
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
// production renderers don't expose overrideHookState; dispatching through
|
|
997
|
-
// the hook's own queue still works there, but only for whole-value writes
|
|
998
|
-
// (a path write through dispatch would replace the entire hook state)
|
|
999
|
-
if (isPOJO(partialValue)) return;
|
|
1000
|
-
const dispatch = getHookStateDispatch(fiber, id);
|
|
1001
|
-
if (!dispatch) return;
|
|
1002
|
-
try {
|
|
1003
|
-
dispatch(partialValue);
|
|
1004
|
-
} catch {}
|
|
1005
|
-
};
|
|
1006
|
-
|
|
1007
|
-
export const overrideContext = (fiber: Fiber, contextType: unknown, partialValue: unknown) => {
|
|
1008
|
-
const providerFiber = findContextProviderFiber(fiber, contextType);
|
|
1009
|
-
if (!providerFiber) return;
|
|
1010
|
-
const renderers = resolveOverrideRenderers(providerFiber);
|
|
1011
|
-
for (const { path, value } of buildValueWrites(partialValue)) {
|
|
1012
|
-
applyPropsOverride(renderers, providerFiber, ["value", ...path], value);
|
|
1013
|
-
if (providerFiber.alternate) {
|
|
1014
|
-
applyPropsOverride(renderers, providerFiber.alternate, ["value", ...path], value);
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
};
|
|
1018
|
-
|
|
1019
618
|
export interface InstrumentationOptions {
|
|
1020
619
|
name?: string;
|
|
1021
620
|
onActive?: () => unknown;
|
|
@@ -1036,21 +635,6 @@ interface InstrumentationSubscription {
|
|
|
1036
635
|
|
|
1037
636
|
const instrumentationSubscriptions = new Set<InstrumentationSubscription>();
|
|
1038
637
|
|
|
1039
|
-
const runInstrumentationCallback = (
|
|
1040
|
-
instrumentationName: string,
|
|
1041
|
-
callbackName: string,
|
|
1042
|
-
callback: () => unknown,
|
|
1043
|
-
): void => {
|
|
1044
|
-
runWithBippyError(
|
|
1045
|
-
callback,
|
|
1046
|
-
(cause) => new BippyInstrumentationError(instrumentationName, callbackName, cause),
|
|
1047
|
-
);
|
|
1048
|
-
};
|
|
1049
|
-
|
|
1050
|
-
const runReactDevToolsCallback = (callbackName: string, callback: () => unknown): void => {
|
|
1051
|
-
runWithBippyError(callback, (cause) => new BippyReactDevToolsError(callbackName, cause));
|
|
1052
|
-
};
|
|
1053
|
-
|
|
1054
638
|
interface HookDispatchers {
|
|
1055
639
|
onCommitFiberRoot: ReactDevToolsGlobalHook["onCommitFiberRoot"];
|
|
1056
640
|
onCommitFiberUnmount: ReactDevToolsGlobalHook["onCommitFiberUnmount"];
|
|
@@ -1061,8 +645,6 @@ interface HookDispatchers {
|
|
|
1061
645
|
const hookDispatchers = new WeakMap<ReactDevToolsGlobalHook, Partial<HookDispatchers>>();
|
|
1062
646
|
let didSubscribeToHookReplacements = false;
|
|
1063
647
|
|
|
1064
|
-
const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
1065
|
-
|
|
1066
648
|
// each hook event is dispatched from a single re-installable wrapper. If
|
|
1067
649
|
// something overwrites the hook method (devtools, direct assignment), the
|
|
1068
650
|
// next instrument() call installs a fresh wrapper over it; a superseded
|
|
@@ -1084,9 +666,7 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1084
666
|
didError,
|
|
1085
667
|
) => {
|
|
1086
668
|
if (prevOnCommitFiberRoot) {
|
|
1087
|
-
|
|
1088
|
-
prevOnCommitFiberRoot.call(rdtHook, rendererID, root, priority, didError),
|
|
1089
|
-
);
|
|
669
|
+
prevOnCommitFiberRoot.call(rdtHook, rendererID, root, priority, didError);
|
|
1090
670
|
}
|
|
1091
671
|
if (hookDispatchers.get(rdtHook)?.onCommitFiberRoot !== dispatchCommitFiberRoot) return;
|
|
1092
672
|
setReactWorkTagsForFiber(root.current, rdtHook.renderers.get(rendererID));
|
|
@@ -1104,11 +684,7 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1104
684
|
}
|
|
1105
685
|
for (const { options } of instrumentationSubscriptions) {
|
|
1106
686
|
if (options.onCommitFiberRoot) {
|
|
1107
|
-
|
|
1108
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1109
|
-
"onCommitFiberRoot",
|
|
1110
|
-
() => options.onCommitFiberRoot?.(rendererID, root, priority, didError),
|
|
1111
|
-
);
|
|
687
|
+
options.onCommitFiberRoot(rendererID, root, priority, didError);
|
|
1112
688
|
}
|
|
1113
689
|
}
|
|
1114
690
|
};
|
|
@@ -1127,20 +703,14 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1127
703
|
) => {
|
|
1128
704
|
setReactWorkTagsForFiber(fiber, rdtHook.renderers.get(rendererID));
|
|
1129
705
|
if (prevOnCommitFiberUnmount) {
|
|
1130
|
-
|
|
1131
|
-
prevOnCommitFiberUnmount.call(rdtHook, rendererID, fiber),
|
|
1132
|
-
);
|
|
706
|
+
prevOnCommitFiberUnmount.call(rdtHook, rendererID, fiber);
|
|
1133
707
|
}
|
|
1134
708
|
if (hookDispatchers.get(rdtHook)?.onCommitFiberUnmount !== dispatchCommitFiberUnmount) {
|
|
1135
709
|
return;
|
|
1136
710
|
}
|
|
1137
711
|
for (const { options } of instrumentationSubscriptions) {
|
|
1138
712
|
if (options.onCommitFiberUnmount) {
|
|
1139
|
-
|
|
1140
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1141
|
-
"onCommitFiberUnmount",
|
|
1142
|
-
() => options.onCommitFiberUnmount?.(rendererID, fiber),
|
|
1143
|
-
);
|
|
713
|
+
options.onCommitFiberUnmount(rendererID, fiber);
|
|
1144
714
|
}
|
|
1145
715
|
}
|
|
1146
716
|
};
|
|
@@ -1158,20 +728,14 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1158
728
|
root,
|
|
1159
729
|
) => {
|
|
1160
730
|
if (prevOnPostCommitFiberRoot) {
|
|
1161
|
-
|
|
1162
|
-
prevOnPostCommitFiberRoot.call(rdtHook, rendererID, root),
|
|
1163
|
-
);
|
|
731
|
+
prevOnPostCommitFiberRoot.call(rdtHook, rendererID, root);
|
|
1164
732
|
}
|
|
1165
733
|
if (hookDispatchers.get(rdtHook)?.onPostCommitFiberRoot !== dispatchPostCommitFiberRoot) {
|
|
1166
734
|
return;
|
|
1167
735
|
}
|
|
1168
736
|
for (const { options } of instrumentationSubscriptions) {
|
|
1169
737
|
if (options.onPostCommitFiberRoot) {
|
|
1170
|
-
|
|
1171
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1172
|
-
"onPostCommitFiberRoot",
|
|
1173
|
-
() => options.onPostCommitFiberRoot?.(rendererID, root),
|
|
1174
|
-
);
|
|
738
|
+
options.onPostCommitFiberRoot(rendererID, root);
|
|
1175
739
|
}
|
|
1176
740
|
}
|
|
1177
741
|
};
|
|
@@ -1190,18 +754,12 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1190
754
|
children,
|
|
1191
755
|
) => {
|
|
1192
756
|
if (prevOnScheduleFiberRoot) {
|
|
1193
|
-
|
|
1194
|
-
prevOnScheduleFiberRoot.call(rdtHook, rendererID, root, children),
|
|
1195
|
-
);
|
|
757
|
+
prevOnScheduleFiberRoot.call(rdtHook, rendererID, root, children);
|
|
1196
758
|
}
|
|
1197
759
|
if (hookDispatchers.get(rdtHook)?.onScheduleFiberRoot !== dispatchScheduleFiberRoot) return;
|
|
1198
760
|
for (const { options } of instrumentationSubscriptions) {
|
|
1199
761
|
if (options.onScheduleFiberRoot) {
|
|
1200
|
-
|
|
1201
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1202
|
-
"onScheduleFiberRoot",
|
|
1203
|
-
() => options.onScheduleFiberRoot?.(rendererID, root, children),
|
|
1204
|
-
);
|
|
762
|
+
options.onScheduleFiberRoot(rendererID, root, children);
|
|
1205
763
|
}
|
|
1206
764
|
}
|
|
1207
765
|
};
|
|
@@ -1210,6 +768,18 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1210
768
|
}
|
|
1211
769
|
};
|
|
1212
770
|
|
|
771
|
+
const wireHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
772
|
+
if (!didSubscribeToHookReplacements) {
|
|
773
|
+
onRDTHookReplace(setHookEventDispatchers);
|
|
774
|
+
didSubscribeToHookReplacements = true;
|
|
775
|
+
}
|
|
776
|
+
setHookEventDispatchers(rdtHook);
|
|
777
|
+
};
|
|
778
|
+
|
|
779
|
+
if (hasRDTHook()) {
|
|
780
|
+
wireHookEventDispatchers(getRDTHook());
|
|
781
|
+
}
|
|
782
|
+
|
|
1213
783
|
/**
|
|
1214
784
|
* Instruments the DevTools hook. Each hook event is patched once and
|
|
1215
785
|
* dispatches to a set of listeners, so multiple `instrument` calls compose
|
|
@@ -1228,30 +798,15 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1228
798
|
* unsubscribe();
|
|
1229
799
|
*/
|
|
1230
800
|
export const instrument = (options: InstrumentationOptions): Unsubscribe => {
|
|
1231
|
-
const
|
|
1232
|
-
const onActive = onActiveListener
|
|
1233
|
-
? () =>
|
|
1234
|
-
runInstrumentationCallback(
|
|
1235
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1236
|
-
"onActive",
|
|
1237
|
-
onActiveListener,
|
|
1238
|
-
)
|
|
1239
|
-
: undefined;
|
|
1240
|
-
const rdtHook = getRDTHook(onActive);
|
|
1241
|
-
|
|
1242
|
-
if (!didSubscribeToHookReplacements) {
|
|
1243
|
-
onRDTHookReplace(setHookEventDispatchers);
|
|
1244
|
-
didSubscribeToHookReplacements = true;
|
|
1245
|
-
}
|
|
1246
|
-
|
|
801
|
+
const rdtHook = getRDTHook(options.onActive);
|
|
1247
802
|
rdtHook._instrumentationSource = options.name ?? BIPPY_INSTRUMENTATION_STRING;
|
|
1248
803
|
|
|
1249
|
-
|
|
804
|
+
wireHookEventDispatchers(rdtHook);
|
|
1250
805
|
const subscription: InstrumentationSubscription = { options };
|
|
1251
806
|
instrumentationSubscriptions.add(subscription);
|
|
1252
807
|
|
|
1253
808
|
return createUnsubscribe(() => {
|
|
1254
|
-
if (onActive) _onActiveListeners.delete(onActive);
|
|
809
|
+
if (options.onActive) _onActiveListeners.delete(options.onActive);
|
|
1255
810
|
instrumentationSubscriptions.delete(subscription);
|
|
1256
811
|
});
|
|
1257
812
|
};
|
|
@@ -1264,33 +819,38 @@ const isFiberPropertyKey = (key: string): boolean =>
|
|
|
1264
819
|
key.startsWith("__reactInternalInstance$") ||
|
|
1265
820
|
key.startsWith("__reactFiber");
|
|
1266
821
|
|
|
1267
|
-
const getLegacyRootFiber = (hostInstance:
|
|
1268
|
-
const reactRootContainer = hostInstance
|
|
1269
|
-
if (
|
|
1270
|
-
const internalRoot = reactRootContainer
|
|
1271
|
-
if (
|
|
1272
|
-
const current = internalRoot
|
|
1273
|
-
if (
|
|
1274
|
-
const child = current
|
|
1275
|
-
return
|
|
822
|
+
const getLegacyRootFiber = (hostInstance: object): Fiber | null => {
|
|
823
|
+
const reactRootContainer = Reflect.get(hostInstance, "_reactRootContainer");
|
|
824
|
+
if (typeof reactRootContainer !== "object" || reactRootContainer === null) return null;
|
|
825
|
+
const internalRoot = Reflect.get(reactRootContainer, "_internalRoot");
|
|
826
|
+
if (typeof internalRoot !== "object" || internalRoot === null) return null;
|
|
827
|
+
const current = Reflect.get(internalRoot, "current");
|
|
828
|
+
if (typeof current !== "object" || current === null) return null;
|
|
829
|
+
const child = Reflect.get(current, "child");
|
|
830
|
+
return isFiber(child) ? child : null;
|
|
1276
831
|
};
|
|
1277
832
|
|
|
1278
|
-
const getInternalInstanceHandle = (hostInstance:
|
|
833
|
+
const getInternalInstanceHandle = (hostInstance: object): Fiber | null => {
|
|
1279
834
|
const internalInstanceHandle =
|
|
1280
|
-
hostInstance
|
|
1281
|
-
|
|
835
|
+
Reflect.get(hostInstance, "__internalInstanceHandle") ??
|
|
836
|
+
Reflect.get(hostInstance, "_internalInstanceHandle");
|
|
837
|
+
return isFiber(internalInstanceHandle) ? internalInstanceHandle : null;
|
|
1282
838
|
};
|
|
1283
839
|
|
|
1284
840
|
const getPublicHostInstance = (stateNode: unknown): unknown => {
|
|
1285
|
-
if (
|
|
1286
|
-
const canonical = stateNode
|
|
1287
|
-
if (
|
|
1288
|
-
|
|
841
|
+
if (typeof stateNode !== "object" || stateNode === null) return stateNode;
|
|
842
|
+
const canonical = Reflect.get(stateNode, "canonical");
|
|
843
|
+
if (typeof canonical === "object" && canonical !== null) {
|
|
844
|
+
const publicInstance = Reflect.get(canonical, "publicInstance");
|
|
845
|
+
if (typeof publicInstance === "object" && publicInstance !== null) {
|
|
846
|
+
return publicInstance;
|
|
847
|
+
}
|
|
1289
848
|
}
|
|
1290
|
-
|
|
849
|
+
const nativeTag = Reflect.get(stateNode, "_nativeTag");
|
|
850
|
+
return typeof nativeTag === "number" ? nativeTag : stateNode;
|
|
1291
851
|
};
|
|
1292
852
|
|
|
1293
|
-
export const
|
|
853
|
+
export const getFiber = <T>(hostInstance: T): Fiber | null => {
|
|
1294
854
|
const rdtHook = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
1295
855
|
if (rdtHook?.renderers) {
|
|
1296
856
|
for (const renderer of rdtHook.renderers.values()) {
|
|
@@ -1301,7 +861,7 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1301
861
|
}
|
|
1302
862
|
}
|
|
1303
863
|
|
|
1304
|
-
if (
|
|
864
|
+
if (typeof hostInstance === "object" && hostInstance !== null) {
|
|
1305
865
|
const legacyRootFiber = getLegacyRootFiber(hostInstance);
|
|
1306
866
|
if (legacyRootFiber) return legacyRootFiber;
|
|
1307
867
|
|
|
@@ -1309,15 +869,15 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1309
869
|
if (internalInstanceHandle) return internalInstanceHandle;
|
|
1310
870
|
|
|
1311
871
|
for (const knownKey of knownFiberPropertyKeys) {
|
|
1312
|
-
const fiber = hostInstance
|
|
1313
|
-
if (
|
|
872
|
+
const fiber = Reflect.get(hostInstance, knownKey);
|
|
873
|
+
if (isFiber(fiber)) return fiber;
|
|
1314
874
|
}
|
|
1315
875
|
|
|
1316
876
|
for (const key of Object.keys(hostInstance)) {
|
|
1317
877
|
if (isFiberPropertyKey(key)) {
|
|
1318
878
|
knownFiberPropertyKeys.add(key);
|
|
1319
|
-
const fiber = hostInstance
|
|
1320
|
-
if (
|
|
879
|
+
const fiber = Reflect.get(hostInstance, key);
|
|
880
|
+
if (isFiber(fiber)) return fiber;
|
|
1321
881
|
}
|
|
1322
882
|
}
|
|
1323
883
|
}
|
|
@@ -1340,6 +900,8 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1340
900
|
return null;
|
|
1341
901
|
};
|
|
1342
902
|
|
|
903
|
+
export const getFiberFromHostInstance = getFiber;
|
|
904
|
+
|
|
1343
905
|
export {
|
|
1344
906
|
BIPPY_INSTRUMENTATION_STRING,
|
|
1345
907
|
_onActiveListeners,
|
|
@@ -1350,8 +912,7 @@ export {
|
|
|
1350
912
|
isRealReactDevtools,
|
|
1351
913
|
onRendererInject,
|
|
1352
914
|
patchRDTHook,
|
|
1353
|
-
safelyInstallRDTHook,
|
|
1354
915
|
version,
|
|
1355
916
|
} from "./rdt-hook.js";
|
|
1356
917
|
export type { Unsubscribe } from "./rdt-hook.js";
|
|
1357
|
-
export
|
|
918
|
+
export * from "./react-internals/index.js";
|