@safetnsr/vet 1.22.2 → 1.23.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/dist/cli.js +59 -2
- package/dist/utils-bad.d.ts +1 -0
- package/dist/utils-bad.js +6 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { readFileSync } from 'node:fs';
|
|
4
|
-
import { isGitRepo, readFile, c } from './util.js';
|
|
4
|
+
import { isGitRepo, readFile, c, gitExec } from './util.js';
|
|
5
5
|
import { checkReady } from './checks/ready.js';
|
|
6
6
|
import { checkDiff } from './checks/diff.js';
|
|
7
7
|
import { checkModels } from './checks/models.js';
|
|
@@ -35,6 +35,7 @@ import { checkContext, runContextCommand } from './checks/context.js';
|
|
|
35
35
|
import { checkSplit, runSplitCommand } from './checks/split.js';
|
|
36
36
|
import { checkCompleteness } from './checks/completeness.js';
|
|
37
37
|
import { score } from './scorer.js';
|
|
38
|
+
import { toGrade } from './categories.js';
|
|
38
39
|
import { reportPretty, reportJSON, reportBadge } from './reporter.js';
|
|
39
40
|
import { clearCache } from './file-cache.js';
|
|
40
41
|
const args = process.argv.slice(2);
|
|
@@ -105,6 +106,7 @@ if (flags.has('--help') || flags.has('-h')) {
|
|
|
105
106
|
--hook pre-commit hook mode (exit 1 if below grade C)
|
|
106
107
|
--badge print markdown badge string and exit
|
|
107
108
|
--fix auto-fix configs, models
|
|
109
|
+
--diff-only only score files changed in current branch (great for CI)
|
|
108
110
|
--since REF diff against specific commit/range
|
|
109
111
|
--watch re-run on file changes
|
|
110
112
|
--json JSON output
|
|
@@ -133,6 +135,7 @@ const isHook = flags.has('--hook');
|
|
|
133
135
|
const isFix = flags.has('--fix');
|
|
134
136
|
const isWatch = flags.has('--watch');
|
|
135
137
|
const isBadge = flags.has('--badge');
|
|
138
|
+
const isDiffOnly = flags.has('--diff-only');
|
|
136
139
|
const isJSON = flags.has('--json') || (!process.stdout.isTTY && !flags.has('--pretty') && !isBadge);
|
|
137
140
|
const since = flagMap.get('since');
|
|
138
141
|
const maxFiles = flagMap.has('max-files') ? (parseInt(flagMap.get('max-files'), 10) || 0) : 0;
|
|
@@ -339,6 +342,56 @@ async function withTimeout(name, fn, timeoutMs = 30_000) {
|
|
|
339
342
|
Promise.resolve(fn()).then((r) => { clearTimeout(timer); res(r); }).catch(() => { clearTimeout(timer); res({ name, score: 100, maxScore: 100, issues: [], summary: 'check failed' }); });
|
|
340
343
|
});
|
|
341
344
|
}
|
|
345
|
+
/** Get files changed vs main/master branch or --since ref */
|
|
346
|
+
function getChangedFiles(cwd, sinceRef) {
|
|
347
|
+
const base = sinceRef || (() => {
|
|
348
|
+
const main = gitExec(['merge-base', 'HEAD', 'origin/main'], cwd);
|
|
349
|
+
if (main)
|
|
350
|
+
return main;
|
|
351
|
+
const master = gitExec(['merge-base', 'HEAD', 'origin/master'], cwd);
|
|
352
|
+
if (master)
|
|
353
|
+
return master;
|
|
354
|
+
return 'HEAD~1';
|
|
355
|
+
})();
|
|
356
|
+
const output = gitExec(['diff', '--name-only', base, 'HEAD'], cwd);
|
|
357
|
+
if (!output)
|
|
358
|
+
return new Set();
|
|
359
|
+
return new Set(output.split('\n').filter(Boolean));
|
|
360
|
+
}
|
|
361
|
+
/** Filter VetResult to only include issues from changed files, then re-score */
|
|
362
|
+
function filterDiffOnly(result, changedFiles) {
|
|
363
|
+
if (changedFiles.size === 0)
|
|
364
|
+
return result;
|
|
365
|
+
const filtered = {
|
|
366
|
+
...result,
|
|
367
|
+
categories: result.categories.map(cat => {
|
|
368
|
+
const filteredChecks = cat.checks.map(check => {
|
|
369
|
+
const filteredIssues = check.issues.filter(issue => !issue.file || changedFiles.has(issue.file));
|
|
370
|
+
const penalty = filteredIssues.reduce((sum, i) => {
|
|
371
|
+
if (i.severity === 'error')
|
|
372
|
+
return sum + 25;
|
|
373
|
+
if (i.severity === 'warning')
|
|
374
|
+
return sum + 10;
|
|
375
|
+
return sum + 2;
|
|
376
|
+
}, 0);
|
|
377
|
+
const newScore = Math.max(0, 100 - penalty);
|
|
378
|
+
return { ...check, score: newScore, issues: filteredIssues };
|
|
379
|
+
});
|
|
380
|
+
const allIssues = filteredChecks.flatMap(c => c.issues);
|
|
381
|
+
const checksWithIssues = filteredChecks.filter(c => c.issues.length > 0);
|
|
382
|
+
const avgScore = checksWithIssues.length > 0
|
|
383
|
+
? Math.round(checksWithIssues.reduce((sum, c) => sum + c.score, 0) / checksWithIssues.length)
|
|
384
|
+
: 100;
|
|
385
|
+
return { ...cat, checks: filteredChecks, issues: allIssues, score: avgScore };
|
|
386
|
+
}),
|
|
387
|
+
};
|
|
388
|
+
const totalWeight = filtered.categories.reduce((sum, c) => sum + c.weight, 0);
|
|
389
|
+
filtered.score = Math.round(filtered.categories.reduce((sum, c) => sum + c.score * c.weight, 0) / totalWeight);
|
|
390
|
+
filtered.grade = toGrade(filtered.score);
|
|
391
|
+
filtered.totalIssues = filtered.categories.reduce((sum, c) => c.issues.length + sum, 0);
|
|
392
|
+
filtered.fixableIssues = filtered.categories.reduce((sum, c) => c.issues.filter(i => i.fixable).length + sum, 0);
|
|
393
|
+
return filtered;
|
|
394
|
+
}
|
|
342
395
|
async function runChecks() {
|
|
343
396
|
const globalStart = Date.now();
|
|
344
397
|
const GLOBAL_TIMEOUT = 120_000;
|
|
@@ -454,7 +507,11 @@ if (isWatch) {
|
|
|
454
507
|
else {
|
|
455
508
|
// Normal run
|
|
456
509
|
try {
|
|
457
|
-
|
|
510
|
+
let result = await runChecks();
|
|
511
|
+
if (isDiffOnly) {
|
|
512
|
+
const changedFiles = getChangedFiles(cwd, since);
|
|
513
|
+
result = filterDiffOnly(result, changedFiles);
|
|
514
|
+
}
|
|
458
515
|
if (isJSON) {
|
|
459
516
|
console.log(reportJSON(result));
|
|
460
517
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function bad(): void;
|