bippy 0.7.3-dev.8ba0705 → 0.7.3-dev.9f2850b
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 +12 -11
- package/dist/core.cjs +1 -1
- package/dist/core.js +1 -1
- package/dist/errors.d.cts +5 -2
- package/dist/errors.d.ts +5 -2
- 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 +47 -11
- package/src/call-listener.ts +13 -0
- package/src/core.ts +256 -250
- package/src/index.ts +3 -3
- package/src/install-hook-only.ts +1 -1
- package/src/rdt-hook.ts +46 -30
- package/src/react-internals/current-fiber.ts +84 -0
- package/src/react-internals/generated/react-work-tags.ts +4 -1
- package/src/react-internals/index.ts +46 -19
- package/src/react-internals/types.ts +1 -1
- package/src/react.ts +144 -59
- package/src/source/constants.ts +10 -6
- package/src/source/get-display-name-from-source.ts +5 -5
- package/src/source/get-source.ts +8 -143
- package/src/source/index.ts +9 -9
- package/src/source/inspect-hooks.ts +35 -31
- package/src/source/normalize-file-name.ts +416 -0
- package/src/source/owner-stack.ts +9 -21
- package/src/source/parse-debug-stack.ts +3 -3
- package/src/source/parse-hook-names.ts +2 -2
- package/src/source/parse-stack.ts +111 -63
- package/src/source/renderer-dispatchers.ts +3 -3
- package/src/source/symbolication.ts +81 -41
package/src/source/get-source.ts
CHANGED
|
@@ -1,26 +1,17 @@
|
|
|
1
|
-
import type { Fiber } from "../react-internals/index
|
|
2
|
-
import { getDisplayName } from "../core
|
|
1
|
+
import type { Fiber } from "../react-internals/index";
|
|
2
|
+
import { getDisplayName } from "../core";
|
|
3
3
|
|
|
4
|
-
import type { FiberSource } from "./types
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
import { getDefinitionFrameFromOwnedChild, getParentStack, hasDebugStack } from "./owner-stack.js";
|
|
15
|
-
import { parseDebugStack } from "./parse-debug-stack.js";
|
|
16
|
-
import { parseStack, type StackFrame } from "./parse-stack.js";
|
|
4
|
+
import type { FiberSource } from "./types";
|
|
5
|
+
import { getDefinitionFrameFromOwnedChild, getParentStack, hasDebugStack } from "./owner-stack";
|
|
6
|
+
import { parseDebugStack } from "./parse-debug-stack";
|
|
7
|
+
import { parseStack, type StackFrame } from "./parse-stack";
|
|
17
8
|
import {
|
|
18
9
|
getSourceFromSourceMapByFunctionName,
|
|
19
10
|
getSourceMap,
|
|
20
11
|
symbolicateStack,
|
|
21
12
|
type SourceFetch,
|
|
22
13
|
type SourceMapRequestOptions,
|
|
23
|
-
} from "./symbolication
|
|
14
|
+
} from "./symbolication";
|
|
24
15
|
|
|
25
16
|
export const hasDebugSource = (
|
|
26
17
|
fiber: Fiber,
|
|
@@ -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";
|
package/src/source/index.ts
CHANGED
|
@@ -6,8 +6,8 @@ export {
|
|
|
6
6
|
getParentStack,
|
|
7
7
|
getRawOwnerStack,
|
|
8
8
|
hasDebugStack,
|
|
9
|
-
} from "./owner-stack
|
|
10
|
-
export { getRawSource, getSource, isSourceFile, normalizeFileName } from "./get-source
|
|
9
|
+
} from "./owner-stack";
|
|
10
|
+
export { getRawSource, getSource, isSourceFile, normalizeFileName } from "./get-source";
|
|
11
11
|
export {
|
|
12
12
|
getSourceContentFromSourceMap,
|
|
13
13
|
getSourceFromSourceMap,
|
|
@@ -20,22 +20,22 @@ export {
|
|
|
20
20
|
type SourceMap,
|
|
21
21
|
type SourceMapRequestOptions,
|
|
22
22
|
type StandardSourceMap,
|
|
23
|
-
} from "./symbolication
|
|
24
|
-
export type { FiberSource } from "./types
|
|
25
|
-
export { parseStack, type ParseOptions, type StackFrame } from "./parse-stack
|
|
26
|
-
export { getDisplayNameFromSource } from "./get-display-name-from-source
|
|
23
|
+
} from "./symbolication";
|
|
24
|
+
export type { FiberSource } from "./types";
|
|
25
|
+
export { parseStack, type ParseOptions, type StackFrame } from "./parse-stack";
|
|
26
|
+
export { getDisplayNameFromSource } from "./get-display-name-from-source";
|
|
27
27
|
export {
|
|
28
28
|
BippyError,
|
|
29
29
|
BippyHookInspectionError,
|
|
30
30
|
BippyHookRenderError,
|
|
31
31
|
BippySourceMapError,
|
|
32
32
|
BippyUnsupportedHookError,
|
|
33
|
-
} from "../errors
|
|
33
|
+
} from "../errors";
|
|
34
34
|
export {
|
|
35
35
|
getFiberHooks,
|
|
36
36
|
inspectHooks,
|
|
37
37
|
type HookSource,
|
|
38
38
|
type HooksNode,
|
|
39
39
|
type HooksTree,
|
|
40
|
-
} from "./inspect-hooks
|
|
41
|
-
export { parseHookNames, type HookNames } from "./parse-hook-names
|
|
40
|
+
} from "./inspect-hooks";
|
|
41
|
+
export { parseHookNames, type HookNames } from "./parse-hook-names";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getRenderer } from "../core
|
|
2
|
-
import type { ReactDevToolsTarget } from "../rdt-hook
|
|
1
|
+
import { getRenderer } from "../core";
|
|
2
|
+
import type { ReactDevToolsTarget } from "../rdt-hook";
|
|
3
3
|
import type {
|
|
4
4
|
Fiber,
|
|
5
5
|
ContextDependency,
|
|
@@ -7,19 +7,15 @@ import type {
|
|
|
7
7
|
ReactContext,
|
|
8
8
|
ReactDebugInfo,
|
|
9
9
|
RendererDispatcherRef,
|
|
10
|
-
} from "../react-internals/index
|
|
10
|
+
} from "../react-internals/index";
|
|
11
11
|
import {
|
|
12
12
|
BippyHookInspectionError,
|
|
13
13
|
BippyHookRenderError,
|
|
14
14
|
BippyUnsupportedHookError,
|
|
15
|
-
} from "../errors
|
|
16
|
-
import { getReactWorkTagsForFiber } from "../react-internals/index
|
|
17
|
-
import { parseStack, type StackFrame } from "./parse-stack
|
|
18
|
-
import {
|
|
19
|
-
getRendererDispatcherRefs,
|
|
20
|
-
readDispatcher,
|
|
21
|
-
writeDispatcher,
|
|
22
|
-
} from "./renderer-dispatchers.js";
|
|
15
|
+
} from "../errors";
|
|
16
|
+
import { getReactWorkTagsForFiber } from "../react-internals/index";
|
|
17
|
+
import { createStackParser, parseStack, type StackFrame } from "./parse-stack";
|
|
18
|
+
import { getRendererDispatcherRefs, readDispatcher, writeDispatcher } from "./renderer-dispatchers";
|
|
23
19
|
|
|
24
20
|
const REACT_CONTEXT_TYPE = Symbol.for("react.context");
|
|
25
21
|
const REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel");
|
|
@@ -87,6 +83,16 @@ let currentHook: MemoizedState | null = null;
|
|
|
87
83
|
let currentContextDependency: ContextDependency<unknown> | null = null;
|
|
88
84
|
let currentThenableIndex = 0;
|
|
89
85
|
let currentThenableState: unknown[] | null = null;
|
|
86
|
+
let currentMemoCacheIndex = 0;
|
|
87
|
+
let isInspectingHooks = false;
|
|
88
|
+
|
|
89
|
+
const assertNotInspectingHooks = (): void => {
|
|
90
|
+
if (isInspectingHooks) {
|
|
91
|
+
throw new BippyHookInspectionError(
|
|
92
|
+
"Hook inspection cannot be called during another inspection.",
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
90
96
|
|
|
91
97
|
const SuspenseException: unknown = new Error(
|
|
92
98
|
"Suspense interrupted this render. This error is an internal implementation detail of `use`.",
|
|
@@ -323,16 +329,8 @@ const dispatcherUseMemoCache = (size: number): unknown[] => {
|
|
|
323
329
|
const memoCache = fiber.updateQueue?.memoCache;
|
|
324
330
|
if (memoCache === null || memoCache === undefined) return [];
|
|
325
331
|
|
|
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;
|
|
332
|
+
const memoCacheSlots = memoCache.data[currentMemoCacheIndex++];
|
|
333
|
+
return memoCacheSlots?.slice() ?? Array.from({ length: size }, () => REACT_MEMO_CACHE_SENTINEL);
|
|
336
334
|
};
|
|
337
335
|
|
|
338
336
|
const dispatcherUseOptimistic = (passthrough: unknown): [unknown, () => void] => {
|
|
@@ -602,8 +600,9 @@ const findPrimitiveIndex = (hookStack: StackFrame[], hook: HookLogEntry): number
|
|
|
602
600
|
const parseTrimmedStack = (
|
|
603
601
|
rootStack: StackFrame[],
|
|
604
602
|
hook: HookLogEntry,
|
|
603
|
+
parseHookStack: (stack: string) => StackFrame[],
|
|
605
604
|
): [StackFrame | null, StackFrame[] | null] => {
|
|
606
|
-
const hookStack =
|
|
605
|
+
const hookStack = parseHookStack(hook.stackError.stack || "");
|
|
607
606
|
const rootIndex = findCommonAncestorIndex(rootStack, hookStack);
|
|
608
607
|
const primitiveIndex = findPrimitiveIndex(hookStack, hook);
|
|
609
608
|
if (rootIndex === -1 || primitiveIndex === -1 || rootIndex - primitiveIndex < 2) {
|
|
@@ -624,13 +623,14 @@ const NON_ID_HOOK_PRIMITIVES = new Set([
|
|
|
624
623
|
|
|
625
624
|
const buildTree = (rootStack: StackFrame[], capturedHookLog: HookLogEntry[]): HooksTree => {
|
|
626
625
|
const rootChildren: HooksNode[] = [];
|
|
626
|
+
const parseHookStack = createStackParser();
|
|
627
627
|
let previousStack: StackFrame[] | null = null;
|
|
628
628
|
let levelChildren = rootChildren;
|
|
629
629
|
let nativeHookID = 0;
|
|
630
630
|
const childrenStack: HooksNode[][] = [];
|
|
631
631
|
|
|
632
632
|
for (const hook of capturedHookLog) {
|
|
633
|
-
const [primitiveFrame, stack] = parseTrimmedStack(rootStack, hook);
|
|
633
|
+
const [primitiveFrame, stack] = parseTrimmedStack(rootStack, hook, parseHookStack);
|
|
634
634
|
let displayName = hook.displayName;
|
|
635
635
|
if (displayName === null && primitiveFrame !== null) {
|
|
636
636
|
const primitiveName = parseHookName(primitiveFrame.functionName);
|
|
@@ -834,6 +834,7 @@ const performDispatcherInspection = <TArgs extends unknown[]>(
|
|
|
834
834
|
): HooksTree => {
|
|
835
835
|
const previousDispatcher = readDispatcher(dispatcherRef);
|
|
836
836
|
writeDispatcher(dispatcherRef, dispatcherProxy);
|
|
837
|
+
isInspectingHooks = true;
|
|
837
838
|
|
|
838
839
|
let capturedHookLog: HookLogEntry[] = [];
|
|
839
840
|
let ancestorStackError: Error | undefined;
|
|
@@ -846,6 +847,7 @@ const performDispatcherInspection = <TArgs extends unknown[]>(
|
|
|
846
847
|
} finally {
|
|
847
848
|
capturedHookLog = hookLog;
|
|
848
849
|
hookLog = [];
|
|
850
|
+
isInspectingHooks = false;
|
|
849
851
|
writeDispatcher(dispatcherRef, previousDispatcher);
|
|
850
852
|
}
|
|
851
853
|
|
|
@@ -938,6 +940,7 @@ export const inspectHooks = (
|
|
|
938
940
|
props: Record<string, unknown>,
|
|
939
941
|
target: ReactDevToolsTarget = globalThis,
|
|
940
942
|
): HooksTree => {
|
|
943
|
+
assertNotInspectingHooks();
|
|
941
944
|
const dispatcherRef = requireDispatcherRef(undefined, target);
|
|
942
945
|
getPrimitiveStackCache();
|
|
943
946
|
currentHook = null;
|
|
@@ -961,6 +964,7 @@ export const inspectHooks = (
|
|
|
961
964
|
};
|
|
962
965
|
|
|
963
966
|
export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
967
|
+
assertNotInspectingHooks();
|
|
964
968
|
const dispatcherRef = requireDispatcherRef(fiber);
|
|
965
969
|
const workTags = getReactWorkTagsForFiber(fiber);
|
|
966
970
|
|
|
@@ -976,6 +980,7 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
976
980
|
|
|
977
981
|
currentHook = fiber.memoizedState;
|
|
978
982
|
currentFiber = fiber;
|
|
983
|
+
currentMemoCacheIndex = 0;
|
|
979
984
|
|
|
980
985
|
const debugThenableState = fiber.dependencies?._debugThenableState;
|
|
981
986
|
const usedThenables = Array.isArray(debugThenableState)
|
|
@@ -984,18 +989,16 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
984
989
|
currentThenableState = Array.isArray(usedThenables) ? usedThenables : null;
|
|
985
990
|
currentThenableIndex = 0;
|
|
986
991
|
|
|
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
992
|
const originalConsoleMethods = suppressConsole();
|
|
996
993
|
const contextMap = new Map<ReactContext<unknown>, unknown>();
|
|
997
994
|
|
|
998
995
|
try {
|
|
996
|
+
resolveContextDependency(fiber);
|
|
997
|
+
const type = fiber.type;
|
|
998
|
+
const props =
|
|
999
|
+
type !== fiber.elementType
|
|
1000
|
+
? resolveDefaultProps(type, fiber.memoizedProps)
|
|
1001
|
+
: fiber.memoizedProps;
|
|
999
1002
|
if (
|
|
1000
1003
|
currentContextDependency !== null &&
|
|
1001
1004
|
!Object.hasOwn(currentContextDependency, "memoizedValue")
|
|
@@ -1030,6 +1033,7 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
1030
1033
|
currentContextDependency = null;
|
|
1031
1034
|
currentThenableState = null;
|
|
1032
1035
|
currentThenableIndex = 0;
|
|
1036
|
+
currentMemoCacheIndex = 0;
|
|
1033
1037
|
restoreContexts(contextMap);
|
|
1034
1038
|
restoreConsole(originalConsoleMethods);
|
|
1035
1039
|
}
|