react-native-bundle-discovery 2.7.0-rc.0 → 2.7.0
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/CHANGELOG.md +7 -0
- package/dist/index.js +956 -602
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -7,19 +7,33 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
9
|
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
if ((from && typeof from === "object") || typeof from === "function")
|
|
11
|
+
for (
|
|
12
|
+
var keys = __getOwnPropNames(from), i = 0, n = keys.length, key;
|
|
13
|
+
i < n;
|
|
14
|
+
i++
|
|
15
|
+
) {
|
|
16
|
+
key = keys[i];
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
+
__defProp(to, key, {
|
|
19
|
+
get: ((k) => from[k]).bind(null, key),
|
|
20
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
18
24
|
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
var __toESM = (mod, isNodeMode, target) => (
|
|
26
|
+
(target = mod != null ? __create(__getProtoOf(mod)) : {}),
|
|
27
|
+
__copyProps(
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default")
|
|
29
|
+
? __defProp(target, "default", {
|
|
30
|
+
value: mod,
|
|
31
|
+
enumerable: true,
|
|
32
|
+
})
|
|
33
|
+
: target,
|
|
34
|
+
mod,
|
|
35
|
+
)
|
|
36
|
+
);
|
|
23
37
|
//#endregion
|
|
24
38
|
let node_buffer = require("node:buffer");
|
|
25
39
|
let node_fs = require("node:fs");
|
|
@@ -41,689 +55,1029 @@ const DEFAULT_TIMEOUT_MS = 5e3;
|
|
|
41
55
|
const DEFAULT_CONCURRENCY = 5;
|
|
42
56
|
const cache = /* @__PURE__ */ new Map();
|
|
43
57
|
/**
|
|
44
|
-
* `@babel/runtime` -> `@babel%2fruntime`
|
|
45
|
-
*/
|
|
58
|
+
* `@babel/runtime` -> `@babel%2fruntime`
|
|
59
|
+
*/
|
|
46
60
|
function encodePackageName(name) {
|
|
47
|
-
|
|
61
|
+
return name.startsWith("@") ? `@${encodeURIComponent(name.slice(1))}` : name;
|
|
48
62
|
}
|
|
49
63
|
async function fetchJson(url, timeoutMs) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
const res = await fetch(url, {
|
|
65
|
+
headers: { Accept: "application/json" },
|
|
66
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
67
|
+
});
|
|
68
|
+
if (res.status === 404) return null;
|
|
69
|
+
if (!res.ok) throw new Error(`${res.status} ${res.statusText} (${url})`);
|
|
70
|
+
return res.json();
|
|
57
71
|
}
|
|
58
72
|
/**
|
|
59
|
-
* The version manifest (`/<name>/<version>`) has no publish date,
|
|
60
|
-
* so the packument is fetched once and only the fields we need are kept.
|
|
61
|
-
*/
|
|
73
|
+
* The version manifest (`/<name>/<version>`) has no publish date,
|
|
74
|
+
* so the packument is fetched once and only the fields we need are kept.
|
|
75
|
+
*/
|
|
62
76
|
async function fetchPackageSummary(name, { registry, timeoutMs }) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
const packument = await fetchJson(
|
|
78
|
+
`${registry}/${encodePackageName(name)}`,
|
|
79
|
+
timeoutMs,
|
|
80
|
+
);
|
|
81
|
+
if (!packument) return null;
|
|
82
|
+
const versions = {};
|
|
83
|
+
for (const [version, manifest] of Object.entries(packument.versions ?? {}))
|
|
84
|
+
versions[version] = {
|
|
85
|
+
createdAt: packument.time?.[version] ?? null,
|
|
86
|
+
deprecated: manifest.deprecated || false,
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
latestVersion: packument["dist-tags"]?.latest ?? null,
|
|
90
|
+
versions,
|
|
91
|
+
};
|
|
74
92
|
}
|
|
75
93
|
function getPackageSummary(name, { registry, timeoutMs }) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
const key = `${registry}|${name}`;
|
|
95
|
+
let promise = cache.get(key);
|
|
96
|
+
if (!promise) {
|
|
97
|
+
promise = fetchPackageSummary(name, {
|
|
98
|
+
registry,
|
|
99
|
+
timeoutMs,
|
|
100
|
+
}).catch((error) => {
|
|
101
|
+
cache.delete(key);
|
|
102
|
+
throw error;
|
|
103
|
+
});
|
|
104
|
+
cache.set(key, promise);
|
|
105
|
+
}
|
|
106
|
+
return promise;
|
|
89
107
|
}
|
|
90
108
|
/**
|
|
91
|
-
* Returns metadata of a specific (installed) package version, not the latest one.
|
|
92
|
-
*
|
|
93
|
-
* @returns `null` when the package/version is not found in the registry.
|
|
94
|
-
*/
|
|
95
|
-
async function getPackageMetadata(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
* Returns metadata of a specific (installed) package version, not the latest one.
|
|
110
|
+
*
|
|
111
|
+
* @returns `null` when the package/version is not found in the registry.
|
|
112
|
+
*/
|
|
113
|
+
async function getPackageMetadata(
|
|
114
|
+
name,
|
|
115
|
+
version,
|
|
116
|
+
{ registry = DEFAULT_REGISTRY, timeoutMs = DEFAULT_TIMEOUT_MS } = {},
|
|
117
|
+
) {
|
|
118
|
+
const summary = await getPackageSummary(name, {
|
|
119
|
+
registry,
|
|
120
|
+
timeoutMs,
|
|
121
|
+
});
|
|
122
|
+
const info = summary?.versions[version];
|
|
123
|
+
if (!summary || !info) return null;
|
|
124
|
+
return {
|
|
125
|
+
createdAt: info.createdAt,
|
|
126
|
+
deprecated: info.deprecated,
|
|
127
|
+
isLatest: summary.latestVersion === version,
|
|
128
|
+
latestVersion: summary.latestVersion,
|
|
129
|
+
};
|
|
108
130
|
}
|
|
109
131
|
async function mapWithConcurrency(items, limit, fn) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
132
|
+
const results = new Array(items.length);
|
|
133
|
+
let index = 0;
|
|
134
|
+
async function worker() {
|
|
135
|
+
while (index < items.length) {
|
|
136
|
+
const i = index++;
|
|
137
|
+
results[i] = await fn(items[i], i);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
await Promise.all(
|
|
141
|
+
Array.from({ length: Math.min(limit, items.length) }, worker),
|
|
142
|
+
);
|
|
143
|
+
return results;
|
|
120
144
|
}
|
|
121
145
|
/**
|
|
122
|
-
* Adds a `metadata` field to every package of the report.
|
|
123
|
-
* Failed lookups result in `metadata: null` and are passed to `onError`.
|
|
124
|
-
*/
|
|
125
|
-
async function withPackagesMetadata(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
* Adds a `metadata` field to every package of the report.
|
|
147
|
+
* Failed lookups result in `metadata: null` and are passed to `onError`.
|
|
148
|
+
*/
|
|
149
|
+
async function withPackagesMetadata(
|
|
150
|
+
packages,
|
|
151
|
+
{
|
|
152
|
+
registry = DEFAULT_REGISTRY,
|
|
153
|
+
timeoutMs = DEFAULT_TIMEOUT_MS,
|
|
154
|
+
concurrency = DEFAULT_CONCURRENCY,
|
|
155
|
+
onError = () => {},
|
|
156
|
+
} = {},
|
|
157
|
+
) {
|
|
158
|
+
return mapWithConcurrency(packages, concurrency, async (pkg) => {
|
|
159
|
+
if (!pkg.version)
|
|
160
|
+
return {
|
|
161
|
+
...pkg,
|
|
162
|
+
metadata: null,
|
|
163
|
+
};
|
|
164
|
+
try {
|
|
165
|
+
const metadata = await getPackageMetadata(pkg.name, pkg.version, {
|
|
166
|
+
registry,
|
|
167
|
+
timeoutMs,
|
|
168
|
+
});
|
|
169
|
+
return {
|
|
170
|
+
...pkg,
|
|
171
|
+
metadata,
|
|
172
|
+
};
|
|
173
|
+
} catch (error) {
|
|
174
|
+
onError(error, pkg);
|
|
175
|
+
return {
|
|
176
|
+
...pkg,
|
|
177
|
+
metadata: null,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
});
|
|
148
181
|
}
|
|
149
182
|
//#endregion
|
|
150
183
|
//#region src/parseUtils.ts
|
|
151
184
|
function isNumericId(node) {
|
|
152
|
-
|
|
185
|
+
return (
|
|
186
|
+
node.type === "Literal" &&
|
|
187
|
+
node.value !== null &&
|
|
188
|
+
node.value !== void 0 &&
|
|
189
|
+
Number.isInteger(node.value) &&
|
|
190
|
+
node.value >= 0
|
|
191
|
+
);
|
|
153
192
|
}
|
|
154
193
|
function isModuleId(node) {
|
|
155
|
-
|
|
194
|
+
return (
|
|
195
|
+
node !== null &&
|
|
196
|
+
node.type === "Literal" &&
|
|
197
|
+
(isNumericId(node) || typeof node.value === "string")
|
|
198
|
+
);
|
|
156
199
|
}
|
|
157
200
|
function isModuleWrapper(node) {
|
|
158
|
-
|
|
201
|
+
return (
|
|
202
|
+
((node.type === "FunctionExpression" ||
|
|
203
|
+
node.type === "ArrowFunctionExpression") &&
|
|
204
|
+
!node.id) ||
|
|
205
|
+
isModuleId(node) ||
|
|
206
|
+
(node.type === "ArrayExpression" &&
|
|
207
|
+
node.elements.length > 1 &&
|
|
208
|
+
isModuleId(node.elements[0]))
|
|
209
|
+
);
|
|
159
210
|
}
|
|
160
211
|
function isModulesHash(node) {
|
|
161
|
-
|
|
212
|
+
return (
|
|
213
|
+
node !== null &&
|
|
214
|
+
node.type === "ObjectExpression" &&
|
|
215
|
+
node.properties
|
|
216
|
+
.filter((property) => property.type !== "SpreadElement")
|
|
217
|
+
.map((node) => node.value)
|
|
218
|
+
.every(isModuleWrapper)
|
|
219
|
+
);
|
|
162
220
|
}
|
|
163
221
|
function isModulesArray(node) {
|
|
164
|
-
|
|
222
|
+
return (
|
|
223
|
+
node !== null &&
|
|
224
|
+
node.type === "ArrayExpression" &&
|
|
225
|
+
node.elements.every((elem) => !elem || isModuleWrapper(elem))
|
|
226
|
+
);
|
|
165
227
|
}
|
|
166
228
|
function isSimpleModulesList(node) {
|
|
167
|
-
|
|
229
|
+
return isModulesHash(node) || isModulesArray(node);
|
|
168
230
|
}
|
|
169
231
|
function isOptimizedModulesArray(node) {
|
|
170
|
-
|
|
232
|
+
return (
|
|
233
|
+
node !== null &&
|
|
234
|
+
node.type === "CallExpression" &&
|
|
235
|
+
node.callee.type === "MemberExpression" &&
|
|
236
|
+
node.callee.object.type === "CallExpression" &&
|
|
237
|
+
node.callee.object.callee.type === "Identifier" &&
|
|
238
|
+
node.callee.object.callee.name === "Array" &&
|
|
239
|
+
node.callee.object.arguments.length === 1 &&
|
|
240
|
+
node.callee.object.arguments[0].type !== "SpreadElement" &&
|
|
241
|
+
isNumericId(node.callee.object.arguments[0]) &&
|
|
242
|
+
node.callee.property.type === "Identifier" &&
|
|
243
|
+
node.callee.property.name === "concat" &&
|
|
244
|
+
node.arguments.length === 1 &&
|
|
245
|
+
isModulesArray(node.arguments[0])
|
|
246
|
+
);
|
|
171
247
|
}
|
|
172
248
|
function isModulesList(node) {
|
|
173
|
-
|
|
249
|
+
return isSimpleModulesList(node) || isOptimizedModulesArray(node);
|
|
174
250
|
}
|
|
175
251
|
function getModuleLocation(node) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
252
|
+
return {
|
|
253
|
+
start: node.start,
|
|
254
|
+
end: node.end,
|
|
255
|
+
};
|
|
180
256
|
}
|
|
181
257
|
function getModulesLocations(node) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
258
|
+
if (node.type === "ObjectExpression")
|
|
259
|
+
return node.properties.reduce((result, moduleNode) => {
|
|
260
|
+
if (moduleNode.type !== "Property") return result;
|
|
261
|
+
const moduleId =
|
|
262
|
+
moduleNode.key.type === "Identifier"
|
|
263
|
+
? moduleNode.key.name
|
|
264
|
+
: moduleNode.key.value;
|
|
265
|
+
if (moduleId === "undefined") return result;
|
|
266
|
+
result[moduleId] = getModuleLocation(moduleNode.value);
|
|
267
|
+
return result;
|
|
268
|
+
}, {});
|
|
269
|
+
const isOptimizedArray = node.type === "CallExpression";
|
|
270
|
+
if (node.type === "ArrayExpression" || isOptimizedArray) {
|
|
271
|
+
const minId =
|
|
272
|
+
isOptimizedArray &&
|
|
273
|
+
node.callee.type === "MemberExpression" &&
|
|
274
|
+
node.callee.object.type === "CallExpression" &&
|
|
275
|
+
node.callee.object.arguments[0].type === "Literal"
|
|
276
|
+
? node.callee.object.arguments[0].value
|
|
277
|
+
: 0;
|
|
278
|
+
return (
|
|
279
|
+
isOptimizedArray
|
|
280
|
+
? node.arguments[0].type === "ArrayExpression"
|
|
281
|
+
? node.arguments[0].elements
|
|
282
|
+
: []
|
|
283
|
+
: node.elements
|
|
284
|
+
).reduce((result, moduleNode, i) => {
|
|
285
|
+
if (moduleNode) result[i + minId] = getModuleLocation(moduleNode);
|
|
286
|
+
return result;
|
|
287
|
+
}, {});
|
|
288
|
+
}
|
|
289
|
+
return {};
|
|
198
290
|
}
|
|
199
291
|
function getIIFECallExpression(node) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
292
|
+
if (node.expression.type === "CallExpression") return node.expression;
|
|
293
|
+
if (
|
|
294
|
+
node.expression.type === "UnaryExpression" &&
|
|
295
|
+
node.expression.argument.type === "CallExpression"
|
|
296
|
+
)
|
|
297
|
+
return node.expression.argument;
|
|
298
|
+
return null;
|
|
203
299
|
}
|
|
204
300
|
function callsModulesMap(node, modulesVariableName) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
301
|
+
let callsModule = false;
|
|
302
|
+
acorn_walk.simple(node, {
|
|
303
|
+
CallExpression(callExpression) {
|
|
304
|
+
const { callee } = callExpression;
|
|
305
|
+
if (
|
|
306
|
+
callee.type === "MemberExpression" &&
|
|
307
|
+
((callee.object.type === "Identifier" &&
|
|
308
|
+
callee.object.name === modulesVariableName) ||
|
|
309
|
+
(callee.object.type === "MemberExpression" &&
|
|
310
|
+
callee.object.object.type === "Identifier" &&
|
|
311
|
+
callee.object.object.name === modulesVariableName))
|
|
312
|
+
)
|
|
313
|
+
callsModule = true;
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
return callsModule;
|
|
211
317
|
}
|
|
212
|
-
function hasWebpackModulesRuntime(
|
|
213
|
-
|
|
214
|
-
|
|
318
|
+
function hasWebpackModulesRuntime(
|
|
319
|
+
body,
|
|
320
|
+
modulesDeclaration,
|
|
321
|
+
modulesVariableName,
|
|
322
|
+
) {
|
|
323
|
+
const declarationIndex = body.body.indexOf(modulesDeclaration);
|
|
324
|
+
return body.body
|
|
325
|
+
.slice(declarationIndex + 1)
|
|
326
|
+
.some((statement) => callsModulesMap(statement, modulesVariableName));
|
|
215
327
|
}
|
|
216
328
|
function getWebpack5IIFEModulesCandidate(node, isTopLevel) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
329
|
+
if (
|
|
330
|
+
node.arguments.length !== 0 ||
|
|
331
|
+
(node.callee.type !== "FunctionExpression" &&
|
|
332
|
+
node.callee.type !== "ArrowFunctionExpression") ||
|
|
333
|
+
node.callee.params.length !== 0 ||
|
|
334
|
+
node.callee.body.type !== "BlockStatement"
|
|
335
|
+
)
|
|
336
|
+
return null;
|
|
337
|
+
const firstVariableDeclaration = node.callee.body.body.find(
|
|
338
|
+
(node) => node.type === "VariableDeclaration",
|
|
339
|
+
);
|
|
340
|
+
if (firstVariableDeclaration) {
|
|
341
|
+
for (const declaration of firstVariableDeclaration.declarations)
|
|
342
|
+
if (declaration.init && isModulesList(declaration.init)) {
|
|
343
|
+
const locations = getModulesLocations(declaration.init);
|
|
344
|
+
if (Object.keys(locations).length === 0) continue;
|
|
345
|
+
return {
|
|
346
|
+
locations,
|
|
347
|
+
hasWebpackRuntime:
|
|
348
|
+
declaration.id.type === "Identifier" &&
|
|
349
|
+
hasWebpackModulesRuntime(
|
|
350
|
+
node.callee.body,
|
|
351
|
+
firstVariableDeclaration,
|
|
352
|
+
declaration.id.name,
|
|
353
|
+
),
|
|
354
|
+
isTopLevel,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return null;
|
|
231
359
|
}
|
|
232
360
|
function selectWebpack5IIFECandidate(candidates) {
|
|
233
|
-
|
|
361
|
+
return (
|
|
362
|
+
candidates.find(
|
|
363
|
+
(candidate) => candidate.hasWebpackRuntime && candidate.isTopLevel,
|
|
364
|
+
) ||
|
|
365
|
+
candidates.find((candidate) => candidate.hasWebpackRuntime) ||
|
|
366
|
+
candidates.find((candidate) => candidate.isTopLevel) ||
|
|
367
|
+
null
|
|
368
|
+
);
|
|
234
369
|
}
|
|
235
370
|
function selectWebpack5IIFEModulesLocations(candidates, expectedModuleIds) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
371
|
+
if (candidates.length === 0) return null;
|
|
372
|
+
if (expectedModuleIds?.length) {
|
|
373
|
+
const expectedIds = new Set(expectedModuleIds.map(String));
|
|
374
|
+
const rankedCandidates = candidates
|
|
375
|
+
.map((candidate) => ({
|
|
376
|
+
candidate,
|
|
377
|
+
expectedIdsIntersection: Object.keys(candidate.locations).filter(
|
|
378
|
+
(moduleId) => expectedIds.has(moduleId),
|
|
379
|
+
).length,
|
|
380
|
+
}))
|
|
381
|
+
.toSorted(
|
|
382
|
+
(candidateA, candidateB) =>
|
|
383
|
+
candidateB.expectedIdsIntersection -
|
|
384
|
+
candidateA.expectedIdsIntersection,
|
|
385
|
+
);
|
|
386
|
+
if (rankedCandidates[0].expectedIdsIntersection > 0)
|
|
387
|
+
return (
|
|
388
|
+
selectWebpack5IIFECandidate(
|
|
389
|
+
rankedCandidates
|
|
390
|
+
.filter(
|
|
391
|
+
(rankedCandidate) =>
|
|
392
|
+
rankedCandidate.expectedIdsIntersection ===
|
|
393
|
+
rankedCandidates[0].expectedIdsIntersection,
|
|
394
|
+
)
|
|
395
|
+
.map((rankedCandidate) => rankedCandidate.candidate),
|
|
396
|
+
)?.locations || null
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
return selectWebpack5IIFECandidate(candidates)?.locations || null;
|
|
246
400
|
}
|
|
247
401
|
function isChunkIds(node) {
|
|
248
|
-
|
|
402
|
+
return node.type === "ArrayExpression" && node.elements.every(isModuleId);
|
|
249
403
|
}
|
|
250
404
|
function mayBeAsyncChunkArguments(args) {
|
|
251
|
-
|
|
405
|
+
return (
|
|
406
|
+
args.length >= 2 &&
|
|
407
|
+
args[0] !== null &&
|
|
408
|
+
args[0].type !== "SpreadElement" &&
|
|
409
|
+
isChunkIds(args[0])
|
|
410
|
+
);
|
|
252
411
|
}
|
|
253
412
|
/** Returns bundle source except modules */
|
|
254
413
|
function getBundleRuntime(content, modulesLocations) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
414
|
+
const sortedLocations = Object.values(modulesLocations || {}).toSorted(
|
|
415
|
+
(a, b) => a.start - b.start,
|
|
416
|
+
);
|
|
417
|
+
let result = "";
|
|
418
|
+
let lastIndex = 0;
|
|
419
|
+
for (const { start, end } of sortedLocations) {
|
|
420
|
+
result += content.slice(lastIndex, start);
|
|
421
|
+
lastIndex = end;
|
|
422
|
+
}
|
|
423
|
+
return result + content.slice(lastIndex);
|
|
263
424
|
}
|
|
264
425
|
function isAsyncChunkPushExpression(node) {
|
|
265
|
-
|
|
266
|
-
|
|
426
|
+
const { callee, arguments: args } = node;
|
|
427
|
+
return (
|
|
428
|
+
callee.type === "MemberExpression" &&
|
|
429
|
+
callee.property.type === "Identifier" &&
|
|
430
|
+
callee.property.name === "push" &&
|
|
431
|
+
callee.object.type === "AssignmentExpression" &&
|
|
432
|
+
args.length === 1 &&
|
|
433
|
+
args[0].type === "ArrayExpression" &&
|
|
434
|
+
mayBeAsyncChunkArguments(args[0].elements) &&
|
|
435
|
+
isModulesList(args[0].elements[1])
|
|
436
|
+
);
|
|
267
437
|
}
|
|
268
438
|
function isAsyncWebWorkerChunkExpression(node) {
|
|
269
|
-
|
|
270
|
-
|
|
439
|
+
const { callee, type, arguments: args } = node;
|
|
440
|
+
return (
|
|
441
|
+
type === "CallExpression" &&
|
|
442
|
+
callee.type === "MemberExpression" &&
|
|
443
|
+
args.length === 2 &&
|
|
444
|
+
args[0].type !== "SpreadElement" &&
|
|
445
|
+
isChunkIds(args[0]) &&
|
|
446
|
+
isModulesList(args[1])
|
|
447
|
+
);
|
|
271
448
|
}
|
|
272
449
|
function parseBundle(bundlePath, opts) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
450
|
+
const { sourceType = "script", expectedModuleIds } = opts || {};
|
|
451
|
+
const content = node_fs.default.readFileSync(bundlePath, "utf8");
|
|
452
|
+
const ast = acorn.parse(content, {
|
|
453
|
+
sourceType,
|
|
454
|
+
ecmaVersion: "latest",
|
|
455
|
+
});
|
|
456
|
+
const topLevelIIFECalls = /* @__PURE__ */ new Set();
|
|
457
|
+
for (const node of ast.body)
|
|
458
|
+
if (node.type === "ExpressionStatement") {
|
|
459
|
+
const iifeCall = getIIFECallExpression(node);
|
|
460
|
+
if (iifeCall) topLevelIIFECalls.add(iifeCall);
|
|
461
|
+
}
|
|
462
|
+
const walkState = {
|
|
463
|
+
locations: null,
|
|
464
|
+
webpack5IIFECandidates: [],
|
|
465
|
+
};
|
|
466
|
+
acorn_walk.recursive(ast, walkState, {
|
|
467
|
+
AssignmentExpression(node, state) {
|
|
468
|
+
if (state.locations) return;
|
|
469
|
+
const { left, right } = node;
|
|
470
|
+
if (
|
|
471
|
+
left &&
|
|
472
|
+
left.type === "MemberExpression" &&
|
|
473
|
+
left.object &&
|
|
474
|
+
left.object.type === "Identifier" &&
|
|
475
|
+
left.object.name === "exports" &&
|
|
476
|
+
left.property &&
|
|
477
|
+
left.property.type === "Identifier" &&
|
|
478
|
+
left.property.name === "modules" &&
|
|
479
|
+
isModulesHash(right)
|
|
480
|
+
)
|
|
481
|
+
state.locations = getModulesLocations(right);
|
|
482
|
+
},
|
|
483
|
+
CallExpression(node, state, callback) {
|
|
484
|
+
if (state.locations) return;
|
|
485
|
+
const args = node.arguments;
|
|
486
|
+
const webpack5IIFEModulesCandidate = getWebpack5IIFEModulesCandidate(
|
|
487
|
+
node,
|
|
488
|
+
topLevelIIFECalls.has(node),
|
|
489
|
+
);
|
|
490
|
+
if (webpack5IIFEModulesCandidate)
|
|
491
|
+
state.webpack5IIFECandidates.push(webpack5IIFEModulesCandidate);
|
|
492
|
+
if (
|
|
493
|
+
node.callee.type === "FunctionExpression" &&
|
|
494
|
+
!node.callee.id &&
|
|
495
|
+
args.length === 1 &&
|
|
496
|
+
isSimpleModulesList(args[0])
|
|
497
|
+
) {
|
|
498
|
+
state.locations = getModulesLocations(args[0]);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
// webpackJsonp([<chunks>], <modules>, ...)
|
|
502
|
+
if (
|
|
503
|
+
node.callee.type === "Identifier" &&
|
|
504
|
+
mayBeAsyncChunkArguments(args) &&
|
|
505
|
+
args[1].type !== "SpreadElement" &&
|
|
506
|
+
isModulesList(args[1])
|
|
507
|
+
) {
|
|
508
|
+
state.locations = getModulesLocations(args[1]);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (
|
|
512
|
+
isAsyncChunkPushExpression(node) &&
|
|
513
|
+
args[0].type === "ArrayExpression" &&
|
|
514
|
+
args[0].elements[1]
|
|
515
|
+
) {
|
|
516
|
+
state.locations = getModulesLocations(args[0].elements[1]);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
if (isAsyncWebWorkerChunkExpression(node)) {
|
|
520
|
+
state.locations = getModulesLocations(args[1]);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
for (const arg of args) callback(arg, state);
|
|
524
|
+
},
|
|
525
|
+
});
|
|
526
|
+
const modulesLocations =
|
|
527
|
+
walkState.locations ||
|
|
528
|
+
selectWebpack5IIFEModulesLocations(
|
|
529
|
+
walkState.webpack5IIFECandidates,
|
|
530
|
+
expectedModuleIds,
|
|
531
|
+
);
|
|
532
|
+
const modules = {};
|
|
533
|
+
if (modulesLocations)
|
|
534
|
+
for (const [id, loc] of Object.entries(modulesLocations))
|
|
535
|
+
modules[id] = content.slice(loc.start, loc.end);
|
|
536
|
+
return {
|
|
537
|
+
modules,
|
|
538
|
+
src: content,
|
|
539
|
+
runtimeSrc: getBundleRuntime(content, modulesLocations),
|
|
540
|
+
};
|
|
327
541
|
}
|
|
328
542
|
//#endregion
|
|
329
543
|
//#region src/webpack.ts
|
|
330
544
|
const NAME$1 = name;
|
|
331
545
|
const packageRegex = /(?:^|\/)node_modules\/((?:@[^/]+\/)?[^/]+)/g;
|
|
332
546
|
/**
|
|
333
|
-
* Simple Webpack/Rspack plugin
|
|
334
|
-
* to adapt stats object https://webpack.js.org/api/stats/
|
|
335
|
-
* to metro-stats.json format used by `react-native-bundle-discovery`
|
|
336
|
-
*/
|
|
547
|
+
* Simple Webpack/Rspack plugin
|
|
548
|
+
* to adapt stats object https://webpack.js.org/api/stats/
|
|
549
|
+
* to metro-stats.json format used by `react-native-bundle-discovery`
|
|
550
|
+
*/
|
|
337
551
|
var BundleDiscoveryPlugin = class {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
552
|
+
options;
|
|
553
|
+
filename;
|
|
554
|
+
enabled;
|
|
555
|
+
fetchPackagesMetadata;
|
|
556
|
+
constructor({ filename, options, enabled, fetchPackagesMetadata } = {}) {
|
|
557
|
+
this.options = options;
|
|
558
|
+
this.filename = filename || "metro-stats.json";
|
|
559
|
+
this.enabled = enabled ?? true;
|
|
560
|
+
this.fetchPackagesMetadata = fetchPackagesMetadata ?? true;
|
|
561
|
+
}
|
|
562
|
+
extractSizesFromJsBundle(statAsset, options) {
|
|
563
|
+
const assetFile = node_path.default.join(
|
|
564
|
+
options.output.path,
|
|
565
|
+
statAsset.name,
|
|
566
|
+
);
|
|
567
|
+
try {
|
|
568
|
+
return parseBundle(assetFile, {
|
|
569
|
+
sourceType: statAsset.info.javascriptModule ? "module" : "script",
|
|
570
|
+
});
|
|
571
|
+
} catch {
|
|
572
|
+
return null;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
apply(compiler) {
|
|
576
|
+
if (!this.enabled) return;
|
|
577
|
+
compiler.hooks.done.tap("GenerateStatsJsonPlugin", (stats) => {
|
|
578
|
+
const json = stats.toJson({
|
|
579
|
+
version: true,
|
|
580
|
+
builtAt: true,
|
|
581
|
+
modules: true,
|
|
582
|
+
reasons: true,
|
|
583
|
+
assets: true,
|
|
584
|
+
ids: true,
|
|
585
|
+
...this.options,
|
|
586
|
+
all: false,
|
|
587
|
+
source: true,
|
|
588
|
+
});
|
|
589
|
+
const statsJson = this.formatStat(
|
|
590
|
+
json,
|
|
591
|
+
this.extractSizesFromJsBundle(json.assets[0], compiler.options),
|
|
592
|
+
compiler.options,
|
|
593
|
+
);
|
|
594
|
+
const outputPath = node_path.default.resolve(
|
|
595
|
+
compiler.options.context,
|
|
596
|
+
this.filename,
|
|
597
|
+
);
|
|
598
|
+
const keepAlive = setInterval(() => {}, 1e3);
|
|
599
|
+
this.writeReport(statsJson, outputPath)
|
|
600
|
+
.catch((error) => {
|
|
601
|
+
console.error(
|
|
602
|
+
`${chalk.default.yellow(`[${NAME$1}]`)}: Failed to create JSON report: ${error.message}`,
|
|
603
|
+
);
|
|
604
|
+
})
|
|
605
|
+
.finally(() => clearInterval(keepAlive));
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
async writeReport(statsJson, outputPath) {
|
|
609
|
+
if (this.fetchPackagesMetadata)
|
|
610
|
+
statsJson.packages = await withPackagesMetadata(statsJson.packages, {
|
|
611
|
+
onError: (error, pkg) => {
|
|
612
|
+
console.warn(
|
|
613
|
+
`${chalk.default.yellow(`[${NAME$1}]`)}: Failed to fetch metadata for ${pkg.name}@${pkg.version}: ${error.message}`,
|
|
614
|
+
);
|
|
615
|
+
},
|
|
616
|
+
});
|
|
617
|
+
node_fs.default.writeFileSync(
|
|
618
|
+
outputPath,
|
|
619
|
+
JSON.stringify(statsJson, null, 2),
|
|
620
|
+
);
|
|
621
|
+
console.log(
|
|
622
|
+
`${chalk.default.yellow(`[${NAME$1}]`)}: Saved stats to ${chalk.default.green(outputPath)}`,
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
readSource(filePath) {
|
|
626
|
+
const fallback = {
|
|
627
|
+
code: "",
|
|
628
|
+
lineCount: 0,
|
|
629
|
+
sizeInBytes: 0,
|
|
630
|
+
};
|
|
631
|
+
try {
|
|
632
|
+
const code = node_fs.default.readFileSync(filePath, "utf-8");
|
|
633
|
+
const lineCount = code.split("\n").length;
|
|
634
|
+
const sizeInBytes = Buffer.byteLength(code, "utf-8");
|
|
635
|
+
return {
|
|
636
|
+
code: this.options?.source === false ? "" : code,
|
|
637
|
+
lineCount,
|
|
638
|
+
sizeInBytes,
|
|
639
|
+
};
|
|
640
|
+
} catch {
|
|
641
|
+
return fallback;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
getPkgVersionFromPath(path) {
|
|
645
|
+
try {
|
|
646
|
+
const matches = [...path.matchAll(/\.pnpm\/([^/]+)\/node_modules/g)];
|
|
647
|
+
if (!matches.length) return null;
|
|
648
|
+
const versionMatch =
|
|
649
|
+
matches[matches.length - 1][1].match(/^@?[^@]+@([^_]+)/);
|
|
650
|
+
return versionMatch ? versionMatch[1] : null;
|
|
651
|
+
} catch {
|
|
652
|
+
return "";
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
getPackages(statsJson) {
|
|
656
|
+
const packagesMap = /* @__PURE__ */ new Map();
|
|
657
|
+
for (const mdl of statsJson.modules) {
|
|
658
|
+
const filePath = mdl.nameForCondition;
|
|
659
|
+
if (!filePath) continue;
|
|
660
|
+
let lastMatch = null;
|
|
661
|
+
packageRegex.lastIndex = 0;
|
|
662
|
+
let match = packageRegex.exec(filePath);
|
|
663
|
+
while (match !== null) {
|
|
664
|
+
lastMatch = match;
|
|
665
|
+
match = packageRegex.exec(filePath);
|
|
666
|
+
}
|
|
667
|
+
if (!lastMatch) continue;
|
|
668
|
+
const packageName = lastMatch[1];
|
|
669
|
+
const matchIndex = lastMatch.index;
|
|
670
|
+
const cutIndex =
|
|
671
|
+
matchIndex +
|
|
672
|
+
(filePath[matchIndex] === "/" ? 1 : 0) +
|
|
673
|
+
13 +
|
|
674
|
+
packageName.length;
|
|
675
|
+
const absolutePath = filePath.slice(0, cutIndex);
|
|
676
|
+
let version = "";
|
|
677
|
+
try {
|
|
678
|
+
version = require(
|
|
679
|
+
node_path.default.join(absolutePath, "package.json"),
|
|
680
|
+
).version;
|
|
681
|
+
} catch (e) {
|
|
682
|
+
const verFromPath = this.getPkgVersionFromPath(absolutePath);
|
|
683
|
+
if (verFromPath) version = verFromPath;
|
|
684
|
+
else if (e?.code === "MODULE_NOT_FOUND")
|
|
685
|
+
console.warn(`[${NAME$1}] getPackages: unexpected path resolution`, {
|
|
686
|
+
filePath,
|
|
687
|
+
absolutePath,
|
|
688
|
+
});
|
|
689
|
+
else throw e;
|
|
690
|
+
}
|
|
691
|
+
if (!packagesMap.has(absolutePath))
|
|
692
|
+
packagesMap.set(absolutePath, {
|
|
693
|
+
name: packageName,
|
|
694
|
+
absolutePath,
|
|
695
|
+
version,
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
return Array.from(packagesMap.values());
|
|
699
|
+
}
|
|
700
|
+
getEntryFile(statsJson, rootFolder) {
|
|
701
|
+
const fallbackValue = node_path.default.join(rootFolder, "index.js");
|
|
702
|
+
return (
|
|
703
|
+
statsJson.modules.find(
|
|
704
|
+
(mdl) =>
|
|
705
|
+
!mdl.nameForCondition?.includes("node_modules/") &&
|
|
706
|
+
mdl.reasons?.length === 1 &&
|
|
707
|
+
mdl.reasons?.[0].type === "entry",
|
|
708
|
+
)?.nameForCondition || fallbackValue
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
getModuleOutput(mdl, bundleModules) {
|
|
712
|
+
const jsCodeStrFromJSBundle = bundleModules?.modules?.[String(mdl.id)];
|
|
713
|
+
if (jsCodeStrFromJSBundle) {
|
|
714
|
+
const formatted =
|
|
715
|
+
jsCodeStrFromJSBundle.startsWith("function(") &&
|
|
716
|
+
jsCodeStrFromJSBundle.endsWith("}")
|
|
717
|
+
? jsCodeStrFromJSBundle.replace("function(", "function module(")
|
|
718
|
+
: jsCodeStrFromJSBundle;
|
|
719
|
+
return {
|
|
720
|
+
code: formatted,
|
|
721
|
+
lineCount: formatted.split("\n").length ?? 0,
|
|
722
|
+
sizeInBytes: Buffer.byteLength(jsCodeStrFromJSBundle, "utf-8"),
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
return {
|
|
726
|
+
code: mdl.source ?? "",
|
|
727
|
+
lineCount: mdl.source?.split("\n").length ?? 0,
|
|
728
|
+
sizeInBytes: mdl.size ?? 0,
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
formatStat(statsJson, bundleModules, compilerOptions) {
|
|
732
|
+
const modulesDeps = this.buildImportsMapFromReasons(
|
|
733
|
+
statsJson,
|
|
734
|
+
compilerOptions,
|
|
735
|
+
);
|
|
736
|
+
const context = compilerOptions.context;
|
|
737
|
+
return {
|
|
738
|
+
kind: "webpack",
|
|
739
|
+
date: statsJson.builtAt || Date.now(),
|
|
740
|
+
entryPoint: this.getEntryFile(statsJson, context),
|
|
741
|
+
rootFolder:
|
|
742
|
+
this.findCommonRoot(
|
|
743
|
+
statsJson.modules
|
|
744
|
+
.map((m) => m.nameForCondition)
|
|
745
|
+
.filter((p) => Boolean(p)),
|
|
746
|
+
) || context,
|
|
747
|
+
transformOptions: {
|
|
748
|
+
dev: compilerOptions.mode !== "production",
|
|
749
|
+
minify: compilerOptions.optimization?.minimize ?? false,
|
|
750
|
+
platform: compilerOptions.name ?? "ios",
|
|
751
|
+
},
|
|
752
|
+
modules: statsJson.modules
|
|
753
|
+
.map((mdl) => {
|
|
754
|
+
if (mdl.type === "runtime modules") {
|
|
755
|
+
if (!bundleModules) return null;
|
|
756
|
+
const sourceAndOutput = {
|
|
757
|
+
code: bundleModules.runtimeSrc ?? "",
|
|
758
|
+
lineCount: bundleModules.runtimeSrc?.split("\n").length ?? 0,
|
|
759
|
+
sizeInBytes: Buffer.byteLength(
|
|
760
|
+
bundleModules.runtimeSrc ?? "",
|
|
761
|
+
"utf-8",
|
|
762
|
+
),
|
|
763
|
+
};
|
|
764
|
+
return {
|
|
765
|
+
path: "__runtime__",
|
|
766
|
+
source: sourceAndOutput,
|
|
767
|
+
output: sourceAndOutput,
|
|
768
|
+
dependencies: [],
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
if (!mdl.nameForCondition) return null;
|
|
772
|
+
return {
|
|
773
|
+
path: mdl.nameForCondition,
|
|
774
|
+
source: this.readSource(mdl.nameForCondition),
|
|
775
|
+
output: this.getModuleOutput(mdl, bundleModules),
|
|
776
|
+
dependencies: modulesDeps.get(mdl.nameForCondition) ?? [],
|
|
777
|
+
};
|
|
778
|
+
})
|
|
779
|
+
.filter((e) => e !== null && Boolean(e.path)),
|
|
780
|
+
packages: this.getPackages(statsJson),
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
buildImportsMapFromReasons(statsJson, compilerOptions) {
|
|
784
|
+
const modules = Array.isArray(statsJson?.modules) ? statsJson.modules : [];
|
|
785
|
+
const importsMap = /* @__PURE__ */ new Map();
|
|
786
|
+
const getAbs = (p) => {
|
|
787
|
+
if (!p || typeof p !== "string") return null;
|
|
788
|
+
if (node_path.default.isAbsolute(p)) return p;
|
|
789
|
+
return compilerOptions?.context
|
|
790
|
+
? node_path.default.resolve(compilerOptions?.context, p)
|
|
791
|
+
: p;
|
|
792
|
+
};
|
|
793
|
+
const getModulePath = (m) =>
|
|
794
|
+
m?.path || m?.nameForCondition || m?.identifier || null;
|
|
795
|
+
for (const depModule of modules) {
|
|
796
|
+
const depAbsolutePath = getAbs(getModulePath(depModule));
|
|
797
|
+
if (!depAbsolutePath) continue;
|
|
798
|
+
const reasons = Array.isArray(depModule.reasons) ? depModule.reasons : [];
|
|
799
|
+
for (const reason of reasons) {
|
|
800
|
+
if (reason?.type === "entry") continue;
|
|
801
|
+
const importerPath = getAbs(
|
|
802
|
+
reason?.modulePath ||
|
|
803
|
+
reason?.moduleNameForCondition ||
|
|
804
|
+
reason?.resolvedModule ||
|
|
805
|
+
reason?.moduleIdentifier,
|
|
806
|
+
);
|
|
807
|
+
if (!importerPath) continue;
|
|
808
|
+
let deps = importsMap.get(importerPath);
|
|
809
|
+
if (!deps) {
|
|
810
|
+
deps = [];
|
|
811
|
+
importsMap.set(importerPath, deps);
|
|
812
|
+
}
|
|
813
|
+
if (!deps.some((d) => d.absolutePath === depAbsolutePath))
|
|
814
|
+
deps.push({
|
|
815
|
+
absolutePath: depAbsolutePath,
|
|
816
|
+
name: reason?.userRequest || "",
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return importsMap;
|
|
821
|
+
}
|
|
822
|
+
findCommonRoot(paths) {
|
|
823
|
+
if (!paths || paths.length === 0) return "";
|
|
824
|
+
if (paths.length === 1) {
|
|
825
|
+
const lastSlash = paths[0].lastIndexOf("/");
|
|
826
|
+
return lastSlash === -1 ? "" : paths[0].slice(0, lastSlash);
|
|
827
|
+
}
|
|
828
|
+
const first = paths[0];
|
|
829
|
+
let maxLen = first.length;
|
|
830
|
+
for (let i = 1; i < paths.length; i++) {
|
|
831
|
+
const current = paths[i];
|
|
832
|
+
const limit = Math.min(maxLen, current.length);
|
|
833
|
+
let j = 0;
|
|
834
|
+
while (j < limit && first.charCodeAt(j) === current.charCodeAt(j)) j++;
|
|
835
|
+
maxLen = j;
|
|
836
|
+
if (maxLen === 0) return "";
|
|
837
|
+
}
|
|
838
|
+
if (maxLen === first.length) {
|
|
839
|
+
const lastSlash = first.lastIndexOf("/");
|
|
840
|
+
return lastSlash === -1 ? "" : first.slice(0, lastSlash);
|
|
841
|
+
}
|
|
842
|
+
const commonSlice = first.slice(0, maxLen);
|
|
843
|
+
const lastSlash = commonSlice.lastIndexOf("/");
|
|
844
|
+
return lastSlash === -1 ? "" : commonSlice.slice(0, lastSlash);
|
|
845
|
+
}
|
|
564
846
|
};
|
|
565
847
|
//#endregion
|
|
566
848
|
//#region src/index.ts
|
|
567
849
|
const NAME = name;
|
|
568
850
|
function getDefault(module) {
|
|
569
|
-
|
|
851
|
+
return module.__esModule ? module.default : module;
|
|
570
852
|
}
|
|
571
853
|
function getDefaultSerializer() {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
854
|
+
const metroPath = (0, node_path.parse)(
|
|
855
|
+
require.resolve("metro/package.json"),
|
|
856
|
+
).dir;
|
|
857
|
+
const bundleToString = getDefault(
|
|
858
|
+
require(`${metroPath}/src/lib/bundleToString.js`),
|
|
859
|
+
);
|
|
860
|
+
const baseJSBundle = getDefault(
|
|
861
|
+
require(`${metroPath}/src/DeltaBundler/Serializers/baseJSBundle.js`),
|
|
862
|
+
);
|
|
863
|
+
return function defaultSerializer(entryPoint, preModules, graph, options) {
|
|
864
|
+
let bundle = baseJSBundle(entryPoint, preModules, graph, options);
|
|
865
|
+
if (typeof options?.sentryBundleCallback === "function")
|
|
866
|
+
bundle = options.sentryBundleCallback(bundle);
|
|
867
|
+
return bundleToString(bundle).code;
|
|
868
|
+
};
|
|
580
869
|
}
|
|
581
870
|
function getStringSizeInBytes(str) {
|
|
582
|
-
|
|
871
|
+
return node_buffer.Buffer.byteLength(str, "utf8");
|
|
583
872
|
}
|
|
584
873
|
/**
|
|
585
|
-
* `/Users/i/app/node_modules/metro/node_modules/@babel/runtime/helpers/createClass.js` -> `@babel/runtime`
|
|
586
|
-
* `/Users/i/app/node_modules/react/jsx-runtime.js` -> `react`
|
|
587
|
-
*/
|
|
874
|
+
* `/Users/i/app/node_modules/metro/node_modules/@babel/runtime/helpers/createClass.js` -> `@babel/runtime`
|
|
875
|
+
* `/Users/i/app/node_modules/react/jsx-runtime.js` -> `react`
|
|
876
|
+
*/
|
|
588
877
|
function getPackageNameFromPath(path) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
878
|
+
const parts = path.split("node_modules/");
|
|
879
|
+
const lastPart = parts[parts.length - 1];
|
|
880
|
+
if (lastPart.startsWith("@"))
|
|
881
|
+
return lastPart.split("/").slice(0, 2).join("/");
|
|
882
|
+
return lastPart.split("/")[0];
|
|
593
883
|
}
|
|
594
884
|
/**
|
|
595
|
-
* `/Users/i/app/node_modules/metro/node_modules/@babel/runtime/helpers/createClass.js` -> `/Users/i/app/node_modules/metro/node_modules/@babel/runtime`
|
|
596
|
-
* `/Users/i/app/node_modules/react/jsx-runtime.js` -> `/Users/i/app/node_modules/react`
|
|
597
|
-
*/
|
|
885
|
+
* `/Users/i/app/node_modules/metro/node_modules/@babel/runtime/helpers/createClass.js` -> `/Users/i/app/node_modules/metro/node_modules/@babel/runtime`
|
|
886
|
+
* `/Users/i/app/node_modules/react/jsx-runtime.js` -> `/Users/i/app/node_modules/react`
|
|
887
|
+
*/
|
|
598
888
|
function getPackageAbsolutePath(path, pkgName) {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
889
|
+
const parts = path.split("node_modules/");
|
|
890
|
+
parts[parts.length - 1] = pkgName;
|
|
891
|
+
return parts.join("node_modules/");
|
|
602
892
|
}
|
|
603
893
|
function toPackages(modules) {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
894
|
+
const packages = /* @__PURE__ */ new Map();
|
|
895
|
+
modules.forEach((module) => {
|
|
896
|
+
if (!module.path.includes("node_modules/")) return;
|
|
897
|
+
const pkgName = getPackageNameFromPath(module.path);
|
|
898
|
+
const absolutePkgPath = getPackageAbsolutePath(module.path, pkgName);
|
|
899
|
+
if (!packages.has(absolutePkgPath))
|
|
900
|
+
packages.set(absolutePkgPath, {
|
|
901
|
+
name: pkgName,
|
|
902
|
+
absolutePath: absolutePkgPath,
|
|
903
|
+
version: require(
|
|
904
|
+
(0, node_path.resolve)(absolutePkgPath, "package.json"),
|
|
905
|
+
).version,
|
|
906
|
+
});
|
|
907
|
+
});
|
|
908
|
+
return Array.from(packages.values()).sort((a, b) =>
|
|
909
|
+
a.name.localeCompare(b.name),
|
|
910
|
+
);
|
|
616
911
|
}
|
|
617
912
|
function toModuleStruct(m, includeCode) {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
913
|
+
const sourceCode = m.getSource().toString("utf8");
|
|
914
|
+
const outputCode = m.output[0].data.code;
|
|
915
|
+
return {
|
|
916
|
+
path: m.path,
|
|
917
|
+
source: {
|
|
918
|
+
code: includeCode ? sourceCode : "",
|
|
919
|
+
lineCount: sourceCode.split("\n").length,
|
|
920
|
+
sizeInBytes: getStringSizeInBytes(sourceCode),
|
|
921
|
+
},
|
|
922
|
+
output: {
|
|
923
|
+
code: includeCode ? outputCode : "",
|
|
924
|
+
lineCount: m.output[0].data.lineCount,
|
|
925
|
+
sizeInBytes: getStringSizeInBytes(outputCode),
|
|
926
|
+
},
|
|
927
|
+
dependencies: Array.from(m?.dependencies?.values?.() ?? [])
|
|
928
|
+
.filter((e) => e.absolutePath)
|
|
929
|
+
.map((e) => ({
|
|
930
|
+
absolutePath: e.absolutePath,
|
|
931
|
+
name: e.data.name,
|
|
932
|
+
})),
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
async function createJsonReport({
|
|
936
|
+
graph,
|
|
937
|
+
entryPoint,
|
|
938
|
+
includeEnvs,
|
|
939
|
+
preModules,
|
|
940
|
+
includeCode,
|
|
941
|
+
outputJsonPath,
|
|
942
|
+
rootFolder,
|
|
943
|
+
silent,
|
|
944
|
+
options,
|
|
945
|
+
fetchPackagesMetadata,
|
|
946
|
+
}) {
|
|
947
|
+
const { processModuleFilter = () => true } = options || {};
|
|
948
|
+
const dependencies = Array.from(graph.dependencies.values()).filter(
|
|
949
|
+
processModuleFilter,
|
|
950
|
+
);
|
|
951
|
+
let packages = toPackages(preModules).concat(toPackages(dependencies));
|
|
952
|
+
const modules = preModules
|
|
953
|
+
.map((m) => toModuleStruct(m, includeCode))
|
|
954
|
+
.concat(dependencies.map((m) => toModuleStruct(m, includeCode)));
|
|
955
|
+
if (fetchPackagesMetadata)
|
|
956
|
+
packages = await withPackagesMetadata(packages, {
|
|
957
|
+
onError: (error, pkg) => {
|
|
958
|
+
if (!silent)
|
|
959
|
+
console.warn(
|
|
960
|
+
`${chalk.default.yellow(`[${NAME}]`)}: Failed to fetch metadata for ${pkg.name}@${pkg.version}: ${error.message}`,
|
|
961
|
+
);
|
|
962
|
+
},
|
|
963
|
+
});
|
|
964
|
+
const stats = {
|
|
965
|
+
date: Date.now(),
|
|
966
|
+
entryPoint,
|
|
967
|
+
transformOptions: graph.transformOptions,
|
|
968
|
+
envs: includeEnvs.reduce((acc, envName) => {
|
|
969
|
+
acc[envName] = process.env[envName];
|
|
970
|
+
return acc;
|
|
971
|
+
}, {}),
|
|
972
|
+
rootFolder,
|
|
973
|
+
packages,
|
|
974
|
+
modules,
|
|
975
|
+
};
|
|
976
|
+
(0, node_fs.writeFileSync)(outputJsonPath, JSON.stringify(stats));
|
|
977
|
+
if (!silent)
|
|
978
|
+
console.log(
|
|
979
|
+
`${chalk.default.yellow(`[${NAME}]`)}: Saved stats to ${chalk.default.green(outputJsonPath)}`,
|
|
980
|
+
);
|
|
660
981
|
}
|
|
661
982
|
/**
|
|
662
|
-
* Creates a custom serializer function for Metro bundler, which generates a JSON report
|
|
663
|
-
* and optionally modifies the serialization process.
|
|
664
|
-
*
|
|
665
|
-
* @param options - Configuration options for the serializer.
|
|
666
|
-
* @returns A custom serializer function to be used by Metro.
|
|
667
|
-
* @throws Throws an error if the project root does not exist.
|
|
668
|
-
*/
|
|
669
|
-
function createSerializer({
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
983
|
+
* Creates a custom serializer function for Metro bundler, which generates a JSON report
|
|
984
|
+
* and optionally modifies the serialization process.
|
|
985
|
+
*
|
|
986
|
+
* @param options - Configuration options for the serializer.
|
|
987
|
+
* @returns A custom serializer function to be used by Metro.
|
|
988
|
+
* @throws Throws an error if the project root does not exist.
|
|
989
|
+
*/
|
|
990
|
+
function createSerializer({
|
|
991
|
+
serializer,
|
|
992
|
+
projectRoot,
|
|
993
|
+
outputJsonPath,
|
|
994
|
+
includeCode = true,
|
|
995
|
+
silent = false,
|
|
996
|
+
includeEnvs = [],
|
|
997
|
+
fetchPackagesMetadata = true,
|
|
998
|
+
} = {}) {
|
|
999
|
+
const mySerializer = serializer || getDefaultSerializer();
|
|
1000
|
+
if (!(0, node_fs.existsSync)(projectRoot))
|
|
1001
|
+
throw new Error(`[${NAME}]: Project root does not exist: ${projectRoot}`);
|
|
1002
|
+
const myOutputJsonPath =
|
|
1003
|
+
outputJsonPath ?? (0, node_path.resolve)(projectRoot, "metro-stats.json");
|
|
1004
|
+
function customSerializer(entryPoint, preModules, graph, options) {
|
|
1005
|
+
const code = mySerializer(entryPoint, preModules, graph, options);
|
|
1006
|
+
const keepAlive = setInterval(() => {}, 1e3);
|
|
1007
|
+
createJsonReport({
|
|
1008
|
+
graph,
|
|
1009
|
+
entryPoint,
|
|
1010
|
+
includeEnvs,
|
|
1011
|
+
preModules,
|
|
1012
|
+
includeCode,
|
|
1013
|
+
outputJsonPath: myOutputJsonPath,
|
|
1014
|
+
rootFolder: projectRoot,
|
|
1015
|
+
silent,
|
|
1016
|
+
options,
|
|
1017
|
+
fetchPackagesMetadata,
|
|
1018
|
+
}).finally(() => clearInterval(keepAlive));
|
|
1019
|
+
return code;
|
|
1020
|
+
}
|
|
1021
|
+
return customSerializer;
|
|
691
1022
|
}
|
|
692
1023
|
const empty = { type: "empty" };
|
|
693
1024
|
/**
|
|
694
|
-
* Usage:
|
|
695
|
-
*
|
|
696
|
-
* ```js
|
|
697
|
-
* // metro.config.js
|
|
698
|
-
* const { createResolveRequest } = require("react-native-bundle-discovery");
|
|
699
|
-
* const resolveRequest = createResolveRequest({
|
|
700
|
-
* removePromisePolyfill: true,
|
|
701
|
-
* });
|
|
702
|
-
* const config = {
|
|
703
|
-
* resolver: {
|
|
704
|
-
* resolveRequest,
|
|
705
|
-
* },
|
|
706
|
-
* };
|
|
707
|
-
* ```
|
|
708
|
-
*/
|
|
709
|
-
const createResolveRequest = ({
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
1025
|
+
* Usage:
|
|
1026
|
+
*
|
|
1027
|
+
* ```js
|
|
1028
|
+
* // metro.config.js
|
|
1029
|
+
* const { createResolveRequest } = require("react-native-bundle-discovery");
|
|
1030
|
+
* const resolveRequest = createResolveRequest({
|
|
1031
|
+
* removePromisePolyfill: true,
|
|
1032
|
+
* });
|
|
1033
|
+
* const config = {
|
|
1034
|
+
* resolver: {
|
|
1035
|
+
* resolveRequest,
|
|
1036
|
+
* },
|
|
1037
|
+
* };
|
|
1038
|
+
* ```
|
|
1039
|
+
*/
|
|
1040
|
+
const createResolveRequest = ({
|
|
1041
|
+
removeNewRenderer = false,
|
|
1042
|
+
removeUTFSequence = false,
|
|
1043
|
+
} = {}) => {
|
|
1044
|
+
const resolveRequest = (context, ...rest) => {
|
|
1045
|
+
const result = context.resolveRequest(context, ...rest);
|
|
1046
|
+
if (context.dev) return result;
|
|
1047
|
+
if (
|
|
1048
|
+
removeUTFSequence &&
|
|
1049
|
+
result?.filePath?.endsWith("/react-native/Libraries/UTFSequence.js")
|
|
1050
|
+
)
|
|
1051
|
+
return empty;
|
|
1052
|
+
if (
|
|
1053
|
+
removeNewRenderer &&
|
|
1054
|
+
result?.filePath?.endsWith(
|
|
1055
|
+
"/react-native/Libraries/Renderer/shims/ReactFabric.js",
|
|
1056
|
+
)
|
|
1057
|
+
)
|
|
1058
|
+
return empty;
|
|
1059
|
+
return result;
|
|
1060
|
+
};
|
|
1061
|
+
return resolveRequest;
|
|
718
1062
|
};
|
|
719
1063
|
/**
|
|
720
|
-
* @deprecated Use `createResolveRequest` instead.
|
|
721
|
-
*/
|
|
722
|
-
const createProcessModuleFilter =
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
1064
|
+
* @deprecated Use `createResolveRequest` instead.
|
|
1065
|
+
*/
|
|
1066
|
+
const createProcessModuleFilter =
|
|
1067
|
+
({ removePromisePolyfill = false, removeUTFSequence = false } = {}) =>
|
|
1068
|
+
(module) => {
|
|
1069
|
+
if (
|
|
1070
|
+
removePromisePolyfill &&
|
|
1071
|
+
module.path.endsWith("/react-native/Libraries/Promise.js")
|
|
1072
|
+
)
|
|
1073
|
+
return false;
|
|
1074
|
+
if (
|
|
1075
|
+
removeUTFSequence &&
|
|
1076
|
+
module.path.endsWith("/react-native/Libraries/UTFSequence.js")
|
|
1077
|
+
)
|
|
1078
|
+
return false;
|
|
1079
|
+
return true;
|
|
1080
|
+
};
|
|
727
1081
|
//#endregion
|
|
728
1082
|
exports.BundleDiscoveryPlugin = BundleDiscoveryPlugin;
|
|
729
1083
|
exports.createProcessModuleFilter = createProcessModuleFilter;
|