bippy 0.6.1-dev.b88fcb4 → 0.6.1-dev.f9e6c65
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 +159 -487
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +8 -54
- package/dist/core.d.ts +8 -54
- package/dist/core.js +1 -1
- package/dist/core2.cjs +1 -1
- package/dist/core2.d.cts +3 -3
- package/dist/core2.d.ts +3 -3
- package/dist/core2.js +1 -1
- package/dist/errors.d.cts +2 -57
- package/dist/errors.d.ts +2 -57
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +1 -1
- package/dist/install-hook-only.cjs +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 +12 -13
- package/dist/source.d.cts +77 -78
- package/dist/source.d.ts +77 -78
- package/dist/source.js +12 -13
- package/package.json +6 -3
- package/src/core.ts +101 -530
- 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 +30 -43
- package/src/react-internals/generated/react-work-tags.ts +6 -2
- package/src/react-internals/index.ts +4 -4
- package/src/react-internals/semver.ts +2 -0
- package/src/react-internals/types.ts +0 -83
- package/src/react.ts +76 -0
- package/src/source/get-display-name-from-source.ts +44 -40
- package/src/source/get-source.ts +40 -24
- package/src/source/index.ts +2 -0
- package/src/source/inspect-hooks.ts +70 -91
- package/src/source/owner-stack.ts +60 -89
- 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 +312 -111
- package/dist/index.iife.js +0 -9
- package/dist/install-hook-only.iife.js +0 -9
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getDisplayName, getType, traverseFiber } from "../core.js";
|
|
2
|
-
import { _renderers, getRDTHook } from "../rdt-hook.js";
|
|
3
2
|
import { getReactWorkTagsForFiber } from "../react-internals/index.js";
|
|
4
3
|
import type {
|
|
5
4
|
Fiber,
|
|
@@ -7,14 +6,20 @@ import type {
|
|
|
7
6
|
ServerComponentInfo,
|
|
8
7
|
} from "../react-internals/index.js";
|
|
9
8
|
import {
|
|
9
|
+
REACT_STACK_BOTTOM_FRAME_PATTERNS,
|
|
10
10
|
SERVER_FRAME_MARKER,
|
|
11
11
|
SERVER_ENV_PATTERN,
|
|
12
12
|
SERVER_COMPONENT_URL_PREFIXES,
|
|
13
13
|
} from "./constants.js";
|
|
14
14
|
import { getPrepareStackTrace, setPrepareStackTrace } from "./error-stack.js";
|
|
15
15
|
import { parseDebugStack } from "./parse-debug-stack.js";
|
|
16
|
-
import { parseStack, StackFrame } from "./parse-stack.js";
|
|
17
|
-
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";
|
|
18
23
|
|
|
19
24
|
interface RendererDispatcherSnapshot {
|
|
20
25
|
currentDispatcherRef: RendererDispatcherRef;
|
|
@@ -32,9 +37,6 @@ export const hasDebugStack = (
|
|
|
32
37
|
const isFiberOwner = (owner: Fiber | ServerComponentInfo): owner is Fiber =>
|
|
33
38
|
"tag" in owner && typeof owner.tag === "number";
|
|
34
39
|
|
|
35
|
-
const getDebugOwner = (fiber: Fiber): Fiber | ServerComponentInfo | undefined =>
|
|
36
|
-
fiber._debugOwner ?? undefined;
|
|
37
|
-
|
|
38
40
|
/**
|
|
39
41
|
* Locates a frame inside the fiber's own function body without invoking it:
|
|
40
42
|
* any child fiber owned by this fiber was created by JSX inside its body, so
|
|
@@ -80,42 +82,18 @@ export const getDefinitionFrameFromOwnedChild = (fiber: Fiber): StackFrame | nul
|
|
|
80
82
|
return null;
|
|
81
83
|
};
|
|
82
84
|
|
|
83
|
-
const getRendererDispatcherRefs = (): RendererDispatcherRef[] => {
|
|
84
|
-
const rdtHook = getRDTHook();
|
|
85
|
-
const renderers = new Set([..._renderers, ...rdtHook.renderers.values()]);
|
|
86
|
-
const currentDispatcherRefs: RendererDispatcherRef[] = [];
|
|
87
|
-
const seenCurrentDispatcherRefs = new Set<object>();
|
|
88
|
-
for (const renderer of renderers) {
|
|
89
|
-
const currentDispatcherRef = renderer.currentDispatcherRef;
|
|
90
|
-
if (!currentDispatcherRef || seenCurrentDispatcherRefs.has(currentDispatcherRef)) continue;
|
|
91
|
-
seenCurrentDispatcherRefs.add(currentDispatcherRef);
|
|
92
|
-
currentDispatcherRefs.push(currentDispatcherRef);
|
|
93
|
-
}
|
|
94
|
-
return currentDispatcherRefs;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
85
|
const clearRendererDispatchers = (): RendererDispatcherSnapshot[] => {
|
|
98
86
|
const dispatcherSnapshots: RendererDispatcherSnapshot[] = [];
|
|
99
87
|
for (const currentDispatcherRef of getRendererDispatcherRefs()) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
dispatcherSnapshots.push({ currentDispatcherRef, value });
|
|
103
|
-
if ("H" in currentDispatcherRef) {
|
|
104
|
-
currentDispatcherRef.H = null;
|
|
105
|
-
} else {
|
|
106
|
-
currentDispatcherRef.current = null;
|
|
107
|
-
}
|
|
88
|
+
dispatcherSnapshots.push({ currentDispatcherRef, value: readDispatcher(currentDispatcherRef) });
|
|
89
|
+
writeDispatcher(currentDispatcherRef, null);
|
|
108
90
|
}
|
|
109
91
|
return dispatcherSnapshots;
|
|
110
92
|
};
|
|
111
93
|
|
|
112
94
|
const restoreRendererDispatchers = (dispatcherSnapshots: RendererDispatcherSnapshot[]): void => {
|
|
113
95
|
for (const { currentDispatcherRef, value } of dispatcherSnapshots) {
|
|
114
|
-
|
|
115
|
-
currentDispatcherRef.H = value;
|
|
116
|
-
} else {
|
|
117
|
-
currentDispatcherRef.current = value;
|
|
118
|
-
}
|
|
96
|
+
writeDispatcher(currentDispatcherRef, value);
|
|
119
97
|
}
|
|
120
98
|
};
|
|
121
99
|
|
|
@@ -294,6 +272,10 @@ const describeNativeComponentFrame = (
|
|
|
294
272
|
if (controlIndex < 0 || sampleLines[sampleIndex] !== controlLines[controlIndex]) {
|
|
295
273
|
// V8 adds a "new" prefix for native classes. Let's remove it to make it prettier.
|
|
296
274
|
let stackFrame = `\n${sampleLines[sampleIndex].replace(" at new ", " at ")}`;
|
|
275
|
+
const [parsedStackFrame] = parseStack(stackFrame);
|
|
276
|
+
if (!parsedStackFrame?.fileName) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
297
279
|
|
|
298
280
|
const displayName = getDisplayName(component);
|
|
299
281
|
// If our component frame is labeled "<anonymous>"
|
|
@@ -322,7 +304,7 @@ const describeNativeComponentFrame = (
|
|
|
322
304
|
console.warn = previousConsoleWarn;
|
|
323
305
|
}
|
|
324
306
|
|
|
325
|
-
const componentName =
|
|
307
|
+
const componentName = getDisplayName(component);
|
|
326
308
|
const syntheticFrame = componentName ? describeBuiltInComponentFrame(componentName) : "";
|
|
327
309
|
componentFrameCache.set(component, syntheticFrame);
|
|
328
310
|
return syntheticFrame;
|
|
@@ -344,7 +326,7 @@ export const describeFiber = (fiber: Fiber, childFiber: Fiber | null): string =>
|
|
|
344
326
|
break;
|
|
345
327
|
case workTags.FunctionComponent:
|
|
346
328
|
case workTags.SimpleMemoComponent:
|
|
347
|
-
stackFrame = describeNativeComponentFrame(fiber.type, false);
|
|
329
|
+
stackFrame = describeNativeComponentFrame(getType(fiber.type) ?? fiber.type, false);
|
|
348
330
|
break;
|
|
349
331
|
case workTags.HostComponent:
|
|
350
332
|
case workTags.HostHoistable:
|
|
@@ -411,7 +393,7 @@ export const getFallbackParentStack = (thisFiber: Fiber): string => {
|
|
|
411
393
|
return componentStack;
|
|
412
394
|
} catch (error) {
|
|
413
395
|
if (error instanceof Error) {
|
|
414
|
-
return `\
|
|
396
|
+
return `\nBippy couldn’t generate the stack: ${error.message}\n${error.stack}`;
|
|
415
397
|
}
|
|
416
398
|
return "";
|
|
417
399
|
}
|
|
@@ -452,8 +434,7 @@ export const formatOwnerStack = (stack: string): string => {
|
|
|
452
434
|
formattedStack = formattedStack.slice(firstNewlineIndex + 1);
|
|
453
435
|
}
|
|
454
436
|
let bottomFrameIndex = Math.max(
|
|
455
|
-
formattedStack.indexOf(
|
|
456
|
-
formattedStack.indexOf("react-stack-bottom-frame"),
|
|
437
|
+
...REACT_STACK_BOTTOM_FRAME_PATTERNS.map((pattern) => formattedStack.indexOf(pattern)),
|
|
457
438
|
);
|
|
458
439
|
if (bottomFrameIndex !== -1) {
|
|
459
440
|
bottomFrameIndex = formattedStack.lastIndexOf("\n", bottomFrameIndex);
|
|
@@ -470,11 +451,6 @@ export const formatOwnerStack = (stack: string): string => {
|
|
|
470
451
|
return formattedStack;
|
|
471
452
|
};
|
|
472
453
|
|
|
473
|
-
interface DebugStackEntry {
|
|
474
|
-
componentName: string;
|
|
475
|
-
stackFrames: StackFrame[];
|
|
476
|
-
}
|
|
477
|
-
|
|
478
454
|
const isReactServerComponentFrame = (stackFrame: StackFrame): boolean =>
|
|
479
455
|
Boolean(
|
|
480
456
|
stackFrame.functionName && stackFrame.fileName && isServerComponentUrl(stackFrame.fileName),
|
|
@@ -486,24 +462,22 @@ const areStackFramesEqual = (firstFrame: StackFrame, secondFrame: StackFrame): b
|
|
|
486
462
|
firstFrame.columnNumber === secondFrame.columnNumber;
|
|
487
463
|
|
|
488
464
|
const buildFunctionNameToRscFramesMap = (
|
|
489
|
-
|
|
465
|
+
debugStackFrames: StackFrame[],
|
|
490
466
|
): Map<string, StackFrame[]> => {
|
|
491
467
|
const functionNameToRscFrames = new Map<string, StackFrame[]>();
|
|
492
468
|
|
|
493
|
-
for (const
|
|
494
|
-
|
|
495
|
-
if (!isReactServerComponentFrame(stackFrame)) continue;
|
|
469
|
+
for (const stackFrame of debugStackFrames) {
|
|
470
|
+
if (!isReactServerComponentFrame(stackFrame)) continue;
|
|
496
471
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
472
|
+
const functionName = stackFrame.functionName!;
|
|
473
|
+
const framesForFunction = functionNameToRscFrames.get(functionName) ?? [];
|
|
474
|
+
const isDuplicateFrame = framesForFunction.some((existingFrame) =>
|
|
475
|
+
areStackFramesEqual(existingFrame, stackFrame),
|
|
476
|
+
);
|
|
502
477
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
}
|
|
478
|
+
if (!isDuplicateFrame) {
|
|
479
|
+
framesForFunction.push(stackFrame);
|
|
480
|
+
functionNameToRscFrames.set(functionName, framesForFunction);
|
|
507
481
|
}
|
|
508
482
|
}
|
|
509
483
|
|
|
@@ -564,7 +538,7 @@ const getOwnerStackFromDebugStacks = (fiber: Fiber): StackFrame[] => {
|
|
|
564
538
|
while (owner) {
|
|
565
539
|
if (isFiberOwner(owner)) {
|
|
566
540
|
const ownerFiber: Fiber = owner;
|
|
567
|
-
owner =
|
|
541
|
+
owner = ownerFiber._debugOwner;
|
|
568
542
|
if (owner && hasDebugStack(ownerFiber)) {
|
|
569
543
|
const { frames, isTrusted } = parseDebugStack(ownerFiber._debugStack);
|
|
570
544
|
if (isTrusted) {
|
|
@@ -588,53 +562,39 @@ const getOwnerStackFromDebugStacks = (fiber: Fiber): StackFrame[] => {
|
|
|
588
562
|
return ownerStackFrames;
|
|
589
563
|
};
|
|
590
564
|
|
|
591
|
-
const
|
|
592
|
-
const
|
|
565
|
+
const getDebugStackFrames = (rootFiber: Fiber): StackFrame[] => {
|
|
566
|
+
const debugStackFrames: StackFrame[] = [];
|
|
593
567
|
|
|
594
568
|
traverseFiber(
|
|
595
569
|
rootFiber,
|
|
596
570
|
(currentFiber) => {
|
|
597
571
|
if (!hasDebugStack(currentFiber)) return;
|
|
598
572
|
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
debugStackEntries.push({
|
|
605
|
-
componentName,
|
|
606
|
-
stackFrames: parseStack(formatOwnerStack(currentFiber._debugStack?.stack)),
|
|
607
|
-
});
|
|
573
|
+
const { frames, isTrusted } = parseDebugStack(currentFiber._debugStack);
|
|
574
|
+
if (isTrusted) {
|
|
575
|
+
debugStackFrames.push(...frames);
|
|
576
|
+
}
|
|
608
577
|
},
|
|
609
578
|
true,
|
|
610
579
|
);
|
|
611
580
|
|
|
612
|
-
return
|
|
581
|
+
return debugStackFrames;
|
|
613
582
|
};
|
|
614
583
|
|
|
615
584
|
/**
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
* with a throwing dispatcher; server frames are enriched from debug stacks by
|
|
620
|
-
* 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.
|
|
621
588
|
*/
|
|
622
|
-
export const
|
|
623
|
-
fiber
|
|
624
|
-
shouldCache = true,
|
|
625
|
-
fetchFunction?: (url: string) => Promise<Response>,
|
|
626
|
-
): Promise<StackFrame[]> => {
|
|
627
|
-
const debugStackEntries = getDebugStackEntries(fiber);
|
|
589
|
+
export const getRawParentStack = (fiber: Fiber): StackFrame[] => {
|
|
590
|
+
const debugStackFrames = getDebugStackFrames(fiber);
|
|
628
591
|
const fallbackStackFrames = parseStack(getFallbackParentStack(fiber));
|
|
629
|
-
const functionNameToRscFrames = buildFunctionNameToRscFramesMap(
|
|
592
|
+
const functionNameToRscFrames = buildFunctionNameToRscFramesMap(debugStackFrames);
|
|
630
593
|
const functionNameToUsageIndex = new Map<string, number>();
|
|
631
594
|
|
|
632
595
|
const enrichedStackFrames = fallbackStackFrames.map((stackFrame): StackFrame => {
|
|
633
596
|
const isServerFrame =
|
|
634
|
-
|
|
635
|
-
(stackFrame.source !== null &&
|
|
636
|
-
stackFrame.source !== undefined &&
|
|
637
|
-
SERVER_ENV_PATTERN.test(stackFrame.source));
|
|
597
|
+
stackFrame.source !== undefined && SERVER_ENV_PATTERN.test(stackFrame.source);
|
|
638
598
|
|
|
639
599
|
if (isServerFrame) {
|
|
640
600
|
return getEnrichedServerStackFrame(
|
|
@@ -647,15 +607,26 @@ export const getParentStack = async (
|
|
|
647
607
|
return stackFrame;
|
|
648
608
|
});
|
|
649
609
|
|
|
650
|
-
|
|
610
|
+
return enrichedStackFrames.filter((stackFrame, index, frames) => {
|
|
651
611
|
if (index === 0) return true;
|
|
652
612
|
const previousFrame = frames[index - 1];
|
|
653
613
|
return stackFrame.functionName !== previousFrame.functionName;
|
|
654
614
|
});
|
|
655
|
-
|
|
656
|
-
return symbolicateStack(deduplicatedStackFrames, shouldCache, fetchFunction);
|
|
657
615
|
};
|
|
658
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
|
+
|
|
659
630
|
// an owner frame is only actionable if it can point an editor somewhere:
|
|
660
631
|
// it needs a file location and must not be ignore-listed bundler/framework code
|
|
661
632
|
const isLocatableFrame = (stackFrame: StackFrame): boolean =>
|
|
@@ -674,7 +645,7 @@ const isLocatableFrame = (stackFrame: StackFrame): boolean =>
|
|
|
674
645
|
export const getOwnerStack = async (
|
|
675
646
|
fiber: Fiber,
|
|
676
647
|
shouldCache = true,
|
|
677
|
-
fetchFunction?:
|
|
648
|
+
fetchFunction?: SourceFetch,
|
|
678
649
|
): Promise<StackFrame[]> => {
|
|
679
650
|
const debugStackFrames = getOwnerStackFromDebugStacks(fiber);
|
|
680
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: Array<string | null> | 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
|
+
};
|