@rainy-updates/cli 0.5.2-rc.1 → 0.5.2
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/CHANGELOG.md +77 -0
- package/README.md +34 -1
- package/dist/bin/cli.js +128 -3
- package/dist/cache/cache.d.ts +1 -0
- package/dist/cache/cache.js +9 -2
- package/dist/commands/audit/fetcher.d.ts +2 -6
- package/dist/commands/audit/fetcher.js +2 -79
- package/dist/commands/audit/mapper.d.ts +8 -1
- package/dist/commands/audit/mapper.js +105 -9
- package/dist/commands/audit/parser.js +36 -2
- package/dist/commands/audit/runner.js +186 -15
- package/dist/commands/audit/sources/github.d.ts +2 -0
- package/dist/commands/audit/sources/github.js +125 -0
- package/dist/commands/audit/sources/index.d.ts +6 -0
- package/dist/commands/audit/sources/index.js +99 -0
- package/dist/commands/audit/sources/osv.d.ts +2 -0
- package/dist/commands/audit/sources/osv.js +131 -0
- package/dist/commands/audit/sources/types.d.ts +21 -0
- package/dist/commands/audit/sources/types.js +1 -0
- package/dist/commands/audit/targets.d.ts +20 -0
- package/dist/commands/audit/targets.js +314 -0
- package/dist/commands/changelog/fetcher.d.ts +9 -0
- package/dist/commands/changelog/fetcher.js +130 -0
- package/dist/commands/doctor/parser.d.ts +2 -0
- package/dist/commands/doctor/parser.js +92 -0
- package/dist/commands/doctor/runner.d.ts +2 -0
- package/dist/commands/doctor/runner.js +13 -0
- package/dist/commands/resolve/runner.js +3 -0
- package/dist/commands/review/parser.d.ts +2 -0
- package/dist/commands/review/parser.js +174 -0
- package/dist/commands/review/runner.d.ts +2 -0
- package/dist/commands/review/runner.js +30 -0
- package/dist/config/loader.d.ts +3 -0
- package/dist/core/check.js +39 -5
- package/dist/core/errors.d.ts +11 -0
- package/dist/core/errors.js +6 -0
- package/dist/core/options.d.ts +8 -1
- package/dist/core/options.js +43 -0
- package/dist/core/review-model.d.ts +5 -0
- package/dist/core/review-model.js +382 -0
- package/dist/core/summary.js +11 -2
- package/dist/core/upgrade.d.ts +1 -0
- package/dist/core/upgrade.js +27 -21
- package/dist/core/warm-cache.js +28 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/output/format.d.ts +4 -1
- package/dist/output/format.js +29 -3
- package/dist/output/github.js +5 -0
- package/dist/output/sarif.js +11 -0
- package/dist/registry/npm.d.ts +20 -0
- package/dist/registry/npm.js +27 -4
- package/dist/types/index.d.ts +91 -1
- package/dist/ui/tui.d.ts +2 -0
- package/dist/ui/tui.js +107 -0
- package/package.json +12 -2
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { ensureRiskLevel } from "../../core/options.js";
|
|
4
|
+
export function parseReviewArgs(args) {
|
|
5
|
+
const options = {
|
|
6
|
+
cwd: process.cwd(),
|
|
7
|
+
target: "latest",
|
|
8
|
+
filter: undefined,
|
|
9
|
+
reject: undefined,
|
|
10
|
+
cacheTtlSeconds: 3600,
|
|
11
|
+
includeKinds: ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"],
|
|
12
|
+
ci: false,
|
|
13
|
+
format: "table",
|
|
14
|
+
workspace: false,
|
|
15
|
+
jsonFile: undefined,
|
|
16
|
+
githubOutputFile: undefined,
|
|
17
|
+
sarifFile: undefined,
|
|
18
|
+
concurrency: 16,
|
|
19
|
+
registryTimeoutMs: 8000,
|
|
20
|
+
registryRetries: 3,
|
|
21
|
+
offline: false,
|
|
22
|
+
stream: false,
|
|
23
|
+
policyFile: undefined,
|
|
24
|
+
prReportFile: undefined,
|
|
25
|
+
failOn: "none",
|
|
26
|
+
maxUpdates: undefined,
|
|
27
|
+
fixPr: false,
|
|
28
|
+
fixBranch: "chore/rainy-updates",
|
|
29
|
+
fixCommitMessage: undefined,
|
|
30
|
+
fixDryRun: false,
|
|
31
|
+
fixPrNoCheckout: false,
|
|
32
|
+
fixPrBatchSize: undefined,
|
|
33
|
+
noPrReport: false,
|
|
34
|
+
logLevel: "info",
|
|
35
|
+
groupBy: "risk",
|
|
36
|
+
groupMax: undefined,
|
|
37
|
+
cooldownDays: undefined,
|
|
38
|
+
prLimit: undefined,
|
|
39
|
+
onlyChanged: false,
|
|
40
|
+
ciProfile: "minimal",
|
|
41
|
+
lockfileMode: "preserve",
|
|
42
|
+
interactive: false,
|
|
43
|
+
showImpact: true,
|
|
44
|
+
showHomepage: true,
|
|
45
|
+
securityOnly: false,
|
|
46
|
+
risk: undefined,
|
|
47
|
+
diff: undefined,
|
|
48
|
+
applySelected: false,
|
|
49
|
+
};
|
|
50
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
51
|
+
const current = args[i];
|
|
52
|
+
const next = args[i + 1];
|
|
53
|
+
if (current === "--cwd" && next) {
|
|
54
|
+
options.cwd = path.resolve(next);
|
|
55
|
+
i += 1;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (current === "--cwd")
|
|
59
|
+
throw new Error("Missing value for --cwd");
|
|
60
|
+
if (current === "--workspace") {
|
|
61
|
+
options.workspace = true;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (current === "--interactive") {
|
|
65
|
+
options.interactive = true;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (current === "--security-only") {
|
|
69
|
+
options.securityOnly = true;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (current === "--risk" && next) {
|
|
73
|
+
options.risk = ensureRiskLevel(next);
|
|
74
|
+
i += 1;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (current === "--risk")
|
|
78
|
+
throw new Error("Missing value for --risk");
|
|
79
|
+
if (current === "--diff" && next) {
|
|
80
|
+
if (next === "patch" ||
|
|
81
|
+
next === "minor" ||
|
|
82
|
+
next === "major" ||
|
|
83
|
+
next === "latest") {
|
|
84
|
+
options.diff = next;
|
|
85
|
+
i += 1;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
throw new Error("--diff must be patch, minor, major or latest");
|
|
89
|
+
}
|
|
90
|
+
if (current === "--diff")
|
|
91
|
+
throw new Error("Missing value for --diff");
|
|
92
|
+
if (current === "--apply-selected") {
|
|
93
|
+
options.applySelected = true;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (current === "--json-file" && next) {
|
|
97
|
+
options.jsonFile = path.resolve(options.cwd, next);
|
|
98
|
+
i += 1;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (current === "--json-file")
|
|
102
|
+
throw new Error("Missing value for --json-file");
|
|
103
|
+
if (current === "--policy-file" && next) {
|
|
104
|
+
options.policyFile = path.resolve(options.cwd, next);
|
|
105
|
+
i += 1;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (current === "--policy-file")
|
|
109
|
+
throw new Error("Missing value for --policy-file");
|
|
110
|
+
if (current === "--concurrency" && next) {
|
|
111
|
+
const parsed = Number(next);
|
|
112
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
113
|
+
throw new Error("--concurrency must be a positive integer");
|
|
114
|
+
}
|
|
115
|
+
options.concurrency = parsed;
|
|
116
|
+
i += 1;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (current === "--concurrency")
|
|
120
|
+
throw new Error("Missing value for --concurrency");
|
|
121
|
+
if (current === "--registry-timeout-ms" && next) {
|
|
122
|
+
const parsed = Number(next);
|
|
123
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
124
|
+
throw new Error("--registry-timeout-ms must be a positive integer");
|
|
125
|
+
}
|
|
126
|
+
options.registryTimeoutMs = parsed;
|
|
127
|
+
i += 1;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (current === "--registry-timeout-ms") {
|
|
131
|
+
throw new Error("Missing value for --registry-timeout-ms");
|
|
132
|
+
}
|
|
133
|
+
if (current === "--registry-retries" && next) {
|
|
134
|
+
const parsed = Number(next);
|
|
135
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
136
|
+
throw new Error("--registry-retries must be a positive integer");
|
|
137
|
+
}
|
|
138
|
+
options.registryRetries = parsed;
|
|
139
|
+
i += 1;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (current === "--registry-retries") {
|
|
143
|
+
throw new Error("Missing value for --registry-retries");
|
|
144
|
+
}
|
|
145
|
+
if (current === "--help" || current === "-h") {
|
|
146
|
+
process.stdout.write(REVIEW_HELP);
|
|
147
|
+
process.exit(0);
|
|
148
|
+
}
|
|
149
|
+
if (current.startsWith("-"))
|
|
150
|
+
throw new Error(`Unknown review option: ${current}`);
|
|
151
|
+
throw new Error(`Unexpected review argument: ${current}`);
|
|
152
|
+
}
|
|
153
|
+
return options;
|
|
154
|
+
}
|
|
155
|
+
const REVIEW_HELP = `
|
|
156
|
+
rup review — Guided dependency review across updates, security, peer conflicts, and policy
|
|
157
|
+
|
|
158
|
+
Usage:
|
|
159
|
+
rup review [options]
|
|
160
|
+
|
|
161
|
+
Options:
|
|
162
|
+
--interactive Launch the interactive review TUI
|
|
163
|
+
--security-only Show only packages with advisories
|
|
164
|
+
--risk <level> Minimum risk: critical, high, medium, low
|
|
165
|
+
--diff <level> Filter by patch, minor, major, latest
|
|
166
|
+
--apply-selected Apply all filtered updates after review
|
|
167
|
+
--workspace Scan all workspace packages
|
|
168
|
+
--policy-file <path> Load policy overrides
|
|
169
|
+
--json-file <path> Write JSON review report to file
|
|
170
|
+
--registry-timeout-ms <n>
|
|
171
|
+
--registry-retries <n>
|
|
172
|
+
--concurrency <n>
|
|
173
|
+
--cwd <path>
|
|
174
|
+
`.trimStart();
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { runTui } from "../../ui/tui.js";
|
|
3
|
+
import { buildReviewResult, renderReviewResult } from "../../core/review-model.js";
|
|
4
|
+
import { applySelectedUpdates } from "../../core/upgrade.js";
|
|
5
|
+
import { stableStringify } from "../../utils/stable-json.js";
|
|
6
|
+
import { writeFileAtomic } from "../../utils/io.js";
|
|
7
|
+
export async function runReview(options) {
|
|
8
|
+
const review = await buildReviewResult(options);
|
|
9
|
+
let selectedUpdates = review.updates;
|
|
10
|
+
if (options.interactive && review.updates.length > 0) {
|
|
11
|
+
selectedUpdates = await runTui(review.updates);
|
|
12
|
+
}
|
|
13
|
+
if (options.applySelected && selectedUpdates.length > 0) {
|
|
14
|
+
await applySelectedUpdates({
|
|
15
|
+
...options,
|
|
16
|
+
install: false,
|
|
17
|
+
packageManager: "auto",
|
|
18
|
+
sync: false,
|
|
19
|
+
}, selectedUpdates);
|
|
20
|
+
}
|
|
21
|
+
process.stdout.write(renderReviewResult({
|
|
22
|
+
...review,
|
|
23
|
+
updates: selectedUpdates,
|
|
24
|
+
items: review.items.filter((item) => selectedUpdates.some((selected) => selected.name === item.update.name && selected.packagePath === item.update.packagePath)),
|
|
25
|
+
}) + "\n");
|
|
26
|
+
if (options.jsonFile) {
|
|
27
|
+
await writeFileAtomic(options.jsonFile, stableStringify(review, 2) + "\n");
|
|
28
|
+
}
|
|
29
|
+
return review;
|
|
30
|
+
}
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -35,6 +35,9 @@ export interface FileConfig {
|
|
|
35
35
|
onlyChanged?: boolean;
|
|
36
36
|
ciProfile?: CiProfile;
|
|
37
37
|
lockfileMode?: LockfileMode;
|
|
38
|
+
interactive?: boolean;
|
|
39
|
+
showImpact?: boolean;
|
|
40
|
+
showHomepage?: boolean;
|
|
38
41
|
install?: boolean;
|
|
39
42
|
packageManager?: "auto" | "npm" | "pnpm";
|
|
40
43
|
sync?: boolean;
|
package/dist/core/check.js
CHANGED
|
@@ -9,6 +9,8 @@ import { detectPackageManager } from "../pm/detect.js";
|
|
|
9
9
|
import { discoverPackageDirs } from "../workspace/discover.js";
|
|
10
10
|
import { loadPolicy, resolvePolicyRule } from "../config/policy.js";
|
|
11
11
|
import { createSummary, finalizeSummary } from "./summary.js";
|
|
12
|
+
import { applyImpactScores } from "./impact.js";
|
|
13
|
+
import { formatClassifiedMessage } from "./errors.js";
|
|
12
14
|
export async function check(options) {
|
|
13
15
|
const startedAt = Date.now();
|
|
14
16
|
let discoveryMs = 0;
|
|
@@ -28,7 +30,13 @@ export async function check(options) {
|
|
|
28
30
|
const errors = [];
|
|
29
31
|
const warnings = [];
|
|
30
32
|
if (cache.degraded) {
|
|
31
|
-
warnings.push(
|
|
33
|
+
warnings.push(formatClassifiedMessage({
|
|
34
|
+
code: "CACHE_BACKEND_FALLBACK",
|
|
35
|
+
whatFailed: cache.fallbackReason ?? "Preferred SQLite cache backend is unavailable.",
|
|
36
|
+
intact: "Dependency analysis continues with the file cache backend.",
|
|
37
|
+
validity: "partial",
|
|
38
|
+
next: "Run `rup warm-cache` after restoring SQLite support if you want the preferred backend again.",
|
|
39
|
+
}));
|
|
32
40
|
}
|
|
33
41
|
let totalDependencies = 0;
|
|
34
42
|
const tasks = [];
|
|
@@ -85,6 +93,7 @@ export async function check(options) {
|
|
|
85
93
|
latestVersion: cached.latestVersion,
|
|
86
94
|
availableVersions: cached.availableVersions,
|
|
87
95
|
publishedAtByVersion: {},
|
|
96
|
+
hasInstallScript: false,
|
|
88
97
|
});
|
|
89
98
|
}
|
|
90
99
|
else {
|
|
@@ -102,11 +111,18 @@ export async function check(options) {
|
|
|
102
111
|
latestVersion: stale.latestVersion,
|
|
103
112
|
availableVersions: stale.availableVersions,
|
|
104
113
|
publishedAtByVersion: {},
|
|
114
|
+
hasInstallScript: false,
|
|
105
115
|
});
|
|
106
116
|
warnings.push(`Using stale cache for ${packageName} because --offline is enabled.`);
|
|
107
117
|
}
|
|
108
118
|
else {
|
|
109
|
-
errors.push(
|
|
119
|
+
errors.push(formatClassifiedMessage({
|
|
120
|
+
code: "REGISTRY_ERROR",
|
|
121
|
+
whatFailed: `Offline cache miss for ${packageName}.`,
|
|
122
|
+
intact: "Local manifests and previously cached packages remain unchanged.",
|
|
123
|
+
validity: "invalid",
|
|
124
|
+
next: `Run \`rup warm-cache --cwd ${options.cwd}\` or retry without --offline.`,
|
|
125
|
+
}));
|
|
110
126
|
}
|
|
111
127
|
}
|
|
112
128
|
cacheMs += Date.now() - cacheFallbackStartedAt;
|
|
@@ -125,6 +141,9 @@ export async function check(options) {
|
|
|
125
141
|
latestVersion: metadata.latestVersion,
|
|
126
142
|
availableVersions: metadata.versions,
|
|
127
143
|
publishedAtByVersion: metadata.publishedAtByVersion,
|
|
144
|
+
homepage: metadata.homepage,
|
|
145
|
+
repository: metadata.repository,
|
|
146
|
+
hasInstallScript: metadata.hasInstallScript,
|
|
128
147
|
});
|
|
129
148
|
if (metadata.latestVersion) {
|
|
130
149
|
await cache.set(packageName, options.target, metadata.latestVersion, metadata.versions, options.cacheTtlSeconds);
|
|
@@ -139,12 +158,24 @@ export async function check(options) {
|
|
|
139
158
|
latestVersion: stale.latestVersion,
|
|
140
159
|
availableVersions: stale.availableVersions,
|
|
141
160
|
publishedAtByVersion: {},
|
|
161
|
+
hasInstallScript: false,
|
|
142
162
|
});
|
|
143
163
|
warnings.push(`Using stale cache for ${packageName} due to registry error: ${error}`);
|
|
144
164
|
}
|
|
145
165
|
else {
|
|
146
|
-
|
|
147
|
-
|
|
166
|
+
const classified = formatClassifiedMessage({
|
|
167
|
+
code: error.includes("401") || error.includes("403")
|
|
168
|
+
? "AUTH_ERROR"
|
|
169
|
+
: "REGISTRY_ERROR",
|
|
170
|
+
whatFailed: `Unable to resolve ${packageName}: ${error}.`,
|
|
171
|
+
intact: "Other package results and local files remain intact.",
|
|
172
|
+
validity: "partial",
|
|
173
|
+
next: error.includes("401") || error.includes("403")
|
|
174
|
+
? "Check .npmrc scoped registry credentials and retry."
|
|
175
|
+
: "Retry `rup check` or warm the cache before offline runs.",
|
|
176
|
+
});
|
|
177
|
+
errors.push(classified);
|
|
178
|
+
emitStream(`[error] ${classified}`);
|
|
148
179
|
}
|
|
149
180
|
}
|
|
150
181
|
cacheMs += Date.now() - cacheStaleStartedAt;
|
|
@@ -182,10 +213,12 @@ export async function check(options) {
|
|
|
182
213
|
filtered: false,
|
|
183
214
|
autofix: rule?.autofix !== false,
|
|
184
215
|
reason: rule?.maxTarget ? `policy maxTarget=${rule.maxTarget}` : undefined,
|
|
216
|
+
homepage: metadata.homepage,
|
|
185
217
|
});
|
|
186
218
|
emitStream(`[update] ${task.dependency.name} ${task.dependency.range} -> ${nextRange} (${classifyDiff(task.dependency.range, picked)})`);
|
|
187
219
|
}
|
|
188
|
-
const
|
|
220
|
+
const scoredUpdates = applyImpactScores(updates);
|
|
221
|
+
const grouped = groupUpdates(scoredUpdates, options.groupBy);
|
|
189
222
|
const groupedUpdates = grouped.length;
|
|
190
223
|
const groupedSorted = sortUpdates(grouped.flatMap((group) => group.items));
|
|
191
224
|
const groupedCapped = typeof options.groupMax === "number" ? groupedSorted.slice(0, options.groupMax) : groupedSorted;
|
|
@@ -219,6 +252,7 @@ export async function check(options) {
|
|
|
219
252
|
policyOverridesApplied,
|
|
220
253
|
}));
|
|
221
254
|
summary.streamedEvents = streamedEvents;
|
|
255
|
+
summary.riskPackages = limitedUpdates.filter((item) => item.impactScore?.rank === "critical" || item.impactScore?.rank === "high").length;
|
|
222
256
|
return {
|
|
223
257
|
projectPath: options.cwd,
|
|
224
258
|
packagePaths: packageDirs,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ErrorCode = "REGISTRY_ERROR" | "AUTH_ERROR" | "ADVISORY_SOURCE_DEGRADED" | "ADVISORY_SOURCE_DOWN" | "CACHE_BACKEND_FALLBACK";
|
|
2
|
+
export type ErrorValidity = "partial" | "invalid" | "intact";
|
|
3
|
+
export interface ClassifiedMessageInput {
|
|
4
|
+
code: ErrorCode;
|
|
5
|
+
whatFailed: string;
|
|
6
|
+
intact: string;
|
|
7
|
+
validity: ErrorValidity;
|
|
8
|
+
next: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function formatClassifiedMessage(input: ClassifiedMessageInput): string;
|
|
11
|
+
export declare function hasErrorCode(value: string, code: ErrorCode): boolean;
|
package/dist/core/options.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BaselineOptions, CheckOptions, UpgradeOptions, AuditOptions, BisectOptions, HealthOptions, UnusedOptions, ResolveOptions, LicenseOptions, SnapshotOptions } from "../types/index.js";
|
|
1
|
+
import type { BaselineOptions, CheckOptions, UpgradeOptions, AuditOptions, BisectOptions, HealthOptions, UnusedOptions, ResolveOptions, LicenseOptions, SnapshotOptions, ReviewOptions, DoctorOptions, RiskLevel } from "../types/index.js";
|
|
2
2
|
import type { InitCiMode, InitCiSchedule } from "./init-ci.js";
|
|
3
3
|
export type ParsedCliArgs = {
|
|
4
4
|
command: "check";
|
|
@@ -46,5 +46,12 @@ export type ParsedCliArgs = {
|
|
|
46
46
|
} | {
|
|
47
47
|
command: "snapshot";
|
|
48
48
|
options: SnapshotOptions;
|
|
49
|
+
} | {
|
|
50
|
+
command: "review";
|
|
51
|
+
options: ReviewOptions;
|
|
52
|
+
} | {
|
|
53
|
+
command: "doctor";
|
|
54
|
+
options: DoctorOptions;
|
|
49
55
|
};
|
|
50
56
|
export declare function parseCliArgs(argv: string[]): Promise<ParsedCliArgs>;
|
|
57
|
+
export declare function ensureRiskLevel(value: string): RiskLevel;
|
package/dist/core/options.js
CHANGED
|
@@ -21,6 +21,8 @@ const KNOWN_COMMANDS = [
|
|
|
21
21
|
"resolve",
|
|
22
22
|
"licenses",
|
|
23
23
|
"snapshot",
|
|
24
|
+
"review",
|
|
25
|
+
"doctor",
|
|
24
26
|
];
|
|
25
27
|
export async function parseCliArgs(argv) {
|
|
26
28
|
const firstArg = argv[0];
|
|
@@ -62,6 +64,14 @@ export async function parseCliArgs(argv) {
|
|
|
62
64
|
const { parseSnapshotArgs } = await import("../commands/snapshot/parser.js");
|
|
63
65
|
return { command, options: parseSnapshotArgs(args) };
|
|
64
66
|
}
|
|
67
|
+
if (command === "review") {
|
|
68
|
+
const { parseReviewArgs } = await import("../commands/review/parser.js");
|
|
69
|
+
return { command, options: parseReviewArgs(args) };
|
|
70
|
+
}
|
|
71
|
+
if (command === "doctor") {
|
|
72
|
+
const { parseDoctorArgs } = await import("../commands/doctor/parser.js");
|
|
73
|
+
return { command, options: parseDoctorArgs(args) };
|
|
74
|
+
}
|
|
65
75
|
const base = {
|
|
66
76
|
cwd: process.cwd(),
|
|
67
77
|
target: "latest",
|
|
@@ -99,6 +109,9 @@ export async function parseCliArgs(argv) {
|
|
|
99
109
|
onlyChanged: false,
|
|
100
110
|
ciProfile: "minimal",
|
|
101
111
|
lockfileMode: "preserve",
|
|
112
|
+
interactive: false,
|
|
113
|
+
showImpact: false,
|
|
114
|
+
showHomepage: false,
|
|
102
115
|
};
|
|
103
116
|
let force = false;
|
|
104
117
|
let initCiMode = "enterprise";
|
|
@@ -429,6 +442,18 @@ export async function parseCliArgs(argv) {
|
|
|
429
442
|
base.onlyChanged = true;
|
|
430
443
|
continue;
|
|
431
444
|
}
|
|
445
|
+
if (current === "--interactive") {
|
|
446
|
+
base.interactive = true;
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
if (current === "--show-impact") {
|
|
450
|
+
base.showImpact = true;
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
if (current === "--show-homepage") {
|
|
454
|
+
base.showHomepage = true;
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
432
457
|
if (current === "--lockfile-mode" && next) {
|
|
433
458
|
base.lockfileMode = ensureLockfileMode(next);
|
|
434
459
|
index += 1;
|
|
@@ -639,6 +664,15 @@ function applyConfig(base, config) {
|
|
|
639
664
|
if (typeof config.lockfileMode === "string") {
|
|
640
665
|
base.lockfileMode = ensureLockfileMode(config.lockfileMode);
|
|
641
666
|
}
|
|
667
|
+
if (typeof config.interactive === "boolean") {
|
|
668
|
+
base.interactive = config.interactive;
|
|
669
|
+
}
|
|
670
|
+
if (typeof config.showImpact === "boolean") {
|
|
671
|
+
base.showImpact = config.showImpact;
|
|
672
|
+
}
|
|
673
|
+
if (typeof config.showHomepage === "boolean") {
|
|
674
|
+
base.showHomepage = config.showHomepage;
|
|
675
|
+
}
|
|
642
676
|
}
|
|
643
677
|
function parsePackageManager(args) {
|
|
644
678
|
const index = args.indexOf("--pm");
|
|
@@ -743,3 +777,12 @@ function ensureLockfileMode(value) {
|
|
|
743
777
|
}
|
|
744
778
|
throw new Error("--lockfile-mode must be preserve, update or error");
|
|
745
779
|
}
|
|
780
|
+
export function ensureRiskLevel(value) {
|
|
781
|
+
if (value === "critical" ||
|
|
782
|
+
value === "high" ||
|
|
783
|
+
value === "medium" ||
|
|
784
|
+
value === "low") {
|
|
785
|
+
return value;
|
|
786
|
+
}
|
|
787
|
+
throw new Error("--risk must be critical, high, medium or low");
|
|
788
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CheckOptions, DoctorOptions, DoctorResult, ReviewOptions, ReviewResult } from "../types/index.js";
|
|
2
|
+
export declare function buildReviewResult(options: ReviewOptions | DoctorOptions | CheckOptions): Promise<ReviewResult>;
|
|
3
|
+
export declare function createDoctorResult(review: ReviewResult): DoctorResult;
|
|
4
|
+
export declare function renderReviewResult(review: ReviewResult): string;
|
|
5
|
+
export declare function renderDoctorResult(result: DoctorResult, verdictOnly?: boolean): string;
|