react-native-bundle-discovery 1.0.0-rc.10
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/.discoveryrc.js +21 -0
- package/README.md +51 -0
- package/index.js +1 -0
- package/lib/bin.js +52 -0
- package/lib/customSerializer.js +167 -0
- package/package.json +43 -0
- package/pages/_common.js +266 -0
- package/pages/default.js +194 -0
- package/pages/module.js +296 -0
- package/pages/package.js +150 -0
- package/prepare.js +105 -0
- package/queryHelpers.js +329 -0
- package/setup.js +12 -0
- package/vendors/foamtree.js +9008 -0
- package/views/_theme.js +35 -0
- package/views/foamtree.js +135 -0
- package/views/global.css +127 -0
- package/views/highcharts.css +1302 -0
- package/views/highcharts.js +46 -0
package/prepare.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
function getDuplicateId(path) {
|
|
2
|
+
const uniqueNodeModulePath = path.split("node_modules/").pop();
|
|
3
|
+
const ids = [uniqueNodeModulePath];
|
|
4
|
+
|
|
5
|
+
// Special case for lodash
|
|
6
|
+
if (
|
|
7
|
+
uniqueNodeModulePath.startsWith("lodash.") ||
|
|
8
|
+
uniqueNodeModulePath.startsWith("lodash-es/")
|
|
9
|
+
) {
|
|
10
|
+
// node_modules/lodash.debounce/index.js => node_modules/lodash/debounce.js
|
|
11
|
+
// node_modules/lodash-es/get.js => node_modules/lodash/get.js
|
|
12
|
+
const uniqueLodashPath = uniqueNodeModulePath
|
|
13
|
+
.replace("lodash-es/", "lodash/")
|
|
14
|
+
.replace("lodash.", "lodash/")
|
|
15
|
+
.replace("/index.js", ".js");
|
|
16
|
+
|
|
17
|
+
ids.push(uniqueLodashPath);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return ids;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function prepare(data) {
|
|
24
|
+
// data.modules = data.modules.slice(875, 880); TODO for debugging a formtree chart
|
|
25
|
+
let moduleMap = new Map();
|
|
26
|
+
let duplicatesMap = new Map();
|
|
27
|
+
let allLodashModules = new Set();
|
|
28
|
+
|
|
29
|
+
data.packages.forEach((pkg) => {
|
|
30
|
+
pkg.path = pkg.absolutePath.replace(data.rootFolder + "/", "");
|
|
31
|
+
});
|
|
32
|
+
data.modules.forEach((m) => {
|
|
33
|
+
// 0. Data transformation
|
|
34
|
+
m.absolutePath = m.path;
|
|
35
|
+
if (m.absolutePath === data.entryPoint) {
|
|
36
|
+
m.isEntry = true;
|
|
37
|
+
}
|
|
38
|
+
m.path = m.path.replace(data.rootFolder + "/", "");
|
|
39
|
+
m.dependencies.forEach((d) => {
|
|
40
|
+
d.path = d.absolutePath.replace(data.rootFolder + "/", "");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// 1. Duplicates
|
|
44
|
+
m._tmp_ids = getDuplicateId(m.path);
|
|
45
|
+
m.duplicates = [];
|
|
46
|
+
m._tmp_ids.forEach((id) => {
|
|
47
|
+
if (!duplicatesMap.has(id)) {
|
|
48
|
+
duplicatesMap.set(id, []);
|
|
49
|
+
}
|
|
50
|
+
duplicatesMap.get(id).push(m);
|
|
51
|
+
});
|
|
52
|
+
// lodash/*
|
|
53
|
+
// lodash-es/*
|
|
54
|
+
// lodash.*
|
|
55
|
+
if (m.path.includes("node_modules/lodash")) {
|
|
56
|
+
allLodashModules.add(m);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 2. Dependencies
|
|
60
|
+
m.dependents = [];
|
|
61
|
+
moduleMap.set(m.absolutePath, m);
|
|
62
|
+
|
|
63
|
+
// 3. Other
|
|
64
|
+
// 3.1 Format prelude
|
|
65
|
+
if (m.path === "__prelude__") {
|
|
66
|
+
m.source.code = m.source.code
|
|
67
|
+
.replaceAll(";", ";\n\n")
|
|
68
|
+
.replaceAll(",", ",\n ");
|
|
69
|
+
m.output.code = m.output.code
|
|
70
|
+
.replaceAll(";", ";\n\n")
|
|
71
|
+
.replaceAll(",", ",\n ");
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
data.modules.forEach((m) => {
|
|
76
|
+
// 1. Duplicates
|
|
77
|
+
m._tmp_ids.forEach((id) => {
|
|
78
|
+
const duplicates = duplicatesMap.get(id);
|
|
79
|
+
if (duplicates.length > 1) {
|
|
80
|
+
m.duplicates.push(...duplicates.filter((d) => d !== m));
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// lodash/index.js is a special case (as index.js includes all lodash functions)
|
|
85
|
+
if (m.path.endsWith("node_modules/lodash/index.js")) {
|
|
86
|
+
m.duplicates.push(...allLodashModules);
|
|
87
|
+
}
|
|
88
|
+
delete m._tmp_ids;
|
|
89
|
+
|
|
90
|
+
// 2. Dependencies
|
|
91
|
+
m.dependencies.forEach((dependency) => {
|
|
92
|
+
const dependentModule = moduleMap.get(dependency.absolutePath);
|
|
93
|
+
if (dependentModule) {
|
|
94
|
+
dependentModule.dependents.push(m); //add to the dependent module directly
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
allLodashModules = null;
|
|
100
|
+
moduleMap = null;
|
|
101
|
+
duplicatesMap = null;
|
|
102
|
+
return data;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = prepare;
|
package/queryHelpers.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
const helpers = {
|
|
2
|
+
plural(count, [singular, plural]) {
|
|
3
|
+
return count === 1 ? singular : plural;
|
|
4
|
+
},
|
|
5
|
+
pluralWithCount(count, [singular, plural]) {
|
|
6
|
+
return `${count} ${helpers.plural(count, [singular, plural])}`;
|
|
7
|
+
},
|
|
8
|
+
pluralBadge(count, [singular, plural], prefix = "") {
|
|
9
|
+
return {
|
|
10
|
+
text: prefix + count,
|
|
11
|
+
postfix: helpers.plural(count, [singular, plural]),
|
|
12
|
+
};
|
|
13
|
+
},
|
|
14
|
+
getHighchartsColors() {
|
|
15
|
+
const Highcharts = require("highcharts");
|
|
16
|
+
return Highcharts.getOptions().colors;
|
|
17
|
+
},
|
|
18
|
+
getModulesName(path) {
|
|
19
|
+
const modules = path.split("node_modules/");
|
|
20
|
+
const lastModule = modules[modules.length - 1];
|
|
21
|
+
const [folder, subFolder] = lastModule.split("/");
|
|
22
|
+
if (folder.startsWith("@")) {
|
|
23
|
+
return `${folder}/${subFolder}`;
|
|
24
|
+
}
|
|
25
|
+
return folder;
|
|
26
|
+
},
|
|
27
|
+
getBestNetworkGraphSize(module, params) {
|
|
28
|
+
let maxParentDepth = 0;
|
|
29
|
+
let itemsCount = 0;
|
|
30
|
+
do {
|
|
31
|
+
maxParentDepth++;
|
|
32
|
+
itemsCount = helpers.getNetworkGraph(module, {
|
|
33
|
+
...params,
|
|
34
|
+
maxParentDepth,
|
|
35
|
+
}).data.length;
|
|
36
|
+
if (itemsCount < 10) {
|
|
37
|
+
const limit = itemsCount - 1;
|
|
38
|
+
return limit > 2 ? limit : 2;
|
|
39
|
+
}
|
|
40
|
+
} while (maxParentDepth < 6);
|
|
41
|
+
return maxParentDepth;
|
|
42
|
+
},
|
|
43
|
+
getNetworkGraph(
|
|
44
|
+
module,
|
|
45
|
+
{ maxParentDepth = 2, omitVisitedModules = true } = {},
|
|
46
|
+
) {
|
|
47
|
+
const queue = [{ module, parentId: "", level: 0 }];
|
|
48
|
+
const visited = new Set();
|
|
49
|
+
const result = [];
|
|
50
|
+
let entryPointPath = null;
|
|
51
|
+
const data = [];
|
|
52
|
+
|
|
53
|
+
while (queue.length > 0) {
|
|
54
|
+
const { module: currentModule, parentId, level } = queue.shift();
|
|
55
|
+
|
|
56
|
+
if (level >= Number(maxParentDepth)) {
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const id = currentModule.path;
|
|
61
|
+
|
|
62
|
+
if (omitVisitedModules) {
|
|
63
|
+
if (visited.has(id)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
visited.add(id);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (parentId) {
|
|
70
|
+
const isEntryPoint = currentModule.dependents.length === 0;
|
|
71
|
+
result.push({ isEntryPoint, id, parentId });
|
|
72
|
+
data.push([parentId, id]);
|
|
73
|
+
if (isEntryPoint) {
|
|
74
|
+
entryPointPath = id;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (Array.isArray(currentModule.dependents)) {
|
|
79
|
+
for (const dependentModule of currentModule.dependents) {
|
|
80
|
+
queue.push({
|
|
81
|
+
module: dependentModule,
|
|
82
|
+
parentId: id,
|
|
83
|
+
level: level + 1,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!entryPointPath) {
|
|
90
|
+
for (const item of result) {
|
|
91
|
+
if (item.isEntryPoint) {
|
|
92
|
+
entryPointPath = item.id;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { entryPointPath, data };
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
getExtColor(extName) {
|
|
102
|
+
const colors = {
|
|
103
|
+
js: "#f1e05a50",
|
|
104
|
+
ts: "#2b748950",
|
|
105
|
+
tsx: "#2b748950",
|
|
106
|
+
json: "#e34c2650",
|
|
107
|
+
svg: "#e69f0d50",
|
|
108
|
+
css: "#563d7c50",
|
|
109
|
+
png: "#e44b2350",
|
|
110
|
+
};
|
|
111
|
+
return colors[extName] ?? colors["js"];
|
|
112
|
+
},
|
|
113
|
+
getFileExtension(filename) {
|
|
114
|
+
const idx = filename.lastIndexOf(".");
|
|
115
|
+
return idx === -1 ? "js" : filename.slice(idx + 1);
|
|
116
|
+
},
|
|
117
|
+
toFixed(value, fractionDigits = 2) {
|
|
118
|
+
return Number(value).toFixed(fractionDigits);
|
|
119
|
+
},
|
|
120
|
+
percent(value, fractionDigits = 2) {
|
|
121
|
+
return (100 * value).toFixed(fractionDigits) + "%";
|
|
122
|
+
},
|
|
123
|
+
formatBytes(bytes, decimals) {
|
|
124
|
+
if (bytes == 0) return "0 Bytes";
|
|
125
|
+
const k = 1024,
|
|
126
|
+
dm = decimals || 2,
|
|
127
|
+
sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"],
|
|
128
|
+
i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
129
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
|
130
|
+
},
|
|
131
|
+
isPackageImport(moduleName) {
|
|
132
|
+
return moduleName?.[0] !== ".";
|
|
133
|
+
},
|
|
134
|
+
// isRuntimeCode(moduleName) {
|
|
135
|
+
// return (
|
|
136
|
+
// moduleName === "__prelude__" ||
|
|
137
|
+
// moduleName.includes("@babel/runtime") ||
|
|
138
|
+
// moduleName.includes("metro-runtime") ||
|
|
139
|
+
// moduleName.includes("@react-native/js-polyfills")
|
|
140
|
+
// );
|
|
141
|
+
// },
|
|
142
|
+
transformFilesList(files, rootFolder, type) {
|
|
143
|
+
const nodeModulesMap = { children: {}, size: 0 };
|
|
144
|
+
const sourceCodeMap = { children: {}, size: 0 };
|
|
145
|
+
|
|
146
|
+
files.forEach(({ path, size }) => {
|
|
147
|
+
if (path === "__prelude__") {
|
|
148
|
+
path = "node_modules/__prelude__";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const shortPath = path.replace(rootFolder + "/", "");
|
|
152
|
+
const isNodeModule = shortPath.includes("node_modules/");
|
|
153
|
+
const parts = shortenPath(shortPath, nodeModulesMap).split("/");
|
|
154
|
+
let current = (isNodeModule ? nodeModulesMap : sourceCodeMap).children;
|
|
155
|
+
|
|
156
|
+
parts.forEach((part, index) => {
|
|
157
|
+
// console.log((" --- xdebug " + index + " ".repeat(50)).substr(0, 40), {
|
|
158
|
+
// part,
|
|
159
|
+
// parts,
|
|
160
|
+
// });
|
|
161
|
+
if (!current[part]) {
|
|
162
|
+
current[part] = { size: 0, children: {} };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (index === parts.length - 1) {
|
|
166
|
+
current[part].size = size;
|
|
167
|
+
current[part].path = shortPath;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
current = current[part].children;
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (type === "foamtree") {
|
|
175
|
+
sumSizes(nodeModulesMap);
|
|
176
|
+
sumSizes(sourceCodeMap);
|
|
177
|
+
|
|
178
|
+
const sourceCodeGroup = toGroups(sourceCodeMap, "Source Code");
|
|
179
|
+
const nodeModulesGroup = nodeModulesMap?.children?.node_modules
|
|
180
|
+
? toGroups(nodeModulesMap.children.node_modules, "node_modules")
|
|
181
|
+
: {};
|
|
182
|
+
|
|
183
|
+
if (!sourceCodeGroup.groups) {
|
|
184
|
+
return nodeModulesGroup;
|
|
185
|
+
}
|
|
186
|
+
if (!nodeModulesGroup.groups) {
|
|
187
|
+
return nodeModulesGroup;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const topLevelNode = { groups: [sourceCodeGroup, nodeModulesGroup] };
|
|
191
|
+
topLevelNode.weight = topLevelNode.groups.reduce(
|
|
192
|
+
(acc, group) => acc + group.weight,
|
|
193
|
+
0,
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
return topLevelNode;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (type === "highcharts-treemap") {
|
|
200
|
+
const ROOT_ID_1 = "~";
|
|
201
|
+
const ROOT_ID_2 = ".";
|
|
202
|
+
return [
|
|
203
|
+
{ id: ROOT_ID_1, name: "node_modules" },
|
|
204
|
+
{ id: ROOT_ID_2, name: "Source Code" },
|
|
205
|
+
]
|
|
206
|
+
.concat(flattenTree(nodeModulesMap.children.node_modules, ROOT_ID_1))
|
|
207
|
+
.concat(flattenTree(sourceCodeMap, ROOT_ID_2));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
throw new Error("Unsupported type: " + type);
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
function flattenTree(
|
|
215
|
+
node,
|
|
216
|
+
parentId,
|
|
217
|
+
prevWasSkipped = false,
|
|
218
|
+
lvl = 0,
|
|
219
|
+
result = [],
|
|
220
|
+
overrideParentId,
|
|
221
|
+
) {
|
|
222
|
+
const nodeChildrenCount = Object.keys(node.children);
|
|
223
|
+
|
|
224
|
+
for (const key of nodeChildrenCount) {
|
|
225
|
+
const childNode = node.children[key];
|
|
226
|
+
const childId = parentId + "/" + key;
|
|
227
|
+
const childrenCount = Object.keys(childNode.children).length;
|
|
228
|
+
const hasChildren = childrenCount > 0;
|
|
229
|
+
const item = {
|
|
230
|
+
id: childId,
|
|
231
|
+
name: prevWasSkipped ? parentId : key,
|
|
232
|
+
parent: overrideParentId ?? parentId,
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
if (!hasChildren) {
|
|
236
|
+
item.value = childNode.size;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (lvl === 0) {
|
|
240
|
+
item.color = Highcharts.getOptions().colors[randomInt(0, 9)];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const skipThisNode = nodeChildrenCount.length === 1 && childrenCount === 1;
|
|
244
|
+
|
|
245
|
+
if (!skipThisNode) {
|
|
246
|
+
result.push(item);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
flattenTree(
|
|
250
|
+
childNode,
|
|
251
|
+
childId,
|
|
252
|
+
skipThisNode,
|
|
253
|
+
lvl + 1,
|
|
254
|
+
result,
|
|
255
|
+
skipThisNode ? (overrideParentId ?? parentId) : undefined,
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function sumSizes(node) {
|
|
263
|
+
const isEmpty = require("lodash/isEmpty");
|
|
264
|
+
|
|
265
|
+
const isFile = isEmpty(node.children);
|
|
266
|
+
let totalFiles = isFile ? 1 : 0;
|
|
267
|
+
let totalSize = node.size || 0;
|
|
268
|
+
for (const key in node.children) {
|
|
269
|
+
const result = sumSizes(node.children[key]);
|
|
270
|
+
totalSize += result.totalSize;
|
|
271
|
+
totalFiles += result.totalFiles;
|
|
272
|
+
}
|
|
273
|
+
node.type = isFile ? "file" : "folder";
|
|
274
|
+
node.size = totalSize;
|
|
275
|
+
node.files = totalFiles;
|
|
276
|
+
return { totalSize, totalFiles };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function toGroups(node, label) {
|
|
280
|
+
const keys = Object.keys(node.children);
|
|
281
|
+
|
|
282
|
+
const common = {
|
|
283
|
+
label,
|
|
284
|
+
weight: node.size,
|
|
285
|
+
files: node.files,
|
|
286
|
+
type: node.type,
|
|
287
|
+
size: helpers.formatBytes(node.size),
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
if (keys.length === 0) {
|
|
291
|
+
// File
|
|
292
|
+
return common;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Folder
|
|
296
|
+
return Object.assign(common, {
|
|
297
|
+
groups: keys.map((key) => toGroups(node.children[key], key)),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function randomInt(min, max) {
|
|
302
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const nm = "node_modules/";
|
|
306
|
+
function shortenPath(path, nodeModulesMap) {
|
|
307
|
+
let index = path.lastIndexOf(nm);
|
|
308
|
+
|
|
309
|
+
if (index > 0) {
|
|
310
|
+
const pathWithoutNestedNM = path.slice(index);
|
|
311
|
+
// Find the package name after "node_modules/"
|
|
312
|
+
const firstSlash = pathWithoutNestedNM.indexOf("/");
|
|
313
|
+
const secondSlash = pathWithoutNestedNM.indexOf("/", firstSlash + 1);
|
|
314
|
+
const pkgName =
|
|
315
|
+
secondSlash === -1
|
|
316
|
+
? pathWithoutNestedNM.slice(firstSlash + 1)
|
|
317
|
+
: pathWithoutNestedNM.slice(firstSlash + 1, secondSlash);
|
|
318
|
+
|
|
319
|
+
if (nodeModulesMap?.children?.node_modules?.children?.[pkgName]) {
|
|
320
|
+
const parentPackage = helpers.getModulesName(path.slice(0, index));
|
|
321
|
+
return nm + parentPackage + " ~ " + pathWithoutNestedNM.slice(nm.length);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return pathWithoutNestedNM;
|
|
325
|
+
}
|
|
326
|
+
return path;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
module.exports = helpers;
|
package/setup.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const prepare = require("./prepare");
|
|
2
|
+
const queryHelpers = require("./queryHelpers");
|
|
3
|
+
|
|
4
|
+
module.exports = function setup({
|
|
5
|
+
defineObjectMarker,
|
|
6
|
+
addQueryHelpers,
|
|
7
|
+
setPrepare,
|
|
8
|
+
}) {
|
|
9
|
+
// extend queries with custom methods
|
|
10
|
+
addQueryHelpers(queryHelpers);
|
|
11
|
+
setPrepare(prepare);
|
|
12
|
+
};
|