react-doctor 0.7.6-dev.0d11bd5 → 0.7.6-dev.17418
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 +61 -227
- package/dist/index.d.ts +4 -5
- package/dist/index.js +37 -87
- package/dist/lsp.js +61 -104
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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]="
|
|
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]="63b8a227-543e-5501-a998-58c03a1fb10e")}catch(e){}}();
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import * as NodeChildProcess from "node:child_process";
|
|
5
5
|
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
@@ -36341,12 +36341,10 @@ const listSourceFilesViaFilesystem = (rootDirectory) => {
|
|
|
36341
36341
|
const listSourceFilesWithSize = (rootDirectory) => collectSizedSourceFiles(rootDirectory, (listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory)).sort());
|
|
36342
36342
|
const listSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).map((entry) => entry.path);
|
|
36343
36343
|
const countSourceFiles = (rootDirectory) => listSourceFilesWithSize(rootDirectory).length;
|
|
36344
|
-
const UTF8_BOM_CHARACTER = "";
|
|
36345
|
-
const stripUtf8Bom = (content) => content.startsWith(UTF8_BOM_CHARACTER) ? content.slice(1) : content;
|
|
36346
36344
|
const cachedPackageJsons = /* @__PURE__ */ new Map();
|
|
36347
36345
|
const readPackageJsonUncached = (packageJsonPath) => {
|
|
36348
36346
|
try {
|
|
36349
|
-
return JSON.parse(
|
|
36347
|
+
return JSON.parse(NFS.readFileSync(packageJsonPath, "utf-8"));
|
|
36350
36348
|
} catch (error) {
|
|
36351
36349
|
if (error instanceof SyntaxError) return {};
|
|
36352
36350
|
if (isErrnoException(error)) {
|
|
@@ -40019,6 +40017,7 @@ const PNPM_WORKSPACE_FILE = "pnpm-workspace.yaml";
|
|
|
40019
40017
|
const PNPM_LOCKFILE = "pnpm-lock.yaml";
|
|
40020
40018
|
const PACKAGE_JSON_FILE = "package.json";
|
|
40021
40019
|
const PNPM_HARDENING_RULE_KEY = "require-pnpm-hardening";
|
|
40020
|
+
const UTF8_BOM_CHAR = "";
|
|
40022
40021
|
const HARDENING_SETTING_KEYS = new Set([
|
|
40023
40022
|
"minimumReleaseAge",
|
|
40024
40023
|
"blockExoticSubdeps",
|
|
@@ -40043,11 +40042,12 @@ const stripInlineComment = (rawValue) => {
|
|
|
40043
40042
|
return rawValue;
|
|
40044
40043
|
};
|
|
40045
40044
|
const unquote = (rawValue) => rawValue.replace(/^["']|["']$/g, "");
|
|
40045
|
+
const stripBom = (rawContent) => rawContent.startsWith(UTF8_BOM_CHAR) ? rawContent.slice(1) : rawContent;
|
|
40046
40046
|
const parseHardeningSettings = (content) => {
|
|
40047
40047
|
let minimumReleaseAge = null;
|
|
40048
40048
|
let blockExoticSubdeps = null;
|
|
40049
40049
|
let trustPolicy = null;
|
|
40050
|
-
const lines =
|
|
40050
|
+
const lines = stripBom(content).split(/\r?\n/);
|
|
40051
40051
|
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
40052
40052
|
const lineText = lines[lineIndex];
|
|
40053
40053
|
if (lineText === void 0) continue;
|
|
@@ -40081,7 +40081,7 @@ const isPnpmManagedProject = (rootDirectory) => {
|
|
|
40081
40081
|
const packageJsonPath = Path.join(rootDirectory, PACKAGE_JSON_FILE);
|
|
40082
40082
|
if (!isFile(packageJsonPath)) return false;
|
|
40083
40083
|
try {
|
|
40084
|
-
const packageJsonRaw =
|
|
40084
|
+
const packageJsonRaw = NFS.readFileSync(packageJsonPath, "utf-8");
|
|
40085
40085
|
const packageJson = JSON.parse(packageJsonRaw);
|
|
40086
40086
|
if (packageJson !== null && typeof packageJson === "object" && "packageManager" in packageJson && typeof packageJson.packageManager === "string" && packageJson.packageManager.startsWith("pnpm@")) return true;
|
|
40087
40087
|
} catch {
|
|
@@ -40762,7 +40762,9 @@ const setColorEnabled = (enabled) => {
|
|
|
40762
40762
|
highlighter.gray = colors.gray;
|
|
40763
40763
|
highlighter.bold = colors.bold;
|
|
40764
40764
|
};
|
|
40765
|
-
const
|
|
40765
|
+
const NEXT_ENTRY_FILE_PATTERN = /^(?:\.\/)?(?:src\/)?(?:middleware|proxy)\.(?:tsx?|jsx?|mts|mjs)$/;
|
|
40766
|
+
const shouldIncludeExplicitLintPath = (filePath, project) => JSX_FILE_PATTERN.test(filePath) || project?.framework === "nextjs" && NEXT_ENTRY_FILE_PATTERN.test(filePath);
|
|
40767
|
+
const computeExplicitLintIncludePaths = (includePaths, project) => includePaths.length > 0 ? includePaths.filter((filePath) => shouldIncludeExplicitLintPath(filePath, project)) : void 0;
|
|
40766
40768
|
const LINGUIST_ATTRIBUTE_PATTERN = /^linguist-(?:vendored|generated)(?:=([a-zA-Z0-9]+))?$/i;
|
|
40767
40769
|
const FALSY_VALUES = new Set([
|
|
40768
40770
|
"false",
|
|
@@ -41601,11 +41603,11 @@ const resolveDeadCodeTimeout = (input) => {
|
|
|
41601
41603
|
phaseTimeoutMs: workerTimeoutMs + DEAD_CODE_PHASE_TIMEOUT_OVER_WORKER_MS
|
|
41602
41604
|
};
|
|
41603
41605
|
};
|
|
41604
|
-
const resolveLintIncludePaths = (rootDirectory, userConfig) => {
|
|
41606
|
+
const resolveLintIncludePaths = (rootDirectory, userConfig, project) => {
|
|
41605
41607
|
if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) return;
|
|
41606
41608
|
const ignoredPatterns = compileIgnoredFilePatterns(userConfig);
|
|
41607
41609
|
return listSourceFiles(rootDirectory).filter((filePath) => {
|
|
41608
|
-
if (!
|
|
41610
|
+
if (!shouldIncludeExplicitLintPath(filePath, project)) return false;
|
|
41609
41611
|
return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);
|
|
41610
41612
|
});
|
|
41611
41613
|
};
|
|
@@ -41823,7 +41825,6 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
41823
41825
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
41824
41826
|
};
|
|
41825
41827
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
41826
|
-
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
41827
41828
|
/**
|
|
41828
41829
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
41829
41830
|
* behind a `Context.Service`. The production layer (`layerNode`)
|
|
@@ -41894,14 +41895,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
41894
41895
|
args,
|
|
41895
41896
|
directory
|
|
41896
41897
|
});
|
|
41897
|
-
const listUntrackedFilePaths = (directory, includePaths = []) => runGit(directory, [
|
|
41898
|
-
"ls-files",
|
|
41899
|
-
"-z",
|
|
41900
|
-
"--others",
|
|
41901
|
-
"--exclude-standard",
|
|
41902
|
-
...includePaths.length > 0 ? ["--", ...includePaths] : []
|
|
41903
|
-
]).pipe(map$3((result) => result.status === 0 ? splitNullSeparated(result.stdout) : null));
|
|
41904
|
-
const mergeUntracked = (directory, trackedFilePaths, includeUntracked) => includeUntracked ? listUntrackedFilePaths(directory).pipe(map$3((untracked) => untracked === null ? trackedFilePaths : [...new Set([...trackedFilePaths, ...untracked])])) : succeed$2(trackedFilePaths);
|
|
41905
41898
|
const currentBranch = (directory) => runGit(directory, [
|
|
41906
41899
|
"rev-parse",
|
|
41907
41900
|
"--abbrev-ref",
|
|
@@ -42024,7 +42017,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42024
42017
|
githubViewerPermission,
|
|
42025
42018
|
branchExists,
|
|
42026
42019
|
mergeBase,
|
|
42027
|
-
diffSelection: ({ directory, explicitBaseBranch
|
|
42020
|
+
diffSelection: ({ directory, explicitBaseBranch }) => gen(function* () {
|
|
42028
42021
|
if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
|
|
42029
42022
|
if (explicitBaseBranch !== void 0) {
|
|
42030
42023
|
const range = parseGitDiffRange(explicitBaseBranch);
|
|
@@ -42053,7 +42046,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42053
42046
|
"HEAD"
|
|
42054
42047
|
]);
|
|
42055
42048
|
if (uncommitted.status !== 0) return null;
|
|
42056
|
-
const files =
|
|
42049
|
+
const files = splitNullSeparated(uncommitted.stdout);
|
|
42057
42050
|
if (files.length === 0) return null;
|
|
42058
42051
|
return {
|
|
42059
42052
|
currentBranch: resolvedCurrentBranch,
|
|
@@ -42083,7 +42076,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42083
42076
|
currentBranch: resolvedCurrentBranch,
|
|
42084
42077
|
baseBranch,
|
|
42085
42078
|
diffBaseRef: mergeBaseRef,
|
|
42086
|
-
changedFiles:
|
|
42079
|
+
changedFiles: splitNullSeparated(diff.stdout),
|
|
42087
42080
|
isCurrentChanges: false
|
|
42088
42081
|
};
|
|
42089
42082
|
}).pipe(withSpan("Git.diffSelection")),
|
|
@@ -42129,7 +42122,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42129
42122
|
stdout: result.stdout
|
|
42130
42123
|
};
|
|
42131
42124
|
}).pipe(withSpan("Git.grep")),
|
|
42132
|
-
changedLineRanges: ({ directory, baseRef, cached, files
|
|
42125
|
+
changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
|
|
42133
42126
|
if (files.length === 0) return [];
|
|
42134
42127
|
if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
|
|
42135
42128
|
const result = yield* runGit(directory, [
|
|
@@ -42143,14 +42136,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42143
42136
|
...files
|
|
42144
42137
|
]);
|
|
42145
42138
|
if (result.status !== 0) return null;
|
|
42146
|
-
|
|
42147
|
-
if (cached || !includeUntracked) return changedLineRanges;
|
|
42148
|
-
const untrackedFilePaths = yield* listUntrackedFilePaths(directory, files);
|
|
42149
|
-
if (untrackedFilePaths === null) return changedLineRanges;
|
|
42150
|
-
return [...changedLineRanges, ...untrackedFilePaths.map((file) => ({
|
|
42151
|
-
file,
|
|
42152
|
-
ranges: [[1, UNTRACKED_FILE_LAST_LINE]]
|
|
42153
|
-
}))];
|
|
42139
|
+
return parseChangedLineRanges(result.stdout);
|
|
42154
42140
|
}).pipe(catch_$1((error) => error.reason._tag === "GitInvocationFailed" ? succeed$2(null) : fail$4(error)), withSpan("Git.changedLineRanges"))
|
|
42155
42141
|
});
|
|
42156
42142
|
})).pipe(provide$2(layer$3.pipe(provide$2(mergeAll$1(layer$2, layer$1)))));
|
|
@@ -42902,12 +42888,6 @@ const mapWithConcurrency = async (items, concurrency, task) => {
|
|
|
42902
42888
|
if (errors.length > 0) throw errors[0];
|
|
42903
42889
|
return results;
|
|
42904
42890
|
};
|
|
42905
|
-
const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
|
|
42906
|
-
let lineNumber = 1;
|
|
42907
|
-
const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
|
|
42908
|
-
for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === 10) lineNumber++;
|
|
42909
|
-
return lineNumber;
|
|
42910
|
-
};
|
|
42911
42891
|
const REANIMATED_SHARED_VALUE_HINT = "If this is a Reanimated shared value, prefer its React Compiler-compatible `.get()` / `.set()` accessors over `.value` — https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue/#react-compiler-support";
|
|
42912
42892
|
const ACCESSORS_MIN_VERSION = "3.15.0";
|
|
42913
42893
|
const supportsAccessors = (reanimatedVersion) => {
|
|
@@ -43479,6 +43459,13 @@ const findOutermostEnclosingFunctionRange = (sourceFile, targetLine) => {
|
|
|
43479
43459
|
visit(sourceFile);
|
|
43480
43460
|
return foundRange;
|
|
43481
43461
|
};
|
|
43462
|
+
const NEWLINE_BYTE = 10;
|
|
43463
|
+
const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
|
|
43464
|
+
let lineNumber = 1;
|
|
43465
|
+
const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
|
|
43466
|
+
for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === NEWLINE_BYTE) lineNumber++;
|
|
43467
|
+
return lineNumber;
|
|
43468
|
+
};
|
|
43482
43469
|
/**
|
|
43483
43470
|
* Drops `react-doctor/react-compiler-no-manual-memoization` diagnostics
|
|
43484
43471
|
* whose enclosing function also carries a `react-hooks-js` (React
|
|
@@ -43659,11 +43646,11 @@ const buildRelatedLocations = (labels, filePath) => {
|
|
|
43659
43646
|
}
|
|
43660
43647
|
return related;
|
|
43661
43648
|
};
|
|
43662
|
-
const
|
|
43663
|
-
|
|
43664
|
-
const
|
|
43665
|
-
|
|
43666
|
-
|
|
43649
|
+
const isOxlintOutput = (value) => {
|
|
43650
|
+
if (typeof value !== "object" || value === null) return false;
|
|
43651
|
+
const candidate = value;
|
|
43652
|
+
return Array.isArray(candidate.diagnostics);
|
|
43653
|
+
};
|
|
43667
43654
|
/**
|
|
43668
43655
|
* Parses one oxlint subprocess's stdout into a flat `Diagnostic[]`.
|
|
43669
43656
|
* Tolerates the leading-notice-line shape oxlint sometimes prints
|
|
@@ -43682,59 +43669,23 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
43682
43669
|
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
43683
43670
|
}
|
|
43684
43671
|
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
43685
|
-
const engineFailureDiagnostic = parsed.diagnostics.find(isEngineFailureDiagnostic);
|
|
43686
|
-
if (engineFailureDiagnostic !== void 0) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: JSON.stringify(engineFailureDiagnostic).slice(0, 600) }) });
|
|
43687
43672
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
43688
|
-
const sourceBufferCache = /* @__PURE__ */ new Map();
|
|
43689
|
-
const sourceLinesCache = /* @__PURE__ */ new Map();
|
|
43690
|
-
const resolveAbsolutePath = (filename) => Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
43691
|
-
const readSourceBuffer = (filename) => {
|
|
43692
|
-
const absolutePath = resolveAbsolutePath(filename);
|
|
43693
|
-
const cached = sourceBufferCache.get(absolutePath);
|
|
43694
|
-
if (cached !== void 0) return cached;
|
|
43695
|
-
let sourceBuffer;
|
|
43696
|
-
try {
|
|
43697
|
-
sourceBuffer = NFS.readFileSync(absolutePath);
|
|
43698
|
-
} catch {
|
|
43699
|
-
sourceBuffer = null;
|
|
43700
|
-
}
|
|
43701
|
-
sourceBufferCache.set(absolutePath, sourceBuffer);
|
|
43702
|
-
return sourceBuffer;
|
|
43703
|
-
};
|
|
43704
|
-
const readSourceLines = (filename) => {
|
|
43705
|
-
const absolutePath = resolveAbsolutePath(filename);
|
|
43706
|
-
const cached = sourceLinesCache.get(absolutePath);
|
|
43707
|
-
if (cached !== void 0) return cached;
|
|
43708
|
-
const sourceBuffer = readSourceBuffer(filename);
|
|
43709
|
-
const sourceLines = sourceBuffer ? sourceBuffer.toString("utf8").split("\n") : null;
|
|
43710
|
-
sourceLinesCache.set(absolutePath, sourceLines);
|
|
43711
|
-
return sourceLines;
|
|
43712
|
-
};
|
|
43713
43673
|
const isMinifiedDiagnosticFile = (filename) => {
|
|
43714
|
-
const absolutePath =
|
|
43674
|
+
const absolutePath = Path.isAbsolute(filename) ? filename : Path.resolve(rootDirectory || ".", filename);
|
|
43715
43675
|
const cached = minifiedFileCache.get(absolutePath);
|
|
43716
43676
|
if (cached !== void 0) return cached;
|
|
43717
43677
|
const minified = isMinifiedSource(absolutePath);
|
|
43718
43678
|
minifiedFileCache.set(absolutePath, minified);
|
|
43719
43679
|
return minified;
|
|
43720
43680
|
};
|
|
43721
|
-
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) =>
|
|
43681
|
+
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
43722
43682
|
const { plugin, rule } = parseRuleCode(diagnostic.code);
|
|
43723
43683
|
const primaryLabel = diagnostic.labels[0];
|
|
43724
43684
|
const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
|
|
43725
43685
|
const normalizedFilePath = diagnostic.filename.replaceAll("\\", "/");
|
|
43726
43686
|
const primarySpan = primaryLabel?.span;
|
|
43727
|
-
const sourceBuffer = primarySpan ? readSourceBuffer(diagnostic.filename) : null;
|
|
43728
43687
|
const relatedLocations = buildRelatedLocations(diagnostic.labels, normalizedFilePath);
|
|
43729
43688
|
const category = resolveDiagnosticCategory(plugin, rule);
|
|
43730
|
-
const matchByOccurrence = resolveMatchByOccurrence(rule, category);
|
|
43731
|
-
const sourceLines = primarySpan ? readSourceLines(diagnostic.filename) : null;
|
|
43732
|
-
const primaryLineIndex = primarySpan ? primarySpan.line - 1 : -1;
|
|
43733
|
-
const primaryLine = sourceLines?.[primaryLineIndex];
|
|
43734
|
-
const primaryColumnIndex = primarySpan ? primarySpan.column - 1 : -1;
|
|
43735
|
-
const isJsxTagLabel = primaryLine !== void 0 && primaryColumnIndex >= 0 && (primaryLine[primaryColumnIndex] === "<" || primaryLine[primaryColumnIndex - 1] === "<");
|
|
43736
|
-
const jsxOpenerEndLineIndex = sourceLines && isJsxTagLabel ? findJsxOpenerSpan(sourceLines, primaryLineIndex) : null;
|
|
43737
|
-
const primarySpanEndLine = jsxOpenerEndLineIndex !== null ? jsxOpenerEndLineIndex + 1 : primarySpan && sourceBuffer ? lineOfUtf8Offset(sourceBuffer, primarySpan.offset + Math.max(primarySpan.length - 1, 0)) : void 0;
|
|
43738
43689
|
return {
|
|
43739
43690
|
filePath: normalizedFilePath,
|
|
43740
43691
|
plugin,
|
|
@@ -43748,11 +43699,10 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
43748
43699
|
column: primarySpan?.column ?? 0,
|
|
43749
43700
|
...primarySpan ? {
|
|
43750
43701
|
offset: primarySpan.offset,
|
|
43751
|
-
length: primarySpan.length
|
|
43752
|
-
...primarySpanEndLine !== void 0 ? { endLine: primarySpanEndLine } : {}
|
|
43702
|
+
length: primarySpan.length
|
|
43753
43703
|
} : {},
|
|
43754
43704
|
category,
|
|
43755
|
-
...
|
|
43705
|
+
...resolveMatchByOccurrence(rule, category) ? { matchByOccurrence: true } : {},
|
|
43756
43706
|
...relatedLocations.length > 0 ? { relatedLocations } : {}
|
|
43757
43707
|
};
|
|
43758
43708
|
}), rootDirectory);
|
|
@@ -45539,7 +45489,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
45539
45489
|
directory: scanDirectory,
|
|
45540
45490
|
repo
|
|
45541
45491
|
}).pipe(orElseSucceed(() => null)) : succeed$2(null));
|
|
45542
|
-
const lintIncludePaths = (input.
|
|
45492
|
+
const lintIncludePaths = (input.skipJsxIncludeFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths], project)) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, project);
|
|
45543
45493
|
const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
|
|
45544
45494
|
const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
|
|
45545
45495
|
const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
|
|
@@ -46284,11 +46234,10 @@ const computeDiagnosticDelta = (input) => {
|
|
|
46284
46234
|
* render diff-base mistakes (`GitBaseBranchInvalid` /
|
|
46285
46235
|
* `GitBaseBranchMissing`) as clean user errors instead of crashes.
|
|
46286
46236
|
*/
|
|
46287
|
-
const getDiffInfo = (directory, explicitBaseBranch
|
|
46237
|
+
const getDiffInfo = (directory, explicitBaseBranch) => runPromise(gen(function* () {
|
|
46288
46238
|
const selection = yield* (yield* Git).diffSelection({
|
|
46289
46239
|
directory,
|
|
46290
|
-
explicitBaseBranch
|
|
46291
|
-
includeUntracked
|
|
46240
|
+
explicitBaseBranch
|
|
46292
46241
|
});
|
|
46293
46242
|
if (selection === null) return null;
|
|
46294
46243
|
return {
|
|
@@ -46624,43 +46573,6 @@ const isNonInteractiveEnvironment = () => NON_INTERACTIVE_ENVIRONMENT_VARIABLES.
|
|
|
46624
46573
|
//#region src/cli/utils/constants.ts
|
|
46625
46574
|
const REACT_DOCTOR_CONFIG_PROJECT_NAME = "react-doctor";
|
|
46626
46575
|
const STAGED_FILES_TEMP_DIR_PREFIX = "react-doctor-staged-";
|
|
46627
|
-
const STAGED_SNAPSHOT_ADDITIONAL_CONFIG_FILENAMES = [
|
|
46628
|
-
".babelrc",
|
|
46629
|
-
".babelrc.json",
|
|
46630
|
-
".eslintignore",
|
|
46631
|
-
".eslintrc.json",
|
|
46632
|
-
".oxlintignore",
|
|
46633
|
-
"app.config.cjs",
|
|
46634
|
-
"app.config.js",
|
|
46635
|
-
"app.config.json",
|
|
46636
|
-
"app.config.mjs",
|
|
46637
|
-
"app.config.ts",
|
|
46638
|
-
"app.json",
|
|
46639
|
-
"babel.config.cjs",
|
|
46640
|
-
"babel.config.js",
|
|
46641
|
-
"babel.config.json",
|
|
46642
|
-
"babel.config.mjs",
|
|
46643
|
-
"eslint.config.cjs",
|
|
46644
|
-
"eslint.config.cts",
|
|
46645
|
-
"eslint.config.js",
|
|
46646
|
-
"eslint.config.mjs",
|
|
46647
|
-
"eslint.config.mts",
|
|
46648
|
-
"eslint.config.ts",
|
|
46649
|
-
"next.config.cjs",
|
|
46650
|
-
"next.config.js",
|
|
46651
|
-
"next.config.mjs",
|
|
46652
|
-
"next.config.ts",
|
|
46653
|
-
"oxlint.config.json",
|
|
46654
|
-
"react-doctor.config.json",
|
|
46655
|
-
"vite.config.cjs",
|
|
46656
|
-
"vite.config.cts",
|
|
46657
|
-
"vite.config.js",
|
|
46658
|
-
"vite.config.mjs",
|
|
46659
|
-
"vite.config.mts",
|
|
46660
|
-
"vite.config.ts",
|
|
46661
|
-
"vitest.config.js",
|
|
46662
|
-
"vitest.config.ts"
|
|
46663
|
-
];
|
|
46664
46576
|
const BASELINE_FILES_TEMP_DIR_PREFIX = "react-doctor-baseline-";
|
|
46665
46577
|
const SCAN_RESULT_CACHE_FILENAME = "scan-cache.json";
|
|
46666
46578
|
const RUN_GIT_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
|
|
@@ -46675,7 +46587,6 @@ const METRIC = {
|
|
|
46675
46587
|
cliInvoked: "cli.invoked",
|
|
46676
46588
|
cliError: "cli.error",
|
|
46677
46589
|
cliEnvironmentError: "cli.env_error",
|
|
46678
|
-
stagedSnapshotDivergence: "staged.snapshot_divergence",
|
|
46679
46590
|
projectDetected: "project.detected",
|
|
46680
46591
|
projectPathSelected: "project.path_selected",
|
|
46681
46592
|
projectConfigSelected: "project.config_selected",
|
|
@@ -46756,7 +46667,7 @@ const makeNoopConsole = () => ({
|
|
|
46756
46667
|
});
|
|
46757
46668
|
//#endregion
|
|
46758
46669
|
//#region src/cli/utils/version.ts
|
|
46759
|
-
const VERSION = "0.7.6-dev.
|
|
46670
|
+
const VERSION = "0.7.6-dev.0017418";
|
|
46760
46671
|
//#endregion
|
|
46761
46672
|
//#region src/cli/utils/json-mode.ts
|
|
46762
46673
|
let context = null;
|
|
@@ -47125,13 +47036,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
47125
47036
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
47126
47037
|
* standard `SENTRY_RELEASE` override.
|
|
47127
47038
|
*/
|
|
47128
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.6-dev.
|
|
47039
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.6-dev.0017418`;
|
|
47129
47040
|
/**
|
|
47130
47041
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
47131
47042
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
47132
47043
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
47133
47044
|
*/
|
|
47134
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.6-dev.
|
|
47045
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.6-dev.0017418") ? "development" : "production");
|
|
47135
47046
|
/**
|
|
47136
47047
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
47137
47048
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -47323,7 +47234,7 @@ const NON_BLOCKING_REACT_DOCTOR_COMMAND = [
|
|
|
47323
47234
|
"fi"
|
|
47324
47235
|
].join(" ");
|
|
47325
47236
|
const PACKAGE_JSON_FILE_NAME = "package.json";
|
|
47326
|
-
const
|
|
47237
|
+
const runGit = (projectRoot, args) => {
|
|
47327
47238
|
try {
|
|
47328
47239
|
return execFileSync("git", [...args], {
|
|
47329
47240
|
cwd: projectRoot,
|
|
@@ -47334,12 +47245,11 @@ const runGitRaw = (projectRoot, args) => {
|
|
|
47334
47245
|
"ignore"
|
|
47335
47246
|
],
|
|
47336
47247
|
maxBuffer: RUN_GIT_MAX_BUFFER_BYTES
|
|
47337
|
-
});
|
|
47248
|
+
}).trim();
|
|
47338
47249
|
} catch {
|
|
47339
47250
|
return null;
|
|
47340
47251
|
}
|
|
47341
47252
|
};
|
|
47342
|
-
const runGit = (projectRoot, args) => runGitRaw(projectRoot, args)?.trim() ?? null;
|
|
47343
47253
|
const resolveGitPath = (baseDirectory, value) => Path.isAbsolute(value) ? value : Path.resolve(baseDirectory, value);
|
|
47344
47254
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
47345
47255
|
const getPackageJsonPath = (projectRoot) => Path.join(projectRoot, PACKAGE_JSON_FILE_NAME);
|
|
@@ -50897,7 +50807,7 @@ const BLOCKING_SUMMARY = {
|
|
|
50897
50807
|
const SCOPE_SUMMARY = {
|
|
50898
50808
|
full: "Scan the whole project on every run",
|
|
50899
50809
|
files: "Report every issue in changed files",
|
|
50900
|
-
lines: "Report issues
|
|
50810
|
+
lines: "Report issues on changed lines",
|
|
50901
50811
|
changed: "Report only the issues a change introduces"
|
|
50902
50812
|
};
|
|
50903
50813
|
const gatesEqual = (left, right) => left.blocking === right.blocking && left.scope === right.scope && left.comment === right.comment && left.reviewComments === right.reviewComments && left.commitStatus === right.commitStatus;
|
|
@@ -59210,17 +59120,6 @@ const buildRuleBlastRadii = (diagnostics) => buildSortedRuleGroups(diagnostics).
|
|
|
59210
59120
|
})).toSorted((left, right) => right.fileCount - left.fileCount);
|
|
59211
59121
|
const findMigrationScaleBuckets = (diagnostics) => buildRuleBlastRadii(diagnostics).filter((bucket) => bucket.fileCount >= 40);
|
|
59212
59122
|
//#endregion
|
|
59213
|
-
//#region src/cli/utils/has-lint-hard-failure.ts
|
|
59214
|
-
const hasLintHardFailure = (result) => result.skippedChecks.includes("lint");
|
|
59215
|
-
//#endregion
|
|
59216
|
-
//#region src/cli/utils/is-inspect-result-complete.ts
|
|
59217
|
-
const isInspectResultComplete = (result) => isScanComplete({
|
|
59218
|
-
analyzedFileCount: result.analyzedFiles?.length,
|
|
59219
|
-
scannedFileCount: result.scannedFileCount,
|
|
59220
|
-
skippedCheckCount: result.skippedChecks.length,
|
|
59221
|
-
skippedCheckReasonCount: Object.keys(result.skippedCheckReasons ?? {}).length
|
|
59222
|
-
});
|
|
59223
|
-
//#endregion
|
|
59224
59123
|
//#region src/cli/utils/scan-result-cache.ts
|
|
59225
59124
|
const CACHE_DISABLED_VALUES = new Set(["1", "true"]);
|
|
59226
59125
|
const TOOLCHAIN_PACKAGE_SPECIFIERS = [
|
|
@@ -59303,7 +59202,7 @@ const buildDirtyPathContentFingerprint = (absolutePath, statusCode) => {
|
|
|
59303
59202
|
return null;
|
|
59304
59203
|
}
|
|
59305
59204
|
if (!stats.isFile()) return null;
|
|
59306
|
-
if (stats.size > 10485760) return
|
|
59205
|
+
if (stats.size > 10485760) return `stat:${stats.mtimeMs}:${stats.size}`;
|
|
59307
59206
|
return hashFileContents(absolutePath);
|
|
59308
59207
|
};
|
|
59309
59208
|
const buildWorktreeFingerprint = (projectDirectory) => {
|
|
@@ -59626,12 +59525,15 @@ const buildOutcomeAttributes = (input) => {
|
|
|
59626
59525
|
const summary = summarizeDiagnostics(result.diagnostics);
|
|
59627
59526
|
const blockingLevel = resolveTelemetryBlocking(input.userConfig);
|
|
59628
59527
|
const gateDiagnostics = filterDiagnosticsForSurface(result.diagnostics, "ciFailure", input.userConfig);
|
|
59629
|
-
const complete = isInspectResultComplete(result);
|
|
59630
|
-
const didLintHardFail = hasLintHardFailure(result);
|
|
59631
|
-
const failsOnHardFailure = didLintHardFail && blockingLevel !== "none";
|
|
59632
59528
|
const wouldBlock = !input.scoreOnly && !input.gateExempt && shouldBlockCi(gateDiagnostics, blockingLevel);
|
|
59529
|
+
const complete = isScanComplete({
|
|
59530
|
+
analyzedFileCount: result.analyzedFiles?.length,
|
|
59531
|
+
scannedFileCount: result.scannedFileCount,
|
|
59532
|
+
skippedCheckCount: result.skippedChecks.length,
|
|
59533
|
+
skippedCheckReasonCount: Object.keys(result.skippedCheckReasons ?? {}).length
|
|
59534
|
+
});
|
|
59633
59535
|
const isClean = result.diagnostics.length === 0 && complete;
|
|
59634
|
-
const outcome =
|
|
59536
|
+
const outcome = wouldBlock ? "blocked" : isClean ? "clean" : "ok";
|
|
59635
59537
|
const firings = summarizeRuleFirings(result.diagnostics);
|
|
59636
59538
|
const countByRule = /* @__PURE__ */ new Map();
|
|
59637
59539
|
const countByCategory = /* @__PURE__ */ new Map();
|
|
@@ -59676,7 +59578,7 @@ const buildOutcomeAttributes = (input) => {
|
|
|
59676
59578
|
const attributes = {
|
|
59677
59579
|
...withNamespace("outcome", {
|
|
59678
59580
|
status: outcome,
|
|
59679
|
-
exitCode:
|
|
59581
|
+
exitCode: wouldBlock ? 1 : 0,
|
|
59680
59582
|
wouldBlock,
|
|
59681
59583
|
blocking: blockingLevel,
|
|
59682
59584
|
clean: isClean,
|
|
@@ -59774,9 +59676,7 @@ const buildScanAttributes = (input) => {
|
|
|
59774
59676
|
hasCustomConfig: input.hasCustomConfig,
|
|
59775
59677
|
rulesConfigured: ruleKeys.length,
|
|
59776
59678
|
rulesDisabled: ruleKeys.filter((key) => ruleOverrides[key] === "off").length,
|
|
59777
|
-
fileCount: input.result?.scannedFileCount ?? null
|
|
59778
|
-
nonJsxFileCount: input.result?.analyzedFiles?.filter((filePath) => !JSX_FILE_PATTERN.test(filePath)).length ?? null,
|
|
59779
|
-
multilineDiagnosticCount: input.result?.diagnostics.filter((diagnostic) => (diagnostic.endLine ?? diagnostic.line) > diagnostic.line).length ?? null
|
|
59679
|
+
fileCount: input.result?.scannedFileCount ?? null
|
|
59780
59680
|
});
|
|
59781
59681
|
};
|
|
59782
59682
|
/**
|
|
@@ -59845,12 +59745,6 @@ const countDeadlineSkippedFiles = (lintPartialFailures) => sumFileCountsMatching
|
|
|
59845
59745
|
const DROPPED_FILES_MESSAGE_PATTERN = /^(\d+) file\(s\) failed to lint and were skipped/;
|
|
59846
59746
|
const countDroppedLintFiles = (lintPartialFailures) => sumFileCountsMatching(lintPartialFailures, DROPPED_FILES_MESSAGE_PATTERN);
|
|
59847
59747
|
//#endregion
|
|
59848
|
-
//#region src/cli/utils/diagnostic-intersects-line-ranges.ts
|
|
59849
|
-
const diagnosticIntersectsLineRanges = (diagnostic, lineRanges) => {
|
|
59850
|
-
const diagnosticEndLine = Math.max(diagnostic.line, diagnostic.endLine ?? diagnostic.line);
|
|
59851
|
-
return lineRanges.some(([rangeStartLine, rangeEndLine]) => diagnostic.line <= rangeEndLine && diagnosticEndLine >= rangeStartLine);
|
|
59852
|
-
};
|
|
59853
|
-
//#endregion
|
|
59854
59748
|
//#region src/cli/utils/materialize-baseline-files.ts
|
|
59855
59749
|
/**
|
|
59856
59750
|
* Materializes the `ref` version of `files` into `tempDirectory` (via
|
|
@@ -61036,7 +60930,7 @@ const buildChangedLineMatcher = (directory, changedLineRanges) => {
|
|
|
61036
60930
|
const relativePath = toForwardSlashes(path.isAbsolute(diagnostic.filePath) ? path.relative(directory, diagnostic.filePath) : diagnostic.filePath);
|
|
61037
60931
|
const ranges = rangesByFile.get(relativePath);
|
|
61038
60932
|
if (ranges === void 0) return false;
|
|
61039
|
-
return
|
|
60933
|
+
return ranges.some(([start, end]) => diagnostic.line >= start && diagnostic.line <= end);
|
|
61040
60934
|
};
|
|
61041
60935
|
};
|
|
61042
60936
|
const buildIgnoredTags = (userConfig) => {
|
|
@@ -63858,15 +63752,10 @@ const warnIfAiTrainingEnvironment = () => {
|
|
|
63858
63752
|
//#region src/cli/utils/validate-mode-flags.ts
|
|
63859
63753
|
const usedDiffAlias = (flags) => flags.diff !== void 0 && flags.diff !== false && flags.diff !== "false" && flags.diff !== "";
|
|
63860
63754
|
const usedScope = (flags) => typeof flags.scope === "string" && flags.scope.length > 0;
|
|
63861
|
-
const validateIncludeUntrackedScope = (includeUntracked, scope) => {
|
|
63862
|
-
if (!includeUntracked || scope !== void 0 && scope !== "full") return;
|
|
63863
|
-
throw new CliInputError("--include-untracked requires the files, changed, or lines scope (via --scope, --diff, or config).");
|
|
63864
|
-
};
|
|
63865
63755
|
const validateModeFlags = (flags) => {
|
|
63866
63756
|
if (usedScope(flags) && usedDiffAlias(flags)) throw new CliInputError("Cannot combine --scope and --diff; --diff is the deprecated alias.");
|
|
63867
63757
|
if (flags.staged && usedDiffAlias(flags)) throw new CliInputError("Cannot combine --staged and --diff; pick one mode.");
|
|
63868
63758
|
if (flags.staged && (flags.scope === "full" || flags.scope === "changed")) throw new CliInputError(`Cannot combine --staged with --scope ${flags.scope}; use --scope files or --scope lines, or drop --scope.`);
|
|
63869
|
-
if (flags.includeUntracked && flags.staged) throw new CliInputError("Cannot combine --include-untracked with --staged; the git index never holds untracked files.");
|
|
63870
63759
|
if (flags.score && flags.json) throw new CliInputError("Cannot combine --score and --json; pick one output mode.");
|
|
63871
63760
|
if (flags.score && flags.telemetry === false) throw new CliInputError("Cannot combine --score with --no-telemetry; --score prints the score that --no-telemetry disables.");
|
|
63872
63761
|
if (flags.debug && (flags.score === false || flags.telemetry === false)) {
|
|
@@ -63875,39 +63764,6 @@ const validateModeFlags = (flags) => {
|
|
|
63875
63764
|
}
|
|
63876
63765
|
};
|
|
63877
63766
|
//#endregion
|
|
63878
|
-
//#region src/cli/utils/parse-staged-snapshot-divergences.ts
|
|
63879
|
-
const SNAPSHOT_CONFIG_FILENAMES = new Set([...STAGED_FILES_PROJECT_CONFIG_FILENAMES, ...STAGED_SNAPSHOT_ADDITIONAL_CONFIG_FILENAMES]);
|
|
63880
|
-
const parseStagedSnapshotDivergences = (statusOutput) => {
|
|
63881
|
-
const divergentConfigFiles = /* @__PURE__ */ new Set();
|
|
63882
|
-
const statusEntries = statusOutput.split("\0").filter((entry) => entry.length > 0);
|
|
63883
|
-
for (let entryIndex = 0; entryIndex < statusEntries.length; entryIndex += 1) {
|
|
63884
|
-
const entry = statusEntries[entryIndex];
|
|
63885
|
-
const [indexStatus, worktreeStatus] = entry;
|
|
63886
|
-
const filePath = entry.slice(3);
|
|
63887
|
-
const hasRenameOrCopySource = indexStatus === "R" || indexStatus === "C" || worktreeStatus === "R" || worktreeStatus === "C";
|
|
63888
|
-
const sourcePath = hasRenameOrCopySource ? statusEntries[entryIndex + 1] : void 0;
|
|
63889
|
-
const worktreePaths = worktreeStatus === "R" || worktreeStatus === "C" ? [filePath, sourcePath] : [filePath];
|
|
63890
|
-
if (worktreeStatus !== " ") {
|
|
63891
|
-
for (const worktreePath of worktreePaths) if (worktreePath && SNAPSHOT_CONFIG_FILENAMES.has(Path.basename(worktreePath))) divergentConfigFiles.add(worktreePath);
|
|
63892
|
-
}
|
|
63893
|
-
if (hasRenameOrCopySource) entryIndex += 1;
|
|
63894
|
-
}
|
|
63895
|
-
return [...divergentConfigFiles].sort();
|
|
63896
|
-
};
|
|
63897
|
-
//#endregion
|
|
63898
|
-
//#region src/cli/utils/find-staged-snapshot-divergences.ts
|
|
63899
|
-
const findStagedSnapshotDivergences = (directory) => {
|
|
63900
|
-
const statusOutput = runGitRaw(directory, [
|
|
63901
|
-
"status",
|
|
63902
|
-
"--porcelain=v1",
|
|
63903
|
-
"-z",
|
|
63904
|
-
"--untracked-files=all",
|
|
63905
|
-
"--ignored=matching"
|
|
63906
|
-
]);
|
|
63907
|
-
if (statusOutput === null) return null;
|
|
63908
|
-
return parseStagedSnapshotDivergences(statusOutput);
|
|
63909
|
-
};
|
|
63910
|
-
//#endregion
|
|
63911
63767
|
//#region src/cli/commands/inspect.ts
|
|
63912
63768
|
const filterCompletedScansByCategories = (completedScans, categoryFilters) => {
|
|
63913
63769
|
if (categoryFilters.size === 0) return [...completedScans];
|
|
@@ -63922,14 +63778,9 @@ const filterCompletedScansByCategories = (completedScans, categoryFilters) => {
|
|
|
63922
63778
|
/**
|
|
63923
63779
|
* Post-scan finalization shared by the staged-arm and project-loop
|
|
63924
63780
|
* paths of `inspectAction`: emit the JSON report (when in JSON mode)
|
|
63925
|
-
* and set `process.exitCode = 1` when
|
|
63926
|
-
* (
|
|
63927
|
-
*
|
|
63928
|
-
* threshold (default `"error"`) reaches the `ciFailure` surface.
|
|
63929
|
-
* `--blocking none` keeps the scan advisory (always exits 0), and
|
|
63930
|
-
* fail-open degradations — `--no-lint`, `--max-duration` truncation,
|
|
63931
|
-
* supply-chain/security skips — stay advisory too, surfaced through
|
|
63932
|
-
* `complete: false` in the JSON report.
|
|
63781
|
+
* and set `process.exitCode = 1` when a diagnostic at or above the
|
|
63782
|
+
* `--blocking` threshold (default `"error"`) reaches the `ciFailure`
|
|
63783
|
+
* surface. `--blocking none` keeps the scan advisory (always exits 0).
|
|
63933
63784
|
*/
|
|
63934
63785
|
const finalizeScans = (input) => {
|
|
63935
63786
|
const baselineDeltas = input.completedScans.flatMap((scan) => scan.result.baselineDelta ? [scan.result.baselineDelta] : []);
|
|
@@ -63959,13 +63810,8 @@ const finalizeScans = (input) => {
|
|
|
63959
63810
|
baselineDegraded
|
|
63960
63811
|
}));
|
|
63961
63812
|
}
|
|
63962
|
-
const blockingLevel = resolveBlockingLevel(input.flags, input.userConfig);
|
|
63963
|
-
if (input.completedScans.some(({ result }) => hasLintHardFailure(result)) && blockingLevel !== "none") {
|
|
63964
|
-
process.exitCode = 1;
|
|
63965
|
-
return;
|
|
63966
|
-
}
|
|
63967
63813
|
if (input.isScoreOnly || baselineDegraded) return;
|
|
63968
|
-
if (shouldBlockCi(filterScansForSurface(input.completedScans, "ciFailure"),
|
|
63814
|
+
if (shouldBlockCi(filterScansForSurface(input.completedScans, "ciFailure"), resolveBlockingLevel(input.flags, input.userConfig))) process.exitCode = 1;
|
|
63969
63815
|
};
|
|
63970
63816
|
const buildChangedFilesDiffInfo = (changedFiles) => ({
|
|
63971
63817
|
currentBranch: process.env.GITHUB_HEAD_REF?.trim() || null,
|
|
@@ -64003,7 +63849,6 @@ const inspectAction = async (directory, flags) => {
|
|
|
64003
63849
|
recordCount(METRIC.cliInvoked, 1, { command: "inspect" });
|
|
64004
63850
|
try {
|
|
64005
63851
|
validateModeFlags(flags);
|
|
64006
|
-
if (flags.staged) setJsonReportMode("staged");
|
|
64007
63852
|
await maybeMigrateLegacyConfig(requestedDirectory, {
|
|
64008
63853
|
isQuiet,
|
|
64009
63854
|
isStaged: Boolean(flags.staged)
|
|
@@ -64019,14 +63864,6 @@ const inspectAction = async (directory, flags) => {
|
|
|
64019
63864
|
cliLogger.dim(`Redirected to ${highlighter.info(toRelativePath(resolvedDirectory, requestedDirectory))} via react-doctor config "rootDir".`);
|
|
64020
63865
|
cliLogger.break();
|
|
64021
63866
|
}
|
|
64022
|
-
if (flags.staged) {
|
|
64023
|
-
const divergentConfigFiles = findStagedSnapshotDivergences(resolvedDirectory);
|
|
64024
|
-
if (divergentConfigFiles === null) throw new CliInputError("Could not verify that staged configuration matches the worktree. Run the command from a Git worktree with Git available.");
|
|
64025
|
-
if (divergentConfigFiles.length > 0) {
|
|
64026
|
-
recordCount(METRIC.stagedSnapshotDivergence, 1, { divergentInputCount: divergentConfigFiles.length });
|
|
64027
|
-
throw new CliInputError(`Cannot scan staged files while configuration differs between the index and worktree: ${divergentConfigFiles.join(", ")}. Stage or restore those files, then rerun react-doctor --staged.`);
|
|
64028
|
-
}
|
|
64029
|
-
}
|
|
64030
63867
|
const explainArgument = flags.explain;
|
|
64031
63868
|
if (explainArgument !== void 0) {
|
|
64032
63869
|
await runExplain(explainArgument, {
|
|
@@ -64047,6 +63884,7 @@ const inspectAction = async (directory, flags) => {
|
|
|
64047
63884
|
json: flags.json
|
|
64048
63885
|
});
|
|
64049
63886
|
if (flags.staged) {
|
|
63887
|
+
setJsonReportMode("staged");
|
|
64050
63888
|
const stagedFiles = await getStagedSourceFiles(resolvedDirectory);
|
|
64051
63889
|
if (stagedFiles.length === 0) {
|
|
64052
63890
|
if (isJsonMode) writeJsonReport(buildJsonReport({
|
|
@@ -64127,15 +63965,13 @@ const inspectAction = async (directory, flags) => {
|
|
|
64127
63965
|
const projectDirectories = await selectProjects(resolvedDirectory, flags.project, skipPrompts, userConfig?.projects);
|
|
64128
63966
|
const changedFilesDiffInfo = flags.changedFilesFrom ? buildChangedFilesDiffInfo(readChangedFilesFrom(Path.resolve(flags.changedFilesFrom))) : null;
|
|
64129
63967
|
const requestedScope = resolveScope(flags, userConfig);
|
|
64130
|
-
const includeUntracked = flags.includeUntracked ?? false;
|
|
64131
63968
|
const scopeRequest = requestedScope.scope === void 0 && changedFilesDiffInfo !== null ? {
|
|
64132
63969
|
...requestedScope,
|
|
64133
63970
|
scope: "changed"
|
|
64134
63971
|
} : requestedScope;
|
|
64135
|
-
validateIncludeUntrackedScope(includeUntracked, scopeRequest.scope);
|
|
64136
63972
|
const wantsDiffMode = scopeRequest.scope !== void 0 && scopeRequest.scope !== "full";
|
|
64137
63973
|
const shouldDetectDiff = changedFilesDiffInfo === null && (wantsDiffMode || scopeRequest.scope === void 0 && !skipPrompts && !isQuiet);
|
|
64138
|
-
const diffInfo = changedFilesDiffInfo ?? (shouldDetectDiff ? await getDiffInfo(resolvedDirectory, scopeRequest.base
|
|
63974
|
+
const diffInfo = changedFilesDiffInfo ?? (shouldDetectDiff ? await getDiffInfo(resolvedDirectory, scopeRequest.base) : null);
|
|
64139
63975
|
const scope = await finalizeScope({
|
|
64140
63976
|
requested: scopeRequest,
|
|
64141
63977
|
diffInfo,
|
|
@@ -64149,8 +63985,7 @@ const inspectAction = async (directory, flags) => {
|
|
|
64149
63985
|
const changedLineRanges = scope === "lines" && diffInfo !== null && (diffInfo.isCurrentChanges || linesBaseRef !== null) && diffInfo !== null ? await getChangedLineRanges({
|
|
64150
63986
|
directory: resolvedDirectory,
|
|
64151
63987
|
baseRef: linesBaseRef ?? void 0,
|
|
64152
|
-
files: [...diffInfo.changedFiles]
|
|
64153
|
-
includeUntracked
|
|
63988
|
+
files: [...diffInfo.changedFiles]
|
|
64154
63989
|
}) : null;
|
|
64155
63990
|
if (scope === "lines" && changedLineRanges === null && !isQuiet) {
|
|
64156
63991
|
cliLogger.warn("Could not determine changed lines (no base ref or git diff failed); reporting all issues in changed files.");
|
|
@@ -65083,7 +64918,6 @@ const ROOT_FLAG_SPEC = {
|
|
|
65083
64918
|
"--dead-code",
|
|
65084
64919
|
"--debug",
|
|
65085
64920
|
"--help",
|
|
65086
|
-
"--include-untracked",
|
|
65087
64921
|
"--json",
|
|
65088
64922
|
"--json-compact",
|
|
65089
64923
|
"--lint",
|
|
@@ -65347,7 +65181,7 @@ ${highlighter.dim("Learn more:")}
|
|
|
65347
65181
|
${highlighter.info(CI_URL)}
|
|
65348
65182
|
`;
|
|
65349
65183
|
const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
|
|
65350
|
-
const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much
|
|
65184
|
+
const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much to scan/report: full (default), files, changed (only new issues vs base), or lines (only changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
|
|
65351
65185
|
program.action(inspectAction);
|
|
65352
65186
|
program.command("why <location>").description("Explain why a rule fired (or why a suppression didn't apply) at a file:line").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple)").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").action((location, options) => whyAction(location, options));
|
|
65353
65187
|
program.command("install").alias("setup").description("Install the react-doctor skill into your coding agents and optional git hook").option("-y, --yes", "skip prompts, install for all detected agents").option("--dry-run", "show what would be installed without writing files").option("--agent-hooks", "install native non-blocking agent hooks for Claude Code and Cursor").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderInstallHelpEpilog).action(installAction);
|
|
@@ -65397,4 +65231,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
65397
65231
|
export {};
|
|
65398
65232
|
|
|
65399
65233
|
//# sourceMappingURL=cli.js.map
|
|
65400
|
-
//# debugId=
|
|
65234
|
+
//# debugId=63b8a227-543e-5501-a998-58c03a1fb10e
|