@flotrace/runtime-core 2.2.4 → 2.3.1
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 +94 -0
- package/babel-plugin.d.ts +36 -0
- package/babel-plugin.js +302 -0
- package/dist/chunk-5LSFLPGP.mjs +276 -0
- package/dist/index.d.mts +435 -17
- package/dist/index.d.ts +435 -17
- package/dist/index.js +801 -120
- package/dist/index.mjs +585 -120
- package/dist/jsx-dev-runtime.d.mts +64 -0
- package/dist/jsx-dev-runtime.d.ts +64 -0
- package/dist/jsx-dev-runtime.js +179 -0
- package/dist/jsx-dev-runtime.mjs +46 -0
- package/dist/jsx-runtime.d.mts +1 -0
- package/dist/jsx-runtime.d.ts +1 -0
- package/dist/jsx-runtime.js +34 -0
- package/dist/jsx-runtime.mjs +7 -0
- package/package.json +18 -1
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
// src/jsxRuntimeUtils.ts
|
|
2
|
+
var FLOTRACE_SOURCE = /* @__PURE__ */ Symbol.for("flotrace.source");
|
|
3
|
+
var JSX_RUNTIME_ACTIVE_KEY = /* @__PURE__ */ Symbol.for("flotrace.jsx-runtime-active");
|
|
4
|
+
function normalizeJsxSourcePath(fileName) {
|
|
5
|
+
let p = fileName;
|
|
6
|
+
if (p.startsWith("file://")) p = p.slice("file://".length);
|
|
7
|
+
if (p.startsWith("webpack-internal:///./")) p = p.slice("webpack-internal:///./".length);
|
|
8
|
+
if (p.startsWith("[project]/")) p = p.slice("[project]/".length);
|
|
9
|
+
if (p.startsWith("./")) p = p.slice(2);
|
|
10
|
+
if (/^\/[a-zA-Z]:[\\/]/.test(p)) p = p.slice(1);
|
|
11
|
+
if (/^[a-zA-Z]:[\\/]/.test(p)) p = p[0].toLowerCase() + p.slice(1);
|
|
12
|
+
return p;
|
|
13
|
+
}
|
|
14
|
+
function normalizeStackFramePath(rawPath) {
|
|
15
|
+
let p = rawPath;
|
|
16
|
+
const queryIdx = p.indexOf("?");
|
|
17
|
+
if (queryIdx !== -1) p = p.slice(0, queryIdx);
|
|
18
|
+
const httpMatch = p.match(/^https?:\/\/[^/]+(\/.+)$/);
|
|
19
|
+
if (httpMatch) {
|
|
20
|
+
p = httpMatch[1];
|
|
21
|
+
if (p.startsWith("/")) p = p.slice(1);
|
|
22
|
+
}
|
|
23
|
+
return normalizeJsxSourcePath(p);
|
|
24
|
+
}
|
|
25
|
+
function isJsBundlePath(rawPath) {
|
|
26
|
+
if (/\bindex\.bundle\b/.test(rawPath)) return true;
|
|
27
|
+
if (/\.bundle(\?|$|\.js(\?|$))/.test(rawPath)) return true;
|
|
28
|
+
if (/\?platform=(ios|android|web|native)\b/.test(rawPath)) return true;
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
function parseFirstNonReactFrame(stack) {
|
|
32
|
+
const lines = stack.split("\n");
|
|
33
|
+
for (const line of lines) {
|
|
34
|
+
const parened = line.match(/\(([^)]+):(\d+):(\d+)\)/);
|
|
35
|
+
const hermes = line.match(/@([^\s]+):(\d+):(\d+)$/);
|
|
36
|
+
const match = parened ?? hermes;
|
|
37
|
+
if (!match) continue;
|
|
38
|
+
const path = match[1];
|
|
39
|
+
if (path.includes("react-dom")) continue;
|
|
40
|
+
if (path.includes("react-native/Libraries")) continue;
|
|
41
|
+
if (path.includes("/react/cjs/")) continue;
|
|
42
|
+
if (path.includes("/scheduler/")) continue;
|
|
43
|
+
if (isJsBundlePath(path)) continue;
|
|
44
|
+
return {
|
|
45
|
+
fileName: normalizeStackFramePath(path),
|
|
46
|
+
lineNumber: Number(match[2]),
|
|
47
|
+
columnNumber: Number(match[3])
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
function computeCallSiteId(source) {
|
|
53
|
+
const normPath = normalizeJsxSourcePath(source.fileName);
|
|
54
|
+
const key = `${normPath}:${source.lineNumber}:${source.columnNumber}`;
|
|
55
|
+
let hash = 2166136261;
|
|
56
|
+
for (let i = 0; i < key.length; i++) {
|
|
57
|
+
hash ^= key.charCodeAt(i);
|
|
58
|
+
hash = Math.imul(hash, 16777619);
|
|
59
|
+
}
|
|
60
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
61
|
+
}
|
|
62
|
+
var FLOTRACE_SRC_ATTR = "data-flotrace-src";
|
|
63
|
+
function parseDataFlotraceSrc(value) {
|
|
64
|
+
let obj;
|
|
65
|
+
try {
|
|
66
|
+
obj = JSON.parse(value);
|
|
67
|
+
} catch {
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
if (!obj || typeof obj !== "object") return void 0;
|
|
71
|
+
const o = obj;
|
|
72
|
+
if (typeof o.f !== "string" || typeof o.l !== "number" || typeof o.c !== "number") {
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
const fileName = o.f;
|
|
76
|
+
const lineNumber = o.l;
|
|
77
|
+
const columnNumber = o.c;
|
|
78
|
+
return {
|
|
79
|
+
fileName,
|
|
80
|
+
lineNumber,
|
|
81
|
+
columnNumber,
|
|
82
|
+
callSiteId: computeCallSiteId({ fileName, lineNumber, columnNumber })
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function readJsxSourceFromFiber(fiber) {
|
|
86
|
+
const props = fiber.memoizedProps;
|
|
87
|
+
if (props) {
|
|
88
|
+
const symRaw = props[FLOTRACE_SOURCE];
|
|
89
|
+
if (symRaw && typeof symRaw === "object") {
|
|
90
|
+
const obj = symRaw;
|
|
91
|
+
if (typeof obj.fileName === "string" && typeof obj.lineNumber === "number" && typeof obj.columnNumber === "number" && typeof obj.callSiteId === "string") {
|
|
92
|
+
return symRaw;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const strRaw = props[FLOTRACE_SRC_ATTR];
|
|
96
|
+
if (typeof strRaw === "string") {
|
|
97
|
+
const parsed = parseDataFlotraceSrc(strRaw);
|
|
98
|
+
if (parsed) return parsed;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const type = fiber.type;
|
|
102
|
+
if (type !== null && (typeof type === "function" || typeof type === "object")) {
|
|
103
|
+
const typeAttr = type[FLOTRACE_SRC_ATTR];
|
|
104
|
+
if (typeof typeAttr === "string") {
|
|
105
|
+
const parsed = parseDataFlotraceSrc(typeAttr);
|
|
106
|
+
if (parsed) return parsed;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return void 0;
|
|
110
|
+
}
|
|
111
|
+
function isUserComponent(fiber) {
|
|
112
|
+
const jsxSrc = readJsxSourceFromFiber({
|
|
113
|
+
memoizedProps: fiber.memoizedProps ?? null,
|
|
114
|
+
type: fiber.type
|
|
115
|
+
});
|
|
116
|
+
if (jsxSrc && !jsxSrc.fileName.includes("node_modules")) return true;
|
|
117
|
+
const debugSourcePath = fiber._debugSource?.fileName;
|
|
118
|
+
if (typeof debugSourcePath === "string" && !debugSourcePath.includes("node_modules")) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
const stack = fiber._debugStack?.stack;
|
|
122
|
+
if (typeof stack === "string") {
|
|
123
|
+
const frame = parseFirstNonReactFrame(stack);
|
|
124
|
+
if (frame && !frame.fileName.includes("node_modules")) return true;
|
|
125
|
+
}
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
var callSiteRenders = /* @__PURE__ */ new Map();
|
|
129
|
+
var RING_BUFFER_MAX = 60;
|
|
130
|
+
function recordCallSiteRender(callSiteId, now = performance.now()) {
|
|
131
|
+
const arr = callSiteRenders.get(callSiteId);
|
|
132
|
+
if (arr === void 0) {
|
|
133
|
+
callSiteRenders.set(callSiteId, [now]);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
arr.push(now);
|
|
137
|
+
if (arr.length > RING_BUFFER_MAX) arr.shift();
|
|
138
|
+
}
|
|
139
|
+
function getCallSiteRenders(callSiteId) {
|
|
140
|
+
return callSiteRenders.get(callSiteId) ?? [];
|
|
141
|
+
}
|
|
142
|
+
function getCallSiteRenderRate(callSiteId, windowMs = 5e3, now = performance.now()) {
|
|
143
|
+
const arr = callSiteRenders.get(callSiteId);
|
|
144
|
+
if (!arr || arr.length === 0) return 0;
|
|
145
|
+
const cutoff = now - windowMs;
|
|
146
|
+
let count = 0;
|
|
147
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
148
|
+
if (arr[i] >= cutoff) count++;
|
|
149
|
+
else break;
|
|
150
|
+
}
|
|
151
|
+
return count / windowMs * 1e3;
|
|
152
|
+
}
|
|
153
|
+
function clearCallSiteRenders() {
|
|
154
|
+
callSiteRenders.clear();
|
|
155
|
+
}
|
|
156
|
+
function computeCallSiteMetricsPayload(windowMs = 5e3, now = performance.now()) {
|
|
157
|
+
let out = null;
|
|
158
|
+
const cutoff = now - windowMs;
|
|
159
|
+
for (const [callSiteId, arr] of callSiteRenders) {
|
|
160
|
+
if (arr.length === 0) continue;
|
|
161
|
+
let count = 0;
|
|
162
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
163
|
+
if (arr[i] >= cutoff) count++;
|
|
164
|
+
else break;
|
|
165
|
+
}
|
|
166
|
+
if (count > 0) {
|
|
167
|
+
(out ?? (out = {}))[callSiteId] = count / windowMs * 1e3;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
var duplicateKeyEmitter = null;
|
|
173
|
+
function setDuplicateKeyEmitter(emitter) {
|
|
174
|
+
duplicateKeyEmitter = emitter;
|
|
175
|
+
}
|
|
176
|
+
var currentKeyBatch = /* @__PURE__ */ new Map();
|
|
177
|
+
var keyBatchFlushScheduled = false;
|
|
178
|
+
function recordJsxKey(source, key) {
|
|
179
|
+
const keyType = typeof key;
|
|
180
|
+
if (keyType !== "string" && keyType !== "number" && keyType !== "boolean") return;
|
|
181
|
+
const keyStr = String(key);
|
|
182
|
+
const batchKey = `${source.callSiteId}|${keyStr}`;
|
|
183
|
+
const entry = currentKeyBatch.get(batchKey);
|
|
184
|
+
if (entry !== void 0) {
|
|
185
|
+
entry.count++;
|
|
186
|
+
} else {
|
|
187
|
+
currentKeyBatch.set(batchKey, { count: 1, source });
|
|
188
|
+
}
|
|
189
|
+
if (!keyBatchFlushScheduled) {
|
|
190
|
+
keyBatchFlushScheduled = true;
|
|
191
|
+
queueMicrotask(flushDuplicateKeys);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function flushDuplicateKeys() {
|
|
195
|
+
keyBatchFlushScheduled = false;
|
|
196
|
+
const emitter = duplicateKeyEmitter;
|
|
197
|
+
if (emitter === null) {
|
|
198
|
+
currentKeyBatch.clear();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
for (const [batchKey, { count, source }] of currentKeyBatch) {
|
|
202
|
+
if (count < 2) continue;
|
|
203
|
+
const sep = batchKey.indexOf("|");
|
|
204
|
+
const duplicateKey = batchKey.slice(sep + 1);
|
|
205
|
+
emitter({
|
|
206
|
+
callSiteId: source.callSiteId,
|
|
207
|
+
fileName: source.fileName,
|
|
208
|
+
lineNumber: source.lineNumber,
|
|
209
|
+
columnNumber: source.columnNumber,
|
|
210
|
+
duplicateKey,
|
|
211
|
+
occurrences: count
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
currentKeyBatch.clear();
|
|
215
|
+
}
|
|
216
|
+
function markJsxRuntimeActive() {
|
|
217
|
+
globalThis[JSX_RUNTIME_ACTIVE_KEY] = true;
|
|
218
|
+
}
|
|
219
|
+
function isJsxRuntimeActive() {
|
|
220
|
+
return globalThis[JSX_RUNTIME_ACTIVE_KEY] === true;
|
|
221
|
+
}
|
|
222
|
+
var KNOWN_REACT_PROPS = /* @__PURE__ */ new Set(["key", "ref", "children", "className"]);
|
|
223
|
+
var REACT_ELEMENT_TYPEOF_LEGACY = /* @__PURE__ */ Symbol.for("react.element");
|
|
224
|
+
var REACT_ELEMENT_TYPEOF_R19 = /* @__PURE__ */ Symbol.for("react.transitional.element");
|
|
225
|
+
function isReactElement(v) {
|
|
226
|
+
const typeOf = v.$$typeof;
|
|
227
|
+
return typeOf === REACT_ELEMENT_TYPEOF_LEGACY || typeOf === REACT_ELEMENT_TYPEOF_R19;
|
|
228
|
+
}
|
|
229
|
+
function detectInlineLiterals(props) {
|
|
230
|
+
let out;
|
|
231
|
+
for (const k in props) {
|
|
232
|
+
if (KNOWN_REACT_PROPS.has(k)) continue;
|
|
233
|
+
const v = props[k];
|
|
234
|
+
if (typeof v === "function") {
|
|
235
|
+
if (!v.name) {
|
|
236
|
+
(out ?? (out = {}))[k] = "fn";
|
|
237
|
+
}
|
|
238
|
+
} else if (Array.isArray(v)) {
|
|
239
|
+
if (v.length > 0) {
|
|
240
|
+
(out ?? (out = {}))[k] = "arr";
|
|
241
|
+
}
|
|
242
|
+
} else if (v !== null && typeof v === "object" && // Skip elements processed by our own runtime (marker present).
|
|
243
|
+
!(FLOTRACE_SOURCE in v) && // Skip React elements processed by ANY runtime — `$$typeof` is set on
|
|
244
|
+
// every element regardless of which jsx-runtime created it, so this
|
|
245
|
+
// catches mixed-runtime codebases. Without this guard, an inline
|
|
246
|
+
// `<Outer child={<Inner/>} />` would false-positive on `child` when
|
|
247
|
+
// Inner went through a different jsxImportSource.
|
|
248
|
+
!isReactElement(v)) {
|
|
249
|
+
const proto = Object.getPrototypeOf(v);
|
|
250
|
+
if (proto === Object.prototype || proto === null) {
|
|
251
|
+
(out ?? (out = {}))[k] = "obj";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return out;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export {
|
|
259
|
+
FLOTRACE_SOURCE,
|
|
260
|
+
JSX_RUNTIME_ACTIVE_KEY,
|
|
261
|
+
normalizeJsxSourcePath,
|
|
262
|
+
parseFirstNonReactFrame,
|
|
263
|
+
computeCallSiteId,
|
|
264
|
+
readJsxSourceFromFiber,
|
|
265
|
+
isUserComponent,
|
|
266
|
+
recordCallSiteRender,
|
|
267
|
+
getCallSiteRenders,
|
|
268
|
+
getCallSiteRenderRate,
|
|
269
|
+
clearCallSiteRenders,
|
|
270
|
+
computeCallSiteMetricsPayload,
|
|
271
|
+
setDuplicateKeyEmitter,
|
|
272
|
+
recordJsxKey,
|
|
273
|
+
markJsxRuntimeActive,
|
|
274
|
+
isJsxRuntimeActive,
|
|
275
|
+
detectInlineLiterals
|
|
276
|
+
};
|