bippy 0.6.1-dev.3a24abf → 0.6.1-dev.93556ef
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 +26 -1
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +39 -42
- package/dist/core.d.ts +39 -42
- 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/{types.d.cts → errors.d.cts} +187 -68
- package/dist/{types.d.ts → errors.d.ts} +187 -68
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.iife.js +1 -1
- 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.iife.js +1 -1
- package/dist/install-hook-only.js +1 -1
- package/dist/rdt-hook.cjs +1 -1
- package/dist/rdt-hook.js +1 -1
- package/dist/source.cjs +13 -14
- package/dist/source.d.cts +86 -69
- package/dist/source.d.ts +86 -69
- package/dist/source.js +13 -14
- package/package.json +10 -6
- package/src/core.ts +246 -293
- package/src/errors.ts +34 -0
- package/src/install-hook-only.ts +2 -2
- package/src/rdt-hook.ts +152 -110
- package/src/react-internals/generated/react-work-tags.ts +318 -0
- package/src/react-internals/index.ts +67 -0
- package/src/react-internals/semver.ts +80 -0
- package/src/{types.ts → react-internals/types.ts} +13 -86
- package/src/source/error-stack.ts +11 -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 +11 -1
- package/src/source/inspect-hooks.ts +220 -207
- package/src/source/owner-stack.ts +86 -128
- package/src/source/parse-debug-stack.ts +4 -4
- 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 +703 -135
- package/src/generated/react-work-tags.ts +0 -169
- package/src/react-internals.ts +0 -67
- package/src/unsubscribe.ts +0 -17
package/src/core.ts
CHANGED
|
@@ -10,102 +10,45 @@ import type {
|
|
|
10
10
|
MemoizedState,
|
|
11
11
|
ReactDevToolsGlobalHook,
|
|
12
12
|
ReactRenderer,
|
|
13
|
-
} from "./
|
|
13
|
+
} from "./react-internals/index.js";
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
16
|
_onActiveListeners,
|
|
17
17
|
BIPPY_INSTRUMENTATION_STRING,
|
|
18
|
+
createUnsubscribe,
|
|
18
19
|
getRDTHook,
|
|
19
20
|
hasRDTHook,
|
|
20
21
|
isRealReactDevtools,
|
|
22
|
+
onRDTHookReplace,
|
|
21
23
|
onRendererInject,
|
|
22
24
|
} from "./rdt-hook.js";
|
|
25
|
+
import type { Unsubscribe } from "./rdt-hook.js";
|
|
23
26
|
import {
|
|
24
|
-
|
|
25
|
-
CONCURRENT_MODE_NUMBER,
|
|
26
|
-
CONCURRENT_MODE_SYMBOL_DESCRIPTION,
|
|
27
|
-
CONCURRENT_MODE_SYMBOL_STRING,
|
|
28
|
-
ContextConsumerTag,
|
|
29
|
-
DEPRECATED_ASYNC_MODE_SYMBOL_DESCRIPTION,
|
|
30
|
-
DEPRECATED_ASYNC_MODE_SYMBOL_STRING,
|
|
31
|
-
DehydratedSuspenseComponentTag,
|
|
32
|
-
ELEMENT_TYPE_SYMBOL_STRING,
|
|
33
|
-
ForwardRefTag,
|
|
34
|
-
FragmentTag,
|
|
35
|
-
FunctionComponentTag,
|
|
36
|
-
HostComponentTag,
|
|
37
|
-
HostHoistableTag,
|
|
38
|
-
HostRootTag,
|
|
39
|
-
HostSingletonTag,
|
|
40
|
-
HostTextTag,
|
|
41
|
-
LegacyHiddenComponentTag,
|
|
42
|
-
MemoComponentTag,
|
|
27
|
+
getReactWorkTagsForFiber,
|
|
43
28
|
MutationMask,
|
|
44
|
-
OffscreenComponentTag,
|
|
45
29
|
ReactBuildType,
|
|
46
30
|
ReactFiberFlags,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
} from "./react-internals.js";
|
|
51
|
-
import { toUnsubscribe, type Unsubscribe } from "./unsubscribe.js";
|
|
31
|
+
ReactSymbols,
|
|
32
|
+
setReactWorkTagsForFiber,
|
|
33
|
+
} from "./react-internals/index.js";
|
|
52
34
|
|
|
35
|
+
export { getReactWorkTags, ReactSymbols } from "./react-internals/index.js";
|
|
36
|
+
export type { ReactWorkTagMap, ReactWorkTagVersion } from "./react-internals/index.js";
|
|
53
37
|
export {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
DEPRECATED_ASYNC_MODE_SYMBOL_DESCRIPTION,
|
|
61
|
-
DEPRECATED_ASYNC_MODE_SYMBOL_STRING,
|
|
62
|
-
DehydratedSuspenseComponentTag,
|
|
63
|
-
ELEMENT_TYPE_SYMBOL_STRING,
|
|
64
|
-
ForwardRefTag,
|
|
65
|
-
FragmentTag,
|
|
66
|
-
FunctionComponentTag,
|
|
67
|
-
HostComponentTag,
|
|
68
|
-
HostHoistableTag,
|
|
69
|
-
HostPortalTag,
|
|
70
|
-
HostRootTag,
|
|
71
|
-
HostSingletonTag,
|
|
72
|
-
HostTextTag,
|
|
73
|
-
LazyComponentTag,
|
|
74
|
-
LegacyHiddenComponentTag,
|
|
75
|
-
MemoComponentTag,
|
|
76
|
-
OffscreenComponentTag,
|
|
77
|
-
SimpleMemoComponentTag,
|
|
78
|
-
SuspenseComponentTag,
|
|
79
|
-
SuspenseListComponentTag,
|
|
80
|
-
TRANSITIONAL_ELEMENT_TYPE_SYMBOL_STRING,
|
|
81
|
-
ViewTransitionComponentTag,
|
|
82
|
-
} from "./react-internals.js";
|
|
83
|
-
|
|
84
|
-
const { Cloned, PerformedWork } = ReactFiberFlags;
|
|
85
|
-
|
|
86
|
-
const isObjectRecord = (value: unknown): value is Record<string, unknown> =>
|
|
87
|
-
typeof value === "object" && value !== null;
|
|
38
|
+
BippyError,
|
|
39
|
+
BippyHookInspectionError,
|
|
40
|
+
BippyHookRenderError,
|
|
41
|
+
BippySourceMapError,
|
|
42
|
+
BippyUnsupportedHookError,
|
|
43
|
+
} from "./errors.js";
|
|
88
44
|
|
|
89
45
|
const isComponentType = (value: unknown): value is React.ComponentType<unknown> =>
|
|
90
46
|
typeof value === "function";
|
|
91
47
|
|
|
92
|
-
const getPropertyValue = (value: object, key: PropertyKey): unknown => {
|
|
93
|
-
let currentValue: object | null = value;
|
|
94
|
-
while (currentValue) {
|
|
95
|
-
const descriptor = Object.getOwnPropertyDescriptor(currentValue, key);
|
|
96
|
-
if (descriptor) {
|
|
97
|
-
if ("value" in descriptor) return descriptor.value;
|
|
98
|
-
return descriptor.get?.call(value);
|
|
99
|
-
}
|
|
100
|
-
currentValue = Object.getPrototypeOf(currentValue);
|
|
101
|
-
}
|
|
102
|
-
return undefined;
|
|
103
|
-
};
|
|
104
|
-
|
|
105
48
|
const getTypeName = (value: object): string | null => {
|
|
106
|
-
const displayName =
|
|
49
|
+
const displayName = "displayName" in value ? value.displayName : null;
|
|
107
50
|
if (typeof displayName === "string" && displayName) return displayName;
|
|
108
|
-
const name =
|
|
51
|
+
const name = "name" in value ? value.name : null;
|
|
109
52
|
return typeof name === "string" && name ? name : null;
|
|
110
53
|
};
|
|
111
54
|
|
|
@@ -113,6 +56,20 @@ interface FiberSelector {
|
|
|
113
56
|
(node: Fiber): boolean | Promise<boolean | void> | void;
|
|
114
57
|
}
|
|
115
58
|
|
|
59
|
+
export interface FiberTimings {
|
|
60
|
+
selfTime: number;
|
|
61
|
+
totalTime: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface RenderHandler {
|
|
65
|
+
(fiber: Fiber, phase: RenderPhase): unknown;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface ValueWrite {
|
|
69
|
+
path: string[];
|
|
70
|
+
value: unknown;
|
|
71
|
+
}
|
|
72
|
+
|
|
116
73
|
/**
|
|
117
74
|
* Returns `true` if object is a React Element.
|
|
118
75
|
*
|
|
@@ -122,9 +79,8 @@ export const isValidElement = (element: unknown): element is React.ReactElement
|
|
|
122
79
|
typeof element === "object" &&
|
|
123
80
|
element !== null &&
|
|
124
81
|
"$$typeof" in element &&
|
|
125
|
-
|
|
126
|
-
String(element.$$typeof)
|
|
127
|
-
);
|
|
82
|
+
(String(element.$$typeof) === ReactSymbols.LEGACY_ELEMENT_SYMBOL_STRING ||
|
|
83
|
+
String(element.$$typeof) === ReactSymbols.ELEMENT_SYMBOL_STRING);
|
|
128
84
|
|
|
129
85
|
/**
|
|
130
86
|
* Returns `true` if object is a React Fiber.
|
|
@@ -139,17 +95,24 @@ export const isValidFiber = (fiber: unknown): fiber is Fiber =>
|
|
|
139
95
|
"sibling" in fiber &&
|
|
140
96
|
"flags" in fiber;
|
|
141
97
|
|
|
98
|
+
const isFiberRoot = (fiberRoot: unknown): fiberRoot is FiberRoot =>
|
|
99
|
+
typeof fiberRoot === "object" &&
|
|
100
|
+
fiberRoot !== null &&
|
|
101
|
+
"current" in fiberRoot &&
|
|
102
|
+
isValidFiber(fiberRoot.current);
|
|
103
|
+
|
|
142
104
|
/**
|
|
143
105
|
* Returns `true` if fiber is a host fiber. Host fibers are DOM nodes in react-dom, `View` in react-native, etc.
|
|
144
106
|
*
|
|
145
107
|
* @see https://reactnative.dev/architecture/glossary#host-view-tree-and-host-view
|
|
146
108
|
*/
|
|
147
109
|
export const isHostFiber = (fiber: Fiber): fiber is HostFiber => {
|
|
110
|
+
const workTags = getReactWorkTagsForFiber(fiber);
|
|
148
111
|
switch (fiber.tag) {
|
|
149
|
-
case
|
|
150
|
-
case
|
|
151
|
-
case
|
|
152
|
-
case
|
|
112
|
+
case workTags.HostComponent:
|
|
113
|
+
case workTags.HostText:
|
|
114
|
+
case workTags.HostHoistable:
|
|
115
|
+
case workTags.HostSingleton:
|
|
153
116
|
return true;
|
|
154
117
|
default:
|
|
155
118
|
return false;
|
|
@@ -162,12 +125,13 @@ export const isHostFiber = (fiber: Fiber): fiber is HostFiber => {
|
|
|
162
125
|
* @see https://reactnative.dev/architecture/glossary#react-composite-components
|
|
163
126
|
*/
|
|
164
127
|
export const isCompositeFiber = (fiber: Fiber): boolean => {
|
|
128
|
+
const workTags = getReactWorkTagsForFiber(fiber);
|
|
165
129
|
switch (fiber.tag) {
|
|
166
|
-
case
|
|
167
|
-
case
|
|
168
|
-
case
|
|
169
|
-
case
|
|
170
|
-
case
|
|
130
|
+
case workTags.ClassComponent:
|
|
131
|
+
case workTags.ForwardRef:
|
|
132
|
+
case workTags.FunctionComponent:
|
|
133
|
+
case workTags.MemoComponent:
|
|
134
|
+
case workTags.SimpleMemoComponent:
|
|
171
135
|
return true;
|
|
172
136
|
default:
|
|
173
137
|
return false;
|
|
@@ -275,15 +239,16 @@ export const didFiberRender = (fiber: Fiber): boolean => {
|
|
|
275
239
|
const nextProps = fiber.memoizedProps;
|
|
276
240
|
const prevProps = fiber.alternate?.memoizedProps || {};
|
|
277
241
|
const flags = fiber.flags ?? fiber.effectTag ?? 0;
|
|
242
|
+
const workTags = getReactWorkTagsForFiber(fiber);
|
|
278
243
|
|
|
279
244
|
switch (fiber.tag) {
|
|
280
|
-
case
|
|
281
|
-
case
|
|
282
|
-
case
|
|
283
|
-
case
|
|
284
|
-
case
|
|
285
|
-
case
|
|
286
|
-
return (flags & PerformedWork) === PerformedWork;
|
|
245
|
+
case workTags.ClassComponent:
|
|
246
|
+
case workTags.ContextConsumer:
|
|
247
|
+
case workTags.ForwardRef:
|
|
248
|
+
case workTags.FunctionComponent:
|
|
249
|
+
case workTags.MemoComponent:
|
|
250
|
+
case workTags.SimpleMemoComponent: {
|
|
251
|
+
return (flags & ReactFiberFlags.PerformedWork) === ReactFiberFlags.PerformedWork;
|
|
287
252
|
}
|
|
288
253
|
default:
|
|
289
254
|
// Host nodes (DOM, root, etc.)
|
|
@@ -301,8 +266,8 @@ export const didFiberRender = (fiber: Fiber): boolean => {
|
|
|
301
266
|
*/
|
|
302
267
|
export const didFiberCommit = (fiber: Fiber): boolean => {
|
|
303
268
|
return Boolean(
|
|
304
|
-
(fiber.flags & (MutationMask | Cloned)) !== 0 ||
|
|
305
|
-
(fiber.subtreeFlags & (MutationMask | Cloned)) !== 0,
|
|
269
|
+
(fiber.flags & (MutationMask | ReactFiberFlags.Cloned)) !== 0 ||
|
|
270
|
+
(fiber.subtreeFlags & (MutationMask | ReactFiberFlags.Cloned)) !== 0,
|
|
306
271
|
);
|
|
307
272
|
};
|
|
308
273
|
|
|
@@ -341,8 +306,7 @@ export const getFiberStack = (fiber: Fiber): Fiber[] => {
|
|
|
341
306
|
let currentFiber = fiber;
|
|
342
307
|
while (currentFiber.return) {
|
|
343
308
|
stack.push(currentFiber);
|
|
344
|
-
|
|
345
|
-
currentFiber = parentFiber;
|
|
309
|
+
currentFiber = currentFiber.return;
|
|
346
310
|
}
|
|
347
311
|
return stack;
|
|
348
312
|
};
|
|
@@ -351,8 +315,9 @@ export const getFiberStack = (fiber: Fiber): Fiber[] => {
|
|
|
351
315
|
* Returns `true` if the {@link Fiber} should be filtered out during reconciliation.
|
|
352
316
|
*/
|
|
353
317
|
const shouldFilterFiber = (fiber: Fiber): boolean => {
|
|
318
|
+
const workTags = getReactWorkTagsForFiber(fiber);
|
|
354
319
|
switch (fiber.tag) {
|
|
355
|
-
case
|
|
320
|
+
case workTags.DehydratedSuspenseComponent:
|
|
356
321
|
// TODO: ideally we would show dehydrated Suspense immediately.
|
|
357
322
|
// However, it has some special behavior (like disconnecting
|
|
358
323
|
// an alternate and turning into real Suspense) which breaks DevTools.
|
|
@@ -360,13 +325,13 @@ const shouldFilterFiber = (fiber: Fiber): boolean => {
|
|
|
360
325
|
// https://github.com/bvaughn/react-devtools-experimental/issues/197
|
|
361
326
|
return true;
|
|
362
327
|
|
|
363
|
-
case
|
|
364
|
-
case
|
|
365
|
-
case
|
|
366
|
-
case
|
|
328
|
+
case workTags.Fragment:
|
|
329
|
+
case workTags.HostText:
|
|
330
|
+
case workTags.LegacyHiddenComponent:
|
|
331
|
+
case workTags.OffscreenComponent:
|
|
367
332
|
return true;
|
|
368
333
|
|
|
369
|
-
case
|
|
334
|
+
case workTags.HostRoot:
|
|
370
335
|
// It is never valid to filter the root element.
|
|
371
336
|
return false;
|
|
372
337
|
|
|
@@ -376,15 +341,15 @@ const shouldFilterFiber = (fiber: Fiber): boolean => {
|
|
|
376
341
|
|
|
377
342
|
if (typeof symbolOrNumber === "symbol") {
|
|
378
343
|
return (
|
|
379
|
-
symbolOrNumber.description === CONCURRENT_MODE_SYMBOL_DESCRIPTION ||
|
|
380
|
-
symbolOrNumber.description === DEPRECATED_ASYNC_MODE_SYMBOL_DESCRIPTION
|
|
344
|
+
symbolOrNumber.description === ReactSymbols.CONCURRENT_MODE_SYMBOL_DESCRIPTION ||
|
|
345
|
+
symbolOrNumber.description === ReactSymbols.DEPRECATED_ASYNC_MODE_SYMBOL_DESCRIPTION
|
|
381
346
|
);
|
|
382
347
|
}
|
|
383
348
|
|
|
384
349
|
switch (symbolOrNumber) {
|
|
385
|
-
case CONCURRENT_MODE_NUMBER:
|
|
386
|
-
case CONCURRENT_MODE_SYMBOL_STRING:
|
|
387
|
-
case DEPRECATED_ASYNC_MODE_SYMBOL_STRING:
|
|
350
|
+
case ReactSymbols.CONCURRENT_MODE_NUMBER:
|
|
351
|
+
case ReactSymbols.CONCURRENT_MODE_SYMBOL_STRING:
|
|
352
|
+
case ReactSymbols.DEPRECATED_ASYNC_MODE_SYMBOL_STRING:
|
|
388
353
|
return true;
|
|
389
354
|
|
|
390
355
|
default:
|
|
@@ -448,6 +413,11 @@ export function traverseFiber(
|
|
|
448
413
|
selector: (node: Fiber) => Promise<boolean | void>,
|
|
449
414
|
ascending?: boolean,
|
|
450
415
|
): Promise<Fiber | null>;
|
|
416
|
+
export function traverseFiber(
|
|
417
|
+
fiber: Fiber | null,
|
|
418
|
+
selector: FiberSelector,
|
|
419
|
+
ascending?: boolean,
|
|
420
|
+
): Fiber | null | Promise<Fiber | null>;
|
|
451
421
|
export function traverseFiber(
|
|
452
422
|
fiber: Fiber | null,
|
|
453
423
|
selector: FiberSelector,
|
|
@@ -455,68 +425,47 @@ export function traverseFiber(
|
|
|
455
425
|
): Fiber | null | Promise<Fiber | null> {
|
|
456
426
|
if (!fiber) return null;
|
|
457
427
|
|
|
458
|
-
const
|
|
459
|
-
if (
|
|
460
|
-
return (
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
let child = ascending ? fiber.return : fiber.child;
|
|
464
|
-
while (child) {
|
|
465
|
-
const match = await traverseFiberAsync(child, selector, ascending);
|
|
466
|
-
if (match) return match;
|
|
467
|
-
child = ascending ? null : child.sibling;
|
|
468
|
-
}
|
|
469
|
-
return null;
|
|
470
|
-
})();
|
|
428
|
+
const selection = selector(fiber);
|
|
429
|
+
if (isPromiseLike<boolean | void>(selection)) {
|
|
430
|
+
return Promise.resolve(selection).then((didSelectFiber) =>
|
|
431
|
+
didSelectFiber === true ? fiber : traverseFiberChildren(fiber, selector, ascending),
|
|
432
|
+
);
|
|
471
433
|
}
|
|
434
|
+
if (selection === true) return fiber;
|
|
472
435
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
let child = ascending ? fiber.return : fiber.child;
|
|
476
|
-
while (child) {
|
|
477
|
-
const match = traverseFiberSync(child, selector, ascending);
|
|
478
|
-
if (match) return match;
|
|
479
|
-
child = ascending ? null : child.sibling;
|
|
480
|
-
}
|
|
481
|
-
return null;
|
|
436
|
+
return traverseFiberChildren(fiber, selector, ascending);
|
|
482
437
|
}
|
|
483
438
|
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
if (!fiber) return null;
|
|
490
|
-
const selection = selector(fiber);
|
|
491
|
-
if (selection instanceof Promise) return null;
|
|
492
|
-
if (selection === true) return fiber;
|
|
493
|
-
|
|
494
|
-
let child = ascending ? fiber.return : fiber.child;
|
|
495
|
-
while (child) {
|
|
496
|
-
const match = traverseFiberSync(child, selector, ascending);
|
|
497
|
-
if (match) return match;
|
|
439
|
+
const isPromiseLike = <Result>(value: unknown): value is PromiseLike<Result> =>
|
|
440
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
441
|
+
value !== null &&
|
|
442
|
+
"then" in value &&
|
|
443
|
+
typeof value.then === "function";
|
|
498
444
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
445
|
+
const traverseFiberChildren = (
|
|
446
|
+
fiber: Fiber,
|
|
447
|
+
selector: FiberSelector,
|
|
448
|
+
ascending: boolean,
|
|
449
|
+
): Fiber | null | Promise<Fiber | null> => {
|
|
450
|
+
const firstChild = ascending ? fiber.return : fiber.child;
|
|
451
|
+
return traverseFiberSiblings(firstChild, selector, ascending);
|
|
502
452
|
};
|
|
503
453
|
|
|
504
|
-
const
|
|
454
|
+
const traverseFiberSiblings = (
|
|
505
455
|
fiber: Fiber | null,
|
|
506
456
|
selector: FiberSelector,
|
|
507
|
-
ascending
|
|
508
|
-
): Promise<Fiber | null> => {
|
|
457
|
+
ascending: boolean,
|
|
458
|
+
): Fiber | null | Promise<Fiber | null> => {
|
|
509
459
|
if (!fiber) return null;
|
|
510
|
-
if ((await selector(fiber)) === true) return fiber;
|
|
511
|
-
|
|
512
|
-
let child = ascending ? fiber.return : fiber.child;
|
|
513
|
-
while (child) {
|
|
514
|
-
const match = await traverseFiberAsync(child, selector, ascending);
|
|
515
|
-
if (match) return match;
|
|
516
460
|
|
|
517
|
-
|
|
461
|
+
const nextSibling = ascending ? null : fiber.sibling;
|
|
462
|
+
const match = traverseFiber(fiber, selector, ascending);
|
|
463
|
+
if (isPromiseLike<Fiber | null>(match)) {
|
|
464
|
+
return Promise.resolve(match).then(
|
|
465
|
+
(resolvedMatch) => resolvedMatch ?? traverseFiberSiblings(nextSibling, selector, ascending),
|
|
466
|
+
);
|
|
518
467
|
}
|
|
519
|
-
return
|
|
468
|
+
return match ?? traverseFiberSiblings(nextSibling, selector, ascending);
|
|
520
469
|
};
|
|
521
470
|
|
|
522
471
|
/**
|
|
@@ -528,7 +477,7 @@ const traverseFiberAsync = async (
|
|
|
528
477
|
* console.log(selfTime, totalTime);
|
|
529
478
|
* ```
|
|
530
479
|
*/
|
|
531
|
-
export const getTimings = (fiber?: Fiber | null):
|
|
480
|
+
export const getTimings = (fiber?: Fiber | null): FiberTimings => {
|
|
532
481
|
const totalTime = fiber?.actualDuration ?? 0;
|
|
533
482
|
let selfTime = totalTime;
|
|
534
483
|
// TODO: calculate a DOM time, which is just host component summed up
|
|
@@ -552,8 +501,8 @@ export const hasMemoCache = (fiber: Fiber): boolean => {
|
|
|
552
501
|
*/
|
|
553
502
|
export const getType = (type: unknown): null | React.ComponentType<unknown> => {
|
|
554
503
|
if (isComponentType(type)) return type;
|
|
555
|
-
if (
|
|
556
|
-
return getType(
|
|
504
|
+
if (typeof type !== "object" || type === null) return null;
|
|
505
|
+
return getType(Reflect.get(type, "type") ?? Reflect.get(type, "render"));
|
|
557
506
|
};
|
|
558
507
|
|
|
559
508
|
/**
|
|
@@ -605,35 +554,35 @@ export const getLatestFiber = (fiber: Fiber): Fiber => {
|
|
|
605
554
|
}
|
|
606
555
|
for (const root of _fiberRoots) {
|
|
607
556
|
const latestFiber = traverseFiber(root.current, (innerFiber) => {
|
|
608
|
-
if (innerFiber === fiber) return true;
|
|
557
|
+
if (innerFiber === fiber || innerFiber === alternate) return true;
|
|
609
558
|
});
|
|
610
559
|
if (latestFiber) return latestFiber;
|
|
611
560
|
}
|
|
612
561
|
return fiber;
|
|
613
562
|
};
|
|
614
563
|
|
|
615
|
-
export type RenderHandler = <S>(fiber: Fiber, phase: RenderPhase, state?: S) => unknown;
|
|
616
|
-
|
|
617
564
|
export type RenderPhase = "mount" | "unmount" | "update";
|
|
618
565
|
|
|
619
|
-
let
|
|
566
|
+
let nextFiberId = 0;
|
|
620
567
|
const fiberIdMap = new WeakMap<Fiber, number>();
|
|
621
568
|
|
|
622
|
-
export const setFiberId = (fiber: Fiber,
|
|
623
|
-
fiberIdMap.set(fiber,
|
|
569
|
+
export const setFiberId = (fiber: Fiber, fiberId: number = nextFiberId++): void => {
|
|
570
|
+
fiberIdMap.set(fiber, fiberId);
|
|
571
|
+
if (Number.isSafeInteger(fiberId) && fiberId >= nextFiberId) {
|
|
572
|
+
nextFiberId = fiberId + 1;
|
|
573
|
+
}
|
|
624
574
|
};
|
|
625
575
|
|
|
626
|
-
// Fiber alternates share an identity across double-buffered commits.
|
|
627
576
|
export const getFiberId = (fiber: Fiber): number => {
|
|
628
|
-
let
|
|
629
|
-
if (
|
|
630
|
-
|
|
577
|
+
let currentFiberId = fiberIdMap.get(fiber);
|
|
578
|
+
if (currentFiberId === undefined && fiber.alternate) {
|
|
579
|
+
currentFiberId = fiberIdMap.get(fiber.alternate);
|
|
631
580
|
}
|
|
632
|
-
if (
|
|
633
|
-
|
|
634
|
-
setFiberId(fiber,
|
|
581
|
+
if (currentFiberId === undefined) {
|
|
582
|
+
currentFiberId = nextFiberId++;
|
|
583
|
+
setFiberId(fiber, currentFiberId);
|
|
635
584
|
}
|
|
636
|
-
return
|
|
585
|
+
return currentFiberId;
|
|
637
586
|
};
|
|
638
587
|
|
|
639
588
|
const mountFiberRecursively = (
|
|
@@ -644,15 +593,13 @@ const mountFiberRecursively = (
|
|
|
644
593
|
let fiber: Fiber | null = firstChild;
|
|
645
594
|
|
|
646
595
|
while (fiber !== null) {
|
|
647
|
-
|
|
648
|
-
getFiberId(fiber);
|
|
649
|
-
}
|
|
596
|
+
getFiberId(fiber);
|
|
650
597
|
const shouldIncludeInTree = !shouldFilterFiber(fiber);
|
|
651
598
|
if (shouldIncludeInTree && didFiberRender(fiber)) {
|
|
652
599
|
onRender(fiber, "mount");
|
|
653
600
|
}
|
|
654
601
|
|
|
655
|
-
if (fiber.tag ===
|
|
602
|
+
if (fiber.tag === getReactWorkTagsForFiber(fiber).SuspenseComponent) {
|
|
656
603
|
const isTimedOut = fiber.memoizedState !== null;
|
|
657
604
|
if (isTimedOut) {
|
|
658
605
|
// Special case: if Suspense mounts in a timed-out state,
|
|
@@ -682,18 +629,13 @@ const mountFiberRecursively = (
|
|
|
682
629
|
const updateFiberRecursively = (
|
|
683
630
|
onRender: RenderHandler,
|
|
684
631
|
nextFiber: Fiber,
|
|
685
|
-
prevFiber: Fiber,
|
|
686
|
-
parentFiber: Fiber | null,
|
|
632
|
+
prevFiber: Fiber | null,
|
|
687
633
|
): void => {
|
|
688
|
-
|
|
689
|
-
getFiberId(nextFiber);
|
|
690
|
-
}
|
|
634
|
+
getFiberId(nextFiber);
|
|
691
635
|
if (!prevFiber) return;
|
|
692
|
-
|
|
693
|
-
getFiberId(prevFiber);
|
|
694
|
-
}
|
|
636
|
+
getFiberId(prevFiber);
|
|
695
637
|
|
|
696
|
-
const isSuspense = nextFiber.tag ===
|
|
638
|
+
const isSuspense = nextFiber.tag === getReactWorkTagsForFiber(nextFiber).SuspenseComponent;
|
|
697
639
|
|
|
698
640
|
const shouldIncludeInTree = !shouldFilterFiber(nextFiber);
|
|
699
641
|
if (shouldIncludeInTree && didFiberRender(nextFiber)) {
|
|
@@ -722,7 +664,7 @@ const updateFiberRecursively = (
|
|
|
722
664
|
const prevFallbackChildSet = prevFiber.child?.sibling ?? null;
|
|
723
665
|
|
|
724
666
|
if (nextFallbackChildSet !== null && prevFallbackChildSet !== null) {
|
|
725
|
-
updateFiberRecursively(onRender, nextFallbackChildSet, prevFallbackChildSet
|
|
667
|
+
updateFiberRecursively(onRender, nextFallbackChildSet, prevFallbackChildSet);
|
|
726
668
|
}
|
|
727
669
|
} else if (prevDidTimeout && !nextDidTimeOut) {
|
|
728
670
|
// Fallback -> Primary:
|
|
@@ -761,14 +703,7 @@ const updateFiberRecursively = (
|
|
|
761
703
|
// Schedule updates and mounts depending on whether alternates exist.
|
|
762
704
|
// We don't track deletions here because they are reported separately.
|
|
763
705
|
if (nextChild.alternate) {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
updateFiberRecursively(
|
|
767
|
-
onRender,
|
|
768
|
-
nextChild,
|
|
769
|
-
prevChild,
|
|
770
|
-
shouldIncludeInTree ? nextFiber : parentFiber,
|
|
771
|
-
);
|
|
706
|
+
updateFiberRecursively(onRender, nextChild, nextChild.alternate);
|
|
772
707
|
} else {
|
|
773
708
|
mountFiberRecursively(onRender, nextChild, false);
|
|
774
709
|
}
|
|
@@ -780,7 +715,7 @@ const updateFiberRecursively = (
|
|
|
780
715
|
};
|
|
781
716
|
|
|
782
717
|
const unmountFiber = (onRender: RenderHandler, fiber: Fiber): void => {
|
|
783
|
-
const isRoot = fiber.tag ===
|
|
718
|
+
const isRoot = fiber.tag === getReactWorkTagsForFiber(fiber).HostRoot;
|
|
784
719
|
|
|
785
720
|
if (isRoot || !shouldFilterFiber(fiber)) {
|
|
786
721
|
onRender(fiber, "unmount");
|
|
@@ -789,7 +724,8 @@ const unmountFiber = (onRender: RenderHandler, fiber: Fiber): void => {
|
|
|
789
724
|
|
|
790
725
|
const unmountFiberChildrenRecursively = (onRender: RenderHandler, fiber: Fiber): void => {
|
|
791
726
|
// We might meet a nested Suspense on our way.
|
|
792
|
-
const isTimedOutSuspense =
|
|
727
|
+
const isTimedOutSuspense =
|
|
728
|
+
fiber.tag === getReactWorkTagsForFiber(fiber).SuspenseComponent && fiber.memoizedState !== null;
|
|
793
729
|
let child = fiber.child;
|
|
794
730
|
|
|
795
731
|
if (isTimedOutSuspense) {
|
|
@@ -813,11 +749,9 @@ const unmountFiberChildrenRecursively = (onRender: RenderHandler, fiber: Fiber):
|
|
|
813
749
|
}
|
|
814
750
|
};
|
|
815
751
|
|
|
816
|
-
let commitId = 0;
|
|
817
752
|
const rootInstanceMap = new WeakMap<
|
|
818
|
-
FiberRoot,
|
|
753
|
+
Fiber | FiberRoot,
|
|
819
754
|
{
|
|
820
|
-
id: number;
|
|
821
755
|
prevFiber: Fiber | null;
|
|
822
756
|
}
|
|
823
757
|
>();
|
|
@@ -829,23 +763,23 @@ const rootInstanceMap = new WeakMap<
|
|
|
829
763
|
* console.log(phase)
|
|
830
764
|
* })
|
|
831
765
|
*/
|
|
832
|
-
export const traverseRenderedFibers = (root: FiberRoot, onRender: RenderHandler): void => {
|
|
766
|
+
export const traverseRenderedFibers = (root: Fiber | FiberRoot, onRender: RenderHandler): void => {
|
|
833
767
|
const fiber = "current" in root ? root.current : root;
|
|
834
768
|
|
|
835
769
|
let rootInstance = rootInstanceMap.get(root);
|
|
836
770
|
|
|
837
771
|
if (!rootInstance) {
|
|
838
|
-
rootInstance = {
|
|
772
|
+
rootInstance = { prevFiber: null };
|
|
839
773
|
rootInstanceMap.set(root, rootInstance);
|
|
840
774
|
}
|
|
841
775
|
|
|
842
776
|
const { prevFiber } = rootInstance;
|
|
843
|
-
// if fiberRoot don't have current instance, means it's been unmounted
|
|
844
777
|
if (!fiber) {
|
|
845
|
-
|
|
778
|
+
if (prevFiber) {
|
|
779
|
+
unmountFiber(onRender, prevFiber);
|
|
780
|
+
}
|
|
846
781
|
} else if (prevFiber !== null) {
|
|
847
782
|
const wasMounted =
|
|
848
|
-
prevFiber &&
|
|
849
783
|
prevFiber.memoizedState !== null &&
|
|
850
784
|
prevFiber.memoizedState.element !== null &&
|
|
851
785
|
prevFiber.memoizedState.element !== undefined &&
|
|
@@ -861,7 +795,7 @@ export const traverseRenderedFibers = (root: FiberRoot, onRender: RenderHandler)
|
|
|
861
795
|
if (!wasMounted && isMounted) {
|
|
862
796
|
mountFiberRecursively(onRender, fiber, false);
|
|
863
797
|
} else if (wasMounted && isMounted) {
|
|
864
|
-
updateFiberRecursively(onRender, fiber, fiber.alternate
|
|
798
|
+
updateFiberRecursively(onRender, fiber, fiber.alternate);
|
|
865
799
|
} else if (wasMounted && !isMounted) {
|
|
866
800
|
unmountFiber(onRender, fiber);
|
|
867
801
|
}
|
|
@@ -878,9 +812,8 @@ let areOverrideRenderersWired = false;
|
|
|
878
812
|
const wireOverrideRenderers = (): void => {
|
|
879
813
|
if (!hasRDTHook()) return;
|
|
880
814
|
const rdtHook = getRDTHook();
|
|
881
|
-
if (!rdtHook?.renderers) return;
|
|
882
815
|
|
|
883
|
-
|
|
816
|
+
setHookEventDispatchers(rdtHook);
|
|
884
817
|
for (const renderer of rdtHook.renderers.values()) {
|
|
885
818
|
overrideRenderers.add(renderer);
|
|
886
819
|
}
|
|
@@ -897,14 +830,13 @@ const getRootRenderer = (fiber: Fiber): ReactRenderer | null => {
|
|
|
897
830
|
while (hostRootFiber.return) {
|
|
898
831
|
hostRootFiber = hostRootFiber.return;
|
|
899
832
|
}
|
|
900
|
-
const
|
|
833
|
+
const fiberRoot = hostRootFiber.stateNode;
|
|
834
|
+
if (!isFiberRoot(fiberRoot)) return null;
|
|
835
|
+
const rendererId = rootRendererIds.get(fiberRoot);
|
|
901
836
|
if (rendererId === undefined) return null;
|
|
902
|
-
return getRDTHook().renderers
|
|
837
|
+
return getRDTHook().renderers.get(rendererId) ?? null;
|
|
903
838
|
};
|
|
904
839
|
|
|
905
|
-
// dispatch to the renderer that owns the fiber's root when known; renderers
|
|
906
|
-
// that never committed through bippy's hook patch fall back to "try all",
|
|
907
|
-
// which matches the pre-ownership behavior for single-renderer apps
|
|
908
840
|
const resolveOverrideRenderers = (fiber: Fiber): ReactRenderer[] => {
|
|
909
841
|
wireOverrideRenderers();
|
|
910
842
|
const rootRenderer = getRootRenderer(fiber);
|
|
@@ -930,7 +862,7 @@ const getHookStateDispatch = (
|
|
|
930
862
|
hookIndex: number,
|
|
931
863
|
): ((value: unknown) => void) | null => {
|
|
932
864
|
let hookState = fiber.memoizedState;
|
|
933
|
-
for (let
|
|
865
|
+
for (let currentHookIndex = 0; currentHookIndex < hookIndex; currentHookIndex++) {
|
|
934
866
|
if (!hookState?.next) return null;
|
|
935
867
|
hookState = hookState.next;
|
|
936
868
|
}
|
|
@@ -963,28 +895,30 @@ const isPOJO = (maybePOJO: unknown): maybePOJO is Record<string, unknown> => {
|
|
|
963
895
|
const buildPathsFromValue = (
|
|
964
896
|
maybePOJO: Record<string, unknown>,
|
|
965
897
|
basePath: string[] = [],
|
|
966
|
-
|
|
967
|
-
|
|
898
|
+
ancestors = new WeakSet<object>(),
|
|
899
|
+
): ValueWrite[] => {
|
|
900
|
+
if (ancestors.has(maybePOJO)) {
|
|
968
901
|
return [{ path: basePath, value: maybePOJO }];
|
|
969
902
|
}
|
|
970
903
|
|
|
971
|
-
|
|
904
|
+
ancestors.add(maybePOJO);
|
|
905
|
+
const paths: ValueWrite[] = [];
|
|
972
906
|
|
|
973
|
-
for (const key
|
|
974
|
-
const value = maybePOJO[key];
|
|
907
|
+
for (const [key, value] of Object.entries(maybePOJO)) {
|
|
975
908
|
const path = basePath.concat(key);
|
|
976
909
|
|
|
977
910
|
if (isPOJO(value)) {
|
|
978
|
-
paths.push(...buildPathsFromValue(value, path));
|
|
911
|
+
paths.push(...buildPathsFromValue(value, path, ancestors));
|
|
979
912
|
} else {
|
|
980
913
|
paths.push({ path, value });
|
|
981
914
|
}
|
|
982
915
|
}
|
|
983
916
|
|
|
917
|
+
ancestors.delete(maybePOJO);
|
|
984
918
|
return paths;
|
|
985
919
|
};
|
|
986
920
|
|
|
987
|
-
const buildValueWrites = (partialValue: unknown):
|
|
921
|
+
const buildValueWrites = (partialValue: unknown): ValueWrite[] =>
|
|
988
922
|
isPOJO(partialValue) ? buildPathsFromValue(partialValue) : [{ path: [], value: partialValue }];
|
|
989
923
|
|
|
990
924
|
export const overrideProps = (fiber: Fiber, partialValue: Record<string, unknown>) => {
|
|
@@ -998,9 +932,9 @@ export const overrideHookState = (fiber: Fiber, id: number, partialValue: unknow
|
|
|
998
932
|
const renderers = resolveOverrideRenderers(fiber).filter((renderer) =>
|
|
999
933
|
Boolean(renderer.overrideHookState),
|
|
1000
934
|
);
|
|
1001
|
-
const writes = buildValueWrites(partialValue);
|
|
1002
935
|
|
|
1003
936
|
if (renderers.length > 0) {
|
|
937
|
+
const writes = buildValueWrites(partialValue);
|
|
1004
938
|
for (const renderer of renderers) {
|
|
1005
939
|
for (const { path, value } of writes) {
|
|
1006
940
|
try {
|
|
@@ -1048,18 +982,11 @@ export interface InstrumentationOptions {
|
|
|
1048
982
|
onScheduleFiberRoot?: (rendererID: number, root: FiberRoot, children: React.ReactNode) => unknown;
|
|
1049
983
|
}
|
|
1050
984
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
>();
|
|
1057
|
-
const postCommitFiberRootListeners = new Set<
|
|
1058
|
-
NonNullable<InstrumentationOptions["onPostCommitFiberRoot"]>
|
|
1059
|
-
>();
|
|
1060
|
-
const scheduleFiberRootListeners = new Set<
|
|
1061
|
-
NonNullable<InstrumentationOptions["onScheduleFiberRoot"]>
|
|
1062
|
-
>();
|
|
985
|
+
interface InstrumentationSubscription {
|
|
986
|
+
options: InstrumentationOptions;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
const instrumentationSubscriptions = new Set<InstrumentationSubscription>();
|
|
1063
990
|
|
|
1064
991
|
interface HookDispatchers {
|
|
1065
992
|
onCommitFiberRoot: ReactDevToolsGlobalHook["onCommitFiberRoot"];
|
|
@@ -1069,6 +996,7 @@ interface HookDispatchers {
|
|
|
1069
996
|
}
|
|
1070
997
|
|
|
1071
998
|
const hookDispatchers = new WeakMap<ReactDevToolsGlobalHook, Partial<HookDispatchers>>();
|
|
999
|
+
let didSubscribeToHookReplacements = false;
|
|
1072
1000
|
|
|
1073
1001
|
const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
1074
1002
|
|
|
@@ -1077,7 +1005,7 @@ const rootRendererIds = new WeakMap<FiberRoot, number>();
|
|
|
1077
1005
|
// next instrument() call installs a fresh wrapper over it; a superseded
|
|
1078
1006
|
// wrapper still forwards the previous chain but skips the listeners so
|
|
1079
1007
|
// they never fire twice.
|
|
1080
|
-
const
|
|
1008
|
+
const setHookEventDispatchers = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
1081
1009
|
const dispatchers = hookDispatchers.get(rdtHook) ?? {};
|
|
1082
1010
|
hookDispatchers.set(rdtHook, dispatchers);
|
|
1083
1011
|
|
|
@@ -1092,8 +1020,11 @@ const ensureHookDispatchesToListeners = (rdtHook: ReactDevToolsGlobalHook): void
|
|
|
1092
1020
|
priority,
|
|
1093
1021
|
didError,
|
|
1094
1022
|
) => {
|
|
1095
|
-
prevOnCommitFiberRoot
|
|
1023
|
+
if (prevOnCommitFiberRoot) {
|
|
1024
|
+
prevOnCommitFiberRoot.call(rdtHook, rendererID, root, priority, didError);
|
|
1025
|
+
}
|
|
1096
1026
|
if (hookDispatchers.get(rdtHook)?.onCommitFiberRoot !== dispatchCommitFiberRoot) return;
|
|
1027
|
+
setReactWorkTagsForFiber(root.current, rdtHook.renderers.get(rendererID));
|
|
1097
1028
|
const rootMemoizedState = root.current.memoizedState;
|
|
1098
1029
|
const isUnmounting =
|
|
1099
1030
|
rootMemoizedState === null ||
|
|
@@ -1106,8 +1037,10 @@ const ensureHookDispatchesToListeners = (rdtHook: ReactDevToolsGlobalHook): void
|
|
|
1106
1037
|
_fiberRoots.add(root);
|
|
1107
1038
|
rootRendererIds.set(root, rendererID);
|
|
1108
1039
|
}
|
|
1109
|
-
for (const
|
|
1110
|
-
|
|
1040
|
+
for (const { options } of instrumentationSubscriptions) {
|
|
1041
|
+
if (options.onCommitFiberRoot) {
|
|
1042
|
+
options.onCommitFiberRoot(rendererID, root, priority, didError);
|
|
1043
|
+
}
|
|
1111
1044
|
}
|
|
1112
1045
|
};
|
|
1113
1046
|
dispatchers.onCommitFiberRoot = dispatchCommitFiberRoot;
|
|
@@ -1123,12 +1056,17 @@ const ensureHookDispatchesToListeners = (rdtHook: ReactDevToolsGlobalHook): void
|
|
|
1123
1056
|
rendererID,
|
|
1124
1057
|
fiber,
|
|
1125
1058
|
) => {
|
|
1126
|
-
|
|
1059
|
+
setReactWorkTagsForFiber(fiber, rdtHook.renderers.get(rendererID));
|
|
1060
|
+
if (prevOnCommitFiberUnmount) {
|
|
1061
|
+
prevOnCommitFiberUnmount.call(rdtHook, rendererID, fiber);
|
|
1062
|
+
}
|
|
1127
1063
|
if (hookDispatchers.get(rdtHook)?.onCommitFiberUnmount !== dispatchCommitFiberUnmount) {
|
|
1128
1064
|
return;
|
|
1129
1065
|
}
|
|
1130
|
-
for (const
|
|
1131
|
-
|
|
1066
|
+
for (const { options } of instrumentationSubscriptions) {
|
|
1067
|
+
if (options.onCommitFiberUnmount) {
|
|
1068
|
+
options.onCommitFiberUnmount(rendererID, fiber);
|
|
1069
|
+
}
|
|
1132
1070
|
}
|
|
1133
1071
|
};
|
|
1134
1072
|
dispatchers.onCommitFiberUnmount = dispatchCommitFiberUnmount;
|
|
@@ -1144,12 +1082,16 @@ const ensureHookDispatchesToListeners = (rdtHook: ReactDevToolsGlobalHook): void
|
|
|
1144
1082
|
rendererID,
|
|
1145
1083
|
root,
|
|
1146
1084
|
) => {
|
|
1147
|
-
prevOnPostCommitFiberRoot
|
|
1085
|
+
if (prevOnPostCommitFiberRoot) {
|
|
1086
|
+
prevOnPostCommitFiberRoot.call(rdtHook, rendererID, root);
|
|
1087
|
+
}
|
|
1148
1088
|
if (hookDispatchers.get(rdtHook)?.onPostCommitFiberRoot !== dispatchPostCommitFiberRoot) {
|
|
1149
1089
|
return;
|
|
1150
1090
|
}
|
|
1151
|
-
for (const
|
|
1152
|
-
|
|
1091
|
+
for (const { options } of instrumentationSubscriptions) {
|
|
1092
|
+
if (options.onPostCommitFiberRoot) {
|
|
1093
|
+
options.onPostCommitFiberRoot(rendererID, root);
|
|
1094
|
+
}
|
|
1153
1095
|
}
|
|
1154
1096
|
};
|
|
1155
1097
|
dispatchers.onPostCommitFiberRoot = dispatchPostCommitFiberRoot;
|
|
@@ -1166,10 +1108,14 @@ const ensureHookDispatchesToListeners = (rdtHook: ReactDevToolsGlobalHook): void
|
|
|
1166
1108
|
root,
|
|
1167
1109
|
children,
|
|
1168
1110
|
) => {
|
|
1169
|
-
prevOnScheduleFiberRoot
|
|
1111
|
+
if (prevOnScheduleFiberRoot) {
|
|
1112
|
+
prevOnScheduleFiberRoot.call(rdtHook, rendererID, root, children);
|
|
1113
|
+
}
|
|
1170
1114
|
if (hookDispatchers.get(rdtHook)?.onScheduleFiberRoot !== dispatchScheduleFiberRoot) return;
|
|
1171
|
-
for (const
|
|
1172
|
-
|
|
1115
|
+
for (const { options } of instrumentationSubscriptions) {
|
|
1116
|
+
if (options.onScheduleFiberRoot) {
|
|
1117
|
+
options.onScheduleFiberRoot(rendererID, root, children);
|
|
1118
|
+
}
|
|
1173
1119
|
}
|
|
1174
1120
|
};
|
|
1175
1121
|
dispatchers.onScheduleFiberRoot = dispatchScheduleFiberRoot;
|
|
@@ -1182,8 +1128,7 @@ const ensureHookDispatchesToListeners = (rdtHook: ReactDevToolsGlobalHook): void
|
|
|
1182
1128
|
* dispatches to a set of listeners, so multiple `instrument` calls compose
|
|
1183
1129
|
* without stacking patches. Returns an unsubscribe function that removes
|
|
1184
1130
|
* exactly the handlers this call registered.
|
|
1185
|
-
* The
|
|
1186
|
-
* bippy subscriptions through `using`.
|
|
1131
|
+
* The unsubscribe function can also be disposed through `using`.
|
|
1187
1132
|
* @example
|
|
1188
1133
|
* const unsubscribe = instrument({
|
|
1189
1134
|
* onActive() {
|
|
@@ -1198,28 +1143,20 @@ const ensureHookDispatchesToListeners = (rdtHook: ReactDevToolsGlobalHook): void
|
|
|
1198
1143
|
export const instrument = (options: InstrumentationOptions): Unsubscribe => {
|
|
1199
1144
|
const rdtHook = getRDTHook(options.onActive);
|
|
1200
1145
|
|
|
1146
|
+
if (!didSubscribeToHookReplacements) {
|
|
1147
|
+
onRDTHookReplace(setHookEventDispatchers);
|
|
1148
|
+
didSubscribeToHookReplacements = true;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1201
1151
|
rdtHook._instrumentationSource = options.name ?? BIPPY_INSTRUMENTATION_STRING;
|
|
1202
1152
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
onScheduleFiberRoot,
|
|
1211
|
-
} = options;
|
|
1212
|
-
if (onCommitFiberRoot) commitFiberRootListeners.add(onCommitFiberRoot);
|
|
1213
|
-
if (onCommitFiberUnmount) commitFiberUnmountListeners.add(onCommitFiberUnmount);
|
|
1214
|
-
if (onPostCommitFiberRoot) postCommitFiberRootListeners.add(onPostCommitFiberRoot);
|
|
1215
|
-
if (onScheduleFiberRoot) scheduleFiberRootListeners.add(onScheduleFiberRoot);
|
|
1216
|
-
|
|
1217
|
-
return toUnsubscribe(() => {
|
|
1218
|
-
if (onActive) _onActiveListeners.delete(onActive);
|
|
1219
|
-
if (onCommitFiberRoot) commitFiberRootListeners.delete(onCommitFiberRoot);
|
|
1220
|
-
if (onCommitFiberUnmount) commitFiberUnmountListeners.delete(onCommitFiberUnmount);
|
|
1221
|
-
if (onPostCommitFiberRoot) postCommitFiberRootListeners.delete(onPostCommitFiberRoot);
|
|
1222
|
-
if (onScheduleFiberRoot) scheduleFiberRootListeners.delete(onScheduleFiberRoot);
|
|
1153
|
+
setHookEventDispatchers(rdtHook);
|
|
1154
|
+
const subscription: InstrumentationSubscription = { options };
|
|
1155
|
+
instrumentationSubscriptions.add(subscription);
|
|
1156
|
+
|
|
1157
|
+
return createUnsubscribe(() => {
|
|
1158
|
+
if (options.onActive) _onActiveListeners.delete(options.onActive);
|
|
1159
|
+
instrumentationSubscriptions.delete(subscription);
|
|
1223
1160
|
});
|
|
1224
1161
|
};
|
|
1225
1162
|
|
|
@@ -1231,30 +1168,35 @@ const isFiberPropertyKey = (key: string): boolean =>
|
|
|
1231
1168
|
key.startsWith("__reactInternalInstance$") ||
|
|
1232
1169
|
key.startsWith("__reactFiber");
|
|
1233
1170
|
|
|
1234
|
-
const getLegacyRootFiber = (hostInstance:
|
|
1235
|
-
const reactRootContainer = hostInstance
|
|
1236
|
-
if (
|
|
1237
|
-
const internalRoot = reactRootContainer
|
|
1238
|
-
if (
|
|
1239
|
-
const current = internalRoot
|
|
1240
|
-
if (
|
|
1241
|
-
const child = current
|
|
1171
|
+
const getLegacyRootFiber = (hostInstance: object): Fiber | null => {
|
|
1172
|
+
const reactRootContainer = Reflect.get(hostInstance, "_reactRootContainer");
|
|
1173
|
+
if (typeof reactRootContainer !== "object" || reactRootContainer === null) return null;
|
|
1174
|
+
const internalRoot = Reflect.get(reactRootContainer, "_internalRoot");
|
|
1175
|
+
if (typeof internalRoot !== "object" || internalRoot === null) return null;
|
|
1176
|
+
const current = Reflect.get(internalRoot, "current");
|
|
1177
|
+
if (typeof current !== "object" || current === null) return null;
|
|
1178
|
+
const child = Reflect.get(current, "child");
|
|
1242
1179
|
return isValidFiber(child) ? child : null;
|
|
1243
1180
|
};
|
|
1244
1181
|
|
|
1245
|
-
const getInternalInstanceHandle = (hostInstance:
|
|
1182
|
+
const getInternalInstanceHandle = (hostInstance: object): Fiber | null => {
|
|
1246
1183
|
const internalInstanceHandle =
|
|
1247
|
-
hostInstance
|
|
1184
|
+
Reflect.get(hostInstance, "__internalInstanceHandle") ??
|
|
1185
|
+
Reflect.get(hostInstance, "_internalInstanceHandle");
|
|
1248
1186
|
return isValidFiber(internalInstanceHandle) ? internalInstanceHandle : null;
|
|
1249
1187
|
};
|
|
1250
1188
|
|
|
1251
1189
|
const getPublicHostInstance = (stateNode: unknown): unknown => {
|
|
1252
|
-
if (
|
|
1253
|
-
const canonical = stateNode
|
|
1254
|
-
if (
|
|
1255
|
-
|
|
1190
|
+
if (typeof stateNode !== "object" || stateNode === null) return stateNode;
|
|
1191
|
+
const canonical = Reflect.get(stateNode, "canonical");
|
|
1192
|
+
if (typeof canonical === "object" && canonical !== null) {
|
|
1193
|
+
const publicInstance = Reflect.get(canonical, "publicInstance");
|
|
1194
|
+
if (typeof publicInstance === "object" && publicInstance !== null) {
|
|
1195
|
+
return publicInstance;
|
|
1196
|
+
}
|
|
1256
1197
|
}
|
|
1257
|
-
|
|
1198
|
+
const nativeTag = Reflect.get(stateNode, "_nativeTag");
|
|
1199
|
+
return typeof nativeTag === "number" ? nativeTag : stateNode;
|
|
1258
1200
|
};
|
|
1259
1201
|
|
|
1260
1202
|
export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
@@ -1268,7 +1210,7 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1268
1210
|
}
|
|
1269
1211
|
}
|
|
1270
1212
|
|
|
1271
|
-
if (
|
|
1213
|
+
if (typeof hostInstance === "object" && hostInstance !== null) {
|
|
1272
1214
|
const legacyRootFiber = getLegacyRootFiber(hostInstance);
|
|
1273
1215
|
if (legacyRootFiber) return legacyRootFiber;
|
|
1274
1216
|
|
|
@@ -1276,14 +1218,14 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1276
1218
|
if (internalInstanceHandle) return internalInstanceHandle;
|
|
1277
1219
|
|
|
1278
1220
|
for (const knownKey of knownFiberPropertyKeys) {
|
|
1279
|
-
const fiber = hostInstance
|
|
1221
|
+
const fiber = Reflect.get(hostInstance, knownKey);
|
|
1280
1222
|
if (isValidFiber(fiber)) return fiber;
|
|
1281
1223
|
}
|
|
1282
1224
|
|
|
1283
1225
|
for (const key of Object.keys(hostInstance)) {
|
|
1284
1226
|
if (isFiberPropertyKey(key)) {
|
|
1285
1227
|
knownFiberPropertyKeys.add(key);
|
|
1286
|
-
const fiber = hostInstance
|
|
1228
|
+
const fiber = Reflect.get(hostInstance, key);
|
|
1287
1229
|
if (isValidFiber(fiber)) return fiber;
|
|
1288
1230
|
}
|
|
1289
1231
|
}
|
|
@@ -1307,6 +1249,17 @@ export const getFiberFromHostInstance = <T>(hostInstance: T): Fiber | null => {
|
|
|
1307
1249
|
return null;
|
|
1308
1250
|
};
|
|
1309
1251
|
|
|
1310
|
-
export
|
|
1311
|
-
|
|
1312
|
-
|
|
1252
|
+
export {
|
|
1253
|
+
BIPPY_INSTRUMENTATION_STRING,
|
|
1254
|
+
_onActiveListeners,
|
|
1255
|
+
_renderers,
|
|
1256
|
+
getRDTHook,
|
|
1257
|
+
hasRDTHook,
|
|
1258
|
+
installRDTHook,
|
|
1259
|
+
isRealReactDevtools,
|
|
1260
|
+
onRendererInject,
|
|
1261
|
+
patchRDTHook,
|
|
1262
|
+
version,
|
|
1263
|
+
} from "./rdt-hook.js";
|
|
1264
|
+
export type { Unsubscribe } from "./rdt-hook.js";
|
|
1265
|
+
export type * from "./react-internals/index.js";
|