@vibgrate/cli 0.1.3 → 0.1.4
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.
|
@@ -95,9 +95,9 @@ function clamp(val, min, max) {
|
|
|
95
95
|
return Math.min(max, Math.max(min, val));
|
|
96
96
|
}
|
|
97
97
|
function runtimeScore(projects) {
|
|
98
|
-
if (projects.length === 0) return
|
|
98
|
+
if (projects.length === 0) return null;
|
|
99
99
|
const lags = projects.map((p) => p.runtimeMajorsBehind).filter((v) => v !== void 0);
|
|
100
|
-
if (lags.length === 0) return
|
|
100
|
+
if (lags.length === 0) return null;
|
|
101
101
|
const maxLag = Math.max(...lags);
|
|
102
102
|
if (maxLag === 0) return 100;
|
|
103
103
|
if (maxLag === 1) return 80;
|
|
@@ -107,9 +107,9 @@ function runtimeScore(projects) {
|
|
|
107
107
|
}
|
|
108
108
|
function frameworkScore(projects) {
|
|
109
109
|
const allFrameworks = projects.flatMap((p) => p.frameworks);
|
|
110
|
-
if (allFrameworks.length === 0) return
|
|
110
|
+
if (allFrameworks.length === 0) return null;
|
|
111
111
|
const lags = allFrameworks.map((f) => f.majorsBehind).filter((v) => v !== null);
|
|
112
|
-
if (lags.length === 0) return
|
|
112
|
+
if (lags.length === 0) return null;
|
|
113
113
|
const maxLag = Math.max(...lags);
|
|
114
114
|
const avgLag = lags.reduce((a, b) => a + b, 0) / lags.length;
|
|
115
115
|
const maxPenalty = Math.min(maxLag * 20, 100);
|
|
@@ -128,13 +128,15 @@ function dependencyScore(projects) {
|
|
|
128
128
|
totalUnknown += p.dependencyAgeBuckets.unknown;
|
|
129
129
|
}
|
|
130
130
|
const total = totalCurrent + totalOne + totalTwo;
|
|
131
|
-
if (total === 0) return
|
|
131
|
+
if (total === 0) return null;
|
|
132
132
|
const currentPct = totalCurrent / total;
|
|
133
133
|
const onePct = totalOne / total;
|
|
134
134
|
const twoPct = totalTwo / total;
|
|
135
135
|
return clamp(Math.round(currentPct * 100 - onePct * 10 - twoPct * 40), 0, 100);
|
|
136
136
|
}
|
|
137
137
|
function eolScore(projects) {
|
|
138
|
+
const hasRuntimeData = projects.some((p) => p.runtimeMajorsBehind !== void 0);
|
|
139
|
+
if (!hasRuntimeData) return null;
|
|
138
140
|
let score = 100;
|
|
139
141
|
for (const p of projects) {
|
|
140
142
|
if (p.type === "node" && p.runtimeMajorsBehind !== void 0) {
|
|
@@ -155,20 +157,50 @@ function computeDriftScore(projects) {
|
|
|
155
157
|
const fs5 = frameworkScore(projects);
|
|
156
158
|
const ds = dependencyScore(projects);
|
|
157
159
|
const es = eolScore(projects);
|
|
158
|
-
const
|
|
160
|
+
const components = [
|
|
161
|
+
{ score: rs, weight: 0.25 },
|
|
162
|
+
{ score: fs5, weight: 0.25 },
|
|
163
|
+
{ score: ds, weight: 0.3 },
|
|
164
|
+
{ score: es, weight: 0.2 }
|
|
165
|
+
];
|
|
166
|
+
const active = components.filter((c) => c.score !== null);
|
|
167
|
+
if (active.length === 0) {
|
|
168
|
+
return {
|
|
169
|
+
score: 100,
|
|
170
|
+
riskLevel: "low",
|
|
171
|
+
components: {
|
|
172
|
+
runtimeScore: rs ?? 100,
|
|
173
|
+
frameworkScore: fs5 ?? 100,
|
|
174
|
+
dependencyScore: ds ?? 100,
|
|
175
|
+
eolScore: es ?? 100
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const totalActiveWeight = active.reduce((sum, c) => sum + c.weight, 0);
|
|
180
|
+
let score = 0;
|
|
181
|
+
for (const c of active) {
|
|
182
|
+
score += c.score * (c.weight / totalActiveWeight);
|
|
183
|
+
}
|
|
184
|
+
score = Math.round(score);
|
|
159
185
|
let riskLevel;
|
|
160
186
|
if (score >= 70) riskLevel = "low";
|
|
161
187
|
else if (score >= 40) riskLevel = "moderate";
|
|
162
188
|
else riskLevel = "high";
|
|
189
|
+
const measured = [];
|
|
190
|
+
if (rs !== null) measured.push("runtime");
|
|
191
|
+
if (fs5 !== null) measured.push("framework");
|
|
192
|
+
if (ds !== null) measured.push("dependency");
|
|
193
|
+
if (es !== null) measured.push("eol");
|
|
163
194
|
return {
|
|
164
195
|
score,
|
|
165
196
|
riskLevel,
|
|
166
197
|
components: {
|
|
167
|
-
runtimeScore: rs,
|
|
168
|
-
frameworkScore: fs5,
|
|
169
|
-
dependencyScore: ds,
|
|
170
|
-
eolScore: es
|
|
171
|
-
}
|
|
198
|
+
runtimeScore: rs ?? 100,
|
|
199
|
+
frameworkScore: fs5 ?? 100,
|
|
200
|
+
dependencyScore: ds ?? 100,
|
|
201
|
+
eolScore: es ?? 100
|
|
202
|
+
},
|
|
203
|
+
measured
|
|
172
204
|
};
|
|
173
205
|
}
|
|
174
206
|
function generateFindings(projects, config) {
|
|
@@ -263,11 +295,12 @@ function formatText(artifact) {
|
|
|
263
295
|
lines.push(chalk.bold(" VCS: ") + vcsParts.join(" "));
|
|
264
296
|
}
|
|
265
297
|
lines.push("");
|
|
298
|
+
const m = new Set(artifact.drift.measured ?? ["runtime", "framework", "dependency", "eol"]);
|
|
266
299
|
lines.push(chalk.bold.underline(" Score Breakdown"));
|
|
267
|
-
lines.push(` Runtime: ${scoreBar(artifact.drift.components.runtimeScore)}`);
|
|
268
|
-
lines.push(` Frameworks: ${scoreBar(artifact.drift.components.frameworkScore)}`);
|
|
269
|
-
lines.push(` Dependencies: ${scoreBar(artifact.drift.components.dependencyScore)}`);
|
|
270
|
-
lines.push(` EOL Risk: ${scoreBar(artifact.drift.components.eolScore)}`);
|
|
300
|
+
lines.push(` Runtime: ${m.has("runtime") ? scoreBar(artifact.drift.components.runtimeScore) : chalk.dim("n/a")}`);
|
|
301
|
+
lines.push(` Frameworks: ${m.has("framework") ? scoreBar(artifact.drift.components.frameworkScore) : chalk.dim("n/a")}`);
|
|
302
|
+
lines.push(` Dependencies: ${m.has("dependency") ? scoreBar(artifact.drift.components.dependencyScore) : chalk.dim("n/a")}`);
|
|
303
|
+
lines.push(` EOL Risk: ${m.has("eol") ? scoreBar(artifact.drift.components.eolScore) : chalk.dim("n/a")}`);
|
|
271
304
|
lines.push("");
|
|
272
305
|
for (const project of artifact.projects) {
|
|
273
306
|
lines.push(chalk.bold(` \u2500\u2500 ${project.name} `) + chalk.dim(`(${project.type}) ${project.path}`));
|
|
@@ -293,8 +326,24 @@ function formatText(artifact) {
|
|
|
293
326
|
}
|
|
294
327
|
lines.push("");
|
|
295
328
|
}
|
|
329
|
+
if (artifact.delta !== void 0) {
|
|
330
|
+
const deltaStr = artifact.delta > 0 ? chalk.green(`+${artifact.delta}`) : artifact.delta < 0 ? chalk.red(`${artifact.delta}`) : chalk.dim("0");
|
|
331
|
+
lines.push(chalk.bold(" Drift Delta: ") + deltaStr + " (vs baseline)");
|
|
332
|
+
lines.push("");
|
|
333
|
+
}
|
|
334
|
+
if (artifact.extended) {
|
|
335
|
+
lines.push(...formatExtended(artifact.extended));
|
|
336
|
+
}
|
|
296
337
|
if (artifact.findings.length > 0) {
|
|
297
|
-
|
|
338
|
+
const errors = artifact.findings.filter((f) => f.level === "error");
|
|
339
|
+
const warnings = artifact.findings.filter((f) => f.level === "warning");
|
|
340
|
+
const notes = artifact.findings.filter((f) => f.level === "note");
|
|
341
|
+
const summary = [
|
|
342
|
+
errors.length > 0 ? chalk.red(`${errors.length} error${errors.length !== 1 ? "s" : ""}`) : "",
|
|
343
|
+
warnings.length > 0 ? chalk.yellow(`${warnings.length} warning${warnings.length !== 1 ? "s" : ""}`) : "",
|
|
344
|
+
notes.length > 0 ? chalk.blue(`${notes.length} note${notes.length !== 1 ? "s" : ""}`) : ""
|
|
345
|
+
].filter(Boolean).join(chalk.dim(", "));
|
|
346
|
+
lines.push(chalk.bold.underline(` Findings`) + chalk.dim(` (${summary})`));
|
|
298
347
|
for (const f of artifact.findings) {
|
|
299
348
|
const icon = f.level === "error" ? chalk.red("\u2716") : f.level === "warning" ? chalk.yellow("\u26A0") : chalk.blue("\u2139");
|
|
300
349
|
lines.push(` ${icon} ${f.message}`);
|
|
@@ -302,13 +351,20 @@ function formatText(artifact) {
|
|
|
302
351
|
}
|
|
303
352
|
lines.push("");
|
|
304
353
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
lines.push(chalk.bold("
|
|
354
|
+
const actions = generatePriorityActions(artifact);
|
|
355
|
+
if (actions.length > 0) {
|
|
356
|
+
lines.push(chalk.bold.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
|
|
357
|
+
lines.push(chalk.bold.cyan("\u2551 Top Priority Actions \u2551"));
|
|
358
|
+
lines.push(chalk.bold.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
|
|
308
359
|
lines.push("");
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
360
|
+
for (let i = 0; i < actions.length; i++) {
|
|
361
|
+
const a = actions[i];
|
|
362
|
+
const num = chalk.bold.cyan(` ${i + 1}.`);
|
|
363
|
+
lines.push(`${num} ${chalk.bold(a.title)}`);
|
|
364
|
+
lines.push(chalk.dim(` ${a.explanation}`));
|
|
365
|
+
if (a.impact) lines.push(` Impact: ${chalk.green(a.impact)}`);
|
|
366
|
+
lines.push("");
|
|
367
|
+
}
|
|
312
368
|
}
|
|
313
369
|
lines.push(chalk.dim(` Scanned at ${artifact.timestamp}`));
|
|
314
370
|
lines.push("");
|
|
@@ -331,7 +387,7 @@ function scoreBar(score) {
|
|
|
331
387
|
const filled = Math.round(score / 100 * width);
|
|
332
388
|
const empty = width - filled;
|
|
333
389
|
const color = score >= 70 ? chalk.green : score >= 40 ? chalk.yellow : chalk.red;
|
|
334
|
-
return color("\u2588".repeat(filled)) + chalk.dim("\u2591".repeat(empty)) + ` ${score}`;
|
|
390
|
+
return color("\u2588".repeat(filled)) + chalk.dim("\u2591".repeat(empty)) + ` ${Math.round(score)}`;
|
|
335
391
|
}
|
|
336
392
|
var CATEGORY_LABELS = {
|
|
337
393
|
frontend: "Frontend",
|
|
@@ -471,6 +527,149 @@ function formatExtended(ext) {
|
|
|
471
527
|
}
|
|
472
528
|
return lines;
|
|
473
529
|
}
|
|
530
|
+
function generatePriorityActions(artifact) {
|
|
531
|
+
const actions = [];
|
|
532
|
+
const eolProjects = artifact.projects.filter(
|
|
533
|
+
(p) => p.runtimeMajorsBehind !== void 0 && p.runtimeMajorsBehind >= 3
|
|
534
|
+
);
|
|
535
|
+
if (eolProjects.length > 0) {
|
|
536
|
+
const names = eolProjects.map((p) => p.name).join(", ");
|
|
537
|
+
const runtimes = eolProjects.map((p) => `${p.runtime} \u2192 ${p.runtimeLatest}`).join(", ");
|
|
538
|
+
actions.push({
|
|
539
|
+
title: `Upgrade EOL runtime${eolProjects.length > 1 ? "s" : ""} in ${names}`,
|
|
540
|
+
explanation: `${runtimes}. End-of-life runtimes no longer receive security patches and block ecosystem upgrades.`,
|
|
541
|
+
impact: `+${Math.min(eolProjects.length * 10, 30)} points (runtime & EOL scores)`,
|
|
542
|
+
severity: 100
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
const severeFrameworks = [];
|
|
546
|
+
for (const p of artifact.projects) {
|
|
547
|
+
for (const fw of p.frameworks) {
|
|
548
|
+
if (fw.majorsBehind !== null && fw.majorsBehind >= 3) {
|
|
549
|
+
severeFrameworks.push({ name: fw.name, fw: `${fw.currentVersion} \u2192 ${fw.latestVersion}`, behind: fw.majorsBehind, project: p.name });
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (severeFrameworks.length > 0) {
|
|
554
|
+
const worst = severeFrameworks.sort((a, b) => b.behind - a.behind)[0];
|
|
555
|
+
const others = severeFrameworks.length > 1 ? ` (+${severeFrameworks.length - 1} more)` : "";
|
|
556
|
+
actions.push({
|
|
557
|
+
title: `Upgrade ${worst.name} ${worst.fw} in ${worst.project}${others}`,
|
|
558
|
+
explanation: `${worst.behind} major versions behind. Major framework drift increases breaking change risk and blocks access to security fixes and performance improvements.`,
|
|
559
|
+
impact: `+5\u201315 points (framework score)`,
|
|
560
|
+
severity: 90
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
for (const p of artifact.projects) {
|
|
564
|
+
const b = p.dependencyAgeBuckets;
|
|
565
|
+
const total = b.current + b.oneBehind + b.twoPlusBehind;
|
|
566
|
+
if (total === 0) continue;
|
|
567
|
+
const twoPlusPct = Math.round(b.twoPlusBehind / total * 100);
|
|
568
|
+
if (twoPlusPct >= 40) {
|
|
569
|
+
actions.push({
|
|
570
|
+
title: `Reduce dependency rot in ${p.name} (${twoPlusPct}% severely outdated)`,
|
|
571
|
+
explanation: `${b.twoPlusBehind} of ${total} dependencies are 2+ majors behind. Run \`npm outdated\` and prioritise packages with known CVEs or breaking API changes.`,
|
|
572
|
+
impact: `+5\u201310 points (dependency score)`,
|
|
573
|
+
severity: 80 + twoPlusPct / 10
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
const twoMajorFrameworks = [];
|
|
578
|
+
for (const p of artifact.projects) {
|
|
579
|
+
for (const fw of p.frameworks) {
|
|
580
|
+
if (fw.majorsBehind === 2) {
|
|
581
|
+
twoMajorFrameworks.push({ name: fw.name, project: p.name, fw: `${fw.currentVersion} \u2192 ${fw.latestVersion}` });
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
const uniqueTwo = [...new Map(twoMajorFrameworks.map((f) => [f.name, f])).values()];
|
|
586
|
+
if (uniqueTwo.length > 0) {
|
|
587
|
+
const list = uniqueTwo.slice(0, 3).map((f) => `${f.name} (${f.fw})`).join(", ");
|
|
588
|
+
const moreCount = uniqueTwo.length > 3 ? ` +${uniqueTwo.length - 3} more` : "";
|
|
589
|
+
actions.push({
|
|
590
|
+
title: `Plan major framework upgrades: ${list}${moreCount}`,
|
|
591
|
+
explanation: `These frameworks are 2 major versions behind. Create upgrade tickets and check migration guides \u2014 the gap will widen with each new release.`,
|
|
592
|
+
impact: `+5\u201310 points (framework score)`,
|
|
593
|
+
severity: 60
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
if (artifact.extended?.breakingChangeExposure) {
|
|
597
|
+
const bc = artifact.extended.breakingChangeExposure;
|
|
598
|
+
const total = bc.deprecatedPackages.length + bc.legacyPolyfills.length;
|
|
599
|
+
if (total > 0) {
|
|
600
|
+
const items = [...bc.deprecatedPackages, ...bc.legacyPolyfills].slice(0, 5).join(", ");
|
|
601
|
+
const moreCount = total > 5 ? ` +${total - 5} more` : "";
|
|
602
|
+
actions.push({
|
|
603
|
+
title: `Replace deprecated/legacy packages: ${items}${moreCount}`,
|
|
604
|
+
explanation: `${total} package${total !== 1 ? "s" : ""} are deprecated or legacy polyfills. These receive no updates and may have known vulnerabilities.`,
|
|
605
|
+
severity: 55
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
if (artifact.extended?.dependencyGraph) {
|
|
610
|
+
const dg = artifact.extended.dependencyGraph;
|
|
611
|
+
const phantomCount = dg.phantomDependencies.length;
|
|
612
|
+
if (phantomCount >= 10) {
|
|
613
|
+
let detail = `Packages used in code but not declared in package.json. These rely on transitive installs and can break unpredictably when other packages update.`;
|
|
614
|
+
const details = dg.phantomDependencyDetails;
|
|
615
|
+
if (details && details.length > 0) {
|
|
616
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
617
|
+
for (const d of details) {
|
|
618
|
+
if (!byPath.has(d.sourcePath)) byPath.set(d.sourcePath, []);
|
|
619
|
+
byPath.get(d.sourcePath).push({ package: d.package, spec: d.spec });
|
|
620
|
+
}
|
|
621
|
+
const pathLines = [];
|
|
622
|
+
let shown = 0;
|
|
623
|
+
for (const [srcPath, pkgs] of byPath) {
|
|
624
|
+
if (shown >= 10) break;
|
|
625
|
+
pathLines.push(`
|
|
626
|
+
./${srcPath}`);
|
|
627
|
+
for (const pkg2 of pkgs) {
|
|
628
|
+
if (shown >= 10) break;
|
|
629
|
+
pathLines.push(` ${pkg2.package}: ${pkg2.spec}`);
|
|
630
|
+
shown++;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
const remaining = phantomCount - shown;
|
|
634
|
+
detail += pathLines.join("");
|
|
635
|
+
if (remaining > 0) detail += `
|
|
636
|
+
... and ${remaining} more`;
|
|
637
|
+
}
|
|
638
|
+
actions.push({
|
|
639
|
+
title: `Fix ${phantomCount} phantom dependencies`,
|
|
640
|
+
explanation: detail,
|
|
641
|
+
severity: 45
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (artifact.extended?.securityPosture) {
|
|
646
|
+
const sec = artifact.extended.securityPosture;
|
|
647
|
+
if (sec.envFilesTracked || !sec.lockfilePresent) {
|
|
648
|
+
const issues = [];
|
|
649
|
+
if (sec.envFilesTracked) issues.push(".env files are tracked in git");
|
|
650
|
+
if (!sec.lockfilePresent) issues.push("no lockfile found");
|
|
651
|
+
actions.push({
|
|
652
|
+
title: `Fix security posture: ${issues.join(", ")}`,
|
|
653
|
+
explanation: sec.envFilesTracked ? "Environment files may contain secrets. Add them to .gitignore and rotate any exposed credentials immediately." : "Without a lockfile, installs are non-deterministic. Run the install command to generate one and commit it.",
|
|
654
|
+
severity: 95
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (artifact.extended?.dependencyGraph) {
|
|
659
|
+
const dupes = artifact.extended.dependencyGraph.duplicatedPackages;
|
|
660
|
+
const highImpactDupes = dupes.filter((d) => d.versions.length >= 3);
|
|
661
|
+
if (highImpactDupes.length >= 3) {
|
|
662
|
+
const names = highImpactDupes.slice(0, 4).map((d) => `${d.name} (${d.versions.length}v)`).join(", ");
|
|
663
|
+
actions.push({
|
|
664
|
+
title: `Deduplicate heavily-versioned packages`,
|
|
665
|
+
explanation: `${highImpactDupes.length} packages have 3+ versions installed: ${names}. Run \`npm dedupe\` to reduce bundle size and install time.`,
|
|
666
|
+
severity: 35
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
actions.sort((a, b) => b.severity - a.severity);
|
|
671
|
+
return actions.slice(0, 5);
|
|
672
|
+
}
|
|
474
673
|
|
|
475
674
|
// src/formatters/sarif.ts
|
|
476
675
|
function formatSarif(artifact) {
|
|
@@ -2021,9 +2220,11 @@ async function scanDependencyGraph(rootDir) {
|
|
|
2021
2220
|
const lockedNames = new Set(versionMap.keys());
|
|
2022
2221
|
const pkgFiles = await findPackageJsonFiles(rootDir);
|
|
2023
2222
|
const phantoms = /* @__PURE__ */ new Set();
|
|
2223
|
+
const phantomDetails = [];
|
|
2024
2224
|
for (const pjPath of pkgFiles) {
|
|
2025
2225
|
try {
|
|
2026
2226
|
const pj = await readJsonFile(pjPath);
|
|
2227
|
+
const relPath = path7.relative(rootDir, pjPath);
|
|
2027
2228
|
for (const section of ["dependencies", "devDependencies"]) {
|
|
2028
2229
|
const deps = pj[section];
|
|
2029
2230
|
if (!deps) continue;
|
|
@@ -2031,6 +2232,7 @@ async function scanDependencyGraph(rootDir) {
|
|
|
2031
2232
|
const ver = typeof version === "string" ? version : "";
|
|
2032
2233
|
if (!lockedNames.has(name) && !ver.startsWith("workspace:")) {
|
|
2033
2234
|
phantoms.add(name);
|
|
2235
|
+
phantomDetails.push({ package: name, spec: ver, sourcePath: relPath });
|
|
2034
2236
|
}
|
|
2035
2237
|
}
|
|
2036
2238
|
}
|
|
@@ -2038,6 +2240,7 @@ async function scanDependencyGraph(rootDir) {
|
|
|
2038
2240
|
}
|
|
2039
2241
|
}
|
|
2040
2242
|
result.phantomDependencies = [...phantoms].sort();
|
|
2243
|
+
result.phantomDependencyDetails = phantomDetails.sort((a, b) => a.sourcePath.localeCompare(b.sourcePath) || a.package.localeCompare(b.package));
|
|
2041
2244
|
return result;
|
|
2042
2245
|
}
|
|
2043
2246
|
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-AMOJCCF5.js";
|
|
5
5
|
import {
|
|
6
6
|
baselineCommand
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-BTIIFIOD.js";
|
|
8
8
|
import {
|
|
9
9
|
VERSION,
|
|
10
10
|
ensureDir,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
scanCommand,
|
|
16
16
|
writeDefaultConfig,
|
|
17
17
|
writeTextFile
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-WO6EZ6AF.js";
|
|
19
19
|
|
|
20
20
|
// src/cli.ts
|
|
21
21
|
import { Command as Command6 } from "commander";
|
|
@@ -38,7 +38,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
|
|
|
38
38
|
console.log(chalk.green("\u2714") + ` Created ${chalk.bold("vibgrate.config.ts")}`);
|
|
39
39
|
}
|
|
40
40
|
if (opts.baseline) {
|
|
41
|
-
const { runBaseline } = await import("./baseline-
|
|
41
|
+
const { runBaseline } = await import("./baseline-45AWVXG4.js");
|
|
42
42
|
await runBaseline(rootDir);
|
|
43
43
|
}
|
|
44
44
|
console.log("");
|
package/dist/index.d.ts
CHANGED
|
@@ -43,6 +43,8 @@ interface DriftScore {
|
|
|
43
43
|
dependencyScore: number;
|
|
44
44
|
eolScore: number;
|
|
45
45
|
};
|
|
46
|
+
/** Which components had sufficient data to score. Missing = no data available. */
|
|
47
|
+
measured?: ('runtime' | 'framework' | 'dependency' | 'eol')[];
|
|
46
48
|
}
|
|
47
49
|
interface Finding {
|
|
48
50
|
ruleId: string;
|
|
@@ -130,12 +132,18 @@ interface DuplicatedPackage {
|
|
|
130
132
|
versions: string[];
|
|
131
133
|
consumers: number;
|
|
132
134
|
}
|
|
135
|
+
interface PhantomDependency {
|
|
136
|
+
package: string;
|
|
137
|
+
spec: string;
|
|
138
|
+
sourcePath: string;
|
|
139
|
+
}
|
|
133
140
|
interface DependencyGraphResult {
|
|
134
141
|
lockfileType: string | null;
|
|
135
142
|
totalUnique: number;
|
|
136
143
|
totalInstalled: number;
|
|
137
144
|
duplicatedPackages: DuplicatedPackage[];
|
|
138
145
|
phantomDependencies: string[];
|
|
146
|
+
phantomDependencyDetails?: PhantomDependency[];
|
|
139
147
|
}
|
|
140
148
|
interface InventoryItem {
|
|
141
149
|
name: string;
|
package/dist/index.js
CHANGED