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