react-doctor 0.7.6-dev.c1916d5 → 0.7.6-dev.c5a06bd
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 +70 -214
- package/dist/index.d.ts +1 -1
- package/dist/index.js +49 -86
- package/dist/lsp.js +47 -84
- 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]="9a5c1a3c-7706-5a23-bca4-ddddd2f085af")}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";
|
|
@@ -39594,49 +39594,6 @@ const assignFixGroups = (diagnostics) => {
|
|
|
39594
39594
|
};
|
|
39595
39595
|
});
|
|
39596
39596
|
};
|
|
39597
|
-
const DERIVED_STATE_RULE_PRIORITY = new Map([
|
|
39598
|
-
["no-initialize-state", 0],
|
|
39599
|
-
["no-adjust-state-on-prop-change", 1],
|
|
39600
|
-
["no-derived-state", 2],
|
|
39601
|
-
["no-derived-state-effect", 3]
|
|
39602
|
-
]);
|
|
39603
|
-
const buildDiagnosticSiteKey = (diagnostic) => `${diagnostic.filePath}\u0000${diagnostic.line}\u0000${diagnostic.column}`;
|
|
39604
|
-
const isReactDoctorRulesOfHooksDiagnostic = (diagnostic) => diagnostic.plugin === "react-doctor" && diagnostic.rule === "rules-of-hooks";
|
|
39605
|
-
const isReactCompilerHooksDiagnostic = (diagnostic) => diagnostic.plugin === "react-hooks-js" && diagnostic.rule === "hooks";
|
|
39606
|
-
const doDiagnosticSpansOverlap = (first, second) => {
|
|
39607
|
-
if (first.filePath !== second.filePath || first.plugin !== second.plugin) return false;
|
|
39608
|
-
if (first.offset !== void 0 && second.offset !== void 0) {
|
|
39609
|
-
const firstEnd = first.offset + Math.max(first.length ?? 1, 1);
|
|
39610
|
-
const secondEnd = second.offset + Math.max(second.length ?? 1, 1);
|
|
39611
|
-
return first.offset < secondEnd && second.offset < firstEnd;
|
|
39612
|
-
}
|
|
39613
|
-
const firstEndLine = first.endLine ?? first.line;
|
|
39614
|
-
const secondEndLine = second.endLine ?? second.line;
|
|
39615
|
-
return first.line <= secondEndLine && second.line <= firstEndLine;
|
|
39616
|
-
};
|
|
39617
|
-
const keepHighestSeverity = (survivingDiagnostic, collapsedDiagnostic) => collapsedDiagnostic.severity === "error" && survivingDiagnostic.severity !== "error" ? {
|
|
39618
|
-
...survivingDiagnostic,
|
|
39619
|
-
severity: "error"
|
|
39620
|
-
} : survivingDiagnostic;
|
|
39621
|
-
const dedupeRelatedDiagnostics = (diagnostics) => {
|
|
39622
|
-
const reactDoctorHookSites = new Set(diagnostics.filter(isReactDoctorRulesOfHooksDiagnostic).map(buildDiagnosticSiteKey));
|
|
39623
|
-
const uniqueDiagnostics = [];
|
|
39624
|
-
for (const diagnostic of diagnostics) {
|
|
39625
|
-
if (isReactCompilerHooksDiagnostic(diagnostic) && reactDoctorHookSites.has(buildDiagnosticSiteKey(diagnostic))) continue;
|
|
39626
|
-
const priority = DERIVED_STATE_RULE_PRIORITY.get(diagnostic.rule);
|
|
39627
|
-
if (priority !== void 0) {
|
|
39628
|
-
const overlappingDiagnosticIndex = uniqueDiagnostics.findIndex((candidate) => candidate.rule !== diagnostic.rule && DERIVED_STATE_RULE_PRIORITY.has(candidate.rule) && doDiagnosticSpansOverlap(candidate, diagnostic));
|
|
39629
|
-
if (overlappingDiagnosticIndex >= 0) {
|
|
39630
|
-
const existingDiagnostic = uniqueDiagnostics[overlappingDiagnosticIndex];
|
|
39631
|
-
const existingPriority = existingDiagnostic ? DERIVED_STATE_RULE_PRIORITY.get(existingDiagnostic.rule) : void 0;
|
|
39632
|
-
if (existingDiagnostic && existingPriority !== void 0) uniqueDiagnostics[overlappingDiagnosticIndex] = priority < existingPriority ? keepHighestSeverity(diagnostic, existingDiagnostic) : keepHighestSeverity(existingDiagnostic, diagnostic);
|
|
39633
|
-
continue;
|
|
39634
|
-
}
|
|
39635
|
-
}
|
|
39636
|
-
uniqueDiagnostics.push(diagnostic);
|
|
39637
|
-
}
|
|
39638
|
-
return uniqueDiagnostics;
|
|
39639
|
-
};
|
|
39640
39597
|
const compareStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
39641
39598
|
const sortDiagnosticsStable = (diagnostics) => [...diagnostics].sort((left, right) => compareStrings(left.filePath, right.filePath) || left.line - right.line || left.column - right.column || compareStrings(left.plugin, right.plugin) || compareStrings(left.rule, right.rule) || compareStrings(left.severity, right.severity) || compareStrings(left.message, right.message));
|
|
39642
39599
|
const getDirectDependencyNames = (packageJson) => new Set([...Object.keys(packageJson.dependencies ?? {}), ...Object.keys(packageJson.devDependencies ?? {})]);
|
|
@@ -41866,7 +41823,6 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
41866
41823
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
41867
41824
|
};
|
|
41868
41825
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
41869
|
-
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
41870
41826
|
/**
|
|
41871
41827
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
41872
41828
|
* behind a `Context.Service`. The production layer (`layerNode`)
|
|
@@ -41937,14 +41893,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
41937
41893
|
args,
|
|
41938
41894
|
directory
|
|
41939
41895
|
});
|
|
41940
|
-
const listUntrackedFilePaths = (directory, includePaths = []) => runGit(directory, [
|
|
41941
|
-
"ls-files",
|
|
41942
|
-
"-z",
|
|
41943
|
-
"--others",
|
|
41944
|
-
"--exclude-standard",
|
|
41945
|
-
...includePaths.length > 0 ? ["--", ...includePaths] : []
|
|
41946
|
-
]).pipe(map$3((result) => result.status === 0 ? splitNullSeparated(result.stdout) : null));
|
|
41947
|
-
const mergeUntracked = (directory, trackedFilePaths, includeUntracked) => includeUntracked ? listUntrackedFilePaths(directory).pipe(map$3((untracked) => untracked === null ? trackedFilePaths : [...new Set([...trackedFilePaths, ...untracked])])) : succeed$2(trackedFilePaths);
|
|
41948
41896
|
const currentBranch = (directory) => runGit(directory, [
|
|
41949
41897
|
"rev-parse",
|
|
41950
41898
|
"--abbrev-ref",
|
|
@@ -42067,7 +42015,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42067
42015
|
githubViewerPermission,
|
|
42068
42016
|
branchExists,
|
|
42069
42017
|
mergeBase,
|
|
42070
|
-
diffSelection: ({ directory, explicitBaseBranch
|
|
42018
|
+
diffSelection: ({ directory, explicitBaseBranch }) => gen(function* () {
|
|
42071
42019
|
if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
|
|
42072
42020
|
if (explicitBaseBranch !== void 0) {
|
|
42073
42021
|
const range = parseGitDiffRange(explicitBaseBranch);
|
|
@@ -42096,7 +42044,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42096
42044
|
"HEAD"
|
|
42097
42045
|
]);
|
|
42098
42046
|
if (uncommitted.status !== 0) return null;
|
|
42099
|
-
const files =
|
|
42047
|
+
const files = splitNullSeparated(uncommitted.stdout);
|
|
42100
42048
|
if (files.length === 0) return null;
|
|
42101
42049
|
return {
|
|
42102
42050
|
currentBranch: resolvedCurrentBranch,
|
|
@@ -42126,7 +42074,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42126
42074
|
currentBranch: resolvedCurrentBranch,
|
|
42127
42075
|
baseBranch,
|
|
42128
42076
|
diffBaseRef: mergeBaseRef,
|
|
42129
|
-
changedFiles:
|
|
42077
|
+
changedFiles: splitNullSeparated(diff.stdout),
|
|
42130
42078
|
isCurrentChanges: false
|
|
42131
42079
|
};
|
|
42132
42080
|
}).pipe(withSpan("Git.diffSelection")),
|
|
@@ -42172,7 +42120,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42172
42120
|
stdout: result.stdout
|
|
42173
42121
|
};
|
|
42174
42122
|
}).pipe(withSpan("Git.grep")),
|
|
42175
|
-
changedLineRanges: ({ directory, baseRef, cached, files
|
|
42123
|
+
changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
|
|
42176
42124
|
if (files.length === 0) return [];
|
|
42177
42125
|
if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
|
|
42178
42126
|
const result = yield* runGit(directory, [
|
|
@@ -42186,14 +42134,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
42186
42134
|
...files
|
|
42187
42135
|
]);
|
|
42188
42136
|
if (result.status !== 0) return null;
|
|
42189
|
-
|
|
42190
|
-
if (cached || !includeUntracked) return changedLineRanges;
|
|
42191
|
-
const untrackedFilePaths = yield* listUntrackedFilePaths(directory, files);
|
|
42192
|
-
if (untrackedFilePaths === null) return changedLineRanges;
|
|
42193
|
-
return [...changedLineRanges, ...untrackedFilePaths.map((file) => ({
|
|
42194
|
-
file,
|
|
42195
|
-
ranges: [[1, UNTRACKED_FILE_LAST_LINE]]
|
|
42196
|
-
}))];
|
|
42137
|
+
return parseChangedLineRanges(result.stdout);
|
|
42197
42138
|
}).pipe(catch_$1((error) => error.reason._tag === "GitInvocationFailed" ? succeed$2(null) : fail$4(error)), withSpan("Git.changedLineRanges"))
|
|
42198
42139
|
});
|
|
42199
42140
|
})).pipe(provide$2(layer$3.pipe(provide$2(mergeAll$1(layer$2, layer$1)))));
|
|
@@ -42778,13 +42719,13 @@ const encodeSidecarFileEntry = (entry) => ({
|
|
|
42778
42719
|
diagnostics: entry.diagnostics
|
|
42779
42720
|
});
|
|
42780
42721
|
const emptyCache = () => ({
|
|
42781
|
-
version:
|
|
42722
|
+
version: 1,
|
|
42782
42723
|
rulesets: {}
|
|
42783
42724
|
});
|
|
42784
42725
|
const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
|
|
42785
42726
|
const entries = /* @__PURE__ */ new Map();
|
|
42786
42727
|
const persisted = failOpenReadJson(cacheFilePath, emptyCache());
|
|
42787
|
-
if (persisted.version !==
|
|
42728
|
+
if (persisted.version !== 1 || !isRecord$1(persisted.rulesets)) return entries;
|
|
42788
42729
|
const bucket = persisted.rulesets[rulesetHash];
|
|
42789
42730
|
if (!isRecord$1(bucket) || !isRecord$1(bucket.files)) return entries;
|
|
42790
42731
|
for (const [fileKey, rawEntry] of Object.entries(bucket.files)) {
|
|
@@ -42804,7 +42745,7 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
42804
42745
|
},
|
|
42805
42746
|
persist: () => {
|
|
42806
42747
|
const onDisk = failOpenReadJson(cacheFilePath, emptyCache());
|
|
42807
|
-
const rulesets = onDisk.version ===
|
|
42748
|
+
const rulesets = onDisk.version === 1 && isRecord$1(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
42808
42749
|
const existingBucket = rulesets[rulesetHash];
|
|
42809
42750
|
const existingFiles = isRecord$1(existingBucket) && isRecord$1(existingBucket.files) ? existingBucket.files : {};
|
|
42810
42751
|
const ourFiles = {};
|
|
@@ -42818,7 +42759,7 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
42818
42759
|
files: Object.fromEntries(cappedEntries)
|
|
42819
42760
|
};
|
|
42820
42761
|
atomicWriteJson(cacheFilePath, {
|
|
42821
|
-
version:
|
|
42762
|
+
version: 1,
|
|
42822
42763
|
rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord$1(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
|
|
42823
42764
|
});
|
|
42824
42765
|
}
|
|
@@ -42869,6 +42810,23 @@ const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
|
42869
42810
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
42870
42811
|
return null;
|
|
42871
42812
|
};
|
|
42813
|
+
const DERIVED_STATE_RULE_PRIORITY = new Map([
|
|
42814
|
+
["no-initialize-state", 0],
|
|
42815
|
+
["no-adjust-state-on-prop-change", 1],
|
|
42816
|
+
["no-derived-state", 2],
|
|
42817
|
+
["no-derived-state-effect", 3]
|
|
42818
|
+
]);
|
|
42819
|
+
const doDiagnosticSpansOverlap = (first, second) => {
|
|
42820
|
+
if (first.filePath !== second.filePath || first.plugin !== second.plugin) return false;
|
|
42821
|
+
if (first.offset !== void 0 && second.offset !== void 0) {
|
|
42822
|
+
const firstEnd = first.offset + Math.max(first.length ?? 1, 1);
|
|
42823
|
+
const secondEnd = second.offset + Math.max(second.length ?? 1, 1);
|
|
42824
|
+
return first.offset < secondEnd && second.offset < firstEnd;
|
|
42825
|
+
}
|
|
42826
|
+
const firstEndLine = first.endLine ?? first.line;
|
|
42827
|
+
const secondEndLine = second.endLine ?? second.line;
|
|
42828
|
+
return first.line <= secondEndLine && second.line <= firstEndLine;
|
|
42829
|
+
};
|
|
42872
42830
|
const dedupeDiagnostics = (diagnostics) => {
|
|
42873
42831
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
42874
42832
|
const uniqueDiagnostics = [];
|
|
@@ -42876,6 +42834,16 @@ const dedupeDiagnostics = (diagnostics) => {
|
|
|
42876
42834
|
const key = `${diagnostic.filePath}\u0000${diagnostic.line}\u0000${diagnostic.column}\u0000${diagnostic.plugin}\u0000${diagnostic.rule}\u0000${diagnostic.severity}\u0000${diagnostic.message}`;
|
|
42877
42835
|
if (seenKeys.has(key)) continue;
|
|
42878
42836
|
seenKeys.add(key);
|
|
42837
|
+
const priority = DERIVED_STATE_RULE_PRIORITY.get(diagnostic.rule);
|
|
42838
|
+
if (priority !== void 0) {
|
|
42839
|
+
const overlappingDiagnosticIndex = uniqueDiagnostics.findIndex((candidate) => candidate.rule !== diagnostic.rule && candidate.severity === diagnostic.severity && DERIVED_STATE_RULE_PRIORITY.has(candidate.rule) && doDiagnosticSpansOverlap(candidate, diagnostic));
|
|
42840
|
+
if (overlappingDiagnosticIndex >= 0) {
|
|
42841
|
+
const existingDiagnostic = uniqueDiagnostics[overlappingDiagnosticIndex];
|
|
42842
|
+
const existingPriority = existingDiagnostic ? DERIVED_STATE_RULE_PRIORITY.get(existingDiagnostic.rule) : void 0;
|
|
42843
|
+
if (existingPriority !== void 0 && priority < existingPriority) uniqueDiagnostics[overlappingDiagnosticIndex] = diagnostic;
|
|
42844
|
+
continue;
|
|
42845
|
+
}
|
|
42846
|
+
}
|
|
42879
42847
|
uniqueDiagnostics.push(diagnostic);
|
|
42880
42848
|
}
|
|
42881
42849
|
return uniqueDiagnostics;
|
|
@@ -43675,11 +43643,11 @@ const buildRelatedLocations = (labels, filePath) => {
|
|
|
43675
43643
|
}
|
|
43676
43644
|
return related;
|
|
43677
43645
|
};
|
|
43678
|
-
const
|
|
43679
|
-
|
|
43680
|
-
const
|
|
43681
|
-
|
|
43682
|
-
|
|
43646
|
+
const isOxlintOutput = (value) => {
|
|
43647
|
+
if (typeof value !== "object" || value === null) return false;
|
|
43648
|
+
const candidate = value;
|
|
43649
|
+
return Array.isArray(candidate.diagnostics);
|
|
43650
|
+
};
|
|
43683
43651
|
/**
|
|
43684
43652
|
* Parses one oxlint subprocess's stdout into a flat `Diagnostic[]`.
|
|
43685
43653
|
* Tolerates the leading-notice-line shape oxlint sometimes prints
|
|
@@ -43698,8 +43666,6 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
43698
43666
|
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
43699
43667
|
}
|
|
43700
43668
|
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
43701
|
-
const engineFailureDiagnostic = parsed.diagnostics.find(isEngineFailureDiagnostic);
|
|
43702
|
-
if (engineFailureDiagnostic !== void 0) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: JSON.stringify(engineFailureDiagnostic).slice(0, 600) }) });
|
|
43703
43669
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
43704
43670
|
const sourceBufferCache = /* @__PURE__ */ new Map();
|
|
43705
43671
|
const sourceLinesCache = /* @__PURE__ */ new Map();
|
|
@@ -43734,7 +43700,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
43734
43700
|
minifiedFileCache.set(absolutePath, minified);
|
|
43735
43701
|
return minified;
|
|
43736
43702
|
};
|
|
43737
|
-
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) =>
|
|
43703
|
+
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
43738
43704
|
const { plugin, rule } = parseRuleCode(diagnostic.code);
|
|
43739
43705
|
const primaryLabel = diagnostic.labels[0];
|
|
43740
43706
|
const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
|
|
@@ -45569,8 +45535,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
45569
45535
|
respectInlineDisables: input.respectInlineDisables,
|
|
45570
45536
|
showWarnings
|
|
45571
45537
|
});
|
|
45572
|
-
const
|
|
45573
|
-
const applyPerElementPipeline = (rawStream) => filterPerElementPipeline(rawStream).pipe(tap((diagnostic) => reporterService.emit(diagnostic)));
|
|
45538
|
+
const applyPerElementPipeline = (rawStream) => rawStream.pipe(filterMap(filterMapNullable(transform.apply)), tap((diagnostic) => reporterService.emit(diagnostic)));
|
|
45574
45539
|
const envCollected = yield* runCollect(applyPerElementPipeline(fromIterable$1(isDiffMode ? [] : [
|
|
45575
45540
|
...checkReducedMotion(scanDirectory),
|
|
45576
45541
|
...checkPnpmHardening(scanDirectory),
|
|
@@ -45699,7 +45664,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
45699
45664
|
});
|
|
45700
45665
|
return empty$4;
|
|
45701
45666
|
}))));
|
|
45702
|
-
const lintCollected =
|
|
45667
|
+
const lintCollected = yield* runCollect(applyPerElementPipeline(shouldOverlapDeadCode ? baseLintStream.pipe(provideService(OxlintConcurrency, lintConcurrency)) : baseLintStream)).pipe(timeoutOption(lintPhaseTimeoutMs), flatMap$2(match$3({
|
|
45703
45668
|
onNone: () => set(lintFailure, {
|
|
45704
45669
|
didFail: true,
|
|
45705
45670
|
reason: `Lint analysis exceeded ${lintPhaseTimeoutMs / MILLISECONDS_PER_SECOND}s and was skipped.`,
|
|
@@ -45707,8 +45672,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
45707
45672
|
reasonKind: null
|
|
45708
45673
|
}).pipe(as([])),
|
|
45709
45674
|
onSome: succeed$2
|
|
45710
|
-
})))
|
|
45711
|
-
yield* forEach$1(lintCollected, reporterService.emit, { discard: true });
|
|
45675
|
+
})));
|
|
45712
45676
|
const lintFailureState = yield* get$2(lintFailure);
|
|
45713
45677
|
yield* afterLint(lintFailureState.didFail);
|
|
45714
45678
|
if (lintFailureState.didFail) yield* scanProgress.fail(formatLintFailText(lintFailureState.reasonTag, process.version));
|
|
@@ -46302,11 +46266,10 @@ const computeDiagnosticDelta = (input) => {
|
|
|
46302
46266
|
* render diff-base mistakes (`GitBaseBranchInvalid` /
|
|
46303
46267
|
* `GitBaseBranchMissing`) as clean user errors instead of crashes.
|
|
46304
46268
|
*/
|
|
46305
|
-
const getDiffInfo = (directory, explicitBaseBranch
|
|
46269
|
+
const getDiffInfo = (directory, explicitBaseBranch) => runPromise(gen(function* () {
|
|
46306
46270
|
const selection = yield* (yield* Git).diffSelection({
|
|
46307
46271
|
directory,
|
|
46308
|
-
explicitBaseBranch
|
|
46309
|
-
includeUntracked
|
|
46272
|
+
explicitBaseBranch
|
|
46310
46273
|
});
|
|
46311
46274
|
if (selection === null) return null;
|
|
46312
46275
|
return {
|
|
@@ -46642,43 +46605,6 @@ const isNonInteractiveEnvironment = () => NON_INTERACTIVE_ENVIRONMENT_VARIABLES.
|
|
|
46642
46605
|
//#region src/cli/utils/constants.ts
|
|
46643
46606
|
const REACT_DOCTOR_CONFIG_PROJECT_NAME = "react-doctor";
|
|
46644
46607
|
const STAGED_FILES_TEMP_DIR_PREFIX = "react-doctor-staged-";
|
|
46645
|
-
const STAGED_SNAPSHOT_ADDITIONAL_CONFIG_FILENAMES = [
|
|
46646
|
-
".babelrc",
|
|
46647
|
-
".babelrc.json",
|
|
46648
|
-
".eslintignore",
|
|
46649
|
-
".eslintrc.json",
|
|
46650
|
-
".oxlintignore",
|
|
46651
|
-
"app.config.cjs",
|
|
46652
|
-
"app.config.js",
|
|
46653
|
-
"app.config.json",
|
|
46654
|
-
"app.config.mjs",
|
|
46655
|
-
"app.config.ts",
|
|
46656
|
-
"app.json",
|
|
46657
|
-
"babel.config.cjs",
|
|
46658
|
-
"babel.config.js",
|
|
46659
|
-
"babel.config.json",
|
|
46660
|
-
"babel.config.mjs",
|
|
46661
|
-
"eslint.config.cjs",
|
|
46662
|
-
"eslint.config.cts",
|
|
46663
|
-
"eslint.config.js",
|
|
46664
|
-
"eslint.config.mjs",
|
|
46665
|
-
"eslint.config.mts",
|
|
46666
|
-
"eslint.config.ts",
|
|
46667
|
-
"next.config.cjs",
|
|
46668
|
-
"next.config.js",
|
|
46669
|
-
"next.config.mjs",
|
|
46670
|
-
"next.config.ts",
|
|
46671
|
-
"oxlint.config.json",
|
|
46672
|
-
"react-doctor.config.json",
|
|
46673
|
-
"vite.config.cjs",
|
|
46674
|
-
"vite.config.cts",
|
|
46675
|
-
"vite.config.js",
|
|
46676
|
-
"vite.config.mjs",
|
|
46677
|
-
"vite.config.mts",
|
|
46678
|
-
"vite.config.ts",
|
|
46679
|
-
"vitest.config.js",
|
|
46680
|
-
"vitest.config.ts"
|
|
46681
|
-
];
|
|
46682
46608
|
const BASELINE_FILES_TEMP_DIR_PREFIX = "react-doctor-baseline-";
|
|
46683
46609
|
const SCAN_RESULT_CACHE_FILENAME = "scan-cache.json";
|
|
46684
46610
|
const RUN_GIT_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
|
|
@@ -46693,7 +46619,6 @@ const METRIC = {
|
|
|
46693
46619
|
cliInvoked: "cli.invoked",
|
|
46694
46620
|
cliError: "cli.error",
|
|
46695
46621
|
cliEnvironmentError: "cli.env_error",
|
|
46696
|
-
stagedSnapshotDivergence: "staged.snapshot_divergence",
|
|
46697
46622
|
projectDetected: "project.detected",
|
|
46698
46623
|
projectPathSelected: "project.path_selected",
|
|
46699
46624
|
projectConfigSelected: "project.config_selected",
|
|
@@ -46774,7 +46699,7 @@ const makeNoopConsole = () => ({
|
|
|
46774
46699
|
});
|
|
46775
46700
|
//#endregion
|
|
46776
46701
|
//#region src/cli/utils/version.ts
|
|
46777
|
-
const VERSION = "0.7.6-dev.
|
|
46702
|
+
const VERSION = "0.7.6-dev.c5a06bd";
|
|
46778
46703
|
//#endregion
|
|
46779
46704
|
//#region src/cli/utils/json-mode.ts
|
|
46780
46705
|
let context = null;
|
|
@@ -47143,13 +47068,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
|
|
|
47143
47068
|
* uploads source-map artifacts under, so stack frames symbolicate. Honors the
|
|
47144
47069
|
* standard `SENTRY_RELEASE` override.
|
|
47145
47070
|
*/
|
|
47146
|
-
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.6-dev.
|
|
47071
|
+
const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.6-dev.c5a06bd`;
|
|
47147
47072
|
/**
|
|
47148
47073
|
* Deployment environment shown in Sentry's environment filter. Defaults to
|
|
47149
47074
|
* `production` for tagged releases and `development` for dev/unbuilt versions,
|
|
47150
47075
|
* overridable via the standard `SENTRY_ENVIRONMENT` env var.
|
|
47151
47076
|
*/
|
|
47152
|
-
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.6-dev.
|
|
47077
|
+
const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.6-dev.c5a06bd") ? "development" : "production");
|
|
47153
47078
|
/**
|
|
47154
47079
|
* Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
|
|
47155
47080
|
* (set to `0` to disable tracing) and falls back to
|
|
@@ -47341,7 +47266,7 @@ const NON_BLOCKING_REACT_DOCTOR_COMMAND = [
|
|
|
47341
47266
|
"fi"
|
|
47342
47267
|
].join(" ");
|
|
47343
47268
|
const PACKAGE_JSON_FILE_NAME = "package.json";
|
|
47344
|
-
const
|
|
47269
|
+
const runGit = (projectRoot, args) => {
|
|
47345
47270
|
try {
|
|
47346
47271
|
return execFileSync("git", [...args], {
|
|
47347
47272
|
cwd: projectRoot,
|
|
@@ -47352,12 +47277,11 @@ const runGitRaw = (projectRoot, args) => {
|
|
|
47352
47277
|
"ignore"
|
|
47353
47278
|
],
|
|
47354
47279
|
maxBuffer: RUN_GIT_MAX_BUFFER_BYTES
|
|
47355
|
-
});
|
|
47280
|
+
}).trim();
|
|
47356
47281
|
} catch {
|
|
47357
47282
|
return null;
|
|
47358
47283
|
}
|
|
47359
47284
|
};
|
|
47360
|
-
const runGit = (projectRoot, args) => runGitRaw(projectRoot, args)?.trim() ?? null;
|
|
47361
47285
|
const resolveGitPath = (baseDirectory, value) => Path.isAbsolute(value) ? value : Path.resolve(baseDirectory, value);
|
|
47362
47286
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
47363
47287
|
const getPackageJsonPath = (projectRoot) => Path.join(projectRoot, PACKAGE_JSON_FILE_NAME);
|
|
@@ -59228,17 +59152,6 @@ const buildRuleBlastRadii = (diagnostics) => buildSortedRuleGroups(diagnostics).
|
|
|
59228
59152
|
})).toSorted((left, right) => right.fileCount - left.fileCount);
|
|
59229
59153
|
const findMigrationScaleBuckets = (diagnostics) => buildRuleBlastRadii(diagnostics).filter((bucket) => bucket.fileCount >= 40);
|
|
59230
59154
|
//#endregion
|
|
59231
|
-
//#region src/cli/utils/has-lint-hard-failure.ts
|
|
59232
|
-
const hasLintHardFailure = (result) => result.skippedChecks.includes("lint");
|
|
59233
|
-
//#endregion
|
|
59234
|
-
//#region src/cli/utils/is-inspect-result-complete.ts
|
|
59235
|
-
const isInspectResultComplete = (result) => isScanComplete({
|
|
59236
|
-
analyzedFileCount: result.analyzedFiles?.length,
|
|
59237
|
-
scannedFileCount: result.scannedFileCount,
|
|
59238
|
-
skippedCheckCount: result.skippedChecks.length,
|
|
59239
|
-
skippedCheckReasonCount: Object.keys(result.skippedCheckReasons ?? {}).length
|
|
59240
|
-
});
|
|
59241
|
-
//#endregion
|
|
59242
59155
|
//#region src/cli/utils/scan-result-cache.ts
|
|
59243
59156
|
const CACHE_DISABLED_VALUES = new Set(["1", "true"]);
|
|
59244
59157
|
const TOOLCHAIN_PACKAGE_SPECIFIERS = [
|
|
@@ -59644,12 +59557,15 @@ const buildOutcomeAttributes = (input) => {
|
|
|
59644
59557
|
const summary = summarizeDiagnostics(result.diagnostics);
|
|
59645
59558
|
const blockingLevel = resolveTelemetryBlocking(input.userConfig);
|
|
59646
59559
|
const gateDiagnostics = filterDiagnosticsForSurface(result.diagnostics, "ciFailure", input.userConfig);
|
|
59647
|
-
const complete = isInspectResultComplete(result);
|
|
59648
|
-
const didLintHardFail = hasLintHardFailure(result);
|
|
59649
|
-
const failsOnHardFailure = didLintHardFail && blockingLevel !== "none";
|
|
59650
59560
|
const wouldBlock = !input.scoreOnly && !input.gateExempt && shouldBlockCi(gateDiagnostics, blockingLevel);
|
|
59561
|
+
const complete = isScanComplete({
|
|
59562
|
+
analyzedFileCount: result.analyzedFiles?.length,
|
|
59563
|
+
scannedFileCount: result.scannedFileCount,
|
|
59564
|
+
skippedCheckCount: result.skippedChecks.length,
|
|
59565
|
+
skippedCheckReasonCount: Object.keys(result.skippedCheckReasons ?? {}).length
|
|
59566
|
+
});
|
|
59651
59567
|
const isClean = result.diagnostics.length === 0 && complete;
|
|
59652
|
-
const outcome =
|
|
59568
|
+
const outcome = wouldBlock ? "blocked" : isClean ? "clean" : "ok";
|
|
59653
59569
|
const firings = summarizeRuleFirings(result.diagnostics);
|
|
59654
59570
|
const countByRule = /* @__PURE__ */ new Map();
|
|
59655
59571
|
const countByCategory = /* @__PURE__ */ new Map();
|
|
@@ -59694,7 +59610,7 @@ const buildOutcomeAttributes = (input) => {
|
|
|
59694
59610
|
const attributes = {
|
|
59695
59611
|
...withNamespace("outcome", {
|
|
59696
59612
|
status: outcome,
|
|
59697
|
-
exitCode:
|
|
59613
|
+
exitCode: wouldBlock ? 1 : 0,
|
|
59698
59614
|
wouldBlock,
|
|
59699
59615
|
blocking: blockingLevel,
|
|
59700
59616
|
clean: isClean,
|
|
@@ -63876,15 +63792,10 @@ const warnIfAiTrainingEnvironment = () => {
|
|
|
63876
63792
|
//#region src/cli/utils/validate-mode-flags.ts
|
|
63877
63793
|
const usedDiffAlias = (flags) => flags.diff !== void 0 && flags.diff !== false && flags.diff !== "false" && flags.diff !== "";
|
|
63878
63794
|
const usedScope = (flags) => typeof flags.scope === "string" && flags.scope.length > 0;
|
|
63879
|
-
const validateIncludeUntrackedScope = (includeUntracked, scope) => {
|
|
63880
|
-
if (!includeUntracked || scope !== void 0 && scope !== "full") return;
|
|
63881
|
-
throw new CliInputError("--include-untracked requires the files, changed, or lines scope (via --scope, --diff, or config).");
|
|
63882
|
-
};
|
|
63883
63795
|
const validateModeFlags = (flags) => {
|
|
63884
63796
|
if (usedScope(flags) && usedDiffAlias(flags)) throw new CliInputError("Cannot combine --scope and --diff; --diff is the deprecated alias.");
|
|
63885
63797
|
if (flags.staged && usedDiffAlias(flags)) throw new CliInputError("Cannot combine --staged and --diff; pick one mode.");
|
|
63886
63798
|
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.`);
|
|
63887
|
-
if (flags.includeUntracked && flags.staged) throw new CliInputError("Cannot combine --include-untracked with --staged; the git index never holds untracked files.");
|
|
63888
63799
|
if (flags.score && flags.json) throw new CliInputError("Cannot combine --score and --json; pick one output mode.");
|
|
63889
63800
|
if (flags.score && flags.telemetry === false) throw new CliInputError("Cannot combine --score with --no-telemetry; --score prints the score that --no-telemetry disables.");
|
|
63890
63801
|
if (flags.debug && (flags.score === false || flags.telemetry === false)) {
|
|
@@ -63893,39 +63804,6 @@ const validateModeFlags = (flags) => {
|
|
|
63893
63804
|
}
|
|
63894
63805
|
};
|
|
63895
63806
|
//#endregion
|
|
63896
|
-
//#region src/cli/utils/parse-staged-snapshot-divergences.ts
|
|
63897
|
-
const SNAPSHOT_CONFIG_FILENAMES = new Set([...STAGED_FILES_PROJECT_CONFIG_FILENAMES, ...STAGED_SNAPSHOT_ADDITIONAL_CONFIG_FILENAMES]);
|
|
63898
|
-
const parseStagedSnapshotDivergences = (statusOutput) => {
|
|
63899
|
-
const divergentConfigFiles = /* @__PURE__ */ new Set();
|
|
63900
|
-
const statusEntries = statusOutput.split("\0").filter((entry) => entry.length > 0);
|
|
63901
|
-
for (let entryIndex = 0; entryIndex < statusEntries.length; entryIndex += 1) {
|
|
63902
|
-
const entry = statusEntries[entryIndex];
|
|
63903
|
-
const [indexStatus, worktreeStatus] = entry;
|
|
63904
|
-
const filePath = entry.slice(3);
|
|
63905
|
-
const hasRenameOrCopySource = indexStatus === "R" || indexStatus === "C" || worktreeStatus === "R" || worktreeStatus === "C";
|
|
63906
|
-
const sourcePath = hasRenameOrCopySource ? statusEntries[entryIndex + 1] : void 0;
|
|
63907
|
-
const worktreePaths = worktreeStatus === "R" || worktreeStatus === "C" ? [filePath, sourcePath] : [filePath];
|
|
63908
|
-
if (worktreeStatus !== " ") {
|
|
63909
|
-
for (const worktreePath of worktreePaths) if (worktreePath && SNAPSHOT_CONFIG_FILENAMES.has(Path.basename(worktreePath))) divergentConfigFiles.add(worktreePath);
|
|
63910
|
-
}
|
|
63911
|
-
if (hasRenameOrCopySource) entryIndex += 1;
|
|
63912
|
-
}
|
|
63913
|
-
return [...divergentConfigFiles].sort();
|
|
63914
|
-
};
|
|
63915
|
-
//#endregion
|
|
63916
|
-
//#region src/cli/utils/find-staged-snapshot-divergences.ts
|
|
63917
|
-
const findStagedSnapshotDivergences = (directory) => {
|
|
63918
|
-
const statusOutput = runGitRaw(directory, [
|
|
63919
|
-
"status",
|
|
63920
|
-
"--porcelain=v1",
|
|
63921
|
-
"-z",
|
|
63922
|
-
"--untracked-files=all",
|
|
63923
|
-
"--ignored=matching"
|
|
63924
|
-
]);
|
|
63925
|
-
if (statusOutput === null) return null;
|
|
63926
|
-
return parseStagedSnapshotDivergences(statusOutput);
|
|
63927
|
-
};
|
|
63928
|
-
//#endregion
|
|
63929
63807
|
//#region src/cli/commands/inspect.ts
|
|
63930
63808
|
const filterCompletedScansByCategories = (completedScans, categoryFilters) => {
|
|
63931
63809
|
if (categoryFilters.size === 0) return [...completedScans];
|
|
@@ -63940,14 +63818,9 @@ const filterCompletedScansByCategories = (completedScans, categoryFilters) => {
|
|
|
63940
63818
|
/**
|
|
63941
63819
|
* Post-scan finalization shared by the staged-arm and project-loop
|
|
63942
63820
|
* paths of `inspectAction`: emit the JSON report (when in JSON mode)
|
|
63943
|
-
* and set `process.exitCode = 1` when
|
|
63944
|
-
* (
|
|
63945
|
-
*
|
|
63946
|
-
* threshold (default `"error"`) reaches the `ciFailure` surface.
|
|
63947
|
-
* `--blocking none` keeps the scan advisory (always exits 0), and
|
|
63948
|
-
* fail-open degradations — `--no-lint`, `--max-duration` truncation,
|
|
63949
|
-
* supply-chain/security skips — stay advisory too, surfaced through
|
|
63950
|
-
* `complete: false` in the JSON report.
|
|
63821
|
+
* and set `process.exitCode = 1` when a diagnostic at or above the
|
|
63822
|
+
* `--blocking` threshold (default `"error"`) reaches the `ciFailure`
|
|
63823
|
+
* surface. `--blocking none` keeps the scan advisory (always exits 0).
|
|
63951
63824
|
*/
|
|
63952
63825
|
const finalizeScans = (input) => {
|
|
63953
63826
|
const baselineDeltas = input.completedScans.flatMap((scan) => scan.result.baselineDelta ? [scan.result.baselineDelta] : []);
|
|
@@ -63977,13 +63850,8 @@ const finalizeScans = (input) => {
|
|
|
63977
63850
|
baselineDegraded
|
|
63978
63851
|
}));
|
|
63979
63852
|
}
|
|
63980
|
-
const blockingLevel = resolveBlockingLevel(input.flags, input.userConfig);
|
|
63981
|
-
if (input.completedScans.some(({ result }) => hasLintHardFailure(result)) && blockingLevel !== "none") {
|
|
63982
|
-
process.exitCode = 1;
|
|
63983
|
-
return;
|
|
63984
|
-
}
|
|
63985
63853
|
if (input.isScoreOnly || baselineDegraded) return;
|
|
63986
|
-
if (shouldBlockCi(filterScansForSurface(input.completedScans, "ciFailure"),
|
|
63854
|
+
if (shouldBlockCi(filterScansForSurface(input.completedScans, "ciFailure"), resolveBlockingLevel(input.flags, input.userConfig))) process.exitCode = 1;
|
|
63987
63855
|
};
|
|
63988
63856
|
const buildChangedFilesDiffInfo = (changedFiles) => ({
|
|
63989
63857
|
currentBranch: process.env.GITHUB_HEAD_REF?.trim() || null,
|
|
@@ -64021,7 +63889,6 @@ const inspectAction = async (directory, flags) => {
|
|
|
64021
63889
|
recordCount(METRIC.cliInvoked, 1, { command: "inspect" });
|
|
64022
63890
|
try {
|
|
64023
63891
|
validateModeFlags(flags);
|
|
64024
|
-
if (flags.staged) setJsonReportMode("staged");
|
|
64025
63892
|
await maybeMigrateLegacyConfig(requestedDirectory, {
|
|
64026
63893
|
isQuiet,
|
|
64027
63894
|
isStaged: Boolean(flags.staged)
|
|
@@ -64037,14 +63904,6 @@ const inspectAction = async (directory, flags) => {
|
|
|
64037
63904
|
cliLogger.dim(`Redirected to ${highlighter.info(toRelativePath(resolvedDirectory, requestedDirectory))} via react-doctor config "rootDir".`);
|
|
64038
63905
|
cliLogger.break();
|
|
64039
63906
|
}
|
|
64040
|
-
if (flags.staged) {
|
|
64041
|
-
const divergentConfigFiles = findStagedSnapshotDivergences(resolvedDirectory);
|
|
64042
|
-
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.");
|
|
64043
|
-
if (divergentConfigFiles.length > 0) {
|
|
64044
|
-
recordCount(METRIC.stagedSnapshotDivergence, 1, { divergentInputCount: divergentConfigFiles.length });
|
|
64045
|
-
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.`);
|
|
64046
|
-
}
|
|
64047
|
-
}
|
|
64048
63907
|
const explainArgument = flags.explain;
|
|
64049
63908
|
if (explainArgument !== void 0) {
|
|
64050
63909
|
await runExplain(explainArgument, {
|
|
@@ -64065,6 +63924,7 @@ const inspectAction = async (directory, flags) => {
|
|
|
64065
63924
|
json: flags.json
|
|
64066
63925
|
});
|
|
64067
63926
|
if (flags.staged) {
|
|
63927
|
+
setJsonReportMode("staged");
|
|
64068
63928
|
const stagedFiles = await getStagedSourceFiles(resolvedDirectory);
|
|
64069
63929
|
if (stagedFiles.length === 0) {
|
|
64070
63930
|
if (isJsonMode) writeJsonReport(buildJsonReport({
|
|
@@ -64145,15 +64005,13 @@ const inspectAction = async (directory, flags) => {
|
|
|
64145
64005
|
const projectDirectories = await selectProjects(resolvedDirectory, flags.project, skipPrompts, userConfig?.projects);
|
|
64146
64006
|
const changedFilesDiffInfo = flags.changedFilesFrom ? buildChangedFilesDiffInfo(readChangedFilesFrom(Path.resolve(flags.changedFilesFrom))) : null;
|
|
64147
64007
|
const requestedScope = resolveScope(flags, userConfig);
|
|
64148
|
-
const includeUntracked = flags.includeUntracked ?? false;
|
|
64149
64008
|
const scopeRequest = requestedScope.scope === void 0 && changedFilesDiffInfo !== null ? {
|
|
64150
64009
|
...requestedScope,
|
|
64151
64010
|
scope: "changed"
|
|
64152
64011
|
} : requestedScope;
|
|
64153
|
-
validateIncludeUntrackedScope(includeUntracked, scopeRequest.scope);
|
|
64154
64012
|
const wantsDiffMode = scopeRequest.scope !== void 0 && scopeRequest.scope !== "full";
|
|
64155
64013
|
const shouldDetectDiff = changedFilesDiffInfo === null && (wantsDiffMode || scopeRequest.scope === void 0 && !skipPrompts && !isQuiet);
|
|
64156
|
-
const diffInfo = changedFilesDiffInfo ?? (shouldDetectDiff ? await getDiffInfo(resolvedDirectory, scopeRequest.base
|
|
64014
|
+
const diffInfo = changedFilesDiffInfo ?? (shouldDetectDiff ? await getDiffInfo(resolvedDirectory, scopeRequest.base) : null);
|
|
64157
64015
|
const scope = await finalizeScope({
|
|
64158
64016
|
requested: scopeRequest,
|
|
64159
64017
|
diffInfo,
|
|
@@ -64167,8 +64025,7 @@ const inspectAction = async (directory, flags) => {
|
|
|
64167
64025
|
const changedLineRanges = scope === "lines" && diffInfo !== null && (diffInfo.isCurrentChanges || linesBaseRef !== null) && diffInfo !== null ? await getChangedLineRanges({
|
|
64168
64026
|
directory: resolvedDirectory,
|
|
64169
64027
|
baseRef: linesBaseRef ?? void 0,
|
|
64170
|
-
files: [...diffInfo.changedFiles]
|
|
64171
|
-
includeUntracked
|
|
64028
|
+
files: [...diffInfo.changedFiles]
|
|
64172
64029
|
}) : null;
|
|
64173
64030
|
if (scope === "lines" && changedLineRanges === null && !isQuiet) {
|
|
64174
64031
|
cliLogger.warn("Could not determine changed lines (no base ref or git diff failed); reporting all issues in changed files.");
|
|
@@ -65101,7 +64958,6 @@ const ROOT_FLAG_SPEC = {
|
|
|
65101
64958
|
"--dead-code",
|
|
65102
64959
|
"--debug",
|
|
65103
64960
|
"--help",
|
|
65104
|
-
"--include-untracked",
|
|
65105
64961
|
"--json",
|
|
65106
64962
|
"--json-compact",
|
|
65107
64963
|
"--lint",
|
|
@@ -65365,7 +65221,7 @@ ${highlighter.dim("Learn more:")}
|
|
|
65365
65221
|
${highlighter.info(CI_URL)}
|
|
65366
65222
|
`;
|
|
65367
65223
|
const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
|
|
65368
|
-
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 supported JS/TS source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").
|
|
65224
|
+
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 supported JS/TS source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch 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);
|
|
65369
65225
|
program.action(inspectAction);
|
|
65370
65226
|
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));
|
|
65371
65227
|
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);
|
|
@@ -65415,4 +65271,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
|
|
|
65415
65271
|
export {};
|
|
65416
65272
|
|
|
65417
65273
|
//# sourceMappingURL=cli.js.map
|
|
65418
|
-
//# debugId=
|
|
65274
|
+
//# debugId=9a5c1a3c-7706-5a23-bca4-ddddd2f085af
|
package/dist/index.d.ts
CHANGED
|
@@ -10256,7 +10256,7 @@ declare const buildJsonReport: (input: BuildJsonReportInput) => JsonReportV3$1;
|
|
|
10256
10256
|
* render diff-base mistakes (`GitBaseBranchInvalid` /
|
|
10257
10257
|
* `GitBaseBranchMissing`) as clean user errors instead of crashes.
|
|
10258
10258
|
*/
|
|
10259
|
-
declare const getDiffInfo: (directory: string, explicitBaseBranch?: string
|
|
10259
|
+
declare const getDiffInfo: (directory: string, explicitBaseBranch?: string) => Promise<DiffInfo | null>;
|
|
10260
10260
|
declare const filterSourceFiles: (filePaths: string[]) => string[];
|
|
10261
10261
|
/**
|
|
10262
10262
|
* Programmatic façade over `Git.changedLineRanges` (the `lines` scope). Diffs
|
package/dist/index.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]="11364a34-6c8b-5bd3-b9e8-aaa7c0ea264c")}catch(e){}}();
|
|
3
3
|
import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
@@ -36366,49 +36366,6 @@ const assignFixGroups = (diagnostics) => {
|
|
|
36366
36366
|
};
|
|
36367
36367
|
});
|
|
36368
36368
|
};
|
|
36369
|
-
const DERIVED_STATE_RULE_PRIORITY = new Map([
|
|
36370
|
-
["no-initialize-state", 0],
|
|
36371
|
-
["no-adjust-state-on-prop-change", 1],
|
|
36372
|
-
["no-derived-state", 2],
|
|
36373
|
-
["no-derived-state-effect", 3]
|
|
36374
|
-
]);
|
|
36375
|
-
const buildDiagnosticSiteKey = (diagnostic) => `${diagnostic.filePath}\u0000${diagnostic.line}\u0000${diagnostic.column}`;
|
|
36376
|
-
const isReactDoctorRulesOfHooksDiagnostic = (diagnostic) => diagnostic.plugin === "react-doctor" && diagnostic.rule === "rules-of-hooks";
|
|
36377
|
-
const isReactCompilerHooksDiagnostic = (diagnostic) => diagnostic.plugin === "react-hooks-js" && diagnostic.rule === "hooks";
|
|
36378
|
-
const doDiagnosticSpansOverlap = (first, second) => {
|
|
36379
|
-
if (first.filePath !== second.filePath || first.plugin !== second.plugin) return false;
|
|
36380
|
-
if (first.offset !== void 0 && second.offset !== void 0) {
|
|
36381
|
-
const firstEnd = first.offset + Math.max(first.length ?? 1, 1);
|
|
36382
|
-
const secondEnd = second.offset + Math.max(second.length ?? 1, 1);
|
|
36383
|
-
return first.offset < secondEnd && second.offset < firstEnd;
|
|
36384
|
-
}
|
|
36385
|
-
const firstEndLine = first.endLine ?? first.line;
|
|
36386
|
-
const secondEndLine = second.endLine ?? second.line;
|
|
36387
|
-
return first.line <= secondEndLine && second.line <= firstEndLine;
|
|
36388
|
-
};
|
|
36389
|
-
const keepHighestSeverity = (survivingDiagnostic, collapsedDiagnostic) => collapsedDiagnostic.severity === "error" && survivingDiagnostic.severity !== "error" ? {
|
|
36390
|
-
...survivingDiagnostic,
|
|
36391
|
-
severity: "error"
|
|
36392
|
-
} : survivingDiagnostic;
|
|
36393
|
-
const dedupeRelatedDiagnostics = (diagnostics) => {
|
|
36394
|
-
const reactDoctorHookSites = new Set(diagnostics.filter(isReactDoctorRulesOfHooksDiagnostic).map(buildDiagnosticSiteKey));
|
|
36395
|
-
const uniqueDiagnostics = [];
|
|
36396
|
-
for (const diagnostic of diagnostics) {
|
|
36397
|
-
if (isReactCompilerHooksDiagnostic(diagnostic) && reactDoctorHookSites.has(buildDiagnosticSiteKey(diagnostic))) continue;
|
|
36398
|
-
const priority = DERIVED_STATE_RULE_PRIORITY.get(diagnostic.rule);
|
|
36399
|
-
if (priority !== void 0) {
|
|
36400
|
-
const overlappingDiagnosticIndex = uniqueDiagnostics.findIndex((candidate) => candidate.rule !== diagnostic.rule && DERIVED_STATE_RULE_PRIORITY.has(candidate.rule) && doDiagnosticSpansOverlap(candidate, diagnostic));
|
|
36401
|
-
if (overlappingDiagnosticIndex >= 0) {
|
|
36402
|
-
const existingDiagnostic = uniqueDiagnostics[overlappingDiagnosticIndex];
|
|
36403
|
-
const existingPriority = existingDiagnostic ? DERIVED_STATE_RULE_PRIORITY.get(existingDiagnostic.rule) : void 0;
|
|
36404
|
-
if (existingDiagnostic && existingPriority !== void 0) uniqueDiagnostics[overlappingDiagnosticIndex] = priority < existingPriority ? keepHighestSeverity(diagnostic, existingDiagnostic) : keepHighestSeverity(existingDiagnostic, diagnostic);
|
|
36405
|
-
continue;
|
|
36406
|
-
}
|
|
36407
|
-
}
|
|
36408
|
-
uniqueDiagnostics.push(diagnostic);
|
|
36409
|
-
}
|
|
36410
|
-
return uniqueDiagnostics;
|
|
36411
|
-
};
|
|
36412
36369
|
const compareStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
36413
36370
|
const sortDiagnosticsStable = (diagnostics) => [...diagnostics].sort((left, right) => compareStrings(left.filePath, right.filePath) || left.line - right.line || left.column - right.column || compareStrings(left.plugin, right.plugin) || compareStrings(left.rule, right.rule) || compareStrings(left.severity, right.severity) || compareStrings(left.message, right.message));
|
|
36414
36371
|
const getDirectDependencyNames = (packageJson) => new Set([...Object.keys(packageJson.dependencies ?? {}), ...Object.keys(packageJson.devDependencies ?? {})]);
|
|
@@ -38622,7 +38579,6 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
38622
38579
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
38623
38580
|
};
|
|
38624
38581
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
38625
|
-
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
38626
38582
|
/**
|
|
38627
38583
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
38628
38584
|
* behind a `Context.Service`. The production layer (`layerNode`)
|
|
@@ -38693,14 +38649,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38693
38649
|
args,
|
|
38694
38650
|
directory
|
|
38695
38651
|
});
|
|
38696
|
-
const listUntrackedFilePaths = (directory, includePaths = []) => runGit(directory, [
|
|
38697
|
-
"ls-files",
|
|
38698
|
-
"-z",
|
|
38699
|
-
"--others",
|
|
38700
|
-
"--exclude-standard",
|
|
38701
|
-
...includePaths.length > 0 ? ["--", ...includePaths] : []
|
|
38702
|
-
]).pipe(map$3((result) => result.status === 0 ? splitNullSeparated(result.stdout) : null));
|
|
38703
|
-
const mergeUntracked = (directory, trackedFilePaths, includeUntracked) => includeUntracked ? listUntrackedFilePaths(directory).pipe(map$3((untracked) => untracked === null ? trackedFilePaths : [...new Set([...trackedFilePaths, ...untracked])])) : succeed$2(trackedFilePaths);
|
|
38704
38652
|
const currentBranch = (directory) => runGit(directory, [
|
|
38705
38653
|
"rev-parse",
|
|
38706
38654
|
"--abbrev-ref",
|
|
@@ -38823,7 +38771,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38823
38771
|
githubViewerPermission,
|
|
38824
38772
|
branchExists,
|
|
38825
38773
|
mergeBase,
|
|
38826
|
-
diffSelection: ({ directory, explicitBaseBranch
|
|
38774
|
+
diffSelection: ({ directory, explicitBaseBranch }) => gen(function* () {
|
|
38827
38775
|
if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
|
|
38828
38776
|
if (explicitBaseBranch !== void 0) {
|
|
38829
38777
|
const range = parseGitDiffRange(explicitBaseBranch);
|
|
@@ -38852,7 +38800,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38852
38800
|
"HEAD"
|
|
38853
38801
|
]);
|
|
38854
38802
|
if (uncommitted.status !== 0) return null;
|
|
38855
|
-
const files =
|
|
38803
|
+
const files = splitNullSeparated(uncommitted.stdout);
|
|
38856
38804
|
if (files.length === 0) return null;
|
|
38857
38805
|
return {
|
|
38858
38806
|
currentBranch: resolvedCurrentBranch,
|
|
@@ -38882,7 +38830,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38882
38830
|
currentBranch: resolvedCurrentBranch,
|
|
38883
38831
|
baseBranch,
|
|
38884
38832
|
diffBaseRef: mergeBaseRef,
|
|
38885
|
-
changedFiles:
|
|
38833
|
+
changedFiles: splitNullSeparated(diff.stdout),
|
|
38886
38834
|
isCurrentChanges: false
|
|
38887
38835
|
};
|
|
38888
38836
|
}).pipe(withSpan("Git.diffSelection")),
|
|
@@ -38928,7 +38876,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38928
38876
|
stdout: result.stdout
|
|
38929
38877
|
};
|
|
38930
38878
|
}).pipe(withSpan("Git.grep")),
|
|
38931
|
-
changedLineRanges: ({ directory, baseRef, cached, files
|
|
38879
|
+
changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
|
|
38932
38880
|
if (files.length === 0) return [];
|
|
38933
38881
|
if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
|
|
38934
38882
|
const result = yield* runGit(directory, [
|
|
@@ -38942,14 +38890,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38942
38890
|
...files
|
|
38943
38891
|
]);
|
|
38944
38892
|
if (result.status !== 0) return null;
|
|
38945
|
-
|
|
38946
|
-
if (cached || !includeUntracked) return changedLineRanges;
|
|
38947
|
-
const untrackedFilePaths = yield* listUntrackedFilePaths(directory, files);
|
|
38948
|
-
if (untrackedFilePaths === null) return changedLineRanges;
|
|
38949
|
-
return [...changedLineRanges, ...untrackedFilePaths.map((file) => ({
|
|
38950
|
-
file,
|
|
38951
|
-
ranges: [[1, UNTRACKED_FILE_LAST_LINE]]
|
|
38952
|
-
}))];
|
|
38893
|
+
return parseChangedLineRanges(result.stdout);
|
|
38953
38894
|
}).pipe(catch_$1((error) => error.reason._tag === "GitInvocationFailed" ? succeed$2(null) : fail$4(error)), withSpan("Git.changedLineRanges"))
|
|
38954
38895
|
});
|
|
38955
38896
|
})).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
|
|
@@ -39534,13 +39475,13 @@ const encodeSidecarFileEntry = (entry) => ({
|
|
|
39534
39475
|
diagnostics: entry.diagnostics
|
|
39535
39476
|
});
|
|
39536
39477
|
const emptyCache = () => ({
|
|
39537
|
-
version:
|
|
39478
|
+
version: 1,
|
|
39538
39479
|
rulesets: {}
|
|
39539
39480
|
});
|
|
39540
39481
|
const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
|
|
39541
39482
|
const entries = /* @__PURE__ */ new Map();
|
|
39542
39483
|
const persisted = failOpenReadJson(cacheFilePath, emptyCache());
|
|
39543
|
-
if (persisted.version !==
|
|
39484
|
+
if (persisted.version !== 1 || !isRecord(persisted.rulesets)) return entries;
|
|
39544
39485
|
const bucket = persisted.rulesets[rulesetHash];
|
|
39545
39486
|
if (!isRecord(bucket) || !isRecord(bucket.files)) return entries;
|
|
39546
39487
|
for (const [fileKey, rawEntry] of Object.entries(bucket.files)) {
|
|
@@ -39560,7 +39501,7 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
39560
39501
|
},
|
|
39561
39502
|
persist: () => {
|
|
39562
39503
|
const onDisk = failOpenReadJson(cacheFilePath, emptyCache());
|
|
39563
|
-
const rulesets = onDisk.version ===
|
|
39504
|
+
const rulesets = onDisk.version === 1 && isRecord(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
39564
39505
|
const existingBucket = rulesets[rulesetHash];
|
|
39565
39506
|
const existingFiles = isRecord(existingBucket) && isRecord(existingBucket.files) ? existingBucket.files : {};
|
|
39566
39507
|
const ourFiles = {};
|
|
@@ -39574,7 +39515,7 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
39574
39515
|
files: Object.fromEntries(cappedEntries)
|
|
39575
39516
|
};
|
|
39576
39517
|
atomicWriteJson(cacheFilePath, {
|
|
39577
|
-
version:
|
|
39518
|
+
version: 1,
|
|
39578
39519
|
rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
|
|
39579
39520
|
});
|
|
39580
39521
|
}
|
|
@@ -39625,6 +39566,23 @@ const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
|
39625
39566
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
39626
39567
|
return null;
|
|
39627
39568
|
};
|
|
39569
|
+
const DERIVED_STATE_RULE_PRIORITY = new Map([
|
|
39570
|
+
["no-initialize-state", 0],
|
|
39571
|
+
["no-adjust-state-on-prop-change", 1],
|
|
39572
|
+
["no-derived-state", 2],
|
|
39573
|
+
["no-derived-state-effect", 3]
|
|
39574
|
+
]);
|
|
39575
|
+
const doDiagnosticSpansOverlap = (first, second) => {
|
|
39576
|
+
if (first.filePath !== second.filePath || first.plugin !== second.plugin) return false;
|
|
39577
|
+
if (first.offset !== void 0 && second.offset !== void 0) {
|
|
39578
|
+
const firstEnd = first.offset + Math.max(first.length ?? 1, 1);
|
|
39579
|
+
const secondEnd = second.offset + Math.max(second.length ?? 1, 1);
|
|
39580
|
+
return first.offset < secondEnd && second.offset < firstEnd;
|
|
39581
|
+
}
|
|
39582
|
+
const firstEndLine = first.endLine ?? first.line;
|
|
39583
|
+
const secondEndLine = second.endLine ?? second.line;
|
|
39584
|
+
return first.line <= secondEndLine && second.line <= firstEndLine;
|
|
39585
|
+
};
|
|
39628
39586
|
const dedupeDiagnostics = (diagnostics) => {
|
|
39629
39587
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
39630
39588
|
const uniqueDiagnostics = [];
|
|
@@ -39632,6 +39590,16 @@ const dedupeDiagnostics = (diagnostics) => {
|
|
|
39632
39590
|
const key = `${diagnostic.filePath}\u0000${diagnostic.line}\u0000${diagnostic.column}\u0000${diagnostic.plugin}\u0000${diagnostic.rule}\u0000${diagnostic.severity}\u0000${diagnostic.message}`;
|
|
39633
39591
|
if (seenKeys.has(key)) continue;
|
|
39634
39592
|
seenKeys.add(key);
|
|
39593
|
+
const priority = DERIVED_STATE_RULE_PRIORITY.get(diagnostic.rule);
|
|
39594
|
+
if (priority !== void 0) {
|
|
39595
|
+
const overlappingDiagnosticIndex = uniqueDiagnostics.findIndex((candidate) => candidate.rule !== diagnostic.rule && candidate.severity === diagnostic.severity && DERIVED_STATE_RULE_PRIORITY.has(candidate.rule) && doDiagnosticSpansOverlap(candidate, diagnostic));
|
|
39596
|
+
if (overlappingDiagnosticIndex >= 0) {
|
|
39597
|
+
const existingDiagnostic = uniqueDiagnostics[overlappingDiagnosticIndex];
|
|
39598
|
+
const existingPriority = existingDiagnostic ? DERIVED_STATE_RULE_PRIORITY.get(existingDiagnostic.rule) : void 0;
|
|
39599
|
+
if (existingPriority !== void 0 && priority < existingPriority) uniqueDiagnostics[overlappingDiagnosticIndex] = diagnostic;
|
|
39600
|
+
continue;
|
|
39601
|
+
}
|
|
39602
|
+
}
|
|
39635
39603
|
uniqueDiagnostics.push(diagnostic);
|
|
39636
39604
|
}
|
|
39637
39605
|
return uniqueDiagnostics;
|
|
@@ -40431,11 +40399,11 @@ const buildRelatedLocations = (labels, filePath) => {
|
|
|
40431
40399
|
}
|
|
40432
40400
|
return related;
|
|
40433
40401
|
};
|
|
40434
|
-
const
|
|
40435
|
-
|
|
40436
|
-
const
|
|
40437
|
-
|
|
40438
|
-
|
|
40402
|
+
const isOxlintOutput = (value) => {
|
|
40403
|
+
if (typeof value !== "object" || value === null) return false;
|
|
40404
|
+
const candidate = value;
|
|
40405
|
+
return Array.isArray(candidate.diagnostics);
|
|
40406
|
+
};
|
|
40439
40407
|
/**
|
|
40440
40408
|
* Parses one oxlint subprocess's stdout into a flat `Diagnostic[]`.
|
|
40441
40409
|
* Tolerates the leading-notice-line shape oxlint sometimes prints
|
|
@@ -40454,8 +40422,6 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
40454
40422
|
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
40455
40423
|
}
|
|
40456
40424
|
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
40457
|
-
const engineFailureDiagnostic = parsed.diagnostics.find(isEngineFailureDiagnostic);
|
|
40458
|
-
if (engineFailureDiagnostic !== void 0) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: JSON.stringify(engineFailureDiagnostic).slice(0, 600) }) });
|
|
40459
40425
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
40460
40426
|
const sourceBufferCache = /* @__PURE__ */ new Map();
|
|
40461
40427
|
const sourceLinesCache = /* @__PURE__ */ new Map();
|
|
@@ -40490,7 +40456,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
40490
40456
|
minifiedFileCache.set(absolutePath, minified);
|
|
40491
40457
|
return minified;
|
|
40492
40458
|
};
|
|
40493
|
-
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) =>
|
|
40459
|
+
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
40494
40460
|
const { plugin, rule } = parseRuleCode(diagnostic.code);
|
|
40495
40461
|
const primaryLabel = diagnostic.labels[0];
|
|
40496
40462
|
const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
|
|
@@ -42325,8 +42291,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42325
42291
|
respectInlineDisables: input.respectInlineDisables,
|
|
42326
42292
|
showWarnings
|
|
42327
42293
|
});
|
|
42328
|
-
const
|
|
42329
|
-
const applyPerElementPipeline = (rawStream) => filterPerElementPipeline(rawStream).pipe(tap((diagnostic) => reporterService.emit(diagnostic)));
|
|
42294
|
+
const applyPerElementPipeline = (rawStream) => rawStream.pipe(filterMap(filterMapNullable(transform.apply)), tap((diagnostic) => reporterService.emit(diagnostic)));
|
|
42330
42295
|
const envCollected = yield* runCollect(applyPerElementPipeline(fromIterable$1(isDiffMode ? [] : [
|
|
42331
42296
|
...checkReducedMotion(scanDirectory),
|
|
42332
42297
|
...checkPnpmHardening(scanDirectory),
|
|
@@ -42455,7 +42420,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42455
42420
|
});
|
|
42456
42421
|
return empty$4;
|
|
42457
42422
|
}))));
|
|
42458
|
-
const lintCollected =
|
|
42423
|
+
const lintCollected = yield* runCollect(applyPerElementPipeline(shouldOverlapDeadCode ? baseLintStream.pipe(provideService(OxlintConcurrency, lintConcurrency)) : baseLintStream)).pipe(timeoutOption(lintPhaseTimeoutMs), flatMap$2(match$3({
|
|
42459
42424
|
onNone: () => set(lintFailure, {
|
|
42460
42425
|
didFail: true,
|
|
42461
42426
|
reason: `Lint analysis exceeded ${lintPhaseTimeoutMs / MILLISECONDS_PER_SECOND}s and was skipped.`,
|
|
@@ -42463,8 +42428,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42463
42428
|
reasonKind: null
|
|
42464
42429
|
}).pipe(as([])),
|
|
42465
42430
|
onSome: succeed$2
|
|
42466
|
-
})))
|
|
42467
|
-
yield* forEach$1(lintCollected, reporterService.emit, { discard: true });
|
|
42431
|
+
})));
|
|
42468
42432
|
const lintFailureState = yield* get$2(lintFailure);
|
|
42469
42433
|
yield* afterLint(lintFailureState.didFail);
|
|
42470
42434
|
if (lintFailureState.didFail) yield* scanProgress.fail(formatLintFailText(lintFailureState.reasonTag, process.version));
|
|
@@ -42984,11 +42948,10 @@ const buildSkippedChecks = (input) => {
|
|
|
42984
42948
|
* render diff-base mistakes (`GitBaseBranchInvalid` /
|
|
42985
42949
|
* `GitBaseBranchMissing`) as clean user errors instead of crashes.
|
|
42986
42950
|
*/
|
|
42987
|
-
const getDiffInfo = (directory, explicitBaseBranch
|
|
42951
|
+
const getDiffInfo = (directory, explicitBaseBranch) => runPromise(gen(function* () {
|
|
42988
42952
|
const selection = yield* (yield* Git).diffSelection({
|
|
42989
42953
|
directory,
|
|
42990
|
-
explicitBaseBranch
|
|
42991
|
-
includeUntracked
|
|
42954
|
+
explicitBaseBranch
|
|
42992
42955
|
});
|
|
42993
42956
|
if (selection === null) return null;
|
|
42994
42957
|
return {
|
|
@@ -43278,4 +43241,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
43278
43241
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
43279
43242
|
|
|
43280
43243
|
//# sourceMappingURL=index.js.map
|
|
43281
|
-
//# debugId=
|
|
43244
|
+
//# debugId=11364a34-6c8b-5bd3-b9e8-aaa7c0ea264c
|
package/dist/lsp.js
CHANGED
|
@@ -36344,49 +36344,6 @@ const assignFixGroups = (diagnostics) => {
|
|
|
36344
36344
|
};
|
|
36345
36345
|
});
|
|
36346
36346
|
};
|
|
36347
|
-
const DERIVED_STATE_RULE_PRIORITY = new Map([
|
|
36348
|
-
["no-initialize-state", 0],
|
|
36349
|
-
["no-adjust-state-on-prop-change", 1],
|
|
36350
|
-
["no-derived-state", 2],
|
|
36351
|
-
["no-derived-state-effect", 3]
|
|
36352
|
-
]);
|
|
36353
|
-
const buildDiagnosticSiteKey = (diagnostic) => `${diagnostic.filePath}\u0000${diagnostic.line}\u0000${diagnostic.column}`;
|
|
36354
|
-
const isReactDoctorRulesOfHooksDiagnostic = (diagnostic) => diagnostic.plugin === "react-doctor" && diagnostic.rule === "rules-of-hooks";
|
|
36355
|
-
const isReactCompilerHooksDiagnostic = (diagnostic) => diagnostic.plugin === "react-hooks-js" && diagnostic.rule === "hooks";
|
|
36356
|
-
const doDiagnosticSpansOverlap = (first, second) => {
|
|
36357
|
-
if (first.filePath !== second.filePath || first.plugin !== second.plugin) return false;
|
|
36358
|
-
if (first.offset !== void 0 && second.offset !== void 0) {
|
|
36359
|
-
const firstEnd = first.offset + Math.max(first.length ?? 1, 1);
|
|
36360
|
-
const secondEnd = second.offset + Math.max(second.length ?? 1, 1);
|
|
36361
|
-
return first.offset < secondEnd && second.offset < firstEnd;
|
|
36362
|
-
}
|
|
36363
|
-
const firstEndLine = first.endLine ?? first.line;
|
|
36364
|
-
const secondEndLine = second.endLine ?? second.line;
|
|
36365
|
-
return first.line <= secondEndLine && second.line <= firstEndLine;
|
|
36366
|
-
};
|
|
36367
|
-
const keepHighestSeverity = (survivingDiagnostic, collapsedDiagnostic) => collapsedDiagnostic.severity === "error" && survivingDiagnostic.severity !== "error" ? {
|
|
36368
|
-
...survivingDiagnostic,
|
|
36369
|
-
severity: "error"
|
|
36370
|
-
} : survivingDiagnostic;
|
|
36371
|
-
const dedupeRelatedDiagnostics = (diagnostics) => {
|
|
36372
|
-
const reactDoctorHookSites = new Set(diagnostics.filter(isReactDoctorRulesOfHooksDiagnostic).map(buildDiagnosticSiteKey));
|
|
36373
|
-
const uniqueDiagnostics = [];
|
|
36374
|
-
for (const diagnostic of diagnostics) {
|
|
36375
|
-
if (isReactCompilerHooksDiagnostic(diagnostic) && reactDoctorHookSites.has(buildDiagnosticSiteKey(diagnostic))) continue;
|
|
36376
|
-
const priority = DERIVED_STATE_RULE_PRIORITY.get(diagnostic.rule);
|
|
36377
|
-
if (priority !== void 0) {
|
|
36378
|
-
const overlappingDiagnosticIndex = uniqueDiagnostics.findIndex((candidate) => candidate.rule !== diagnostic.rule && DERIVED_STATE_RULE_PRIORITY.has(candidate.rule) && doDiagnosticSpansOverlap(candidate, diagnostic));
|
|
36379
|
-
if (overlappingDiagnosticIndex >= 0) {
|
|
36380
|
-
const existingDiagnostic = uniqueDiagnostics[overlappingDiagnosticIndex];
|
|
36381
|
-
const existingPriority = existingDiagnostic ? DERIVED_STATE_RULE_PRIORITY.get(existingDiagnostic.rule) : void 0;
|
|
36382
|
-
if (existingDiagnostic && existingPriority !== void 0) uniqueDiagnostics[overlappingDiagnosticIndex] = priority < existingPriority ? keepHighestSeverity(diagnostic, existingDiagnostic) : keepHighestSeverity(existingDiagnostic, diagnostic);
|
|
36383
|
-
continue;
|
|
36384
|
-
}
|
|
36385
|
-
}
|
|
36386
|
-
uniqueDiagnostics.push(diagnostic);
|
|
36387
|
-
}
|
|
36388
|
-
return uniqueDiagnostics;
|
|
36389
|
-
};
|
|
36390
36347
|
const compareStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
36391
36348
|
const sortDiagnosticsStable = (diagnostics) => [...diagnostics].sort((left, right) => compareStrings(left.filePath, right.filePath) || left.line - right.line || left.column - right.column || compareStrings(left.plugin, right.plugin) || compareStrings(left.rule, right.rule) || compareStrings(left.severity, right.severity) || compareStrings(left.message, right.message));
|
|
36392
36349
|
const getDirectDependencyNames = (packageJson) => new Set([...Object.keys(packageJson.dependencies ?? {}), ...Object.keys(packageJson.devDependencies ?? {})]);
|
|
@@ -38600,7 +38557,6 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
38600
38557
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
38601
38558
|
};
|
|
38602
38559
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
38603
|
-
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
38604
38560
|
/**
|
|
38605
38561
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
38606
38562
|
* behind a `Context.Service`. The production layer (`layerNode`)
|
|
@@ -38671,14 +38627,6 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38671
38627
|
args,
|
|
38672
38628
|
directory
|
|
38673
38629
|
});
|
|
38674
|
-
const listUntrackedFilePaths = (directory, includePaths = []) => runGit(directory, [
|
|
38675
|
-
"ls-files",
|
|
38676
|
-
"-z",
|
|
38677
|
-
"--others",
|
|
38678
|
-
"--exclude-standard",
|
|
38679
|
-
...includePaths.length > 0 ? ["--", ...includePaths] : []
|
|
38680
|
-
]).pipe(map$3((result) => result.status === 0 ? splitNullSeparated(result.stdout) : null));
|
|
38681
|
-
const mergeUntracked = (directory, trackedFilePaths, includeUntracked) => includeUntracked ? listUntrackedFilePaths(directory).pipe(map$3((untracked) => untracked === null ? trackedFilePaths : [...new Set([...trackedFilePaths, ...untracked])])) : succeed$2(trackedFilePaths);
|
|
38682
38630
|
const currentBranch = (directory) => runGit(directory, [
|
|
38683
38631
|
"rev-parse",
|
|
38684
38632
|
"--abbrev-ref",
|
|
@@ -38801,7 +38749,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38801
38749
|
githubViewerPermission,
|
|
38802
38750
|
branchExists,
|
|
38803
38751
|
mergeBase,
|
|
38804
|
-
diffSelection: ({ directory, explicitBaseBranch
|
|
38752
|
+
diffSelection: ({ directory, explicitBaseBranch }) => gen(function* () {
|
|
38805
38753
|
if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
|
|
38806
38754
|
if (explicitBaseBranch !== void 0) {
|
|
38807
38755
|
const range = parseGitDiffRange(explicitBaseBranch);
|
|
@@ -38830,7 +38778,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38830
38778
|
"HEAD"
|
|
38831
38779
|
]);
|
|
38832
38780
|
if (uncommitted.status !== 0) return null;
|
|
38833
|
-
const files =
|
|
38781
|
+
const files = splitNullSeparated(uncommitted.stdout);
|
|
38834
38782
|
if (files.length === 0) return null;
|
|
38835
38783
|
return {
|
|
38836
38784
|
currentBranch: resolvedCurrentBranch,
|
|
@@ -38860,7 +38808,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38860
38808
|
currentBranch: resolvedCurrentBranch,
|
|
38861
38809
|
baseBranch,
|
|
38862
38810
|
diffBaseRef: mergeBaseRef,
|
|
38863
|
-
changedFiles:
|
|
38811
|
+
changedFiles: splitNullSeparated(diff.stdout),
|
|
38864
38812
|
isCurrentChanges: false
|
|
38865
38813
|
};
|
|
38866
38814
|
}).pipe(withSpan("Git.diffSelection")),
|
|
@@ -38906,7 +38854,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38906
38854
|
stdout: result.stdout
|
|
38907
38855
|
};
|
|
38908
38856
|
}).pipe(withSpan("Git.grep")),
|
|
38909
|
-
changedLineRanges: ({ directory, baseRef, cached, files
|
|
38857
|
+
changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
|
|
38910
38858
|
if (files.length === 0) return [];
|
|
38911
38859
|
if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
|
|
38912
38860
|
const result = yield* runGit(directory, [
|
|
@@ -38920,14 +38868,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
38920
38868
|
...files
|
|
38921
38869
|
]);
|
|
38922
38870
|
if (result.status !== 0) return null;
|
|
38923
|
-
|
|
38924
|
-
if (cached || !includeUntracked) return changedLineRanges;
|
|
38925
|
-
const untrackedFilePaths = yield* listUntrackedFilePaths(directory, files);
|
|
38926
|
-
if (untrackedFilePaths === null) return changedLineRanges;
|
|
38927
|
-
return [...changedLineRanges, ...untrackedFilePaths.map((file) => ({
|
|
38928
|
-
file,
|
|
38929
|
-
ranges: [[1, UNTRACKED_FILE_LAST_LINE]]
|
|
38930
|
-
}))];
|
|
38871
|
+
return parseChangedLineRanges(result.stdout);
|
|
38931
38872
|
}).pipe(catch_$1((error) => error.reason._tag === "GitInvocationFailed" ? succeed$2(null) : fail$4(error)), withSpan("Git.changedLineRanges"))
|
|
38932
38873
|
});
|
|
38933
38874
|
})).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
|
|
@@ -39512,13 +39453,13 @@ const encodeSidecarFileEntry = (entry) => ({
|
|
|
39512
39453
|
diagnostics: entry.diagnostics
|
|
39513
39454
|
});
|
|
39514
39455
|
const emptyCache = () => ({
|
|
39515
|
-
version:
|
|
39456
|
+
version: 1,
|
|
39516
39457
|
rulesets: {}
|
|
39517
39458
|
});
|
|
39518
39459
|
const loadRulesetEntries = (cacheFilePath, rulesetHash) => {
|
|
39519
39460
|
const entries = /* @__PURE__ */ new Map();
|
|
39520
39461
|
const persisted = failOpenReadJson(cacheFilePath, emptyCache());
|
|
39521
|
-
if (persisted.version !==
|
|
39462
|
+
if (persisted.version !== 1 || !isRecord(persisted.rulesets)) return entries;
|
|
39522
39463
|
const bucket = persisted.rulesets[rulesetHash];
|
|
39523
39464
|
if (!isRecord(bucket) || !isRecord(bucket.files)) return entries;
|
|
39524
39465
|
for (const [fileKey, rawEntry] of Object.entries(bucket.files)) {
|
|
@@ -39538,7 +39479,7 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
39538
39479
|
},
|
|
39539
39480
|
persist: () => {
|
|
39540
39481
|
const onDisk = failOpenReadJson(cacheFilePath, emptyCache());
|
|
39541
|
-
const rulesets = onDisk.version ===
|
|
39482
|
+
const rulesets = onDisk.version === 1 && isRecord(onDisk.rulesets) ? { ...onDisk.rulesets } : {};
|
|
39542
39483
|
const existingBucket = rulesets[rulesetHash];
|
|
39543
39484
|
const existingFiles = isRecord(existingBucket) && isRecord(existingBucket.files) ? existingBucket.files : {};
|
|
39544
39485
|
const ourFiles = {};
|
|
@@ -39552,7 +39493,7 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
|
|
|
39552
39493
|
files: Object.fromEntries(cappedEntries)
|
|
39553
39494
|
};
|
|
39554
39495
|
atomicWriteJson(cacheFilePath, {
|
|
39555
|
-
version:
|
|
39496
|
+
version: 1,
|
|
39556
39497
|
rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
|
|
39557
39498
|
});
|
|
39558
39499
|
}
|
|
@@ -39603,6 +39544,23 @@ const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
|
39603
39544
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
39604
39545
|
return null;
|
|
39605
39546
|
};
|
|
39547
|
+
const DERIVED_STATE_RULE_PRIORITY = new Map([
|
|
39548
|
+
["no-initialize-state", 0],
|
|
39549
|
+
["no-adjust-state-on-prop-change", 1],
|
|
39550
|
+
["no-derived-state", 2],
|
|
39551
|
+
["no-derived-state-effect", 3]
|
|
39552
|
+
]);
|
|
39553
|
+
const doDiagnosticSpansOverlap = (first, second) => {
|
|
39554
|
+
if (first.filePath !== second.filePath || first.plugin !== second.plugin) return false;
|
|
39555
|
+
if (first.offset !== void 0 && second.offset !== void 0) {
|
|
39556
|
+
const firstEnd = first.offset + Math.max(first.length ?? 1, 1);
|
|
39557
|
+
const secondEnd = second.offset + Math.max(second.length ?? 1, 1);
|
|
39558
|
+
return first.offset < secondEnd && second.offset < firstEnd;
|
|
39559
|
+
}
|
|
39560
|
+
const firstEndLine = first.endLine ?? first.line;
|
|
39561
|
+
const secondEndLine = second.endLine ?? second.line;
|
|
39562
|
+
return first.line <= secondEndLine && second.line <= firstEndLine;
|
|
39563
|
+
};
|
|
39606
39564
|
const dedupeDiagnostics = (diagnostics) => {
|
|
39607
39565
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
39608
39566
|
const uniqueDiagnostics = [];
|
|
@@ -39610,6 +39568,16 @@ const dedupeDiagnostics = (diagnostics) => {
|
|
|
39610
39568
|
const key = `${diagnostic.filePath}\u0000${diagnostic.line}\u0000${diagnostic.column}\u0000${diagnostic.plugin}\u0000${diagnostic.rule}\u0000${diagnostic.severity}\u0000${diagnostic.message}`;
|
|
39611
39569
|
if (seenKeys.has(key)) continue;
|
|
39612
39570
|
seenKeys.add(key);
|
|
39571
|
+
const priority = DERIVED_STATE_RULE_PRIORITY.get(diagnostic.rule);
|
|
39572
|
+
if (priority !== void 0) {
|
|
39573
|
+
const overlappingDiagnosticIndex = uniqueDiagnostics.findIndex((candidate) => candidate.rule !== diagnostic.rule && candidate.severity === diagnostic.severity && DERIVED_STATE_RULE_PRIORITY.has(candidate.rule) && doDiagnosticSpansOverlap(candidate, diagnostic));
|
|
39574
|
+
if (overlappingDiagnosticIndex >= 0) {
|
|
39575
|
+
const existingDiagnostic = uniqueDiagnostics[overlappingDiagnosticIndex];
|
|
39576
|
+
const existingPriority = existingDiagnostic ? DERIVED_STATE_RULE_PRIORITY.get(existingDiagnostic.rule) : void 0;
|
|
39577
|
+
if (existingPriority !== void 0 && priority < existingPriority) uniqueDiagnostics[overlappingDiagnosticIndex] = diagnostic;
|
|
39578
|
+
continue;
|
|
39579
|
+
}
|
|
39580
|
+
}
|
|
39613
39581
|
uniqueDiagnostics.push(diagnostic);
|
|
39614
39582
|
}
|
|
39615
39583
|
return uniqueDiagnostics;
|
|
@@ -40409,11 +40377,11 @@ const buildRelatedLocations = (labels, filePath) => {
|
|
|
40409
40377
|
}
|
|
40410
40378
|
return related;
|
|
40411
40379
|
};
|
|
40412
|
-
const
|
|
40413
|
-
|
|
40414
|
-
const
|
|
40415
|
-
|
|
40416
|
-
|
|
40380
|
+
const isOxlintOutput = (value) => {
|
|
40381
|
+
if (typeof value !== "object" || value === null) return false;
|
|
40382
|
+
const candidate = value;
|
|
40383
|
+
return Array.isArray(candidate.diagnostics);
|
|
40384
|
+
};
|
|
40417
40385
|
/**
|
|
40418
40386
|
* Parses one oxlint subprocess's stdout into a flat `Diagnostic[]`.
|
|
40419
40387
|
* Tolerates the leading-notice-line shape oxlint sometimes prints
|
|
@@ -40432,8 +40400,6 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
40432
40400
|
throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
40433
40401
|
}
|
|
40434
40402
|
if (!isOxlintOutput(parsed)) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: stdout.slice(0, 600) }) });
|
|
40435
|
-
const engineFailureDiagnostic = parsed.diagnostics.find(isEngineFailureDiagnostic);
|
|
40436
|
-
if (engineFailureDiagnostic !== void 0) throw new ReactDoctorError({ reason: new OxlintOutputUnparseable({ preview: JSON.stringify(engineFailureDiagnostic).slice(0, 600) }) });
|
|
40437
40403
|
const minifiedFileCache = /* @__PURE__ */ new Map();
|
|
40438
40404
|
const sourceBufferCache = /* @__PURE__ */ new Map();
|
|
40439
40405
|
const sourceLinesCache = /* @__PURE__ */ new Map();
|
|
@@ -40468,7 +40434,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
|
|
|
40468
40434
|
minifiedFileCache.set(absolutePath, minified);
|
|
40469
40435
|
return minified;
|
|
40470
40436
|
};
|
|
40471
|
-
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) =>
|
|
40437
|
+
return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
|
|
40472
40438
|
const { plugin, rule } = parseRuleCode(diagnostic.code);
|
|
40473
40439
|
const primaryLabel = diagnostic.labels[0];
|
|
40474
40440
|
const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
|
|
@@ -42303,8 +42269,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42303
42269
|
respectInlineDisables: input.respectInlineDisables,
|
|
42304
42270
|
showWarnings
|
|
42305
42271
|
});
|
|
42306
|
-
const
|
|
42307
|
-
const applyPerElementPipeline = (rawStream) => filterPerElementPipeline(rawStream).pipe(tap((diagnostic) => reporterService.emit(diagnostic)));
|
|
42272
|
+
const applyPerElementPipeline = (rawStream) => rawStream.pipe(filterMap(filterMapNullable(transform.apply)), tap((diagnostic) => reporterService.emit(diagnostic)));
|
|
42308
42273
|
const envCollected = yield* runCollect(applyPerElementPipeline(fromIterable$1(isDiffMode ? [] : [
|
|
42309
42274
|
...checkReducedMotion(scanDirectory),
|
|
42310
42275
|
...checkPnpmHardening(scanDirectory),
|
|
@@ -42433,7 +42398,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42433
42398
|
});
|
|
42434
42399
|
return empty$4;
|
|
42435
42400
|
}))));
|
|
42436
|
-
const lintCollected =
|
|
42401
|
+
const lintCollected = yield* runCollect(applyPerElementPipeline(shouldOverlapDeadCode ? baseLintStream.pipe(provideService(OxlintConcurrency, lintConcurrency)) : baseLintStream)).pipe(timeoutOption(lintPhaseTimeoutMs), flatMap$2(match$3({
|
|
42437
42402
|
onNone: () => set(lintFailure, {
|
|
42438
42403
|
didFail: true,
|
|
42439
42404
|
reason: `Lint analysis exceeded ${lintPhaseTimeoutMs / MILLISECONDS_PER_SECOND}s and was skipped.`,
|
|
@@ -42441,8 +42406,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42441
42406
|
reasonKind: null
|
|
42442
42407
|
}).pipe(as([])),
|
|
42443
42408
|
onSome: succeed$2
|
|
42444
|
-
})))
|
|
42445
|
-
yield* forEach$1(lintCollected, reporterService.emit, { discard: true });
|
|
42409
|
+
})));
|
|
42446
42410
|
const lintFailureState = yield* get$2(lintFailure);
|
|
42447
42411
|
yield* afterLint(lintFailureState.didFail);
|
|
42448
42412
|
if (lintFailureState.didFail) yield* scanProgress.fail(formatLintFailText(lintFailureState.reasonTag, process.version));
|
|
@@ -44560,7 +44524,6 @@ const METRIC = {
|
|
|
44560
44524
|
cliInvoked: "cli.invoked",
|
|
44561
44525
|
cliError: "cli.error",
|
|
44562
44526
|
cliEnvironmentError: "cli.env_error",
|
|
44563
|
-
stagedSnapshotDivergence: "staged.snapshot_divergence",
|
|
44564
44527
|
projectDetected: "project.detected",
|
|
44565
44528
|
projectPathSelected: "project.path_selected",
|
|
44566
44529
|
projectConfigSelected: "project.config_selected",
|
|
@@ -44915,5 +44878,5 @@ const startLanguageServer = () => {
|
|
|
44915
44878
|
};
|
|
44916
44879
|
//#endregion
|
|
44917
44880
|
export { startLanguageServer };
|
|
44918
|
-
!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]="
|
|
44919
|
-
//# debugId=
|
|
44881
|
+
!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]="f9337714-b38f-5f28-ac00-c9d7d79ebaea")}catch(e){}}();
|
|
44882
|
+
//# debugId=f9337714-b38f-5f28-ac00-c9d7d79ebaea
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-doctor",
|
|
3
|
-
"version": "0.7.6-dev.
|
|
3
|
+
"version": "0.7.6-dev.c5a06bd",
|
|
4
4
|
"description": "Your agent writes bad React. This catches it",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"vscode-uri": "^3.1.0",
|
|
67
67
|
"yaml": "^2.9.0",
|
|
68
68
|
"deslop-js": "0.7.6",
|
|
69
|
-
"oxlint-plugin-react-doctor": "0.7.6-dev.
|
|
69
|
+
"oxlint-plugin-react-doctor": "0.7.6-dev.c5a06bd"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/babel__code-frame": "^7.27.0",
|