hermex 1.0.0 → 1.1.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/README.md +141 -145
- package/dist/cli.js +487 -253
- package/dist/cli.js.map +1 -1
- package/package.json +7 -10
package/dist/cli.js
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
'use strict';
|
|
3
2
|
|
|
4
3
|
var commander = require('commander');
|
|
5
|
-
var glob = require('glob');
|
|
6
4
|
var ora = require('ora');
|
|
7
|
-
var
|
|
5
|
+
var chalk6 = require('chalk');
|
|
8
6
|
var core = require('@swc/core');
|
|
9
|
-
var
|
|
10
|
-
var path = require('path');
|
|
7
|
+
var fs3 = require('fs');
|
|
11
8
|
var Table = require('cli-table3');
|
|
9
|
+
var glob = require('glob');
|
|
10
|
+
var path = require('path');
|
|
11
|
+
var yaml = require('js-yaml');
|
|
12
|
+
var lockfile = require('@yarnpkg/lockfile');
|
|
12
13
|
|
|
13
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
15
|
|
|
15
16
|
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
16
|
-
var
|
|
17
|
-
var
|
|
18
|
-
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
17
|
+
var chalk6__default = /*#__PURE__*/_interopDefault(chalk6);
|
|
18
|
+
var fs3__default = /*#__PURE__*/_interopDefault(fs3);
|
|
19
19
|
var Table__default = /*#__PURE__*/_interopDefault(Table);
|
|
20
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
21
|
+
var yaml__default = /*#__PURE__*/_interopDefault(yaml);
|
|
22
|
+
var lockfile__default = /*#__PURE__*/_interopDefault(lockfile);
|
|
23
|
+
|
|
24
|
+
// src/cli.ts
|
|
20
25
|
|
|
21
26
|
// src/swc-parser/core/state.ts
|
|
22
27
|
function createState() {
|
|
@@ -699,7 +704,7 @@ function parseFile(filePath, options = {}) {
|
|
|
699
704
|
console.log(`
|
|
700
705
|
\u{1F4C1} Analyzing: ${filePath}`);
|
|
701
706
|
try {
|
|
702
|
-
const code =
|
|
707
|
+
const code = fs3__default.default.readFileSync(filePath, "utf8");
|
|
703
708
|
return parseCode(code, options);
|
|
704
709
|
} catch (error) {
|
|
705
710
|
console.error(`\u274C Error parsing ${filePath}:`, error.message);
|
|
@@ -744,11 +749,12 @@ function filterReportByLibrary(report, libraryName) {
|
|
|
744
749
|
}
|
|
745
750
|
|
|
746
751
|
// src/utils/aggregator.ts
|
|
747
|
-
function aggregateReports(reports) {
|
|
752
|
+
function aggregateReports(reports, versions = {}) {
|
|
748
753
|
const componentUsageMap = /* @__PURE__ */ new Map();
|
|
749
754
|
let totalImports = 0;
|
|
750
755
|
let totalUsagePatterns = 0;
|
|
751
756
|
const patternCountMap = /* @__PURE__ */ new Map();
|
|
757
|
+
const availablePackages = Object.keys(versions);
|
|
752
758
|
for (const report of reports) {
|
|
753
759
|
totalImports += report.summary.totalImports;
|
|
754
760
|
totalUsagePatterns += report.summary.totalUsagePatterns;
|
|
@@ -758,7 +764,11 @@ function aggregateReports(reports) {
|
|
|
758
764
|
if (existing) {
|
|
759
765
|
existing.count++;
|
|
760
766
|
} else {
|
|
761
|
-
const source = findComponentSource(
|
|
767
|
+
const source = findComponentSource(
|
|
768
|
+
jsx.component,
|
|
769
|
+
report,
|
|
770
|
+
availablePackages
|
|
771
|
+
);
|
|
762
772
|
componentUsageMap.set(key, {
|
|
763
773
|
name: jsx.component,
|
|
764
774
|
source,
|
|
@@ -778,6 +788,10 @@ function aggregateReports(reports) {
|
|
|
778
788
|
displayName: getPatternDisplayName(type),
|
|
779
789
|
count
|
|
780
790
|
})).sort((a, b) => b.count - a.count);
|
|
791
|
+
const packageDistribution = calculatePackageDistribution(
|
|
792
|
+
componentUsageMap,
|
|
793
|
+
versions
|
|
794
|
+
);
|
|
781
795
|
return {
|
|
782
796
|
filesAnalyzed: reports.length,
|
|
783
797
|
totalImports,
|
|
@@ -787,22 +801,49 @@ function aggregateReports(reports) {
|
|
|
787
801
|
componentUsage: componentUsageMap,
|
|
788
802
|
topComponents,
|
|
789
803
|
allComponents,
|
|
804
|
+
packageDistribution,
|
|
790
805
|
reports
|
|
791
806
|
};
|
|
792
807
|
}
|
|
793
|
-
function
|
|
808
|
+
function resolvePackageFromImportPath(importPath, availablePackages) {
|
|
809
|
+
if (importPath.startsWith(".") || importPath.startsWith("/")) {
|
|
810
|
+
return "local";
|
|
811
|
+
}
|
|
812
|
+
const sortedPackages = [...availablePackages].sort(
|
|
813
|
+
(a, b) => b.length - a.length
|
|
814
|
+
);
|
|
815
|
+
for (const pkg of sortedPackages) {
|
|
816
|
+
if (importPath === pkg) {
|
|
817
|
+
return pkg;
|
|
818
|
+
}
|
|
819
|
+
if (importPath.startsWith(`${pkg}/`)) {
|
|
820
|
+
return pkg;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return "unknown";
|
|
824
|
+
}
|
|
825
|
+
function findComponentSource(componentName, report, availablePackages) {
|
|
794
826
|
const namedImport = report.patterns.imports.named.find(
|
|
795
827
|
(imp) => imp.name === componentName
|
|
796
828
|
);
|
|
797
|
-
if (namedImport)
|
|
829
|
+
if (namedImport)
|
|
830
|
+
return resolvePackageFromImportPath(namedImport.source, availablePackages);
|
|
798
831
|
const defaultImport = report.patterns.imports.default.find(
|
|
799
832
|
(imp) => imp.name === componentName
|
|
800
833
|
);
|
|
801
|
-
if (defaultImport)
|
|
834
|
+
if (defaultImport)
|
|
835
|
+
return resolvePackageFromImportPath(
|
|
836
|
+
defaultImport.source,
|
|
837
|
+
availablePackages
|
|
838
|
+
);
|
|
802
839
|
const aliasedImport = report.patterns.imports.aliased.find(
|
|
803
840
|
(imp) => imp.local === componentName
|
|
804
841
|
);
|
|
805
|
-
if (aliasedImport)
|
|
842
|
+
if (aliasedImport)
|
|
843
|
+
return resolvePackageFromImportPath(
|
|
844
|
+
aliasedImport.source,
|
|
845
|
+
availablePackages
|
|
846
|
+
);
|
|
806
847
|
return "unknown";
|
|
807
848
|
}
|
|
808
849
|
function countPatterns(report, patternMap) {
|
|
@@ -883,132 +924,115 @@ function getPatternDisplayName(patternType) {
|
|
|
883
924
|
};
|
|
884
925
|
return displayNames[patternType] || patternType;
|
|
885
926
|
}
|
|
886
|
-
function
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
}
|
|
904
|
-
for (const imp of report.patterns.imports.namespace) {
|
|
905
|
-
console.log(
|
|
906
|
-
chalk__default.default.gray(
|
|
907
|
-
`[VERBOSE] Found namespace import: ${imp.name} from ${imp.source}`
|
|
908
|
-
)
|
|
909
|
-
);
|
|
910
|
-
}
|
|
911
|
-
for (const imp of report.patterns.imports.aliased) {
|
|
912
|
-
console.log(
|
|
913
|
-
chalk__default.default.gray(
|
|
914
|
-
`[VERBOSE] Found aliased import: ${imp.imported} as ${imp.local} from ${imp.source}`
|
|
915
|
-
)
|
|
916
|
-
);
|
|
917
|
-
}
|
|
918
|
-
for (const obj of report.patterns.usage.objects) {
|
|
919
|
-
for (const mapping of obj.mappings) {
|
|
920
|
-
console.log(
|
|
921
|
-
chalk__default.default.gray(
|
|
922
|
-
`[VERBOSE] Found Object mapping with Component: ${mapping.component}`
|
|
923
|
-
)
|
|
924
|
-
);
|
|
927
|
+
function getPackageVersion(packageName, versions) {
|
|
928
|
+
if (versions[packageName]) {
|
|
929
|
+
return versions[packageName];
|
|
930
|
+
}
|
|
931
|
+
if (packageName.includes("/")) {
|
|
932
|
+
const parts = packageName.split("/");
|
|
933
|
+
if (packageName.startsWith("@") && parts.length > 2) {
|
|
934
|
+
const basePackage = `${parts[0]}/${parts[1]}`;
|
|
935
|
+
if (versions[basePackage]) {
|
|
936
|
+
return versions[basePackage];
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if (!packageName.startsWith("@") && parts.length > 1) {
|
|
940
|
+
const basePackage = parts[0];
|
|
941
|
+
if (versions[basePackage]) {
|
|
942
|
+
return versions[basePackage];
|
|
943
|
+
}
|
|
925
944
|
}
|
|
926
945
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
chalk__default.default.gray(
|
|
949
|
-
`[VERBOSE] Found Destructuring: ${destructure.property} from ${destructure.source}`
|
|
950
|
-
)
|
|
951
|
-
);
|
|
952
|
-
}
|
|
953
|
-
for (const lazy of report.patterns.advanced.lazy) {
|
|
954
|
-
console.log(chalk__default.default.gray(`[VERBOSE] Found Lazy import: ${lazy.source}`));
|
|
955
|
-
}
|
|
956
|
-
for (const dynamic of report.patterns.advanced.dynamic) {
|
|
957
|
-
console.log(
|
|
958
|
-
chalk__default.default.gray(`[VERBOSE] Found Dynamic import: ${dynamic.source}`)
|
|
959
|
-
);
|
|
960
|
-
}
|
|
961
|
-
for (const hoc of report.patterns.advanced.hoc) {
|
|
962
|
-
console.log(
|
|
963
|
-
chalk__default.default.gray(`[VERBOSE] Found HOC: ${hoc.function}(${hoc.component})`)
|
|
964
|
-
);
|
|
965
|
-
}
|
|
966
|
-
for (const memo of report.patterns.advanced.memo) {
|
|
967
|
-
console.log(
|
|
968
|
-
chalk__default.default.gray(`[VERBOSE] Found Memoized component: ${memo.component}`)
|
|
969
|
-
);
|
|
970
|
-
}
|
|
971
|
-
if (report.patterns.advanced.forwardRef.length > 0) {
|
|
972
|
-
console.log(chalk__default.default.gray(`[VERBOSE] Found Forward Ref usage`));
|
|
946
|
+
return null;
|
|
947
|
+
}
|
|
948
|
+
function calculatePackageDistribution(componentUsageMap, versions) {
|
|
949
|
+
const packageMap = /* @__PURE__ */ new Map();
|
|
950
|
+
for (const component of componentUsageMap.values()) {
|
|
951
|
+
if (component.source === "unknown") continue;
|
|
952
|
+
const existing = packageMap.get(component.source);
|
|
953
|
+
if (existing) {
|
|
954
|
+
existing.componentCount++;
|
|
955
|
+
existing.usageCount += component.count;
|
|
956
|
+
existing.components.push(component.name);
|
|
957
|
+
} else {
|
|
958
|
+
packageMap.set(component.source, {
|
|
959
|
+
packageName: component.source,
|
|
960
|
+
version: getPackageVersion(component.source, versions),
|
|
961
|
+
componentCount: 1,
|
|
962
|
+
usageCount: component.count,
|
|
963
|
+
percentage: 0,
|
|
964
|
+
components: [component.name]
|
|
965
|
+
});
|
|
966
|
+
}
|
|
973
967
|
}
|
|
974
|
-
|
|
975
|
-
|
|
968
|
+
const distribution = Array.from(packageMap.values());
|
|
969
|
+
const totalExternalUsage = distribution.reduce(
|
|
970
|
+
(sum, pkg) => sum + pkg.usageCount,
|
|
971
|
+
0
|
|
972
|
+
);
|
|
973
|
+
for (const pkg of distribution) {
|
|
974
|
+
pkg.percentage = totalExternalUsage > 0 ? pkg.usageCount / totalExternalUsage * 100 : 0;
|
|
976
975
|
}
|
|
977
|
-
|
|
976
|
+
return distribution.sort((a, b) => b.usageCount - a.usageCount);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// src/utils/format-utils.ts
|
|
980
|
+
function formatCount(num) {
|
|
981
|
+
return num.toLocaleString();
|
|
982
|
+
}
|
|
983
|
+
function formatDuration(seconds) {
|
|
984
|
+
return `${seconds.toFixed(1)}s`;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// src/utils/print-summary.ts
|
|
988
|
+
function printHeader() {
|
|
989
|
+
console.log(chalk6__default.default.green.bold("\n\u{1F4CA} Summary\n"));
|
|
978
990
|
}
|
|
979
991
|
function printSummary(aggregated, elapsedTimeSeconds) {
|
|
980
992
|
console.log(
|
|
981
|
-
|
|
982
|
-
`
|
|
983
|
-
|
|
984
|
-
);
|
|
985
|
-
console.log(
|
|
986
|
-
chalk__default.default.green(
|
|
987
|
-
`[SUMMARY] Files analyzed: ${aggregated.filesAnalyzed.toLocaleString()}`
|
|
993
|
+
chalk6__default.default.green(
|
|
994
|
+
`Analysis completed successfully in ${formatDuration(elapsedTimeSeconds)}
|
|
995
|
+
`
|
|
988
996
|
)
|
|
989
997
|
);
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
998
|
+
printHeader();
|
|
999
|
+
const table = new Table__default.default({
|
|
1000
|
+
head: ["Metric", "Count"],
|
|
1001
|
+
style: {
|
|
1002
|
+
head: ["cyan"],
|
|
1003
|
+
border: ["gray"]
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
const externalComponents = aggregated.topComponents.filter(
|
|
1007
|
+
(comp) => comp.source !== "unknown" && comp.source !== "local"
|
|
1008
|
+
).length;
|
|
1009
|
+
const totalExternalUsage = aggregated.packageDistribution.reduce(
|
|
1010
|
+
(sum, pkg) => sum + pkg.usageCount,
|
|
1011
|
+
0
|
|
994
1012
|
);
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
)
|
|
1013
|
+
table.push(
|
|
1014
|
+
["Files Analyzed", formatCount(aggregated.filesAnalyzed)],
|
|
1015
|
+
["External Packages", formatCount(aggregated.packageDistribution.length)],
|
|
1016
|
+
["External Components", formatCount(externalComponents)],
|
|
1017
|
+
["Total Usages", formatCount(totalExternalUsage)]
|
|
999
1018
|
);
|
|
1019
|
+
console.log(table.toString());
|
|
1020
|
+
}
|
|
1021
|
+
function printHeader2() {
|
|
1022
|
+
console.log(chalk6__default.default.cyan.bold("\n\u{1F4CB} Details\n"));
|
|
1000
1023
|
}
|
|
1001
1024
|
function printDetails(aggregated) {
|
|
1025
|
+
printHeader2();
|
|
1002
1026
|
console.log(
|
|
1003
|
-
|
|
1004
|
-
`
|
|
1027
|
+
chalk6__default.default.cyan(
|
|
1028
|
+
` Total usage patterns: ${aggregated.totalUsagePatterns.toLocaleString()}`
|
|
1005
1029
|
)
|
|
1006
1030
|
);
|
|
1007
1031
|
for (const pattern of aggregated.patternCounts) {
|
|
1008
1032
|
if (pattern.count > 0) {
|
|
1009
1033
|
console.log(
|
|
1010
|
-
|
|
1011
|
-
`
|
|
1034
|
+
chalk6__default.default.cyan(
|
|
1035
|
+
` ${pattern.displayName}: ${pattern.count.toLocaleString()}`
|
|
1012
1036
|
)
|
|
1013
1037
|
);
|
|
1014
1038
|
}
|
|
@@ -1022,12 +1046,12 @@ function renderBarChart(data, options = {}) {
|
|
|
1022
1046
|
emptyChar = "\u2591"
|
|
1023
1047
|
} = options;
|
|
1024
1048
|
if (data.length === 0) {
|
|
1025
|
-
console.log(
|
|
1049
|
+
console.log(chalk6__default.default.gray(" No data to display"));
|
|
1026
1050
|
return;
|
|
1027
1051
|
}
|
|
1028
1052
|
const maxValue = Math.max(...data.map((d) => d.value));
|
|
1029
1053
|
if (maxValue === 0) {
|
|
1030
|
-
console.log(
|
|
1054
|
+
console.log(chalk6__default.default.gray(" All values are zero"));
|
|
1031
1055
|
return;
|
|
1032
1056
|
}
|
|
1033
1057
|
const maxLabelLength = Math.max(...data.map((d) => d.label.length));
|
|
@@ -1036,156 +1060,357 @@ function renderBarChart(data, options = {}) {
|
|
|
1036
1060
|
const barLength = Math.round(percentage * maxWidth);
|
|
1037
1061
|
const emptyLength = maxWidth - barLength;
|
|
1038
1062
|
const paddedLabel = item.label.padEnd(maxLabelLength, " ");
|
|
1039
|
-
const bar =
|
|
1063
|
+
const bar = chalk6__default.default.green(barChar.repeat(barLength)) + chalk6__default.default.gray(emptyChar.repeat(emptyLength));
|
|
1040
1064
|
const valueStr = showValues ? ` ${item.value.toLocaleString()}` : "";
|
|
1041
1065
|
console.log(`${paddedLabel} ${bar}${valueStr}
|
|
1042
1066
|
`);
|
|
1043
1067
|
}
|
|
1044
1068
|
}
|
|
1045
1069
|
|
|
1046
|
-
// src/utils/print-
|
|
1047
|
-
function
|
|
1048
|
-
|
|
1049
|
-
if (mode === "log") {
|
|
1050
|
-
printTopComponentsLog(topComponents);
|
|
1051
|
-
} else if (mode === "table") {
|
|
1052
|
-
printTopComponentsTable(topComponents);
|
|
1053
|
-
} else if (mode === "chart") {
|
|
1054
|
-
printTopComponentsChart(topComponents);
|
|
1055
|
-
}
|
|
1070
|
+
// src/utils/print-components.ts
|
|
1071
|
+
function printHeader3() {
|
|
1072
|
+
console.log(chalk6__default.default.magenta.bold("\n\u269B\uFE0F Components\n"));
|
|
1056
1073
|
}
|
|
1057
|
-
function
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
if (
|
|
1062
|
-
|
|
1063
|
-
return;
|
|
1074
|
+
function printComponents(aggregated, mode) {
|
|
1075
|
+
const components = aggregated.topComponents;
|
|
1076
|
+
if (mode === "table") {
|
|
1077
|
+
printComponentsTable(components);
|
|
1078
|
+
} else if (mode === "chart") {
|
|
1079
|
+
printComponentsChart(components);
|
|
1064
1080
|
}
|
|
1065
|
-
components.forEach((comp, idx) => {
|
|
1066
|
-
const rank = idx + 1;
|
|
1067
|
-
const emoji = rank === 1 ? "\u{1F947}" : rank === 2 ? "\u{1F948}" : rank === 3 ? "\u{1F949}" : " ";
|
|
1068
|
-
const sourceStr = comp.source !== "unknown" ? ` from ${comp.source}` : "";
|
|
1069
|
-
console.log(
|
|
1070
|
-
chalk__default.default.yellow(
|
|
1071
|
-
`[TOP-COMPONENTS] ${emoji} ${rank}. ${comp.name}${sourceStr}: ${comp.count} uses`
|
|
1072
|
-
)
|
|
1073
|
-
);
|
|
1074
|
-
});
|
|
1075
1081
|
}
|
|
1076
|
-
function
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1082
|
+
function printComponentsTable(components) {
|
|
1083
|
+
printHeader3();
|
|
1084
|
+
const externalComponents = components.filter(
|
|
1085
|
+
(comp) => comp.source !== "unknown" && comp.source !== "local"
|
|
1086
|
+
);
|
|
1087
|
+
if (externalComponents.length === 0) {
|
|
1088
|
+
console.log(chalk6__default.default.gray(" No external components found"));
|
|
1080
1089
|
return;
|
|
1081
1090
|
}
|
|
1082
1091
|
const table = new Table__default.default({
|
|
1083
|
-
head: ["
|
|
1092
|
+
head: ["Component", "Package", "Count"],
|
|
1084
1093
|
style: {
|
|
1085
1094
|
head: ["cyan"],
|
|
1086
1095
|
border: ["gray"]
|
|
1087
1096
|
}
|
|
1088
1097
|
});
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
const emoji = rank === 1 ? "\u{1F947}" : rank === 2 ? "\u{1F948}" : rank === 3 ? "\u{1F949}" : `${rank}.`;
|
|
1092
|
-
table.push([emoji, comp.name, comp.source, comp.count.toString()]);
|
|
1098
|
+
externalComponents.forEach((comp) => {
|
|
1099
|
+
table.push([comp.name, comp.source, comp.count.toString()]);
|
|
1093
1100
|
});
|
|
1094
1101
|
console.log(table.toString());
|
|
1095
1102
|
}
|
|
1096
|
-
function
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1103
|
+
function printComponentsChart(components) {
|
|
1104
|
+
printHeader3();
|
|
1105
|
+
const externalComponents = components.filter(
|
|
1106
|
+
(comp) => comp.source !== "unknown" && comp.source !== "local"
|
|
1107
|
+
);
|
|
1108
|
+
if (externalComponents.length === 0) {
|
|
1109
|
+
console.log(chalk6__default.default.gray(" No external components found"));
|
|
1100
1110
|
return;
|
|
1101
1111
|
}
|
|
1102
|
-
const data =
|
|
1112
|
+
const data = externalComponents.map((comp) => ({
|
|
1103
1113
|
label: comp.name,
|
|
1104
1114
|
value: comp.count
|
|
1105
1115
|
}));
|
|
1106
1116
|
renderBarChart(data, { maxWidth: 50 });
|
|
1107
1117
|
}
|
|
1108
|
-
function
|
|
1109
|
-
|
|
1118
|
+
function printHeader4() {
|
|
1119
|
+
console.log(chalk6__default.default.blue.bold("\n\u{1F50D} Code Patterns\n"));
|
|
1120
|
+
}
|
|
1121
|
+
function printPatterns(aggregated, mode) {
|
|
1122
|
+
const patterns = aggregated.patternCounts.filter((p) => p.count > 0);
|
|
1110
1123
|
if (mode === "table") {
|
|
1111
|
-
|
|
1124
|
+
printPatternsTable(patterns);
|
|
1112
1125
|
} else if (mode === "chart") {
|
|
1113
|
-
|
|
1126
|
+
printPatternsChart(patterns);
|
|
1114
1127
|
}
|
|
1115
1128
|
}
|
|
1116
|
-
function
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
if (components.length === 0) {
|
|
1121
|
-
console.log(chalk__default.default.gray(" No components found"));
|
|
1129
|
+
function printPatternsTable(patterns) {
|
|
1130
|
+
printHeader4();
|
|
1131
|
+
if (patterns.length === 0) {
|
|
1132
|
+
console.log(chalk6__default.default.gray(" No patterns found"));
|
|
1122
1133
|
return;
|
|
1123
1134
|
}
|
|
1124
1135
|
const table = new Table__default.default({
|
|
1125
|
-
head: ["
|
|
1136
|
+
head: ["Pattern", "Count"],
|
|
1126
1137
|
style: {
|
|
1127
1138
|
head: ["cyan"],
|
|
1128
1139
|
border: ["gray"]
|
|
1129
1140
|
}
|
|
1130
1141
|
});
|
|
1131
|
-
|
|
1132
|
-
table.push([
|
|
1142
|
+
patterns.forEach((pattern) => {
|
|
1143
|
+
table.push([pattern.displayName, pattern.count.toString()]);
|
|
1133
1144
|
});
|
|
1134
1145
|
console.log(table.toString());
|
|
1146
|
+
const totalPatterns = patterns.reduce((sum, p) => sum + p.count, 0);
|
|
1147
|
+
console.log(chalk6__default.default.gray(`
|
|
1148
|
+
Total: ${totalPatterns} patterns detected`));
|
|
1135
1149
|
}
|
|
1136
|
-
function
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
if (components.length === 0) {
|
|
1141
|
-
console.log(chalk__default.default.gray(" No components found"));
|
|
1150
|
+
function printPatternsChart(patterns) {
|
|
1151
|
+
printHeader4();
|
|
1152
|
+
if (patterns.length === 0) {
|
|
1153
|
+
console.log(chalk6__default.default.gray(" No patterns found"));
|
|
1142
1154
|
return;
|
|
1143
1155
|
}
|
|
1144
|
-
const data =
|
|
1145
|
-
label:
|
|
1146
|
-
value:
|
|
1156
|
+
const data = patterns.map((pattern) => ({
|
|
1157
|
+
label: pattern.displayName,
|
|
1158
|
+
value: pattern.count
|
|
1147
1159
|
}));
|
|
1148
1160
|
renderBarChart(data, { maxWidth: 50 });
|
|
1149
1161
|
}
|
|
1150
|
-
function
|
|
1151
|
-
|
|
1162
|
+
function printHeader5() {
|
|
1163
|
+
console.log(chalk6__default.default.blueBright.bold("\n\u{1F4E6} Packages\n"));
|
|
1164
|
+
}
|
|
1165
|
+
function printPackages(aggregated, mode) {
|
|
1166
|
+
const packages = aggregated.packageDistribution;
|
|
1152
1167
|
if (mode === "table") {
|
|
1153
|
-
|
|
1168
|
+
printPackagesTable(packages);
|
|
1154
1169
|
} else if (mode === "chart") {
|
|
1155
|
-
|
|
1170
|
+
printPackagesChart(packages);
|
|
1156
1171
|
}
|
|
1157
1172
|
}
|
|
1158
|
-
function
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
if (patterns.length === 0) {
|
|
1163
|
-
console.log(chalk__default.default.gray(" No patterns found"));
|
|
1173
|
+
function printPackagesTable(packages) {
|
|
1174
|
+
printHeader5();
|
|
1175
|
+
if (packages.length === 0) {
|
|
1176
|
+
console.log(chalk6__default.default.gray(" No packages found"));
|
|
1164
1177
|
return;
|
|
1165
1178
|
}
|
|
1166
1179
|
const table = new Table__default.default({
|
|
1167
|
-
head: ["
|
|
1180
|
+
head: ["Package", "Version", "Components", "Usage", "Percentage"],
|
|
1168
1181
|
style: {
|
|
1169
1182
|
head: ["cyan"],
|
|
1170
1183
|
border: ["gray"]
|
|
1171
1184
|
}
|
|
1172
1185
|
});
|
|
1173
|
-
|
|
1174
|
-
table.push([
|
|
1186
|
+
packages.forEach((pkg) => {
|
|
1187
|
+
table.push([
|
|
1188
|
+
pkg.packageName,
|
|
1189
|
+
pkg.version || "N/A",
|
|
1190
|
+
formatCount(pkg.componentCount),
|
|
1191
|
+
formatCount(pkg.usageCount),
|
|
1192
|
+
`${pkg.percentage.toFixed(1)}%`
|
|
1193
|
+
]);
|
|
1175
1194
|
});
|
|
1176
1195
|
console.log(table.toString());
|
|
1196
|
+
const totalComponents = packages.reduce(
|
|
1197
|
+
(sum, p) => sum + p.componentCount,
|
|
1198
|
+
0
|
|
1199
|
+
);
|
|
1200
|
+
const totalExternalUsage = packages.reduce((sum, p) => sum + p.usageCount, 0);
|
|
1201
|
+
console.log(
|
|
1202
|
+
chalk6__default.default.gray(
|
|
1203
|
+
`
|
|
1204
|
+
Total: ${formatCount(packages.length)} packages | ${formatCount(totalComponents)} unique components | ${formatCount(totalExternalUsage)} total usages`
|
|
1205
|
+
)
|
|
1206
|
+
);
|
|
1177
1207
|
}
|
|
1178
|
-
function
|
|
1179
|
-
|
|
1180
|
-
if (
|
|
1181
|
-
console.log(
|
|
1208
|
+
function printPackagesChart(packages) {
|
|
1209
|
+
printHeader5();
|
|
1210
|
+
if (packages.length === 0) {
|
|
1211
|
+
console.log(chalk6__default.default.gray(" No packages found"));
|
|
1182
1212
|
return;
|
|
1183
1213
|
}
|
|
1184
|
-
const
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1214
|
+
const maxBarWidth = 40;
|
|
1215
|
+
const maxPercentage = Math.max(...packages.map((p) => p.percentage));
|
|
1216
|
+
const maxLabelLength = Math.max(...packages.map((p) => p.packageName.length));
|
|
1217
|
+
packages.forEach((pkg) => {
|
|
1218
|
+
const barLength = Math.round(
|
|
1219
|
+
pkg.percentage / maxPercentage * maxBarWidth
|
|
1220
|
+
);
|
|
1221
|
+
const emptyLength = maxBarWidth - barLength;
|
|
1222
|
+
const paddedLabel = pkg.packageName.padEnd(maxLabelLength, " ");
|
|
1223
|
+
const bar = chalk6__default.default.green("\u2588".repeat(barLength)) + chalk6__default.default.gray("\u2591".repeat(emptyLength));
|
|
1224
|
+
console.log(
|
|
1225
|
+
`${paddedLabel} ${bar} ${chalk6__default.default.bold(pkg.percentage.toFixed(1) + "%")} (${pkg.usageCount})`
|
|
1226
|
+
);
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
async function findFiles(pattern, ignorePatterns) {
|
|
1230
|
+
const files = await glob.glob(pattern, {
|
|
1231
|
+
ignore: ignorePatterns,
|
|
1232
|
+
nodir: true,
|
|
1233
|
+
absolute: true,
|
|
1234
|
+
windowsPathsNoEscape: true
|
|
1235
|
+
});
|
|
1236
|
+
return files;
|
|
1237
|
+
}
|
|
1238
|
+
var NpmLockfileAdapter = class {
|
|
1239
|
+
constructor() {
|
|
1240
|
+
this.name = "npm";
|
|
1241
|
+
this.supportedVersions = ["v2", "v3"];
|
|
1242
|
+
}
|
|
1243
|
+
detect(projectPath) {
|
|
1244
|
+
const lockfilePath = path__default.default.join(projectPath, "package-lock.json");
|
|
1245
|
+
return fs3__default.default.existsSync(lockfilePath) ? lockfilePath : null;
|
|
1246
|
+
}
|
|
1247
|
+
parse(lockFilePath) {
|
|
1248
|
+
try {
|
|
1249
|
+
const content = fs3__default.default.readFileSync(lockFilePath, "utf8");
|
|
1250
|
+
const lockData = JSON.parse(content);
|
|
1251
|
+
const versions = {};
|
|
1252
|
+
if (lockData.packages) {
|
|
1253
|
+
Object.entries(lockData.packages).forEach(
|
|
1254
|
+
([pkgPath, pkgData]) => {
|
|
1255
|
+
if (!pkgPath || pkgPath === "") return;
|
|
1256
|
+
const pkgName = pkgPath.replace(/^node_modules\//, "");
|
|
1257
|
+
if (pkgData.version) {
|
|
1258
|
+
versions[pkgName] = pkgData.version;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
if (lockData.dependencies && Object.keys(versions).length === 0) {
|
|
1264
|
+
let extractVersions = function(deps, prefix = "") {
|
|
1265
|
+
Object.entries(deps).forEach(([name, data]) => {
|
|
1266
|
+
const fullName = prefix ? `${prefix}/${name}` : name;
|
|
1267
|
+
if (data.version) {
|
|
1268
|
+
versions[fullName] = data.version;
|
|
1269
|
+
}
|
|
1270
|
+
if (data.dependencies) {
|
|
1271
|
+
extractVersions(data.dependencies, fullName);
|
|
1272
|
+
}
|
|
1273
|
+
});
|
|
1274
|
+
};
|
|
1275
|
+
extractVersions(lockData.dependencies);
|
|
1276
|
+
}
|
|
1277
|
+
return versions;
|
|
1278
|
+
} catch (error) {
|
|
1279
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1280
|
+
console.warn(`Warning: Could not parse package-lock.json: ${message}`);
|
|
1281
|
+
return {};
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
var PnpmLockfileAdapter = class {
|
|
1286
|
+
constructor() {
|
|
1287
|
+
this.name = "pnpm";
|
|
1288
|
+
this.supportedVersions = ["v5", "v6", "v9"];
|
|
1289
|
+
}
|
|
1290
|
+
detect(projectPath) {
|
|
1291
|
+
const lockfilePath = path__default.default.join(projectPath, "pnpm-lock.yaml");
|
|
1292
|
+
return fs3__default.default.existsSync(lockfilePath) ? lockfilePath : null;
|
|
1293
|
+
}
|
|
1294
|
+
parse(lockFilePath) {
|
|
1295
|
+
try {
|
|
1296
|
+
const content = fs3__default.default.readFileSync(lockFilePath, "utf8");
|
|
1297
|
+
const lockData = yaml__default.default.load(content);
|
|
1298
|
+
const versions = {};
|
|
1299
|
+
if (lockData.importers) {
|
|
1300
|
+
const rootImporter = lockData.importers["."];
|
|
1301
|
+
if (rootImporter) {
|
|
1302
|
+
if (rootImporter.dependencies) {
|
|
1303
|
+
for (const [name, data] of Object.entries(
|
|
1304
|
+
rootImporter.dependencies
|
|
1305
|
+
)) {
|
|
1306
|
+
if (typeof data === "object" && data !== null && "version" in data) {
|
|
1307
|
+
versions[name] = data.version;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
if (rootImporter.devDependencies) {
|
|
1312
|
+
for (const [name, data] of Object.entries(
|
|
1313
|
+
rootImporter.devDependencies
|
|
1314
|
+
)) {
|
|
1315
|
+
if (typeof data === "object" && data !== null && "version" in data) {
|
|
1316
|
+
versions[name] = data.version;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
if (lockData.packages && Object.keys(versions).length === 0) {
|
|
1323
|
+
Object.keys(lockData.packages).forEach((key) => {
|
|
1324
|
+
const match = key.match(/\/(.+?)\/(\d+\.\d+\.\d+.*?)(?:_|$)/);
|
|
1325
|
+
if (match) {
|
|
1326
|
+
const [, pkgName, version] = match;
|
|
1327
|
+
versions[pkgName] = version;
|
|
1328
|
+
}
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
if (lockData.dependencies && Object.keys(versions).length === 0) {
|
|
1332
|
+
Object.entries(lockData.dependencies).forEach(
|
|
1333
|
+
([name, versionSpec]) => {
|
|
1334
|
+
if (typeof versionSpec === "string" && !versionSpec.startsWith("link:")) {
|
|
1335
|
+
versions[name] = versionSpec;
|
|
1336
|
+
} else if (typeof versionSpec === "object" && versionSpec.version) {
|
|
1337
|
+
versions[name] = versionSpec.version;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
);
|
|
1341
|
+
}
|
|
1342
|
+
return versions;
|
|
1343
|
+
} catch (error) {
|
|
1344
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1345
|
+
console.warn(`Warning: Could not parse pnpm-lock.yaml: ${message}`);
|
|
1346
|
+
return {};
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1350
|
+
var YarnLockfileAdapter = class {
|
|
1351
|
+
constructor() {
|
|
1352
|
+
this.name = "yarn";
|
|
1353
|
+
this.supportedVersions = ["v1", "v2+"];
|
|
1354
|
+
}
|
|
1355
|
+
detect(projectPath) {
|
|
1356
|
+
const lockfilePath = path__default.default.join(projectPath, "yarn.lock");
|
|
1357
|
+
return fs3__default.default.existsSync(lockfilePath) ? lockfilePath : null;
|
|
1358
|
+
}
|
|
1359
|
+
parse(lockFilePath) {
|
|
1360
|
+
try {
|
|
1361
|
+
const content = fs3__default.default.readFileSync(lockFilePath, "utf8");
|
|
1362
|
+
const parsed = lockfile__default.default.parse(content);
|
|
1363
|
+
if (parsed.type !== "success") {
|
|
1364
|
+
console.warn("Warning: Failed to parse yarn.lock");
|
|
1365
|
+
return {};
|
|
1366
|
+
}
|
|
1367
|
+
const versions = {};
|
|
1368
|
+
Object.entries(parsed.object).forEach(([key, value]) => {
|
|
1369
|
+
let pkgName = key;
|
|
1370
|
+
if (key.startsWith("@")) {
|
|
1371
|
+
const match = key.match(/^(@[^@]+\/[^@]+)@/);
|
|
1372
|
+
if (match) {
|
|
1373
|
+
pkgName = match[1];
|
|
1374
|
+
}
|
|
1375
|
+
} else {
|
|
1376
|
+
const match = key.match(/^([^@]+)@/);
|
|
1377
|
+
if (match) {
|
|
1378
|
+
pkgName = match[1];
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
if (value.version && (!versions[pkgName] || value.version)) {
|
|
1382
|
+
versions[pkgName] = value.version;
|
|
1383
|
+
}
|
|
1384
|
+
});
|
|
1385
|
+
return versions;
|
|
1386
|
+
} catch (error) {
|
|
1387
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1388
|
+
console.warn(`Warning: Could not parse yarn.lock: ${message}`);
|
|
1389
|
+
return {};
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
|
|
1394
|
+
// src/lock-parser/index.ts
|
|
1395
|
+
var LOCKFILE_ADAPTERS = [
|
|
1396
|
+
new NpmLockfileAdapter(),
|
|
1397
|
+
new YarnLockfileAdapter(),
|
|
1398
|
+
new PnpmLockfileAdapter()
|
|
1399
|
+
];
|
|
1400
|
+
function findAndParseLockfile(projectPath) {
|
|
1401
|
+
for (const adapter of LOCKFILE_ADAPTERS) {
|
|
1402
|
+
const lockfilePath = adapter.detect(projectPath);
|
|
1403
|
+
if (lockfilePath) {
|
|
1404
|
+
const versions = adapter.parse(lockfilePath);
|
|
1405
|
+
return {
|
|
1406
|
+
versions,
|
|
1407
|
+
lockfileType: adapter.name,
|
|
1408
|
+
lockfilePath,
|
|
1409
|
+
supportedVersions: adapter.supportedVersions
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
throw new Error("No supported lockfile found");
|
|
1189
1414
|
}
|
|
1190
1415
|
|
|
1191
1416
|
// src/commands/scan.ts
|
|
@@ -1194,51 +1419,70 @@ function registerScanCommand(program2) {
|
|
|
1194
1419
|
"[pattern]",
|
|
1195
1420
|
"Glob pattern for files to analyze (defaults to current directory recursively)",
|
|
1196
1421
|
"**/*.{tsx,jsx,ts,js}"
|
|
1422
|
+
).option("--ignore <pattern>", "Glob pattern for files to ignore", [
|
|
1423
|
+
"**/node_modules/**",
|
|
1424
|
+
"**/dist/**",
|
|
1425
|
+
"**/build/**"
|
|
1426
|
+
]).option(
|
|
1427
|
+
"--allow-packages <pattern>",
|
|
1428
|
+
"Glob pattern for what packages to scan",
|
|
1429
|
+
"ALL"
|
|
1430
|
+
// TO FIX
|
|
1197
1431
|
).option(
|
|
1198
|
-
"--
|
|
1199
|
-
"
|
|
1200
|
-
|
|
1201
|
-
).option("--summary [mode]", "Show summary stats (log, false)", "log").option("--details", "Show detailed pattern counts").option(
|
|
1202
|
-
"--
|
|
1203
|
-
"Show top components (log, table, chart)",
|
|
1204
|
-
"log"
|
|
1205
|
-
).option(
|
|
1206
|
-
"--components-usage [mode]",
|
|
1432
|
+
"--ignore-packages <pattern>",
|
|
1433
|
+
"Glob pattern for what packages to ignore",
|
|
1434
|
+
[]
|
|
1435
|
+
).option("--summary [mode]", "Show summary stats (log, false)", "log").option("--no-summary", "Do not show summary stats").option("--details", "Show detailed pattern counts").option(
|
|
1436
|
+
"--components [mode]",
|
|
1207
1437
|
"Show components table/chart (table, chart)",
|
|
1208
1438
|
"table"
|
|
1209
|
-
).option(
|
|
1439
|
+
).option("--no-components", "Do not show components").option(
|
|
1440
|
+
"--packages [mode]",
|
|
1441
|
+
"Show packages table/chart (table, chart)",
|
|
1442
|
+
"table"
|
|
1443
|
+
).option("--no-packages", "Do not show packages").option(
|
|
1210
1444
|
"--patterns [mode]",
|
|
1211
1445
|
"Show patterns table/chart (table, chart)",
|
|
1212
1446
|
"table"
|
|
1213
|
-
).action(async (pattern, options) => {
|
|
1447
|
+
).option("--no-patterns", "Do not show patterns").action(async (pattern, options) => {
|
|
1214
1448
|
const normalizedOptions = normalizeOptions(options);
|
|
1215
1449
|
await executeScan(pattern, normalizedOptions);
|
|
1216
1450
|
});
|
|
1217
1451
|
}
|
|
1452
|
+
function normalizeIgnorePatterns(ignore) {
|
|
1453
|
+
if (!ignore) {
|
|
1454
|
+
return [];
|
|
1455
|
+
}
|
|
1456
|
+
return Array.isArray(ignore) ? ignore : [ignore];
|
|
1457
|
+
}
|
|
1218
1458
|
function normalizeOptions(options) {
|
|
1219
1459
|
return {
|
|
1220
1460
|
verbose: options.verbose || false,
|
|
1221
1461
|
summary: options.summary === false || options.summary === "false" ? false : "log",
|
|
1222
1462
|
details: options.details || false,
|
|
1223
|
-
|
|
1224
|
-
|
|
1463
|
+
components: options.components || "table",
|
|
1464
|
+
packages: options.packages || "table",
|
|
1225
1465
|
patterns: options.patterns || "table",
|
|
1226
|
-
|
|
1466
|
+
ignore: normalizeIgnorePatterns(options.ignore)
|
|
1227
1467
|
};
|
|
1228
1468
|
}
|
|
1229
1469
|
async function executeScan(pattern, options) {
|
|
1230
1470
|
const startTime = Date.now();
|
|
1231
|
-
const spinner = ora__default.default("
|
|
1471
|
+
const spinner = ora__default.default("Parsing lockfile...").start();
|
|
1232
1472
|
try {
|
|
1233
|
-
const
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1473
|
+
const lockfileResult = findAndParseLockfile(process.cwd());
|
|
1474
|
+
spinner.succeed(
|
|
1475
|
+
chalk6__default.default.blue(
|
|
1476
|
+
`\u{1F4E6} Found ${lockfileResult.lockfileType} lockfile (supports: ${lockfileResult.supportedVersions.join(", ")}) - ${Object.keys(lockfileResult.versions).length} packages`
|
|
1477
|
+
)
|
|
1478
|
+
);
|
|
1479
|
+
spinner.start("Finding files...");
|
|
1480
|
+
const files = await findFiles(pattern, options.ignore);
|
|
1237
1481
|
if (files.length === 0) {
|
|
1238
|
-
spinner.fail(
|
|
1482
|
+
spinner.fail("TEST");
|
|
1239
1483
|
return;
|
|
1240
1484
|
}
|
|
1241
|
-
spinner.succeed(
|
|
1485
|
+
spinner.succeed(chalk6__default.default.green(` Found ${files.length} files`));
|
|
1242
1486
|
spinner.start("Analyzing files...");
|
|
1243
1487
|
const reports = [];
|
|
1244
1488
|
for (let i = 0; i < files.length; i++) {
|
|
@@ -1250,45 +1494,35 @@ async function executeScan(pattern, options) {
|
|
|
1250
1494
|
const report = parseFile(file);
|
|
1251
1495
|
if (report) {
|
|
1252
1496
|
reports.push(report);
|
|
1253
|
-
if (options.verbose) {
|
|
1254
|
-
spinner.stop();
|
|
1255
|
-
printVerbose(file, report);
|
|
1256
|
-
spinner.start();
|
|
1257
|
-
}
|
|
1258
1497
|
}
|
|
1259
1498
|
} catch (error) {
|
|
1260
1499
|
spinner.stop();
|
|
1261
|
-
console.error(
|
|
1500
|
+
console.error(chalk6__default.default.red(`Error analyzing ${file}: ${error.message}`));
|
|
1262
1501
|
spinner.start();
|
|
1263
1502
|
}
|
|
1264
1503
|
}
|
|
1265
1504
|
spinner.succeed(
|
|
1266
|
-
|
|
1505
|
+
chalk6__default.default.green(`Analysis complete! Analyzed ${reports.length} files`)
|
|
1267
1506
|
);
|
|
1268
1507
|
const elapsedTime = (Date.now() - startTime) / 1e3;
|
|
1269
|
-
const aggregated = aggregateReports(reports);
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
printSummary(aggregated, elapsedTime);
|
|
1508
|
+
const aggregated = aggregateReports(reports, lockfileResult.versions);
|
|
1509
|
+
if (options.packages) {
|
|
1510
|
+
printPackages(aggregated, options.packages);
|
|
1273
1511
|
}
|
|
1274
1512
|
if (options.details) {
|
|
1275
|
-
console.log("");
|
|
1276
1513
|
printDetails(aggregated);
|
|
1277
1514
|
}
|
|
1278
|
-
if (options.
|
|
1279
|
-
|
|
1280
|
-
printTopComponents(aggregated, options.topComponents);
|
|
1281
|
-
}
|
|
1282
|
-
if (options.componentsUsage) {
|
|
1283
|
-
console.log("");
|
|
1284
|
-
printComponentsUsage(aggregated, options.componentsUsage);
|
|
1515
|
+
if (options.components) {
|
|
1516
|
+
printComponents(aggregated, options.components);
|
|
1285
1517
|
}
|
|
1286
1518
|
if (options.patterns) {
|
|
1287
|
-
console.log("");
|
|
1288
1519
|
printPatterns(aggregated, options.patterns);
|
|
1289
1520
|
}
|
|
1521
|
+
if (options.summary) {
|
|
1522
|
+
printSummary(aggregated, elapsedTime);
|
|
1523
|
+
}
|
|
1290
1524
|
} catch (error) {
|
|
1291
|
-
spinner.fail(
|
|
1525
|
+
spinner.fail(chalk6__default.default.red("Analysis failed: " + error.message));
|
|
1292
1526
|
console.error(error);
|
|
1293
1527
|
process.exit(1);
|
|
1294
1528
|
}
|
|
@@ -1296,7 +1530,7 @@ async function executeScan(pattern, options) {
|
|
|
1296
1530
|
|
|
1297
1531
|
// package.json
|
|
1298
1532
|
var package_default = {
|
|
1299
|
-
version: "1.0.0
|
|
1533
|
+
version: "1.0.0"};
|
|
1300
1534
|
|
|
1301
1535
|
// src/cli.ts
|
|
1302
1536
|
var program = new commander.Command();
|