bippy 0.6.1-dev.3a24abf → 0.6.1-dev.d7876ea
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 +7 -1
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +22 -24
- package/dist/core.d.ts +22 -24
- 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/{types.d.cts → errors.d.cts} +174 -29
- package/dist/{types.d.ts → errors.d.ts} +174 -29
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.iife.js +1 -1
- package/dist/index.js +1 -1
- package/dist/install-hook-only.iife.js +1 -1
- package/dist/rdt-hook.cjs +1 -1
- package/dist/rdt-hook.js +1 -1
- package/dist/source.cjs +13 -13
- package/dist/source.d.cts +18 -9
- package/dist/source.d.ts +18 -9
- package/dist/source.js +13 -13
- package/package.json +9 -5
- package/src/core.ts +195 -156
- package/src/errors.ts +99 -0
- package/src/generated/react-work-tags.d.ts +261 -0
- package/src/generated/react-work-tags.js +240 -0
- package/src/rdt-hook.ts +144 -96
- package/src/react-internals.ts +43 -45
- package/src/semver.ts +78 -0
- package/src/source/error-stack.ts +11 -0
- package/src/source/index.ts +9 -1
- package/src/source/inspect-hooks.ts +199 -164
- package/src/source/owner-stack.ts +21 -38
- package/src/source/parse-debug-stack.ts +4 -4
- package/src/source/symbolication.ts +358 -103
- package/src/types.ts +12 -2
- package/src/generated/react-work-tags.ts +0 -169
package/src/rdt-hook.ts
CHANGED
|
@@ -1,23 +1,43 @@
|
|
|
1
1
|
// This module must load before React so renderers can inject into the hook.
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
BippyHookInstallationError,
|
|
5
|
+
BippyHookListenerError,
|
|
6
|
+
BippyReactBuildError,
|
|
7
|
+
runWithBippyError,
|
|
8
|
+
} from "./errors.js";
|
|
3
9
|
import type { ReactDevToolsGlobalHook, ReactRenderer } from "./types.js";
|
|
4
10
|
import { toUnsubscribe, type Unsubscribe } from "./unsubscribe.js";
|
|
5
11
|
|
|
12
|
+
interface ActiveListener {
|
|
13
|
+
(): unknown;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface RendererInjectListener {
|
|
17
|
+
(renderer: ReactRenderer): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface RDTHookReplaceListener {
|
|
21
|
+
(rdtHook: ReactDevToolsGlobalHook): void;
|
|
22
|
+
}
|
|
23
|
+
|
|
6
24
|
export const version = process.env.VERSION;
|
|
7
25
|
export const BIPPY_INSTRUMENTATION_STRING = `bippy-${version}`;
|
|
8
26
|
|
|
9
27
|
const objectDefineProperty = Object.defineProperty;
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
11
|
-
const objectHasOwnProperty = Object.prototype.hasOwnProperty;
|
|
12
28
|
|
|
13
|
-
const
|
|
29
|
+
const noOp = (): void => {};
|
|
30
|
+
|
|
31
|
+
const runHookListener = (listenerName: string, callback: () => unknown): void =>
|
|
32
|
+
runWithBippyError(callback, (cause) => new BippyHookListenerError(listenerName, cause));
|
|
14
33
|
|
|
15
34
|
const checkDCE = (functionToCheck: unknown): void => {
|
|
16
35
|
try {
|
|
17
36
|
const code = Function.prototype.toString.call(functionToCheck);
|
|
18
37
|
if (code.includes("^_^")) {
|
|
38
|
+
// HACK: React DevTools reports failed dead-code elimination asynchronously.
|
|
19
39
|
setTimeout(() => {
|
|
20
|
-
throw new
|
|
40
|
+
throw new BippyReactBuildError(
|
|
21
41
|
"React is running in production mode, but dead code " +
|
|
22
42
|
"elimination has not been applied. Read how to correctly " +
|
|
23
43
|
"configure React for production: " +
|
|
@@ -34,49 +54,75 @@ export const isRealReactDevtools = (
|
|
|
34
54
|
return Boolean(rdtHook && "getFiberRoots" in rdtHook);
|
|
35
55
|
};
|
|
36
56
|
|
|
37
|
-
export const _onActiveListeners = new Set<
|
|
57
|
+
export const _onActiveListeners = new Set<ActiveListener>();
|
|
38
58
|
|
|
39
59
|
export const _renderers = new Set<ReactRenderer>();
|
|
40
60
|
|
|
41
|
-
const rendererInjectListeners = new Set<
|
|
61
|
+
const rendererInjectListeners = new Set<RendererInjectListener>();
|
|
62
|
+
const rdtHookReplaceListeners = new Set<RDTHookReplaceListener>();
|
|
42
63
|
// HACK: Hook replacement can leave an old inject wrapper in the call chain, so notifications must be deduplicated.
|
|
43
64
|
const notifiedRenderers = new WeakSet<ReactRenderer>();
|
|
44
|
-
|
|
65
|
+
const notifyingInjectByHook = new WeakMap<
|
|
66
|
+
ReactDevToolsGlobalHook,
|
|
67
|
+
ReactDevToolsGlobalHook["inject"]
|
|
68
|
+
>();
|
|
69
|
+
|
|
70
|
+
const notifyActiveListeners = (): void => {
|
|
71
|
+
for (const listener of _onActiveListeners) {
|
|
72
|
+
runHookListener("onActive", listener);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const notifyRendererInjectListeners = (renderer: ReactRenderer): void => {
|
|
77
|
+
for (const listener of rendererInjectListeners) {
|
|
78
|
+
runHookListener("onRendererInject", () => listener(renderer));
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const notifyRDTHookReplaceListeners = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
83
|
+
for (const listener of rdtHookReplaceListeners) {
|
|
84
|
+
runHookListener("onRDTHookReplace", () => listener(rdtHook));
|
|
85
|
+
}
|
|
86
|
+
};
|
|
45
87
|
|
|
46
|
-
const
|
|
47
|
-
if (rdtHook.inject ===
|
|
48
|
-
const
|
|
88
|
+
const setRendererInjectDispatcher = (rdtHook: ReactDevToolsGlobalHook): void => {
|
|
89
|
+
if (rdtHook.inject === notifyingInjectByHook.get(rdtHook)) return;
|
|
90
|
+
const previousInject = rdtHook.inject;
|
|
49
91
|
const nextInject = (renderer: ReactRenderer) => {
|
|
50
|
-
const rendererId =
|
|
92
|
+
const rendererId = previousInject.call(rdtHook, renderer);
|
|
51
93
|
if (!notifiedRenderers.has(renderer)) {
|
|
52
94
|
notifiedRenderers.add(renderer);
|
|
53
|
-
|
|
54
|
-
listener(renderer);
|
|
55
|
-
}
|
|
95
|
+
notifyRendererInjectListeners(renderer);
|
|
56
96
|
}
|
|
57
97
|
return rendererId;
|
|
58
98
|
};
|
|
59
99
|
rdtHook.inject = nextInject;
|
|
60
|
-
|
|
100
|
+
notifyingInjectByHook.set(rdtHook, nextInject);
|
|
61
101
|
};
|
|
62
102
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
ensureInjectNotifiesListeners(getRDTHook());
|
|
103
|
+
export const onRendererInject = (listener: RendererInjectListener): Unsubscribe => {
|
|
104
|
+
setRendererInjectDispatcher(getRDTHook());
|
|
66
105
|
rendererInjectListeners.add(listener);
|
|
67
106
|
return toUnsubscribe(() => {
|
|
68
107
|
rendererInjectListeners.delete(listener);
|
|
69
108
|
});
|
|
70
109
|
};
|
|
71
110
|
|
|
72
|
-
const
|
|
111
|
+
export const onRDTHookReplace = (listener: RDTHookReplaceListener): Unsubscribe => {
|
|
112
|
+
rdtHookReplaceListeners.add(listener);
|
|
113
|
+
return toUnsubscribe(() => {
|
|
114
|
+
rdtHookReplaceListeners.delete(listener);
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const getRendererMap = (rdtHook: ReactDevToolsGlobalHook): Map<number, ReactRenderer> => {
|
|
73
119
|
if (!(rdtHook.renderers instanceof Map)) {
|
|
74
120
|
rdtHook.renderers = new Map();
|
|
75
121
|
}
|
|
76
122
|
return rdtHook.renderers;
|
|
77
123
|
};
|
|
78
124
|
|
|
79
|
-
export const installRDTHook = (onActive?:
|
|
125
|
+
export const installRDTHook = (onActive?: ActiveListener): ReactDevToolsGlobalHook => {
|
|
80
126
|
if (onActive) {
|
|
81
127
|
_onActiveListeners.add(onActive);
|
|
82
128
|
}
|
|
@@ -87,20 +133,20 @@ export const installRDTHook = (onActive?: () => unknown): ReactDevToolsGlobalHoo
|
|
|
87
133
|
_instrumentationSource: BIPPY_INSTRUMENTATION_STRING,
|
|
88
134
|
checkDCE,
|
|
89
135
|
hasUnsupportedRendererAttached: false,
|
|
90
|
-
inject(renderer) {
|
|
136
|
+
inject: (renderer) => {
|
|
91
137
|
const nextRendererId = ++rendererIdCounter;
|
|
92
138
|
renderers.set(nextRendererId, renderer);
|
|
93
139
|
_renderers.add(renderer);
|
|
94
140
|
if (!rdtHook._instrumentationIsActive) {
|
|
95
141
|
rdtHook._instrumentationIsActive = true;
|
|
96
|
-
|
|
142
|
+
notifyActiveListeners();
|
|
97
143
|
}
|
|
98
144
|
return nextRendererId;
|
|
99
145
|
},
|
|
100
|
-
on:
|
|
101
|
-
onCommitFiberRoot:
|
|
102
|
-
onCommitFiberUnmount:
|
|
103
|
-
onPostCommitFiberRoot:
|
|
146
|
+
on: noOp,
|
|
147
|
+
onCommitFiberRoot: noOp,
|
|
148
|
+
onCommitFiberUnmount: noOp,
|
|
149
|
+
onPostCommitFiberRoot: noOp,
|
|
104
150
|
renderers,
|
|
105
151
|
supportsFiber: true,
|
|
106
152
|
supportsFlight: true,
|
|
@@ -116,92 +162,106 @@ export const installRDTHook = (onActive?: () => unknown): ReactDevToolsGlobalHoo
|
|
|
116
162
|
if (newHook && typeof newHook === "object") {
|
|
117
163
|
const ourRenderers = rdtHook.renderers;
|
|
118
164
|
rdtHook = newHook;
|
|
119
|
-
const nextRenderers =
|
|
165
|
+
const nextRenderers = getRendererMap(rdtHook);
|
|
120
166
|
if (ourRenderers.size > 0) {
|
|
121
|
-
ourRenderers.forEach((renderer,
|
|
167
|
+
ourRenderers.forEach((renderer, rendererId) => {
|
|
122
168
|
_renderers.add(renderer);
|
|
123
|
-
nextRenderers.set(
|
|
169
|
+
nextRenderers.set(rendererId, renderer);
|
|
124
170
|
});
|
|
171
|
+
}
|
|
172
|
+
if (ourRenderers.size > 0 || rdtHookReplaceListeners.size > 0) {
|
|
125
173
|
patchRDTHook(onActive);
|
|
126
174
|
}
|
|
175
|
+
notifyRDTHookReplaceListeners(rdtHook);
|
|
127
176
|
}
|
|
128
177
|
},
|
|
129
178
|
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
179
|
+
if (typeof window !== "undefined") {
|
|
180
|
+
// HACK: The DevTools extension uses hasOwnProperty to decide whether it may replace an earlier hook.
|
|
181
|
+
const originalWindowHasOwnProperty = window.hasOwnProperty.bind(window);
|
|
182
|
+
const originalHasOwnPropertyDescriptor = Object.getOwnPropertyDescriptor(
|
|
183
|
+
window,
|
|
184
|
+
"hasOwnProperty",
|
|
185
|
+
);
|
|
186
|
+
let didRunHasOwnPropertyHack = false;
|
|
187
|
+
const restoreWindowHasOwnProperty = (): void => {
|
|
188
|
+
if (originalHasOwnPropertyDescriptor) {
|
|
189
|
+
objectDefineProperty(window, "hasOwnProperty", originalHasOwnPropertyDescriptor);
|
|
190
|
+
} else {
|
|
191
|
+
Reflect.deleteProperty(window, "hasOwnProperty");
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
objectDefineProperty(window, "hasOwnProperty", {
|
|
195
|
+
configurable: true,
|
|
196
|
+
value: (...propertyKeys: [PropertyKey]) => {
|
|
197
|
+
if (!didRunHasOwnPropertyHack && propertyKeys[0] === "__REACT_DEVTOOLS_GLOBAL_HOOK__") {
|
|
198
|
+
didRunHasOwnPropertyHack = true;
|
|
199
|
+
restoreWindowHasOwnProperty();
|
|
139
200
|
globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__ = undefined;
|
|
140
|
-
|
|
141
|
-
return -0;
|
|
201
|
+
return false;
|
|
142
202
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
203
|
+
return originalWindowHasOwnProperty(...propertyKeys);
|
|
204
|
+
},
|
|
205
|
+
writable: true,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
148
208
|
} catch {
|
|
149
209
|
patchRDTHook(onActive);
|
|
150
210
|
}
|
|
151
211
|
return rdtHook;
|
|
152
212
|
};
|
|
153
213
|
|
|
154
|
-
export const patchRDTHook = (onActive?:
|
|
214
|
+
export const patchRDTHook = (onActive?: ActiveListener): void => {
|
|
155
215
|
if (onActive) {
|
|
156
216
|
_onActiveListeners.add(onActive);
|
|
157
217
|
}
|
|
158
218
|
let didNotifyActiveListeners = false;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
rdtHook.on = NO_OP;
|
|
174
|
-
}
|
|
175
|
-
if (renderers.size) {
|
|
176
|
-
renderers.forEach((renderer) => _renderers.add(renderer));
|
|
177
|
-
rdtHook._instrumentationIsActive = true;
|
|
178
|
-
_onActiveListeners.forEach((listener) => listener());
|
|
179
|
-
didNotifyActiveListeners = true;
|
|
180
|
-
}
|
|
181
|
-
const prevInject = rdtHook.inject;
|
|
182
|
-
rdtHook.inject = (renderer) => {
|
|
183
|
-
const rendererId = prevInject(renderer);
|
|
184
|
-
_renderers.add(renderer);
|
|
185
|
-
renderers.set(rendererId, renderer);
|
|
186
|
-
rdtHook._instrumentationIsActive = true;
|
|
187
|
-
_onActiveListeners.forEach((listener) => listener());
|
|
188
|
-
return rendererId;
|
|
189
|
-
};
|
|
219
|
+
const rdtHook = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
220
|
+
if (!rdtHook) return;
|
|
221
|
+
const renderers = getRendererMap(rdtHook);
|
|
222
|
+
if (!rdtHook._instrumentationSource) {
|
|
223
|
+
rdtHook.checkDCE = checkDCE;
|
|
224
|
+
rdtHook.supportsFiber = true;
|
|
225
|
+
rdtHook.supportsFlight = true;
|
|
226
|
+
rdtHook.hasUnsupportedRendererAttached = false;
|
|
227
|
+
rdtHook._instrumentationSource = BIPPY_INSTRUMENTATION_STRING;
|
|
228
|
+
rdtHook._instrumentationIsActive = false;
|
|
229
|
+
// HACK: DevTools detection must happen after setting the source to avoid recursive patching.
|
|
230
|
+
const isReactDevtools = isRealReactDevtools(rdtHook);
|
|
231
|
+
if (!isReactDevtools) {
|
|
232
|
+
rdtHook.on = noOp;
|
|
190
233
|
}
|
|
191
|
-
if (
|
|
192
|
-
|
|
234
|
+
if (renderers.size) {
|
|
235
|
+
renderers.forEach((renderer) => _renderers.add(renderer));
|
|
236
|
+
rdtHook._instrumentationIsActive = true;
|
|
237
|
+
notifyActiveListeners();
|
|
238
|
+
didNotifyActiveListeners = true;
|
|
193
239
|
}
|
|
194
|
-
|
|
240
|
+
const previousInject = rdtHook.inject;
|
|
241
|
+
rdtHook.inject = (renderer) => {
|
|
242
|
+
const rendererId = previousInject.call(rdtHook, renderer);
|
|
243
|
+
_renderers.add(renderer);
|
|
244
|
+
renderers.set(rendererId, renderer);
|
|
245
|
+
if (!rdtHook._instrumentationIsActive) {
|
|
246
|
+
rdtHook._instrumentationIsActive = true;
|
|
247
|
+
notifyActiveListeners();
|
|
248
|
+
}
|
|
249
|
+
return rendererId;
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (!didNotifyActiveListeners && (renderers.size || rdtHook._instrumentationIsActive)) {
|
|
253
|
+
if (onActive) runHookListener("onActive", onActive);
|
|
254
|
+
}
|
|
195
255
|
};
|
|
196
256
|
|
|
197
257
|
export const hasRDTHook = (): boolean => {
|
|
198
|
-
return
|
|
258
|
+
return Object.hasOwn(globalThis, "__REACT_DEVTOOLS_GLOBAL_HOOK__");
|
|
199
259
|
};
|
|
200
260
|
|
|
201
261
|
/**
|
|
202
262
|
* Returns the current React DevTools global hook.
|
|
203
263
|
*/
|
|
204
|
-
export const getRDTHook = (onActive?:
|
|
264
|
+
export const getRDTHook = (onActive?: ActiveListener): ReactDevToolsGlobalHook => {
|
|
205
265
|
if (!hasRDTHook()) {
|
|
206
266
|
return installRDTHook(onActive);
|
|
207
267
|
}
|
|
@@ -210,18 +270,6 @@ export const getRDTHook = (onActive?: () => unknown): ReactDevToolsGlobalHook =>
|
|
|
210
270
|
return globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__ ?? installRDTHook(onActive);
|
|
211
271
|
};
|
|
212
272
|
|
|
213
|
-
export const
|
|
214
|
-
|
|
215
|
-
typeof window !== "undefined" &&
|
|
216
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
217
|
-
(window.document?.createElement || window.navigator?.product === "ReactNative"),
|
|
218
|
-
);
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
export const safelyInstallRDTHook = () => {
|
|
222
|
-
try {
|
|
223
|
-
if (isClientEnvironment()) {
|
|
224
|
-
getRDTHook();
|
|
225
|
-
}
|
|
226
|
-
} catch {}
|
|
273
|
+
export const safelyInstallRDTHook = (): void => {
|
|
274
|
+
runWithBippyError(getRDTHook, (cause) => new BippyHookInstallationError(cause));
|
|
227
275
|
};
|
package/src/react-internals.ts
CHANGED
|
@@ -1,27 +1,13 @@
|
|
|
1
|
+
import { getReactWorkTags, ReactFiberFlags } from "./generated/react-work-tags.js";
|
|
2
|
+
import type { ReactWorkTagMap } from "./generated/react-work-tags.js";
|
|
3
|
+
import { compareSemver } from "./semver.js";
|
|
4
|
+
import type { Fiber, ReactRenderer } from "./types.js";
|
|
5
|
+
|
|
1
6
|
export {
|
|
2
|
-
ActivityComponentTag,
|
|
3
|
-
ClassComponentTag,
|
|
4
|
-
ContextConsumerTag,
|
|
5
|
-
DehydratedSuspenseComponentTag,
|
|
6
|
-
ForwardRefTag,
|
|
7
|
-
FragmentTag,
|
|
8
|
-
FunctionComponentTag,
|
|
9
7
|
getReactWorkTags,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
HostRootTag,
|
|
14
|
-
HostSingletonTag,
|
|
15
|
-
HostTextTag,
|
|
16
|
-
LazyComponentTag,
|
|
17
|
-
LegacyHiddenComponentTag,
|
|
18
|
-
MemoComponentTag,
|
|
19
|
-
OffscreenComponentTag,
|
|
20
|
-
ReactWorkTags,
|
|
21
|
-
SimpleMemoComponentTag,
|
|
22
|
-
SuspenseComponentTag,
|
|
23
|
-
SuspenseListComponentTag,
|
|
24
|
-
ViewTransitionComponentTag,
|
|
8
|
+
ReactBuildType,
|
|
9
|
+
ReactFiberFlags,
|
|
10
|
+
ReactSymbols,
|
|
25
11
|
} from "./generated/react-work-tags.js";
|
|
26
12
|
export type {
|
|
27
13
|
HostWorkTag,
|
|
@@ -30,22 +16,43 @@ export type {
|
|
|
30
16
|
ReactWorkTagVersion,
|
|
31
17
|
} from "./generated/react-work-tags.js";
|
|
32
18
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
19
|
+
const defaultReactWorkTags = getReactWorkTags("");
|
|
20
|
+
const fiberReactWorkTags = new WeakMap<Fiber, Readonly<ReactWorkTagMap>>();
|
|
21
|
+
|
|
22
|
+
export const getReactWorkTagsForRenderer = (
|
|
23
|
+
renderer?: ReactRenderer | null,
|
|
24
|
+
): Readonly<ReactWorkTagMap> => {
|
|
25
|
+
const reconcilerVersion = renderer?.reconcilerVersion;
|
|
26
|
+
if (reconcilerVersion && compareSemver(reconcilerVersion, reconcilerVersion) === 0) {
|
|
27
|
+
return getReactWorkTags(reconcilerVersion);
|
|
28
|
+
}
|
|
29
|
+
return getReactWorkTags(renderer?.version ?? "");
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const setReactWorkTagsForFiber = (fiber: Fiber, renderer?: ReactRenderer): void => {
|
|
33
|
+
const workTags = getReactWorkTagsForRenderer(renderer);
|
|
34
|
+
fiberReactWorkTags.set(fiber, workTags);
|
|
35
|
+
if (fiber.alternate) fiberReactWorkTags.set(fiber.alternate, workTags);
|
|
44
36
|
};
|
|
45
37
|
|
|
46
|
-
export const
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
export const getReactWorkTagsForFiber = (fiber: Fiber): Readonly<ReactWorkTagMap> => {
|
|
39
|
+
const cachedWorkTags = fiberReactWorkTags.get(fiber);
|
|
40
|
+
if (cachedWorkTags) return cachedWorkTags;
|
|
41
|
+
|
|
42
|
+
const traversedFibers: Fiber[] = [fiber];
|
|
43
|
+
let rootFiber = fiber;
|
|
44
|
+
while (rootFiber.return) {
|
|
45
|
+
rootFiber = rootFiber.return;
|
|
46
|
+
traversedFibers.push(rootFiber);
|
|
47
|
+
}
|
|
48
|
+
const workTags = fiberReactWorkTags.get(rootFiber) ?? defaultReactWorkTags;
|
|
49
|
+
for (const traversedFiber of traversedFibers) {
|
|
50
|
+
fiberReactWorkTags.set(traversedFiber, workTags);
|
|
51
|
+
if (traversedFiber.alternate) {
|
|
52
|
+
fiberReactWorkTags.set(traversedFiber.alternate, workTags);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return workTags;
|
|
49
56
|
};
|
|
50
57
|
|
|
51
58
|
export const MutationMask =
|
|
@@ -56,12 +63,3 @@ export const MutationMask =
|
|
|
56
63
|
ReactFiberFlags.Hydrating |
|
|
57
64
|
ReactFiberFlags.Visibility |
|
|
58
65
|
ReactFiberFlags.Snapshot;
|
|
59
|
-
|
|
60
|
-
// HACK: React does not export its legacy mode and element symbols, which differ between React 17, 18, and 19.
|
|
61
|
-
export const CONCURRENT_MODE_NUMBER = 0xeacf;
|
|
62
|
-
export const ELEMENT_TYPE_SYMBOL_STRING = "Symbol(react.element)";
|
|
63
|
-
export const TRANSITIONAL_ELEMENT_TYPE_SYMBOL_STRING = "Symbol(react.transitional.element)";
|
|
64
|
-
export const CONCURRENT_MODE_SYMBOL_STRING = "Symbol(react.concurrent_mode)";
|
|
65
|
-
export const DEPRECATED_ASYNC_MODE_SYMBOL_STRING = "Symbol(react.async_mode)";
|
|
66
|
-
export const CONCURRENT_MODE_SYMBOL_DESCRIPTION = "react.concurrent_mode";
|
|
67
|
-
export const DEPRECATED_ASYNC_MODE_SYMBOL_DESCRIPTION = "react.async_mode";
|
package/src/semver.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
interface SemanticVersion {
|
|
2
|
+
major: string;
|
|
3
|
+
minor: string;
|
|
4
|
+
patch: string;
|
|
5
|
+
prerelease: string[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const SEMVER_PATTERN =
|
|
9
|
+
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
10
|
+
const NUMERIC_IDENTIFIER_PATTERN = /^\d+$/;
|
|
11
|
+
|
|
12
|
+
const parseSemver = (version: string): SemanticVersion | null => {
|
|
13
|
+
const match = SEMVER_PATTERN.exec(version);
|
|
14
|
+
if (!match) return null;
|
|
15
|
+
const prerelease = match[4]?.split(".") ?? [];
|
|
16
|
+
if (
|
|
17
|
+
prerelease.some(
|
|
18
|
+
(identifier) =>
|
|
19
|
+
NUMERIC_IDENTIFIER_PATTERN.test(identifier) &&
|
|
20
|
+
identifier.length > 1 &&
|
|
21
|
+
identifier.startsWith("0"),
|
|
22
|
+
)
|
|
23
|
+
) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
major: match[1],
|
|
28
|
+
minor: match[2],
|
|
29
|
+
patch: match[3],
|
|
30
|
+
prerelease,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const compareNumericIdentifiers = (left: string, right: string): -1 | 0 | 1 => {
|
|
35
|
+
if (left.length !== right.length) return left.length < right.length ? -1 : 1;
|
|
36
|
+
if (left === right) return 0;
|
|
37
|
+
return left < right ? -1 : 1;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const comparePrereleaseIdentifiers = (left: string, right: string): -1 | 0 | 1 => {
|
|
41
|
+
const isLeftNumeric = NUMERIC_IDENTIFIER_PATTERN.test(left);
|
|
42
|
+
const isRightNumeric = NUMERIC_IDENTIFIER_PATTERN.test(right);
|
|
43
|
+
if (isLeftNumeric && isRightNumeric) return compareNumericIdentifiers(left, right);
|
|
44
|
+
if (isLeftNumeric !== isRightNumeric) return isLeftNumeric ? -1 : 1;
|
|
45
|
+
if (left === right) return 0;
|
|
46
|
+
return left < right ? -1 : 1;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const comparePrerelease = (left: string[], right: string[]): -1 | 0 | 1 => {
|
|
50
|
+
if (left.length === 0 || right.length === 0) {
|
|
51
|
+
if (left.length === right.length) return 0;
|
|
52
|
+
return left.length === 0 ? 1 : -1;
|
|
53
|
+
}
|
|
54
|
+
const identifierCount = Math.max(left.length, right.length);
|
|
55
|
+
for (let identifierIndex = 0; identifierIndex < identifierCount; identifierIndex++) {
|
|
56
|
+
const leftIdentifier = left[identifierIndex];
|
|
57
|
+
const rightIdentifier = right[identifierIndex];
|
|
58
|
+
if (leftIdentifier === undefined || rightIdentifier === undefined) {
|
|
59
|
+
return leftIdentifier === undefined ? -1 : 1;
|
|
60
|
+
}
|
|
61
|
+
const comparison = comparePrereleaseIdentifiers(leftIdentifier, rightIdentifier);
|
|
62
|
+
if (comparison !== 0) return comparison;
|
|
63
|
+
}
|
|
64
|
+
return 0;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const compareSemver = (leftVersion: string, rightVersion: string): -1 | 0 | 1 | null => {
|
|
68
|
+
const left = parseSemver(leftVersion);
|
|
69
|
+
const right = parseSemver(rightVersion);
|
|
70
|
+
if (!left || !right) return null;
|
|
71
|
+
const majorComparison = compareNumericIdentifiers(left.major, right.major);
|
|
72
|
+
if (majorComparison !== 0) return majorComparison;
|
|
73
|
+
const minorComparison = compareNumericIdentifiers(left.minor, right.minor);
|
|
74
|
+
if (minorComparison !== 0) return minorComparison;
|
|
75
|
+
const patchComparison = compareNumericIdentifiers(left.patch, right.patch);
|
|
76
|
+
if (patchComparison !== 0) return patchComparison;
|
|
77
|
+
return comparePrerelease(left.prerelease, right.prerelease);
|
|
78
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface ErrorConstructorWithPrepareStackTrace {
|
|
2
|
+
prepareStackTrace?: unknown;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const errorConstructor: ErrorConstructorWithPrepareStackTrace = Error;
|
|
6
|
+
|
|
7
|
+
export const getPrepareStackTrace = (): unknown => errorConstructor.prepareStackTrace;
|
|
8
|
+
|
|
9
|
+
export const setPrepareStackTrace = (prepareStackTrace: unknown): void => {
|
|
10
|
+
errorConstructor.prepareStackTrace = prepareStackTrace;
|
|
11
|
+
};
|
package/src/source/index.ts
CHANGED
|
@@ -6,12 +6,20 @@ export {
|
|
|
6
6
|
symbolicateStack,
|
|
7
7
|
type DecodedSourceMapSection,
|
|
8
8
|
type IndexSourceMap,
|
|
9
|
-
type
|
|
9
|
+
type SourceFetch,
|
|
10
10
|
type SourceMap,
|
|
11
|
+
type SourceMapRequestOptions,
|
|
11
12
|
type StandardSourceMap,
|
|
12
13
|
} from "./symbolication.js";
|
|
13
14
|
export type { FiberSource } from "./types.js";
|
|
14
15
|
export { parseStack, type ParseOptions, type StackFrame } from "./parse-stack.js";
|
|
15
16
|
export { getDisplayNameFromSource } from "./get-display-name-from-source.js";
|
|
17
|
+
export {
|
|
18
|
+
BippyError,
|
|
19
|
+
BippyHookInspectionError,
|
|
20
|
+
BippyHookRenderError,
|
|
21
|
+
BippySourceMapError,
|
|
22
|
+
BippyUnsupportedHookError,
|
|
23
|
+
} from "../errors.js";
|
|
16
24
|
export { getFiberHooks, type HookSource, type HooksNode, type HooksTree } from "./inspect-hooks.js";
|
|
17
25
|
export { parseHookNames, type HookNames } from "./parse-hook-names.js";
|