bippy 0.6.1-dev.d7876ea → 0.6.1-dev.f9e6c65
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 -1
- package/README.md +159 -487
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +24 -70
- package/dist/core.d.ts +24 -70
- package/dist/core.js +1 -1
- package/dist/core2.cjs +1 -1
- package/dist/core2.d.cts +11 -3
- package/dist/core2.d.ts +11 -3
- package/dist/core2.js +1 -1
- package/dist/errors.d.cts +33 -59
- package/dist/errors.d.ts +33 -59
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +14 -3
- package/dist/index.d.ts +14 -3
- package/dist/index.js +1 -1
- package/dist/install-hook-only.cjs +1 -1
- package/dist/install-hook-only.d.cts +8 -0
- package/dist/install-hook-only.d.ts +8 -0
- 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 +85 -77
- package/dist/source.d.ts +85 -77
- package/dist/source.js +12 -13
- package/package.json +6 -3
- package/src/core.ts +141 -564
- 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 +39 -45
- package/src/{generated/react-work-tags.js → react-internals/generated/react-work-tags.ts} +85 -7
- package/src/{react-internals.ts → react-internals/index.ts} +6 -4
- package/src/{semver.ts → react-internals/semver.ts} +2 -0
- package/src/{types.ts → react-internals/types.ts} +1 -84
- package/src/react.ts +76 -0
- package/src/source/get-display-name-from-source.ts +44 -40
- package/src/source/get-source.ts +42 -26
- package/src/source/index.ts +2 -0
- package/src/source/inspect-hooks.ts +74 -96
- package/src/source/owner-stack.ts +66 -91
- 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 +421 -108
- package/dist/index.iife.js +0 -9
- package/dist/install-hook-only.iife.js +0 -9
- package/src/generated/react-work-tags.d.ts +0 -261
- package/src/unsubscribe.ts +0 -17
package/src/core.ts
CHANGED
|
@@ -3,26 +3,23 @@
|
|
|
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
|
-
} from "./
|
|
14
|
-
|
|
15
|
-
import { BippyInstrumentationError, BippyReactDevToolsError, runWithBippyError } from "./errors.js";
|
|
11
|
+
} from "./react-internals/index.js";
|
|
16
12
|
|
|
17
13
|
import {
|
|
18
14
|
_onActiveListeners,
|
|
19
15
|
BIPPY_INSTRUMENTATION_STRING,
|
|
16
|
+
createUnsubscribe,
|
|
20
17
|
getRDTHook,
|
|
21
18
|
hasRDTHook,
|
|
22
19
|
isRealReactDevtools,
|
|
23
20
|
onRDTHookReplace,
|
|
24
|
-
onRendererInject,
|
|
25
21
|
} from "./rdt-hook.js";
|
|
22
|
+
import type { Unsubscribe } from "./rdt-hook.js";
|
|
26
23
|
import {
|
|
27
24
|
getReactWorkTagsForFiber,
|
|
28
25
|
MutationMask,
|
|
@@ -30,47 +27,23 @@ import {
|
|
|
30
27
|
ReactFiberFlags,
|
|
31
28
|
ReactSymbols,
|
|
32
29
|
setReactWorkTagsForFiber,
|
|
33
|
-
} from "./react-internals.js";
|
|
34
|
-
import { toUnsubscribe, type Unsubscribe } from "./unsubscribe.js";
|
|
30
|
+
} from "./react-internals/index.js";
|
|
35
31
|
|
|
36
|
-
export { getReactWorkTags, ReactSymbols } from "./react-internals.js";
|
|
37
|
-
export type { ReactWorkTagMap, ReactWorkTagVersion } from "./react-internals.js";
|
|
38
32
|
export {
|
|
39
33
|
BippyError,
|
|
40
|
-
BippyHookInstallationError,
|
|
41
34
|
BippyHookInspectionError,
|
|
42
|
-
BippyHookListenerError,
|
|
43
35
|
BippyHookRenderError,
|
|
44
|
-
BippyInstrumentationError,
|
|
45
|
-
BippyReactBuildError,
|
|
46
|
-
BippyReactDevToolsError,
|
|
47
36
|
BippySourceMapError,
|
|
48
37
|
BippyUnsupportedHookError,
|
|
49
38
|
} from "./errors.js";
|
|
50
39
|
|
|
51
|
-
const isObjectRecord = (value: unknown): value is Record<string, unknown> =>
|
|
52
|
-
typeof value === "object" && value !== null;
|
|
53
|
-
|
|
54
40
|
const isComponentType = (value: unknown): value is React.ComponentType<unknown> =>
|
|
55
41
|
typeof value === "function";
|
|
56
42
|
|
|
57
|
-
const getPropertyValue = (value: object, key: PropertyKey): unknown => {
|
|
58
|
-
let currentValue: object | null = value;
|
|
59
|
-
while (currentValue) {
|
|
60
|
-
const descriptor = Object.getOwnPropertyDescriptor(currentValue, key);
|
|
61
|
-
if (descriptor) {
|
|
62
|
-
if ("value" in descriptor) return descriptor.value;
|
|
63
|
-
return descriptor.get?.call(value);
|
|
64
|
-
}
|
|
65
|
-
currentValue = Object.getPrototypeOf(currentValue);
|
|
66
|
-
}
|
|
67
|
-
return undefined;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
43
|
const getTypeName = (value: object): string | null => {
|
|
71
|
-
const displayName =
|
|
44
|
+
const displayName = "displayName" in value ? value.displayName : null;
|
|
72
45
|
if (typeof displayName === "string" && displayName) return displayName;
|
|
73
|
-
const name =
|
|
46
|
+
const name = "name" in value ? value.name : null;
|
|
74
47
|
return typeof name === "string" && name ? name : null;
|
|
75
48
|
};
|
|
76
49
|
|
|
@@ -78,18 +51,8 @@ interface FiberSelector {
|
|
|
78
51
|
(node: Fiber): boolean | Promise<boolean | void> | void;
|
|
79
52
|
}
|
|
80
53
|
|
|
81
|
-
export interface FiberTimings {
|
|
82
|
-
selfTime: number;
|
|
83
|
-
totalTime: number;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
54
|
export interface RenderHandler {
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
interface ValueWrite {
|
|
91
|
-
path: string[];
|
|
92
|
-
value: unknown;
|
|
55
|
+
(fiber: Fiber, phase: RenderPhase): unknown;
|
|
93
56
|
}
|
|
94
57
|
|
|
95
58
|
/**
|
|
@@ -101,9 +64,8 @@ export const isValidElement = (element: unknown): element is React.ReactElement
|
|
|
101
64
|
typeof element === "object" &&
|
|
102
65
|
element !== null &&
|
|
103
66
|
"$$typeof" in element &&
|
|
104
|
-
|
|
105
|
-
String(element.$$typeof)
|
|
106
|
-
);
|
|
67
|
+
(String(element.$$typeof) === ReactSymbols.LEGACY_ELEMENT_SYMBOL_STRING ||
|
|
68
|
+
String(element.$$typeof) === ReactSymbols.ELEMENT_SYMBOL_STRING);
|
|
107
69
|
|
|
108
70
|
/**
|
|
109
71
|
* Returns `true` if object is a React Fiber.
|
|
@@ -118,6 +80,12 @@ export const isValidFiber = (fiber: unknown): fiber is Fiber =>
|
|
|
118
80
|
"sibling" in fiber &&
|
|
119
81
|
"flags" in fiber;
|
|
120
82
|
|
|
83
|
+
const isFiberRoot = (fiberRoot: unknown): fiberRoot is FiberRoot =>
|
|
84
|
+
typeof fiberRoot === "object" &&
|
|
85
|
+
fiberRoot !== null &&
|
|
86
|
+
"current" in fiberRoot &&
|
|
87
|
+
isValidFiber(fiberRoot.current);
|
|
88
|
+
|
|
121
89
|
/**
|
|
122
90
|
* Returns `true` if fiber is a host fiber. Host fibers are DOM nodes in react-dom, `View` in react-native, etc.
|
|
123
91
|
*
|
|
@@ -165,90 +133,6 @@ export const isFiber = (maybeFiber: unknown): maybeFiber is Fiber => {
|
|
|
165
133
|
return "pendingProps" in maybeFiber && !("containerInfo" in maybeFiber);
|
|
166
134
|
};
|
|
167
135
|
|
|
168
|
-
/**
|
|
169
|
-
* Traverses up or down a {@link Fiber}'s contexts, return `true` to stop and select the current and previous context value.
|
|
170
|
-
*/
|
|
171
|
-
export const traverseContexts = (
|
|
172
|
-
fiber: Fiber,
|
|
173
|
-
selector: (
|
|
174
|
-
nextValue: ContextDependency<unknown> | null | undefined,
|
|
175
|
-
prevValue: ContextDependency<unknown> | null | undefined,
|
|
176
|
-
) => boolean | void,
|
|
177
|
-
): boolean => {
|
|
178
|
-
try {
|
|
179
|
-
const nextDependencies = fiber.dependencies;
|
|
180
|
-
const prevDependencies = fiber.alternate?.dependencies;
|
|
181
|
-
|
|
182
|
-
if (!nextDependencies || !prevDependencies) return false;
|
|
183
|
-
if (
|
|
184
|
-
typeof nextDependencies !== "object" ||
|
|
185
|
-
!("firstContext" in nextDependencies) ||
|
|
186
|
-
typeof prevDependencies !== "object" ||
|
|
187
|
-
!("firstContext" in prevDependencies)
|
|
188
|
-
) {
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
let nextContext: ContextDependency<unknown> | null | undefined = nextDependencies.firstContext;
|
|
192
|
-
let prevContext: ContextDependency<unknown> | null | undefined = prevDependencies.firstContext;
|
|
193
|
-
while (
|
|
194
|
-
(nextContext && typeof nextContext === "object" && "memoizedValue" in nextContext) ||
|
|
195
|
-
(prevContext && typeof prevContext === "object" && "memoizedValue" in prevContext)
|
|
196
|
-
) {
|
|
197
|
-
if (selector(nextContext, prevContext) === true) return true;
|
|
198
|
-
|
|
199
|
-
nextContext = nextContext?.next;
|
|
200
|
-
prevContext = prevContext?.next;
|
|
201
|
-
}
|
|
202
|
-
} catch {}
|
|
203
|
-
return false;
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* 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.
|
|
208
|
-
*/
|
|
209
|
-
export const traverseState = (
|
|
210
|
-
fiber: Fiber,
|
|
211
|
-
selector: (
|
|
212
|
-
nextValue: MemoizedState | null | undefined,
|
|
213
|
-
prevValue: MemoizedState | null | undefined,
|
|
214
|
-
) => boolean | void,
|
|
215
|
-
): boolean => {
|
|
216
|
-
try {
|
|
217
|
-
let nextState: MemoizedState | null | undefined = fiber.memoizedState;
|
|
218
|
-
let prevState: MemoizedState | null | undefined = fiber.alternate?.memoizedState;
|
|
219
|
-
|
|
220
|
-
while (nextState || prevState) {
|
|
221
|
-
if (selector(nextState, prevState) === true) return true;
|
|
222
|
-
|
|
223
|
-
nextState = nextState?.next;
|
|
224
|
-
prevState = prevState?.next;
|
|
225
|
-
}
|
|
226
|
-
} catch {}
|
|
227
|
-
return false;
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Traverses up or down a {@link Fiber}'s props, return `true` to stop and select the current and previous props value.
|
|
232
|
-
*/
|
|
233
|
-
export const traverseProps = (
|
|
234
|
-
fiber: Fiber,
|
|
235
|
-
selector: (propName: string, nextValue: unknown, prevValue: unknown) => boolean | void,
|
|
236
|
-
): boolean => {
|
|
237
|
-
try {
|
|
238
|
-
const nextProps = fiber.memoizedProps;
|
|
239
|
-
const prevProps = fiber.alternate?.memoizedProps || {};
|
|
240
|
-
|
|
241
|
-
for (const propName of Object.keys(nextProps)) {
|
|
242
|
-
if (selector(propName, nextProps[propName], prevProps[propName]) === true) return true;
|
|
243
|
-
}
|
|
244
|
-
for (const propName of Object.keys(prevProps)) {
|
|
245
|
-
if (propName in nextProps) continue;
|
|
246
|
-
if (selector(propName, nextProps[propName], prevProps[propName]) === true) return true;
|
|
247
|
-
}
|
|
248
|
-
} catch {}
|
|
249
|
-
return false;
|
|
250
|
-
};
|
|
251
|
-
|
|
252
136
|
/**
|
|
253
137
|
* 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.
|
|
254
138
|
*/
|
|
@@ -288,47 +172,6 @@ export const didFiberCommit = (fiber: Fiber): boolean => {
|
|
|
288
172
|
);
|
|
289
173
|
};
|
|
290
174
|
|
|
291
|
-
/**
|
|
292
|
-
* Returns all host {@link Fiber}s that have committed and rendered.
|
|
293
|
-
*/
|
|
294
|
-
export const getMutatedHostFibers = (fiber: Fiber): Fiber[] => {
|
|
295
|
-
const mutations: Fiber[] = [];
|
|
296
|
-
const stack: Fiber[] = [fiber];
|
|
297
|
-
|
|
298
|
-
while (stack.length) {
|
|
299
|
-
const node = stack.pop();
|
|
300
|
-
if (!node) continue;
|
|
301
|
-
|
|
302
|
-
if (isHostFiber(node) && didFiberCommit(node) && didFiberRender(node)) {
|
|
303
|
-
mutations.push(node);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (node.child) stack.push(node.child);
|
|
307
|
-
if (node.sibling) stack.push(node.sibling);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return mutations;
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Returns the stack of {@link Fiber}s from the current fiber to the root fiber.
|
|
315
|
-
*
|
|
316
|
-
* @example
|
|
317
|
-
* ```ts
|
|
318
|
-
* [fiber, fiber.return, fiber.return.return, ...]
|
|
319
|
-
* ```
|
|
320
|
-
*/
|
|
321
|
-
export const getFiberStack = (fiber: Fiber): Fiber[] => {
|
|
322
|
-
const stack: Fiber[] = [];
|
|
323
|
-
let currentFiber = fiber;
|
|
324
|
-
while (currentFiber.return) {
|
|
325
|
-
stack.push(currentFiber);
|
|
326
|
-
const parentFiber = currentFiber.return;
|
|
327
|
-
currentFiber = parentFiber;
|
|
328
|
-
}
|
|
329
|
-
return stack;
|
|
330
|
-
};
|
|
331
|
-
|
|
332
175
|
/**
|
|
333
176
|
* Returns `true` if the {@link Fiber} should be filtered out during reconciliation.
|
|
334
177
|
*/
|
|
@@ -377,47 +220,6 @@ const shouldFilterFiber = (fiber: Fiber): boolean => {
|
|
|
377
220
|
}
|
|
378
221
|
};
|
|
379
222
|
|
|
380
|
-
/**
|
|
381
|
-
* Returns the nearest host {@link Fiber} to the current {@link Fiber}.
|
|
382
|
-
*/
|
|
383
|
-
export const getNearestHostFiber = (fiber: Fiber, ascending = false): Fiber | null => {
|
|
384
|
-
let hostFiber = traverseFiber(fiber, isHostFiber, ascending);
|
|
385
|
-
if (!hostFiber) {
|
|
386
|
-
hostFiber = traverseFiber(fiber, isHostFiber, !ascending);
|
|
387
|
-
}
|
|
388
|
-
return hostFiber;
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Returns all host {@link Fiber}s in the tree that are associated with the current {@link Fiber}.
|
|
393
|
-
*/
|
|
394
|
-
export const getNearestHostFibers = (fiber: Fiber): Fiber[] => {
|
|
395
|
-
const hostFibers: Fiber[] = [];
|
|
396
|
-
const stack: Fiber[] = [];
|
|
397
|
-
|
|
398
|
-
if (isHostFiber(fiber)) {
|
|
399
|
-
hostFibers.push(fiber);
|
|
400
|
-
} else if (fiber.child) {
|
|
401
|
-
stack.push(fiber.child);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
while (stack.length) {
|
|
405
|
-
const currentNode = stack.pop();
|
|
406
|
-
if (!currentNode) break;
|
|
407
|
-
if (isHostFiber(currentNode)) {
|
|
408
|
-
hostFibers.push(currentNode);
|
|
409
|
-
} else if (currentNode.child) {
|
|
410
|
-
stack.push(currentNode.child);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (currentNode.sibling) {
|
|
414
|
-
stack.push(currentNode.sibling);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
return hostFibers;
|
|
419
|
-
};
|
|
420
|
-
|
|
421
223
|
/**
|
|
422
224
|
* Traverses up or down a {@link Fiber}, return `true` to stop and select a node.
|
|
423
225
|
*/
|
|
@@ -431,6 +233,11 @@ export function traverseFiber(
|
|
|
431
233
|
selector: (node: Fiber) => Promise<boolean | void>,
|
|
432
234
|
ascending?: boolean,
|
|
433
235
|
): Promise<Fiber | null>;
|
|
236
|
+
export function traverseFiber(
|
|
237
|
+
fiber: Fiber | null,
|
|
238
|
+
selector: FiberSelector,
|
|
239
|
+
ascending?: boolean,
|
|
240
|
+
): Fiber | null | Promise<Fiber | null>;
|
|
434
241
|
export function traverseFiber(
|
|
435
242
|
fiber: Fiber | null,
|
|
436
243
|
selector: FiberSelector,
|
|
@@ -438,89 +245,47 @@ export function traverseFiber(
|
|
|
438
245
|
): Fiber | null | Promise<Fiber | null> {
|
|
439
246
|
if (!fiber) return null;
|
|
440
247
|
|
|
441
|
-
const
|
|
442
|
-
if (
|
|
443
|
-
return (
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
let child = ascending ? fiber.return : fiber.child;
|
|
447
|
-
while (child) {
|
|
448
|
-
const match = await traverseFiberAsync(child, selector, ascending);
|
|
449
|
-
if (match) return match;
|
|
450
|
-
child = ascending ? null : child.sibling;
|
|
451
|
-
}
|
|
452
|
-
return null;
|
|
453
|
-
})();
|
|
248
|
+
const selection = selector(fiber);
|
|
249
|
+
if (isPromiseLike<boolean | void>(selection)) {
|
|
250
|
+
return Promise.resolve(selection).then((didSelectFiber) =>
|
|
251
|
+
didSelectFiber === true ? fiber : traverseFiberChildren(fiber, selector, ascending),
|
|
252
|
+
);
|
|
454
253
|
}
|
|
254
|
+
if (selection === true) return fiber;
|
|
455
255
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
let child = ascending ? fiber.return : fiber.child;
|
|
459
|
-
while (child) {
|
|
460
|
-
const match = traverseFiberSync(child, selector, ascending);
|
|
461
|
-
if (match) return match;
|
|
462
|
-
child = ascending ? null : child.sibling;
|
|
463
|
-
}
|
|
464
|
-
return null;
|
|
256
|
+
return traverseFiberChildren(fiber, selector, ascending);
|
|
465
257
|
}
|
|
466
258
|
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
if (!fiber) return null;
|
|
473
|
-
const selection = selector(fiber);
|
|
474
|
-
if (selection instanceof Promise) return null;
|
|
475
|
-
if (selection === true) return fiber;
|
|
476
|
-
|
|
477
|
-
let child = ascending ? fiber.return : fiber.child;
|
|
478
|
-
while (child) {
|
|
479
|
-
const match = traverseFiberSync(child, selector, ascending);
|
|
480
|
-
if (match) return match;
|
|
259
|
+
const isPromiseLike = <Result>(value: unknown): value is PromiseLike<Result> =>
|
|
260
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
261
|
+
value !== null &&
|
|
262
|
+
"then" in value &&
|
|
263
|
+
typeof value.then === "function";
|
|
481
264
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
265
|
+
const traverseFiberChildren = (
|
|
266
|
+
fiber: Fiber,
|
|
267
|
+
selector: FiberSelector,
|
|
268
|
+
ascending: boolean,
|
|
269
|
+
): Fiber | null | Promise<Fiber | null> => {
|
|
270
|
+
const firstChild = ascending ? fiber.return : fiber.child;
|
|
271
|
+
return traverseFiberSiblings(firstChild, selector, ascending);
|
|
485
272
|
};
|
|
486
273
|
|
|
487
|
-
const
|
|
274
|
+
const traverseFiberSiblings = (
|
|
488
275
|
fiber: Fiber | null,
|
|
489
276
|
selector: FiberSelector,
|
|
490
|
-
ascending
|
|
491
|
-
): Promise<Fiber | null> => {
|
|
277
|
+
ascending: boolean,
|
|
278
|
+
): Fiber | null | Promise<Fiber | null> => {
|
|
492
279
|
if (!fiber) return null;
|
|
493
|
-
if ((await selector(fiber)) === true) return fiber;
|
|
494
|
-
|
|
495
|
-
let child = ascending ? fiber.return : fiber.child;
|
|
496
|
-
while (child) {
|
|
497
|
-
const match = await traverseFiberAsync(child, selector, ascending);
|
|
498
|
-
if (match) return match;
|
|
499
280
|
|
|
500
|
-
|
|
281
|
+
const nextSibling = ascending ? null : fiber.sibling;
|
|
282
|
+
const match = traverseFiber(fiber, selector, ascending);
|
|
283
|
+
if (isPromiseLike<Fiber | null>(match)) {
|
|
284
|
+
return Promise.resolve(match).then(
|
|
285
|
+
(resolvedMatch) => resolvedMatch ?? traverseFiberSiblings(nextSibling, selector, ascending),
|
|
286
|
+
);
|
|
501
287
|
}
|
|
502
|
-
return
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
/**
|
|
506
|
-
* Returns the timings of the {@link Fiber}.
|
|
507
|
-
*
|
|
508
|
-
* @example
|
|
509
|
-
* ```ts
|
|
510
|
-
* const { selfTime, totalTime } = getTimings(fiber);
|
|
511
|
-
* console.log(selfTime, totalTime);
|
|
512
|
-
* ```
|
|
513
|
-
*/
|
|
514
|
-
export const getTimings = (fiber?: Fiber | null): FiberTimings => {
|
|
515
|
-
const totalTime = fiber?.actualDuration ?? 0;
|
|
516
|
-
let selfTime = totalTime;
|
|
517
|
-
// TODO: calculate a DOM time, which is just host component summed up
|
|
518
|
-
let child = fiber?.child ?? null;
|
|
519
|
-
while (totalTime > 0 && child !== null) {
|
|
520
|
-
selfTime -= child.actualDuration ?? 0;
|
|
521
|
-
child = child.sibling;
|
|
522
|
-
}
|
|
523
|
-
return { selfTime, totalTime };
|
|
288
|
+
return match ?? traverseFiberSiblings(nextSibling, selector, ascending);
|
|
524
289
|
};
|
|
525
290
|
|
|
526
291
|
/**
|
|
@@ -535,8 +300,8 @@ export const hasMemoCache = (fiber: Fiber): boolean => {
|
|
|
535
300
|
*/
|
|
536
301
|
export const getType = (type: unknown): null | React.ComponentType<unknown> => {
|
|
537
302
|
if (isComponentType(type)) return type;
|
|
538
|
-
if (
|
|
539
|
-
return getType(
|
|
303
|
+
if (typeof type !== "object" || type === null) return null;
|
|
304
|
+
return getType(Reflect.get(type, "type") ?? Reflect.get(type, "render"));
|
|
540
305
|
};
|
|
541
306
|
|
|
542
307
|
/**
|
|
@@ -576,6 +341,7 @@ export const isInstrumentationActive = (): boolean => {
|
|
|
576
341
|
};
|
|
577
342
|
|
|
578
343
|
export const _fiberRoots = new Set<FiberRoot>();
|
|
344
|
+
const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
579
345
|
|
|
580
346
|
/**
|
|
581
347
|
* Returns the latest fiber (since it may be double-buffered).
|
|
@@ -588,13 +354,32 @@ export const getLatestFiber = (fiber: Fiber): Fiber => {
|
|
|
588
354
|
}
|
|
589
355
|
for (const root of _fiberRoots) {
|
|
590
356
|
const latestFiber = traverseFiber(root.current, (innerFiber) => {
|
|
591
|
-
if (innerFiber === fiber) return true;
|
|
357
|
+
if (innerFiber === fiber || innerFiber === alternate) return true;
|
|
592
358
|
});
|
|
593
359
|
if (latestFiber) return latestFiber;
|
|
594
360
|
}
|
|
595
361
|
return fiber;
|
|
596
362
|
};
|
|
597
363
|
|
|
364
|
+
/**
|
|
365
|
+
* Returns the renderer that owns the {@link Fiber}.
|
|
366
|
+
*/
|
|
367
|
+
export const getRenderer = (fiber: Fiber): ReactRenderer | null => {
|
|
368
|
+
if (!hasRDTHook()) return null;
|
|
369
|
+
|
|
370
|
+
let rootFiber = fiber;
|
|
371
|
+
while (rootFiber.return) {
|
|
372
|
+
rootFiber = rootFiber.return;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const fiberRoot = rootFiber.stateNode;
|
|
376
|
+
if (!isFiberRoot(fiberRoot)) return null;
|
|
377
|
+
|
|
378
|
+
const rendererID = rootRendererIds.get(fiberRoot);
|
|
379
|
+
if (rendererID === undefined) return null;
|
|
380
|
+
return getRDTHook().renderers.get(rendererID) ?? null;
|
|
381
|
+
};
|
|
382
|
+
|
|
598
383
|
export type RenderPhase = "mount" | "unmount" | "update";
|
|
599
384
|
|
|
600
385
|
let nextFiberId = 0;
|
|
@@ -602,6 +387,9 @@ const fiberIdMap = new WeakMap<Fiber, number>();
|
|
|
602
387
|
|
|
603
388
|
export const setFiberId = (fiber: Fiber, fiberId: number = nextFiberId++): void => {
|
|
604
389
|
fiberIdMap.set(fiber, fiberId);
|
|
390
|
+
if (Number.isSafeInteger(fiberId) && fiberId >= nextFiberId) {
|
|
391
|
+
nextFiberId = fiberId + 1;
|
|
392
|
+
}
|
|
605
393
|
};
|
|
606
394
|
|
|
607
395
|
export const getFiberId = (fiber: Fiber): number => {
|
|
@@ -624,9 +412,7 @@ const mountFiberRecursively = (
|
|
|
624
412
|
let fiber: Fiber | null = firstChild;
|
|
625
413
|
|
|
626
414
|
while (fiber !== null) {
|
|
627
|
-
|
|
628
|
-
getFiberId(fiber);
|
|
629
|
-
}
|
|
415
|
+
getFiberId(fiber);
|
|
630
416
|
const shouldIncludeInTree = !shouldFilterFiber(fiber);
|
|
631
417
|
if (shouldIncludeInTree && didFiberRender(fiber)) {
|
|
632
418
|
onRender(fiber, "mount");
|
|
@@ -662,16 +448,11 @@ const mountFiberRecursively = (
|
|
|
662
448
|
const updateFiberRecursively = (
|
|
663
449
|
onRender: RenderHandler,
|
|
664
450
|
nextFiber: Fiber,
|
|
665
|
-
prevFiber: Fiber,
|
|
666
|
-
parentFiber: Fiber | null,
|
|
451
|
+
prevFiber: Fiber | null,
|
|
667
452
|
): void => {
|
|
668
|
-
|
|
669
|
-
getFiberId(nextFiber);
|
|
670
|
-
}
|
|
453
|
+
getFiberId(nextFiber);
|
|
671
454
|
if (!prevFiber) return;
|
|
672
|
-
|
|
673
|
-
getFiberId(prevFiber);
|
|
674
|
-
}
|
|
455
|
+
getFiberId(prevFiber);
|
|
675
456
|
|
|
676
457
|
const isSuspense = nextFiber.tag === getReactWorkTagsForFiber(nextFiber).SuspenseComponent;
|
|
677
458
|
|
|
@@ -702,7 +483,7 @@ const updateFiberRecursively = (
|
|
|
702
483
|
const prevFallbackChildSet = prevFiber.child?.sibling ?? null;
|
|
703
484
|
|
|
704
485
|
if (nextFallbackChildSet !== null && prevFallbackChildSet !== null) {
|
|
705
|
-
updateFiberRecursively(onRender, nextFallbackChildSet, prevFallbackChildSet
|
|
486
|
+
updateFiberRecursively(onRender, nextFallbackChildSet, prevFallbackChildSet);
|
|
706
487
|
}
|
|
707
488
|
} else if (prevDidTimeout && !nextDidTimeOut) {
|
|
708
489
|
// Fallback -> Primary:
|
|
@@ -741,14 +522,7 @@ const updateFiberRecursively = (
|
|
|
741
522
|
// Schedule updates and mounts depending on whether alternates exist.
|
|
742
523
|
// We don't track deletions here because they are reported separately.
|
|
743
524
|
if (nextChild.alternate) {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
updateFiberRecursively(
|
|
747
|
-
onRender,
|
|
748
|
-
nextChild,
|
|
749
|
-
prevChild,
|
|
750
|
-
shouldIncludeInTree ? nextFiber : parentFiber,
|
|
751
|
-
);
|
|
525
|
+
updateFiberRecursively(onRender, nextChild, nextChild.alternate);
|
|
752
526
|
} else {
|
|
753
527
|
mountFiberRecursively(onRender, nextChild, false);
|
|
754
528
|
}
|
|
@@ -794,11 +568,9 @@ const unmountFiberChildrenRecursively = (onRender: RenderHandler, fiber: Fiber):
|
|
|
794
568
|
}
|
|
795
569
|
};
|
|
796
570
|
|
|
797
|
-
let commitId = 0;
|
|
798
571
|
const rootInstanceMap = new WeakMap<
|
|
799
|
-
FiberRoot,
|
|
572
|
+
Fiber | FiberRoot,
|
|
800
573
|
{
|
|
801
|
-
id: number;
|
|
802
574
|
prevFiber: Fiber | null;
|
|
803
575
|
}
|
|
804
576
|
>();
|
|
@@ -810,23 +582,23 @@ const rootInstanceMap = new WeakMap<
|
|
|
810
582
|
* console.log(phase)
|
|
811
583
|
* })
|
|
812
584
|
*/
|
|
813
|
-
export const traverseRenderedFibers = (root: FiberRoot, onRender: RenderHandler): void => {
|
|
585
|
+
export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: RenderHandler): void => {
|
|
814
586
|
const fiber = "current" in root ? root.current : root;
|
|
815
587
|
|
|
816
588
|
let rootInstance = rootInstanceMap.get(root);
|
|
817
589
|
|
|
818
590
|
if (!rootInstance) {
|
|
819
|
-
rootInstance = {
|
|
591
|
+
rootInstance = { prevFiber: null };
|
|
820
592
|
rootInstanceMap.set(root, rootInstance);
|
|
821
593
|
}
|
|
822
594
|
|
|
823
595
|
const { prevFiber } = rootInstance;
|
|
824
|
-
// if fiberRoot don't have current instance, means it's been unmounted
|
|
825
596
|
if (!fiber) {
|
|
826
|
-
|
|
597
|
+
if (prevFiber) {
|
|
598
|
+
unmountFiber(onRender, prevFiber);
|
|
599
|
+
}
|
|
827
600
|
} else if (prevFiber !== null) {
|
|
828
601
|
const wasMounted =
|
|
829
|
-
prevFiber &&
|
|
830
602
|
prevFiber.memoizedState !== null &&
|
|
831
603
|
prevFiber.memoizedState.element !== null &&
|
|
832
604
|
prevFiber.memoizedState.element !== undefined &&
|
|
@@ -842,7 +614,7 @@ export const traverseRenderedFibers = (root: FiberRoot, onRender: RenderHandler)
|
|
|
842
614
|
if (!wasMounted && isMounted) {
|
|
843
615
|
mountFiberRecursively(onRender, fiber, false);
|
|
844
616
|
} else if (wasMounted && isMounted) {
|
|
845
|
-
updateFiberRecursively(onRender, fiber, fiber.alternate
|
|
617
|
+
updateFiberRecursively(onRender, fiber, fiber.alternate);
|
|
846
618
|
} else if (wasMounted && !isMounted) {
|
|
847
619
|
unmountFiber(onRender, fiber);
|
|
848
620
|
}
|
|
@@ -853,164 +625,6 @@ export const traverseRenderedFibers = (root: FiberRoot, onRender: RenderHandler)
|
|
|
853
625
|
rootInstance.prevFiber = fiber;
|
|
854
626
|
};
|
|
855
627
|
|
|
856
|
-
const overrideRenderers = new Set<ReactRenderer>();
|
|
857
|
-
let areOverrideRenderersWired = false;
|
|
858
|
-
|
|
859
|
-
const wireOverrideRenderers = (): void => {
|
|
860
|
-
if (!hasRDTHook()) return;
|
|
861
|
-
const rdtHook = getRDTHook();
|
|
862
|
-
|
|
863
|
-
setHookEventDispatchers(rdtHook);
|
|
864
|
-
for (const renderer of rdtHook.renderers.values()) {
|
|
865
|
-
overrideRenderers.add(renderer);
|
|
866
|
-
}
|
|
867
|
-
if (areOverrideRenderersWired) return;
|
|
868
|
-
areOverrideRenderersWired = true;
|
|
869
|
-
onRendererInject((renderer) => {
|
|
870
|
-
overrideRenderers.add(renderer);
|
|
871
|
-
});
|
|
872
|
-
};
|
|
873
|
-
|
|
874
|
-
const getRootRenderer = (fiber: Fiber): ReactRenderer | null => {
|
|
875
|
-
if (!hasRDTHook()) return null;
|
|
876
|
-
let hostRootFiber = fiber;
|
|
877
|
-
while (hostRootFiber.return) {
|
|
878
|
-
hostRootFiber = hostRootFiber.return;
|
|
879
|
-
}
|
|
880
|
-
const rendererId = rootRendererIds.get(hostRootFiber.stateNode);
|
|
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
|
-
): ValueWrite[] => {
|
|
944
|
-
if (!isPOJO(maybePOJO)) {
|
|
945
|
-
return [{ path: basePath, value: maybePOJO }];
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
const paths: ValueWrite[] = [];
|
|
949
|
-
|
|
950
|
-
for (const key in maybePOJO) {
|
|
951
|
-
const value = maybePOJO[key];
|
|
952
|
-
const path = basePath.concat(key);
|
|
953
|
-
|
|
954
|
-
if (isPOJO(value)) {
|
|
955
|
-
paths.push(...buildPathsFromValue(value, path));
|
|
956
|
-
} else {
|
|
957
|
-
paths.push({ path, value });
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
return paths;
|
|
962
|
-
};
|
|
963
|
-
|
|
964
|
-
const buildValueWrites = (partialValue: unknown): ValueWrite[] =>
|
|
965
|
-
isPOJO(partialValue) ? buildPathsFromValue(partialValue) : [{ path: [], value: partialValue }];
|
|
966
|
-
|
|
967
|
-
export const overrideProps = (fiber: Fiber, partialValue: Record<string, unknown>) => {
|
|
968
|
-
const renderers = resolveOverrideRenderers(fiber);
|
|
969
|
-
for (const { path, value } of buildValueWrites(partialValue)) {
|
|
970
|
-
applyPropsOverride(renderers, fiber, path, value);
|
|
971
|
-
}
|
|
972
|
-
};
|
|
973
|
-
|
|
974
|
-
export const overrideHookState = (fiber: Fiber, id: number, partialValue: unknown) => {
|
|
975
|
-
const renderers = resolveOverrideRenderers(fiber).filter((renderer) =>
|
|
976
|
-
Boolean(renderer.overrideHookState),
|
|
977
|
-
);
|
|
978
|
-
const writes = buildValueWrites(partialValue);
|
|
979
|
-
|
|
980
|
-
if (renderers.length > 0) {
|
|
981
|
-
for (const renderer of renderers) {
|
|
982
|
-
for (const { path, value } of writes) {
|
|
983
|
-
try {
|
|
984
|
-
renderer.overrideHookState?.(fiber, id, path, value);
|
|
985
|
-
} catch {}
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
return;
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
// production renderers don't expose overrideHookState; dispatching through
|
|
992
|
-
// the hook's own queue still works there, but only for whole-value writes
|
|
993
|
-
// (a path write through dispatch would replace the entire hook state)
|
|
994
|
-
if (isPOJO(partialValue)) return;
|
|
995
|
-
const dispatch = getHookStateDispatch(fiber, id);
|
|
996
|
-
if (!dispatch) return;
|
|
997
|
-
try {
|
|
998
|
-
dispatch(partialValue);
|
|
999
|
-
} catch {}
|
|
1000
|
-
};
|
|
1001
|
-
|
|
1002
|
-
export const overrideContext = (fiber: Fiber, contextType: unknown, partialValue: unknown) => {
|
|
1003
|
-
const providerFiber = findContextProviderFiber(fiber, contextType);
|
|
1004
|
-
if (!providerFiber) return;
|
|
1005
|
-
const renderers = resolveOverrideRenderers(providerFiber);
|
|
1006
|
-
for (const { path, value } of buildValueWrites(partialValue)) {
|
|
1007
|
-
applyPropsOverride(renderers, providerFiber, ["value", ...path], value);
|
|
1008
|
-
if (providerFiber.alternate) {
|
|
1009
|
-
applyPropsOverride(renderers, providerFiber.alternate, ["value", ...path], value);
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
};
|
|
1013
|
-
|
|
1014
628
|
export interface InstrumentationOptions {
|
|
1015
629
|
name?: string;
|
|
1016
630
|
onActive?: () => unknown;
|
|
@@ -1031,19 +645,6 @@ interface InstrumentationSubscription {
|
|
|
1031
645
|
|
|
1032
646
|
const instrumentationSubscriptions = new Set<InstrumentationSubscription>();
|
|
1033
647
|
|
|
1034
|
-
const runInstrumentationCallback = (
|
|
1035
|
-
instrumentationName: string,
|
|
1036
|
-
callbackName: string,
|
|
1037
|
-
callback: () => unknown,
|
|
1038
|
-
): void =>
|
|
1039
|
-
runWithBippyError(
|
|
1040
|
-
callback,
|
|
1041
|
-
(cause) => new BippyInstrumentationError(instrumentationName, callbackName, cause),
|
|
1042
|
-
);
|
|
1043
|
-
|
|
1044
|
-
const runReactDevToolsCallback = (callbackName: string, callback: () => unknown): void =>
|
|
1045
|
-
runWithBippyError(callback, (cause) => new BippyReactDevToolsError(callbackName, cause));
|
|
1046
|
-
|
|
1047
648
|
interface HookDispatchers {
|
|
1048
649
|
onCommitFiberRoot: ReactDevToolsGlobalHook["onCommitFiberRoot"];
|
|
1049
650
|
onCommitFiberUnmount: ReactDevToolsGlobalHook["onCommitFiberUnmount"];
|
|
@@ -1054,8 +655,6 @@ interface HookDispatchers {
|
|
|
1054
655
|
const hookDispatchers = new WeakMap<ReactDevToolsGlobalHook, Partial<HookDispatchers>>();
|
|
1055
656
|
let didSubscribeToHookReplacements = false;
|
|
1056
657
|
|
|
1057
|
-
const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
1058
|
-
|
|
1059
658
|
// each hook event is dispatched from a single re-installable wrapper. If
|
|
1060
659
|
// something overwrites the hook method (devtools, direct assignment), the
|
|
1061
660
|
// next instrument() call installs a fresh wrapper over it; a superseded
|
|
@@ -1077,9 +676,7 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1077
676
|
didError,
|
|
1078
677
|
) => {
|
|
1079
678
|
if (prevOnCommitFiberRoot) {
|
|
1080
|
-
|
|
1081
|
-
prevOnCommitFiberRoot(rendererID, root, priority, didError),
|
|
1082
|
-
);
|
|
679
|
+
prevOnCommitFiberRoot.call(rdtHook, rendererID, root, priority, didError);
|
|
1083
680
|
}
|
|
1084
681
|
if (hookDispatchers.get(rdtHook)?.onCommitFiberRoot !== dispatchCommitFiberRoot) return;
|
|
1085
682
|
setReactWorkTagsForFiber(root.current, rdtHook.renderers.get(rendererID));
|
|
@@ -1097,11 +694,7 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1097
694
|
}
|
|
1098
695
|
for (const { options } of instrumentationSubscriptions) {
|
|
1099
696
|
if (options.onCommitFiberRoot) {
|
|
1100
|
-
|
|
1101
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1102
|
-
"onCommitFiberRoot",
|
|
1103
|
-
() => options.onCommitFiberRoot?.(rendererID, root, priority, didError),
|
|
1104
|
-
);
|
|
697
|
+
options.onCommitFiberRoot(rendererID, root, priority, didError);
|
|
1105
698
|
}
|
|
1106
699
|
}
|
|
1107
700
|
};
|
|
@@ -1120,20 +713,14 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1120
713
|
) => {
|
|
1121
714
|
setReactWorkTagsForFiber(fiber, rdtHook.renderers.get(rendererID));
|
|
1122
715
|
if (prevOnCommitFiberUnmount) {
|
|
1123
|
-
|
|
1124
|
-
prevOnCommitFiberUnmount(rendererID, fiber),
|
|
1125
|
-
);
|
|
716
|
+
prevOnCommitFiberUnmount.call(rdtHook, rendererID, fiber);
|
|
1126
717
|
}
|
|
1127
718
|
if (hookDispatchers.get(rdtHook)?.onCommitFiberUnmount !== dispatchCommitFiberUnmount) {
|
|
1128
719
|
return;
|
|
1129
720
|
}
|
|
1130
721
|
for (const { options } of instrumentationSubscriptions) {
|
|
1131
722
|
if (options.onCommitFiberUnmount) {
|
|
1132
|
-
|
|
1133
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1134
|
-
"onCommitFiberUnmount",
|
|
1135
|
-
() => options.onCommitFiberUnmount?.(rendererID, fiber),
|
|
1136
|
-
);
|
|
723
|
+
options.onCommitFiberUnmount(rendererID, fiber);
|
|
1137
724
|
}
|
|
1138
725
|
}
|
|
1139
726
|
};
|
|
@@ -1151,20 +738,14 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1151
738
|
root,
|
|
1152
739
|
) => {
|
|
1153
740
|
if (prevOnPostCommitFiberRoot) {
|
|
1154
|
-
|
|
1155
|
-
prevOnPostCommitFiberRoot(rendererID, root),
|
|
1156
|
-
);
|
|
741
|
+
prevOnPostCommitFiberRoot.call(rdtHook, rendererID, root);
|
|
1157
742
|
}
|
|
1158
743
|
if (hookDispatchers.get(rdtHook)?.onPostCommitFiberRoot !== dispatchPostCommitFiberRoot) {
|
|
1159
744
|
return;
|
|
1160
745
|
}
|
|
1161
746
|
for (const { options } of instrumentationSubscriptions) {
|
|
1162
747
|
if (options.onPostCommitFiberRoot) {
|
|
1163
|
-
|
|
1164
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1165
|
-
"onPostCommitFiberRoot",
|
|
1166
|
-
() => options.onPostCommitFiberRoot?.(rendererID, root),
|
|
1167
|
-
);
|
|
748
|
+
options.onPostCommitFiberRoot(rendererID, root);
|
|
1168
749
|
}
|
|
1169
750
|
}
|
|
1170
751
|
};
|
|
@@ -1183,18 +764,12 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1183
764
|
children,
|
|
1184
765
|
) => {
|
|
1185
766
|
if (prevOnScheduleFiberRoot) {
|
|
1186
|
-
|
|
1187
|
-
prevOnScheduleFiberRoot(rendererID, root, children),
|
|
1188
|
-
);
|
|
767
|
+
prevOnScheduleFiberRoot.call(rdtHook, rendererID, root, children);
|
|
1189
768
|
}
|
|
1190
769
|
if (hookDispatchers.get(rdtHook)?.onScheduleFiberRoot !== dispatchScheduleFiberRoot) return;
|
|
1191
770
|
for (const { options } of instrumentationSubscriptions) {
|
|
1192
771
|
if (options.onScheduleFiberRoot) {
|
|
1193
|
-
|
|
1194
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1195
|
-
"onScheduleFiberRoot",
|
|
1196
|
-
() => options.onScheduleFiberRoot?.(rendererID, root, children),
|
|
1197
|
-
);
|
|
772
|
+
options.onScheduleFiberRoot(rendererID, root, children);
|
|
1198
773
|
}
|
|
1199
774
|
}
|
|
1200
775
|
};
|
|
@@ -1203,13 +778,24 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1203
778
|
}
|
|
1204
779
|
};
|
|
1205
780
|
|
|
781
|
+
const wireHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
782
|
+
if (!didSubscribeToHookReplacements) {
|
|
783
|
+
onRDTHookReplace(setHookEventDispatchers);
|
|
784
|
+
didSubscribeToHookReplacements = true;
|
|
785
|
+
}
|
|
786
|
+
setHookEventDispatchers(rdtHook);
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
if (hasRDTHook()) {
|
|
790
|
+
wireHookEventDispatchers(getRDTHook());
|
|
791
|
+
}
|
|
792
|
+
|
|
1206
793
|
/**
|
|
1207
794
|
* Instruments the DevTools hook. Each hook event is patched once and
|
|
1208
795
|
* dispatches to a set of listeners, so multiple `instrument` calls compose
|
|
1209
796
|
* without stacking patches. Returns an unsubscribe function that removes
|
|
1210
797
|
* exactly the handlers this call registered.
|
|
1211
|
-
* The
|
|
1212
|
-
* bippy subscriptions through `using`.
|
|
798
|
+
* The unsubscribe function can also be disposed through `using`.
|
|
1213
799
|
* @example
|
|
1214
800
|
* const unsubscribe = instrument({
|
|
1215
801
|
* onActive() {
|
|
@@ -1222,30 +808,15 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1222
808
|
* unsubscribe();
|
|
1223
809
|
*/
|
|
1224
810
|
export const instrument = (options: InstrumentationOptions): Unsubscribe => {
|
|
1225
|
-
const
|
|
1226
|
-
const onActive = onActiveListener
|
|
1227
|
-
? () =>
|
|
1228
|
-
runInstrumentationCallback(
|
|
1229
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1230
|
-
"onActive",
|
|
1231
|
-
onActiveListener,
|
|
1232
|
-
)
|
|
1233
|
-
: undefined;
|
|
1234
|
-
const rdtHook = getRDTHook(onActive);
|
|
1235
|
-
|
|
1236
|
-
if (!didSubscribeToHookReplacements) {
|
|
1237
|
-
onRDTHookReplace(setHookEventDispatchers);
|
|
1238
|
-
didSubscribeToHookReplacements = true;
|
|
1239
|
-
}
|
|
1240
|
-
|
|
811
|
+
const rdtHook = getRDTHook(options.onActive);
|
|
1241
812
|
rdtHook._instrumentationSource = options.name ?? BIPPY_INSTRUMENTATION_STRING;
|
|
1242
813
|
|
|
1243
|
-
|
|
814
|
+
wireHookEventDispatchers(rdtHook);
|
|
1244
815
|
const subscription: InstrumentationSubscription = { options };
|
|
1245
816
|
instrumentationSubscriptions.add(subscription);
|
|
1246
817
|
|
|
1247
|
-
return
|
|
1248
|
-
if (onActive) _onActiveListeners.delete(onActive);
|
|
818
|
+
return createUnsubscribe(() => {
|
|
819
|
+
if (options.onActive) _onActiveListeners.delete(options.onActive);
|
|
1249
820
|
instrumentationSubscriptions.delete(subscription);
|
|
1250
821
|
});
|
|
1251
822
|
};
|
|
@@ -1258,33 +829,38 @@ const isFiberPropertyKey = (key: string): boolean =>
|
|
|
1258
829
|
key.startsWith("__reactInternalInstance$") ||
|
|
1259
830
|
key.startsWith("__reactFiber");
|
|
1260
831
|
|
|
1261
|
-
const getLegacyRootFiber = (hostInstance:
|
|
1262
|
-
const reactRootContainer = hostInstance
|
|
1263
|
-
if (
|
|
1264
|
-
const internalRoot = reactRootContainer
|
|
1265
|
-
if (
|
|
1266
|
-
const current = internalRoot
|
|
1267
|
-
if (
|
|
1268
|
-
const child = current
|
|
832
|
+
const getLegacyRootFiber = (hostInstance: object): Fiber | null => {
|
|
833
|
+
const reactRootContainer = Reflect.get(hostInstance, "_reactRootContainer");
|
|
834
|
+
if (typeof reactRootContainer !== "object" || reactRootContainer === null) return null;
|
|
835
|
+
const internalRoot = Reflect.get(reactRootContainer, "_internalRoot");
|
|
836
|
+
if (typeof internalRoot !== "object" || internalRoot === null) return null;
|
|
837
|
+
const current = Reflect.get(internalRoot, "current");
|
|
838
|
+
if (typeof current !== "object" || current === null) return null;
|
|
839
|
+
const child = Reflect.get(current, "child");
|
|
1269
840
|
return isValidFiber(child) ? child : null;
|
|
1270
841
|
};
|
|
1271
842
|
|
|
1272
|
-
const getInternalInstanceHandle = (hostInstance:
|
|
843
|
+
const getInternalInstanceHandle = (hostInstance: object): Fiber | null => {
|
|
1273
844
|
const internalInstanceHandle =
|
|
1274
|
-
hostInstance
|
|
845
|
+
Reflect.get(hostInstance, "__internalInstanceHandle") ??
|
|
846
|
+
Reflect.get(hostInstance, "_internalInstanceHandle");
|
|
1275
847
|
return isValidFiber(internalInstanceHandle) ? internalInstanceHandle : null;
|
|
1276
848
|
};
|
|
1277
849
|
|
|
1278
850
|
const getPublicHostInstance = (stateNode: unknown): unknown => {
|
|
1279
|
-
if (
|
|
1280
|
-
const canonical = stateNode
|
|
1281
|
-
if (
|
|
1282
|
-
|
|
851
|
+
if (typeof stateNode !== "object" || stateNode === null) return stateNode;
|
|
852
|
+
const canonical = Reflect.get(stateNode, "canonical");
|
|
853
|
+
if (typeof canonical === "object" && canonical !== null) {
|
|
854
|
+
const publicInstance = Reflect.get(canonical, "publicInstance");
|
|
855
|
+
if (typeof publicInstance === "object" && publicInstance !== null) {
|
|
856
|
+
return publicInstance;
|
|
857
|
+
}
|
|
1283
858
|
}
|
|
1284
|
-
|
|
859
|
+
const nativeTag = Reflect.get(stateNode, "_nativeTag");
|
|
860
|
+
return typeof nativeTag === "number" ? nativeTag : stateNode;
|
|
1285
861
|
};
|
|
1286
862
|
|
|
1287
|
-
export const
|
|
863
|
+
export const getFiber = <T>(hostInstance: T): Fiber | null => {
|
|
1288
864
|
const rdtHook = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
1289
865
|
if (rdtHook?.renderers) {
|
|
1290
866
|
for (const renderer of rdtHook.renderers.values()) {
|
|
@@ -1295,7 +871,7 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1295
871
|
}
|
|
1296
872
|
}
|
|
1297
873
|
|
|
1298
|
-
if (
|
|
874
|
+
if (typeof hostInstance === "object" && hostInstance !== null) {
|
|
1299
875
|
const legacyRootFiber = getLegacyRootFiber(hostInstance);
|
|
1300
876
|
if (legacyRootFiber) return legacyRootFiber;
|
|
1301
877
|
|
|
@@ -1303,14 +879,14 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1303
879
|
if (internalInstanceHandle) return internalInstanceHandle;
|
|
1304
880
|
|
|
1305
881
|
for (const knownKey of knownFiberPropertyKeys) {
|
|
1306
|
-
const fiber = hostInstance
|
|
882
|
+
const fiber = Reflect.get(hostInstance, knownKey);
|
|
1307
883
|
if (isValidFiber(fiber)) return fiber;
|
|
1308
884
|
}
|
|
1309
885
|
|
|
1310
886
|
for (const key of Object.keys(hostInstance)) {
|
|
1311
887
|
if (isFiberPropertyKey(key)) {
|
|
1312
888
|
knownFiberPropertyKeys.add(key);
|
|
1313
|
-
const fiber = hostInstance
|
|
889
|
+
const fiber = Reflect.get(hostInstance, key);
|
|
1314
890
|
if (isValidFiber(fiber)) return fiber;
|
|
1315
891
|
}
|
|
1316
892
|
}
|
|
@@ -1334,6 +910,8 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1334
910
|
return null;
|
|
1335
911
|
};
|
|
1336
912
|
|
|
913
|
+
export const getFiberFromHostInstance = getFiber;
|
|
914
|
+
|
|
1337
915
|
export {
|
|
1338
916
|
BIPPY_INSTRUMENTATION_STRING,
|
|
1339
917
|
_onActiveListeners,
|
|
@@ -1344,8 +922,7 @@ export {
|
|
|
1344
922
|
isRealReactDevtools,
|
|
1345
923
|
onRendererInject,
|
|
1346
924
|
patchRDTHook,
|
|
1347
|
-
safelyInstallRDTHook,
|
|
1348
925
|
version,
|
|
1349
926
|
} from "./rdt-hook.js";
|
|
1350
|
-
export
|
|
1351
|
-
export
|
|
927
|
+
export type { Unsubscribe } from "./rdt-hook.js";
|
|
928
|
+
export * from "./react-internals/index.js";
|