react-doctor 0.9.7-dev.13138a4 → 0.9.7
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 +10780 -96
- package/dist/{devtools-DPRVRu3S.js → devtools-BQATi33M.js} +3 -3
- package/dist/{record-metric-CtlQma6P.js → exit-gracefully-BJRsqdaK.js} +11954 -6251
- package/dist/index.d.ts +4082 -4704
- package/dist/index.js +4386 -6069
- package/dist/lsp.js +4510 -6181
- package/dist/{run-scan-app-Drlqxtzl.js → run-scan-app-DawD5rhU.js} +29 -36
- package/package.json +3 -2
- package/dist/build-section-divider-QykRnrlR.js +0 -312
- package/dist/ci-BvGqcDKc.js +0 -7501
- package/dist/design-SGX69YQq.js +0 -14
- package/dist/exit-gracefully-CddufLS0.js +0 -47
- package/dist/inspect-DBJtHure.js +0 -1443
- package/dist/install-doctor-script-DxrteuEw.js +0 -3251
- package/dist/install-ffJ108LC.js +0 -32
- package/dist/install-github-workflow-BP6t3YBA.js +0 -267
- package/dist/install-react-doctor-BhfvyNZB.js +0 -1154
- package/dist/print-branded-header-Cw5AlicW.js +0 -22
- package/dist/read-object-file-ITGVjFKp.js +0 -24
- package/dist/report-error-DUoFKR7d.js +0 -158
- package/dist/report-workflow-result-D3GCowCN.js +0 -279
- package/dist/resolve-scope-gy72JH3h.js +0 -339
- package/dist/rules-6-d19pN1.js +0 -581
- package/dist/scan-C3Io41Dq.js +0 -53
- package/dist/should-fail-scan-gate-DImKUuu-.js +0 -3075
- package/dist/should-skip-prompts-CbIIaU8b.js +0 -10
- package/dist/unref-stdin-B5RnVeLa.js +0 -120
- package/dist/version-BFKBxkKV.js +0 -21
- package/dist/why-DO4CTn-R.js +0 -21
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6d1dde0f-d9fe-5053-b24c-3e5de5579599")}catch(e){}}();
|
|
3
|
-
import { Bt as filterSourceFiles, an as isPathInsideDirectory, jn as toCanonicalPath } from "./record-metric-CtlQma6P.js";
|
|
4
|
-
import { L as cliLogger } from "./install-doctor-script-DxrteuEw.js";
|
|
5
|
-
import { d as detectDefaultBranch, f as runCommand, l as prompts, u as isCommandAvailable } from "./install-github-workflow-BP6t3YBA.js";
|
|
6
|
-
import * as path$1 from "node:path";
|
|
7
|
-
//#region src/cli/utils/path-format.ts
|
|
8
|
-
const toForwardSlashes = (filePath) => filePath.replaceAll("\\", "/");
|
|
9
|
-
//#endregion
|
|
10
|
-
//#region src/cli/utils/open-workflow-pull-request.ts
|
|
11
|
-
const NEW_BRANCH_PREFIX = "react-doctor/add-github-actions";
|
|
12
|
-
const DEFAULT_COMMIT_MESSAGE = "ci: add React Doctor GitHub Actions workflow";
|
|
13
|
-
const DEFAULT_PR_TITLE = "Add React Doctor to GitHub Actions";
|
|
14
|
-
const DEFAULT_PR_BODY = `Adds a [React Doctor](https://www.react.doctor) scan to every pull request and every push to the default branch. The workflow file is documented inline.
|
|
15
|
-
|
|
16
|
-
Docs: https://www.react.doctor/ci`;
|
|
17
|
-
const resolveWorkflowRepositoryLocation = (workflowPath, repositoryRoot) => {
|
|
18
|
-
const canonicalWorkflowPath = toCanonicalPath(workflowPath);
|
|
19
|
-
const canonicalRepositoryRoot = toCanonicalPath(repositoryRoot);
|
|
20
|
-
if (!isPathInsideDirectory(canonicalWorkflowPath, canonicalRepositoryRoot)) return null;
|
|
21
|
-
return {
|
|
22
|
-
repositoryRoot: canonicalRepositoryRoot,
|
|
23
|
-
workflowRelativePath: toForwardSlashes(path$1.relative(canonicalRepositoryRoot, canonicalWorkflowPath))
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
const findUniqueBranchName = async (cwd, run) => {
|
|
27
|
-
if (!(await run("git", [
|
|
28
|
-
"rev-parse",
|
|
29
|
-
"--verify",
|
|
30
|
-
NEW_BRANCH_PREFIX
|
|
31
|
-
], cwd)).success) return NEW_BRANCH_PREFIX;
|
|
32
|
-
return `${NEW_BRANCH_PREFIX}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16).replace(/[-:T]/g, "")}`;
|
|
33
|
-
};
|
|
34
|
-
const findExistingSetupPullRequest = async (cwd, run) => {
|
|
35
|
-
const prList = await run("gh", [
|
|
36
|
-
"pr",
|
|
37
|
-
"list",
|
|
38
|
-
"--state",
|
|
39
|
-
"open",
|
|
40
|
-
"--json",
|
|
41
|
-
"headRefName,url",
|
|
42
|
-
"--limit",
|
|
43
|
-
String(100)
|
|
44
|
-
], cwd);
|
|
45
|
-
if (!prList.success) return null;
|
|
46
|
-
try {
|
|
47
|
-
return JSON.parse(prList.stdout).find((pullRequest) => (pullRequest.headRefName ?? "").startsWith(NEW_BRANCH_PREFIX)) ?? null;
|
|
48
|
-
} catch {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
const hasUnrelatedTrackedChanges = async (cwd, workflowRelative, run) => {
|
|
53
|
-
const statusProbe = await run("git", [
|
|
54
|
-
"status",
|
|
55
|
-
"--porcelain",
|
|
56
|
-
"--",
|
|
57
|
-
".",
|
|
58
|
-
`:!${workflowRelative}`
|
|
59
|
-
], cwd);
|
|
60
|
-
if (!statusProbe.success) return true;
|
|
61
|
-
return statusProbe.stdout.split(/\r?\n/).filter(Boolean).some((statusLine) => !statusLine.startsWith("??"));
|
|
62
|
-
};
|
|
63
|
-
const openWorkflowPullRequest = async (input) => {
|
|
64
|
-
const workflowPath = path$1.resolve(input.workflowPath);
|
|
65
|
-
const commitMessage = input.commitMessage ?? DEFAULT_COMMIT_MESSAGE;
|
|
66
|
-
const prTitle = input.prTitle ?? DEFAULT_PR_TITLE;
|
|
67
|
-
const prBody = input.prBody ?? DEFAULT_PR_BODY;
|
|
68
|
-
const run = input.run ?? runCommand;
|
|
69
|
-
const checkCommandAvailable = input.checkCommandAvailable ?? isCommandAvailable;
|
|
70
|
-
const repoRootProbe = await run("git", ["rev-parse", "--show-toplevel"], path$1.dirname(workflowPath));
|
|
71
|
-
if (!repoRootProbe.success) return {
|
|
72
|
-
status: "not-attempted",
|
|
73
|
-
reason: "not-a-git-repo"
|
|
74
|
-
};
|
|
75
|
-
const repositoryLocation = resolveWorkflowRepositoryLocation(workflowPath, repoRootProbe.stdout);
|
|
76
|
-
if (repositoryLocation === null) return {
|
|
77
|
-
status: "not-attempted",
|
|
78
|
-
reason: "workflow-outside-repository"
|
|
79
|
-
};
|
|
80
|
-
const cwd = repositoryLocation.repositoryRoot;
|
|
81
|
-
const workflowRelative = repositoryLocation.workflowRelativePath;
|
|
82
|
-
if (!checkCommandAvailable("gh")) return {
|
|
83
|
-
status: "not-attempted",
|
|
84
|
-
reason: "gh-not-installed"
|
|
85
|
-
};
|
|
86
|
-
if (!(await run("gh", ["auth", "status"], cwd)).success) return {
|
|
87
|
-
status: "not-attempted",
|
|
88
|
-
reason: "gh-not-authenticated"
|
|
89
|
-
};
|
|
90
|
-
const existingSetupPullRequest = await findExistingSetupPullRequest(cwd, run);
|
|
91
|
-
if (existingSetupPullRequest) return {
|
|
92
|
-
status: "pr-exists",
|
|
93
|
-
url: existingSetupPullRequest.url ?? ""
|
|
94
|
-
};
|
|
95
|
-
if (await hasUnrelatedTrackedChanges(cwd, workflowRelative, run)) return {
|
|
96
|
-
status: "not-attempted",
|
|
97
|
-
reason: "working-tree-dirty"
|
|
98
|
-
};
|
|
99
|
-
const defaultBranch = input.baseBranch ?? await detectDefaultBranch(cwd, run);
|
|
100
|
-
if (!defaultBranch) return {
|
|
101
|
-
status: "not-attempted",
|
|
102
|
-
reason: "no-default-branch"
|
|
103
|
-
};
|
|
104
|
-
const previousBranchProbe = await run("git", [
|
|
105
|
-
"rev-parse",
|
|
106
|
-
"--abbrev-ref",
|
|
107
|
-
"HEAD"
|
|
108
|
-
], cwd);
|
|
109
|
-
if (!previousBranchProbe.success || previousBranchProbe.stdout === "HEAD") return {
|
|
110
|
-
status: "not-attempted",
|
|
111
|
-
reason: "detached-head"
|
|
112
|
-
};
|
|
113
|
-
const previousBranch = previousBranchProbe.stdout;
|
|
114
|
-
await run("git", [
|
|
115
|
-
"fetch",
|
|
116
|
-
"origin",
|
|
117
|
-
defaultBranch
|
|
118
|
-
], cwd);
|
|
119
|
-
const newBranch = await findUniqueBranchName(cwd, run);
|
|
120
|
-
if (!(await run("git", [
|
|
121
|
-
"checkout",
|
|
122
|
-
"-b",
|
|
123
|
-
newBranch,
|
|
124
|
-
`origin/${defaultBranch}`
|
|
125
|
-
], cwd)).success) return {
|
|
126
|
-
status: "not-attempted",
|
|
127
|
-
reason: "checkout-failed"
|
|
128
|
-
};
|
|
129
|
-
const restoreToPreviousBranch = async (deleteNewBranch) => {
|
|
130
|
-
await run("git", ["checkout", previousBranch], cwd);
|
|
131
|
-
if (deleteNewBranch) await run("git", [
|
|
132
|
-
"branch",
|
|
133
|
-
"-D",
|
|
134
|
-
newBranch
|
|
135
|
-
], cwd);
|
|
136
|
-
};
|
|
137
|
-
if (!(await run("git", [
|
|
138
|
-
"add",
|
|
139
|
-
"--",
|
|
140
|
-
workflowRelative
|
|
141
|
-
], cwd)).success) {
|
|
142
|
-
await restoreToPreviousBranch(true);
|
|
143
|
-
return {
|
|
144
|
-
status: "not-attempted",
|
|
145
|
-
reason: "git-add-failed"
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
if (!(await run("git", [
|
|
149
|
-
"commit",
|
|
150
|
-
"-m",
|
|
151
|
-
commitMessage
|
|
152
|
-
], cwd)).success) {
|
|
153
|
-
await restoreToPreviousBranch(true);
|
|
154
|
-
return {
|
|
155
|
-
status: "not-attempted",
|
|
156
|
-
reason: "git-commit-failed"
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
if (!(await run("git", [
|
|
160
|
-
"push",
|
|
161
|
-
"-u",
|
|
162
|
-
"origin",
|
|
163
|
-
newBranch
|
|
164
|
-
], cwd)).success) {
|
|
165
|
-
await restoreToPreviousBranch(true);
|
|
166
|
-
return {
|
|
167
|
-
status: "not-attempted",
|
|
168
|
-
reason: "git-push-failed"
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
const prCreate = await run("gh", [
|
|
172
|
-
"pr",
|
|
173
|
-
"create",
|
|
174
|
-
"--title",
|
|
175
|
-
prTitle,
|
|
176
|
-
"--body",
|
|
177
|
-
prBody,
|
|
178
|
-
"--base",
|
|
179
|
-
defaultBranch,
|
|
180
|
-
"--head",
|
|
181
|
-
newBranch
|
|
182
|
-
], cwd);
|
|
183
|
-
await restoreToPreviousBranch(false);
|
|
184
|
-
if (!prCreate.success) return {
|
|
185
|
-
status: "branch-pushed",
|
|
186
|
-
branch: newBranch
|
|
187
|
-
};
|
|
188
|
-
return {
|
|
189
|
-
status: "pr-opened",
|
|
190
|
-
url: prCreate.stdout.split(/\r?\n/).filter(Boolean).pop() ?? ""
|
|
191
|
-
};
|
|
192
|
-
};
|
|
193
|
-
const stageWorkflowFile = async (input) => {
|
|
194
|
-
const workflowPath = path$1.resolve(input.workflowPath);
|
|
195
|
-
const run = input.run ?? runCommand;
|
|
196
|
-
const repoRootProbe = await run("git", ["rev-parse", "--show-toplevel"], path$1.dirname(workflowPath));
|
|
197
|
-
if (!repoRootProbe.success) return false;
|
|
198
|
-
const repositoryLocation = resolveWorkflowRepositoryLocation(workflowPath, repoRootProbe.stdout);
|
|
199
|
-
if (repositoryLocation === null) return false;
|
|
200
|
-
return (await run("git", [
|
|
201
|
-
"add",
|
|
202
|
-
"--",
|
|
203
|
-
repositoryLocation.workflowRelativePath
|
|
204
|
-
], repositoryLocation.repositoryRoot)).success;
|
|
205
|
-
};
|
|
206
|
-
//#endregion
|
|
207
|
-
//#region src/cli/utils/resolve-blocking-level.ts
|
|
208
|
-
const VALID_BLOCKING_LEVELS = new Set([
|
|
209
|
-
"error",
|
|
210
|
-
"warning",
|
|
211
|
-
"none"
|
|
212
|
-
]);
|
|
213
|
-
const DEFAULT_BLOCKING_LEVEL = "error";
|
|
214
|
-
const isValidBlockingLevel = (level) => VALID_BLOCKING_LEVELS.has(level);
|
|
215
|
-
const pickBlockingLevel = (flags, userConfig) => flags.blocking ?? flags.failOn ?? userConfig?.blocking ?? userConfig?.failOn;
|
|
216
|
-
const resolveBlockingLevel = (flags, userConfig) => {
|
|
217
|
-
const sourceValue = pickBlockingLevel(flags, userConfig) ?? DEFAULT_BLOCKING_LEVEL;
|
|
218
|
-
if (isValidBlockingLevel(sourceValue)) return sourceValue;
|
|
219
|
-
cliLogger.warn(`Invalid blocking level "${sourceValue}". Expected one of: error, warning, none. Falling back to "${DEFAULT_BLOCKING_LEVEL}".`);
|
|
220
|
-
return DEFAULT_BLOCKING_LEVEL;
|
|
221
|
-
};
|
|
222
|
-
//#endregion
|
|
223
|
-
//#region src/cli/utils/resolve-scope.ts
|
|
224
|
-
const SCOPE_VALUES = new Set([
|
|
225
|
-
"full",
|
|
226
|
-
"files",
|
|
227
|
-
"changed",
|
|
228
|
-
"lines"
|
|
229
|
-
]);
|
|
230
|
-
const isScopeValue = (value) => SCOPE_VALUES.has(value);
|
|
231
|
-
const coerceDeprecatedDiff = (value) => {
|
|
232
|
-
if (value === void 0) return void 0;
|
|
233
|
-
if (value === false || value === "false") return { scope: "full" };
|
|
234
|
-
if (value === true || value === "true") return { scope: "changed" };
|
|
235
|
-
if (value === "") return void 0;
|
|
236
|
-
return {
|
|
237
|
-
scope: "changed",
|
|
238
|
-
base: value
|
|
239
|
-
};
|
|
240
|
-
};
|
|
241
|
-
/**
|
|
242
|
-
* Resolves the *requested* scope from flags + config without touching git.
|
|
243
|
-
* Precedence mirrors `pickBlockingLevel`: flags win over config, and the new
|
|
244
|
-
* `--scope` wins over the deprecated `--diff` alias on each side
|
|
245
|
-
* (`flags.scope` > `flags.diff` > `config.scope` > `config.diff`). Returns
|
|
246
|
-
* `scope: undefined` when nothing is set so the caller can default to `full`
|
|
247
|
-
* or offer the interactive prompt.
|
|
248
|
-
*/
|
|
249
|
-
const resolveScope = (flags, userConfig) => {
|
|
250
|
-
const base = flags.base ?? userConfig?.base;
|
|
251
|
-
if (typeof flags.scope === "string" && flags.scope.length > 0) {
|
|
252
|
-
if (isScopeValue(flags.scope)) return {
|
|
253
|
-
scope: flags.scope,
|
|
254
|
-
base,
|
|
255
|
-
usedDeprecatedDiff: false
|
|
256
|
-
};
|
|
257
|
-
cliLogger.warn(`Invalid --scope "${flags.scope}". Expected one of: full, files, changed, lines. Ignoring.`);
|
|
258
|
-
}
|
|
259
|
-
const flagDiff = coerceDeprecatedDiff(flags.diff);
|
|
260
|
-
if (flagDiff !== void 0) return {
|
|
261
|
-
scope: flagDiff.scope,
|
|
262
|
-
base: base ?? flagDiff.base,
|
|
263
|
-
usedDeprecatedDiff: true
|
|
264
|
-
};
|
|
265
|
-
if (userConfig?.scope !== void 0) {
|
|
266
|
-
if (isScopeValue(userConfig.scope)) return {
|
|
267
|
-
scope: userConfig.scope,
|
|
268
|
-
base,
|
|
269
|
-
usedDeprecatedDiff: false
|
|
270
|
-
};
|
|
271
|
-
cliLogger.warn(`Invalid scope "${userConfig.scope}" in config. Expected one of: full, files, changed, lines. Ignoring.`);
|
|
272
|
-
}
|
|
273
|
-
const configDiff = coerceDeprecatedDiff(userConfig?.diff);
|
|
274
|
-
if (configDiff !== void 0) return {
|
|
275
|
-
scope: configDiff.scope,
|
|
276
|
-
base: base ?? configDiff.base,
|
|
277
|
-
usedDeprecatedDiff: true
|
|
278
|
-
};
|
|
279
|
-
return {
|
|
280
|
-
scope: void 0,
|
|
281
|
-
base,
|
|
282
|
-
usedDeprecatedDiff: false
|
|
283
|
-
};
|
|
284
|
-
};
|
|
285
|
-
const warnDeprecatedDiff = (flags, userConfig) => {
|
|
286
|
-
const usedFlag = flags.diff !== void 0;
|
|
287
|
-
if (!usedFlag && userConfig?.diff === void 0) return;
|
|
288
|
-
const targetScope = coerceDeprecatedDiff(usedFlag ? flags.diff : userConfig?.diff)?.scope ?? "changed";
|
|
289
|
-
if (usedFlag) {
|
|
290
|
-
const baseHint = targetScope === "changed" ? " (add `--base <ref>` to pin the base)" : "";
|
|
291
|
-
cliLogger.warn(`The \`--diff\` flag is deprecated; use \`--scope ${targetScope}\`${baseHint} instead.`);
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
cliLogger.warn(`The \`diff\` config option is deprecated; use \`scope: "${targetScope}"\` instead.`);
|
|
295
|
-
};
|
|
296
|
-
const warnDiffUnavailable = (requested, isQuiet) => {
|
|
297
|
-
if (isQuiet) return;
|
|
298
|
-
if (typeof requested.base === "string") cliLogger.warn(`Could not compute diff against "${requested.base}" (git unavailable, ref not found, or merge-base failed). Running full scan.`);
|
|
299
|
-
else cliLogger.warn("No feature branch or uncommitted changes detected. Running full scan.");
|
|
300
|
-
cliLogger.break();
|
|
301
|
-
};
|
|
302
|
-
/**
|
|
303
|
-
* Resolves the requested scope against the detected diff into the final scope.
|
|
304
|
-
* An explicit non-`full` scope needs a usable `diffInfo`; without one it warns
|
|
305
|
-
* and falls back to `full`. When nothing was requested, an interactive run on a
|
|
306
|
-
* branch with changed source files is offered the "full vs changed" prompt.
|
|
307
|
-
*/
|
|
308
|
-
const finalizeScope = async ({ requested, diffInfo, skipPrompts, isQuiet }) => {
|
|
309
|
-
if (requested.scope !== void 0) {
|
|
310
|
-
if (requested.scope === "full") return "full";
|
|
311
|
-
if (diffInfo !== null) return requested.scope;
|
|
312
|
-
warnDiffUnavailable(requested, isQuiet);
|
|
313
|
-
return "full";
|
|
314
|
-
}
|
|
315
|
-
if (diffInfo === null || skipPrompts || isQuiet) return "full";
|
|
316
|
-
const changedSourceFiles = filterSourceFiles([...diffInfo.changedFiles]);
|
|
317
|
-
if (changedSourceFiles.length === 0) return "full";
|
|
318
|
-
const { scanScope } = await prompts({
|
|
319
|
-
type: "select",
|
|
320
|
-
name: "scanScope",
|
|
321
|
-
message: "Choose what to scan",
|
|
322
|
-
choices: [{
|
|
323
|
-
title: "Full codebase",
|
|
324
|
-
description: "Scan every source file",
|
|
325
|
-
value: "full"
|
|
326
|
-
}, {
|
|
327
|
-
title: diffInfo.isCurrentChanges ? `Uncommitted changes (${changedSourceFiles.length})` : `Changed files on ${diffInfo.currentBranch ?? "this branch"} (${changedSourceFiles.length})`,
|
|
328
|
-
description: diffInfo.isCurrentChanges ? "Compare working tree changes against HEAD" : `Compare against ${diffInfo.baseBranch} from the branch merge-base`,
|
|
329
|
-
value: "changed"
|
|
330
|
-
}],
|
|
331
|
-
initial: diffInfo.isCurrentChanges ? 0 : 1
|
|
332
|
-
});
|
|
333
|
-
return scanScope === "changed" ? "changed" : "full";
|
|
334
|
-
};
|
|
335
|
-
//#endregion
|
|
336
|
-
export { isValidBlockingLevel as a, openWorkflowPullRequest as c, warnDeprecatedDiff as i, stageWorkflowFile as l, isScopeValue as n, pickBlockingLevel as o, resolveScope as r, resolveBlockingLevel as s, finalizeScope as t, toForwardSlashes as u };
|
|
337
|
-
|
|
338
|
-
//# sourceMappingURL=resolve-scope-gy72JH3h.js.map
|
|
339
|
-
//# debugId=6d1dde0f-d9fe-5053-b24c-3e5de5579599
|