bippy 0.6.1-dev.d7876ea → 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/LICENSE +1 -1
- package/README.md +159 -487
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +24 -70
- package/dist/core.d.ts +24 -70
- 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 +141 -564
- 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,8 +1,29 @@
|
|
|
1
|
-
import { Fiber } from "../
|
|
1
|
+
import type { Fiber } from "../react-internals/index.js";
|
|
2
2
|
import { getDisplayName } from "../core.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import { getDefinitionFrameFromOwnedChild, getRawParentStack } from "./owner-stack.js";
|
|
4
|
+
import {
|
|
5
|
+
getSourceContentFromSourceMap,
|
|
6
|
+
getSourceFromSourceMap,
|
|
7
|
+
getSourceMap,
|
|
8
|
+
type SourceFetch,
|
|
9
|
+
} from "./symbolication.js";
|
|
10
|
+
import type { StackFrame } from "./parse-stack.js";
|
|
11
|
+
|
|
12
|
+
const COMPONENT_DECLARATION_PATTERNS = [
|
|
13
|
+
/(?:^|export\s+)(?:const|let|var)\s+(\w+)\s*=/,
|
|
14
|
+
/(?:^|export\s+)function\s+(\w+)/,
|
|
15
|
+
/(?:^|export\s+)class\s+(\w+)/,
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const findComponentDeclarationOnLine = (line: string): string | null => {
|
|
19
|
+
for (const pattern of COMPONENT_DECLARATION_PATTERNS) {
|
|
20
|
+
const match = line.match(pattern);
|
|
21
|
+
if (match?.[1]) return match[1];
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const MAX_DECLARATION_LINE_DISTANCE = 5;
|
|
6
27
|
|
|
7
28
|
const extractComponentNameFromSource = (
|
|
8
29
|
sourceContent: string,
|
|
@@ -15,27 +36,16 @@ const extractComponentNameFromSource = (
|
|
|
15
36
|
return null;
|
|
16
37
|
}
|
|
17
38
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return arrowMatch[1];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const functionMatch = contextLines.match(functionPattern);
|
|
32
|
-
if (functionMatch?.[1]) {
|
|
33
|
-
return functionMatch[1];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const classMatch = contextLines.match(classPattern);
|
|
37
|
-
if (classMatch?.[1]) {
|
|
38
|
-
return classMatch[1];
|
|
39
|
+
for (let lineDistance = 0; lineDistance <= MAX_DECLARATION_LINE_DISTANCE; lineDistance++) {
|
|
40
|
+
const lineIndexes =
|
|
41
|
+
lineDistance === 0
|
|
42
|
+
? [targetLineIndex]
|
|
43
|
+
: [targetLineIndex - lineDistance, targetLineIndex + lineDistance];
|
|
44
|
+
for (const lineIndex of lineIndexes) {
|
|
45
|
+
if (lineIndex < 0 || lineIndex >= lines.length) continue;
|
|
46
|
+
const declarationName = findComponentDeclarationOnLine(lines[lineIndex]);
|
|
47
|
+
if (declarationName) return declarationName;
|
|
48
|
+
}
|
|
39
49
|
}
|
|
40
50
|
|
|
41
51
|
return null;
|
|
@@ -44,10 +54,11 @@ const extractComponentNameFromSource = (
|
|
|
44
54
|
export const getDisplayNameFromSource = async (
|
|
45
55
|
fiber: Fiber,
|
|
46
56
|
cache = true,
|
|
47
|
-
fetchFn?:
|
|
57
|
+
fetchFn?: SourceFetch,
|
|
48
58
|
): Promise<string | null> => {
|
|
49
|
-
const
|
|
50
|
-
|
|
59
|
+
const stackFrame =
|
|
60
|
+
getDefinitionFrameFromOwnedChild(fiber) ??
|
|
61
|
+
getRawParentStack(fiber).find((innerFrame) => innerFrame.fileName);
|
|
51
62
|
|
|
52
63
|
if (!stackFrame?.fileName) {
|
|
53
64
|
return getDisplayName(fiber.type);
|
|
@@ -73,21 +84,14 @@ export const getDisplayNameFromSource = async (
|
|
|
73
84
|
return getDisplayName(fiber.type);
|
|
74
85
|
}
|
|
75
86
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const sourceIndex = bundleSourceMap.sources.indexOf(source.fileName);
|
|
81
|
-
if (sourceIndex === -1 || !bundleSourceMap.sourcesContent[sourceIndex]) {
|
|
82
|
-
return getDisplayName(fiber.type);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const sourceContent = bundleSourceMap.sourcesContent[sourceIndex];
|
|
86
|
-
const extractedName = extractComponentNameFromSource(sourceContent, source.lineNumber);
|
|
87
|
+
const sourceContent = getSourceContentFromSourceMap(bundleSourceMap, source.fileName);
|
|
88
|
+
const extractedName = sourceContent
|
|
89
|
+
? extractComponentNameFromSource(sourceContent, source.lineNumber)
|
|
90
|
+
: null;
|
|
87
91
|
|
|
88
92
|
if (extractedName) {
|
|
89
93
|
return extractedName;
|
|
90
94
|
}
|
|
91
95
|
|
|
92
|
-
return getDisplayName(fiber.type);
|
|
96
|
+
return source.functionName ?? getDisplayName(fiber.type);
|
|
93
97
|
};
|
package/src/source/get-source.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Fiber } from "../
|
|
1
|
+
import type { Fiber } from "../react-internals/index.js";
|
|
2
|
+
import { getDisplayName } from "../core.js";
|
|
2
3
|
|
|
3
|
-
import { FiberSource } from "./types.js";
|
|
4
|
+
import type { FiberSource } from "./types.js";
|
|
4
5
|
import {
|
|
5
6
|
SCHEME_REGEX,
|
|
6
7
|
INTERNAL_SCHEME_PREFIXES,
|
|
@@ -12,8 +13,13 @@ import {
|
|
|
12
13
|
} from "./constants.js";
|
|
13
14
|
import { getDefinitionFrameFromOwnedChild, getParentStack, hasDebugStack } from "./owner-stack.js";
|
|
14
15
|
import { parseDebugStack } from "./parse-debug-stack.js";
|
|
15
|
-
import { StackFrame } from "./parse-stack.js";
|
|
16
|
-
import {
|
|
16
|
+
import { parseStack, type StackFrame } from "./parse-stack.js";
|
|
17
|
+
import {
|
|
18
|
+
getSourceFromSourceMapByFunctionName,
|
|
19
|
+
getSourceMap,
|
|
20
|
+
symbolicateStack,
|
|
21
|
+
type SourceFetch,
|
|
22
|
+
} from "./symbolication.js";
|
|
17
23
|
|
|
18
24
|
export const hasDebugSource = (
|
|
19
25
|
fiber: Fiber,
|
|
@@ -26,10 +32,8 @@ export const hasDebugSource = (
|
|
|
26
32
|
}
|
|
27
33
|
return (
|
|
28
34
|
typeof debugSource === "object" &&
|
|
29
|
-
debugSource !== null &&
|
|
30
|
-
"fileName" in debugSource &&
|
|
31
35
|
typeof debugSource.fileName === "string" &&
|
|
32
|
-
"
|
|
36
|
+
debugSource.fileName !== "(native)" &&
|
|
33
37
|
typeof debugSource.lineNumber === "number"
|
|
34
38
|
);
|
|
35
39
|
};
|
|
@@ -63,6 +67,30 @@ const getUsageFrameFromDebugStack = (fiber: Fiber): StackFrame | null => {
|
|
|
63
67
|
return null;
|
|
64
68
|
};
|
|
65
69
|
|
|
70
|
+
const getSourceByComponentName = async (
|
|
71
|
+
fiber: Fiber,
|
|
72
|
+
cache: boolean,
|
|
73
|
+
fetchFn: SourceFetch | undefined,
|
|
74
|
+
): Promise<FiberSource | null> => {
|
|
75
|
+
const functionName = getDisplayName(fiber.type);
|
|
76
|
+
if (!functionName) return null;
|
|
77
|
+
|
|
78
|
+
const runtimeStackFrames = parseStack(new Error().stack ?? "");
|
|
79
|
+
const visitedFileNames = new Set<string>();
|
|
80
|
+
for (const stackFrame of runtimeStackFrames) {
|
|
81
|
+
const fileName = stackFrame.fileName;
|
|
82
|
+
if (!fileName || visitedFileNames.has(fileName)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
visitedFileNames.add(fileName);
|
|
86
|
+
const sourceMap = await getSourceMap(fileName, cache, fetchFn);
|
|
87
|
+
if (!sourceMap) continue;
|
|
88
|
+
const source = getSourceFromSourceMapByFunctionName(sourceMap, functionName);
|
|
89
|
+
if (source && !source.isIgnoreListed) return toFiberSource(source);
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
};
|
|
93
|
+
|
|
66
94
|
/**
|
|
67
95
|
* Returns the source of where the component is used. Available only in dev, for composite {@link Fiber}s.
|
|
68
96
|
*
|
|
@@ -92,11 +120,10 @@ const getUsageFrameFromDebugStack = (fiber: Fiber): StackFrame | null => {
|
|
|
92
120
|
export const getSource = async (
|
|
93
121
|
fiber: Fiber,
|
|
94
122
|
cache = true,
|
|
95
|
-
fetchFn?:
|
|
123
|
+
fetchFn?: SourceFetch,
|
|
96
124
|
): Promise<FiberSource | null> => {
|
|
97
125
|
if (hasDebugSource(fiber)) {
|
|
98
|
-
|
|
99
|
-
return debugSource || null;
|
|
126
|
+
return fiber._debugSource;
|
|
100
127
|
}
|
|
101
128
|
|
|
102
129
|
const debugStackFrame =
|
|
@@ -115,16 +142,11 @@ export const getSource = async (
|
|
|
115
142
|
return toFiberSource(stackFrame);
|
|
116
143
|
}
|
|
117
144
|
}
|
|
118
|
-
return
|
|
145
|
+
return getSourceByComponentName(fiber, cache, fetchFn);
|
|
119
146
|
};
|
|
120
147
|
|
|
121
148
|
const getPathSegmentCount = (path: string): number => path.split("/").filter(Boolean).length;
|
|
122
149
|
|
|
123
|
-
const getFirstPathSegment = (path: string): string | null => {
|
|
124
|
-
const segments = path.split("/").filter(Boolean);
|
|
125
|
-
return segments[0] ?? null;
|
|
126
|
-
};
|
|
127
|
-
|
|
128
150
|
const stripSingleBasePathPrefix = (path: string): string => {
|
|
129
151
|
const firstSlashIndex = path.indexOf("/", 1);
|
|
130
152
|
if (firstSlashIndex === -1) {
|
|
@@ -141,15 +163,12 @@ const stripSingleBasePathPrefix = (path: string): string => {
|
|
|
141
163
|
return path;
|
|
142
164
|
}
|
|
143
165
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const firstRemainderSegment = getFirstPathSegment(remainderPath);
|
|
149
|
-
if (!firstRemainderSegment) {
|
|
166
|
+
const remainderSegments = remainderPath.split("/").filter(Boolean);
|
|
167
|
+
if (remainderSegments.length < 2) {
|
|
150
168
|
return path;
|
|
151
169
|
}
|
|
152
170
|
|
|
171
|
+
const firstRemainderSegment = remainderSegments[0];
|
|
153
172
|
if (firstRemainderSegment.startsWith("@")) {
|
|
154
173
|
return path;
|
|
155
174
|
}
|
|
@@ -180,9 +199,6 @@ export const normalizeFileName = (fileName: string): string => {
|
|
|
180
199
|
const parsedUrl = new URL(normalizedFileName);
|
|
181
200
|
normalizedFileName = parsedUrl.pathname;
|
|
182
201
|
} catch {}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (isHttpUrl) {
|
|
186
202
|
normalizedFileName = stripSingleBasePathPrefix(normalizedFileName);
|
|
187
203
|
}
|
|
188
204
|
|
|
@@ -215,7 +231,7 @@ export const normalizeFileName = (fileName: string): string => {
|
|
|
215
231
|
}
|
|
216
232
|
}
|
|
217
233
|
|
|
218
|
-
if (!isWindowsDrivePath
|
|
234
|
+
if (!isWindowsDrivePath) {
|
|
219
235
|
const schemeMatch = normalizedFileName.match(SCHEME_REGEX);
|
|
220
236
|
if (schemeMatch) {
|
|
221
237
|
normalizedFileName = normalizedFileName.slice(schemeMatch[0].length);
|
package/src/source/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { formatOwnerStack, getOwnerStack, getParentStack, hasDebugStack } from "./owner-stack.js";
|
|
2
2
|
export { getSource, isSourceFile, normalizeFileName } from "./get-source.js";
|
|
3
3
|
export {
|
|
4
|
+
getSourceContentFromSourceMap,
|
|
4
5
|
getSourceFromSourceMap,
|
|
6
|
+
getSourceFromSourceMapByFunctionName,
|
|
5
7
|
getSourceMap,
|
|
6
8
|
symbolicateStack,
|
|
7
9
|
type DecodedSourceMapSection,
|
|
@@ -4,15 +4,19 @@ import type {
|
|
|
4
4
|
MemoizedState,
|
|
5
5
|
ReactContext,
|
|
6
6
|
RendererDispatcherRef,
|
|
7
|
-
} from "../
|
|
7
|
+
} from "../react-internals/index.js";
|
|
8
8
|
import {
|
|
9
9
|
BippyHookInspectionError,
|
|
10
10
|
BippyHookRenderError,
|
|
11
11
|
BippyUnsupportedHookError,
|
|
12
12
|
} from "../errors.js";
|
|
13
|
-
import { getReactWorkTagsForFiber } from "../react-internals.js";
|
|
13
|
+
import { getReactWorkTagsForFiber } from "../react-internals/index.js";
|
|
14
14
|
import { parseStack, type StackFrame } from "./parse-stack.js";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
getRendererDispatcherRefs,
|
|
17
|
+
readDispatcher,
|
|
18
|
+
writeDispatcher,
|
|
19
|
+
} from "./renderer-dispatchers.js";
|
|
16
20
|
|
|
17
21
|
const REACT_CONTEXT_TYPE = Symbol.for("react.context");
|
|
18
22
|
const REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel");
|
|
@@ -77,7 +81,7 @@ let currentThenableIndex = 0;
|
|
|
77
81
|
let currentThenableState: unknown[] | null = null;
|
|
78
82
|
|
|
79
83
|
const SuspenseException: unknown = new Error(
|
|
80
|
-
"Suspense
|
|
84
|
+
"Suspense interrupted this render. This error is an internal implementation detail of `use`.",
|
|
81
85
|
);
|
|
82
86
|
|
|
83
87
|
const parseErrorStack = (error: Error): StackFrame[] =>
|
|
@@ -89,28 +93,31 @@ const nextHook = (): MemoizedState | null => {
|
|
|
89
93
|
return hook;
|
|
90
94
|
};
|
|
91
95
|
|
|
92
|
-
const isObjectRecord = (value: unknown): value is Record<string, unknown> =>
|
|
93
|
-
typeof value === "object" && value !== null;
|
|
94
|
-
|
|
95
96
|
const isInspectableThenable = (value: unknown): value is InspectableThenable =>
|
|
96
|
-
|
|
97
|
+
typeof value === "object" &&
|
|
98
|
+
value !== null &&
|
|
99
|
+
"then" in value &&
|
|
100
|
+
typeof value.then === "function";
|
|
97
101
|
|
|
98
102
|
const isInspectableRef = (value: unknown): value is InspectableRef =>
|
|
99
|
-
|
|
103
|
+
typeof value === "object" && value !== null && "current" in value;
|
|
100
104
|
|
|
101
105
|
const isReactContext = (value: unknown): value is ReactContext<unknown> =>
|
|
102
|
-
|
|
106
|
+
typeof value === "object" && value !== null && "_currentValue" in value;
|
|
103
107
|
|
|
104
108
|
const isContextDependency = (value: unknown): value is ContextDependency<unknown> =>
|
|
105
|
-
|
|
109
|
+
typeof value === "object" && value !== null && "context" in value && "next" in value;
|
|
106
110
|
|
|
107
111
|
const isForwardRefRenderType = (value: unknown): value is ForwardRefRenderType =>
|
|
108
|
-
|
|
112
|
+
typeof value === "object" &&
|
|
113
|
+
value !== null &&
|
|
114
|
+
"render" in value &&
|
|
115
|
+
typeof value.render === "function";
|
|
109
116
|
|
|
110
117
|
const readContext = (context: InspectableReactContext): unknown => {
|
|
111
118
|
if (currentFiber === null) return context._currentValue;
|
|
112
119
|
if (currentContextDependency === null) {
|
|
113
|
-
throw new BippyHookInspectionError("Context reads
|
|
120
|
+
throw new BippyHookInspectionError("Context reads don’t match context dependencies.");
|
|
114
121
|
}
|
|
115
122
|
if (Object.hasOwn(currentContextDependency, "memoizedValue")) {
|
|
116
123
|
const value = currentContextDependency.memoizedValue;
|
|
@@ -120,27 +127,6 @@ const readContext = (context: InspectableReactContext): unknown => {
|
|
|
120
127
|
return context._currentValue;
|
|
121
128
|
};
|
|
122
129
|
|
|
123
|
-
const getDispatcherRef = (): RendererDispatcherRef | null => {
|
|
124
|
-
const rdtHook = getRDTHook();
|
|
125
|
-
const allRenderers = [..._renderers, ...rdtHook.renderers.values()];
|
|
126
|
-
for (const renderer of allRenderers) {
|
|
127
|
-
const ref = renderer.currentDispatcherRef;
|
|
128
|
-
if (ref) return ref;
|
|
129
|
-
}
|
|
130
|
-
return null;
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const getDispatcherFromRef = (ref: RendererDispatcherRef): unknown =>
|
|
134
|
-
"H" in ref ? ref.H : ref.current;
|
|
135
|
-
|
|
136
|
-
const setDispatcherOnRef = (ref: RendererDispatcherRef, dispatcher: unknown): void => {
|
|
137
|
-
if ("H" in ref) {
|
|
138
|
-
ref.H = dispatcher;
|
|
139
|
-
} else {
|
|
140
|
-
ref.current = dispatcher;
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
|
|
144
130
|
const pushHookLogEntry = (
|
|
145
131
|
primitive: string,
|
|
146
132
|
value: unknown,
|
|
@@ -157,7 +143,7 @@ const pushHookLogEntry = (
|
|
|
157
143
|
};
|
|
158
144
|
|
|
159
145
|
const dispatcherUse = (usable: unknown): unknown => {
|
|
160
|
-
if (
|
|
146
|
+
if (typeof usable === "object" && usable !== null) {
|
|
161
147
|
if (isInspectableThenable(usable)) {
|
|
162
148
|
const cachedThenable =
|
|
163
149
|
currentThenableState !== null && currentThenableIndex < currentThenableState.length
|
|
@@ -176,7 +162,7 @@ const dispatcherUse = (usable: unknown): unknown => {
|
|
|
176
162
|
pushHookLogEntry("Unresolved", thenable, "Use");
|
|
177
163
|
throw SuspenseException;
|
|
178
164
|
}
|
|
179
|
-
if (usable.$$typeof === REACT_CONTEXT_TYPE &&
|
|
165
|
+
if ("$$typeof" in usable && usable.$$typeof === REACT_CONTEXT_TYPE && isReactContext(usable)) {
|
|
180
166
|
const context: InspectableReactContext = {
|
|
181
167
|
_currentValue: usable._currentValue,
|
|
182
168
|
displayName: typeof usable.displayName === "string" ? usable.displayName : undefined,
|
|
@@ -186,7 +172,7 @@ const dispatcherUse = (usable: unknown): unknown => {
|
|
|
186
172
|
return value;
|
|
187
173
|
}
|
|
188
174
|
}
|
|
189
|
-
throw new BippyHookInspectionError("
|
|
175
|
+
throw new BippyHookInspectionError("use() received an unsupported value: " + String(usable));
|
|
190
176
|
};
|
|
191
177
|
|
|
192
178
|
const dispatcherUseContext = (context: InspectableReactContext): unknown => {
|
|
@@ -251,10 +237,7 @@ const dispatcherUseEffect = (create: () => void): void => {
|
|
|
251
237
|
|
|
252
238
|
const dispatcherUseImperativeHandle = (ref: unknown): void => {
|
|
253
239
|
nextHook();
|
|
254
|
-
|
|
255
|
-
if (ref !== null && typeof ref === "object" && "current" in ref) {
|
|
256
|
-
instance = ref.current;
|
|
257
|
-
}
|
|
240
|
+
const instance = isInspectableRef(ref) ? ref.current : undefined;
|
|
258
241
|
pushHookLogEntry("ImperativeHandle", instance, "ImperativeHandle");
|
|
259
242
|
};
|
|
260
243
|
|
|
@@ -380,15 +363,8 @@ const createActionStateDispatcher =
|
|
|
380
363
|
const hook = nextHook();
|
|
381
364
|
nextHook();
|
|
382
365
|
nextHook();
|
|
383
|
-
const stackError = new Error();
|
|
384
366
|
const { value, error } = inspectActionStateHook(hook, initialState);
|
|
385
|
-
|
|
386
|
-
displayName: null,
|
|
387
|
-
primitive,
|
|
388
|
-
stackError,
|
|
389
|
-
value,
|
|
390
|
-
dispatcherHookName: primitive,
|
|
391
|
-
});
|
|
367
|
+
pushHookLogEntry(primitive, value, primitive);
|
|
392
368
|
if (error !== null) throw error;
|
|
393
369
|
return [value, () => {}, false];
|
|
394
370
|
};
|
|
@@ -436,15 +412,12 @@ const dispatcher = {
|
|
|
436
412
|
useEffectEvent: dispatcherUseEffectEvent,
|
|
437
413
|
};
|
|
438
414
|
|
|
439
|
-
const dispatcherProxy =
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
throw new BippyUnsupportedHookError("Missing method in Dispatcher: " + propertyName);
|
|
446
|
-
},
|
|
447
|
-
});
|
|
415
|
+
const dispatcherProxy = new Proxy(dispatcher, {
|
|
416
|
+
get(target, propertyName: string) {
|
|
417
|
+
if (Object.hasOwn(target, propertyName)) return Reflect.get(target, propertyName);
|
|
418
|
+
throw new BippyUnsupportedHookError("The React dispatcher is missing method " + propertyName);
|
|
419
|
+
},
|
|
420
|
+
});
|
|
448
421
|
|
|
449
422
|
const getPrimitiveStackCache = (): Map<string, StackFrame[]> => {
|
|
450
423
|
if (primitiveStackCache !== null) return primitiveStackCache;
|
|
@@ -457,38 +430,34 @@ const getPrimitiveStackCache = (): Map<string, StackFrame[]> => {
|
|
|
457
430
|
dispatcher.useState(null);
|
|
458
431
|
dispatcher.useReducer((state: unknown) => state, null);
|
|
459
432
|
dispatcher.useRef(null);
|
|
460
|
-
|
|
433
|
+
dispatcher.useCacheRefresh();
|
|
461
434
|
dispatcher.useLayoutEffect(() => {});
|
|
462
435
|
dispatcher.useInsertionEffect(() => {});
|
|
463
436
|
dispatcher.useEffect(() => {});
|
|
464
|
-
dispatcher.useImperativeHandle(undefined
|
|
437
|
+
dispatcher.useImperativeHandle(undefined);
|
|
465
438
|
dispatcher.useDebugValue(null);
|
|
466
439
|
dispatcher.useCallback(() => {});
|
|
467
440
|
dispatcher.useTransition();
|
|
468
441
|
dispatcher.useSyncExternalStore(
|
|
469
442
|
() => () => {},
|
|
470
443
|
() => null,
|
|
471
|
-
() => null,
|
|
472
444
|
);
|
|
473
445
|
dispatcher.useDeferredValue(null);
|
|
474
446
|
dispatcher.useMemo(() => null);
|
|
475
|
-
dispatcher.useOptimistic(null
|
|
447
|
+
dispatcher.useOptimistic(null);
|
|
476
448
|
dispatcher.useFormState((state: unknown) => state, null);
|
|
477
449
|
dispatcher.useActionState((state: unknown) => state, null);
|
|
478
450
|
dispatcher.useHostTransitionStatus();
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
dispatcher.use(
|
|
486
|
-
|
|
487
|
-
dispatcher.use(new Promise<never>(() => {}));
|
|
488
|
-
} catch {}
|
|
489
|
-
}
|
|
451
|
+
dispatcher.use({ $$typeof: REACT_CONTEXT_TYPE, _currentValue: null });
|
|
452
|
+
const fulfilledPromise = Promise.resolve(null);
|
|
453
|
+
Reflect.set(fulfilledPromise, "status", "fulfilled");
|
|
454
|
+
Reflect.set(fulfilledPromise, "value", null);
|
|
455
|
+
dispatcher.use(fulfilledPromise);
|
|
456
|
+
try {
|
|
457
|
+
dispatcher.use(new Promise<never>(() => {}));
|
|
458
|
+
} catch {}
|
|
490
459
|
dispatcher.useId();
|
|
491
|
-
|
|
460
|
+
dispatcher.useEffectEvent(() => {});
|
|
492
461
|
} finally {
|
|
493
462
|
capturedHookLog = hookLog;
|
|
494
463
|
hookLog = [];
|
|
@@ -719,7 +688,10 @@ const setupContexts = (contextMap: Map<ReactContext<unknown>, unknown>, fiber: F
|
|
|
719
688
|
while (current) {
|
|
720
689
|
if (current.tag === getReactWorkTagsForFiber(current).ContextProvider) {
|
|
721
690
|
const providerType = current.type;
|
|
722
|
-
const nestedContext =
|
|
691
|
+
const nestedContext =
|
|
692
|
+
typeof providerType === "object" && providerType !== null && "_context" in providerType
|
|
693
|
+
? providerType._context
|
|
694
|
+
: undefined;
|
|
723
695
|
const context = isReactContext(nestedContext)
|
|
724
696
|
? nestedContext
|
|
725
697
|
: isReactContext(providerType)
|
|
@@ -743,7 +715,7 @@ const restoreContexts = (contextMap: Map<ReactContext<unknown>, unknown>): void
|
|
|
743
715
|
const handleRenderFunctionError = (error: unknown): void => {
|
|
744
716
|
if (error === SuspenseException) return;
|
|
745
717
|
if (error instanceof BippyUnsupportedHookError) throw error;
|
|
746
|
-
throw new BippyHookRenderError("
|
|
718
|
+
throw new BippyHookRenderError("Bippy couldn’t render the inspected component", error);
|
|
747
719
|
};
|
|
748
720
|
|
|
749
721
|
const resolveDefaultProps = (
|
|
@@ -754,13 +726,14 @@ const resolveDefaultProps = (
|
|
|
754
726
|
component &&
|
|
755
727
|
typeof component === "object" &&
|
|
756
728
|
"defaultProps" in component &&
|
|
757
|
-
|
|
729
|
+
typeof component.defaultProps === "object" &&
|
|
730
|
+
component.defaultProps !== null
|
|
758
731
|
) {
|
|
759
732
|
const props = { ...baseProps };
|
|
760
733
|
const defaultProps = component.defaultProps;
|
|
761
|
-
for (const propName
|
|
734
|
+
for (const [propName, value] of Object.entries(defaultProps)) {
|
|
762
735
|
if (props[propName] === undefined) {
|
|
763
|
-
props[propName] =
|
|
736
|
+
props[propName] = value;
|
|
764
737
|
}
|
|
765
738
|
}
|
|
766
739
|
return props;
|
|
@@ -791,8 +764,8 @@ const performDispatcherInspection = (
|
|
|
791
764
|
dispatcherRef: RendererDispatcherRef,
|
|
792
765
|
renderFn: () => void,
|
|
793
766
|
): HooksTree => {
|
|
794
|
-
const previousDispatcher =
|
|
795
|
-
|
|
767
|
+
const previousDispatcher = readDispatcher(dispatcherRef);
|
|
768
|
+
writeDispatcher(dispatcherRef, dispatcherProxy);
|
|
796
769
|
|
|
797
770
|
let capturedHookLog: HookLogEntry[] = [];
|
|
798
771
|
let ancestorStackError: Error | undefined;
|
|
@@ -805,7 +778,7 @@ const performDispatcherInspection = (
|
|
|
805
778
|
} finally {
|
|
806
779
|
capturedHookLog = hookLog;
|
|
807
780
|
hookLog = [];
|
|
808
|
-
|
|
781
|
+
writeDispatcher(dispatcherRef, previousDispatcher);
|
|
809
782
|
}
|
|
810
783
|
|
|
811
784
|
const rootStack = ancestorStackError !== undefined ? parseErrorStack(ancestorStackError) : [];
|
|
@@ -813,33 +786,40 @@ const performDispatcherInspection = (
|
|
|
813
786
|
};
|
|
814
787
|
|
|
815
788
|
const requireDispatcherRef = (): RendererDispatcherRef => {
|
|
816
|
-
const dispatcherRef =
|
|
789
|
+
const dispatcherRef = getRendererDispatcherRefs()[0];
|
|
817
790
|
if (!dispatcherRef) {
|
|
818
791
|
throw new BippyHookInspectionError(
|
|
819
|
-
"
|
|
792
|
+
"Bippy couldn’t find a React renderer. Load React and install Bippy’s hook.",
|
|
820
793
|
);
|
|
821
794
|
}
|
|
822
795
|
return dispatcherRef;
|
|
823
796
|
};
|
|
824
797
|
|
|
825
798
|
const resolveContextDependency = (fiber: Fiber): void => {
|
|
799
|
+
const legacyDependenciesKey = ["dependencies_old", "dependencies_new"].find((key) =>
|
|
800
|
+
Object.hasOwn(fiber, key),
|
|
801
|
+
);
|
|
826
802
|
if (Object.hasOwn(fiber, "dependencies")) {
|
|
827
803
|
const dependencies = fiber.dependencies;
|
|
828
804
|
currentContextDependency = dependencies !== null ? dependencies.firstContext : null;
|
|
829
|
-
} else if (
|
|
830
|
-
const dependencies: unknown = Reflect.get(fiber,
|
|
831
|
-
const firstContext =
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
const firstContext = isObjectRecord(dependencies) ? dependencies.firstContext : null;
|
|
805
|
+
} else if (legacyDependenciesKey) {
|
|
806
|
+
const dependencies: unknown = Reflect.get(fiber, legacyDependenciesKey);
|
|
807
|
+
const firstContext =
|
|
808
|
+
typeof dependencies === "object" && dependencies !== null && "firstContext" in dependencies
|
|
809
|
+
? dependencies.firstContext
|
|
810
|
+
: null;
|
|
836
811
|
currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
|
|
837
812
|
} else if (Object.hasOwn(fiber, "contextDependencies")) {
|
|
838
813
|
const contextDependencies: unknown = Reflect.get(fiber, "contextDependencies");
|
|
839
|
-
const firstContext =
|
|
814
|
+
const firstContext =
|
|
815
|
+
typeof contextDependencies === "object" &&
|
|
816
|
+
contextDependencies !== null &&
|
|
817
|
+
"first" in contextDependencies
|
|
818
|
+
? contextDependencies.first
|
|
819
|
+
: null;
|
|
840
820
|
currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
|
|
841
821
|
} else {
|
|
842
|
-
throw new BippyHookInspectionError("
|
|
822
|
+
throw new BippyHookInspectionError("Bippy doesn’t support this React version.");
|
|
843
823
|
}
|
|
844
824
|
};
|
|
845
825
|
|
|
@@ -852,9 +832,7 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
|
|
|
852
832
|
fiber.tag !== workTags.SimpleMemoComponent &&
|
|
853
833
|
fiber.tag !== workTags.ForwardRef
|
|
854
834
|
) {
|
|
855
|
-
throw new BippyHookInspectionError(
|
|
856
|
-
"Unknown Fiber. Needs to be a function component to inspect hooks.",
|
|
857
|
-
);
|
|
835
|
+
throw new BippyHookInspectionError("Hook inspection requires a function component Fiber.");
|
|
858
836
|
}
|
|
859
837
|
|
|
860
838
|
getPrimitiveStackCache();
|