bippy 0.7.1 → 0.7.2-dev.b756bd6

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.
@@ -3,6 +3,7 @@ import type {
3
3
  ContextDependency,
4
4
  MemoizedState,
5
5
  ReactContext,
6
+ ReactDebugInfo,
6
7
  RendererDispatcherRef,
7
8
  } from "../react-internals/index.js";
8
9
  import {
@@ -20,6 +21,7 @@ import {
20
21
 
21
22
  const REACT_CONTEXT_TYPE = Symbol.for("react.context");
22
23
  const REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel");
24
+ const REACT_RECOVERABLE_TYPE = Symbol.for("react.recoverable");
23
25
 
24
26
  export interface HookSource {
25
27
  lineNumber: number | null;
@@ -34,6 +36,7 @@ export interface HooksNode {
34
36
  name: string;
35
37
  value: unknown;
36
38
  subHooks: HooksNode[];
39
+ debugInfo: ReactDebugInfo[] | null;
37
40
  hookSource: HookSource | null;
38
41
  }
39
42
 
@@ -44,6 +47,7 @@ interface HookLogEntry {
44
47
  primitive: string;
45
48
  stackError: Error;
46
49
  value: unknown;
50
+ debugInfo: ReactDebugInfo[] | null;
47
51
  dispatcherHookName: string;
48
52
  }
49
53
 
@@ -61,6 +65,7 @@ interface InspectableThenable {
61
65
  status?: unknown;
62
66
  then: (...arguments_: unknown[]) => unknown;
63
67
  value?: unknown;
68
+ _debugInfo?: ReactDebugInfo[];
64
69
  }
65
70
 
66
71
  interface ForwardRefRenderType {
@@ -68,6 +73,7 @@ interface ForwardRefRenderType {
68
73
  }
69
74
 
70
75
  interface InspectedActionState {
76
+ debugInfo: ReactDebugInfo[] | null;
71
77
  error: unknown;
72
78
  value: unknown;
73
79
  }
@@ -132,12 +138,14 @@ const pushHookLogEntry = (
132
138
  value: unknown,
133
139
  dispatcherHookName: string,
134
140
  displayName: string | null = null,
141
+ debugInfo: ReactDebugInfo[] | null = null,
135
142
  ): void => {
136
143
  hookLog.push({
137
144
  displayName,
138
145
  primitive,
139
146
  stackError: new Error(),
140
147
  value,
148
+ debugInfo,
141
149
  dispatcherHookName,
142
150
  });
143
151
  };
@@ -153,22 +161,26 @@ const dispatcherUse = (usable: unknown): unknown => {
153
161
 
154
162
  switch (thenable.status) {
155
163
  case "fulfilled": {
156
- pushHookLogEntry("Promise", thenable.value, "Use");
164
+ pushHookLogEntry("Promise", thenable.value, "Use", null, thenable._debugInfo ?? null);
157
165
  return thenable.value;
158
166
  }
159
167
  case "rejected":
160
168
  throw thenable.reason;
161
169
  }
162
- pushHookLogEntry("Unresolved", thenable, "Use");
170
+ pushHookLogEntry("Unresolved", thenable, "Use", null, thenable._debugInfo ?? null);
163
171
  throw SuspenseException;
164
172
  }
173
+ if ("$$typeof" in usable && usable.$$typeof === REACT_RECOVERABLE_TYPE) {
174
+ pushHookLogEntry("Recoverable", undefined, "Use");
175
+ return undefined;
176
+ }
165
177
  if ("$$typeof" in usable && usable.$$typeof === REACT_CONTEXT_TYPE && isReactContext(usable)) {
166
178
  const context: InspectableReactContext = {
167
179
  _currentValue: usable._currentValue,
168
180
  displayName: typeof usable.displayName === "string" ? usable.displayName : undefined,
169
181
  };
170
182
  const value = readContext(context);
171
- pushHookLogEntry("Context (use)", value, "Use", context.displayName ?? "Context");
183
+ pushHookLogEntry("Context (use)", value, "Use", context.displayName || "Context");
172
184
  return value;
173
185
  }
174
186
  }
@@ -177,7 +189,7 @@ const dispatcherUse = (usable: unknown): unknown => {
177
189
 
178
190
  const dispatcherUseContext = (context: InspectableReactContext): unknown => {
179
191
  const value = readContext(context);
180
- pushHookLogEntry("Context", value, "Context", context.displayName ?? null);
192
+ pushHookLogEntry("Context", value, "Context", context.displayName || null);
181
193
  return value;
182
194
  };
183
195
 
@@ -304,7 +316,7 @@ const dispatcherUseId = (): string => {
304
316
 
305
317
  const dispatcherUseMemoCache = (size: number): unknown[] => {
306
318
  const fiber = currentFiber;
307
- if (fiber === null || fiber === undefined) return [];
319
+ if (fiber === null) return [];
308
320
 
309
321
  const memoCache = fiber.updateQueue?.memoCache;
310
322
  if (memoCache === null || memoCache === undefined) return [];
@@ -333,6 +345,7 @@ const inspectActionStateHook = (
333
345
  initialState: unknown,
334
346
  ): InspectedActionState => {
335
347
  let value: unknown;
348
+ let debugInfo: ReactDebugInfo[] | null = null;
336
349
  let error: unknown = null;
337
350
  if (hook !== null) {
338
351
  const actionResult = hook.memoizedState;
@@ -340,6 +353,7 @@ const inspectActionStateHook = (
340
353
  switch (actionResult.status) {
341
354
  case "fulfilled":
342
355
  value = actionResult.value;
356
+ debugInfo = actionResult._debugInfo ?? null;
343
357
  break;
344
358
  case "rejected":
345
359
  error = actionResult.reason;
@@ -347,6 +361,7 @@ const inspectActionStateHook = (
347
361
  default:
348
362
  error = SuspenseException;
349
363
  value = actionResult;
364
+ debugInfo = actionResult._debugInfo ?? null;
350
365
  }
351
366
  } else {
352
367
  value = actionResult;
@@ -354,7 +369,7 @@ const inspectActionStateHook = (
354
369
  } else {
355
370
  value = initialState;
356
371
  }
357
- return { value, error };
372
+ return { value, debugInfo, error };
358
373
  };
359
374
 
360
375
  const createActionStateDispatcher =
@@ -363,8 +378,8 @@ const createActionStateDispatcher =
363
378
  const hook = nextHook();
364
379
  nextHook();
365
380
  nextHook();
366
- const { value, error } = inspectActionStateHook(hook, initialState);
367
- pushHookLogEntry(primitive, value, primitive);
381
+ const { value, debugInfo, error } = inspectActionStateHook(hook, initialState);
382
+ pushHookLogEntry(primitive, value, primitive, null, debugInfo);
368
383
  if (error !== null) throw error;
369
384
  return [value, () => {}, false];
370
385
  };
@@ -449,6 +464,7 @@ const getPrimitiveStackCache = (): Map<string, StackFrame[]> => {
449
464
  dispatcher.useActionState((state: unknown) => state, null);
450
465
  dispatcher.useHostTransitionStatus();
451
466
  dispatcher.use({ $$typeof: REACT_CONTEXT_TYPE, _currentValue: null });
467
+ dispatcher.use({ $$typeof: REACT_RECOVERABLE_TYPE });
452
468
  const fulfilledPromise = Promise.resolve(null);
453
469
  Reflect.set(fulfilledPromise, "status", "fulfilled");
454
470
  Reflect.set(fulfilledPromise, "value", null);
@@ -628,6 +644,7 @@ const buildTree = (rootStack: StackFrame[], capturedHookLog: HookLogEntry[]): Ho
628
644
  name: parseHookName(stack[stackIndex - 1].functionName),
629
645
  value: undefined,
630
646
  subHooks: children,
647
+ debugInfo: null,
631
648
  hookSource: {
632
649
  lineNumber: stackFrame.lineNumber ?? null,
633
650
  columnNumber: stackFrame.columnNumber ?? null,
@@ -655,7 +672,15 @@ const buildTree = (rootStack: StackFrame[], capturedHookLog: HookLogEntry[]): Ho
655
672
  fileName: firstStackFrame?.fileName ?? null,
656
673
  };
657
674
 
658
- levelChildren.push({ id, isStateEditable, name, value: hook.value, subHooks: [], hookSource });
675
+ levelChildren.push({
676
+ id,
677
+ isStateEditable,
678
+ name,
679
+ value: hook.value,
680
+ subHooks: [],
681
+ debugInfo: hook.debugInfo,
682
+ hookSource,
683
+ });
659
684
  }
660
685
 
661
686
  processDebugValues(rootChildren, null);
@@ -723,8 +748,8 @@ const resolveDefaultProps = (
723
748
  baseProps: Record<string, unknown>,
724
749
  ): Record<string, unknown> => {
725
750
  if (
726
- component &&
727
- typeof component === "object" &&
751
+ component !== null &&
752
+ (typeof component === "object" || typeof component === "function") &&
728
753
  "defaultProps" in component &&
729
754
  typeof component.defaultProps === "object" &&
730
755
  component.defaultProps !== null
@@ -7,7 +7,6 @@ import type {
7
7
  } from "../react-internals/index.js";
8
8
  import {
9
9
  REACT_STACK_BOTTOM_FRAME_PATTERNS,
10
- SERVER_FRAME_MARKER,
11
10
  SERVER_ENV_PATTERN,
12
11
  SERVER_COMPONENT_URL_PREFIXES,
13
12
  } from "./constants.js";
@@ -101,12 +100,18 @@ const describeBuiltInComponentFrame = (name: string): string => {
101
100
  return `\n in ${name}`;
102
101
  };
103
102
 
104
- export const describeDebugInfoFrame = (name: string, env?: string): string => {
105
- let frameDescription = describeBuiltInComponentFrame(name);
106
- if (env) {
107
- frameDescription += ` (at ${env})`;
103
+ export const describeDebugInfoFrame = (
104
+ name: string,
105
+ env?: string,
106
+ location?: Error | null,
107
+ ): string => {
108
+ if (location) {
109
+ const childStack = formatOwnerStack(location.stack ?? "");
110
+ const lastNewlineIndex = childStack.lastIndexOf("\n");
111
+ const lastLine = lastNewlineIndex === -1 ? childStack : childStack.slice(lastNewlineIndex + 1);
112
+ if (lastLine.includes(name)) return `\n${lastLine}`;
108
113
  }
109
- return frameDescription;
114
+ return describeBuiltInComponentFrame(`${name}${env ? ` [${env}]` : ""}`);
110
115
  };
111
116
 
112
117
  let reEntry = false;
@@ -115,7 +120,7 @@ let reEntry = false;
115
120
  // component type like React DevTools does.
116
121
  const componentFrameCache = new WeakMap<React.ComponentType<unknown>, string>();
117
122
 
118
- // https://github.com/facebook/react/blob/f739642745577a8e4dcb9753836ac3589b9c590a/packages/react-devtools-shared/src/backend/shared/DevToolsComponentStackFrame.js#L22
123
+ // https://github.com/facebook/react/blob/eafeac0/packages/shared/ReactComponentStackFrame.js#L64
119
124
  const describeNativeComponentFrame = (
120
125
  component: React.ComponentType<unknown>,
121
126
  construct: boolean,
@@ -153,21 +158,12 @@ const describeNativeComponentFrame = (
153
158
  throw Error();
154
159
  },
155
160
  });
156
- if (typeof Reflect === "object" && Reflect.construct) {
157
- try {
158
- Reflect.construct(ThrowingConstructor, []);
159
- } catch (caughtError) {
160
- control = caughtError;
161
- }
162
- Reflect.construct(component, [], ThrowingConstructor);
163
- } else {
164
- try {
165
- Function.prototype.apply.call(ThrowingConstructor, undefined, []);
166
- } catch (caughtError) {
167
- control = caughtError;
168
- }
169
- Function.prototype.apply.call(component, ThrowingConstructor.prototype, []);
161
+ try {
162
+ Reflect.construct(ThrowingConstructor, []);
163
+ } catch (caughtError) {
164
+ control = caughtError;
170
165
  }
166
+ Reflect.construct(component, [], ThrowingConstructor);
171
167
  } else {
172
168
  try {
173
169
  throw Error();
@@ -312,7 +308,7 @@ const describeNativeComponentFrame = (
312
308
  return syntheticFrame;
313
309
  };
314
310
 
315
- // https://github.com/facebook/react/blob/ac3e705a18696168acfcaed39dce0cfaa6be8836/packages/react-reconciler/src/ReactFiberComponentStack.js#L180
311
+ // https://github.com/facebook/react/blob/eafeac0/packages/react-reconciler/src/ReactFiberComponentStack.js#L37
316
312
  export const describeFiber = (fiber: Fiber, childFiber: Fiber | null): string => {
317
313
  let stackFrame = "";
318
314
  const workTags = getReactWorkTagsForFiber(fiber);
@@ -384,7 +380,11 @@ export const getFallbackParentStack = (thisFiber: Fiber): string => {
384
380
  for (let debugInfoIndex = debugInfo.length - 1; debugInfoIndex >= 0; debugInfoIndex--) {
385
381
  const debugEntry = debugInfo[debugInfoIndex];
386
382
  if (typeof debugEntry.name === "string") {
387
- componentStack += describeDebugInfoFrame(debugEntry.name, debugEntry.env);
383
+ componentStack += describeDebugInfoFrame(
384
+ debugEntry.name,
385
+ debugEntry.env,
386
+ debugEntry.debugLocation,
387
+ );
388
388
  }
389
389
  }
390
390
  }
@@ -511,7 +511,7 @@ const getEnrichedServerStackFrame = (
511
511
  lineNumber: resolvedRscFrame.lineNumber,
512
512
  columnNumber: resolvedRscFrame.columnNumber,
513
513
  source: serverFrame.source?.replace(
514
- SERVER_FRAME_MARKER,
514
+ SERVER_ENV_PATTERN,
515
515
  `(${resolvedRscFrame.fileName}:${resolvedRscFrame.lineNumber}:${resolvedRscFrame.columnNumber})`,
516
516
  ),
517
517
  };
@@ -31,7 +31,9 @@ export const parseStack = (stackString: string, options?: ParseOptions): StackFr
31
31
  const parsed = parseV8OrIeString(rawLine)[0];
32
32
  if (parsed) frames.push(parsed);
33
33
  } else if (/^\s*in\s+/.test(rawLine)) {
34
- const elementName = rawLine.replace(/^\s*in\s+/, "").replace(/\s*\(at .*\)$/, "");
34
+ const elementName = rawLine
35
+ .replace(/^\s*in\s+/, "")
36
+ .replace(/\s*(?:\(at .*\)|\[[^\]]+\])$/, "");
35
37
  frames.push({ functionName: elementName, source: rawLine });
36
38
  } else if (rawLine.match(FIREFOX_SAFARI_STACK_REGEXP)) {
37
39
  const parsed = parseFFOrSafariString(rawLine)[0];