bippy 0.6.1-dev.d7876ea → 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/LICENSE +1 -1
- package/README.md +211 -445
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +25 -75
- package/dist/core.d.ts +25 -75
- 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 +146 -579
- 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,14 +64,13 @@ 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.
|
|
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 &&
|
|
@@ -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
|
+
isFiber(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
|
*
|
|
@@ -155,100 +123,6 @@ export const isCompositeFiber = (fiber: Fiber): boolean => {
|
|
|
155
123
|
}
|
|
156
124
|
};
|
|
157
125
|
|
|
158
|
-
/**
|
|
159
|
-
* Returns `true` if the object is a {@link Fiber}
|
|
160
|
-
*/
|
|
161
|
-
export const isFiber = (maybeFiber: unknown): maybeFiber is Fiber => {
|
|
162
|
-
if (!maybeFiber || typeof maybeFiber !== "object") return false;
|
|
163
|
-
// this is a fast check. pendingProps will ALWAYS exist in fiber
|
|
164
|
-
// `containerInfo` is in FiberRootNode, not FiberNode
|
|
165
|
-
return "pendingProps" in maybeFiber && !("containerInfo" in maybeFiber);
|
|
166
|
-
};
|
|
167
|
-
|
|
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
126
|
/**
|
|
253
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.
|
|
254
128
|
*/
|
|
@@ -288,47 +162,6 @@ export const didFiberCommit = (fiber: Fiber): boolean => {
|
|
|
288
162
|
);
|
|
289
163
|
};
|
|
290
164
|
|
|
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
165
|
/**
|
|
333
166
|
* Returns `true` if the {@link Fiber} should be filtered out during reconciliation.
|
|
334
167
|
*/
|
|
@@ -377,47 +210,6 @@ const shouldFilterFiber = (fiber: Fiber): boolean => {
|
|
|
377
210
|
}
|
|
378
211
|
};
|
|
379
212
|
|
|
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
213
|
/**
|
|
422
214
|
* Traverses up or down a {@link Fiber}, return `true` to stop and select a node.
|
|
423
215
|
*/
|
|
@@ -431,6 +223,11 @@ export function traverseFiber(
|
|
|
431
223
|
selector: (node: Fiber) => Promise<boolean | void>,
|
|
432
224
|
ascending?: boolean,
|
|
433
225
|
): Promise<Fiber | null>;
|
|
226
|
+
export function traverseFiber(
|
|
227
|
+
fiber: Fiber | null,
|
|
228
|
+
selector: FiberSelector,
|
|
229
|
+
ascending?: boolean,
|
|
230
|
+
): Fiber | null | Promise<Fiber | null>;
|
|
434
231
|
export function traverseFiber(
|
|
435
232
|
fiber: Fiber | null,
|
|
436
233
|
selector: FiberSelector,
|
|
@@ -438,89 +235,47 @@ export function traverseFiber(
|
|
|
438
235
|
): Fiber | null | Promise<Fiber | null> {
|
|
439
236
|
if (!fiber) return null;
|
|
440
237
|
|
|
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
|
-
})();
|
|
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
|
+
);
|
|
454
243
|
}
|
|
244
|
+
if (selection === true) return fiber;
|
|
455
245
|
|
|
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;
|
|
246
|
+
return traverseFiberChildren(fiber, selector, ascending);
|
|
465
247
|
}
|
|
466
248
|
|
|
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;
|
|
249
|
+
const isPromiseLike = <Result>(value: unknown): value is PromiseLike<Result> =>
|
|
250
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
251
|
+
value !== null &&
|
|
252
|
+
"then" in value &&
|
|
253
|
+
typeof value.then === "function";
|
|
481
254
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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);
|
|
485
262
|
};
|
|
486
263
|
|
|
487
|
-
const
|
|
264
|
+
const traverseFiberSiblings = (
|
|
488
265
|
fiber: Fiber | null,
|
|
489
266
|
selector: FiberSelector,
|
|
490
|
-
ascending
|
|
491
|
-
): Promise<Fiber | null> => {
|
|
267
|
+
ascending: boolean,
|
|
268
|
+
): Fiber | null | Promise<Fiber | null> => {
|
|
492
269
|
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
270
|
|
|
500
|
-
|
|
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
|
+
);
|
|
501
277
|
}
|
|
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 };
|
|
278
|
+
return match ?? traverseFiberSiblings(nextSibling, selector, ascending);
|
|
524
279
|
};
|
|
525
280
|
|
|
526
281
|
/**
|
|
@@ -535,8 +290,8 @@ export const hasMemoCache = (fiber: Fiber): boolean => {
|
|
|
535
290
|
*/
|
|
536
291
|
export const getType = (type: unknown): null | React.ComponentType<unknown> => {
|
|
537
292
|
if (isComponentType(type)) return type;
|
|
538
|
-
if (
|
|
539
|
-
return getType(
|
|
293
|
+
if (typeof type !== "object" || type === null) return null;
|
|
294
|
+
return getType(Reflect.get(type, "type") ?? Reflect.get(type, "render"));
|
|
540
295
|
};
|
|
541
296
|
|
|
542
297
|
/**
|
|
@@ -576,6 +331,7 @@ export const isInstrumentationActive = (): boolean => {
|
|
|
576
331
|
};
|
|
577
332
|
|
|
578
333
|
export const _fiberRoots = new Set<FiberRoot>();
|
|
334
|
+
const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
579
335
|
|
|
580
336
|
/**
|
|
581
337
|
* Returns the latest fiber (since it may be double-buffered).
|
|
@@ -588,13 +344,32 @@ export const getLatestFiber = (fiber: Fiber): Fiber => {
|
|
|
588
344
|
}
|
|
589
345
|
for (const root of _fiberRoots) {
|
|
590
346
|
const latestFiber = traverseFiber(root.current, (innerFiber) => {
|
|
591
|
-
if (innerFiber === fiber) return true;
|
|
347
|
+
if (innerFiber === fiber || innerFiber === alternate) return true;
|
|
592
348
|
});
|
|
593
349
|
if (latestFiber) return latestFiber;
|
|
594
350
|
}
|
|
595
351
|
return fiber;
|
|
596
352
|
};
|
|
597
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
|
+
|
|
598
373
|
export type RenderPhase = "mount" | "unmount" | "update";
|
|
599
374
|
|
|
600
375
|
let nextFiberId = 0;
|
|
@@ -602,6 +377,9 @@ const fiberIdMap = new WeakMap<Fiber, number>();
|
|
|
602
377
|
|
|
603
378
|
export const setFiberId = (fiber: Fiber, fiberId: number = nextFiberId++): void => {
|
|
604
379
|
fiberIdMap.set(fiber, fiberId);
|
|
380
|
+
if (Number.isSafeInteger(fiberId) && fiberId >= nextFiberId) {
|
|
381
|
+
nextFiberId = fiberId + 1;
|
|
382
|
+
}
|
|
605
383
|
};
|
|
606
384
|
|
|
607
385
|
export const getFiberId = (fiber: Fiber): number => {
|
|
@@ -624,9 +402,7 @@ const mountFiberRecursively = (
|
|
|
624
402
|
let fiber: Fiber | null = firstChild;
|
|
625
403
|
|
|
626
404
|
while (fiber !== null) {
|
|
627
|
-
|
|
628
|
-
getFiberId(fiber);
|
|
629
|
-
}
|
|
405
|
+
getFiberId(fiber);
|
|
630
406
|
const shouldIncludeInTree = !shouldFilterFiber(fiber);
|
|
631
407
|
if (shouldIncludeInTree && didFiberRender(fiber)) {
|
|
632
408
|
onRender(fiber, "mount");
|
|
@@ -662,16 +438,11 @@ const mountFiberRecursively = (
|
|
|
662
438
|
const updateFiberRecursively = (
|
|
663
439
|
onRender: RenderHandler,
|
|
664
440
|
nextFiber: Fiber,
|
|
665
|
-
prevFiber: Fiber,
|
|
666
|
-
parentFiber: Fiber | null,
|
|
441
|
+
prevFiber: Fiber | null,
|
|
667
442
|
): void => {
|
|
668
|
-
|
|
669
|
-
getFiberId(nextFiber);
|
|
670
|
-
}
|
|
443
|
+
getFiberId(nextFiber);
|
|
671
444
|
if (!prevFiber) return;
|
|
672
|
-
|
|
673
|
-
getFiberId(prevFiber);
|
|
674
|
-
}
|
|
445
|
+
getFiberId(prevFiber);
|
|
675
446
|
|
|
676
447
|
const isSuspense = nextFiber.tag === getReactWorkTagsForFiber(nextFiber).SuspenseComponent;
|
|
677
448
|
|
|
@@ -702,7 +473,7 @@ const updateFiberRecursively = (
|
|
|
702
473
|
const prevFallbackChildSet = prevFiber.child?.sibling ?? null;
|
|
703
474
|
|
|
704
475
|
if (nextFallbackChildSet !== null && prevFallbackChildSet !== null) {
|
|
705
|
-
updateFiberRecursively(onRender, nextFallbackChildSet, prevFallbackChildSet
|
|
476
|
+
updateFiberRecursively(onRender, nextFallbackChildSet, prevFallbackChildSet);
|
|
706
477
|
}
|
|
707
478
|
} else if (prevDidTimeout && !nextDidTimeOut) {
|
|
708
479
|
// Fallback -> Primary:
|
|
@@ -741,14 +512,7 @@ const updateFiberRecursively = (
|
|
|
741
512
|
// Schedule updates and mounts depending on whether alternates exist.
|
|
742
513
|
// We don't track deletions here because they are reported separately.
|
|
743
514
|
if (nextChild.alternate) {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
updateFiberRecursively(
|
|
747
|
-
onRender,
|
|
748
|
-
nextChild,
|
|
749
|
-
prevChild,
|
|
750
|
-
shouldIncludeInTree ? nextFiber : parentFiber,
|
|
751
|
-
);
|
|
515
|
+
updateFiberRecursively(onRender, nextChild, nextChild.alternate);
|
|
752
516
|
} else {
|
|
753
517
|
mountFiberRecursively(onRender, nextChild, false);
|
|
754
518
|
}
|
|
@@ -794,11 +558,9 @@ const unmountFiberChildrenRecursively = (onRender: RenderHandler, fiber: Fiber):
|
|
|
794
558
|
}
|
|
795
559
|
};
|
|
796
560
|
|
|
797
|
-
let commitId = 0;
|
|
798
561
|
const rootInstanceMap = new WeakMap<
|
|
799
|
-
FiberRoot,
|
|
562
|
+
Fiber | FiberRoot,
|
|
800
563
|
{
|
|
801
|
-
id: number;
|
|
802
564
|
prevFiber: Fiber | null;
|
|
803
565
|
}
|
|
804
566
|
>();
|
|
@@ -810,23 +572,23 @@ const rootInstanceMap = new WeakMap<
|
|
|
810
572
|
* console.log(phase)
|
|
811
573
|
* })
|
|
812
574
|
*/
|
|
813
|
-
export const traverseRenderedFibers = (root: FiberRoot, onRender: RenderHandler): void => {
|
|
575
|
+
export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: RenderHandler): void => {
|
|
814
576
|
const fiber = "current" in root ? root.current : root;
|
|
815
577
|
|
|
816
578
|
let rootInstance = rootInstanceMap.get(root);
|
|
817
579
|
|
|
818
580
|
if (!rootInstance) {
|
|
819
|
-
rootInstance = {
|
|
581
|
+
rootInstance = { prevFiber: null };
|
|
820
582
|
rootInstanceMap.set(root, rootInstance);
|
|
821
583
|
}
|
|
822
584
|
|
|
823
585
|
const { prevFiber } = rootInstance;
|
|
824
|
-
// if fiberRoot don't have current instance, means it's been unmounted
|
|
825
586
|
if (!fiber) {
|
|
826
|
-
|
|
587
|
+
if (prevFiber) {
|
|
588
|
+
unmountFiber(onRender, prevFiber);
|
|
589
|
+
}
|
|
827
590
|
} else if (prevFiber !== null) {
|
|
828
591
|
const wasMounted =
|
|
829
|
-
prevFiber &&
|
|
830
592
|
prevFiber.memoizedState !== null &&
|
|
831
593
|
prevFiber.memoizedState.element !== null &&
|
|
832
594
|
prevFiber.memoizedState.element !== undefined &&
|
|
@@ -842,7 +604,7 @@ export const traverseRenderedFibers = (root: FiberRoot, onRender: RenderHandler)
|
|
|
842
604
|
if (!wasMounted && isMounted) {
|
|
843
605
|
mountFiberRecursively(onRender, fiber, false);
|
|
844
606
|
} else if (wasMounted && isMounted) {
|
|
845
|
-
updateFiberRecursively(onRender, fiber, fiber.alternate
|
|
607
|
+
updateFiberRecursively(onRender, fiber, fiber.alternate);
|
|
846
608
|
} else if (wasMounted && !isMounted) {
|
|
847
609
|
unmountFiber(onRender, fiber);
|
|
848
610
|
}
|
|
@@ -853,164 +615,6 @@ export const traverseRenderedFibers = (root: FiberRoot, onRender: RenderHandler)
|
|
|
853
615
|
rootInstance.prevFiber = fiber;
|
|
854
616
|
};
|
|
855
617
|
|
|
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
618
|
export interface InstrumentationOptions {
|
|
1015
619
|
name?: string;
|
|
1016
620
|
onActive?: () => unknown;
|
|
@@ -1031,19 +635,6 @@ interface InstrumentationSubscription {
|
|
|
1031
635
|
|
|
1032
636
|
const instrumentationSubscriptions = new Set<InstrumentationSubscription>();
|
|
1033
637
|
|
|
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
638
|
interface HookDispatchers {
|
|
1048
639
|
onCommitFiberRoot: ReactDevToolsGlobalHook["onCommitFiberRoot"];
|
|
1049
640
|
onCommitFiberUnmount: ReactDevToolsGlobalHook["onCommitFiberUnmount"];
|
|
@@ -1054,8 +645,6 @@ interface HookDispatchers {
|
|
|
1054
645
|
const hookDispatchers = new WeakMap<ReactDevToolsGlobalHook, Partial<HookDispatchers>>();
|
|
1055
646
|
let didSubscribeToHookReplacements = false;
|
|
1056
647
|
|
|
1057
|
-
const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
1058
|
-
|
|
1059
648
|
// each hook event is dispatched from a single re-installable wrapper. If
|
|
1060
649
|
// something overwrites the hook method (devtools, direct assignment), the
|
|
1061
650
|
// next instrument() call installs a fresh wrapper over it; a superseded
|
|
@@ -1077,9 +666,7 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1077
666
|
didError,
|
|
1078
667
|
) => {
|
|
1079
668
|
if (prevOnCommitFiberRoot) {
|
|
1080
|
-
|
|
1081
|
-
prevOnCommitFiberRoot(rendererID, root, priority, didError),
|
|
1082
|
-
);
|
|
669
|
+
prevOnCommitFiberRoot.call(rdtHook, rendererID, root, priority, didError);
|
|
1083
670
|
}
|
|
1084
671
|
if (hookDispatchers.get(rdtHook)?.onCommitFiberRoot !== dispatchCommitFiberRoot) return;
|
|
1085
672
|
setReactWorkTagsForFiber(root.current, rdtHook.renderers.get(rendererID));
|
|
@@ -1097,11 +684,7 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1097
684
|
}
|
|
1098
685
|
for (const { options } of instrumentationSubscriptions) {
|
|
1099
686
|
if (options.onCommitFiberRoot) {
|
|
1100
|
-
|
|
1101
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1102
|
-
"onCommitFiberRoot",
|
|
1103
|
-
() => options.onCommitFiberRoot?.(rendererID, root, priority, didError),
|
|
1104
|
-
);
|
|
687
|
+
options.onCommitFiberRoot(rendererID, root, priority, didError);
|
|
1105
688
|
}
|
|
1106
689
|
}
|
|
1107
690
|
};
|
|
@@ -1120,20 +703,14 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1120
703
|
) => {
|
|
1121
704
|
setReactWorkTagsForFiber(fiber, rdtHook.renderers.get(rendererID));
|
|
1122
705
|
if (prevOnCommitFiberUnmount) {
|
|
1123
|
-
|
|
1124
|
-
prevOnCommitFiberUnmount(rendererID, fiber),
|
|
1125
|
-
);
|
|
706
|
+
prevOnCommitFiberUnmount.call(rdtHook, rendererID, fiber);
|
|
1126
707
|
}
|
|
1127
708
|
if (hookDispatchers.get(rdtHook)?.onCommitFiberUnmount !== dispatchCommitFiberUnmount) {
|
|
1128
709
|
return;
|
|
1129
710
|
}
|
|
1130
711
|
for (const { options } of instrumentationSubscriptions) {
|
|
1131
712
|
if (options.onCommitFiberUnmount) {
|
|
1132
|
-
|
|
1133
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1134
|
-
"onCommitFiberUnmount",
|
|
1135
|
-
() => options.onCommitFiberUnmount?.(rendererID, fiber),
|
|
1136
|
-
);
|
|
713
|
+
options.onCommitFiberUnmount(rendererID, fiber);
|
|
1137
714
|
}
|
|
1138
715
|
}
|
|
1139
716
|
};
|
|
@@ -1151,20 +728,14 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1151
728
|
root,
|
|
1152
729
|
) => {
|
|
1153
730
|
if (prevOnPostCommitFiberRoot) {
|
|
1154
|
-
|
|
1155
|
-
prevOnPostCommitFiberRoot(rendererID, root),
|
|
1156
|
-
);
|
|
731
|
+
prevOnPostCommitFiberRoot.call(rdtHook, rendererID, root);
|
|
1157
732
|
}
|
|
1158
733
|
if (hookDispatchers.get(rdtHook)?.onPostCommitFiberRoot !== dispatchPostCommitFiberRoot) {
|
|
1159
734
|
return;
|
|
1160
735
|
}
|
|
1161
736
|
for (const { options } of instrumentationSubscriptions) {
|
|
1162
737
|
if (options.onPostCommitFiberRoot) {
|
|
1163
|
-
|
|
1164
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1165
|
-
"onPostCommitFiberRoot",
|
|
1166
|
-
() => options.onPostCommitFiberRoot?.(rendererID, root),
|
|
1167
|
-
);
|
|
738
|
+
options.onPostCommitFiberRoot(rendererID, root);
|
|
1168
739
|
}
|
|
1169
740
|
}
|
|
1170
741
|
};
|
|
@@ -1183,18 +754,12 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1183
754
|
children,
|
|
1184
755
|
) => {
|
|
1185
756
|
if (prevOnScheduleFiberRoot) {
|
|
1186
|
-
|
|
1187
|
-
prevOnScheduleFiberRoot(rendererID, root, children),
|
|
1188
|
-
);
|
|
757
|
+
prevOnScheduleFiberRoot.call(rdtHook, rendererID, root, children);
|
|
1189
758
|
}
|
|
1190
759
|
if (hookDispatchers.get(rdtHook)?.onScheduleFiberRoot !== dispatchScheduleFiberRoot) return;
|
|
1191
760
|
for (const { options } of instrumentationSubscriptions) {
|
|
1192
761
|
if (options.onScheduleFiberRoot) {
|
|
1193
|
-
|
|
1194
|
-
options.name ?? BIPPY_INSTRUMENTATION_STRING,
|
|
1195
|
-
"onScheduleFiberRoot",
|
|
1196
|
-
() => options.onScheduleFiberRoot?.(rendererID, root, children),
|
|
1197
|
-
);
|
|
762
|
+
options.onScheduleFiberRoot(rendererID, root, children);
|
|
1198
763
|
}
|
|
1199
764
|
}
|
|
1200
765
|
};
|
|
@@ -1203,13 +768,24 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1203
768
|
}
|
|
1204
769
|
};
|
|
1205
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
|
+
|
|
1206
783
|
/**
|
|
1207
784
|
* Instruments the DevTools hook. Each hook event is patched once and
|
|
1208
785
|
* dispatches to a set of listeners, so multiple `instrument` calls compose
|
|
1209
786
|
* without stacking patches. Returns an unsubscribe function that removes
|
|
1210
787
|
* exactly the handlers this call registered.
|
|
1211
|
-
* The
|
|
1212
|
-
* bippy subscriptions through `using`.
|
|
788
|
+
* The unsubscribe function can also be disposed through `using`.
|
|
1213
789
|
* @example
|
|
1214
790
|
* const unsubscribe = instrument({
|
|
1215
791
|
* onActive() {
|
|
@@ -1222,30 +798,15 @@ const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
|
1222
798
|
* unsubscribe();
|
|
1223
799
|
*/
|
|
1224
800
|
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
|
-
|
|
801
|
+
const rdtHook = getRDTHook(options.onActive);
|
|
1241
802
|
rdtHook._instrumentationSource = options.name ?? BIPPY_INSTRUMENTATION_STRING;
|
|
1242
803
|
|
|
1243
|
-
|
|
804
|
+
wireHookEventDispatchers(rdtHook);
|
|
1244
805
|
const subscription: InstrumentationSubscription = { options };
|
|
1245
806
|
instrumentationSubscriptions.add(subscription);
|
|
1246
807
|
|
|
1247
|
-
return
|
|
1248
|
-
if (onActive) _onActiveListeners.delete(onActive);
|
|
808
|
+
return createUnsubscribe(() => {
|
|
809
|
+
if (options.onActive) _onActiveListeners.delete(options.onActive);
|
|
1249
810
|
instrumentationSubscriptions.delete(subscription);
|
|
1250
811
|
});
|
|
1251
812
|
};
|
|
@@ -1258,33 +819,38 @@ const isFiberPropertyKey = (key: string): boolean =>
|
|
|
1258
819
|
key.startsWith("__reactInternalInstance$") ||
|
|
1259
820
|
key.startsWith("__reactFiber");
|
|
1260
821
|
|
|
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
|
|
1269
|
-
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;
|
|
1270
831
|
};
|
|
1271
832
|
|
|
1272
|
-
const getInternalInstanceHandle = (hostInstance:
|
|
833
|
+
const getInternalInstanceHandle = (hostInstance: object): Fiber | null => {
|
|
1273
834
|
const internalInstanceHandle =
|
|
1274
|
-
hostInstance
|
|
1275
|
-
|
|
835
|
+
Reflect.get(hostInstance, "__internalInstanceHandle") ??
|
|
836
|
+
Reflect.get(hostInstance, "_internalInstanceHandle");
|
|
837
|
+
return isFiber(internalInstanceHandle) ? internalInstanceHandle : null;
|
|
1276
838
|
};
|
|
1277
839
|
|
|
1278
840
|
const getPublicHostInstance = (stateNode: unknown): unknown => {
|
|
1279
|
-
if (
|
|
1280
|
-
const canonical = stateNode
|
|
1281
|
-
if (
|
|
1282
|
-
|
|
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
|
+
}
|
|
1283
848
|
}
|
|
1284
|
-
|
|
849
|
+
const nativeTag = Reflect.get(stateNode, "_nativeTag");
|
|
850
|
+
return typeof nativeTag === "number" ? nativeTag : stateNode;
|
|
1285
851
|
};
|
|
1286
852
|
|
|
1287
|
-
export const
|
|
853
|
+
export const getFiber = <T>(hostInstance: T): Fiber | null => {
|
|
1288
854
|
const rdtHook = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
1289
855
|
if (rdtHook?.renderers) {
|
|
1290
856
|
for (const renderer of rdtHook.renderers.values()) {
|
|
@@ -1295,7 +861,7 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1295
861
|
}
|
|
1296
862
|
}
|
|
1297
863
|
|
|
1298
|
-
if (
|
|
864
|
+
if (typeof hostInstance === "object" && hostInstance !== null) {
|
|
1299
865
|
const legacyRootFiber = getLegacyRootFiber(hostInstance);
|
|
1300
866
|
if (legacyRootFiber) return legacyRootFiber;
|
|
1301
867
|
|
|
@@ -1303,15 +869,15 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1303
869
|
if (internalInstanceHandle) return internalInstanceHandle;
|
|
1304
870
|
|
|
1305
871
|
for (const knownKey of knownFiberPropertyKeys) {
|
|
1306
|
-
const fiber = hostInstance
|
|
1307
|
-
if (
|
|
872
|
+
const fiber = Reflect.get(hostInstance, knownKey);
|
|
873
|
+
if (isFiber(fiber)) return fiber;
|
|
1308
874
|
}
|
|
1309
875
|
|
|
1310
876
|
for (const key of Object.keys(hostInstance)) {
|
|
1311
877
|
if (isFiberPropertyKey(key)) {
|
|
1312
878
|
knownFiberPropertyKeys.add(key);
|
|
1313
|
-
const fiber = hostInstance
|
|
1314
|
-
if (
|
|
879
|
+
const fiber = Reflect.get(hostInstance, key);
|
|
880
|
+
if (isFiber(fiber)) return fiber;
|
|
1315
881
|
}
|
|
1316
882
|
}
|
|
1317
883
|
}
|
|
@@ -1334,6 +900,8 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1334
900
|
return null;
|
|
1335
901
|
};
|
|
1336
902
|
|
|
903
|
+
export const getFiberFromHostInstance = getFiber;
|
|
904
|
+
|
|
1337
905
|
export {
|
|
1338
906
|
BIPPY_INSTRUMENTATION_STRING,
|
|
1339
907
|
_onActiveListeners,
|
|
@@ -1344,8 +912,7 @@ export {
|
|
|
1344
912
|
isRealReactDevtools,
|
|
1345
913
|
onRendererInject,
|
|
1346
914
|
patchRDTHook,
|
|
1347
|
-
safelyInstallRDTHook,
|
|
1348
915
|
version,
|
|
1349
916
|
} from "./rdt-hook.js";
|
|
1350
|
-
export
|
|
1351
|
-
export
|
|
917
|
+
export type { Unsubscribe } from "./rdt-hook.js";
|
|
918
|
+
export * from "./react-internals/index.js";
|