bippy 0.6.1-dev.051a9b2 → 0.6.1-dev.3a24abf
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/README.md +26 -48
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +32 -44
- package/dist/core.d.ts +32 -44
- package/dist/core.js +1 -1
- package/dist/core2.cjs +9 -0
- package/dist/core2.d.cts +3 -3
- package/dist/core2.d.ts +3 -3
- package/dist/core2.js +9 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -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 +1 -1
- package/dist/install-hook-only.d.ts +1 -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 +1 -1
- package/dist/source.d.ts +1 -1
- package/dist/source.js +14 -4
- package/dist/types.d.cts +291 -0
- package/dist/types.d.ts +291 -0
- package/package.json +14 -12
- package/src/core.ts +206 -155
- package/src/generated/react-work-tags.ts +169 -0
- package/src/rdt-hook.ts +24 -67
- package/src/react-internals.ts +67 -0
- package/src/source/constants.ts +1 -1
- package/src/source/get-source.ts +2 -1
- package/src/source/owner-stack.ts +64 -77
- package/src/source/parse-stack.ts +1 -1
- package/src/source/symbolication.ts +25 -4
- package/src/types.ts +154 -333
- package/src/unsubscribe.ts +2 -2
- 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
|
@@ -1,11 +1,10 @@
|
|
|
1
|
+
import { getDisplayName, getType, traverseFiber } from "../core.js";
|
|
2
|
+
import { _renderers, getRDTHook } from "../rdt-hook.js";
|
|
1
3
|
import {
|
|
2
|
-
_renderers,
|
|
3
4
|
ActivityComponentTag,
|
|
4
5
|
ClassComponentTag,
|
|
5
|
-
Fiber,
|
|
6
6
|
ForwardRefTag,
|
|
7
7
|
FunctionComponentTag,
|
|
8
|
-
getRDTHook,
|
|
9
8
|
HostComponentTag,
|
|
10
9
|
HostHoistableTag,
|
|
11
10
|
HostSingletonTag,
|
|
@@ -14,10 +13,8 @@ import {
|
|
|
14
13
|
SuspenseComponentTag,
|
|
15
14
|
SuspenseListComponentTag,
|
|
16
15
|
ViewTransitionComponentTag,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} from "../core.js";
|
|
20
|
-
import { ServerComponentInfo } from "../types.js";
|
|
16
|
+
} from "../react-internals.js";
|
|
17
|
+
import type { Fiber, RendererDispatcherRef, ServerComponentInfo } from "../types.js";
|
|
21
18
|
import {
|
|
22
19
|
SERVER_FRAME_MARKER,
|
|
23
20
|
SERVER_ENV_PATTERN,
|
|
@@ -28,6 +25,11 @@ import { parseDebugStack } from "./parse-debug-stack.js";
|
|
|
28
25
|
import { parseStack, StackFrame } from "./parse-stack.js";
|
|
29
26
|
import { symbolicateStack } from "./symbolication.js";
|
|
30
27
|
|
|
28
|
+
interface RendererDispatcherSnapshot {
|
|
29
|
+
currentDispatcherRef: RendererDispatcherRef;
|
|
30
|
+
value: unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
31
33
|
export const hasDebugStack = (
|
|
32
34
|
fiber: Fiber,
|
|
33
35
|
): fiber is Fiber & {
|
|
@@ -37,13 +39,10 @@ export const hasDebugStack = (
|
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
const isFiberOwner = (owner: Fiber | ServerComponentInfo): owner is Fiber =>
|
|
40
|
-
|
|
42
|
+
"tag" in owner && typeof owner.tag === "number";
|
|
41
43
|
|
|
42
|
-
// react's typings (and bippy's Fiber, which mirrors them) declare _debugOwner
|
|
43
|
-
// as a Fiber, but react 19 flight sets a ReactComponentInfo object for server
|
|
44
|
-
// component owners
|
|
45
44
|
const getDebugOwner = (fiber: Fiber): Fiber | ServerComponentInfo | undefined =>
|
|
46
|
-
fiber._debugOwner
|
|
45
|
+
fiber._debugOwner ?? undefined;
|
|
47
46
|
|
|
48
47
|
/**
|
|
49
48
|
* Locates a frame inside the fiber's own function body without invoking it:
|
|
@@ -90,26 +89,41 @@ export const getDefinitionFrameFromOwnedChild = (fiber: Fiber): StackFrame | nul
|
|
|
90
89
|
return null;
|
|
91
90
|
};
|
|
92
91
|
|
|
93
|
-
const
|
|
92
|
+
const getRendererDispatcherRefs = (): RendererDispatcherRef[] => {
|
|
94
93
|
const rdtHook = getRDTHook();
|
|
95
|
-
|
|
94
|
+
const renderers = new Set([..._renderers, ...rdtHook.renderers.values()]);
|
|
95
|
+
const currentDispatcherRefs: RendererDispatcherRef[] = [];
|
|
96
|
+
const seenCurrentDispatcherRefs = new Set<object>();
|
|
97
|
+
for (const renderer of renderers) {
|
|
96
98
|
const currentDispatcherRef = renderer.currentDispatcherRef;
|
|
97
|
-
if (currentDispatcherRef
|
|
98
|
-
|
|
99
|
+
if (!currentDispatcherRef || seenCurrentDispatcherRefs.has(currentDispatcherRef)) continue;
|
|
100
|
+
seenCurrentDispatcherRefs.add(currentDispatcherRef);
|
|
101
|
+
currentDispatcherRefs.push(currentDispatcherRef);
|
|
102
|
+
}
|
|
103
|
+
return currentDispatcherRefs;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const clearRendererDispatchers = (): RendererDispatcherSnapshot[] => {
|
|
107
|
+
const dispatcherSnapshots: RendererDispatcherSnapshot[] = [];
|
|
108
|
+
for (const currentDispatcherRef of getRendererDispatcherRefs()) {
|
|
109
|
+
const value =
|
|
110
|
+
"H" in currentDispatcherRef ? currentDispatcherRef.H : currentDispatcherRef.current;
|
|
111
|
+
dispatcherSnapshots.push({ currentDispatcherRef, value });
|
|
112
|
+
if ("H" in currentDispatcherRef) {
|
|
113
|
+
currentDispatcherRef.H = null;
|
|
114
|
+
} else {
|
|
115
|
+
currentDispatcherRef.current = null;
|
|
99
116
|
}
|
|
100
117
|
}
|
|
101
|
-
return
|
|
118
|
+
return dispatcherSnapshots;
|
|
102
119
|
};
|
|
103
120
|
|
|
104
|
-
const
|
|
105
|
-
for (const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
} else {
|
|
111
|
-
currentDispatcherRef.current = value;
|
|
112
|
-
}
|
|
121
|
+
const restoreRendererDispatchers = (dispatcherSnapshots: RendererDispatcherSnapshot[]): void => {
|
|
122
|
+
for (const { currentDispatcherRef, value } of dispatcherSnapshots) {
|
|
123
|
+
if ("H" in currentDispatcherRef) {
|
|
124
|
+
currentDispatcherRef.H = value;
|
|
125
|
+
} else {
|
|
126
|
+
currentDispatcherRef.current = value;
|
|
113
127
|
}
|
|
114
128
|
}
|
|
115
129
|
};
|
|
@@ -151,44 +165,27 @@ const describeNativeComponentFrame = (
|
|
|
151
165
|
(Error as { prepareStackTrace?: typeof Error.prepareStackTrace }).prepareStackTrace = undefined;
|
|
152
166
|
reEntry = true;
|
|
153
167
|
|
|
154
|
-
const
|
|
155
|
-
setCurrentDispatcher(null);
|
|
168
|
+
const dispatcherSnapshots = clearRendererDispatchers();
|
|
156
169
|
const previousConsoleError = console.error;
|
|
157
170
|
const previousConsoleWarn = console.warn;
|
|
158
171
|
console.error = () => {};
|
|
159
172
|
console.warn = () => {};
|
|
160
173
|
try {
|
|
161
|
-
|
|
162
|
-
* Finding a common stack frame between sample and control errors can be
|
|
163
|
-
* tricky given the different types and levels of stack trace truncation from
|
|
164
|
-
* different JS VMs. So instead we'll attempt to control what that common
|
|
165
|
-
* frame should be through this object method:
|
|
166
|
-
* Having both the sample and control errors be in the function under the
|
|
167
|
-
* `DescribeNativeComponentFrameRoot` property, + setting the `name` and
|
|
168
|
-
* `displayName` properties of the function ensures that a stack
|
|
169
|
-
* frame exists that has the method name `DescribeNativeComponentFrameRoot` in
|
|
170
|
-
* it for both control and sample stacks.
|
|
171
|
-
*/
|
|
174
|
+
// HACK: Run the control and sample under the same property name so their stacks share a frame.
|
|
172
175
|
const RunInRootFrame = {
|
|
173
176
|
DetermineComponentFrameRoot() {
|
|
174
177
|
let control: unknown;
|
|
175
178
|
try {
|
|
176
|
-
// This should throw.
|
|
177
179
|
if (construct) {
|
|
178
|
-
// Something should be setting the props in the constructor.
|
|
179
180
|
const ThrowingConstructor = function () {
|
|
180
181
|
throw Error();
|
|
181
182
|
};
|
|
182
183
|
Object.defineProperty(ThrowingConstructor.prototype, "props", {
|
|
183
184
|
set: function () {
|
|
184
|
-
// We use a throwing setter instead of frozen or non-writable props
|
|
185
|
-
// because that won't throw in a non-strict mode function.
|
|
186
185
|
throw Error();
|
|
187
186
|
},
|
|
188
187
|
});
|
|
189
188
|
if (typeof Reflect === "object" && Reflect.construct) {
|
|
190
|
-
// We construct a different control for this case to include any extra
|
|
191
|
-
// frames added by the construct call.
|
|
192
189
|
try {
|
|
193
190
|
Reflect.construct(ThrowingConstructor, []);
|
|
194
191
|
} catch (caughtError) {
|
|
@@ -197,13 +194,11 @@ const describeNativeComponentFrame = (
|
|
|
197
194
|
Reflect.construct(component, [], ThrowingConstructor);
|
|
198
195
|
} else {
|
|
199
196
|
try {
|
|
200
|
-
|
|
201
|
-
ThrowingConstructor.call();
|
|
197
|
+
Function.prototype.apply.call(ThrowingConstructor, undefined, []);
|
|
202
198
|
} catch (caughtError) {
|
|
203
199
|
control = caughtError;
|
|
204
200
|
}
|
|
205
|
-
|
|
206
|
-
component.call(ThrowingConstructor.prototype);
|
|
201
|
+
Function.prototype.apply.call(component, ThrowingConstructor.prototype, []);
|
|
207
202
|
}
|
|
208
203
|
} else {
|
|
209
204
|
try {
|
|
@@ -211,22 +206,17 @@ const describeNativeComponentFrame = (
|
|
|
211
206
|
} catch (caughtError) {
|
|
212
207
|
control = caughtError;
|
|
213
208
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
// TODO: Implement component stacks for async client components?
|
|
223
|
-
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- we literally check if this is a promise here
|
|
224
|
-
if (maybePromise && typeof maybePromise.catch === "function") {
|
|
225
|
-
maybePromise.catch(() => {});
|
|
209
|
+
const maybePromise = Function.prototype.apply.call(component, undefined, []);
|
|
210
|
+
if (
|
|
211
|
+
typeof maybePromise === "object" &&
|
|
212
|
+
maybePromise !== null &&
|
|
213
|
+
"catch" in maybePromise &&
|
|
214
|
+
typeof maybePromise.catch === "function"
|
|
215
|
+
) {
|
|
216
|
+
maybePromise.catch(() => undefined);
|
|
226
217
|
}
|
|
227
218
|
}
|
|
228
219
|
} catch (sample: unknown) {
|
|
229
|
-
// This is inlined manually because closure doesn't do it for us.
|
|
230
220
|
if (
|
|
231
221
|
sample instanceof Error &&
|
|
232
222
|
control instanceof Error &&
|
|
@@ -239,21 +229,18 @@ const describeNativeComponentFrame = (
|
|
|
239
229
|
},
|
|
240
230
|
};
|
|
241
231
|
|
|
242
|
-
|
|
243
|
-
|
|
232
|
+
Object.defineProperty(RunInRootFrame.DetermineComponentFrameRoot, "displayName", {
|
|
233
|
+
value: "DetermineComponentFrameRoot",
|
|
234
|
+
});
|
|
244
235
|
const namePropDescriptor = Object.getOwnPropertyDescriptor(
|
|
245
236
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
246
237
|
RunInRootFrame.DetermineComponentFrameRoot,
|
|
247
238
|
"name",
|
|
248
239
|
);
|
|
249
|
-
// Before ES6, the `name` property was not configurable.
|
|
250
240
|
if (namePropDescriptor?.configurable) {
|
|
251
|
-
// V8 utilizes a function's `name` property when generating a stack trace.
|
|
252
241
|
Object.defineProperty(
|
|
253
242
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
254
243
|
RunInRootFrame.DetermineComponentFrameRoot,
|
|
255
|
-
// Configurable properties can be updated even if its writable descriptor
|
|
256
|
-
// is set to `false`.
|
|
257
244
|
"name",
|
|
258
245
|
{ value: "DetermineComponentFrameRoot" },
|
|
259
246
|
);
|
|
@@ -340,7 +327,7 @@ const describeNativeComponentFrame = (
|
|
|
340
327
|
|
|
341
328
|
Error.prepareStackTrace = previousPrepareStackTrace;
|
|
342
329
|
|
|
343
|
-
|
|
330
|
+
restoreRendererDispatchers(dispatcherSnapshots);
|
|
344
331
|
console.error = previousConsoleError;
|
|
345
332
|
console.warn = previousConsoleWarn;
|
|
346
333
|
}
|
|
@@ -353,9 +340,8 @@ const describeNativeComponentFrame = (
|
|
|
353
340
|
|
|
354
341
|
// https://github.com/facebook/react/blob/ac3e705a18696168acfcaed39dce0cfaa6be8836/packages/react-reconciler/src/ReactFiberComponentStack.js#L180
|
|
355
342
|
export const describeFiber = (fiber: Fiber, childFiber: Fiber | null): string => {
|
|
356
|
-
const tag = fiber.tag as number;
|
|
357
343
|
let stackFrame = "";
|
|
358
|
-
switch (tag) {
|
|
344
|
+
switch (fiber.tag) {
|
|
359
345
|
case ActivityComponentTag:
|
|
360
346
|
stackFrame = describeBuiltInComponentFrame("Activity");
|
|
361
347
|
break;
|
|
@@ -363,10 +349,7 @@ export const describeFiber = (fiber: Fiber, childFiber: Fiber | null): string =>
|
|
|
363
349
|
stackFrame = describeNativeComponentFrame(fiber.type, true);
|
|
364
350
|
break;
|
|
365
351
|
case ForwardRefTag:
|
|
366
|
-
stackFrame = describeNativeComponentFrame(
|
|
367
|
-
(fiber.type as { render: React.ComponentType<unknown> }).render,
|
|
368
|
-
false,
|
|
369
|
-
);
|
|
352
|
+
stackFrame = describeNativeComponentFrame(getType(fiber.type) ?? fiber.type, false);
|
|
370
353
|
break;
|
|
371
354
|
case FunctionComponentTag:
|
|
372
355
|
case SimpleMemoComponentTag:
|
|
@@ -375,7 +358,9 @@ export const describeFiber = (fiber: Fiber, childFiber: Fiber | null): string =>
|
|
|
375
358
|
case HostComponentTag:
|
|
376
359
|
case HostHoistableTag:
|
|
377
360
|
case HostSingletonTag:
|
|
378
|
-
|
|
361
|
+
if (typeof fiber.type === "string") {
|
|
362
|
+
stackFrame = describeBuiltInComponentFrame(fiber.type);
|
|
363
|
+
}
|
|
379
364
|
break;
|
|
380
365
|
case LazyComponentTag:
|
|
381
366
|
// TODO: When we support Thenables as component types we should rename this.
|
|
@@ -660,7 +645,9 @@ export const getParentStack = async (
|
|
|
660
645
|
const enrichedStackFrames = fallbackStackFrames.map((stackFrame): StackFrame => {
|
|
661
646
|
const isServerFrame =
|
|
662
647
|
(stackFrame.source?.includes(SERVER_FRAME_MARKER) ?? false) ||
|
|
663
|
-
(stackFrame.source
|
|
648
|
+
(stackFrame.source !== null &&
|
|
649
|
+
stackFrame.source !== undefined &&
|
|
650
|
+
SERVER_ENV_PATTERN.test(stackFrame.source));
|
|
664
651
|
|
|
665
652
|
if (isServerFrame) {
|
|
666
653
|
return getEnrichedServerStackFrame(
|
|
@@ -67,7 +67,7 @@ export const extractLocation = (
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
const applySlice = <T>(lines: T[], options?: ParseOptions): T[] => {
|
|
70
|
-
if (options && options.slice
|
|
70
|
+
if (options && options.slice !== null && options.slice !== undefined) {
|
|
71
71
|
if (Array.isArray(options.slice)) return lines.slice(options.slice[0], options.slice[1]);
|
|
72
72
|
return lines.slice(0, options.slice);
|
|
73
73
|
}
|
|
@@ -211,13 +211,28 @@ const getIgnoredSourceIndices = (rawSourceMap: StandardSourceMap): Set<number> |
|
|
|
211
211
|
return Array.isArray(ignoreList) && ignoreList.length > 0 ? new Set(ignoreList) : undefined;
|
|
212
212
|
};
|
|
213
213
|
|
|
214
|
+
const resolveSourceRoot = (sourceRoot: string | undefined, source: string): string => {
|
|
215
|
+
if (!sourceRoot || SCHEME_REGEX.test(source) || source.startsWith("/")) return source;
|
|
216
|
+
const normalizedSourceRoot = sourceRoot.endsWith("/") ? sourceRoot : `${sourceRoot}/`;
|
|
217
|
+
const normalizedSource = source.replace(/^\.\//, "");
|
|
218
|
+
if (SCHEME_REGEX.test(normalizedSourceRoot)) {
|
|
219
|
+
try {
|
|
220
|
+
return new URL(normalizedSource, normalizedSourceRoot).toString();
|
|
221
|
+
} catch {}
|
|
222
|
+
}
|
|
223
|
+
return `${normalizedSourceRoot}${normalizedSource}`;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const resolveSourceMapSources = (rawSourceMap: StandardSourceMap): string[] =>
|
|
227
|
+
rawSourceMap.sources.map((source) => resolveSourceRoot(rawSourceMap.sourceRoot, source));
|
|
228
|
+
|
|
214
229
|
const decodeStandardSourceMap = (rawSourceMap: StandardSourceMap): SourceMap => ({
|
|
215
230
|
file: rawSourceMap.file,
|
|
216
231
|
ignoredSourceIndices: getIgnoredSourceIndices(rawSourceMap),
|
|
217
232
|
mappings: decode(rawSourceMap.mappings),
|
|
218
233
|
names: rawSourceMap.names,
|
|
219
234
|
sourceRoot: rawSourceMap.sourceRoot,
|
|
220
|
-
sources: rawSourceMap
|
|
235
|
+
sources: resolveSourceMapSources(rawSourceMap),
|
|
221
236
|
sourcesContent: rawSourceMap.sourcesContent,
|
|
222
237
|
version: 3,
|
|
223
238
|
});
|
|
@@ -229,6 +244,7 @@ const decodeIndexSourceMap = (rawSourceMap: IndexSourceMap): SourceMap => {
|
|
|
229
244
|
...map,
|
|
230
245
|
ignoredSourceIndices: getIgnoredSourceIndices(map),
|
|
231
246
|
mappings: decode(map.mappings),
|
|
247
|
+
sources: resolveSourceMapSources(map),
|
|
232
248
|
},
|
|
233
249
|
offset,
|
|
234
250
|
}),
|
|
@@ -282,13 +298,18 @@ const isFetchableUrl = (url: string): boolean => {
|
|
|
282
298
|
// return null, but a dropped connection is not and must stay retryable.
|
|
283
299
|
export const getSourceMapImpl = async (
|
|
284
300
|
bundleUrl: string,
|
|
285
|
-
fetchFn
|
|
301
|
+
fetchFn?: (url: string) => Promise<Response>,
|
|
286
302
|
): Promise<null | SourceMap> => {
|
|
287
303
|
if (!isFetchableUrl(bundleUrl)) {
|
|
288
304
|
return null;
|
|
289
305
|
}
|
|
290
306
|
|
|
291
|
-
const
|
|
307
|
+
const sourceFetch =
|
|
308
|
+
fetchFn ??
|
|
309
|
+
(typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : undefined);
|
|
310
|
+
if (!sourceFetch) return null;
|
|
311
|
+
|
|
312
|
+
const bundleResponse = await sourceFetch(bundleUrl);
|
|
292
313
|
if (!bundleResponse.ok) {
|
|
293
314
|
return null;
|
|
294
315
|
}
|
|
@@ -306,7 +327,7 @@ export const getSourceMapImpl = async (
|
|
|
306
327
|
return null;
|
|
307
328
|
}
|
|
308
329
|
|
|
309
|
-
const sourceMapResponse = await
|
|
330
|
+
const sourceMapResponse = await sourceFetch(sourceMapUrl);
|
|
310
331
|
if (!sourceMapResponse.ok) {
|
|
311
332
|
return null;
|
|
312
333
|
}
|