bippy 0.5.35 → 0.5.38
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/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core2.d.cts +1 -1
- package/dist/core2.d.ts +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.iife.js +1 -1
- package/dist/install-hook-only.iife.js +1 -1
- package/dist/rdt-hook.cjs +1 -1
- package/dist/rdt-hook.js +1 -1
- package/dist/source.cjs +14 -11
- package/dist/source.d.cts +26 -2
- package/dist/source.d.ts +26 -2
- package/dist/source.js +14 -11
- package/package.json +1 -1
- package/src/source/index.ts +2 -0
- package/src/source/inspect-hooks.ts +879 -0
- package/src/source/parse-hook-names.ts +224 -0
- package/src/types.ts +157 -22
|
@@ -0,0 +1,879 @@
|
|
|
1
|
+
import type { Fiber, ContextDependency, MemoizedState, ReactContext } from "../types.js";
|
|
2
|
+
import { parseStack, type StackFrame } from "./parse-stack.js";
|
|
3
|
+
import { getRDTHook, _renderers } from "../rdt-hook.js";
|
|
4
|
+
|
|
5
|
+
const REACT_CONTEXT_TYPE = Symbol.for("react.context");
|
|
6
|
+
const REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel");
|
|
7
|
+
|
|
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
|
+
export interface HookSource {
|
|
14
|
+
lineNumber: number | null;
|
|
15
|
+
columnNumber: number | null;
|
|
16
|
+
fileName: string | null;
|
|
17
|
+
functionName: string | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface HooksNode {
|
|
21
|
+
id: number | null;
|
|
22
|
+
isStateEditable: boolean;
|
|
23
|
+
name: string;
|
|
24
|
+
value: unknown;
|
|
25
|
+
subHooks: HooksNode[];
|
|
26
|
+
hookSource: HookSource | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
30
|
+
export interface HooksTree extends Array<HooksNode> {}
|
|
31
|
+
|
|
32
|
+
interface HookLogEntry {
|
|
33
|
+
displayName: string | null;
|
|
34
|
+
primitive: string;
|
|
35
|
+
stackError: Error;
|
|
36
|
+
value: unknown;
|
|
37
|
+
dispatcherHookName: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface DispatcherRefContainer {
|
|
41
|
+
H?: unknown;
|
|
42
|
+
current?: unknown;
|
|
43
|
+
[key: string]: unknown;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let hookLog: HookLogEntry[] = [];
|
|
47
|
+
let primitiveStackCache: Map<string, StackFrame[]> | null = null;
|
|
48
|
+
let currentFiber: Fiber | null = null;
|
|
49
|
+
let currentHook: MemoizedState | null = null;
|
|
50
|
+
let currentContextDependency: ContextDependency<unknown> | null = null;
|
|
51
|
+
let currentThenableIndex = 0;
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
let currentThenableState: any[] | null = null;
|
|
54
|
+
|
|
55
|
+
const SuspenseException: unknown = new Error(
|
|
56
|
+
"Suspense Exception: This is not a real error! It's an implementation detail of `use` to interrupt the current render.",
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const parseErrorStack = (error: Error): StackFrame[] =>
|
|
60
|
+
parseStack(error.stack || "", { includeInElement: false });
|
|
61
|
+
|
|
62
|
+
const nextHook = (): MemoizedState | null => {
|
|
63
|
+
const hook = currentHook;
|
|
64
|
+
if (hook !== null) currentHook = hook.next;
|
|
65
|
+
return hook;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const readContext = <T>(context: ReactContext<T>): T => {
|
|
69
|
+
if (currentFiber === null) return context._currentValue;
|
|
70
|
+
if (currentContextDependency === null) {
|
|
71
|
+
throw new Error("Context reads do not line up with context dependencies.");
|
|
72
|
+
}
|
|
73
|
+
if (Object.prototype.hasOwnProperty.call(currentContextDependency, "memoizedValue")) {
|
|
74
|
+
const value = currentContextDependency.memoizedValue as T;
|
|
75
|
+
currentContextDependency = currentContextDependency.next;
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
return context._currentValue;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const getDispatcherRef = (): DispatcherRefContainer | null => {
|
|
82
|
+
const rdtHook = getRDTHook();
|
|
83
|
+
const allRenderers = [..._renderers, ...rdtHook.renderers.values()];
|
|
84
|
+
for (const renderer of allRenderers) {
|
|
85
|
+
const ref = renderer.currentDispatcherRef;
|
|
86
|
+
if (ref && typeof ref === "object") return ref as DispatcherRefContainer;
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const getDispatcherFromRef = (ref: DispatcherRefContainer): unknown =>
|
|
92
|
+
"H" in ref ? ref.H : ref.current;
|
|
93
|
+
|
|
94
|
+
const setDispatcherOnRef = (ref: DispatcherRefContainer, dispatcher: unknown): void => {
|
|
95
|
+
if ("H" in ref) {
|
|
96
|
+
ref.H = dispatcher;
|
|
97
|
+
} else {
|
|
98
|
+
ref.current = dispatcher;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const pushHookLogEntry = (
|
|
103
|
+
primitive: string,
|
|
104
|
+
value: unknown,
|
|
105
|
+
dispatcherHookName: string,
|
|
106
|
+
displayName: string | null = null,
|
|
107
|
+
): void => {
|
|
108
|
+
hookLog.push({
|
|
109
|
+
displayName,
|
|
110
|
+
primitive,
|
|
111
|
+
stackError: new Error(),
|
|
112
|
+
value,
|
|
113
|
+
dispatcherHookName,
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const dispatcherUse = (usable: unknown): unknown => {
|
|
118
|
+
if (usable !== null && typeof usable === "object") {
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
120
|
+
const asThenable = usable as any;
|
|
121
|
+
if (typeof asThenable.then === "function") {
|
|
122
|
+
const thenable =
|
|
123
|
+
currentThenableState !== null && currentThenableIndex < currentThenableState.length
|
|
124
|
+
? currentThenableState[currentThenableIndex++]
|
|
125
|
+
: asThenable;
|
|
126
|
+
|
|
127
|
+
switch (thenable.status) {
|
|
128
|
+
case "fulfilled": {
|
|
129
|
+
pushHookLogEntry("Promise", thenable.value, "Use");
|
|
130
|
+
return thenable.value;
|
|
131
|
+
}
|
|
132
|
+
case "rejected":
|
|
133
|
+
throw thenable.reason;
|
|
134
|
+
}
|
|
135
|
+
pushHookLogEntry("Unresolved", thenable, "Use");
|
|
136
|
+
throw SuspenseException;
|
|
137
|
+
}
|
|
138
|
+
if (asThenable.$$typeof === REACT_CONTEXT_TYPE && "_currentValue" in asThenable) {
|
|
139
|
+
const context: ReactContext<unknown> = asThenable;
|
|
140
|
+
const value = readContext(context);
|
|
141
|
+
pushHookLogEntry("Context (use)", value, "Use", context.displayName || "Context");
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
throw new Error("An unsupported type was passed to use(): " + String(usable));
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const dispatcherUseContext = (context: ReactContext<unknown>): unknown => {
|
|
149
|
+
const value = readContext(context);
|
|
150
|
+
pushHookLogEntry("Context", value, "Context", context.displayName || null);
|
|
151
|
+
return value;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const dispatcherUseState = (initialState: unknown): [unknown, () => void] => {
|
|
155
|
+
const hook = nextHook();
|
|
156
|
+
const state =
|
|
157
|
+
hook !== null
|
|
158
|
+
? hook.memoizedState
|
|
159
|
+
: typeof initialState === "function"
|
|
160
|
+
? (initialState as () => unknown)()
|
|
161
|
+
: initialState;
|
|
162
|
+
pushHookLogEntry("State", state, "State");
|
|
163
|
+
return [state, () => {}];
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const dispatcherUseReducer = (
|
|
167
|
+
_reducer: unknown,
|
|
168
|
+
initialArg: unknown,
|
|
169
|
+
init?: (arg: unknown) => unknown,
|
|
170
|
+
): [unknown, () => void] => {
|
|
171
|
+
const hook = nextHook();
|
|
172
|
+
const state =
|
|
173
|
+
hook !== null ? hook.memoizedState : init !== undefined ? init(initialArg) : initialArg;
|
|
174
|
+
pushHookLogEntry("Reducer", state, "Reducer");
|
|
175
|
+
return [state, () => {}];
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const dispatcherUseRef = (initialValue: unknown): { current: unknown } => {
|
|
179
|
+
const hook = nextHook();
|
|
180
|
+
const ref = hook !== null ? hook.memoizedState : { current: initialValue };
|
|
181
|
+
pushHookLogEntry("Ref", (ref as { current: unknown }).current, "Ref");
|
|
182
|
+
return ref as { current: unknown };
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const dispatcherUseCacheRefresh = (): (() => void) => {
|
|
186
|
+
const hook = nextHook();
|
|
187
|
+
pushHookLogEntry("CacheRefresh", hook !== null ? hook.memoizedState : () => {}, "CacheRefresh");
|
|
188
|
+
return () => {};
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const dispatcherUseLayoutEffect = (create: () => void): void => {
|
|
192
|
+
nextHook();
|
|
193
|
+
pushHookLogEntry("LayoutEffect", create, "LayoutEffect");
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const dispatcherUseInsertionEffect = (create: () => unknown): void => {
|
|
197
|
+
nextHook();
|
|
198
|
+
pushHookLogEntry("InsertionEffect", create, "InsertionEffect");
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const dispatcherUseEffect = (create: () => void): void => {
|
|
202
|
+
nextHook();
|
|
203
|
+
pushHookLogEntry("Effect", create, "Effect");
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const dispatcherUseImperativeHandle = (ref: unknown): void => {
|
|
207
|
+
nextHook();
|
|
208
|
+
let instance: unknown;
|
|
209
|
+
if (ref !== null && typeof ref === "object" && "current" in ref) {
|
|
210
|
+
instance = ref.current;
|
|
211
|
+
}
|
|
212
|
+
pushHookLogEntry("ImperativeHandle", instance, "ImperativeHandle");
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const dispatcherUseDebugValue = (
|
|
216
|
+
value: unknown,
|
|
217
|
+
formatterFn?: (value: unknown) => unknown,
|
|
218
|
+
): void => {
|
|
219
|
+
pushHookLogEntry(
|
|
220
|
+
"DebugValue",
|
|
221
|
+
typeof formatterFn === "function" ? formatterFn(value) : value,
|
|
222
|
+
"DebugValue",
|
|
223
|
+
);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const dispatcherUseCallback = (callback: unknown): unknown => {
|
|
227
|
+
const hook = nextHook();
|
|
228
|
+
pushHookLogEntry(
|
|
229
|
+
"Callback",
|
|
230
|
+
hook !== null ? (hook.memoizedState as unknown[])[0] : callback,
|
|
231
|
+
"Callback",
|
|
232
|
+
);
|
|
233
|
+
return callback;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const dispatcherUseMemo = (nextCreate: () => unknown): unknown => {
|
|
237
|
+
const hook = nextHook();
|
|
238
|
+
const value = hook !== null ? (hook.memoizedState as unknown[])[0] : nextCreate();
|
|
239
|
+
pushHookLogEntry("Memo", value, "Memo");
|
|
240
|
+
return value;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const dispatcherUseSyncExternalStore = (
|
|
244
|
+
_subscribe: unknown,
|
|
245
|
+
getSnapshot: () => unknown,
|
|
246
|
+
): unknown => {
|
|
247
|
+
const hook = nextHook();
|
|
248
|
+
nextHook();
|
|
249
|
+
const value = hook !== null ? hook.memoizedState : getSnapshot();
|
|
250
|
+
pushHookLogEntry("SyncExternalStore", value, "SyncExternalStore");
|
|
251
|
+
return value;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const dispatcherUseTransition = (): [boolean, () => void] => {
|
|
255
|
+
const stateHook = nextHook();
|
|
256
|
+
nextHook();
|
|
257
|
+
const isPending = stateHook !== null ? (stateHook.memoizedState as boolean) : false;
|
|
258
|
+
pushHookLogEntry("Transition", isPending, "Transition");
|
|
259
|
+
return [isPending, () => {}];
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const dispatcherUseDeferredValue = (value: unknown): unknown => {
|
|
263
|
+
const hook = nextHook();
|
|
264
|
+
const previousValue = hook !== null ? hook.memoizedState : value;
|
|
265
|
+
pushHookLogEntry("DeferredValue", previousValue, "DeferredValue");
|
|
266
|
+
return previousValue;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const dispatcherUseId = (): string => {
|
|
270
|
+
const hook = nextHook();
|
|
271
|
+
const identifier = hook !== null ? (hook.memoizedState as string) : "";
|
|
272
|
+
pushHookLogEntry("Id", identifier, "Id");
|
|
273
|
+
return identifier;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const dispatcherUseMemoCache = (size: number): unknown[] => {
|
|
277
|
+
const fiber = currentFiber;
|
|
278
|
+
if (fiber === null || fiber === undefined) return [];
|
|
279
|
+
|
|
280
|
+
const memoCache = (
|
|
281
|
+
fiber.updateQueue as { memoCache?: { data: unknown[][]; index: number } } | null
|
|
282
|
+
)?.memoCache;
|
|
283
|
+
if (memoCache === null || memoCache === undefined) return [];
|
|
284
|
+
|
|
285
|
+
let data = memoCache.data[memoCache.index];
|
|
286
|
+
if (data === undefined) {
|
|
287
|
+
data = memoCache.data[memoCache.index] = Array.from(
|
|
288
|
+
{ length: size },
|
|
289
|
+
() => REACT_MEMO_CACHE_SENTINEL,
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
memoCache.index++;
|
|
294
|
+
return data;
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const dispatcherUseOptimistic = (passthrough: unknown): [unknown, () => void] => {
|
|
298
|
+
const hook = nextHook();
|
|
299
|
+
const state = hook !== null ? hook.memoizedState : passthrough;
|
|
300
|
+
pushHookLogEntry("Optimistic", state, "Optimistic");
|
|
301
|
+
return [state, () => {}];
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const inspectActionStateHook = (
|
|
305
|
+
hook: MemoizedState | null,
|
|
306
|
+
initialState: unknown,
|
|
307
|
+
): { value: unknown; error: unknown } => {
|
|
308
|
+
let value: unknown;
|
|
309
|
+
let error: unknown = null;
|
|
310
|
+
if (hook !== null) {
|
|
311
|
+
const actionResult = hook.memoizedState;
|
|
312
|
+
if (
|
|
313
|
+
typeof actionResult === "object" &&
|
|
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) {
|
|
320
|
+
case "fulfilled":
|
|
321
|
+
value = thenable.value;
|
|
322
|
+
break;
|
|
323
|
+
case "rejected":
|
|
324
|
+
error = thenable.reason;
|
|
325
|
+
break;
|
|
326
|
+
default:
|
|
327
|
+
error = SuspenseException;
|
|
328
|
+
value = thenable;
|
|
329
|
+
}
|
|
330
|
+
} else {
|
|
331
|
+
value = actionResult;
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
value = initialState;
|
|
335
|
+
}
|
|
336
|
+
return { value, error };
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
const createActionStateDispatcher =
|
|
340
|
+
(primitive: string) =>
|
|
341
|
+
(_action: unknown, initialState: unknown): [unknown, () => void, boolean] => {
|
|
342
|
+
const hook = nextHook();
|
|
343
|
+
nextHook();
|
|
344
|
+
nextHook();
|
|
345
|
+
const stackError = new Error();
|
|
346
|
+
const { value, error } = inspectActionStateHook(hook, initialState);
|
|
347
|
+
hookLog.push({
|
|
348
|
+
displayName: null,
|
|
349
|
+
primitive,
|
|
350
|
+
stackError,
|
|
351
|
+
value,
|
|
352
|
+
dispatcherHookName: primitive,
|
|
353
|
+
});
|
|
354
|
+
if (error !== null) throw error;
|
|
355
|
+
return [value, () => {}, false];
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const dispatcherUseActionState = createActionStateDispatcher("ActionState");
|
|
359
|
+
const dispatcherUseFormState = createActionStateDispatcher("FormState");
|
|
360
|
+
|
|
361
|
+
const dispatcherUseHostTransitionStatus = (): unknown => {
|
|
362
|
+
// HACK: creating a minimal fake context because useHostTransitionStatus reads from an internal context not available outside React
|
|
363
|
+
const status = readContext({ _currentValue: null } as unknown as ReactContext<unknown>);
|
|
364
|
+
pushHookLogEntry("HostTransitionStatus", status, "HostTransitionStatus");
|
|
365
|
+
return status;
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
const dispatcherUseEffectEvent = (callback: (...args: unknown[]) => unknown): typeof callback => {
|
|
369
|
+
nextHook();
|
|
370
|
+
pushHookLogEntry("EffectEvent", callback, "EffectEvent");
|
|
371
|
+
return callback;
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
375
|
+
const Dispatcher: Record<string, (...args: any[]) => any> = {
|
|
376
|
+
readContext,
|
|
377
|
+
use: dispatcherUse,
|
|
378
|
+
useCallback: dispatcherUseCallback,
|
|
379
|
+
useContext: dispatcherUseContext,
|
|
380
|
+
useEffect: dispatcherUseEffect,
|
|
381
|
+
useImperativeHandle: dispatcherUseImperativeHandle,
|
|
382
|
+
useLayoutEffect: dispatcherUseLayoutEffect,
|
|
383
|
+
useInsertionEffect: dispatcherUseInsertionEffect,
|
|
384
|
+
useMemo: dispatcherUseMemo,
|
|
385
|
+
useReducer: dispatcherUseReducer,
|
|
386
|
+
useRef: dispatcherUseRef,
|
|
387
|
+
useState: dispatcherUseState,
|
|
388
|
+
useDebugValue: dispatcherUseDebugValue,
|
|
389
|
+
useDeferredValue: dispatcherUseDeferredValue,
|
|
390
|
+
useTransition: dispatcherUseTransition,
|
|
391
|
+
useSyncExternalStore: dispatcherUseSyncExternalStore,
|
|
392
|
+
useId: dispatcherUseId,
|
|
393
|
+
useHostTransitionStatus: dispatcherUseHostTransitionStatus,
|
|
394
|
+
useFormState: dispatcherUseFormState,
|
|
395
|
+
useActionState: dispatcherUseActionState,
|
|
396
|
+
useOptimistic: dispatcherUseOptimistic,
|
|
397
|
+
useMemoCache: dispatcherUseMemoCache,
|
|
398
|
+
useCacheRefresh: dispatcherUseCacheRefresh,
|
|
399
|
+
useEffectEvent: dispatcherUseEffectEvent,
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
const DispatcherProxy =
|
|
403
|
+
typeof Proxy === "undefined"
|
|
404
|
+
? Dispatcher
|
|
405
|
+
: new Proxy(Dispatcher, {
|
|
406
|
+
get(target, prop: string) {
|
|
407
|
+
if (Object.prototype.hasOwnProperty.call(target, prop)) return target[prop];
|
|
408
|
+
const error = new Error("Missing method in Dispatcher: " + prop);
|
|
409
|
+
error.name = "ReactDebugToolsUnsupportedHookError";
|
|
410
|
+
throw error;
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
const getPrimitiveStackCache = (): Map<string, StackFrame[]> => {
|
|
415
|
+
if (primitiveStackCache !== null) return primitiveStackCache;
|
|
416
|
+
|
|
417
|
+
const cache = new Map<string, StackFrame[]>();
|
|
418
|
+
let capturedHookLog: HookLogEntry[];
|
|
419
|
+
|
|
420
|
+
try {
|
|
421
|
+
Dispatcher.useContext({ _currentValue: null });
|
|
422
|
+
Dispatcher.useState(null);
|
|
423
|
+
Dispatcher.useReducer((state: unknown) => state, null);
|
|
424
|
+
Dispatcher.useRef(null);
|
|
425
|
+
if (typeof Dispatcher.useCacheRefresh === "function") Dispatcher.useCacheRefresh();
|
|
426
|
+
Dispatcher.useLayoutEffect(() => {});
|
|
427
|
+
Dispatcher.useInsertionEffect(() => {});
|
|
428
|
+
Dispatcher.useEffect(() => {});
|
|
429
|
+
Dispatcher.useImperativeHandle(undefined, () => null);
|
|
430
|
+
Dispatcher.useDebugValue(null);
|
|
431
|
+
Dispatcher.useCallback(() => {});
|
|
432
|
+
Dispatcher.useTransition();
|
|
433
|
+
Dispatcher.useSyncExternalStore(
|
|
434
|
+
() => () => {},
|
|
435
|
+
() => null,
|
|
436
|
+
() => null,
|
|
437
|
+
);
|
|
438
|
+
Dispatcher.useDeferredValue(null);
|
|
439
|
+
Dispatcher.useMemo(() => null);
|
|
440
|
+
Dispatcher.useOptimistic(null, (state: unknown) => state);
|
|
441
|
+
Dispatcher.useFormState((state: unknown) => state, null);
|
|
442
|
+
Dispatcher.useActionState((state: unknown) => state, null);
|
|
443
|
+
Dispatcher.useHostTransitionStatus();
|
|
444
|
+
if (typeof Dispatcher.useMemoCache === "function") Dispatcher.useMemoCache(0);
|
|
445
|
+
if (typeof Dispatcher.use === "function") {
|
|
446
|
+
Dispatcher.use({ $$typeof: REACT_CONTEXT_TYPE, _currentValue: null });
|
|
447
|
+
Dispatcher.use({ then() {}, status: "fulfilled", value: null });
|
|
448
|
+
try {
|
|
449
|
+
Dispatcher.use({ then() {} });
|
|
450
|
+
} catch {
|
|
451
|
+
/* noop */
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
Dispatcher.useId();
|
|
455
|
+
if (typeof Dispatcher.useEffectEvent === "function") Dispatcher.useEffectEvent(() => {});
|
|
456
|
+
} finally {
|
|
457
|
+
capturedHookLog = hookLog;
|
|
458
|
+
hookLog = [];
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
for (const hook of capturedHookLog) {
|
|
462
|
+
cache.set(hook.primitive, parseErrorStack(hook.stackError));
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
primitiveStackCache = cache;
|
|
466
|
+
return primitiveStackCache;
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
let mostLikelyAncestorIndex = 0;
|
|
470
|
+
|
|
471
|
+
const findSharedIndex = (
|
|
472
|
+
hookStack: StackFrame[],
|
|
473
|
+
rootStack: StackFrame[],
|
|
474
|
+
rootIndex: number,
|
|
475
|
+
): number => {
|
|
476
|
+
const source = rootStack[rootIndex].source;
|
|
477
|
+
hookSearch: for (let hookIndex = 0; hookIndex < hookStack.length; hookIndex++) {
|
|
478
|
+
if (hookStack[hookIndex].source === source) {
|
|
479
|
+
for (
|
|
480
|
+
let rootOffset = rootIndex + 1, hookOffset = hookIndex + 1;
|
|
481
|
+
rootOffset < rootStack.length && hookOffset < hookStack.length;
|
|
482
|
+
rootOffset++, hookOffset++
|
|
483
|
+
) {
|
|
484
|
+
if (hookStack[hookOffset].source !== rootStack[rootOffset].source) continue hookSearch;
|
|
485
|
+
}
|
|
486
|
+
return hookIndex;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return -1;
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
const findCommonAncestorIndex = (rootStack: StackFrame[], hookStack: StackFrame[]): number => {
|
|
493
|
+
let rootIndex = findSharedIndex(hookStack, rootStack, mostLikelyAncestorIndex);
|
|
494
|
+
if (rootIndex !== -1) return rootIndex;
|
|
495
|
+
for (
|
|
496
|
+
let candidateIndex = 0;
|
|
497
|
+
candidateIndex < rootStack.length && candidateIndex < 5;
|
|
498
|
+
candidateIndex++
|
|
499
|
+
) {
|
|
500
|
+
rootIndex = findSharedIndex(hookStack, rootStack, candidateIndex);
|
|
501
|
+
if (rootIndex !== -1) {
|
|
502
|
+
mostLikelyAncestorIndex = candidateIndex;
|
|
503
|
+
return rootIndex;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return -1;
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
const parseHookName = (functionName: string | undefined): string => {
|
|
510
|
+
if (!functionName) return "";
|
|
511
|
+
let startIndex = functionName.lastIndexOf("[as ");
|
|
512
|
+
if (startIndex !== -1) {
|
|
513
|
+
return parseHookName(functionName.slice(startIndex + "[as ".length, -1));
|
|
514
|
+
}
|
|
515
|
+
startIndex = functionName.lastIndexOf(".");
|
|
516
|
+
startIndex = startIndex === -1 ? 0 : startIndex + 1;
|
|
517
|
+
if (functionName.slice(startIndex).startsWith("unstable_")) startIndex += "unstable_".length;
|
|
518
|
+
if (functionName.slice(startIndex).startsWith("experimental_"))
|
|
519
|
+
startIndex += "experimental_".length;
|
|
520
|
+
if (functionName.slice(startIndex, startIndex + 3) === "use") {
|
|
521
|
+
if (functionName.length - startIndex === 3) return "Use";
|
|
522
|
+
startIndex += 3;
|
|
523
|
+
}
|
|
524
|
+
return functionName.slice(startIndex);
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
const isReactWrapper = (functionName: string | undefined, wrapperName: string): boolean => {
|
|
528
|
+
const hookName = parseHookName(functionName);
|
|
529
|
+
if (wrapperName === "HostTransitionStatus") {
|
|
530
|
+
return hookName === wrapperName || hookName === "FormStatus";
|
|
531
|
+
}
|
|
532
|
+
return hookName === wrapperName;
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
const findPrimitiveIndex = (hookStack: StackFrame[], hook: HookLogEntry): number => {
|
|
536
|
+
const stackCache = getPrimitiveStackCache();
|
|
537
|
+
const primitiveStack = stackCache.get(hook.primitive);
|
|
538
|
+
if (primitiveStack === undefined) return -1;
|
|
539
|
+
for (
|
|
540
|
+
let frameIndex = 0;
|
|
541
|
+
frameIndex < primitiveStack.length && frameIndex < hookStack.length;
|
|
542
|
+
frameIndex++
|
|
543
|
+
) {
|
|
544
|
+
if (primitiveStack[frameIndex].source !== hookStack[frameIndex].source) {
|
|
545
|
+
if (
|
|
546
|
+
frameIndex < hookStack.length - 1 &&
|
|
547
|
+
isReactWrapper(hookStack[frameIndex].functionName, hook.dispatcherHookName)
|
|
548
|
+
) {
|
|
549
|
+
frameIndex++;
|
|
550
|
+
}
|
|
551
|
+
if (
|
|
552
|
+
frameIndex < hookStack.length - 1 &&
|
|
553
|
+
isReactWrapper(hookStack[frameIndex].functionName, hook.dispatcherHookName)
|
|
554
|
+
) {
|
|
555
|
+
frameIndex++;
|
|
556
|
+
}
|
|
557
|
+
return frameIndex;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return -1;
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
const parseTrimmedStack = (
|
|
564
|
+
rootStack: StackFrame[],
|
|
565
|
+
hook: HookLogEntry,
|
|
566
|
+
): [StackFrame | null, StackFrame[] | null] => {
|
|
567
|
+
const hookStack = parseErrorStack(hook.stackError);
|
|
568
|
+
const rootIndex = findCommonAncestorIndex(rootStack, hookStack);
|
|
569
|
+
const primitiveIndex = findPrimitiveIndex(hookStack, hook);
|
|
570
|
+
if (rootIndex === -1 || primitiveIndex === -1 || rootIndex - primitiveIndex < 2) {
|
|
571
|
+
if (primitiveIndex === -1) return [null, null];
|
|
572
|
+
return [hookStack[primitiveIndex - 1] ?? null, null];
|
|
573
|
+
}
|
|
574
|
+
return [hookStack[primitiveIndex - 1] ?? null, hookStack.slice(primitiveIndex, rootIndex - 1)];
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
const NON_ID_HOOK_PRIMITIVES = new Set([
|
|
578
|
+
"Context",
|
|
579
|
+
"Context (use)",
|
|
580
|
+
"DebugValue",
|
|
581
|
+
"Promise",
|
|
582
|
+
"Unresolved",
|
|
583
|
+
"HostTransitionStatus",
|
|
584
|
+
]);
|
|
585
|
+
|
|
586
|
+
const buildTree = (rootStack: StackFrame[], capturedHookLog: HookLogEntry[]): HooksTree => {
|
|
587
|
+
const rootChildren: HooksNode[] = [];
|
|
588
|
+
let previousStack: StackFrame[] | null = null;
|
|
589
|
+
let levelChildren = rootChildren;
|
|
590
|
+
let nativeHookID = 0;
|
|
591
|
+
const childrenStack: HooksNode[][] = [];
|
|
592
|
+
|
|
593
|
+
for (const hook of capturedHookLog) {
|
|
594
|
+
const [primitiveFrame, stack] = parseTrimmedStack(rootStack, hook);
|
|
595
|
+
let displayName = hook.displayName;
|
|
596
|
+
if (displayName === null && primitiveFrame !== null) {
|
|
597
|
+
displayName =
|
|
598
|
+
parseHookName(primitiveFrame.functionName) || parseHookName(hook.dispatcherHookName);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (stack !== null) {
|
|
602
|
+
let commonSteps = 0;
|
|
603
|
+
if (previousStack !== null) {
|
|
604
|
+
while (commonSteps < stack.length && commonSteps < previousStack.length) {
|
|
605
|
+
const stackSource = stack[stack.length - commonSteps - 1].source;
|
|
606
|
+
const previousSource = previousStack[previousStack.length - commonSteps - 1].source;
|
|
607
|
+
if (stackSource !== previousSource) break;
|
|
608
|
+
commonSteps++;
|
|
609
|
+
}
|
|
610
|
+
for (let popIndex = previousStack.length - 1; popIndex > commonSteps; popIndex--) {
|
|
611
|
+
levelChildren = childrenStack.pop() ?? rootChildren;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
for (let stackIndex = stack.length - commonSteps - 1; stackIndex >= 1; stackIndex--) {
|
|
615
|
+
const children: HooksNode[] = [];
|
|
616
|
+
const stackFrame = stack[stackIndex];
|
|
617
|
+
const levelChild: HooksNode = {
|
|
618
|
+
id: null,
|
|
619
|
+
isStateEditable: false,
|
|
620
|
+
name: parseHookName(stack[stackIndex - 1].functionName),
|
|
621
|
+
value: undefined,
|
|
622
|
+
subHooks: children,
|
|
623
|
+
hookSource: {
|
|
624
|
+
lineNumber: stackFrame.lineNumber ?? null,
|
|
625
|
+
columnNumber: stackFrame.columnNumber ?? null,
|
|
626
|
+
functionName: stackFrame.functionName ?? null,
|
|
627
|
+
fileName: stackFrame.fileName ?? null,
|
|
628
|
+
},
|
|
629
|
+
};
|
|
630
|
+
levelChildren.push(levelChild);
|
|
631
|
+
childrenStack.push(levelChildren);
|
|
632
|
+
levelChildren = children;
|
|
633
|
+
}
|
|
634
|
+
previousStack = stack;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
const { primitive } = hook;
|
|
638
|
+
const id = NON_ID_HOOK_PRIMITIVES.has(primitive) ? null : nativeHookID++;
|
|
639
|
+
const isStateEditable = primitive === "Reducer" || primitive === "State";
|
|
640
|
+
const name = displayName || primitive;
|
|
641
|
+
|
|
642
|
+
const firstStackFrame = stack?.[0];
|
|
643
|
+
const hookSource: HookSource = {
|
|
644
|
+
lineNumber: firstStackFrame?.lineNumber ?? null,
|
|
645
|
+
columnNumber: firstStackFrame?.columnNumber ?? null,
|
|
646
|
+
functionName: firstStackFrame?.functionName ?? null,
|
|
647
|
+
fileName: firstStackFrame?.fileName ?? null,
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
levelChildren.push({ id, isStateEditable, name, value: hook.value, subHooks: [], hookSource });
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
processDebugValues(rootChildren, null);
|
|
654
|
+
return rootChildren;
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
const processDebugValues = (hooksTree: HooksTree, parentHooksNode: HooksNode | null): void => {
|
|
658
|
+
const debugValueNodes: HooksNode[] = [];
|
|
659
|
+
for (let nodeIndex = 0; nodeIndex < hooksTree.length; nodeIndex++) {
|
|
660
|
+
const hooksNode = hooksTree[nodeIndex];
|
|
661
|
+
if (hooksNode.name === "DebugValue" && hooksNode.subHooks.length === 0) {
|
|
662
|
+
hooksTree.splice(nodeIndex, 1);
|
|
663
|
+
nodeIndex--;
|
|
664
|
+
debugValueNodes.push(hooksNode);
|
|
665
|
+
} else {
|
|
666
|
+
processDebugValues(hooksNode.subHooks, hooksNode);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (parentHooksNode !== null) {
|
|
670
|
+
if (debugValueNodes.length === 1) {
|
|
671
|
+
parentHooksNode.value = debugValueNodes[0].value;
|
|
672
|
+
} else if (debugValueNodes.length > 1) {
|
|
673
|
+
parentHooksNode.value = debugValueNodes.map(({ value }) => value);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
const setupContexts = (contextMap: Map<ReactContext<unknown>, unknown>, fiber: Fiber): void => {
|
|
679
|
+
let current: Fiber | null = fiber;
|
|
680
|
+
while (current) {
|
|
681
|
+
if (current.tag === CONTEXT_PROVIDER_TAG) {
|
|
682
|
+
let context = current.type as ReactContext<unknown>;
|
|
683
|
+
if ("_context" in context && context._context !== undefined) {
|
|
684
|
+
context = context._context as ReactContext<unknown>;
|
|
685
|
+
}
|
|
686
|
+
if (!contextMap.has(context)) {
|
|
687
|
+
contextMap.set(context, context._currentValue);
|
|
688
|
+
context._currentValue = (current.memoizedProps as { value: unknown }).value;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
current = current.return;
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
|
|
695
|
+
const restoreContexts = (contextMap: Map<ReactContext<unknown>, unknown>): void => {
|
|
696
|
+
contextMap.forEach((value, context) => {
|
|
697
|
+
context._currentValue = value;
|
|
698
|
+
});
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
const handleRenderFunctionError = (error: unknown): void => {
|
|
702
|
+
if (error === SuspenseException) return;
|
|
703
|
+
if (error instanceof Error && error.name === "ReactDebugToolsUnsupportedHookError") throw error;
|
|
704
|
+
const wrapperError = new Error("Error rendering inspected component", { cause: error });
|
|
705
|
+
wrapperError.name = "ReactDebugToolsRenderError";
|
|
706
|
+
(wrapperError as { cause: unknown }).cause = error;
|
|
707
|
+
throw wrapperError;
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
const resolveDefaultProps = (
|
|
711
|
+
Component: unknown,
|
|
712
|
+
baseProps: Record<string, unknown>,
|
|
713
|
+
): Record<string, unknown> => {
|
|
714
|
+
if (
|
|
715
|
+
Component &&
|
|
716
|
+
typeof Component === "object" &&
|
|
717
|
+
"defaultProps" in Component &&
|
|
718
|
+
Component.defaultProps
|
|
719
|
+
) {
|
|
720
|
+
const props = { ...baseProps };
|
|
721
|
+
const defaultProps = Component.defaultProps as Record<string, unknown>;
|
|
722
|
+
for (const propName in defaultProps) {
|
|
723
|
+
if (props[propName] === undefined) {
|
|
724
|
+
props[propName] = defaultProps[propName];
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return props;
|
|
728
|
+
}
|
|
729
|
+
return baseProps;
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
const suppressConsole = (): Record<string, unknown> => {
|
|
733
|
+
const originalMethods: Record<string, unknown> = {};
|
|
734
|
+
for (const method in console) {
|
|
735
|
+
try {
|
|
736
|
+
originalMethods[method] = (console as Record<string, unknown>)[method];
|
|
737
|
+
(console as Record<string, unknown>)[method] = () => {};
|
|
738
|
+
} catch {
|
|
739
|
+
/* noop */
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
return originalMethods;
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
const restoreConsole = (originalMethods: Record<string, unknown>): void => {
|
|
746
|
+
for (const method in originalMethods) {
|
|
747
|
+
try {
|
|
748
|
+
(console as Record<string, unknown>)[method] = originalMethods[method];
|
|
749
|
+
} catch {
|
|
750
|
+
/* noop */
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
const performDispatcherInspection = (
|
|
756
|
+
dispatcherRef: DispatcherRefContainer,
|
|
757
|
+
renderFn: () => void,
|
|
758
|
+
): HooksTree => {
|
|
759
|
+
const previousDispatcher = getDispatcherFromRef(dispatcherRef);
|
|
760
|
+
setDispatcherOnRef(dispatcherRef, DispatcherProxy);
|
|
761
|
+
|
|
762
|
+
let capturedHookLog: HookLogEntry[] = [];
|
|
763
|
+
let ancestorStackError: Error | undefined;
|
|
764
|
+
|
|
765
|
+
try {
|
|
766
|
+
ancestorStackError = new Error();
|
|
767
|
+
renderFn();
|
|
768
|
+
} catch (renderError) {
|
|
769
|
+
handleRenderFunctionError(renderError);
|
|
770
|
+
} finally {
|
|
771
|
+
capturedHookLog = hookLog;
|
|
772
|
+
hookLog = [];
|
|
773
|
+
setDispatcherOnRef(dispatcherRef, previousDispatcher);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
const rootStack = ancestorStackError !== undefined ? parseErrorStack(ancestorStackError) : [];
|
|
777
|
+
return buildTree(rootStack, capturedHookLog);
|
|
778
|
+
};
|
|
779
|
+
|
|
780
|
+
const requireDispatcherRef = (): DispatcherRefContainer => {
|
|
781
|
+
const dispatcherRef = getDispatcherRef();
|
|
782
|
+
if (!dispatcherRef) {
|
|
783
|
+
throw new Error(
|
|
784
|
+
"No React renderer found. Make sure React is loaded and bippy's hook is installed.",
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
return dispatcherRef;
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
const resolveContextDependency = (fiber: Fiber): void => {
|
|
791
|
+
if (Object.prototype.hasOwnProperty.call(fiber, "dependencies")) {
|
|
792
|
+
const dependencies = fiber.dependencies;
|
|
793
|
+
currentContextDependency = dependencies !== null ? dependencies.firstContext : null;
|
|
794
|
+
} else if (Object.prototype.hasOwnProperty.call(fiber, "dependencies_old")) {
|
|
795
|
+
const dependencies = (fiber as unknown as { dependencies_old: typeof fiber.dependencies })
|
|
796
|
+
.dependencies_old;
|
|
797
|
+
currentContextDependency = dependencies !== null ? dependencies!.firstContext : null;
|
|
798
|
+
} else if (Object.prototype.hasOwnProperty.call(fiber, "dependencies_new")) {
|
|
799
|
+
const dependencies = (fiber as unknown as { dependencies_new: typeof fiber.dependencies })
|
|
800
|
+
.dependencies_new;
|
|
801
|
+
currentContextDependency = dependencies !== null ? dependencies!.firstContext : null;
|
|
802
|
+
} else if (Object.prototype.hasOwnProperty.call(fiber, "contextDependencies")) {
|
|
803
|
+
const contextDependencies = (
|
|
804
|
+
fiber as unknown as {
|
|
805
|
+
contextDependencies: { first: ContextDependency<unknown> | null } | null;
|
|
806
|
+
}
|
|
807
|
+
).contextDependencies;
|
|
808
|
+
currentContextDependency = contextDependencies !== null ? contextDependencies.first : null;
|
|
809
|
+
} else {
|
|
810
|
+
throw new Error("Unsupported React version.");
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
815
|
+
const dispatcherRef = requireDispatcherRef();
|
|
816
|
+
|
|
817
|
+
if (
|
|
818
|
+
fiber.tag !== FUNCTION_COMPONENT_TAG &&
|
|
819
|
+
fiber.tag !== SIMPLE_MEMO_COMPONENT_TAG &&
|
|
820
|
+
fiber.tag !== FORWARD_REF_TAG
|
|
821
|
+
) {
|
|
822
|
+
throw new Error("Unknown Fiber. Needs to be a function component to inspect hooks.");
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
getPrimitiveStackCache();
|
|
826
|
+
|
|
827
|
+
currentHook = fiber.memoizedState;
|
|
828
|
+
currentFiber = fiber;
|
|
829
|
+
|
|
830
|
+
const debugThenableState =
|
|
831
|
+
fiber.dependencies &&
|
|
832
|
+
(fiber.dependencies as { _debugThenableState?: { thenables?: unknown[] } })._debugThenableState;
|
|
833
|
+
const usedThenables = debugThenableState
|
|
834
|
+
? debugThenableState.thenables || debugThenableState
|
|
835
|
+
: null;
|
|
836
|
+
currentThenableState = Array.isArray(usedThenables) ? usedThenables : null;
|
|
837
|
+
currentThenableIndex = 0;
|
|
838
|
+
|
|
839
|
+
resolveContextDependency(fiber);
|
|
840
|
+
|
|
841
|
+
const type = fiber.type;
|
|
842
|
+
let props = fiber.memoizedProps as Record<string, unknown>;
|
|
843
|
+
if (type !== fiber.elementType) {
|
|
844
|
+
props = resolveDefaultProps(type, props);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const originalConsoleMethods = suppressConsole();
|
|
848
|
+
const contextMap = new Map<ReactContext<unknown>, unknown>();
|
|
849
|
+
|
|
850
|
+
try {
|
|
851
|
+
if (
|
|
852
|
+
currentContextDependency !== null &&
|
|
853
|
+
!Object.prototype.hasOwnProperty.call(currentContextDependency, "memoizedValue")
|
|
854
|
+
) {
|
|
855
|
+
setupContexts(contextMap, fiber);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
if (fiber.tag === FORWARD_REF_TAG) {
|
|
859
|
+
return performDispatcherInspection(dispatcherRef, () => {
|
|
860
|
+
(type as { render: (props: Record<string, unknown>, ref: unknown) => unknown }).render(
|
|
861
|
+
props,
|
|
862
|
+
fiber.ref,
|
|
863
|
+
);
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return performDispatcherInspection(dispatcherRef, () => {
|
|
868
|
+
(type as (props: Record<string, unknown>) => unknown)(props);
|
|
869
|
+
});
|
|
870
|
+
} finally {
|
|
871
|
+
currentFiber = null;
|
|
872
|
+
currentHook = null;
|
|
873
|
+
currentContextDependency = null;
|
|
874
|
+
currentThenableState = null;
|
|
875
|
+
currentThenableIndex = 0;
|
|
876
|
+
restoreContexts(contextMap);
|
|
877
|
+
restoreConsole(originalConsoleMethods);
|
|
878
|
+
}
|
|
879
|
+
};
|