sonda 0.13.0 → 0.14.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 +18 -0
- package/dist/entrypoints/next.js +9 -0
- package/dist/entrypoints/rolldown.d.ts +47 -28
- package/dist/index.d.ts +5 -2
- package/dist/index.html +2 -2
- package/dist/index.js +128 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -168,7 +168,7 @@ function hasIgnoredExtension(name) {
|
|
|
168
168
|
}
|
|
169
169
|
//#endregion
|
|
170
170
|
//#region package.json
|
|
171
|
-
var version = "0.
|
|
171
|
+
var version = "0.14.0";
|
|
172
172
|
//#endregion
|
|
173
173
|
//#region src/report/formatters/Formatter.ts
|
|
174
174
|
var Formatter = class {
|
|
@@ -414,6 +414,7 @@ const parentMap = {};
|
|
|
414
414
|
* Update the report with the output assets and their sources from the source map.
|
|
415
415
|
*/
|
|
416
416
|
function updateOutput(report, path, entrypoints) {
|
|
417
|
+
if (!existsSync(path)) return;
|
|
417
418
|
const type = getTypeByName(path);
|
|
418
419
|
RESOURCE_TYPES_TO_ANALYZE.includes(type) ? addAnalyzableType(report, path, entrypoints, type) : addNonAnalyzableType(report, path, type);
|
|
419
420
|
}
|
|
@@ -539,6 +540,7 @@ const packageNameRegExp = /(.*)(?:.*node_modules\/)(@[^\/]+\/[^\/]+|[^\/]+)/;
|
|
|
539
540
|
function updateDependencies(report) {
|
|
540
541
|
const dependencies = {};
|
|
541
542
|
report.resources.map((file) => packageNameRegExp.exec(file.name)).filter((match) => match !== null).forEach(([path, , name]) => {
|
|
543
|
+
if (!existsSync(path)) return;
|
|
542
544
|
const paths = dependencies[name] ??= [];
|
|
543
545
|
if (!paths.includes(path)) paths.push(path);
|
|
544
546
|
});
|
|
@@ -548,6 +550,127 @@ function updateDependencies(report) {
|
|
|
548
550
|
}));
|
|
549
551
|
}
|
|
550
552
|
//#endregion
|
|
553
|
+
//#region src/report/processors/issues.ts
|
|
554
|
+
const MAX_CIRCULAR_IMPORT_ISSUES = 100;
|
|
555
|
+
const IMPORT_CONNECTION_KINDS = /* @__PURE__ */ new Set([
|
|
556
|
+
"import",
|
|
557
|
+
"require",
|
|
558
|
+
"dynamic-import"
|
|
559
|
+
]);
|
|
560
|
+
/**
|
|
561
|
+
* Finds common issues in the report data.
|
|
562
|
+
*/
|
|
563
|
+
function updateIssues(dependencies, connections) {
|
|
564
|
+
return [...findDuplicatedDependencies(dependencies), ...findCircularImports(connections)];
|
|
565
|
+
}
|
|
566
|
+
function findDuplicatedDependencies(dependencies) {
|
|
567
|
+
return dependencies.filter((dependency) => dependency.paths.length > 1).map((dependency) => ({
|
|
568
|
+
type: "duplicated-dependency",
|
|
569
|
+
severity: "warning",
|
|
570
|
+
message: `Dependency "${dependency.name}" appears to be bundled from multiple paths.`,
|
|
571
|
+
data: {
|
|
572
|
+
name: dependency.name,
|
|
573
|
+
paths: dependency.paths
|
|
574
|
+
}
|
|
575
|
+
}));
|
|
576
|
+
}
|
|
577
|
+
function findCircularImports(connections) {
|
|
578
|
+
const graph = createImportGraph(connections);
|
|
579
|
+
return findStronglyConnectedComponents(graph).filter((component) => component.length > 1 || hasSelfReference(graph, component[0])).toSorted(compareComponents).slice(0, MAX_CIRCULAR_IMPORT_ISSUES).map((component) => {
|
|
580
|
+
const cycle = findCycleInComponent(graph, component);
|
|
581
|
+
return {
|
|
582
|
+
type: "circular-import",
|
|
583
|
+
severity: "warning",
|
|
584
|
+
message: `Circular import detected between ${cycle.length - 1} modules.`,
|
|
585
|
+
data: { cycle }
|
|
586
|
+
};
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
function createImportGraph(connections) {
|
|
590
|
+
const graph = /* @__PURE__ */ new Map();
|
|
591
|
+
for (const connection of connections) {
|
|
592
|
+
if (!IMPORT_CONNECTION_KINDS.has(connection.kind)) continue;
|
|
593
|
+
const targets = graph.get(connection.source) ?? /* @__PURE__ */ new Set();
|
|
594
|
+
targets.add(connection.target);
|
|
595
|
+
graph.set(connection.source, targets);
|
|
596
|
+
if (!graph.has(connection.target)) graph.set(connection.target, /* @__PURE__ */ new Set());
|
|
597
|
+
}
|
|
598
|
+
return new Map([...graph].map(([node, targets]) => [node, [...targets].toSorted()]));
|
|
599
|
+
}
|
|
600
|
+
function findStronglyConnectedComponents(graph) {
|
|
601
|
+
let index = 0;
|
|
602
|
+
const stack = [];
|
|
603
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
604
|
+
const lowLinks = /* @__PURE__ */ new Map();
|
|
605
|
+
const stacked = /* @__PURE__ */ new Set();
|
|
606
|
+
const components = [];
|
|
607
|
+
function visit(node) {
|
|
608
|
+
indexes.set(node, index);
|
|
609
|
+
lowLinks.set(node, index);
|
|
610
|
+
index++;
|
|
611
|
+
stack.push(node);
|
|
612
|
+
stacked.add(node);
|
|
613
|
+
for (const next of graph.get(node) ?? []) if (!indexes.has(next)) {
|
|
614
|
+
visit(next);
|
|
615
|
+
lowLinks.set(node, Math.min(lowLinks.get(node), lowLinks.get(next)));
|
|
616
|
+
} else if (stacked.has(next)) lowLinks.set(node, Math.min(lowLinks.get(node), indexes.get(next)));
|
|
617
|
+
if (lowLinks.get(node) !== indexes.get(node)) return;
|
|
618
|
+
const component = [];
|
|
619
|
+
let current;
|
|
620
|
+
do {
|
|
621
|
+
current = stack.pop();
|
|
622
|
+
if (current === void 0) break;
|
|
623
|
+
stacked.delete(current);
|
|
624
|
+
component.push(current);
|
|
625
|
+
} while (current !== node);
|
|
626
|
+
components.push(component.toSorted());
|
|
627
|
+
}
|
|
628
|
+
for (const node of [...graph.keys()].toSorted()) if (!indexes.has(node)) visit(node);
|
|
629
|
+
return components;
|
|
630
|
+
}
|
|
631
|
+
function findCycleInComponent(graph, component) {
|
|
632
|
+
const nodes = new Set(component);
|
|
633
|
+
const start = component[0];
|
|
634
|
+
if (hasSelfReference(graph, start)) return [start, start];
|
|
635
|
+
for (const next of graph.get(start) ?? []) {
|
|
636
|
+
if (!nodes.has(next)) continue;
|
|
637
|
+
const path = findPath(graph, next, start, nodes);
|
|
638
|
+
if (path) return [start, ...path];
|
|
639
|
+
}
|
|
640
|
+
return [start, start];
|
|
641
|
+
}
|
|
642
|
+
function findPath(graph, source, target, allowedNodes) {
|
|
643
|
+
const queue = [source];
|
|
644
|
+
const visited = /* @__PURE__ */ new Set([source]);
|
|
645
|
+
const previous = /* @__PURE__ */ new Map();
|
|
646
|
+
for (let index = 0; index < queue.length; index++) {
|
|
647
|
+
const current = queue[index];
|
|
648
|
+
if (current === target) return reconstructPath(previous, source, target);
|
|
649
|
+
for (const next of graph.get(current) ?? []) {
|
|
650
|
+
if (!allowedNodes.has(next) || visited.has(next)) continue;
|
|
651
|
+
visited.add(next);
|
|
652
|
+
previous.set(next, current);
|
|
653
|
+
queue.push(next);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
function reconstructPath(previous, source, target) {
|
|
659
|
+
const path = [target];
|
|
660
|
+
let current = target;
|
|
661
|
+
while (current !== source) {
|
|
662
|
+
current = previous.get(current);
|
|
663
|
+
path.push(current);
|
|
664
|
+
}
|
|
665
|
+
return path.reverse();
|
|
666
|
+
}
|
|
667
|
+
function hasSelfReference(graph, node) {
|
|
668
|
+
return graph.get(node)?.includes(node) ?? false;
|
|
669
|
+
}
|
|
670
|
+
function compareComponents(a, b) {
|
|
671
|
+
return a[0] < b[0] ? -1 : Number(a[0] > b[0]);
|
|
672
|
+
}
|
|
673
|
+
//#endregion
|
|
551
674
|
//#region src/report/report.ts
|
|
552
675
|
const formatters = {
|
|
553
676
|
html: HtmlFormatter,
|
|
@@ -602,8 +725,9 @@ var Report = class {
|
|
|
602
725
|
this.assets[name] = entrypoints;
|
|
603
726
|
}
|
|
604
727
|
async generate() {
|
|
605
|
-
Object.entries(this.assets).filter(([_, entrypoints]) =>
|
|
728
|
+
Object.entries(this.assets).filter(([_, entrypoints]) => entrypoints !== void 0).forEach(([path, entrypoints]) => updateOutput(this, path, entrypoints));
|
|
606
729
|
this.dependencies = updateDependencies(this);
|
|
730
|
+
this.issues = updateIssues(this.dependencies, this.connections);
|
|
607
731
|
const outputs = [];
|
|
608
732
|
for (const format of this.config.format) {
|
|
609
733
|
const path = await new formatters[format](this.config).write(this.#getFormattedData());
|
|
@@ -625,7 +749,7 @@ var Report = class {
|
|
|
625
749
|
resources: sortByKey(this.resources, "name"),
|
|
626
750
|
connections: this.connections,
|
|
627
751
|
dependencies: sortByKey(this.dependencies, "name"),
|
|
628
|
-
issues: this.issues,
|
|
752
|
+
issues: sortByKey(this.issues, "message"),
|
|
629
753
|
sourcemaps: this.sourcemaps
|
|
630
754
|
};
|
|
631
755
|
}
|
|
@@ -733,7 +857,7 @@ function SondaRollupPlugin(userOptions = {}) {
|
|
|
733
857
|
},
|
|
734
858
|
async writeBundle({ dir, file }, bundle) {
|
|
735
859
|
const outputDir = resolve(process.cwd(), dir ?? dirname(file));
|
|
736
|
-
for (const [path, asset] of Object.entries(bundle)) report.addAsset(resolve(outputDir, path), asset.type === "chunk"
|
|
860
|
+
for (const [path, asset] of Object.entries(bundle)) report.addAsset(resolve(outputDir, path), asset.type === "chunk" ? asset.facadeModuleId ? [asset.facadeModuleId] : [] : void 0);
|
|
737
861
|
},
|
|
738
862
|
async closeBundle() {
|
|
739
863
|
const reportPaths = await report.generate();
|