react-native-bundle-discovery-ui 2.6.0 → 2.7.0-rc.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/queryHelpers.js DELETED
@@ -1,375 +0,0 @@
1
- const helpers = {
2
- prettifyMap: new Map(),
3
- prettifyJS(sourceStr) {
4
- if (helpers.prettifyMap.has(sourceStr)) {
5
- return helpers.prettifyMap.get(sourceStr);
6
- }
7
-
8
- const prettier = require("prettier/standalone");
9
- const prettierPluginBabel = require("prettier/plugins/babel");
10
- const prettierPluginEstree = require("prettier/plugins/estree");
11
-
12
- return prettier
13
- .format(sourceStr, {
14
- parser: "babel",
15
- plugins: [prettierPluginBabel, prettierPluginEstree],
16
- })
17
- .then((formatted) => {
18
- helpers.prettifyMap.set(sourceStr, formatted);
19
- return formatted;
20
- })
21
- .catch(() => {
22
- return sourceStr;
23
- });
24
- },
25
- askChatGPTAboutPackages() {
26
- const prompt = `I have a list of JavaScript packages from my React Native bundle (see below). I want to optimize bundle size by identifying similar or redundant packages — such as multiple versions of similar libraries (e.g., lodash, lodash-es, underscore, etc.), duplicate utilities, or overlapping functionality (e.g., date libraries like moment, dayjs, date-fns).
27
-
28
- Please do the following:
29
-
30
- 1. Group similar or overlapping packages together.
31
- 2. For each group, suggest which one to keep and which ones to consider removing.
32
- 3. For each group, provide a regex string that can be used to filter those packages from the list (e.g., in grep, find, or search tools).
33
- 4. Keep the output concise and copy-paste friendly.`;
34
- return `https://chat.openai.com/?prompt=${encodeURIComponent(prompt)}`;
35
- },
36
- plural(count, [singular, plural]) {
37
- return count === 1 ? singular : plural;
38
- },
39
- pluralWithCount(count, [singular, plural]) {
40
- return `${count} ${helpers.plural(count, [singular, plural])}`;
41
- },
42
- pluralBadge(count, [singular, plural], prefix = "") {
43
- return {
44
- text: prefix + count,
45
- postfix: helpers.plural(count, [singular, plural]),
46
- };
47
- },
48
- getModulesName(path) {
49
- const modules = path.split("node_modules/");
50
- const lastModule = modules[modules.length - 1];
51
- const [folder, subFolder] = lastModule.split("/");
52
- if (folder.startsWith("@")) {
53
- return `${folder}/${subFolder}`;
54
- }
55
- return folder;
56
- },
57
- getBestNetworkGraphSize(module, params) {
58
- let maxParentDepth = 0;
59
- let itemsCount = 0;
60
- do {
61
- maxParentDepth++;
62
- itemsCount = helpers.getNetworkGraph(module, {
63
- ...params,
64
- maxParentDepth,
65
- }).data.length;
66
- if (itemsCount < 10) {
67
- const limit = itemsCount - 1;
68
- return limit > 2 ? limit : 2;
69
- }
70
- } while (maxParentDepth < 6);
71
- return maxParentDepth;
72
- },
73
- getNetworkGraph(
74
- module,
75
- { maxParentDepth = 2, omitVisitedModules = true } = {},
76
- ) {
77
- const queue = [{ module, parentId: "", level: 0 }];
78
- const visited = new Set();
79
- const result = [];
80
- let entryPointPath = null;
81
- const data = [];
82
-
83
- while (queue.length > 0) {
84
- const { module: currentModule, parentId, level } = queue.shift();
85
-
86
- if (level >= Number(maxParentDepth)) {
87
- break;
88
- }
89
-
90
- const id = currentModule.path;
91
-
92
- if (omitVisitedModules) {
93
- if (visited.has(id)) {
94
- continue;
95
- }
96
- visited.add(id);
97
- }
98
-
99
- if (parentId) {
100
- const isEntryPoint = currentModule.dependents.length === 0;
101
- result.push({ isEntryPoint, id, parentId });
102
- data.push([parentId, id]);
103
- if (isEntryPoint) {
104
- entryPointPath = id;
105
- }
106
- }
107
-
108
- if (Array.isArray(currentModule.dependents)) {
109
- for (const dependentModule of currentModule.dependents) {
110
- queue.push({
111
- module: dependentModule,
112
- parentId: id,
113
- level: level + 1,
114
- });
115
- }
116
- }
117
- }
118
-
119
- if (!entryPointPath) {
120
- for (const item of result) {
121
- if (item.isEntryPoint) {
122
- entryPointPath = item.id;
123
- break;
124
- }
125
- }
126
- }
127
-
128
- return { entryPointPath, data };
129
- },
130
-
131
- getExtColor(extName) {
132
- const colors = {
133
- js: "#f1e05a50",
134
- ts: "#2b748950",
135
- tsx: "#2b748950",
136
- json: "#e34c2650",
137
- svg: "#e69f0d50",
138
- css: "#563d7c50",
139
- png: "#e44b2350",
140
- };
141
- return colors[extName] ?? colors["js"];
142
- },
143
- getFileExtension(filename) {
144
- const idx = filename.lastIndexOf(".");
145
- return idx === -1 ? "js" : filename.slice(idx + 1);
146
- },
147
- // "2022-06-14T19:46:38.369Z" -> "2022-06-14"
148
- formatDate(isoDate) {
149
- return isoDate ? new Date(isoDate).toISOString().slice(0, 10) : "";
150
- },
151
- // "2022-06-14T19:46:38.369Z" -> "3 years ago"
152
- timeAgo(isoDate) {
153
- if (!isoDate) return "";
154
- const days = Math.floor((Date.now() - new Date(isoDate)) / 86_400_000);
155
- const [count, unit] =
156
- days >= 365
157
- ? [Math.floor(days / 365), ["year", "years"]]
158
- : days >= 30
159
- ? [Math.floor(days / 30), ["month", "months"]]
160
- : [days, ["day", "days"]];
161
- return count === 0
162
- ? "today"
163
- : `${helpers.pluralWithCount(count, unit)} ago`;
164
- },
165
- toFixed(value, fractionDigits = 2) {
166
- return Number(value).toFixed(fractionDigits);
167
- },
168
- percent(value, fractionDigits = 2) {
169
- return (100 * value).toFixed(fractionDigits) + "%";
170
- },
171
- formatBytes(bytes, decimals) {
172
- if (bytes == 0) return "0 Bytes";
173
- const k = 1024,
174
- dm = decimals || 2,
175
- sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"],
176
- i = Math.floor(Math.log(bytes) / Math.log(k));
177
- return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
178
- },
179
- isPackageImport(moduleName) {
180
- return moduleName?.[0] !== ".";
181
- },
182
- transformFilesList(files, rootFolder, type) {
183
- const nodeModulesMap = { children: {}, size: 0 };
184
- const sourceCodeMap = { children: {}, size: 0 };
185
-
186
- files.forEach(({ path, size }) => {
187
- if (path === "__prelude__") {
188
- path = "node_modules/__prelude__";
189
- }
190
- if (path === "__runtime__") {
191
- path = "node_modules/__runtime__";
192
- }
193
-
194
- const shortPath = path.replace(rootFolder + "/", "");
195
- const isNodeModule = shortPath.includes("node_modules/");
196
- const parts = shortenPath(shortPath, nodeModulesMap).split("/");
197
- let current = (isNodeModule ? nodeModulesMap : sourceCodeMap).children;
198
-
199
- parts.forEach((part, index) => {
200
- // console.log((" --- xdebug " + index + " ".repeat(50)).substr(0, 40), {
201
- // part,
202
- // parts,
203
- // });
204
- if (!current[part]) {
205
- current[part] = { size: 0, children: {} };
206
- }
207
-
208
- if (index === parts.length - 1) {
209
- current[part].size = size;
210
- current[part].path = shortPath;
211
- current[part].fullPath = path;
212
- }
213
-
214
- current = current[part].children;
215
- });
216
- });
217
-
218
- if (type === "foamtree") {
219
- sumSizes(nodeModulesMap);
220
- sumSizes(sourceCodeMap);
221
-
222
- const sourceCodeGroup = toGroups(sourceCodeMap, "Source Code");
223
- const nodeModulesGroup = nodeModulesMap?.children?.node_modules
224
- ? toGroups(nodeModulesMap.children.node_modules, "node_modules")
225
- : {};
226
-
227
- if (!sourceCodeGroup.groups) {
228
- return nodeModulesGroup;
229
- }
230
- if (!nodeModulesGroup.groups) {
231
- return sourceCodeGroup;
232
- }
233
-
234
- const topLevelNode = { groups: [sourceCodeGroup, nodeModulesGroup] };
235
- topLevelNode.weight = topLevelNode.groups.reduce(
236
- (acc, group) => acc + group.weight,
237
- 0,
238
- );
239
-
240
- return topLevelNode;
241
- }
242
-
243
- if (type === "highcharts-treemap") {
244
- const ROOT_ID_1 = "~";
245
- const ROOT_ID_2 = ".";
246
- return [
247
- { id: ROOT_ID_1, name: "node_modules" },
248
- { id: ROOT_ID_2, name: "Source Code" },
249
- ]
250
- .concat(flattenTree(nodeModulesMap.children.node_modules, ROOT_ID_1))
251
- .concat(flattenTree(sourceCodeMap, ROOT_ID_2));
252
- }
253
-
254
- throw new Error("Unsupported type: " + type);
255
- },
256
- };
257
-
258
- function flattenTree(
259
- node,
260
- parentId,
261
- prevWasSkipped = false,
262
- lvl = 0,
263
- result = [],
264
- overrideParentId,
265
- ) {
266
- const nodeChildrenCount = Object.keys(node.children);
267
-
268
- for (const key of nodeChildrenCount) {
269
- const childNode = node.children[key];
270
- const childId = parentId + "/" + key;
271
- const childrenCount = Object.keys(childNode.children).length;
272
- const hasChildren = childrenCount > 0;
273
- const item = {
274
- id: childId,
275
- name: prevWasSkipped ? parentId : key,
276
- parent: overrideParentId ?? parentId,
277
- };
278
-
279
- if (!hasChildren) {
280
- item.value = childNode.size;
281
- }
282
-
283
- if (lvl === 0) {
284
- item.color = Highcharts.getOptions().colors[randomInt(0, 9)];
285
- }
286
-
287
- const skipThisNode = nodeChildrenCount.length === 1 && childrenCount === 1;
288
-
289
- if (!skipThisNode) {
290
- result.push(item);
291
- }
292
-
293
- flattenTree(
294
- childNode,
295
- childId,
296
- skipThisNode,
297
- lvl + 1,
298
- result,
299
- skipThisNode ? (overrideParentId ?? parentId) : undefined,
300
- );
301
- }
302
-
303
- return result;
304
- }
305
-
306
- function sumSizes(node) {
307
- const isFile = Object.keys(node.children).length === 0;
308
- let totalFiles = isFile ? 1 : 0;
309
- let totalSize = node.size || 0;
310
- for (const key in node.children) {
311
- const result = sumSizes(node.children[key]);
312
- totalSize += result.totalSize;
313
- totalFiles += result.totalFiles;
314
- }
315
- node.type = isFile ? "file" : "folder";
316
- node.size = totalSize;
317
- node.files = totalFiles;
318
- return { totalSize, totalFiles };
319
- }
320
-
321
- function toGroups(node, label) {
322
- const keys = Object.keys(node.children);
323
-
324
- const common = {
325
- label,
326
- weight: node.size,
327
- fullPath: node.fullPath,
328
- files: node.files,
329
- type: node.type,
330
- size: helpers.formatBytes(node.size),
331
- };
332
-
333
- if (keys.length === 0) {
334
- // File
335
- return common;
336
- }
337
-
338
- // Folder
339
- return Object.assign(common, {
340
- groups: keys.map((key) => toGroups(node.children[key], key)),
341
- });
342
- }
343
-
344
- function randomInt(min, max) {
345
- return Math.floor(Math.random() * (max - min + 1)) + min;
346
- }
347
-
348
- const nm = "node_modules/";
349
- function shortenPath(path, nodeModulesMap) {
350
- if (path.startsWith(nm + ".pnpm/")) {
351
- path = path.replaceAll(nm + ".pnpm/", "");
352
- }
353
- let index = path.lastIndexOf(nm);
354
-
355
- if (index > 0) {
356
- const pathWithoutNestedNM = path.slice(index);
357
- // Find the package name after "node_modules/"
358
- const firstSlash = pathWithoutNestedNM.indexOf("/");
359
- const secondSlash = pathWithoutNestedNM.indexOf("/", firstSlash + 1);
360
- const pkgName =
361
- secondSlash === -1
362
- ? pathWithoutNestedNM.slice(firstSlash + 1)
363
- : pathWithoutNestedNM.slice(firstSlash + 1, secondSlash);
364
-
365
- if (nodeModulesMap?.children?.node_modules?.children?.[pkgName]) {
366
- const parentPackage = helpers.getModulesName(path.slice(0, index));
367
- return nm + parentPackage + " ~ " + pathWithoutNestedNM.slice(nm.length);
368
- }
369
-
370
- return pathWithoutNestedNM;
371
- }
372
- return path;
373
- }
374
-
375
- module.exports = helpers;
package/setup.js DELETED
@@ -1,12 +0,0 @@
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
- };
package/views/_theme.js DELETED
@@ -1,35 +0,0 @@
1
- function isDark() {
2
- const isSystemDarkMode = window?.matchMedia?.(
3
- "(prefers-color-scheme: dark)",
4
- )?.matches;
5
- const userMode = localStorage.getItem("discoveryjs:color-scheme");
6
- return userMode === "auto" ? isSystemDarkMode : userMode === "dark";
7
- }
8
-
9
- function doTheming(el) {
10
- const dark = isDark();
11
- el.classList.add("highcharts-light");
12
- el.classList[!dark ? "add" : "remove"]("my-light");
13
- el.classList[dark ? "add" : "remove"]("highcharts-dark");
14
- }
15
-
16
- // apply theme on import
17
- if (isDark()) {
18
- // require("highcharts/themes/dark-unica"); // no
19
- // require("highcharts/themes/brand-dark");
20
- // require("highcharts/themes/dark-blue");
21
- // require("highcharts/themes/dark-green");
22
- require("../vendors/high-contrast-dark.js");
23
- } else {
24
- // require("highcharts/themes/avocado");
25
- // require("highcharts/themes/brand-light");
26
- // require("highcharts/themes/gray");
27
- // require("highcharts/themes/grid-light"); // no
28
- // require("highcharts/themes/grid");
29
- // require("highcharts/themes/high-contrast-light");
30
- // require("highcharts/themes/sand-signika"); // no
31
- // require("highcharts/themes/skies");
32
- // require("highcharts/themes/sunset");
33
- }
34
-
35
- module.exports = { doTheming };
package/views/foamtree.js DELETED
@@ -1,136 +0,0 @@
1
- const { FoamTree } = require("../vendors/foamtree.js");
2
-
3
- function injectTooltip(root) {
4
- const t = root.querySelector(".tooltip");
5
- if (t) return t;
6
-
7
- const tooltip = document.createElement("div");
8
- tooltip.className = "tooltip";
9
- tooltip.id = "foamtree-tooltip";
10
- root.appendChild(tooltip);
11
- return tooltip;
12
- }
13
-
14
- function prependDuplicateTo(label) {
15
- if (label.includes(" ~ ")) {
16
- return "<b class='i-duplicate'>Duplicate</b> " + label.split(" ~ ")[1];
17
- }
18
- return label;
19
- }
20
-
21
- // Based on https://github.com/webpack-contrib/webpack-bundle-analyzer/blob/master/client/components/Treemap.jsx
22
- discovery.view.define("foamtree", function (el, config, rawData, context) {
23
- if (Array.isArray(rawData?.options?.series)) {
24
- rawData.options.series.forEach((e) => {
25
- if (e.data?.[0]?.value !== undefined) {
26
- // mutate data by link
27
- e.data = e.data.map((d) => d.value ?? null);
28
- }
29
- });
30
- }
31
-
32
- // console.log({ rawData });
33
-
34
- // Render after element will be added to the DOM
35
- // to avoid "FoamTree: element has zero dimensions: 0 x 0" error
36
- setTimeout(() => {
37
- try {
38
- // Dirty hack to fix shadow DOM issue, xd
39
- window.__el = el;
40
-
41
- const root = el.closest(".discovery-root");
42
- const tooltip = injectTooltip(root);
43
-
44
- window.addEventListener("resize", () => ft.resize(), { passive: true });
45
-
46
- root.addEventListener(
47
- "mousemove",
48
- (event) => {
49
- if (tooltip.style.display === "none") return;
50
- tooltip.style.left = event.pageX + 10 + "px";
51
- tooltip.style.top = event.pageY + 10 + "px";
52
- },
53
- {
54
- passive: true,
55
- },
56
- );
57
- el.addEventListener("mouseover", () => {
58
- tooltip.style.display = "block";
59
- });
60
- el.addEventListener("mouseout", () => {
61
- tooltip.style.display = "none";
62
- });
63
-
64
- const ft = new FoamTree({
65
- element: el,
66
- layout: "squarified",
67
- stacking: "flattened",
68
- pixelRatio: window.devicePixelRatio || 1,
69
- maxGroups: Infinity,
70
- maxGroupLevelsDrawn: Infinity,
71
- maxGroupLabelLevelsDrawn: Infinity,
72
- maxGroupLevelsAttached: Infinity,
73
- wireframeLabelDrawing: "always",
74
- groupMinDiameter: 0,
75
- groupLabelVerticalPadding: 0.2,
76
- rolloutDuration: 0,
77
- pullbackDuration: 0,
78
- fadeDuration: 0,
79
- groupExposureZoomMargin: 0.2,
80
- zoomMouseWheelDuration: 300,
81
- openCloseDuration: 200,
82
- onGroupClick(event) {
83
- event.preventDefault();
84
- ft.zoom(event.group);
85
- },
86
- onGroupDoubleClick: (e) => e.preventDefault(),
87
- onGroupHover(event) {
88
- // Ignoring hovering on `FoamTree` branding group and the root group
89
- if (event.group && event.group === rawData.options.dataObject) {
90
- return event.preventDefault();
91
- }
92
-
93
- const { group } = event;
94
-
95
- if (group && group.type) {
96
- const htmlContent = [
97
- `<b class="tooltip-name">${group.type}</b>: ${prependDuplicateTo(group.label)}`,
98
- `<b>Size</b>: ${group.size}`,
99
- group.type === "folder" ? null : `<b>Path</b>: ${group.fullPath}`,
100
- group.type === "folder" ? `<b>Files</b>: ${group.files}` : null,
101
- ]
102
- .filter((e) => !!e)
103
- .join("<br/>");
104
-
105
- tooltip.style.display = "block";
106
- tooltip.innerHTML = htmlContent;
107
- } else {
108
- tooltip.style.display = "none";
109
- tooltip.innerHTML = "";
110
- }
111
-
112
- // if (group) {
113
- // this.setState({
114
- // showTooltip: true,
115
- // tooltipContent: this.getTooltipContent(group)
116
- // });
117
- // } else {
118
- // this.setState({showTooltip: false});
119
- // }
120
- },
121
- ...rawData.options,
122
- });
123
- } catch (e) {
124
- console.error(e, rawData);
125
- discovery.view.render(
126
- el,
127
- {
128
- view: "alert-danger",
129
- data: '"Error rendering chart, please check the console for more information."',
130
- },
131
- rawData,
132
- context,
133
- );
134
- }
135
- }, 0);
136
- });