bippy 0.6.1-dev.d7876ea → 0.6.1-dev.f9a65c0
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/LICENSE +1 -1
- package/README.md +211 -445
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +25 -75
- package/dist/core.d.ts +25 -75
- package/dist/core.js +1 -1
- package/dist/core2.cjs +1 -1
- package/dist/core2.d.cts +11 -3
- package/dist/core2.d.ts +11 -3
- package/dist/core2.js +1 -1
- package/dist/errors.d.cts +33 -59
- package/dist/errors.d.ts +33 -59
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +14 -3
- package/dist/index.d.ts +14 -3
- package/dist/index.js +1 -1
- package/dist/install-hook-only.cjs +1 -1
- package/dist/install-hook-only.d.cts +8 -0
- package/dist/install-hook-only.d.ts +8 -0
- 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 +12 -13
- package/dist/source.d.cts +85 -77
- package/dist/source.d.ts +85 -77
- package/dist/source.js +12 -13
- package/package.json +6 -3
- package/src/core.ts +146 -579
- package/src/errors.ts +0 -65
- package/src/index.ts +1 -0
- package/src/install-hook-only.ts +2 -2
- package/src/rdt-hook.ts +39 -45
- package/src/{generated/react-work-tags.js → react-internals/generated/react-work-tags.ts} +85 -7
- package/src/{react-internals.ts → react-internals/index.ts} +6 -4
- package/src/{semver.ts → react-internals/semver.ts} +2 -0
- package/src/{types.ts → react-internals/types.ts} +1 -84
- package/src/react.ts +76 -0
- package/src/source/get-display-name-from-source.ts +44 -40
- package/src/source/get-source.ts +42 -26
- package/src/source/index.ts +2 -0
- package/src/source/inspect-hooks.ts +74 -96
- package/src/source/owner-stack.ts +66 -91
- package/src/source/parse-hook-names.ts +14 -53
- package/src/source/parse-stack.ts +14 -31
- package/src/source/renderer-dispatchers.ts +30 -0
- package/src/source/symbolication.ts +421 -108
- package/dist/index.iife.js +0 -9
- package/dist/install-hook-only.iife.js +0 -9
- package/src/generated/react-work-tags.d.ts +0 -261
- package/src/unsubscribe.ts +0 -17
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import { getDisplayName, getType, traverseFiber } from "../core.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
2
|
+
import { getReactWorkTagsForFiber } from "../react-internals/index.js";
|
|
3
|
+
import type {
|
|
4
|
+
Fiber,
|
|
5
|
+
RendererDispatcherRef,
|
|
6
|
+
ServerComponentInfo,
|
|
7
|
+
} from "../react-internals/index.js";
|
|
5
8
|
import {
|
|
9
|
+
REACT_STACK_BOTTOM_FRAME_PATTERNS,
|
|
6
10
|
SERVER_FRAME_MARKER,
|
|
7
11
|
SERVER_ENV_PATTERN,
|
|
8
12
|
SERVER_COMPONENT_URL_PREFIXES,
|
|
9
13
|
} from "./constants.js";
|
|
10
14
|
import { getPrepareStackTrace, setPrepareStackTrace } from "./error-stack.js";
|
|
11
15
|
import { parseDebugStack } from "./parse-debug-stack.js";
|
|
12
|
-
import { parseStack, StackFrame } from "./parse-stack.js";
|
|
13
|
-
import {
|
|
16
|
+
import { parseStack, type StackFrame } from "./parse-stack.js";
|
|
17
|
+
import {
|
|
18
|
+
getRendererDispatcherRefs,
|
|
19
|
+
readDispatcher,
|
|
20
|
+
writeDispatcher,
|
|
21
|
+
} from "./renderer-dispatchers.js";
|
|
22
|
+
import { symbolicateStack, type SourceFetch } from "./symbolication.js";
|
|
14
23
|
|
|
15
24
|
interface RendererDispatcherSnapshot {
|
|
16
25
|
currentDispatcherRef: RendererDispatcherRef;
|
|
@@ -28,9 +37,6 @@ export const hasDebugStack = (
|
|
|
28
37
|
const isFiberOwner = (owner: Fiber | ServerComponentInfo): owner is Fiber =>
|
|
29
38
|
"tag" in owner && typeof owner.tag === "number";
|
|
30
39
|
|
|
31
|
-
const getDebugOwner = (fiber: Fiber): Fiber | ServerComponentInfo | undefined =>
|
|
32
|
-
fiber._debugOwner ?? undefined;
|
|
33
|
-
|
|
34
40
|
/**
|
|
35
41
|
* Locates a frame inside the fiber's own function body without invoking it:
|
|
36
42
|
* any child fiber owned by this fiber was created by JSX inside its body, so
|
|
@@ -76,42 +82,18 @@ export const getDefinitionFrameFromOwnedChild = (fiber: Fiber): StackFrame | nul
|
|
|
76
82
|
return null;
|
|
77
83
|
};
|
|
78
84
|
|
|
79
|
-
const getRendererDispatcherRefs = (): RendererDispatcherRef[] => {
|
|
80
|
-
const rdtHook = getRDTHook();
|
|
81
|
-
const renderers = new Set([..._renderers, ...rdtHook.renderers.values()]);
|
|
82
|
-
const currentDispatcherRefs: RendererDispatcherRef[] = [];
|
|
83
|
-
const seenCurrentDispatcherRefs = new Set<object>();
|
|
84
|
-
for (const renderer of renderers) {
|
|
85
|
-
const currentDispatcherRef = renderer.currentDispatcherRef;
|
|
86
|
-
if (!currentDispatcherRef || seenCurrentDispatcherRefs.has(currentDispatcherRef)) continue;
|
|
87
|
-
seenCurrentDispatcherRefs.add(currentDispatcherRef);
|
|
88
|
-
currentDispatcherRefs.push(currentDispatcherRef);
|
|
89
|
-
}
|
|
90
|
-
return currentDispatcherRefs;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
85
|
const clearRendererDispatchers = (): RendererDispatcherSnapshot[] => {
|
|
94
86
|
const dispatcherSnapshots: RendererDispatcherSnapshot[] = [];
|
|
95
87
|
for (const currentDispatcherRef of getRendererDispatcherRefs()) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
dispatcherSnapshots.push({ currentDispatcherRef, value });
|
|
99
|
-
if ("H" in currentDispatcherRef) {
|
|
100
|
-
currentDispatcherRef.H = null;
|
|
101
|
-
} else {
|
|
102
|
-
currentDispatcherRef.current = null;
|
|
103
|
-
}
|
|
88
|
+
dispatcherSnapshots.push({ currentDispatcherRef, value: readDispatcher(currentDispatcherRef) });
|
|
89
|
+
writeDispatcher(currentDispatcherRef, null);
|
|
104
90
|
}
|
|
105
91
|
return dispatcherSnapshots;
|
|
106
92
|
};
|
|
107
93
|
|
|
108
94
|
const restoreRendererDispatchers = (dispatcherSnapshots: RendererDispatcherSnapshot[]): void => {
|
|
109
95
|
for (const { currentDispatcherRef, value } of dispatcherSnapshots) {
|
|
110
|
-
|
|
111
|
-
currentDispatcherRef.H = value;
|
|
112
|
-
} else {
|
|
113
|
-
currentDispatcherRef.current = value;
|
|
114
|
-
}
|
|
96
|
+
writeDispatcher(currentDispatcherRef, value);
|
|
115
97
|
}
|
|
116
98
|
};
|
|
117
99
|
|
|
@@ -290,6 +272,10 @@ const describeNativeComponentFrame = (
|
|
|
290
272
|
if (controlIndex < 0 || sampleLines[sampleIndex] !== controlLines[controlIndex]) {
|
|
291
273
|
// V8 adds a "new" prefix for native classes. Let's remove it to make it prettier.
|
|
292
274
|
let stackFrame = `\n${sampleLines[sampleIndex].replace(" at new ", " at ")}`;
|
|
275
|
+
const [parsedStackFrame] = parseStack(stackFrame);
|
|
276
|
+
if (!parsedStackFrame?.fileName) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
293
279
|
|
|
294
280
|
const displayName = getDisplayName(component);
|
|
295
281
|
// If our component frame is labeled "<anonymous>"
|
|
@@ -318,7 +304,7 @@ const describeNativeComponentFrame = (
|
|
|
318
304
|
console.warn = previousConsoleWarn;
|
|
319
305
|
}
|
|
320
306
|
|
|
321
|
-
const componentName =
|
|
307
|
+
const componentName = getDisplayName(component);
|
|
322
308
|
const syntheticFrame = componentName ? describeBuiltInComponentFrame(componentName) : "";
|
|
323
309
|
componentFrameCache.set(component, syntheticFrame);
|
|
324
310
|
return syntheticFrame;
|
|
@@ -340,7 +326,7 @@ export const describeFiber = (fiber: Fiber, childFiber: Fiber | null): string =>
|
|
|
340
326
|
break;
|
|
341
327
|
case workTags.FunctionComponent:
|
|
342
328
|
case workTags.SimpleMemoComponent:
|
|
343
|
-
stackFrame = describeNativeComponentFrame(fiber.type, false);
|
|
329
|
+
stackFrame = describeNativeComponentFrame(getType(fiber.type) ?? fiber.type, false);
|
|
344
330
|
break;
|
|
345
331
|
case workTags.HostComponent:
|
|
346
332
|
case workTags.HostHoistable:
|
|
@@ -407,7 +393,7 @@ export const getFallbackParentStack = (thisFiber: Fiber): string => {
|
|
|
407
393
|
return componentStack;
|
|
408
394
|
} catch (error) {
|
|
409
395
|
if (error instanceof Error) {
|
|
410
|
-
return `\
|
|
396
|
+
return `\nBippy couldn’t generate the stack: ${error.message}\n${error.stack}`;
|
|
411
397
|
}
|
|
412
398
|
return "";
|
|
413
399
|
}
|
|
@@ -448,8 +434,7 @@ export const formatOwnerStack = (stack: string): string => {
|
|
|
448
434
|
formattedStack = formattedStack.slice(firstNewlineIndex + 1);
|
|
449
435
|
}
|
|
450
436
|
let bottomFrameIndex = Math.max(
|
|
451
|
-
formattedStack.indexOf(
|
|
452
|
-
formattedStack.indexOf("react-stack-bottom-frame"),
|
|
437
|
+
...REACT_STACK_BOTTOM_FRAME_PATTERNS.map((pattern) => formattedStack.indexOf(pattern)),
|
|
453
438
|
);
|
|
454
439
|
if (bottomFrameIndex !== -1) {
|
|
455
440
|
bottomFrameIndex = formattedStack.lastIndexOf("\n", bottomFrameIndex);
|
|
@@ -466,11 +451,6 @@ export const formatOwnerStack = (stack: string): string => {
|
|
|
466
451
|
return formattedStack;
|
|
467
452
|
};
|
|
468
453
|
|
|
469
|
-
interface DebugStackEntry {
|
|
470
|
-
componentName: string;
|
|
471
|
-
stackFrames: StackFrame[];
|
|
472
|
-
}
|
|
473
|
-
|
|
474
454
|
const isReactServerComponentFrame = (stackFrame: StackFrame): boolean =>
|
|
475
455
|
Boolean(
|
|
476
456
|
stackFrame.functionName && stackFrame.fileName && isServerComponentUrl(stackFrame.fileName),
|
|
@@ -482,24 +462,22 @@ const areStackFramesEqual = (firstFrame: StackFrame, secondFrame: StackFrame): b
|
|
|
482
462
|
firstFrame.columnNumber === secondFrame.columnNumber;
|
|
483
463
|
|
|
484
464
|
const buildFunctionNameToRscFramesMap = (
|
|
485
|
-
|
|
465
|
+
debugStackFrames: StackFrame[],
|
|
486
466
|
): Map<string, StackFrame[]> => {
|
|
487
467
|
const functionNameToRscFrames = new Map<string, StackFrame[]>();
|
|
488
468
|
|
|
489
|
-
for (const
|
|
490
|
-
|
|
491
|
-
if (!isReactServerComponentFrame(stackFrame)) continue;
|
|
469
|
+
for (const stackFrame of debugStackFrames) {
|
|
470
|
+
if (!isReactServerComponentFrame(stackFrame)) continue;
|
|
492
471
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
472
|
+
const functionName = stackFrame.functionName!;
|
|
473
|
+
const framesForFunction = functionNameToRscFrames.get(functionName) ?? [];
|
|
474
|
+
const isDuplicateFrame = framesForFunction.some((existingFrame) =>
|
|
475
|
+
areStackFramesEqual(existingFrame, stackFrame),
|
|
476
|
+
);
|
|
498
477
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
478
|
+
if (!isDuplicateFrame) {
|
|
479
|
+
framesForFunction.push(stackFrame);
|
|
480
|
+
functionNameToRscFrames.set(functionName, framesForFunction);
|
|
503
481
|
}
|
|
504
482
|
}
|
|
505
483
|
|
|
@@ -560,7 +538,7 @@ const getOwnerStackFromDebugStacks = (fiber: Fiber): StackFrame[] => {
|
|
|
560
538
|
while (owner) {
|
|
561
539
|
if (isFiberOwner(owner)) {
|
|
562
540
|
const ownerFiber: Fiber = owner;
|
|
563
|
-
owner =
|
|
541
|
+
owner = ownerFiber._debugOwner;
|
|
564
542
|
if (owner && hasDebugStack(ownerFiber)) {
|
|
565
543
|
const { frames, isTrusted } = parseDebugStack(ownerFiber._debugStack);
|
|
566
544
|
if (isTrusted) {
|
|
@@ -584,53 +562,39 @@ const getOwnerStackFromDebugStacks = (fiber: Fiber): StackFrame[] => {
|
|
|
584
562
|
return ownerStackFrames;
|
|
585
563
|
};
|
|
586
564
|
|
|
587
|
-
const
|
|
588
|
-
const
|
|
565
|
+
const getDebugStackFrames = (rootFiber: Fiber): StackFrame[] => {
|
|
566
|
+
const debugStackFrames: StackFrame[] = [];
|
|
589
567
|
|
|
590
568
|
traverseFiber(
|
|
591
569
|
rootFiber,
|
|
592
570
|
(currentFiber) => {
|
|
593
571
|
if (!hasDebugStack(currentFiber)) return;
|
|
594
572
|
|
|
595
|
-
const
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
debugStackEntries.push({
|
|
601
|
-
componentName,
|
|
602
|
-
stackFrames: parseStack(formatOwnerStack(currentFiber._debugStack?.stack)),
|
|
603
|
-
});
|
|
573
|
+
const { frames, isTrusted } = parseDebugStack(currentFiber._debugStack);
|
|
574
|
+
if (isTrusted) {
|
|
575
|
+
debugStackFrames.push(...frames);
|
|
576
|
+
}
|
|
604
577
|
},
|
|
605
578
|
true,
|
|
606
579
|
);
|
|
607
580
|
|
|
608
|
-
return
|
|
581
|
+
return debugStackFrames;
|
|
609
582
|
};
|
|
610
583
|
|
|
611
584
|
/**
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
* with a throwing dispatcher; server frames are enriched from debug stacks by
|
|
616
|
-
* name matching. Works on every React version.
|
|
585
|
+
* The unsymbolicated frames behind {@link getParentStack}: bundle-space
|
|
586
|
+
* locations from re-invoking each component with a throwing dispatcher,
|
|
587
|
+
* with server frames enriched from debug stacks by name matching.
|
|
617
588
|
*/
|
|
618
|
-
export const
|
|
619
|
-
fiber
|
|
620
|
-
shouldCache = true,
|
|
621
|
-
fetchFunction?: (url: string) => Promise<Response>,
|
|
622
|
-
): Promise<StackFrame[]> => {
|
|
623
|
-
const debugStackEntries = getDebugStackEntries(fiber);
|
|
589
|
+
export const getRawParentStack = (fiber: Fiber): StackFrame[] => {
|
|
590
|
+
const debugStackFrames = getDebugStackFrames(fiber);
|
|
624
591
|
const fallbackStackFrames = parseStack(getFallbackParentStack(fiber));
|
|
625
|
-
const functionNameToRscFrames = buildFunctionNameToRscFramesMap(
|
|
592
|
+
const functionNameToRscFrames = buildFunctionNameToRscFramesMap(debugStackFrames);
|
|
626
593
|
const functionNameToUsageIndex = new Map<string, number>();
|
|
627
594
|
|
|
628
595
|
const enrichedStackFrames = fallbackStackFrames.map((stackFrame): StackFrame => {
|
|
629
596
|
const isServerFrame =
|
|
630
|
-
|
|
631
|
-
(stackFrame.source !== null &&
|
|
632
|
-
stackFrame.source !== undefined &&
|
|
633
|
-
SERVER_ENV_PATTERN.test(stackFrame.source));
|
|
597
|
+
stackFrame.source !== undefined && SERVER_ENV_PATTERN.test(stackFrame.source);
|
|
634
598
|
|
|
635
599
|
if (isServerFrame) {
|
|
636
600
|
return getEnrichedServerStackFrame(
|
|
@@ -643,15 +607,26 @@ export const getParentStack = async (
|
|
|
643
607
|
return stackFrame;
|
|
644
608
|
});
|
|
645
609
|
|
|
646
|
-
|
|
610
|
+
return enrichedStackFrames.filter((stackFrame, index, frames) => {
|
|
647
611
|
if (index === 0) return true;
|
|
648
612
|
const previousFrame = frames[index - 1];
|
|
649
613
|
return stackFrame.functionName !== previousFrame.functionName;
|
|
650
614
|
});
|
|
651
|
-
|
|
652
|
-
return symbolicateStack(deduplicatedStackFrames, shouldCache, fetchFunction);
|
|
653
615
|
};
|
|
654
616
|
|
|
617
|
+
/**
|
|
618
|
+
* Returns a stack of ALL ancestor components in the render tree (the fiber's
|
|
619
|
+
* `return` chain), including wrappers that render `{children}` without having
|
|
620
|
+
* created this fiber's JSX. Locations come from re-invoking each component
|
|
621
|
+
* with a throwing dispatcher; server frames are enriched from debug stacks by
|
|
622
|
+
* name matching. Works on every React version.
|
|
623
|
+
*/
|
|
624
|
+
export const getParentStack = async (
|
|
625
|
+
fiber: Fiber,
|
|
626
|
+
shouldCache = true,
|
|
627
|
+
fetchFunction?: SourceFetch,
|
|
628
|
+
): Promise<StackFrame[]> => symbolicateStack(getRawParentStack(fiber), shouldCache, fetchFunction);
|
|
629
|
+
|
|
655
630
|
// an owner frame is only actionable if it can point an editor somewhere:
|
|
656
631
|
// it needs a file location and must not be ignore-listed bundler/framework code
|
|
657
632
|
const isLocatableFrame = (stackFrame: StackFrame): boolean =>
|
|
@@ -670,7 +645,7 @@ const isLocatableFrame = (stackFrame: StackFrame): boolean =>
|
|
|
670
645
|
export const getOwnerStack = async (
|
|
671
646
|
fiber: Fiber,
|
|
672
647
|
shouldCache = true,
|
|
673
|
-
fetchFunction?:
|
|
648
|
+
fetchFunction?: SourceFetch,
|
|
674
649
|
): Promise<StackFrame[]> => {
|
|
675
650
|
const debugStackFrames = getOwnerStackFromDebugStacks(fiber);
|
|
676
651
|
if (debugStackFrames.length > 0) {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { HooksNode, HooksTree, HookSource } from "./inspect-hooks.js";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getSourceContentFromSourceMap,
|
|
4
|
+
getSourceFromSourceMap,
|
|
5
|
+
getSourceMap,
|
|
6
|
+
type SourceFetch,
|
|
7
|
+
} from "./symbolication.js";
|
|
3
8
|
|
|
4
9
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
5
10
|
export interface HookNames extends Map<string, string> {}
|
|
@@ -33,40 +38,6 @@ const flattenHooksTree = (hooksTree: HooksTree): HooksNode[] => {
|
|
|
33
38
|
return hooksList;
|
|
34
39
|
};
|
|
35
40
|
|
|
36
|
-
const findSourceContentByFileName = (
|
|
37
|
-
sources: string[],
|
|
38
|
-
sourcesContent: string[] | undefined,
|
|
39
|
-
fileName: string,
|
|
40
|
-
): string | null => {
|
|
41
|
-
if (!sourcesContent) return null;
|
|
42
|
-
const sourceIndex = sources.indexOf(fileName);
|
|
43
|
-
return sourceIndex !== -1 ? (sourcesContent[sourceIndex] ?? null) : null;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const getSourceContentFromSourceMap = (
|
|
47
|
-
sourceMap: SourceMap,
|
|
48
|
-
originalFileName: string,
|
|
49
|
-
): string | null => {
|
|
50
|
-
const directResult = findSourceContentByFileName(
|
|
51
|
-
sourceMap.sources,
|
|
52
|
-
sourceMap.sourcesContent,
|
|
53
|
-
originalFileName,
|
|
54
|
-
);
|
|
55
|
-
if (directResult) return directResult;
|
|
56
|
-
|
|
57
|
-
if (sourceMap.sections) {
|
|
58
|
-
for (const section of sourceMap.sections) {
|
|
59
|
-
const sectionResult = findSourceContentByFileName(
|
|
60
|
-
section.map.sources,
|
|
61
|
-
section.map.sourcesContent,
|
|
62
|
-
originalFileName,
|
|
63
|
-
);
|
|
64
|
-
if (sectionResult) return sectionResult;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return null;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
41
|
const extractVariableNameFromBinding = (binding: string): string | null => {
|
|
71
42
|
const trimmed = binding.trim();
|
|
72
43
|
if (trimmed.startsWith("[")) {
|
|
@@ -109,9 +80,8 @@ interface ResolvedSource {
|
|
|
109
80
|
}
|
|
110
81
|
|
|
111
82
|
interface SourceResolutionContext {
|
|
112
|
-
sourceMapsByFile: Map<string, SourceMap | null>;
|
|
113
83
|
sourceContentCache: Map<string, string | null>;
|
|
114
|
-
fetchFn?:
|
|
84
|
+
fetchFn?: SourceFetch;
|
|
115
85
|
}
|
|
116
86
|
|
|
117
87
|
const resolveOriginalSource = async (
|
|
@@ -120,25 +90,17 @@ const resolveOriginalSource = async (
|
|
|
120
90
|
runtimeColumn: number,
|
|
121
91
|
context: SourceResolutionContext,
|
|
122
92
|
): Promise<ResolvedSource | null> => {
|
|
123
|
-
const {
|
|
93
|
+
const { sourceContentCache, fetchFn } = context;
|
|
124
94
|
|
|
125
|
-
|
|
126
|
-
sourceMapsByFile.set(runtimeFileName, await getSourceMap(runtimeFileName, true, fetchFn));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const sourceMap = sourceMapsByFile.get(runtimeFileName) ?? null;
|
|
95
|
+
const sourceMap = await getSourceMap(runtimeFileName, true, fetchFn);
|
|
130
96
|
|
|
131
97
|
if (sourceMap) {
|
|
132
98
|
const originalLocation = getSourceFromSourceMap(sourceMap, runtimeLine, runtimeColumn);
|
|
133
99
|
if (originalLocation?.fileName && originalLocation.lineNumber !== undefined) {
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
getSourceContentFromSourceMap(sourceMap, originalLocation.fileName),
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
const originalSourceCode = sourceContentCache.get(cacheKey) ?? null;
|
|
100
|
+
const originalSourceCode = getSourceContentFromSourceMap(
|
|
101
|
+
sourceMap,
|
|
102
|
+
originalLocation.fileName,
|
|
103
|
+
);
|
|
142
104
|
if (originalSourceCode) {
|
|
143
105
|
return {
|
|
144
106
|
sourceCode: originalSourceCode,
|
|
@@ -173,7 +135,7 @@ const resolveOriginalSource = async (
|
|
|
173
135
|
|
|
174
136
|
export const parseHookNames = async (
|
|
175
137
|
hooksTree: HooksTree,
|
|
176
|
-
fetchFn?:
|
|
138
|
+
fetchFn?: SourceFetch,
|
|
177
139
|
): Promise<HookNames> => {
|
|
178
140
|
const hookNames: HookNames = new Map();
|
|
179
141
|
const hooksList = flattenHooksTree(hooksTree);
|
|
@@ -181,7 +143,6 @@ export const parseHookNames = async (
|
|
|
181
143
|
if (hooksList.length === 0) return hookNames;
|
|
182
144
|
|
|
183
145
|
const resolutionContext: SourceResolutionContext = {
|
|
184
|
-
sourceMapsByFile: new Map(),
|
|
185
146
|
sourceContentCache: new Map(),
|
|
186
147
|
fetchFn,
|
|
187
148
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export interface StackFrame {
|
|
2
|
-
args?: unknown[];
|
|
3
2
|
columnNumber?: number;
|
|
4
3
|
lineNumber?: number;
|
|
5
4
|
// start of the enclosing function (the definition, not the call site);
|
|
@@ -16,8 +15,6 @@ export interface StackFrame {
|
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
export interface ParseOptions {
|
|
19
|
-
slice?: number | [number, number];
|
|
20
|
-
allowEmpty?: boolean;
|
|
21
18
|
includeInElement?: boolean;
|
|
22
19
|
}
|
|
23
20
|
|
|
@@ -31,22 +28,22 @@ export const parseStack = (stackString: string, options?: ParseOptions): StackFr
|
|
|
31
28
|
const frames: StackFrame[] = [];
|
|
32
29
|
for (const rawLine of lines) {
|
|
33
30
|
if (/^\s*at\s+/.test(rawLine)) {
|
|
34
|
-
const parsed = parseV8OrIeString(rawLine
|
|
31
|
+
const parsed = parseV8OrIeString(rawLine)[0];
|
|
35
32
|
if (parsed) frames.push(parsed);
|
|
36
33
|
} else if (/^\s*in\s+/.test(rawLine)) {
|
|
37
34
|
const elementName = rawLine.replace(/^\s*in\s+/, "").replace(/\s*\(at .*\)$/, "");
|
|
38
35
|
frames.push({ functionName: elementName, source: rawLine });
|
|
39
36
|
} else if (rawLine.match(FIREFOX_SAFARI_STACK_REGEXP)) {
|
|
40
|
-
const parsed = parseFFOrSafariString(rawLine
|
|
37
|
+
const parsed = parseFFOrSafariString(rawLine)[0];
|
|
41
38
|
if (parsed) frames.push(parsed);
|
|
42
39
|
}
|
|
43
40
|
}
|
|
44
|
-
return
|
|
41
|
+
return frames;
|
|
45
42
|
}
|
|
46
43
|
if (stackString.match(CHROME_IE_STACK_REGEXP)) {
|
|
47
|
-
return parseV8OrIeString(stackString
|
|
44
|
+
return parseV8OrIeString(stackString);
|
|
48
45
|
}
|
|
49
|
-
return parseFFOrSafariString(stackString
|
|
46
|
+
return parseFFOrSafariString(stackString);
|
|
50
47
|
};
|
|
51
48
|
|
|
52
49
|
export const extractLocation = (
|
|
@@ -66,21 +63,10 @@ export const extractLocation = (
|
|
|
66
63
|
return [parts[1], parts[2] || undefined, parts[3] || undefined] as const;
|
|
67
64
|
};
|
|
68
65
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
return lines;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
export const parseV8OrIeString = (stack: string, options?: ParseOptions): StackFrame[] => {
|
|
78
|
-
const filteredLines = applySlice(
|
|
79
|
-
stack.split("\n").filter((line) => {
|
|
80
|
-
return !!line.match(CHROME_IE_STACK_REGEXP);
|
|
81
|
-
}),
|
|
82
|
-
options,
|
|
83
|
-
);
|
|
66
|
+
export const parseV8OrIeString = (stack: string): StackFrame[] => {
|
|
67
|
+
const filteredLines = stack.split("\n").filter((line) => {
|
|
68
|
+
return !!line.match(CHROME_IE_STACK_REGEXP);
|
|
69
|
+
});
|
|
84
70
|
|
|
85
71
|
return filteredLines.map((line): StackFrame => {
|
|
86
72
|
let currentLine = line;
|
|
@@ -100,7 +86,7 @@ export const parseV8OrIeString = (stack: string, options?: ParseOptions): StackF
|
|
|
100
86
|
|
|
101
87
|
const locationParts = extractLocation(locationMatch ? locationMatch[1] : sanitizedLine);
|
|
102
88
|
const functionName = (locationMatch && sanitizedLine) || undefined;
|
|
103
|
-
const fileName = ["eval", "<anonymous>"].includes(locationParts[0])
|
|
89
|
+
const fileName = ["eval", "<anonymous>", "(native)"].includes(locationParts[0])
|
|
104
90
|
? undefined
|
|
105
91
|
: locationParts[0];
|
|
106
92
|
|
|
@@ -114,13 +100,10 @@ export const parseV8OrIeString = (stack: string, options?: ParseOptions): StackF
|
|
|
114
100
|
});
|
|
115
101
|
};
|
|
116
102
|
|
|
117
|
-
export const parseFFOrSafariString = (stack: string
|
|
118
|
-
const filteredLines =
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}),
|
|
122
|
-
options,
|
|
123
|
-
);
|
|
103
|
+
export const parseFFOrSafariString = (stack: string): StackFrame[] => {
|
|
104
|
+
const filteredLines = stack.split("\n").filter((line) => {
|
|
105
|
+
return !line.match(SAFARI_NATIVE_CODE_REGEXP);
|
|
106
|
+
});
|
|
124
107
|
|
|
125
108
|
return filteredLines.map((line): StackFrame => {
|
|
126
109
|
let currentLine = line;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RendererDispatcherRef } from "../react-internals/index.js";
|
|
2
|
+
import { _renderers, getRDTHook } from "../rdt-hook.js";
|
|
3
|
+
|
|
4
|
+
export const getRendererDispatcherRefs = (): RendererDispatcherRef[] => {
|
|
5
|
+
const rdtHook = getRDTHook();
|
|
6
|
+
const renderers = new Set([..._renderers, ...rdtHook.renderers.values()]);
|
|
7
|
+
const currentDispatcherRefs: RendererDispatcherRef[] = [];
|
|
8
|
+
const seenCurrentDispatcherRefs = new Set<object>();
|
|
9
|
+
for (const renderer of renderers) {
|
|
10
|
+
const currentDispatcherRef = renderer.currentDispatcherRef;
|
|
11
|
+
if (!currentDispatcherRef || seenCurrentDispatcherRefs.has(currentDispatcherRef)) continue;
|
|
12
|
+
seenCurrentDispatcherRefs.add(currentDispatcherRef);
|
|
13
|
+
currentDispatcherRefs.push(currentDispatcherRef);
|
|
14
|
+
}
|
|
15
|
+
return currentDispatcherRefs;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const readDispatcher = (currentDispatcherRef: RendererDispatcherRef): unknown =>
|
|
19
|
+
"H" in currentDispatcherRef ? currentDispatcherRef.H : currentDispatcherRef.current;
|
|
20
|
+
|
|
21
|
+
export const writeDispatcher = (
|
|
22
|
+
currentDispatcherRef: RendererDispatcherRef,
|
|
23
|
+
dispatcher: unknown,
|
|
24
|
+
): void => {
|
|
25
|
+
if ("H" in currentDispatcherRef) {
|
|
26
|
+
currentDispatcherRef.H = dispatcher;
|
|
27
|
+
} else {
|
|
28
|
+
currentDispatcherRef.current = dispatcher;
|
|
29
|
+
}
|
|
30
|
+
};
|