bippy 0.6.0 → 0.6.1-dev.03b829a
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 +126 -136
- 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 +447 -0
- package/dist/errors.d.ts +447 -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 -4
- package/dist/source.d.cts +27 -9
- package/dist/source.d.ts +27 -9
- package/dist/source.js +14 -4
- package/package.json +32 -22
- package/src/core.ts +368 -314
- package/src/errors.ts +34 -0
- package/src/install-hook-only.ts +2 -2
- package/src/rdt-hook.ts +150 -153
- 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 +78 -0
- package/src/react-internals/types.ts +269 -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 +1 -1
- package/src/source/get-source.ts +4 -3
- package/src/source/index.ts +9 -1
- package/src/source/inspect-hooks.ts +221 -169
- package/src/source/owner-stack.ts +88 -114
- 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 -1
- package/src/source/symbolication.ts +488 -88
- 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;
|
|
@@ -360,7 +401,7 @@ const dispatcherUseFormState = createActionStateDispatcher("FormState");
|
|
|
360
401
|
|
|
361
402
|
const dispatcherUseHostTransitionStatus = (): unknown => {
|
|
362
403
|
// HACK: creating a minimal fake context because useHostTransitionStatus reads from an internal context not available outside React
|
|
363
|
-
const status = readContext({ _currentValue: null }
|
|
404
|
+
const status = readContext({ _currentValue: null });
|
|
364
405
|
pushHookLogEntry("HostTransitionStatus", status, "HostTransitionStatus");
|
|
365
406
|
return status;
|
|
366
407
|
};
|
|
@@ -371,8 +412,7 @@ const dispatcherUseEffectEvent = (callback: (...args: unknown[]) => unknown): ty
|
|
|
371
412
|
return callback;
|
|
372
413
|
};
|
|
373
414
|
|
|
374
|
-
|
|
375
|
-
const Dispatcher: Record<string, (...args: any[]) => any> = {
|
|
415
|
+
const dispatcher = {
|
|
376
416
|
readContext,
|
|
377
417
|
use: dispatcherUse,
|
|
378
418
|
useCallback: dispatcherUseCallback,
|
|
@@ -399,15 +439,15 @@ const Dispatcher: Record<string, (...args: any[]) => any> = {
|
|
|
399
439
|
useEffectEvent: dispatcherUseEffectEvent,
|
|
400
440
|
};
|
|
401
441
|
|
|
402
|
-
const
|
|
442
|
+
const dispatcherProxy =
|
|
403
443
|
typeof Proxy === "undefined"
|
|
404
|
-
?
|
|
405
|
-
: new Proxy(
|
|
406
|
-
get(target,
|
|
407
|
-
if (Object.
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
444
|
+
? dispatcher
|
|
445
|
+
: new Proxy(dispatcher, {
|
|
446
|
+
get(target, propertyName: string) {
|
|
447
|
+
if (Object.hasOwn(target, propertyName)) return Reflect.get(target, propertyName);
|
|
448
|
+
throw new BippyUnsupportedHookError(
|
|
449
|
+
"The React dispatcher is missing method " + propertyName,
|
|
450
|
+
);
|
|
411
451
|
},
|
|
412
452
|
});
|
|
413
453
|
|
|
@@ -418,41 +458,41 @@ const getPrimitiveStackCache = (): Map<string, StackFrame[]> => {
|
|
|
418
458
|
let capturedHookLog: HookLogEntry[];
|
|
419
459
|
|
|
420
460
|
try {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
if (typeof
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
461
|
+
dispatcher.useContext({ _currentValue: null });
|
|
462
|
+
dispatcher.useState(null);
|
|
463
|
+
dispatcher.useReducer((state: unknown) => state, null);
|
|
464
|
+
dispatcher.useRef(null);
|
|
465
|
+
if (typeof dispatcher.useCacheRefresh === "function") dispatcher.useCacheRefresh();
|
|
466
|
+
dispatcher.useLayoutEffect(() => {});
|
|
467
|
+
dispatcher.useInsertionEffect(() => {});
|
|
468
|
+
dispatcher.useEffect(() => {});
|
|
469
|
+
dispatcher.useImperativeHandle(undefined);
|
|
470
|
+
dispatcher.useDebugValue(null);
|
|
471
|
+
dispatcher.useCallback(() => {});
|
|
472
|
+
dispatcher.useTransition();
|
|
473
|
+
dispatcher.useSyncExternalStore(
|
|
434
474
|
() => () => {},
|
|
435
475
|
() => null,
|
|
436
|
-
() => null,
|
|
437
476
|
);
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
if (typeof
|
|
445
|
-
if (typeof
|
|
446
|
-
|
|
447
|
-
|
|
477
|
+
dispatcher.useDeferredValue(null);
|
|
478
|
+
dispatcher.useMemo(() => null);
|
|
479
|
+
dispatcher.useOptimistic(null);
|
|
480
|
+
dispatcher.useFormState((state: unknown) => state, null);
|
|
481
|
+
dispatcher.useActionState((state: unknown) => state, null);
|
|
482
|
+
dispatcher.useHostTransitionStatus();
|
|
483
|
+
if (typeof dispatcher.useMemoCache === "function") dispatcher.useMemoCache(0);
|
|
484
|
+
if (typeof dispatcher.use === "function") {
|
|
485
|
+
dispatcher.use({ $$typeof: REACT_CONTEXT_TYPE, _currentValue: null });
|
|
486
|
+
const fulfilledPromise = Promise.resolve(null);
|
|
487
|
+
Reflect.set(fulfilledPromise, "status", "fulfilled");
|
|
488
|
+
Reflect.set(fulfilledPromise, "value", null);
|
|
489
|
+
dispatcher.use(fulfilledPromise);
|
|
448
490
|
try {
|
|
449
|
-
|
|
450
|
-
} catch {
|
|
451
|
-
/* noop */
|
|
452
|
-
}
|
|
491
|
+
dispatcher.use(new Promise<never>(() => {}));
|
|
492
|
+
} catch {}
|
|
453
493
|
}
|
|
454
|
-
|
|
455
|
-
if (typeof
|
|
494
|
+
dispatcher.useId();
|
|
495
|
+
if (typeof dispatcher.useEffectEvent === "function") dispatcher.useEffectEvent(() => {});
|
|
456
496
|
} finally {
|
|
457
497
|
capturedHookLog = hookLog;
|
|
458
498
|
hookLog = [];
|
|
@@ -681,14 +721,20 @@ const processDebugValues = (hooksTree: HooksTree, parentHooksNode: HooksNode | n
|
|
|
681
721
|
const setupContexts = (contextMap: Map<ReactContext<unknown>, unknown>, fiber: Fiber): void => {
|
|
682
722
|
let current: Fiber | null = fiber;
|
|
683
723
|
while (current) {
|
|
684
|
-
if (current.tag ===
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
724
|
+
if (current.tag === getReactWorkTagsForFiber(current).ContextProvider) {
|
|
725
|
+
const providerType = current.type;
|
|
726
|
+
const nestedContext =
|
|
727
|
+
typeof providerType === "object" && providerType !== null && "_context" in providerType
|
|
728
|
+
? providerType._context
|
|
729
|
+
: undefined;
|
|
730
|
+
const context = isReactContext(nestedContext)
|
|
731
|
+
? nestedContext
|
|
732
|
+
: isReactContext(providerType)
|
|
733
|
+
? providerType
|
|
734
|
+
: null;
|
|
735
|
+
if (context && !contextMap.has(context)) {
|
|
690
736
|
contextMap.set(context, context._currentValue);
|
|
691
|
-
context._currentValue =
|
|
737
|
+
context._currentValue = current.memoizedProps.value;
|
|
692
738
|
}
|
|
693
739
|
}
|
|
694
740
|
current = current.return;
|
|
@@ -703,28 +749,26 @@ const restoreContexts = (contextMap: Map<ReactContext<unknown>, unknown>): void
|
|
|
703
749
|
|
|
704
750
|
const handleRenderFunctionError = (error: unknown): void => {
|
|
705
751
|
if (error === SuspenseException) return;
|
|
706
|
-
if (error instanceof
|
|
707
|
-
|
|
708
|
-
wrapperError.name = "ReactDebugToolsRenderError";
|
|
709
|
-
(wrapperError as { cause: unknown }).cause = error;
|
|
710
|
-
throw wrapperError;
|
|
752
|
+
if (error instanceof BippyUnsupportedHookError) throw error;
|
|
753
|
+
throw new BippyHookRenderError("Bippy couldn’t render the inspected component", error);
|
|
711
754
|
};
|
|
712
755
|
|
|
713
756
|
const resolveDefaultProps = (
|
|
714
|
-
|
|
757
|
+
component: unknown,
|
|
715
758
|
baseProps: Record<string, unknown>,
|
|
716
759
|
): Record<string, unknown> => {
|
|
717
760
|
if (
|
|
718
|
-
|
|
719
|
-
typeof
|
|
720
|
-
"defaultProps" in
|
|
721
|
-
|
|
761
|
+
component &&
|
|
762
|
+
typeof component === "object" &&
|
|
763
|
+
"defaultProps" in component &&
|
|
764
|
+
typeof component.defaultProps === "object" &&
|
|
765
|
+
component.defaultProps !== null
|
|
722
766
|
) {
|
|
723
767
|
const props = { ...baseProps };
|
|
724
|
-
const defaultProps =
|
|
725
|
-
for (const propName
|
|
768
|
+
const defaultProps = component.defaultProps;
|
|
769
|
+
for (const [propName, value] of Object.entries(defaultProps)) {
|
|
726
770
|
if (props[propName] === undefined) {
|
|
727
|
-
props[propName] =
|
|
771
|
+
props[propName] = value;
|
|
728
772
|
}
|
|
729
773
|
}
|
|
730
774
|
return props;
|
|
@@ -736,11 +780,9 @@ const suppressConsole = (): Record<string, unknown> => {
|
|
|
736
780
|
const originalMethods: Record<string, unknown> = {};
|
|
737
781
|
for (const method in console) {
|
|
738
782
|
try {
|
|
739
|
-
originalMethods[method] = (console
|
|
740
|
-
(console
|
|
741
|
-
} catch {
|
|
742
|
-
/* noop */
|
|
743
|
-
}
|
|
783
|
+
originalMethods[method] = Reflect.get(console, method);
|
|
784
|
+
Reflect.set(console, method, () => {});
|
|
785
|
+
} catch {}
|
|
744
786
|
}
|
|
745
787
|
return originalMethods;
|
|
746
788
|
};
|
|
@@ -748,19 +790,17 @@ const suppressConsole = (): Record<string, unknown> => {
|
|
|
748
790
|
const restoreConsole = (originalMethods: Record<string, unknown>): void => {
|
|
749
791
|
for (const method in originalMethods) {
|
|
750
792
|
try {
|
|
751
|
-
(console
|
|
752
|
-
} catch {
|
|
753
|
-
/* noop */
|
|
754
|
-
}
|
|
793
|
+
Reflect.set(console, method, originalMethods[method]);
|
|
794
|
+
} catch {}
|
|
755
795
|
}
|
|
756
796
|
};
|
|
757
797
|
|
|
758
798
|
const performDispatcherInspection = (
|
|
759
|
-
dispatcherRef:
|
|
799
|
+
dispatcherRef: RendererDispatcherRef,
|
|
760
800
|
renderFn: () => void,
|
|
761
801
|
): HooksTree => {
|
|
762
802
|
const previousDispatcher = getDispatcherFromRef(dispatcherRef);
|
|
763
|
-
setDispatcherOnRef(dispatcherRef,
|
|
803
|
+
setDispatcherOnRef(dispatcherRef, dispatcherProxy);
|
|
764
804
|
|
|
765
805
|
let capturedHookLog: HookLogEntry[] = [];
|
|
766
806
|
let ancestorStackError: Error | undefined;
|
|
@@ -780,49 +820,58 @@ const performDispatcherInspection = (
|
|
|
780
820
|
return buildTree(rootStack, capturedHookLog);
|
|
781
821
|
};
|
|
782
822
|
|
|
783
|
-
const requireDispatcherRef = ():
|
|
823
|
+
const requireDispatcherRef = (): RendererDispatcherRef => {
|
|
784
824
|
const dispatcherRef = getDispatcherRef();
|
|
785
825
|
if (!dispatcherRef) {
|
|
786
|
-
throw new
|
|
787
|
-
"
|
|
826
|
+
throw new BippyHookInspectionError(
|
|
827
|
+
"Bippy couldn’t find a React renderer. Load React and install Bippy’s hook.",
|
|
788
828
|
);
|
|
789
829
|
}
|
|
790
830
|
return dispatcherRef;
|
|
791
831
|
};
|
|
792
832
|
|
|
793
833
|
const resolveContextDependency = (fiber: Fiber): void => {
|
|
794
|
-
if (Object.
|
|
834
|
+
if (Object.hasOwn(fiber, "dependencies")) {
|
|
795
835
|
const dependencies = fiber.dependencies;
|
|
796
836
|
currentContextDependency = dependencies !== null ? dependencies.firstContext : null;
|
|
797
|
-
} else if (Object.
|
|
798
|
-
const dependencies = (fiber
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
)
|
|
811
|
-
|
|
837
|
+
} else if (Object.hasOwn(fiber, "dependencies_old")) {
|
|
838
|
+
const dependencies: unknown = Reflect.get(fiber, "dependencies_old");
|
|
839
|
+
const firstContext =
|
|
840
|
+
typeof dependencies === "object" && dependencies !== null && "firstContext" in dependencies
|
|
841
|
+
? dependencies.firstContext
|
|
842
|
+
: null;
|
|
843
|
+
currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
|
|
844
|
+
} else if (Object.hasOwn(fiber, "dependencies_new")) {
|
|
845
|
+
const dependencies: unknown = Reflect.get(fiber, "dependencies_new");
|
|
846
|
+
const firstContext =
|
|
847
|
+
typeof dependencies === "object" && dependencies !== null && "firstContext" in dependencies
|
|
848
|
+
? dependencies.firstContext
|
|
849
|
+
: null;
|
|
850
|
+
currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
|
|
851
|
+
} else if (Object.hasOwn(fiber, "contextDependencies")) {
|
|
852
|
+
const contextDependencies: unknown = Reflect.get(fiber, "contextDependencies");
|
|
853
|
+
const firstContext =
|
|
854
|
+
typeof contextDependencies === "object" &&
|
|
855
|
+
contextDependencies !== null &&
|
|
856
|
+
"first" in contextDependencies
|
|
857
|
+
? contextDependencies.first
|
|
858
|
+
: null;
|
|
859
|
+
currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
|
|
812
860
|
} else {
|
|
813
|
-
throw new
|
|
861
|
+
throw new BippyHookInspectionError("Bippy doesn’t support this React version.");
|
|
814
862
|
}
|
|
815
863
|
};
|
|
816
864
|
|
|
817
865
|
export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
818
866
|
const dispatcherRef = requireDispatcherRef();
|
|
867
|
+
const workTags = getReactWorkTagsForFiber(fiber);
|
|
819
868
|
|
|
820
869
|
if (
|
|
821
|
-
fiber.tag !==
|
|
822
|
-
fiber.tag !==
|
|
823
|
-
fiber.tag !==
|
|
870
|
+
fiber.tag !== workTags.FunctionComponent &&
|
|
871
|
+
fiber.tag !== workTags.SimpleMemoComponent &&
|
|
872
|
+
fiber.tag !== workTags.ForwardRef
|
|
824
873
|
) {
|
|
825
|
-
throw new
|
|
874
|
+
throw new BippyHookInspectionError("Hook inspection requires a function component Fiber.");
|
|
826
875
|
}
|
|
827
876
|
|
|
828
877
|
getPrimitiveStackCache();
|
|
@@ -830,19 +879,17 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
830
879
|
currentHook = fiber.memoizedState;
|
|
831
880
|
currentFiber = fiber;
|
|
832
881
|
|
|
833
|
-
const debugThenableState =
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
? debugThenableState.thenables || debugThenableState
|
|
838
|
-
: null;
|
|
882
|
+
const debugThenableState = fiber.dependencies?._debugThenableState;
|
|
883
|
+
const usedThenables = Array.isArray(debugThenableState)
|
|
884
|
+
? debugThenableState
|
|
885
|
+
: debugThenableState?.thenables;
|
|
839
886
|
currentThenableState = Array.isArray(usedThenables) ? usedThenables : null;
|
|
840
887
|
currentThenableIndex = 0;
|
|
841
888
|
|
|
842
889
|
resolveContextDependency(fiber);
|
|
843
890
|
|
|
844
891
|
const type = fiber.type;
|
|
845
|
-
let props = fiber.memoizedProps
|
|
892
|
+
let props = fiber.memoizedProps;
|
|
846
893
|
if (type !== fiber.elementType) {
|
|
847
894
|
props = resolveDefaultProps(type, props);
|
|
848
895
|
}
|
|
@@ -853,22 +900,27 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
853
900
|
try {
|
|
854
901
|
if (
|
|
855
902
|
currentContextDependency !== null &&
|
|
856
|
-
!Object.
|
|
903
|
+
!Object.hasOwn(currentContextDependency, "memoizedValue")
|
|
857
904
|
) {
|
|
858
905
|
setupContexts(contextMap, fiber);
|
|
859
906
|
}
|
|
860
907
|
|
|
861
|
-
if (fiber.tag ===
|
|
908
|
+
if (fiber.tag === workTags.ForwardRef) {
|
|
909
|
+
if (!isForwardRefRenderType(type)) {
|
|
910
|
+
throw new BippyHookInspectionError("ForwardRef fiber is missing its render function.");
|
|
911
|
+
}
|
|
862
912
|
return performDispatcherInspection(dispatcherRef, () => {
|
|
863
|
-
|
|
864
|
-
props,
|
|
865
|
-
fiber.ref,
|
|
866
|
-
);
|
|
913
|
+
type.render(props, fiber.ref);
|
|
867
914
|
});
|
|
868
915
|
}
|
|
869
916
|
|
|
917
|
+
if (typeof type !== "function") {
|
|
918
|
+
throw new BippyHookInspectionError(
|
|
919
|
+
"Function component fiber is missing its component function.",
|
|
920
|
+
);
|
|
921
|
+
}
|
|
870
922
|
return performDispatcherInspection(dispatcherRef, () => {
|
|
871
|
-
|
|
923
|
+
type(props);
|
|
872
924
|
});
|
|
873
925
|
} finally {
|
|
874
926
|
currentFiber = null;
|