hermex 1.1.1 → 1.2.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 +131 -152
- package/dist/cli.js +125 -111
- package/dist/cli.js.map +1 -1
- package/package.json +4 -2
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
-
import
|
|
4
|
+
import chalk5 from 'chalk';
|
|
5
|
+
import { minimatch } from 'minimatch';
|
|
5
6
|
import { parseSync } from '@swc/core';
|
|
6
7
|
import fs3 from 'fs';
|
|
7
8
|
import Table from 'cli-table3';
|
|
@@ -45,7 +46,6 @@ function createState() {
|
|
|
45
46
|
// src/swc-parser/patterns/imports.ts
|
|
46
47
|
function analyzeImportDeclaration(node, state) {
|
|
47
48
|
const source = node.source.value;
|
|
48
|
-
console.log(`\u{1F4E6} Found import: ${source}`);
|
|
49
49
|
for (const spec of node.specifiers) {
|
|
50
50
|
switch (spec.type) {
|
|
51
51
|
case "ImportDefaultSpecifier":
|
|
@@ -297,7 +297,6 @@ function analyzeJSXOpeningElement(node, state, parent) {
|
|
|
297
297
|
if (!state.usagePatterns.jsxUsage.has(elementName)) {
|
|
298
298
|
state.usagePatterns.jsxUsage.set(elementName, usage);
|
|
299
299
|
}
|
|
300
|
-
console.log(`\u{1F3A8} JSX Usage: <${elementName}>`);
|
|
301
300
|
}
|
|
302
301
|
|
|
303
302
|
// src/swc-parser/utils/matchers.ts
|
|
@@ -319,7 +318,6 @@ function analyzeVariableDeclaration(node, state) {
|
|
|
319
318
|
line: node.span?.start || 0
|
|
320
319
|
});
|
|
321
320
|
state.componentNames.add(varName);
|
|
322
|
-
console.log(`\u{1F4DD} Variable assignment: ${varName} = ${assignment}`);
|
|
323
321
|
}
|
|
324
322
|
}
|
|
325
323
|
}
|
|
@@ -340,7 +338,6 @@ function analyzeDestructuringPattern(pattern, init, state) {
|
|
|
340
338
|
line: pattern.span?.start || 0
|
|
341
339
|
});
|
|
342
340
|
state.componentNames.add(propName);
|
|
343
|
-
console.log(`\u{1F527} Destructuring: ${propName} from ${init.value}`);
|
|
344
341
|
}
|
|
345
342
|
}
|
|
346
343
|
}
|
|
@@ -368,7 +365,6 @@ function analyzeConditionalExpression(node, state) {
|
|
|
368
365
|
alternate: alternate || "",
|
|
369
366
|
line: node.span?.start || 0
|
|
370
367
|
});
|
|
371
|
-
console.log("\u{1F500} Conditional component usage found");
|
|
372
368
|
}
|
|
373
369
|
}
|
|
374
370
|
|
|
@@ -385,7 +381,6 @@ function analyzeArrayExpression(node, state) {
|
|
|
385
381
|
components: node.elements?.map((elem) => elem?.value).filter(Boolean),
|
|
386
382
|
line: node.span?.start || 0
|
|
387
383
|
});
|
|
388
|
-
console.log("\u{1F4CB} Array with components found");
|
|
389
384
|
}
|
|
390
385
|
}
|
|
391
386
|
function analyzeObjectExpression(node, state) {
|
|
@@ -403,7 +398,6 @@ function analyzeObjectExpression(node, state) {
|
|
|
403
398
|
})),
|
|
404
399
|
line: node.span?.start || 0
|
|
405
400
|
});
|
|
406
|
-
console.log("\u{1F5FA}\uFE0F Object mapping with components found");
|
|
407
401
|
}
|
|
408
402
|
}
|
|
409
403
|
|
|
@@ -419,7 +413,6 @@ function analyzeLazyImport(node, state) {
|
|
|
419
413
|
source,
|
|
420
414
|
line: node.span?.start || 0
|
|
421
415
|
});
|
|
422
|
-
console.log(`\u{1F504} Found lazy import: ${source}`);
|
|
423
416
|
}
|
|
424
417
|
}
|
|
425
418
|
}
|
|
@@ -431,7 +424,6 @@ function analyzeDynamicImport(node, state) {
|
|
|
431
424
|
source,
|
|
432
425
|
line: node.span?.start || 0
|
|
433
426
|
});
|
|
434
|
-
console.log(`\u26A1 Found dynamic import: ${source}`);
|
|
435
427
|
}
|
|
436
428
|
}
|
|
437
429
|
|
|
@@ -442,7 +434,6 @@ function analyzeHOCUsage(node, state) {
|
|
|
442
434
|
component: node.arguments?.[0]?.value || "[unknown]",
|
|
443
435
|
line: node.span?.start || 0
|
|
444
436
|
});
|
|
445
|
-
console.log(`\u{1F381} HOC usage found`);
|
|
446
437
|
}
|
|
447
438
|
function analyzeMemoUsage(node, state) {
|
|
448
439
|
const component = node.arguments?.[0];
|
|
@@ -451,28 +442,23 @@ function analyzeMemoUsage(node, state) {
|
|
|
451
442
|
component: component.value,
|
|
452
443
|
line: node.span?.start || 0
|
|
453
444
|
});
|
|
454
|
-
console.log(`\u{1F9E0} Memoized component: ${component.value}`);
|
|
455
445
|
}
|
|
456
446
|
}
|
|
457
447
|
function analyzeForwardRefUsage(node, state) {
|
|
458
448
|
state.usagePatterns.forwardedRefs.add({
|
|
459
449
|
line: node.span?.start || 0
|
|
460
450
|
});
|
|
461
|
-
console.log("\u2197\uFE0F ForwardRef usage found");
|
|
462
451
|
}
|
|
463
452
|
function analyzePortalUsage(node, state) {
|
|
464
453
|
state.usagePatterns.portalUsage.add({
|
|
465
454
|
line: node.span?.start || 0
|
|
466
455
|
});
|
|
467
|
-
console.log("\u{1F300} Portal usage found");
|
|
468
456
|
}
|
|
469
457
|
function analyzeMemberExpression(node, state) {
|
|
470
458
|
if (node.object?.type === "Identifier" && state.allIdentifiers.has(node.object.value)) {
|
|
471
|
-
const namespaceName = node.object.value;
|
|
472
459
|
const propertyName = node.property?.value;
|
|
473
460
|
if (propertyName) {
|
|
474
461
|
state.componentNames.add(propertyName);
|
|
475
|
-
console.log(`\u{1F517} Namespace access: ${namespaceName}.${propertyName}`);
|
|
476
462
|
}
|
|
477
463
|
}
|
|
478
464
|
}
|
|
@@ -664,14 +650,14 @@ function parseCode(code, options = {}) {
|
|
|
664
650
|
return report;
|
|
665
651
|
}
|
|
666
652
|
function parseFile(filePath, options = {}) {
|
|
667
|
-
console.log(`
|
|
668
|
-
\u{1F4C1} Analyzing: ${filePath}`);
|
|
669
653
|
try {
|
|
670
654
|
const code = fs3.readFileSync(filePath, "utf8");
|
|
671
655
|
return parseCode(code, options);
|
|
672
656
|
} catch (error) {
|
|
673
|
-
|
|
674
|
-
|
|
657
|
+
if (options.ignoreErrors) {
|
|
658
|
+
return null;
|
|
659
|
+
}
|
|
660
|
+
throw error;
|
|
675
661
|
}
|
|
676
662
|
}
|
|
677
663
|
function filterReportByLibrary(report, libraryName) {
|
|
@@ -712,7 +698,7 @@ function filterReportByLibrary(report, libraryName) {
|
|
|
712
698
|
}
|
|
713
699
|
|
|
714
700
|
// src/utils/aggregator.ts
|
|
715
|
-
function aggregateReports(reports, versions = {}) {
|
|
701
|
+
function aggregateReports(reports, versions = {}, errors = []) {
|
|
716
702
|
const componentUsageMap = /* @__PURE__ */ new Map();
|
|
717
703
|
let totalImports = 0;
|
|
718
704
|
let totalUsagePatterns = 0;
|
|
@@ -765,7 +751,8 @@ function aggregateReports(reports, versions = {}) {
|
|
|
765
751
|
topComponents,
|
|
766
752
|
allComponents,
|
|
767
753
|
packageDistribution,
|
|
768
|
-
reports
|
|
754
|
+
reports,
|
|
755
|
+
errors
|
|
769
756
|
};
|
|
770
757
|
}
|
|
771
758
|
function resolvePackageFromImportPath(importPath, availablePackages) {
|
|
@@ -945,14 +932,14 @@ function formatCount(num) {
|
|
|
945
932
|
return num.toLocaleString();
|
|
946
933
|
}
|
|
947
934
|
function formatDuration(seconds) {
|
|
948
|
-
return `${seconds.toFixed(
|
|
935
|
+
return `${seconds.toFixed(2)}s`;
|
|
949
936
|
}
|
|
950
937
|
|
|
951
938
|
// src/utils/print-summary.ts
|
|
952
939
|
function printHeader() {
|
|
953
|
-
console.log(
|
|
940
|
+
console.log(chalk5.green.bold("\n\u{1F4CA} Summary\n"));
|
|
954
941
|
}
|
|
955
|
-
function printSummary(aggregated
|
|
942
|
+
function printSummary(aggregated) {
|
|
956
943
|
printHeader();
|
|
957
944
|
const table = new Table({
|
|
958
945
|
head: ["Metric", "Count"],
|
|
@@ -975,30 +962,6 @@ function printSummary(aggregated, elapsedTimeSeconds) {
|
|
|
975
962
|
["Total Usages", formatCount(totalExternalUsage)]
|
|
976
963
|
);
|
|
977
964
|
console.log(table.toString());
|
|
978
|
-
console.log(
|
|
979
|
-
chalk6.green(
|
|
980
|
-
`Analysis completed successfully in ${formatDuration(elapsedTimeSeconds)}
|
|
981
|
-
`
|
|
982
|
-
)
|
|
983
|
-
);
|
|
984
|
-
}
|
|
985
|
-
function printHeader2() {
|
|
986
|
-
console.log(chalk6.cyan.bold("\n\u{1F4CB} Details\n"));
|
|
987
|
-
}
|
|
988
|
-
function printDetails(aggregated) {
|
|
989
|
-
printHeader2();
|
|
990
|
-
console.log(
|
|
991
|
-
chalk6.cyan(
|
|
992
|
-
` Total usage patterns: ${formatCount(aggregated.totalUsagePatterns)}`
|
|
993
|
-
)
|
|
994
|
-
);
|
|
995
|
-
for (const pattern of aggregated.patternCounts) {
|
|
996
|
-
if (pattern.count > 0) {
|
|
997
|
-
console.log(
|
|
998
|
-
chalk6.cyan(` ${pattern.displayName}: ${formatCount(pattern.count)}`)
|
|
999
|
-
);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
965
|
}
|
|
1003
966
|
function renderBarChart(data, options = {}) {
|
|
1004
967
|
const {
|
|
@@ -1008,12 +971,12 @@ function renderBarChart(data, options = {}) {
|
|
|
1008
971
|
emptyChar = "\u2591"
|
|
1009
972
|
} = options;
|
|
1010
973
|
if (data.length === 0) {
|
|
1011
|
-
console.log(
|
|
974
|
+
console.log(chalk5.gray(" No data to display"));
|
|
1012
975
|
return;
|
|
1013
976
|
}
|
|
1014
977
|
const maxValue = Math.max(...data.map((d) => d.value));
|
|
1015
978
|
if (maxValue === 0) {
|
|
1016
|
-
console.log(
|
|
979
|
+
console.log(chalk5.gray(" All values are zero"));
|
|
1017
980
|
return;
|
|
1018
981
|
}
|
|
1019
982
|
const maxLabelLength = Math.max(...data.map((d) => d.label.length));
|
|
@@ -1022,7 +985,7 @@ function renderBarChart(data, options = {}) {
|
|
|
1022
985
|
const barLength = Math.round(percentage * maxWidth);
|
|
1023
986
|
const emptyLength = maxWidth - barLength;
|
|
1024
987
|
const paddedLabel = item.label.padEnd(maxLabelLength, " ");
|
|
1025
|
-
const bar =
|
|
988
|
+
const bar = chalk5.green(barChar.repeat(barLength)) + chalk5.gray(emptyChar.repeat(emptyLength));
|
|
1026
989
|
const valueStr = showValues ? ` ${formatCount(item.value)}` : "";
|
|
1027
990
|
console.log(`${paddedLabel} ${bar}${valueStr}
|
|
1028
991
|
`);
|
|
@@ -1030,8 +993,8 @@ function renderBarChart(data, options = {}) {
|
|
|
1030
993
|
}
|
|
1031
994
|
|
|
1032
995
|
// src/utils/print-components.ts
|
|
1033
|
-
function
|
|
1034
|
-
console.log(
|
|
996
|
+
function printHeader2() {
|
|
997
|
+
console.log(chalk5.magenta.bold("\n\u269B\uFE0F Components\n"));
|
|
1035
998
|
}
|
|
1036
999
|
function printComponents(aggregated, mode) {
|
|
1037
1000
|
const components = aggregated.topComponents;
|
|
@@ -1042,12 +1005,12 @@ function printComponents(aggregated, mode) {
|
|
|
1042
1005
|
}
|
|
1043
1006
|
}
|
|
1044
1007
|
function printComponentsTable(components) {
|
|
1045
|
-
|
|
1008
|
+
printHeader2();
|
|
1046
1009
|
const externalComponents = components.filter(
|
|
1047
1010
|
(comp) => comp.source !== "unknown" && comp.source !== "local"
|
|
1048
1011
|
);
|
|
1049
1012
|
if (externalComponents.length === 0) {
|
|
1050
|
-
console.log(
|
|
1013
|
+
console.log(chalk5.gray(" No external components found"));
|
|
1051
1014
|
return;
|
|
1052
1015
|
}
|
|
1053
1016
|
const table = new Table({
|
|
@@ -1063,12 +1026,12 @@ function printComponentsTable(components) {
|
|
|
1063
1026
|
console.log(table.toString());
|
|
1064
1027
|
}
|
|
1065
1028
|
function printComponentsChart(components) {
|
|
1066
|
-
|
|
1029
|
+
printHeader2();
|
|
1067
1030
|
const externalComponents = components.filter(
|
|
1068
1031
|
(comp) => comp.source !== "unknown" && comp.source !== "local"
|
|
1069
1032
|
);
|
|
1070
1033
|
if (externalComponents.length === 0) {
|
|
1071
|
-
console.log(
|
|
1034
|
+
console.log(chalk5.gray(" No external components found"));
|
|
1072
1035
|
return;
|
|
1073
1036
|
}
|
|
1074
1037
|
const data = externalComponents.map((comp) => ({
|
|
@@ -1077,8 +1040,8 @@ function printComponentsChart(components) {
|
|
|
1077
1040
|
}));
|
|
1078
1041
|
renderBarChart(data, { maxWidth: 50 });
|
|
1079
1042
|
}
|
|
1080
|
-
function
|
|
1081
|
-
console.log(
|
|
1043
|
+
function printHeader3() {
|
|
1044
|
+
console.log(chalk5.blue.bold("\n\u{1F50D} Code Patterns\n"));
|
|
1082
1045
|
}
|
|
1083
1046
|
function printPatterns(aggregated, mode) {
|
|
1084
1047
|
const patterns = aggregated.patternCounts.filter((p) => p.count > 0);
|
|
@@ -1089,9 +1052,9 @@ function printPatterns(aggregated, mode) {
|
|
|
1089
1052
|
}
|
|
1090
1053
|
}
|
|
1091
1054
|
function printPatternsTable(patterns) {
|
|
1092
|
-
|
|
1055
|
+
printHeader3();
|
|
1093
1056
|
if (patterns.length === 0) {
|
|
1094
|
-
console.log(
|
|
1057
|
+
console.log(chalk5.gray(" No patterns found"));
|
|
1095
1058
|
return;
|
|
1096
1059
|
}
|
|
1097
1060
|
const table = new Table({
|
|
@@ -1106,13 +1069,13 @@ function printPatternsTable(patterns) {
|
|
|
1106
1069
|
});
|
|
1107
1070
|
console.log(table.toString());
|
|
1108
1071
|
const totalPatterns = patterns.reduce((sum, p) => sum + p.count, 0);
|
|
1109
|
-
console.log(
|
|
1072
|
+
console.log(chalk5.gray(`
|
|
1110
1073
|
Total: ${totalPatterns} patterns detected`));
|
|
1111
1074
|
}
|
|
1112
1075
|
function printPatternsChart(patterns) {
|
|
1113
|
-
|
|
1076
|
+
printHeader3();
|
|
1114
1077
|
if (patterns.length === 0) {
|
|
1115
|
-
console.log(
|
|
1078
|
+
console.log(chalk5.gray(" No patterns found"));
|
|
1116
1079
|
return;
|
|
1117
1080
|
}
|
|
1118
1081
|
const data = patterns.map((pattern) => ({
|
|
@@ -1121,8 +1084,8 @@ function printPatternsChart(patterns) {
|
|
|
1121
1084
|
}));
|
|
1122
1085
|
renderBarChart(data, { maxWidth: 50 });
|
|
1123
1086
|
}
|
|
1124
|
-
function
|
|
1125
|
-
console.log(
|
|
1087
|
+
function printHeader4() {
|
|
1088
|
+
console.log(chalk5.blueBright.bold("\n\u{1F4E6} Packages\n"));
|
|
1126
1089
|
}
|
|
1127
1090
|
function printPackages(aggregated, mode) {
|
|
1128
1091
|
const packages = aggregated.packageDistribution;
|
|
@@ -1133,9 +1096,9 @@ function printPackages(aggregated, mode) {
|
|
|
1133
1096
|
}
|
|
1134
1097
|
}
|
|
1135
1098
|
function printPackagesTable(packages) {
|
|
1136
|
-
|
|
1099
|
+
printHeader4();
|
|
1137
1100
|
if (packages.length === 0) {
|
|
1138
|
-
console.log(
|
|
1101
|
+
console.log(chalk5.gray(" No packages found"));
|
|
1139
1102
|
return;
|
|
1140
1103
|
}
|
|
1141
1104
|
const table = new Table({
|
|
@@ -1161,16 +1124,16 @@ function printPackagesTable(packages) {
|
|
|
1161
1124
|
);
|
|
1162
1125
|
const totalExternalUsage = packages.reduce((sum, p) => sum + p.usageCount, 0);
|
|
1163
1126
|
console.log(
|
|
1164
|
-
|
|
1127
|
+
chalk5.gray(
|
|
1165
1128
|
`
|
|
1166
1129
|
Total: ${formatCount(packages.length)} packages | ${formatCount(totalComponents)} unique components | ${formatCount(totalExternalUsage)} total usages`
|
|
1167
1130
|
)
|
|
1168
1131
|
);
|
|
1169
1132
|
}
|
|
1170
1133
|
function printPackagesChart(packages) {
|
|
1171
|
-
|
|
1134
|
+
printHeader4();
|
|
1172
1135
|
if (packages.length === 0) {
|
|
1173
|
-
console.log(
|
|
1136
|
+
console.log(chalk5.gray(" No packages found"));
|
|
1174
1137
|
return;
|
|
1175
1138
|
}
|
|
1176
1139
|
const maxBarWidth = 40;
|
|
@@ -1182,12 +1145,37 @@ function printPackagesChart(packages) {
|
|
|
1182
1145
|
);
|
|
1183
1146
|
const emptyLength = maxBarWidth - barLength;
|
|
1184
1147
|
const paddedLabel = pkg.packageName.padEnd(maxLabelLength, " ");
|
|
1185
|
-
const bar =
|
|
1148
|
+
const bar = chalk5.green("\u2588".repeat(barLength)) + chalk5.gray("\u2591".repeat(emptyLength));
|
|
1186
1149
|
console.log(
|
|
1187
|
-
`${paddedLabel} ${bar} ${
|
|
1150
|
+
`${paddedLabel} ${bar} ${chalk5.bold(pkg.percentage.toFixed(1) + "%")} (${pkg.usageCount})`
|
|
1188
1151
|
);
|
|
1189
1152
|
});
|
|
1190
1153
|
}
|
|
1154
|
+
function printHeader5(errorCount) {
|
|
1155
|
+
console.log(chalk5.red.bold(`
|
|
1156
|
+
\u274C Parse Errors (${errorCount})
|
|
1157
|
+
`));
|
|
1158
|
+
}
|
|
1159
|
+
function printErrors(aggregated) {
|
|
1160
|
+
const errors = aggregated.errors;
|
|
1161
|
+
if (errors.length === 0) {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
printHeader5(errors.length);
|
|
1165
|
+
const table = new Table({
|
|
1166
|
+
head: ["File", "Error"],
|
|
1167
|
+
style: {
|
|
1168
|
+
head: ["cyan"],
|
|
1169
|
+
border: ["gray"]
|
|
1170
|
+
},
|
|
1171
|
+
colWidths: [50, 80],
|
|
1172
|
+
wordWrap: true
|
|
1173
|
+
});
|
|
1174
|
+
errors.forEach((error) => {
|
|
1175
|
+
table.push([chalk5.yellow(error.file), chalk5.red(error.message)]);
|
|
1176
|
+
});
|
|
1177
|
+
console.log(table.toString());
|
|
1178
|
+
}
|
|
1191
1179
|
async function findFiles(pattern, ignorePatterns) {
|
|
1192
1180
|
const files = await glob(pattern, {
|
|
1193
1181
|
ignore: ignorePatterns,
|
|
@@ -1385,16 +1373,13 @@ function registerScanCommand(program2) {
|
|
|
1385
1373
|
"**/node_modules/**",
|
|
1386
1374
|
"**/dist/**",
|
|
1387
1375
|
"**/build/**"
|
|
1376
|
+
]).option("--allow-packages <pattern>", "Pattern for what packages to scan", [
|
|
1377
|
+
"**"
|
|
1388
1378
|
]).option(
|
|
1389
|
-
"--allow-packages <pattern>",
|
|
1390
|
-
"Glob pattern for what packages to scan",
|
|
1391
|
-
"ALL"
|
|
1392
|
-
// TO FIX
|
|
1393
|
-
).option(
|
|
1394
1379
|
"--ignore-packages <pattern>",
|
|
1395
|
-
"
|
|
1380
|
+
"Pattern for what packages to ignore",
|
|
1396
1381
|
[]
|
|
1397
|
-
).option("--
|
|
1382
|
+
).option("--no-summary", "Hide summary", "table").option(
|
|
1398
1383
|
"--components [mode]",
|
|
1399
1384
|
"Show components table/chart (table, chart)",
|
|
1400
1385
|
"table"
|
|
@@ -1406,26 +1391,32 @@ function registerScanCommand(program2) {
|
|
|
1406
1391
|
"--patterns [mode]",
|
|
1407
1392
|
"Show patterns table/chart (table, chart)",
|
|
1408
1393
|
"table"
|
|
1409
|
-
).option("--no-patterns", "Do not show patterns").
|
|
1394
|
+
).option("--no-patterns", "Do not show patterns").option(
|
|
1395
|
+
"--ignore-errors",
|
|
1396
|
+
"Continue scanning even if some files fail to parse"
|
|
1397
|
+
).action(async (pattern, options) => {
|
|
1410
1398
|
const normalizedOptions = normalizeOptions(options);
|
|
1411
1399
|
await executeScan(pattern, normalizedOptions);
|
|
1412
1400
|
});
|
|
1413
1401
|
}
|
|
1414
|
-
function
|
|
1415
|
-
if (!
|
|
1402
|
+
function normalizeArray(value) {
|
|
1403
|
+
if (!value) {
|
|
1416
1404
|
return [];
|
|
1417
1405
|
}
|
|
1418
|
-
return Array.isArray(
|
|
1406
|
+
return Array.isArray(value) ? value : [value];
|
|
1419
1407
|
}
|
|
1420
1408
|
function normalizeOptions(options) {
|
|
1421
1409
|
return {
|
|
1422
1410
|
verbose: options.verbose || false,
|
|
1423
1411
|
summary: options.summary === false || options.summary === "false" ? false : "log",
|
|
1424
|
-
|
|
1412
|
+
noSummary: options.noSummary || false,
|
|
1425
1413
|
components: options.components || "table",
|
|
1426
1414
|
packages: options.packages || "table",
|
|
1427
1415
|
patterns: options.patterns || "table",
|
|
1428
|
-
ignore:
|
|
1416
|
+
ignore: normalizeArray(options.ignore),
|
|
1417
|
+
allowPackages: normalizeArray(options.allowPackages),
|
|
1418
|
+
ignorePackages: normalizeArray(options.ignorePackages),
|
|
1419
|
+
ignoreErrors: options.ignoreErrors || false
|
|
1429
1420
|
};
|
|
1430
1421
|
}
|
|
1431
1422
|
async function executeScan(pattern, options) {
|
|
@@ -1433,59 +1424,82 @@ async function executeScan(pattern, options) {
|
|
|
1433
1424
|
const spinner = ora("Parsing lockfile...").start();
|
|
1434
1425
|
try {
|
|
1435
1426
|
const lockfileResult = findAndParseLockfile(process.cwd());
|
|
1427
|
+
const allPackages = Object.keys(lockfileResult.versions);
|
|
1428
|
+
const filteredPackages = allPackages.filter((pkg) => {
|
|
1429
|
+
const allowed = options.allowPackages.some((p) => minimatch(pkg, p));
|
|
1430
|
+
const ignored = options.ignorePackages.some((p) => minimatch(pkg, p));
|
|
1431
|
+
return allowed && !ignored;
|
|
1432
|
+
});
|
|
1433
|
+
const filteredVersions = {};
|
|
1434
|
+
for (const pkg of filteredPackages) {
|
|
1435
|
+
filteredVersions[pkg] = lockfileResult.versions[pkg];
|
|
1436
|
+
}
|
|
1436
1437
|
spinner.succeed(
|
|
1437
|
-
|
|
1438
|
-
`\u{1F4E6} Found ${lockfileResult.lockfileType} lockfile (supports: ${lockfileResult.supportedVersions.join(", ")}) - ${Object.keys(lockfileResult.versions).length} packages`
|
|
1439
|
-
)
|
|
1438
|
+
`Found ${lockfileResult.lockfileType} lockfile (supports: ${lockfileResult.supportedVersions.join(", ")}) - ${filteredPackages.length}/${allPackages.length} packages`
|
|
1440
1439
|
);
|
|
1441
|
-
console.log("availablePackages", lockfileResult);
|
|
1442
1440
|
spinner.start("Finding files...");
|
|
1443
1441
|
const files = await findFiles(pattern, options.ignore);
|
|
1444
1442
|
if (files.length === 0) {
|
|
1445
|
-
spinner.fail(
|
|
1443
|
+
spinner.fail(`No files found matching pattern: ${pattern}`);
|
|
1446
1444
|
return;
|
|
1447
1445
|
}
|
|
1448
|
-
spinner.succeed(
|
|
1446
|
+
spinner.succeed(chalk5.green(` Found ${files.length} files`));
|
|
1449
1447
|
spinner.start("Analyzing files...");
|
|
1450
1448
|
const reports = [];
|
|
1449
|
+
const errors = [];
|
|
1451
1450
|
for (let i = 0; i < files.length; i++) {
|
|
1452
1451
|
const file = files[i];
|
|
1453
1452
|
if (!options.verbose) {
|
|
1454
1453
|
spinner.text = `Analyzing files... (${i + 1}/${files.length})`;
|
|
1455
1454
|
}
|
|
1456
1455
|
try {
|
|
1457
|
-
const report = parseFile(file);
|
|
1456
|
+
const report = parseFile(file, { ignoreErrors: options.ignoreErrors });
|
|
1458
1457
|
if (report) {
|
|
1459
1458
|
reports.push(report);
|
|
1459
|
+
} else if (options.ignoreErrors) {
|
|
1460
|
+
errors.push({
|
|
1461
|
+
file,
|
|
1462
|
+
message: "Failed to parse file"
|
|
1463
|
+
});
|
|
1460
1464
|
}
|
|
1461
1465
|
} catch (error) {
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1466
|
+
if (options.ignoreErrors) {
|
|
1467
|
+
errors.push({
|
|
1468
|
+
file,
|
|
1469
|
+
message: error.message || "Unknown error"
|
|
1470
|
+
});
|
|
1471
|
+
} else {
|
|
1472
|
+
throw error;
|
|
1473
|
+
}
|
|
1465
1474
|
}
|
|
1466
1475
|
}
|
|
1467
|
-
spinner.succeed(
|
|
1468
|
-
chalk6.green(`Analysis complete! Analyzed ${reports.length} files`)
|
|
1469
|
-
);
|
|
1470
1476
|
const elapsedTime = (Date.now() - startTime) / 1e3;
|
|
1471
|
-
const aggregated = aggregateReports(reports,
|
|
1472
|
-
|
|
1477
|
+
const aggregated = aggregateReports(reports, filteredVersions, errors);
|
|
1478
|
+
printErrors(aggregated);
|
|
1479
|
+
if (options.packages && !options.noPackages) {
|
|
1473
1480
|
printPackages(aggregated, options.packages);
|
|
1474
1481
|
}
|
|
1475
|
-
if (options.
|
|
1476
|
-
printDetails(aggregated);
|
|
1477
|
-
}
|
|
1478
|
-
if (options.components) {
|
|
1482
|
+
if (options.components && !options.noComponents) {
|
|
1479
1483
|
printComponents(aggregated, options.components);
|
|
1480
1484
|
}
|
|
1481
|
-
if (options.patterns) {
|
|
1485
|
+
if (options.patterns && !options.noPatterns) {
|
|
1482
1486
|
printPatterns(aggregated, options.patterns);
|
|
1483
1487
|
}
|
|
1484
|
-
if (options.summary) {
|
|
1485
|
-
printSummary(aggregated
|
|
1488
|
+
if (options.summary && !options.noSummary) {
|
|
1489
|
+
printSummary(aggregated);
|
|
1490
|
+
}
|
|
1491
|
+
console.log("");
|
|
1492
|
+
const successMessage = aggregated.errors.length > 0 ? ` Analysis complete with ${aggregated.errors.length} error(s)! Analyzed ${reports.length}/${files.length} files in ${formatDuration(elapsedTime)}
|
|
1493
|
+
` : ` Analysis complete! Analyzed ${reports.length} files in ${formatDuration(elapsedTime)}
|
|
1494
|
+
`;
|
|
1495
|
+
if (aggregated.errors.length > 0) {
|
|
1496
|
+
spinner.warn(chalk5.yellow.bold(successMessage));
|
|
1497
|
+
process.exit(1);
|
|
1498
|
+
} else {
|
|
1499
|
+
spinner.succeed(chalk5.green.bold(successMessage));
|
|
1486
1500
|
}
|
|
1487
1501
|
} catch (error) {
|
|
1488
|
-
spinner.fail(
|
|
1502
|
+
spinner.fail(chalk5.red("Analysis failed: " + error.message));
|
|
1489
1503
|
console.error(error);
|
|
1490
1504
|
process.exit(1);
|
|
1491
1505
|
}
|
|
@@ -1493,7 +1507,7 @@ async function executeScan(pattern, options) {
|
|
|
1493
1507
|
|
|
1494
1508
|
// package.json
|
|
1495
1509
|
var package_default = {
|
|
1496
|
-
version: "1.1.
|
|
1510
|
+
version: "1.1.2"};
|
|
1497
1511
|
|
|
1498
1512
|
// src/cli.ts
|
|
1499
1513
|
var program = new Command();
|