bippy 0.6.1-dev.3a24abf → 0.6.1-dev.b88fcb4
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 +7 -1
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +39 -41
- package/dist/core.d.ts +39 -41
- 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} +205 -31
- package/dist/{types.d.ts → errors.d.ts} +205 -31
- 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 -13
- package/dist/source.d.cts +27 -9
- package/dist/source.d.ts +27 -9
- package/dist/source.js +13 -13
- package/package.json +10 -6
- package/src/core.ts +269 -224
- package/src/errors.ts +99 -0
- package/src/rdt-hook.ts +154 -99
- package/src/react-internals/generated/react-work-tags.ts +314 -0
- package/src/react-internals/index.ts +67 -0
- package/src/react-internals/semver.ts +78 -0
- package/src/{types.ts → react-internals/types.ts} +13 -3
- package/src/source/error-stack.ts +11 -0
- package/src/source/get-display-name-from-source.ts +1 -1
- package/src/source/get-source.ts +2 -2
- package/src/source/index.ts +9 -1
- package/src/source/inspect-hooks.ts +199 -165
- package/src/source/owner-stack.ts +26 -39
- package/src/source/parse-debug-stack.ts +4 -4
- package/src/source/parse-hook-names.ts +1 -1
- package/src/source/symbolication.ts +468 -101
- package/src/generated/react-work-tags.ts +0 -169
- package/src/react-internals.ts +0 -67
- package/src/unsubscribe.ts +0 -17
|
@@ -1,15 +1,22 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
Fiber,
|
|
3
|
+
ContextDependency,
|
|
4
|
+
MemoizedState,
|
|
5
|
+
ReactContext,
|
|
6
|
+
RendererDispatcherRef,
|
|
7
|
+
} from "../react-internals/index.js";
|
|
8
|
+
import {
|
|
9
|
+
BippyHookInspectionError,
|
|
10
|
+
BippyHookRenderError,
|
|
11
|
+
BippyUnsupportedHookError,
|
|
12
|
+
} from "../errors.js";
|
|
13
|
+
import { getReactWorkTagsForFiber } from "../react-internals/index.js";
|
|
2
14
|
import { parseStack, type StackFrame } from "./parse-stack.js";
|
|
3
15
|
import { getRDTHook, _renderers } from "../rdt-hook.js";
|
|
4
16
|
|
|
5
17
|
const REACT_CONTEXT_TYPE = Symbol.for("react.context");
|
|
6
18
|
const REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel");
|
|
7
19
|
|
|
8
|
-
const FUNCTION_COMPONENT_TAG = 0;
|
|
9
|
-
const CONTEXT_PROVIDER_TAG = 10;
|
|
10
|
-
const FORWARD_REF_TAG = 11;
|
|
11
|
-
const SIMPLE_MEMO_COMPONENT_TAG = 15;
|
|
12
|
-
|
|
13
20
|
export interface HookSource {
|
|
14
21
|
lineNumber: number | null;
|
|
15
22
|
columnNumber: number | null;
|
|
@@ -26,8 +33,7 @@ export interface HooksNode {
|
|
|
26
33
|
hookSource: HookSource | null;
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
export interface HooksTree extends Array<HooksNode> {}
|
|
36
|
+
export type HooksTree = HooksNode[];
|
|
31
37
|
|
|
32
38
|
interface HookLogEntry {
|
|
33
39
|
displayName: string | null;
|
|
@@ -37,10 +43,29 @@ interface HookLogEntry {
|
|
|
37
43
|
dispatcherHookName: string;
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
interface
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
interface InspectableReactContext {
|
|
47
|
+
_currentValue: unknown;
|
|
48
|
+
displayName?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface InspectableRef {
|
|
52
|
+
current: unknown;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface InspectableThenable {
|
|
56
|
+
reason?: unknown;
|
|
57
|
+
status?: unknown;
|
|
58
|
+
then: (...arguments_: unknown[]) => unknown;
|
|
59
|
+
value?: unknown;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface ForwardRefRenderType {
|
|
63
|
+
render: (props: Record<string, unknown>, ref: unknown) => unknown;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface InspectedActionState {
|
|
67
|
+
error: unknown;
|
|
68
|
+
value: unknown;
|
|
44
69
|
}
|
|
45
70
|
|
|
46
71
|
let hookLog: HookLogEntry[] = [];
|
|
@@ -49,8 +74,7 @@ let currentFiber: Fiber | null = null;
|
|
|
49
74
|
let currentHook: MemoizedState | null = null;
|
|
50
75
|
let currentContextDependency: ContextDependency<unknown> | null = null;
|
|
51
76
|
let currentThenableIndex = 0;
|
|
52
|
-
|
|
53
|
-
let currentThenableState: any[] | null = null;
|
|
77
|
+
let currentThenableState: unknown[] | null = null;
|
|
54
78
|
|
|
55
79
|
const SuspenseException: unknown = new Error(
|
|
56
80
|
"Suspense Exception: This is not a real error! It's an implementation detail of `use` to interrupt the current render.",
|
|
@@ -65,33 +89,51 @@ const nextHook = (): MemoizedState | null => {
|
|
|
65
89
|
return hook;
|
|
66
90
|
};
|
|
67
91
|
|
|
68
|
-
const
|
|
92
|
+
const isObjectRecord = (value: unknown): value is Record<string, unknown> =>
|
|
93
|
+
typeof value === "object" && value !== null;
|
|
94
|
+
|
|
95
|
+
const isInspectableThenable = (value: unknown): value is InspectableThenable =>
|
|
96
|
+
isObjectRecord(value) && typeof value.then === "function";
|
|
97
|
+
|
|
98
|
+
const isInspectableRef = (value: unknown): value is InspectableRef =>
|
|
99
|
+
isObjectRecord(value) && "current" in value;
|
|
100
|
+
|
|
101
|
+
const isReactContext = (value: unknown): value is ReactContext<unknown> =>
|
|
102
|
+
isObjectRecord(value) && "_currentValue" in value;
|
|
103
|
+
|
|
104
|
+
const isContextDependency = (value: unknown): value is ContextDependency<unknown> =>
|
|
105
|
+
isObjectRecord(value) && "context" in value && "next" in value;
|
|
106
|
+
|
|
107
|
+
const isForwardRefRenderType = (value: unknown): value is ForwardRefRenderType =>
|
|
108
|
+
isObjectRecord(value) && typeof value.render === "function";
|
|
109
|
+
|
|
110
|
+
const readContext = (context: InspectableReactContext): unknown => {
|
|
69
111
|
if (currentFiber === null) return context._currentValue;
|
|
70
112
|
if (currentContextDependency === null) {
|
|
71
|
-
throw new
|
|
113
|
+
throw new BippyHookInspectionError("Context reads do not line up with context dependencies.");
|
|
72
114
|
}
|
|
73
|
-
if (Object.
|
|
74
|
-
const value = currentContextDependency.memoizedValue
|
|
115
|
+
if (Object.hasOwn(currentContextDependency, "memoizedValue")) {
|
|
116
|
+
const value = currentContextDependency.memoizedValue;
|
|
75
117
|
currentContextDependency = currentContextDependency.next;
|
|
76
118
|
return value;
|
|
77
119
|
}
|
|
78
120
|
return context._currentValue;
|
|
79
121
|
};
|
|
80
122
|
|
|
81
|
-
const getDispatcherRef = ():
|
|
123
|
+
const getDispatcherRef = (): RendererDispatcherRef | null => {
|
|
82
124
|
const rdtHook = getRDTHook();
|
|
83
125
|
const allRenderers = [..._renderers, ...rdtHook.renderers.values()];
|
|
84
126
|
for (const renderer of allRenderers) {
|
|
85
127
|
const ref = renderer.currentDispatcherRef;
|
|
86
|
-
if (ref
|
|
128
|
+
if (ref) return ref;
|
|
87
129
|
}
|
|
88
130
|
return null;
|
|
89
131
|
};
|
|
90
132
|
|
|
91
|
-
const getDispatcherFromRef = (ref:
|
|
133
|
+
const getDispatcherFromRef = (ref: RendererDispatcherRef): unknown =>
|
|
92
134
|
"H" in ref ? ref.H : ref.current;
|
|
93
135
|
|
|
94
|
-
const setDispatcherOnRef = (ref:
|
|
136
|
+
const setDispatcherOnRef = (ref: RendererDispatcherRef, dispatcher: unknown): void => {
|
|
95
137
|
if ("H" in ref) {
|
|
96
138
|
ref.H = dispatcher;
|
|
97
139
|
} else {
|
|
@@ -115,14 +157,13 @@ const pushHookLogEntry = (
|
|
|
115
157
|
};
|
|
116
158
|
|
|
117
159
|
const dispatcherUse = (usable: unknown): unknown => {
|
|
118
|
-
if (usable
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (typeof asThenable.then === "function") {
|
|
122
|
-
const thenable =
|
|
160
|
+
if (isObjectRecord(usable)) {
|
|
161
|
+
if (isInspectableThenable(usable)) {
|
|
162
|
+
const cachedThenable =
|
|
123
163
|
currentThenableState !== null && currentThenableIndex < currentThenableState.length
|
|
124
164
|
? currentThenableState[currentThenableIndex++]
|
|
125
|
-
:
|
|
165
|
+
: usable;
|
|
166
|
+
const thenable = isInspectableThenable(cachedThenable) ? cachedThenable : usable;
|
|
126
167
|
|
|
127
168
|
switch (thenable.status) {
|
|
128
169
|
case "fulfilled": {
|
|
@@ -135,19 +176,22 @@ const dispatcherUse = (usable: unknown): unknown => {
|
|
|
135
176
|
pushHookLogEntry("Unresolved", thenable, "Use");
|
|
136
177
|
throw SuspenseException;
|
|
137
178
|
}
|
|
138
|
-
if (
|
|
139
|
-
const context:
|
|
179
|
+
if (usable.$$typeof === REACT_CONTEXT_TYPE && "_currentValue" in usable) {
|
|
180
|
+
const context: InspectableReactContext = {
|
|
181
|
+
_currentValue: usable._currentValue,
|
|
182
|
+
displayName: typeof usable.displayName === "string" ? usable.displayName : undefined,
|
|
183
|
+
};
|
|
140
184
|
const value = readContext(context);
|
|
141
|
-
pushHookLogEntry("Context (use)", value, "Use", context.displayName
|
|
185
|
+
pushHookLogEntry("Context (use)", value, "Use", context.displayName ?? "Context");
|
|
142
186
|
return value;
|
|
143
187
|
}
|
|
144
188
|
}
|
|
145
|
-
throw new
|
|
189
|
+
throw new BippyHookInspectionError("An unsupported type was passed to use(): " + String(usable));
|
|
146
190
|
};
|
|
147
191
|
|
|
148
|
-
const dispatcherUseContext = (context:
|
|
192
|
+
const dispatcherUseContext = (context: InspectableReactContext): unknown => {
|
|
149
193
|
const value = readContext(context);
|
|
150
|
-
pushHookLogEntry("Context", value, "Context", context.displayName
|
|
194
|
+
pushHookLogEntry("Context", value, "Context", context.displayName ?? null);
|
|
151
195
|
return value;
|
|
152
196
|
};
|
|
153
197
|
|
|
@@ -157,7 +201,7 @@ const dispatcherUseState = (initialState: unknown): [unknown, () => void] => {
|
|
|
157
201
|
hook !== null
|
|
158
202
|
? hook.memoizedState
|
|
159
203
|
: typeof initialState === "function"
|
|
160
|
-
?
|
|
204
|
+
? initialState()
|
|
161
205
|
: initialState;
|
|
162
206
|
pushHookLogEntry("State", state, "State");
|
|
163
207
|
return [state, () => {}];
|
|
@@ -175,11 +219,13 @@ const dispatcherUseReducer = (
|
|
|
175
219
|
return [state, () => {}];
|
|
176
220
|
};
|
|
177
221
|
|
|
178
|
-
const dispatcherUseRef = (initialValue: unknown):
|
|
222
|
+
const dispatcherUseRef = (initialValue: unknown): InspectableRef => {
|
|
179
223
|
const hook = nextHook();
|
|
180
|
-
const ref = hook
|
|
181
|
-
|
|
182
|
-
|
|
224
|
+
const ref = isInspectableRef(hook?.memoizedState)
|
|
225
|
+
? hook.memoizedState
|
|
226
|
+
: { current: initialValue };
|
|
227
|
+
pushHookLogEntry("Ref", ref.current, "Ref");
|
|
228
|
+
return ref;
|
|
183
229
|
};
|
|
184
230
|
|
|
185
231
|
const dispatcherUseCacheRefresh = (): (() => void) => {
|
|
@@ -227,7 +273,7 @@ const dispatcherUseCallback = (callback: unknown): unknown => {
|
|
|
227
273
|
const hook = nextHook();
|
|
228
274
|
pushHookLogEntry(
|
|
229
275
|
"Callback",
|
|
230
|
-
hook
|
|
276
|
+
Array.isArray(hook?.memoizedState) ? hook.memoizedState[0] : callback,
|
|
231
277
|
"Callback",
|
|
232
278
|
);
|
|
233
279
|
return callback;
|
|
@@ -235,7 +281,7 @@ const dispatcherUseCallback = (callback: unknown): unknown => {
|
|
|
235
281
|
|
|
236
282
|
const dispatcherUseMemo = (nextCreate: () => unknown): unknown => {
|
|
237
283
|
const hook = nextHook();
|
|
238
|
-
const value = hook
|
|
284
|
+
const value = Array.isArray(hook?.memoizedState) ? hook.memoizedState[0] : nextCreate();
|
|
239
285
|
pushHookLogEntry("Memo", value, "Memo");
|
|
240
286
|
return value;
|
|
241
287
|
};
|
|
@@ -254,7 +300,7 @@ const dispatcherUseSyncExternalStore = (
|
|
|
254
300
|
const dispatcherUseTransition = (): [boolean, () => void] => {
|
|
255
301
|
const stateHook = nextHook();
|
|
256
302
|
nextHook();
|
|
257
|
-
const isPending = stateHook
|
|
303
|
+
const isPending = stateHook?.memoizedState === true;
|
|
258
304
|
pushHookLogEntry("Transition", isPending, "Transition");
|
|
259
305
|
return [isPending, () => {}];
|
|
260
306
|
};
|
|
@@ -268,7 +314,7 @@ const dispatcherUseDeferredValue = (value: unknown): unknown => {
|
|
|
268
314
|
|
|
269
315
|
const dispatcherUseId = (): string => {
|
|
270
316
|
const hook = nextHook();
|
|
271
|
-
const identifier = hook
|
|
317
|
+
const identifier = typeof hook?.memoizedState === "string" ? hook.memoizedState : "";
|
|
272
318
|
pushHookLogEntry("Id", identifier, "Id");
|
|
273
319
|
return identifier;
|
|
274
320
|
};
|
|
@@ -277,9 +323,7 @@ const dispatcherUseMemoCache = (size: number): unknown[] => {
|
|
|
277
323
|
const fiber = currentFiber;
|
|
278
324
|
if (fiber === null || fiber === undefined) return [];
|
|
279
325
|
|
|
280
|
-
const memoCache =
|
|
281
|
-
fiber.updateQueue as { memoCache?: { data: unknown[][]; index: number } } | null
|
|
282
|
-
)?.memoCache;
|
|
326
|
+
const memoCache = fiber.updateQueue?.memoCache;
|
|
283
327
|
if (memoCache === null || memoCache === undefined) return [];
|
|
284
328
|
|
|
285
329
|
let memoCacheSlots = memoCache.data[memoCache.index];
|
|
@@ -304,28 +348,22 @@ const dispatcherUseOptimistic = (passthrough: unknown): [unknown, () => void] =>
|
|
|
304
348
|
const inspectActionStateHook = (
|
|
305
349
|
hook: MemoizedState | null,
|
|
306
350
|
initialState: unknown,
|
|
307
|
-
):
|
|
351
|
+
): InspectedActionState => {
|
|
308
352
|
let value: unknown;
|
|
309
353
|
let error: unknown = null;
|
|
310
354
|
if (hook !== null) {
|
|
311
355
|
const actionResult = hook.memoizedState;
|
|
312
|
-
if (
|
|
313
|
-
|
|
314
|
-
actionResult !== null &&
|
|
315
|
-
"then" in actionResult &&
|
|
316
|
-
typeof actionResult.then === "function"
|
|
317
|
-
) {
|
|
318
|
-
const thenable = actionResult as { status?: string; value?: unknown; reason?: unknown };
|
|
319
|
-
switch (thenable.status) {
|
|
356
|
+
if (isInspectableThenable(actionResult)) {
|
|
357
|
+
switch (actionResult.status) {
|
|
320
358
|
case "fulfilled":
|
|
321
|
-
value =
|
|
359
|
+
value = actionResult.value;
|
|
322
360
|
break;
|
|
323
361
|
case "rejected":
|
|
324
|
-
error =
|
|
362
|
+
error = actionResult.reason;
|
|
325
363
|
break;
|
|
326
364
|
default:
|
|
327
365
|
error = SuspenseException;
|
|
328
|
-
value =
|
|
366
|
+
value = actionResult;
|
|
329
367
|
}
|
|
330
368
|
} else {
|
|
331
369
|
value = actionResult;
|
|
@@ -360,7 +398,7 @@ const dispatcherUseFormState = createActionStateDispatcher("FormState");
|
|
|
360
398
|
|
|
361
399
|
const dispatcherUseHostTransitionStatus = (): unknown => {
|
|
362
400
|
// HACK: creating a minimal fake context because useHostTransitionStatus reads from an internal context not available outside React
|
|
363
|
-
const status = readContext({ _currentValue: null }
|
|
401
|
+
const status = readContext({ _currentValue: null });
|
|
364
402
|
pushHookLogEntry("HostTransitionStatus", status, "HostTransitionStatus");
|
|
365
403
|
return status;
|
|
366
404
|
};
|
|
@@ -371,8 +409,7 @@ const dispatcherUseEffectEvent = (callback: (...args: unknown[]) => unknown): ty
|
|
|
371
409
|
return callback;
|
|
372
410
|
};
|
|
373
411
|
|
|
374
|
-
|
|
375
|
-
const Dispatcher: Record<string, (...args: any[]) => any> = {
|
|
412
|
+
const dispatcher = {
|
|
376
413
|
readContext,
|
|
377
414
|
use: dispatcherUse,
|
|
378
415
|
useCallback: dispatcherUseCallback,
|
|
@@ -399,15 +436,13 @@ const Dispatcher: Record<string, (...args: any[]) => any> = {
|
|
|
399
436
|
useEffectEvent: dispatcherUseEffectEvent,
|
|
400
437
|
};
|
|
401
438
|
|
|
402
|
-
const
|
|
439
|
+
const dispatcherProxy =
|
|
403
440
|
typeof Proxy === "undefined"
|
|
404
|
-
?
|
|
405
|
-
: new Proxy(
|
|
406
|
-
get(target,
|
|
407
|
-
if (Object.
|
|
408
|
-
|
|
409
|
-
error.name = "ReactDebugToolsUnsupportedHookError";
|
|
410
|
-
throw error;
|
|
441
|
+
? dispatcher
|
|
442
|
+
: new Proxy(dispatcher, {
|
|
443
|
+
get(target, propertyName: string) {
|
|
444
|
+
if (Object.hasOwn(target, propertyName)) return Reflect.get(target, propertyName);
|
|
445
|
+
throw new BippyUnsupportedHookError("Missing method in Dispatcher: " + propertyName);
|
|
411
446
|
},
|
|
412
447
|
});
|
|
413
448
|
|
|
@@ -418,41 +453,41 @@ const getPrimitiveStackCache = (): Map<string, StackFrame[]> => {
|
|
|
418
453
|
let capturedHookLog: HookLogEntry[];
|
|
419
454
|
|
|
420
455
|
try {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
if (typeof
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
456
|
+
dispatcher.useContext({ _currentValue: null });
|
|
457
|
+
dispatcher.useState(null);
|
|
458
|
+
dispatcher.useReducer((state: unknown) => state, null);
|
|
459
|
+
dispatcher.useRef(null);
|
|
460
|
+
if (typeof dispatcher.useCacheRefresh === "function") dispatcher.useCacheRefresh();
|
|
461
|
+
dispatcher.useLayoutEffect(() => {});
|
|
462
|
+
dispatcher.useInsertionEffect(() => {});
|
|
463
|
+
dispatcher.useEffect(() => {});
|
|
464
|
+
dispatcher.useImperativeHandle(undefined);
|
|
465
|
+
dispatcher.useDebugValue(null);
|
|
466
|
+
dispatcher.useCallback(() => {});
|
|
467
|
+
dispatcher.useTransition();
|
|
468
|
+
dispatcher.useSyncExternalStore(
|
|
434
469
|
() => () => {},
|
|
435
470
|
() => null,
|
|
436
|
-
() => null,
|
|
437
471
|
);
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
if (typeof
|
|
445
|
-
if (typeof
|
|
446
|
-
|
|
447
|
-
|
|
472
|
+
dispatcher.useDeferredValue(null);
|
|
473
|
+
dispatcher.useMemo(() => null);
|
|
474
|
+
dispatcher.useOptimistic(null);
|
|
475
|
+
dispatcher.useFormState((state: unknown) => state, null);
|
|
476
|
+
dispatcher.useActionState((state: unknown) => state, null);
|
|
477
|
+
dispatcher.useHostTransitionStatus();
|
|
478
|
+
if (typeof dispatcher.useMemoCache === "function") dispatcher.useMemoCache(0);
|
|
479
|
+
if (typeof dispatcher.use === "function") {
|
|
480
|
+
dispatcher.use({ $$typeof: REACT_CONTEXT_TYPE, _currentValue: null });
|
|
481
|
+
const fulfilledPromise = Promise.resolve(null);
|
|
482
|
+
Reflect.set(fulfilledPromise, "status", "fulfilled");
|
|
483
|
+
Reflect.set(fulfilledPromise, "value", null);
|
|
484
|
+
dispatcher.use(fulfilledPromise);
|
|
448
485
|
try {
|
|
449
|
-
|
|
450
|
-
} catch {
|
|
451
|
-
/* noop */
|
|
452
|
-
}
|
|
486
|
+
dispatcher.use(new Promise<never>(() => {}));
|
|
487
|
+
} catch {}
|
|
453
488
|
}
|
|
454
|
-
|
|
455
|
-
if (typeof
|
|
489
|
+
dispatcher.useId();
|
|
490
|
+
if (typeof dispatcher.useEffectEvent === "function") dispatcher.useEffectEvent(() => {});
|
|
456
491
|
} finally {
|
|
457
492
|
capturedHookLog = hookLog;
|
|
458
493
|
hookLog = [];
|
|
@@ -681,14 +716,17 @@ const processDebugValues = (hooksTree: HooksTree, parentHooksNode: HooksNode | n
|
|
|
681
716
|
const setupContexts = (contextMap: Map<ReactContext<unknown>, unknown>, fiber: Fiber): void => {
|
|
682
717
|
let current: Fiber | null = fiber;
|
|
683
718
|
while (current) {
|
|
684
|
-
if (current.tag ===
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
719
|
+
if (current.tag === getReactWorkTagsForFiber(current).ContextProvider) {
|
|
720
|
+
const providerType = current.type;
|
|
721
|
+
const nestedContext = isObjectRecord(providerType) ? providerType._context : undefined;
|
|
722
|
+
const context = isReactContext(nestedContext)
|
|
723
|
+
? nestedContext
|
|
724
|
+
: isReactContext(providerType)
|
|
725
|
+
? providerType
|
|
726
|
+
: null;
|
|
727
|
+
if (context && !contextMap.has(context)) {
|
|
690
728
|
contextMap.set(context, context._currentValue);
|
|
691
|
-
context._currentValue =
|
|
729
|
+
context._currentValue = current.memoizedProps.value;
|
|
692
730
|
}
|
|
693
731
|
}
|
|
694
732
|
current = current.return;
|
|
@@ -703,25 +741,22 @@ const restoreContexts = (contextMap: Map<ReactContext<unknown>, unknown>): void
|
|
|
703
741
|
|
|
704
742
|
const handleRenderFunctionError = (error: unknown): void => {
|
|
705
743
|
if (error === SuspenseException) return;
|
|
706
|
-
if (error instanceof
|
|
707
|
-
|
|
708
|
-
wrapperError.name = "ReactDebugToolsRenderError";
|
|
709
|
-
(wrapperError as { cause: unknown }).cause = error;
|
|
710
|
-
throw wrapperError;
|
|
744
|
+
if (error instanceof BippyUnsupportedHookError) throw error;
|
|
745
|
+
throw new BippyHookRenderError("Error rendering inspected component", error);
|
|
711
746
|
};
|
|
712
747
|
|
|
713
748
|
const resolveDefaultProps = (
|
|
714
|
-
|
|
749
|
+
component: unknown,
|
|
715
750
|
baseProps: Record<string, unknown>,
|
|
716
751
|
): Record<string, unknown> => {
|
|
717
752
|
if (
|
|
718
|
-
|
|
719
|
-
typeof
|
|
720
|
-
"defaultProps" in
|
|
721
|
-
|
|
753
|
+
component &&
|
|
754
|
+
typeof component === "object" &&
|
|
755
|
+
"defaultProps" in component &&
|
|
756
|
+
isObjectRecord(component.defaultProps)
|
|
722
757
|
) {
|
|
723
758
|
const props = { ...baseProps };
|
|
724
|
-
const defaultProps =
|
|
759
|
+
const defaultProps = component.defaultProps;
|
|
725
760
|
for (const propName in defaultProps) {
|
|
726
761
|
if (props[propName] === undefined) {
|
|
727
762
|
props[propName] = defaultProps[propName];
|
|
@@ -736,11 +771,9 @@ const suppressConsole = (): Record<string, unknown> => {
|
|
|
736
771
|
const originalMethods: Record<string, unknown> = {};
|
|
737
772
|
for (const method in console) {
|
|
738
773
|
try {
|
|
739
|
-
originalMethods[method] = (console
|
|
740
|
-
(console
|
|
741
|
-
} catch {
|
|
742
|
-
/* noop */
|
|
743
|
-
}
|
|
774
|
+
originalMethods[method] = Reflect.get(console, method);
|
|
775
|
+
Reflect.set(console, method, () => {});
|
|
776
|
+
} catch {}
|
|
744
777
|
}
|
|
745
778
|
return originalMethods;
|
|
746
779
|
};
|
|
@@ -748,19 +781,17 @@ const suppressConsole = (): Record<string, unknown> => {
|
|
|
748
781
|
const restoreConsole = (originalMethods: Record<string, unknown>): void => {
|
|
749
782
|
for (const method in originalMethods) {
|
|
750
783
|
try {
|
|
751
|
-
(console
|
|
752
|
-
} catch {
|
|
753
|
-
/* noop */
|
|
754
|
-
}
|
|
784
|
+
Reflect.set(console, method, originalMethods[method]);
|
|
785
|
+
} catch {}
|
|
755
786
|
}
|
|
756
787
|
};
|
|
757
788
|
|
|
758
789
|
const performDispatcherInspection = (
|
|
759
|
-
dispatcherRef:
|
|
790
|
+
dispatcherRef: RendererDispatcherRef,
|
|
760
791
|
renderFn: () => void,
|
|
761
792
|
): HooksTree => {
|
|
762
793
|
const previousDispatcher = getDispatcherFromRef(dispatcherRef);
|
|
763
|
-
setDispatcherOnRef(dispatcherRef,
|
|
794
|
+
setDispatcherOnRef(dispatcherRef, dispatcherProxy);
|
|
764
795
|
|
|
765
796
|
let capturedHookLog: HookLogEntry[] = [];
|
|
766
797
|
let ancestorStackError: Error | undefined;
|
|
@@ -780,10 +811,10 @@ const performDispatcherInspection = (
|
|
|
780
811
|
return buildTree(rootStack, capturedHookLog);
|
|
781
812
|
};
|
|
782
813
|
|
|
783
|
-
const requireDispatcherRef = ():
|
|
814
|
+
const requireDispatcherRef = (): RendererDispatcherRef => {
|
|
784
815
|
const dispatcherRef = getDispatcherRef();
|
|
785
816
|
if (!dispatcherRef) {
|
|
786
|
-
throw new
|
|
817
|
+
throw new BippyHookInspectionError(
|
|
787
818
|
"No React renderer found. Make sure React is loaded and bippy's hook is installed.",
|
|
788
819
|
);
|
|
789
820
|
}
|
|
@@ -791,38 +822,38 @@ const requireDispatcherRef = (): DispatcherRefContainer => {
|
|
|
791
822
|
};
|
|
792
823
|
|
|
793
824
|
const resolveContextDependency = (fiber: Fiber): void => {
|
|
794
|
-
if (Object.
|
|
825
|
+
if (Object.hasOwn(fiber, "dependencies")) {
|
|
795
826
|
const dependencies = fiber.dependencies;
|
|
796
827
|
currentContextDependency = dependencies !== null ? dependencies.firstContext : null;
|
|
797
|
-
} else if (Object.
|
|
798
|
-
const dependencies = (fiber
|
|
799
|
-
|
|
800
|
-
currentContextDependency =
|
|
801
|
-
} else if (Object.
|
|
802
|
-
const dependencies = (fiber
|
|
803
|
-
|
|
804
|
-
currentContextDependency =
|
|
805
|
-
} else if (Object.
|
|
806
|
-
const contextDependencies = (
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
}
|
|
810
|
-
).contextDependencies;
|
|
811
|
-
currentContextDependency = contextDependencies !== null ? contextDependencies.first : null;
|
|
828
|
+
} else if (Object.hasOwn(fiber, "dependencies_old")) {
|
|
829
|
+
const dependencies: unknown = Reflect.get(fiber, "dependencies_old");
|
|
830
|
+
const firstContext = isObjectRecord(dependencies) ? dependencies.firstContext : null;
|
|
831
|
+
currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
|
|
832
|
+
} else if (Object.hasOwn(fiber, "dependencies_new")) {
|
|
833
|
+
const dependencies: unknown = Reflect.get(fiber, "dependencies_new");
|
|
834
|
+
const firstContext = isObjectRecord(dependencies) ? dependencies.firstContext : null;
|
|
835
|
+
currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
|
|
836
|
+
} else if (Object.hasOwn(fiber, "contextDependencies")) {
|
|
837
|
+
const contextDependencies: unknown = Reflect.get(fiber, "contextDependencies");
|
|
838
|
+
const firstContext = isObjectRecord(contextDependencies) ? contextDependencies.first : null;
|
|
839
|
+
currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
|
|
812
840
|
} else {
|
|
813
|
-
throw new
|
|
841
|
+
throw new BippyHookInspectionError("Unsupported React version.");
|
|
814
842
|
}
|
|
815
843
|
};
|
|
816
844
|
|
|
817
845
|
export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
818
846
|
const dispatcherRef = requireDispatcherRef();
|
|
847
|
+
const workTags = getReactWorkTagsForFiber(fiber);
|
|
819
848
|
|
|
820
849
|
if (
|
|
821
|
-
fiber.tag !==
|
|
822
|
-
fiber.tag !==
|
|
823
|
-
fiber.tag !==
|
|
850
|
+
fiber.tag !== workTags.FunctionComponent &&
|
|
851
|
+
fiber.tag !== workTags.SimpleMemoComponent &&
|
|
852
|
+
fiber.tag !== workTags.ForwardRef
|
|
824
853
|
) {
|
|
825
|
-
throw new
|
|
854
|
+
throw new BippyHookInspectionError(
|
|
855
|
+
"Unknown Fiber. Needs to be a function component to inspect hooks.",
|
|
856
|
+
);
|
|
826
857
|
}
|
|
827
858
|
|
|
828
859
|
getPrimitiveStackCache();
|
|
@@ -830,19 +861,17 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
830
861
|
currentHook = fiber.memoizedState;
|
|
831
862
|
currentFiber = fiber;
|
|
832
863
|
|
|
833
|
-
const debugThenableState =
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
? debugThenableState.thenables || debugThenableState
|
|
838
|
-
: null;
|
|
864
|
+
const debugThenableState = fiber.dependencies?._debugThenableState;
|
|
865
|
+
const usedThenables = Array.isArray(debugThenableState)
|
|
866
|
+
? debugThenableState
|
|
867
|
+
: debugThenableState?.thenables;
|
|
839
868
|
currentThenableState = Array.isArray(usedThenables) ? usedThenables : null;
|
|
840
869
|
currentThenableIndex = 0;
|
|
841
870
|
|
|
842
871
|
resolveContextDependency(fiber);
|
|
843
872
|
|
|
844
873
|
const type = fiber.type;
|
|
845
|
-
let props = fiber.memoizedProps
|
|
874
|
+
let props = fiber.memoizedProps;
|
|
846
875
|
if (type !== fiber.elementType) {
|
|
847
876
|
props = resolveDefaultProps(type, props);
|
|
848
877
|
}
|
|
@@ -853,22 +882,27 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
853
882
|
try {
|
|
854
883
|
if (
|
|
855
884
|
currentContextDependency !== null &&
|
|
856
|
-
!Object.
|
|
885
|
+
!Object.hasOwn(currentContextDependency, "memoizedValue")
|
|
857
886
|
) {
|
|
858
887
|
setupContexts(contextMap, fiber);
|
|
859
888
|
}
|
|
860
889
|
|
|
861
|
-
if (fiber.tag ===
|
|
890
|
+
if (fiber.tag === workTags.ForwardRef) {
|
|
891
|
+
if (!isForwardRefRenderType(type)) {
|
|
892
|
+
throw new BippyHookInspectionError("ForwardRef fiber is missing its render function.");
|
|
893
|
+
}
|
|
862
894
|
return performDispatcherInspection(dispatcherRef, () => {
|
|
863
|
-
|
|
864
|
-
props,
|
|
865
|
-
fiber.ref,
|
|
866
|
-
);
|
|
895
|
+
type.render(props, fiber.ref);
|
|
867
896
|
});
|
|
868
897
|
}
|
|
869
898
|
|
|
899
|
+
if (typeof type !== "function") {
|
|
900
|
+
throw new BippyHookInspectionError(
|
|
901
|
+
"Function component fiber is missing its component function.",
|
|
902
|
+
);
|
|
903
|
+
}
|
|
870
904
|
return performDispatcherInspection(dispatcherRef, () => {
|
|
871
|
-
|
|
905
|
+
type(props);
|
|
872
906
|
});
|
|
873
907
|
} finally {
|
|
874
908
|
currentFiber = null;
|