depstein 0.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 +438 -0
- package/dist/core/cache.d.ts +15 -0
- package/dist/core/cache.js +75 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/fetcher.d.ts +7 -0
- package/dist/core/fetcher.js +59 -0
- package/dist/core/fetcher.js.map +1 -0
- package/dist/core/replacements.d.ts +32 -0
- package/dist/core/replacements.js +419 -0
- package/dist/core/replacements.js.map +1 -0
- package/dist/core/scanner.d.ts +7 -0
- package/dist/core/scanner.js +298 -0
- package/dist/core/scanner.js.map +1 -0
- package/dist/core/scorer.d.ts +5 -0
- package/dist/core/scorer.js +289 -0
- package/dist/core/scorer.js.map +1 -0
- package/dist/core/types.d.ts +99 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/vulnerabilities.d.ts +5 -0
- package/dist/core/vulnerabilities.js +93 -0
- package/dist/core/vulnerabilities.js.map +1 -0
- package/dist/ecosystems/cargo.d.ts +2 -0
- package/dist/ecosystems/cargo.js +74 -0
- package/dist/ecosystems/cargo.js.map +1 -0
- package/dist/ecosystems/golang.d.ts +2 -0
- package/dist/ecosystems/golang.js +90 -0
- package/dist/ecosystems/golang.js.map +1 -0
- package/dist/ecosystems/npm.d.ts +2 -0
- package/dist/ecosystems/npm.js +92 -0
- package/dist/ecosystems/npm.js.map +1 -0
- package/dist/ecosystems/pypi.d.ts +2 -0
- package/dist/ecosystems/pypi.js +80 -0
- package/dist/ecosystems/pypi.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +303 -0
- package/dist/index.js.map +1 -0
- package/dist/tui/colors.d.ts +17 -0
- package/dist/tui/colors.js +86 -0
- package/dist/tui/colors.js.map +1 -0
- package/dist/tui/dashboard.d.ts +7 -0
- package/dist/tui/dashboard.js +236 -0
- package/dist/tui/dashboard.js.map +1 -0
- package/dist/tui/detail.d.ts +6 -0
- package/dist/tui/detail.js +68 -0
- package/dist/tui/detail.js.map +1 -0
- package/dist/tui/picker.d.ts +7 -0
- package/dist/tui/picker.js +62 -0
- package/dist/tui/picker.js.map +1 -0
- package/dist/tui/summary.d.ts +6 -0
- package/dist/tui/summary.js +13 -0
- package/dist/tui/summary.js.map +1 -0
- package/dist/tui/table.d.ts +9 -0
- package/dist/tui/table.js +50 -0
- package/dist/tui/table.js.map +1 -0
- package/dist/utils/format.d.ts +9 -0
- package/dist/utils/format.js +72 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/http.d.ts +2 -0
- package/dist/utils/http.js +53 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/spinner.d.ts +11 -0
- package/dist/utils/spinner.js +40 -0
- package/dist/utils/spinner.js.map +1 -0
- package/package.json +50 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { render } from 'ink';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { dirname, join, resolve } from 'path';
|
|
8
|
+
import { scan, findWorkspaceRoots } from './core/scanner.js';
|
|
9
|
+
import { fetchAll } from './core/fetcher.js';
|
|
10
|
+
import { score as scoreOne, getGrade, getReplacementPackage } from './core/scorer.js';
|
|
11
|
+
import { Dashboard } from './tui/dashboard.js';
|
|
12
|
+
import { PickerApp } from './tui/picker.js';
|
|
13
|
+
import { Spinner } from './utils/spinner.js';
|
|
14
|
+
// ── Version ────────────────────────────────────────────────────────────────────
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
function readVersion() {
|
|
17
|
+
try {
|
|
18
|
+
const pkgPath = join(__dirname, '..', 'package.json');
|
|
19
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
20
|
+
return pkg.version;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return '0.1.0';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// ── Build AuditResult ──────────────────────────────────────────────────────────
|
|
27
|
+
function buildResult(projectPath, ecosystem, scored) {
|
|
28
|
+
const avg = scored.length > 0
|
|
29
|
+
? scored.reduce((s, d) => s + d.totalScore, 0) / scored.length
|
|
30
|
+
: 0;
|
|
31
|
+
return {
|
|
32
|
+
projectPath,
|
|
33
|
+
ecosystem,
|
|
34
|
+
scoredDependencies: scored,
|
|
35
|
+
averageScore: avg,
|
|
36
|
+
grade: getGrade(Math.round(avg)),
|
|
37
|
+
totalCount: scored.length,
|
|
38
|
+
criticalCount: scored.filter(d => d.grade === 'F').length,
|
|
39
|
+
poorCount: scored.filter(d => d.grade === 'D').length,
|
|
40
|
+
fairCount: scored.filter(d => d.grade === 'C').length,
|
|
41
|
+
goodCount: scored.filter(d => d.grade === 'B').length,
|
|
42
|
+
excellentCount: scored.filter(d => d.grade === 'A').length,
|
|
43
|
+
timestamp: new Date().toISOString(),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// ── JSON mode ─────────────────────────────────────────────────────────────────
|
|
47
|
+
async function runJsonMode(scanResult, options) {
|
|
48
|
+
const spinner = new Spinner();
|
|
49
|
+
const { dependencies } = scanResult;
|
|
50
|
+
spinner.start(`Fetching metadata for ${dependencies.length} packages…`);
|
|
51
|
+
let lastDone = 0;
|
|
52
|
+
const metadata = await fetchAll(dependencies, options.noCache, (done, total, current) => {
|
|
53
|
+
if (done !== lastDone) {
|
|
54
|
+
spinner.update(`[${done}/${total}] ${current}`);
|
|
55
|
+
lastDone = done;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
spinner.succeed(`Fetched ${metadata.length} packages`);
|
|
59
|
+
const scored = metadata.map((meta, i) => scoreOne(dependencies[i], meta));
|
|
60
|
+
const result = buildResult(scanResult.projectPath, scanResult.ecosystem, scored);
|
|
61
|
+
process.stdout.write(JSON.stringify(result, null, 2) + '\n');
|
|
62
|
+
// CI threshold check
|
|
63
|
+
if (options.minScore != null && result.averageScore < options.minScore) {
|
|
64
|
+
process.stderr.write(`\n✗ Average score ${Math.round(result.averageScore)}/100 is below ` +
|
|
65
|
+
`the required threshold of ${options.minScore}/100\n`);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ── CI mode ─────────────────────────────────────────────────────────────────
|
|
70
|
+
//
|
|
71
|
+
// Plain-text output + GitHub Actions ::error:: annotations for poor packages.
|
|
72
|
+
// Exits with code 1 if average score is below the threshold (default 70).
|
|
73
|
+
async function runCiMode(scanResult, options) {
|
|
74
|
+
const spinner = new Spinner();
|
|
75
|
+
const { dependencies } = scanResult;
|
|
76
|
+
spinner.start(`Fetching metadata for ${dependencies.length} packages…`);
|
|
77
|
+
let lastDone = 0;
|
|
78
|
+
const metadata = await fetchAll(dependencies, options.noCache, (done, total, current) => {
|
|
79
|
+
if (done !== lastDone) {
|
|
80
|
+
spinner.update(`[${done}/${total}] ${current}`);
|
|
81
|
+
lastDone = done;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
spinner.succeed(`Fetched ${metadata.length} packages`);
|
|
85
|
+
const scored = metadata.map((meta, i) => scoreOne(dependencies[i], meta));
|
|
86
|
+
const result = buildResult(scanResult.projectPath, scanResult.ecosystem, scored);
|
|
87
|
+
const threshold = options.minScore ?? 70;
|
|
88
|
+
const isGHA = process.env['GITHUB_ACTIONS'] === 'true';
|
|
89
|
+
// Table header
|
|
90
|
+
process.stdout.write(`\ndepstein CI — ${result.totalCount} packages, avg ${Math.round(result.averageScore)}/100 (${result.grade})\n`);
|
|
91
|
+
process.stdout.write(`threshold: ${threshold}/100\n\n`);
|
|
92
|
+
// Per-package lines
|
|
93
|
+
const sorted = [...scored].sort((a, b) => a.totalScore - b.totalScore);
|
|
94
|
+
for (const dep of sorted) {
|
|
95
|
+
const icon = dep.grade === 'F' ? '✗' : dep.grade === 'D' ? '!' : dep.grade === 'C' ? '~' : '✓';
|
|
96
|
+
const issueStr = dep.issues.length > 0 ? dep.issues.join(', ') : 'ok';
|
|
97
|
+
process.stdout.write(` ${icon} ${dep.raw.name.padEnd(30)} ${String(dep.totalScore).padStart(3)}/100 ${dep.grade} ${issueStr}\n`);
|
|
98
|
+
if (dep.suggestion) {
|
|
99
|
+
process.stdout.write(` → ${dep.suggestion}\n`);
|
|
100
|
+
}
|
|
101
|
+
// GitHub Actions annotation for F/D packages
|
|
102
|
+
if (isGHA && (dep.grade === 'F' || dep.grade === 'D')) {
|
|
103
|
+
const msg = `${dep.raw.name} scored ${dep.totalScore}/100 (${dep.grade}) — ${issueStr}`;
|
|
104
|
+
process.stdout.write(`::error title=${dep.raw.name}::${msg}\n`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
process.stdout.write('\n');
|
|
108
|
+
const failed = result.averageScore < threshold;
|
|
109
|
+
if (failed) {
|
|
110
|
+
const msg = `Average score ${Math.round(result.averageScore)}/100 is below threshold ${threshold}/100`;
|
|
111
|
+
process.stderr.write(`✗ ${msg}\n`);
|
|
112
|
+
if (isGHA) {
|
|
113
|
+
process.stdout.write(`::error title=depstein::${msg}\n`);
|
|
114
|
+
}
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
process.stdout.write(`✓ Average score ${Math.round(result.averageScore)}/100 meets threshold ${threshold}/100\n`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// ── --fix mode ────────────────────────────────────────────────────────────────
|
|
122
|
+
//
|
|
123
|
+
// Reads package.json, replaces known deprecated packages with their recommended
|
|
124
|
+
// alternatives, writes the modified file, and prints what changed.
|
|
125
|
+
// The user must run `npm install` afterward to apply the changes.
|
|
126
|
+
async function runFixMode(scanResult, options) {
|
|
127
|
+
const spinner = new Spinner();
|
|
128
|
+
const { dependencies } = scanResult;
|
|
129
|
+
if (scanResult.ecosystem !== 'npm') {
|
|
130
|
+
process.stderr.write('--fix currently only supports npm projects (package.json)\n');
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
const pkgJsonPath = join(scanResult.projectPath, 'package.json');
|
|
134
|
+
let pkgJson;
|
|
135
|
+
try {
|
|
136
|
+
pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
process.stderr.write(`Cannot read ${pkgJsonPath}\n`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
spinner.start(`Fetching metadata for ${dependencies.length} packages…`);
|
|
143
|
+
let lastDone = 0;
|
|
144
|
+
const metadata = await fetchAll(dependencies, options.noCache, (done, total, current) => {
|
|
145
|
+
if (done !== lastDone) {
|
|
146
|
+
spinner.update(`[${done}/${total}] ${current}`);
|
|
147
|
+
lastDone = done;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
spinner.succeed(`Fetched ${metadata.length} packages`);
|
|
151
|
+
const scored = metadata.map((meta, i) => scoreOne(dependencies[i], meta));
|
|
152
|
+
// Collect packages with a real npm package replacement
|
|
153
|
+
const replacements = [];
|
|
154
|
+
for (const dep of scored) {
|
|
155
|
+
const replacement = getReplacementPackage(dep.raw.name);
|
|
156
|
+
if (replacement) {
|
|
157
|
+
replacements.push({ from: dep.raw.name, to: replacement, reason: dep.suggestion ?? '' });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (replacements.length === 0) {
|
|
161
|
+
process.stdout.write('✓ No replacements found — all packages look fine!\n');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const deps = (pkgJson.dependencies ?? {});
|
|
165
|
+
const devDeps = (pkgJson.devDependencies ?? {});
|
|
166
|
+
const applied = [];
|
|
167
|
+
for (const { from, to, reason } of replacements) {
|
|
168
|
+
if (from in deps) {
|
|
169
|
+
delete deps[from];
|
|
170
|
+
deps[to] = '*';
|
|
171
|
+
applied.push({ from, to, reason });
|
|
172
|
+
}
|
|
173
|
+
else if (from in devDeps) {
|
|
174
|
+
delete devDeps[from];
|
|
175
|
+
devDeps[to] = '*';
|
|
176
|
+
applied.push({ from, to, reason });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (applied.length === 0) {
|
|
180
|
+
process.stdout.write('✓ No matching packages found in package.json to replace.\n');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (Object.keys(deps).length > 0)
|
|
184
|
+
pkgJson.dependencies = deps;
|
|
185
|
+
if (Object.keys(devDeps).length > 0)
|
|
186
|
+
pkgJson.devDependencies = devDeps;
|
|
187
|
+
writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + '\n', 'utf-8');
|
|
188
|
+
process.stdout.write('\n✓ package.json updated:\n\n');
|
|
189
|
+
for (const { from, to, reason } of applied) {
|
|
190
|
+
process.stdout.write(` ${from} → ${to}\n`);
|
|
191
|
+
if (reason)
|
|
192
|
+
process.stdout.write(` ${reason}\n`);
|
|
193
|
+
}
|
|
194
|
+
process.stdout.write('\nRun npm install to apply changes.\n\n');
|
|
195
|
+
}
|
|
196
|
+
// ── Main ───────────────────────────────────────────────────────────────────────
|
|
197
|
+
async function main() {
|
|
198
|
+
const program = new Command();
|
|
199
|
+
program
|
|
200
|
+
.name('depstein')
|
|
201
|
+
.description('Dependency health scorer for npm, PyPI, Cargo, and Go projects')
|
|
202
|
+
.version(readVersion(), '-v, --version')
|
|
203
|
+
.argument('[path]', 'Path to project directory', '.')
|
|
204
|
+
.option('--ecosystem <type>', 'Force ecosystem: npm | pypi | cargo | golang')
|
|
205
|
+
.option('--filter <mode>', 'Filter: all | critical | poor | dev | prod', 'all')
|
|
206
|
+
.option('--sort <by>', 'Sort by: score | name | size | updated', 'score')
|
|
207
|
+
.option('--no-cache', 'Bypass disk cache')
|
|
208
|
+
.option('--json', 'Output raw JSON instead of TUI')
|
|
209
|
+
.option('--top <n>', 'Show only the N worst packages')
|
|
210
|
+
.option('--fix', 'Replace deprecated packages in package.json with better alternatives')
|
|
211
|
+
.option('--min-score <n>', 'Exit with code 1 if average score drops below N (CI mode)')
|
|
212
|
+
.option('--ci', 'CI mode: plain text + GitHub Actions ::error:: annotations (default threshold 70)')
|
|
213
|
+
.addHelpText('after', `
|
|
214
|
+
Examples:
|
|
215
|
+
$ depstein Analyze current directory
|
|
216
|
+
$ depstein ~/my-project Analyze specific project
|
|
217
|
+
$ depstein --filter critical Show only failing deps
|
|
218
|
+
$ depstein --json > report.json Export full report
|
|
219
|
+
$ depstein --top 10 Show 10 worst packages
|
|
220
|
+
$ depstein --no-cache Bypass cache for fresh data
|
|
221
|
+
$ depstein --fix Replace deprecated packages in package.json
|
|
222
|
+
$ depstein --min-score 75 Fail CI if avg score < 75
|
|
223
|
+
$ depstein --json --min-score 75 Combined: JSON output + CI threshold
|
|
224
|
+
$ depstein --ci CI mode with GitHub Actions annotations
|
|
225
|
+
$ depstein --ci --min-score 80 CI mode with custom threshold
|
|
226
|
+
`);
|
|
227
|
+
program.parse(process.argv);
|
|
228
|
+
const projectArg = program.args[0] ?? '.';
|
|
229
|
+
const opts = program.opts();
|
|
230
|
+
// commander uses --no-cache → opts.cache = false
|
|
231
|
+
const noCache = opts.cache === false || opts.noCache === true;
|
|
232
|
+
const options = {
|
|
233
|
+
path: resolve(projectArg),
|
|
234
|
+
ecosystem: opts.ecosystem,
|
|
235
|
+
filter: opts.filter ?? 'all',
|
|
236
|
+
sort: opts.sort ?? 'score',
|
|
237
|
+
noCache,
|
|
238
|
+
json: opts.json ?? false,
|
|
239
|
+
top: opts.top ? parseInt(opts.top, 10) : undefined,
|
|
240
|
+
fix: opts.fix ?? false,
|
|
241
|
+
minScore: opts.minScore ? parseInt(opts.minScore, 10) : undefined,
|
|
242
|
+
ci: opts.ci ?? false,
|
|
243
|
+
};
|
|
244
|
+
// Validate flags
|
|
245
|
+
const validFilters = ['all', 'critical', 'poor', 'dev', 'prod'];
|
|
246
|
+
if (!validFilters.includes(options.filter)) {
|
|
247
|
+
process.stderr.write(`Invalid --filter value "${options.filter}". Use: ${validFilters.join(' | ')}\n`);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
const validSorts = ['score', 'name', 'size', 'updated'];
|
|
251
|
+
if (!validSorts.includes(options.sort)) {
|
|
252
|
+
process.stderr.write(`Invalid --sort value "${options.sort}". Use: ${validSorts.join(' | ')}\n`);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
// Scan project
|
|
256
|
+
const scanResult = scan(options.path, options.ecosystem);
|
|
257
|
+
if (!scanResult) {
|
|
258
|
+
// No project at the given path — open the interactive path-picker TUI
|
|
259
|
+
// instead of dumping a plain-text error. --json / --ci / --fix still
|
|
260
|
+
// need a real project, so keep the error path for those modes.
|
|
261
|
+
if (options.json || options.ci || options.fix) {
|
|
262
|
+
const workspaceRoots = findWorkspaceRoots(options.path);
|
|
263
|
+
if (workspaceRoots.length > 0) {
|
|
264
|
+
process.stderr.write(`Monorepo detected with ${workspaceRoots.length} workspace packages.\n` +
|
|
265
|
+
`Run depstein with a specific workspace path:\n` +
|
|
266
|
+
workspaceRoots.slice(0, 5).map(r => ` depstein ${r}`).join('\n') + '\n');
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
process.stderr.write(`No recognized project found in: ${options.path}\n` +
|
|
270
|
+
`Expected: package.json, requirements.txt, pyproject.toml, go.mod, or Cargo.toml\n`);
|
|
271
|
+
}
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
// Interactive TUI picker
|
|
275
|
+
const { waitUntilExit } = render(React.createElement(PickerApp, { initialPath: options.path, options }), { exitOnCtrlC: true });
|
|
276
|
+
await waitUntilExit();
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (scanResult.dependencies.length === 0) {
|
|
280
|
+
process.stderr.write(`No dependencies found in ${options.path}\n`);
|
|
281
|
+
process.exit(0);
|
|
282
|
+
}
|
|
283
|
+
if (options.ci) {
|
|
284
|
+
await runCiMode(scanResult, options);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (options.fix) {
|
|
288
|
+
await runFixMode(scanResult, options);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (options.json) {
|
|
292
|
+
await runJsonMode(scanResult, options);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
// TUI mode
|
|
296
|
+
const { waitUntilExit } = render(React.createElement(Dashboard, { scanResult, options }), { exitOnCtrlC: true });
|
|
297
|
+
await waitUntilExit();
|
|
298
|
+
}
|
|
299
|
+
main().catch(err => {
|
|
300
|
+
process.stderr.write(`\nFatal error: ${err.message}\n`);
|
|
301
|
+
process.exit(1);
|
|
302
|
+
});
|
|
303
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Grade } from '../core/types.js';
|
|
2
|
+
export declare const ACCENT = "#e04a1a";
|
|
3
|
+
export declare function gradeColor(grade: Grade): string;
|
|
4
|
+
export declare function scoreColor(score: number, text?: string | number): string;
|
|
5
|
+
/**
|
|
6
|
+
* Color an issue label with an icon prefix.
|
|
7
|
+
* vulnerable / abandoned → red ⚠
|
|
8
|
+
* no types / huge size → yellow ◆
|
|
9
|
+
* outdated / license → orange ◆
|
|
10
|
+
*/
|
|
11
|
+
export declare function issueColor(issue: string): string;
|
|
12
|
+
export declare function severityColor(severity: string): string;
|
|
13
|
+
export declare function barColor(score: number, bar: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Grade-distribution bar — each segment colored by its grade bucket.
|
|
16
|
+
*/
|
|
17
|
+
export declare function gradeDistBar(excellent: number, good: number, fair: number, poor: number, critical: number, width?: number): string;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
export const ACCENT = '#e04a1a';
|
|
3
|
+
export function gradeColor(grade) {
|
|
4
|
+
switch (grade) {
|
|
5
|
+
case 'A': return chalk.greenBright(grade);
|
|
6
|
+
case 'B': return chalk.hex('#9ACD32')(grade); // yellow-green
|
|
7
|
+
case 'C': return chalk.yellow(grade);
|
|
8
|
+
case 'D': return chalk.hex('#FF8C00')(grade); // orange
|
|
9
|
+
case 'F': return chalk.redBright(grade);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function scoreColor(score, text) {
|
|
13
|
+
const t = String(text ?? score);
|
|
14
|
+
if (score >= 90)
|
|
15
|
+
return chalk.greenBright(t);
|
|
16
|
+
if (score >= 75)
|
|
17
|
+
return chalk.green(t);
|
|
18
|
+
if (score >= 60)
|
|
19
|
+
return chalk.yellow(t);
|
|
20
|
+
return chalk.red(t);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Color an issue label with an icon prefix.
|
|
24
|
+
* vulnerable / abandoned → red ⚠
|
|
25
|
+
* no types / huge size → yellow ◆
|
|
26
|
+
* outdated / license → orange ◆
|
|
27
|
+
*/
|
|
28
|
+
export function issueColor(issue) {
|
|
29
|
+
const lower = issue.toLowerCase();
|
|
30
|
+
if (lower.includes('vuln') || lower.includes('critical'))
|
|
31
|
+
return chalk.redBright(`⚠ ${issue}`);
|
|
32
|
+
if (lower.includes('abandoned'))
|
|
33
|
+
return chalk.redBright(`⚠ ${issue}`);
|
|
34
|
+
if (lower.includes('no types'))
|
|
35
|
+
return chalk.yellow(`◆ ${issue}`);
|
|
36
|
+
if (lower.includes('huge size'))
|
|
37
|
+
return chalk.yellow(`◆ ${issue}`);
|
|
38
|
+
if (lower.includes('outdated'))
|
|
39
|
+
return chalk.hex('#FF8C00')(`◆ ${issue}`);
|
|
40
|
+
if (lower.includes('license'))
|
|
41
|
+
return chalk.hex('#FF8C00')(`◆ ${issue}`);
|
|
42
|
+
return chalk.dim(issue);
|
|
43
|
+
}
|
|
44
|
+
export function severityColor(severity) {
|
|
45
|
+
switch (severity.toUpperCase()) {
|
|
46
|
+
case 'CRITICAL': return chalk.bgRed.white(' CRITICAL ');
|
|
47
|
+
case 'HIGH': return chalk.redBright('HIGH');
|
|
48
|
+
case 'MEDIUM': return chalk.yellow('MEDIUM');
|
|
49
|
+
default: return chalk.dim('LOW');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function barColor(score, bar) {
|
|
53
|
+
if (score >= 90)
|
|
54
|
+
return chalk.greenBright(bar);
|
|
55
|
+
if (score >= 75)
|
|
56
|
+
return chalk.green(bar);
|
|
57
|
+
if (score >= 60)
|
|
58
|
+
return chalk.yellow(bar);
|
|
59
|
+
if (score >= 30)
|
|
60
|
+
return chalk.hex('#FF8C00')(bar);
|
|
61
|
+
return chalk.red(bar);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Grade-distribution bar — each segment colored by its grade bucket.
|
|
65
|
+
*/
|
|
66
|
+
export function gradeDistBar(excellent, good, fair, poor, critical, width = 30) {
|
|
67
|
+
const total = excellent + good + fair + poor + critical;
|
|
68
|
+
if (total === 0)
|
|
69
|
+
return chalk.dim('░'.repeat(width));
|
|
70
|
+
const seg = (count, colorFn) => {
|
|
71
|
+
const len = Math.max(0, Math.round((count / total) * width));
|
|
72
|
+
return colorFn('█'.repeat(len));
|
|
73
|
+
};
|
|
74
|
+
const raw = seg(excellent, chalk.greenBright) +
|
|
75
|
+
seg(good, chalk.hex('#9ACD32')) +
|
|
76
|
+
seg(fair, chalk.yellow) +
|
|
77
|
+
seg(poor, chalk.hex('#FF8C00')) +
|
|
78
|
+
seg(critical, chalk.redBright);
|
|
79
|
+
// Pad to exactly `width` visible cells if segments don't fill due to rounding
|
|
80
|
+
const bare = raw.replace(/\x1B\[[0-9;]*m/g, '');
|
|
81
|
+
const diff = width - bare.length;
|
|
82
|
+
if (diff > 0)
|
|
83
|
+
return raw + chalk.dim('░'.repeat(diff));
|
|
84
|
+
return raw;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=colors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colors.js","sourceRoot":"","sources":["../../src/tui/colors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ScanResult, CLIOptions } from '../core/types.js';
|
|
2
|
+
interface DashboardProps {
|
|
3
|
+
scanResult: ScanResult;
|
|
4
|
+
options: CLIOptions;
|
|
5
|
+
}
|
|
6
|
+
export declare function Dashboard({ scanResult, options }: DashboardProps): import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
export {};
|