sonda 0.12.0 → 0.13.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/dist/index.js CHANGED
@@ -1,12 +1,11 @@
1
1
  import { styleText } from "util";
2
2
  import { access, mkdir, readFile, readdir, writeFile } from "fs/promises";
3
- import { basename, dirname, extname, format, join, parse, posix, relative, resolve, win32 } from "path";
3
+ import { basename, dirname, extname, format, isAbsolute, join, parse, posix, relative, resolve, win32 } from "path";
4
4
  import { isBuiltin } from "module";
5
- import open from "open";
5
+ import open from "tiny-open";
6
6
  import { fileURLToPath } from "url";
7
7
  import { brotliCompressSync, gzipSync } from "zlib";
8
- import { readFileSync } from "fs";
9
- import { loadCodeAndMap } from "load-source-map";
8
+ import { existsSync, readFileSync, statSync } from "fs";
10
9
  import remapping from "@jridgewell/remapping";
11
10
  //#region src/config.ts
12
11
  var Config = class Config {
@@ -169,7 +168,7 @@ function hasIgnoredExtension(name) {
169
168
  }
170
169
  //#endregion
171
170
  //#region package.json
172
- var version = "0.12.0";
171
+ var version = "0.13.0";
173
172
  //#endregion
174
173
  //#region src/report/formatters/Formatter.ts
175
174
  var Formatter = class {
@@ -230,6 +229,108 @@ var JsonFormatter = class extends Formatter {
230
229
  }
231
230
  };
232
231
  //#endregion
232
+ //#region ../load-source-map/dist/index.js
233
+ /**
234
+ * Strip any JSON XSSI avoidance prefix from the string (as documented in the source maps specification),
235
+ * and parses the string as JSON.
236
+ *
237
+ * https://github.com/mozilla/source-map/blob/3cb92cc3b73bfab27c146bae4ef2bc09dbb4e5ed/lib/util.js#L162-L164
238
+ */
239
+ function parseSourceMapInput(str) {
240
+ return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, ""));
241
+ }
242
+ /**
243
+ sourceMappingURL=data:application/json;charset=utf-8;base64,data
244
+ sourceMappingURL=data:application/json;base64,data
245
+ sourceMappingURL=data:application/json;uri,data
246
+ sourceMappingURL=map-file-comment.css.map
247
+ sourceMappingURL=map-file-comment.css.map?query=value
248
+ */
249
+ const sourceMappingRegExp = /[@#]\s*sourceMappingURL=(\S+)\b/g;
250
+ /**
251
+ * Checks if the given path is a file.
252
+ */
253
+ function isFile(path) {
254
+ try {
255
+ return statSync(path).isFile();
256
+ } catch {
257
+ return false;
258
+ }
259
+ }
260
+ /**
261
+ * Default path normalizer that resolves the path relative to the source root.
262
+ */
263
+ function defaultPathNormalizer(path, sourceRoot) {
264
+ return isAbsolute(path) ? path : resolve(sourceRoot, path);
265
+ }
266
+ function loadCodeAndMap(codePath, sourcesPathNormalizer) {
267
+ if (!isFile(codePath)) return null;
268
+ const code = readFileSync(codePath, "utf-8");
269
+ const maybeMap = loadMap(codePath, code);
270
+ if (!maybeMap) return { code };
271
+ const { map, mapPath } = maybeMap;
272
+ const sourceRoot = resolve(dirname(mapPath), map.sourceRoot ?? ".");
273
+ const normalizer = sourcesPathNormalizer || defaultPathNormalizer;
274
+ map.sources = map.sources.map((source) => source && normalizer(source, sourceRoot));
275
+ map.sourcesContent = loadMissingSourcesContent(map);
276
+ delete map.sourceRoot;
277
+ return {
278
+ code,
279
+ map
280
+ };
281
+ }
282
+ function loadMap(codePath, code) {
283
+ /**
284
+ * Because in most cases the source map has the same name as the code file,
285
+ * we can try to append `.map` to the code path and check if the file exists.
286
+ */
287
+ try {
288
+ const possibleMapPath = codePath + ".map";
289
+ return {
290
+ map: parseSourceMapInput(readFileSync(possibleMapPath, "utf-8")),
291
+ mapPath: possibleMapPath
292
+ };
293
+ } catch {}
294
+ /**
295
+ * If the source map is not found by file name, we can try to extract it from the code.
296
+ * The path to the source map is usually in a comment at the end of the file, but it can
297
+ * also be inlined in the code itself.
298
+ */
299
+ const extractedComment = code.includes("sourceMappingURL") && Array.from(code.matchAll(sourceMappingRegExp)).at(-1);
300
+ if (!extractedComment || !extractedComment.length) return null;
301
+ const sourceMappingURL = extractedComment[1];
302
+ if (sourceMappingURL.startsWith("data:")) return {
303
+ map: parseSourceMapInput(parseDataUrl(sourceMappingURL)),
304
+ mapPath: codePath
305
+ };
306
+ const sourceMapFilename = new URL(sourceMappingURL, "file://").pathname;
307
+ const mapPath = join(dirname(codePath), sourceMapFilename);
308
+ if (!existsSync(mapPath)) return null;
309
+ return {
310
+ map: parseSourceMapInput(readFileSync(mapPath, "utf-8")),
311
+ mapPath
312
+ };
313
+ }
314
+ function parseDataUrl(url) {
315
+ const [prefix, payload] = url.split(",");
316
+ const encoding = prefix.split(";").at(-1);
317
+ switch (encoding) {
318
+ case "base64": return Buffer.from(payload, "base64").toString();
319
+ case "uri": return decodeURIComponent(payload);
320
+ default: throw new Error("Unsupported source map encoding: " + encoding);
321
+ }
322
+ }
323
+ /**
324
+ * Loop through the sources and try to load missing `sourcesContent` from the file system.
325
+ */
326
+ function loadMissingSourcesContent(map) {
327
+ return map.sources.map((source, index) => {
328
+ if (map.sourcesContent?.[index]) return map.sourcesContent[index];
329
+ if (source && existsSync(source)) return readFileSync(source, "utf-8");
330
+ return null;
331
+ });
332
+ }
333
+ //#endregion
233
334
  //#region src/report/processors/sourcemap.ts
234
335
  const UNASSIGNED = "[unassigned]";
235
336
  function getBytesPerSource(code, map, assetSizes, config) {
@@ -586,10 +687,16 @@ function SondaRollupPlugin(userOptions = {}) {
586
687
  const options = new Config(userOptions, { integration: "rollup" });
587
688
  if (!options.enabled) return { name: "sonda/rollup" };
588
689
  const report = new Report(options);
690
+ const dynamicImportSources = /* @__PURE__ */ new Set();
589
691
  return {
590
692
  name: "sonda/rollup",
693
+ resolveDynamicImport(specifier, importer) {
694
+ if (typeof specifier === "string") dynamicImportSources.add(connectionKey(importer, specifier));
695
+ return null;
696
+ },
591
697
  async resolveId(source, importer, options) {
592
698
  if (!importer) return;
699
+ if (dynamicImportSources.has(connectionKey(importer, source))) return;
593
700
  const resolved = await this.resolve(source, importer, {
594
701
  ...options,
595
702
  skipSelf: true
@@ -612,6 +719,18 @@ function SondaRollupPlugin(userOptions = {}) {
612
719
  uncompressed: module.code ? Buffer.byteLength(module.code) : 0
613
720
  });
614
721
  },
722
+ buildEnd() {
723
+ for (const id of this.getModuleIds()) {
724
+ const module = this.getModuleInfo(id);
725
+ if (!module) continue;
726
+ for (const target of module.dynamicallyImportedIds) report.addConnection({
727
+ kind: "dynamic-import",
728
+ source: normalizePath(module.id),
729
+ target: normalizePath(target),
730
+ original: null
731
+ });
732
+ }
733
+ },
615
734
  async writeBundle({ dir, file }, bundle) {
616
735
  const outputDir = resolve(process.cwd(), dir ?? dirname(file));
617
736
  for (const [path, asset] of Object.entries(bundle)) report.addAsset(resolve(outputDir, path), asset.type === "chunk" && asset.facadeModuleId ? [asset.facadeModuleId] : void 0);
@@ -622,6 +741,9 @@ function SondaRollupPlugin(userOptions = {}) {
622
741
  }
623
742
  };
624
743
  }
744
+ function connectionKey(importer, source) {
745
+ return `${importer}\0${source}`;
746
+ }
625
747
  function getModuleFormat(name, module) {
626
748
  if (getTypeByName(name) !== "script") return "other";
627
749
  const ext = extname(module.id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonda",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Universal bundle analyzer and visualizer that works with most popular bundlers and frameworks.",
5
5
  "keywords": [
6
6
  "analyzer",
@@ -91,9 +91,24 @@
91
91
  },
92
92
  "dependencies": {
93
93
  "@jridgewell/remapping": "^2.3.5",
94
- "open": "^11.0.0"
94
+ "tiny-open": "^1.3.0"
95
95
  },
96
96
  "engines": {
97
97
  "node": ">=22.12"
98
+ },
99
+ "compatiblePackages": {
100
+ "schemaVersion": 1,
101
+ "vite": {
102
+ "type": "compatible",
103
+ "versions": "^7.0.0 || ^8.0.0"
104
+ },
105
+ "rollup": {
106
+ "type": "compatible",
107
+ "versions": "^4.0.0"
108
+ },
109
+ "rolldown": {
110
+ "type": "compatible",
111
+ "versions": "^1.0.0"
112
+ }
98
113
  }
99
114
  }