bippy 0.7.3-dev.1d4f35b → 0.7.3-dev.49fb67e
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 +4 -11
- package/dist/core.cjs +1 -1
- package/dist/core.js +1 -1
- package/dist/errors.d.cts +4 -1
- package/dist/errors.d.ts +4 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +32 -29
- package/dist/index.d.ts +34 -31
- package/dist/index.js +1 -1
- package/dist/rdt-hook.cjs +1 -1
- package/dist/rdt-hook.js +1 -1
- package/dist/source.cjs +11 -12
- package/dist/source.d.cts +24 -22
- package/dist/source.d.ts +24 -22
- package/dist/source.js +11 -12
- package/package.json +6 -34
- package/src/call-listener.ts +13 -0
- package/src/core.ts +248 -241
- package/src/rdt-hook.ts +45 -29
- package/src/react-internals/current-fiber.ts +84 -0
- package/src/react-internals/generated/react-work-tags.ts +3 -0
- package/src/react-internals/index.ts +38 -11
- package/src/react.ts +141 -56
- package/src/source/constants.ts +10 -6
- package/src/source/get-source.ts +1 -136
- package/src/source/inspect-hooks.ts +29 -21
- package/src/source/normalize-file-name.ts +416 -0
- package/src/source/parse-stack.ts +111 -63
- package/src/source/symbolication.ts +78 -38
package/src/source/get-source.ts
CHANGED
|
@@ -2,15 +2,6 @@ import type { Fiber } from "../react-internals/index.js";
|
|
|
2
2
|
import { getDisplayName } from "../core.js";
|
|
3
3
|
|
|
4
4
|
import type { FiberSource } from "./types.js";
|
|
5
|
-
import {
|
|
6
|
-
SCHEME_REGEX,
|
|
7
|
-
INTERNAL_SCHEME_PREFIXES,
|
|
8
|
-
ABOUT_REACT_PREFIX,
|
|
9
|
-
ANONYMOUS_FILE_PATTERNS,
|
|
10
|
-
SOURCE_FILE_EXTENSION_REGEX,
|
|
11
|
-
BUNDLED_FILE_PATTERN_REGEX,
|
|
12
|
-
QUERY_PARAMETER_PATTERN_REGEX,
|
|
13
|
-
} from "./constants.js";
|
|
14
5
|
import { getDefinitionFrameFromOwnedChild, getParentStack, hasDebugStack } from "./owner-stack.js";
|
|
15
6
|
import { parseDebugStack } from "./parse-debug-stack.js";
|
|
16
7
|
import { parseStack, type StackFrame } from "./parse-stack.js";
|
|
@@ -165,130 +156,4 @@ export const getSource = async (
|
|
|
165
156
|
return getSourceByComponentName(fiber, shouldUseCache, sourceFetch, requestOptions);
|
|
166
157
|
};
|
|
167
158
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const stripSingleBasePathPrefix = (path: string): string => {
|
|
171
|
-
const firstSlashIndex = path.indexOf("/", 1);
|
|
172
|
-
if (firstSlashIndex === -1) {
|
|
173
|
-
return path;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const basePath = path.slice(0, firstSlashIndex);
|
|
177
|
-
if (getPathSegmentCount(basePath) !== 1) {
|
|
178
|
-
return path;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const remainderPath = path.slice(firstSlashIndex);
|
|
182
|
-
if (!SOURCE_FILE_EXTENSION_REGEX.test(remainderPath)) {
|
|
183
|
-
return path;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const remainderSegments = remainderPath.split("/").filter(Boolean);
|
|
187
|
-
if (remainderSegments.length < 2) {
|
|
188
|
-
return path;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const firstRemainderSegment = remainderSegments[0];
|
|
192
|
-
if (firstRemainderSegment.startsWith("@")) {
|
|
193
|
-
return path;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (firstRemainderSegment.length > 4) {
|
|
197
|
-
return path;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return remainderPath;
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
export const normalizeFileName = (fileName: string): string => {
|
|
204
|
-
if (!fileName) {
|
|
205
|
-
return "";
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (ANONYMOUS_FILE_PATTERNS.some((pattern) => pattern === fileName)) {
|
|
209
|
-
return "";
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
let normalizedFileName = fileName;
|
|
213
|
-
const isWindowsDrivePath = /^[a-zA-Z]:[\\/]/.test(normalizedFileName);
|
|
214
|
-
|
|
215
|
-
const isHttpUrl =
|
|
216
|
-
normalizedFileName.startsWith("http://") || normalizedFileName.startsWith("https://");
|
|
217
|
-
if (isHttpUrl) {
|
|
218
|
-
try {
|
|
219
|
-
const parsedUrl = new URL(normalizedFileName);
|
|
220
|
-
normalizedFileName = parsedUrl.pathname;
|
|
221
|
-
} catch {}
|
|
222
|
-
normalizedFileName = stripSingleBasePathPrefix(normalizedFileName);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
if (normalizedFileName.startsWith(ABOUT_REACT_PREFIX)) {
|
|
226
|
-
const remainder = normalizedFileName.slice(ABOUT_REACT_PREFIX.length);
|
|
227
|
-
const slashIndex = remainder.indexOf("/");
|
|
228
|
-
const colonIndex = remainder.indexOf(":");
|
|
229
|
-
|
|
230
|
-
if (slashIndex !== -1 && (colonIndex === -1 || slashIndex < colonIndex)) {
|
|
231
|
-
normalizedFileName = remainder.slice(slashIndex + 1);
|
|
232
|
-
} else {
|
|
233
|
-
normalizedFileName = remainder;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
let didStripPrefix = true;
|
|
238
|
-
while (didStripPrefix) {
|
|
239
|
-
didStripPrefix = false;
|
|
240
|
-
for (const prefix of INTERNAL_SCHEME_PREFIXES) {
|
|
241
|
-
if (normalizedFileName.startsWith(prefix)) {
|
|
242
|
-
normalizedFileName = normalizedFileName.slice(prefix.length);
|
|
243
|
-
|
|
244
|
-
if (prefix === "file:///") {
|
|
245
|
-
normalizedFileName = `/${normalizedFileName.replace(/^\/+/, "")}`;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
didStripPrefix = true;
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (!isWindowsDrivePath) {
|
|
255
|
-
const schemeMatch = normalizedFileName.match(SCHEME_REGEX);
|
|
256
|
-
if (schemeMatch) {
|
|
257
|
-
normalizedFileName = normalizedFileName.slice(schemeMatch[0].length);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (normalizedFileName.startsWith("//")) {
|
|
262
|
-
const firstPathSlashIndex = normalizedFileName.indexOf("/", 2);
|
|
263
|
-
normalizedFileName =
|
|
264
|
-
firstPathSlashIndex === -1 ? "" : normalizedFileName.slice(firstPathSlashIndex);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const queryParameterIndex = normalizedFileName.indexOf("?");
|
|
268
|
-
if (queryParameterIndex !== -1) {
|
|
269
|
-
const potentialQueryParameters = normalizedFileName.slice(queryParameterIndex);
|
|
270
|
-
if (QUERY_PARAMETER_PATTERN_REGEX.test(potentialQueryParameters)) {
|
|
271
|
-
normalizedFileName = normalizedFileName.slice(0, queryParameterIndex);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return normalizedFileName;
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
export const isSourceFile = (fileName: string): boolean => {
|
|
279
|
-
const normalizedFileName = normalizeFileName(fileName);
|
|
280
|
-
|
|
281
|
-
if (!normalizedFileName) {
|
|
282
|
-
return false;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (!SOURCE_FILE_EXTENSION_REGEX.test(normalizedFileName)) {
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
if (BUNDLED_FILE_PATTERN_REGEX.test(normalizedFileName)) {
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return true;
|
|
294
|
-
};
|
|
159
|
+
export { isSourceFile, normalizeFileName } from "./normalize-file-name.js";
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
BippyUnsupportedHookError,
|
|
15
15
|
} from "../errors.js";
|
|
16
16
|
import { getReactWorkTagsForFiber } from "../react-internals/index.js";
|
|
17
|
-
import { parseStack, type StackFrame } from "./parse-stack.js";
|
|
17
|
+
import { createStackParser, parseStack, type StackFrame } from "./parse-stack.js";
|
|
18
18
|
import {
|
|
19
19
|
getRendererDispatcherRefs,
|
|
20
20
|
readDispatcher,
|
|
@@ -87,6 +87,16 @@ let currentHook: MemoizedState | null = null;
|
|
|
87
87
|
let currentContextDependency: ContextDependency<unknown> | null = null;
|
|
88
88
|
let currentThenableIndex = 0;
|
|
89
89
|
let currentThenableState: unknown[] | null = null;
|
|
90
|
+
let currentMemoCacheIndex = 0;
|
|
91
|
+
let isInspectingHooks = false;
|
|
92
|
+
|
|
93
|
+
const assertNotInspectingHooks = (): void => {
|
|
94
|
+
if (isInspectingHooks) {
|
|
95
|
+
throw new BippyHookInspectionError(
|
|
96
|
+
"Hook inspection cannot be called during another inspection.",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
90
100
|
|
|
91
101
|
const SuspenseException: unknown = new Error(
|
|
92
102
|
"Suspense interrupted this render. This error is an internal implementation detail of `use`.",
|
|
@@ -323,16 +333,8 @@ const dispatcherUseMemoCache = (size: number): unknown[] => {
|
|
|
323
333
|
const memoCache = fiber.updateQueue?.memoCache;
|
|
324
334
|
if (memoCache === null || memoCache === undefined) return [];
|
|
325
335
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
memoCacheSlots = memoCache.data[memoCache.index] = Array.from(
|
|
329
|
-
{ length: size },
|
|
330
|
-
() => REACT_MEMO_CACHE_SENTINEL,
|
|
331
|
-
);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
memoCache.index++;
|
|
335
|
-
return memoCacheSlots;
|
|
336
|
+
const memoCacheSlots = memoCache.data[currentMemoCacheIndex++];
|
|
337
|
+
return memoCacheSlots?.slice() ?? Array.from({ length: size }, () => REACT_MEMO_CACHE_SENTINEL);
|
|
336
338
|
};
|
|
337
339
|
|
|
338
340
|
const dispatcherUseOptimistic = (passthrough: unknown): [unknown, () => void] => {
|
|
@@ -602,8 +604,9 @@ const findPrimitiveIndex = (hookStack: StackFrame[], hook: HookLogEntry): number
|
|
|
602
604
|
const parseTrimmedStack = (
|
|
603
605
|
rootStack: StackFrame[],
|
|
604
606
|
hook: HookLogEntry,
|
|
607
|
+
parseHookStack: (stack: string) => StackFrame[],
|
|
605
608
|
): [StackFrame | null, StackFrame[] | null] => {
|
|
606
|
-
const hookStack =
|
|
609
|
+
const hookStack = parseHookStack(hook.stackError.stack || "");
|
|
607
610
|
const rootIndex = findCommonAncestorIndex(rootStack, hookStack);
|
|
608
611
|
const primitiveIndex = findPrimitiveIndex(hookStack, hook);
|
|
609
612
|
if (rootIndex === -1 || primitiveIndex === -1 || rootIndex - primitiveIndex < 2) {
|
|
@@ -624,13 +627,14 @@ const NON_ID_HOOK_PRIMITIVES = new Set([
|
|
|
624
627
|
|
|
625
628
|
const buildTree = (rootStack: StackFrame[], capturedHookLog: HookLogEntry[]): HooksTree => {
|
|
626
629
|
const rootChildren: HooksNode[] = [];
|
|
630
|
+
const parseHookStack = createStackParser();
|
|
627
631
|
let previousStack: StackFrame[] | null = null;
|
|
628
632
|
let levelChildren = rootChildren;
|
|
629
633
|
let nativeHookID = 0;
|
|
630
634
|
const childrenStack: HooksNode[][] = [];
|
|
631
635
|
|
|
632
636
|
for (const hook of capturedHookLog) {
|
|
633
|
-
const [primitiveFrame, stack] = parseTrimmedStack(rootStack, hook);
|
|
637
|
+
const [primitiveFrame, stack] = parseTrimmedStack(rootStack, hook, parseHookStack);
|
|
634
638
|
let displayName = hook.displayName;
|
|
635
639
|
if (displayName === null && primitiveFrame !== null) {
|
|
636
640
|
const primitiveName = parseHookName(primitiveFrame.functionName);
|
|
@@ -834,6 +838,7 @@ const performDispatcherInspection = <TArgs extends unknown[]>(
|
|
|
834
838
|
): HooksTree => {
|
|
835
839
|
const previousDispatcher = readDispatcher(dispatcherRef);
|
|
836
840
|
writeDispatcher(dispatcherRef, dispatcherProxy);
|
|
841
|
+
isInspectingHooks = true;
|
|
837
842
|
|
|
838
843
|
let capturedHookLog: HookLogEntry[] = [];
|
|
839
844
|
let ancestorStackError: Error | undefined;
|
|
@@ -846,6 +851,7 @@ const performDispatcherInspection = <TArgs extends unknown[]>(
|
|
|
846
851
|
} finally {
|
|
847
852
|
capturedHookLog = hookLog;
|
|
848
853
|
hookLog = [];
|
|
854
|
+
isInspectingHooks = false;
|
|
849
855
|
writeDispatcher(dispatcherRef, previousDispatcher);
|
|
850
856
|
}
|
|
851
857
|
|
|
@@ -938,6 +944,7 @@ export const inspectHooks = (
|
|
|
938
944
|
props: Record<string, unknown>,
|
|
939
945
|
target: ReactDevToolsTarget = globalThis,
|
|
940
946
|
): HooksTree => {
|
|
947
|
+
assertNotInspectingHooks();
|
|
941
948
|
const dispatcherRef = requireDispatcherRef(undefined, target);
|
|
942
949
|
getPrimitiveStackCache();
|
|
943
950
|
currentHook = null;
|
|
@@ -961,6 +968,7 @@ export const inspectHooks = (
|
|
|
961
968
|
};
|
|
962
969
|
|
|
963
970
|
export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
971
|
+
assertNotInspectingHooks();
|
|
964
972
|
const dispatcherRef = requireDispatcherRef(fiber);
|
|
965
973
|
const workTags = getReactWorkTagsForFiber(fiber);
|
|
966
974
|
|
|
@@ -976,6 +984,7 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
976
984
|
|
|
977
985
|
currentHook = fiber.memoizedState;
|
|
978
986
|
currentFiber = fiber;
|
|
987
|
+
currentMemoCacheIndex = 0;
|
|
979
988
|
|
|
980
989
|
const debugThenableState = fiber.dependencies?._debugThenableState;
|
|
981
990
|
const usedThenables = Array.isArray(debugThenableState)
|
|
@@ -984,18 +993,16 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
984
993
|
currentThenableState = Array.isArray(usedThenables) ? usedThenables : null;
|
|
985
994
|
currentThenableIndex = 0;
|
|
986
995
|
|
|
987
|
-
resolveContextDependency(fiber);
|
|
988
|
-
|
|
989
|
-
const type = fiber.type;
|
|
990
|
-
let props = fiber.memoizedProps;
|
|
991
|
-
if (type !== fiber.elementType) {
|
|
992
|
-
props = resolveDefaultProps(type, props);
|
|
993
|
-
}
|
|
994
|
-
|
|
995
996
|
const originalConsoleMethods = suppressConsole();
|
|
996
997
|
const contextMap = new Map<ReactContext<unknown>, unknown>();
|
|
997
998
|
|
|
998
999
|
try {
|
|
1000
|
+
resolveContextDependency(fiber);
|
|
1001
|
+
const type = fiber.type;
|
|
1002
|
+
const props =
|
|
1003
|
+
type !== fiber.elementType
|
|
1004
|
+
? resolveDefaultProps(type, fiber.memoizedProps)
|
|
1005
|
+
: fiber.memoizedProps;
|
|
999
1006
|
if (
|
|
1000
1007
|
currentContextDependency !== null &&
|
|
1001
1008
|
!Object.hasOwn(currentContextDependency, "memoizedValue")
|
|
@@ -1030,6 +1037,7 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
1030
1037
|
currentContextDependency = null;
|
|
1031
1038
|
currentThenableState = null;
|
|
1032
1039
|
currentThenableIndex = 0;
|
|
1040
|
+
currentMemoCacheIndex = 0;
|
|
1033
1041
|
restoreContexts(contextMap);
|
|
1034
1042
|
restoreConsole(originalConsoleMethods);
|
|
1035
1043
|
}
|