react-doctor 0.7.4-dev.99ac4ff → 0.7.4-dev.a31f5e8
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/README.md +8 -0
- package/dist/cli.js +276 -79
- package/dist/index.d.ts +47 -5
- package/dist/index.js +251 -64
- package/dist/lsp.js +174 -33
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
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]="95e70e55-12b7-5577-81f3-f5331db7ca53")}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
|
+
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";
|
|
5
6
|
import * as NFS from "node:fs";
|
|
6
7
|
import fs from "node:fs";
|
|
7
8
|
import * as Path from "node:path";
|
|
@@ -9,7 +10,6 @@ import path from "node:path";
|
|
|
9
10
|
import * as NodeChildProcess from "node:child_process";
|
|
10
11
|
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
11
12
|
import ts from "typescript";
|
|
12
|
-
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
13
13
|
import * as OS from "node:os";
|
|
14
14
|
import os from "node:os";
|
|
15
15
|
import { parseJSON5 } from "confbox";
|
|
@@ -19310,12 +19310,45 @@ var Diagnostic = class extends Class("Diagnostic")({
|
|
|
19310
19310
|
relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation)),
|
|
19311
19311
|
fixGroupId: optional(String$1)
|
|
19312
19312
|
}) {};
|
|
19313
|
+
var JsonReportDiagnosticV3 = class extends Class("JsonReportDiagnosticV3")({
|
|
19314
|
+
id: String$1,
|
|
19315
|
+
normalizedFilePath: String$1,
|
|
19316
|
+
filePath: String$1,
|
|
19317
|
+
plugin: String$1,
|
|
19318
|
+
rule: String$1,
|
|
19319
|
+
severity: Severity,
|
|
19320
|
+
tags: ArraySchema(String$1),
|
|
19321
|
+
title: optional(String$1),
|
|
19322
|
+
message: String$1,
|
|
19323
|
+
help: String$1,
|
|
19324
|
+
url: optional(String$1),
|
|
19325
|
+
line: Number$1,
|
|
19326
|
+
column: Number$1,
|
|
19327
|
+
offset: optional(Number$1),
|
|
19328
|
+
length: optional(Number$1),
|
|
19329
|
+
endLine: optional(Number$1),
|
|
19330
|
+
endColumn: optional(Number$1),
|
|
19331
|
+
category: String$1,
|
|
19332
|
+
matchByOccurrence: optional(Boolean$1),
|
|
19333
|
+
fileContext: optional(Literals(["test", "story"])),
|
|
19334
|
+
suppressionHint: optional(String$1),
|
|
19335
|
+
relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation)),
|
|
19336
|
+
fixGroupId: optional(String$1)
|
|
19337
|
+
}) {};
|
|
19338
|
+
/**
|
|
19339
|
+
* Deterministic identity string for a diagnostic. Same diagnostic
|
|
19340
|
+
* across two scans yields the same identity; lets baselines,
|
|
19341
|
+
* suppression files, content-hash caches, and IDE "ignore this"
|
|
19342
|
+
* actions all key off one shared shape.
|
|
19343
|
+
*/
|
|
19344
|
+
const buildDiagnosticIdentity = (input) => `${input.filePath}::${input.line}:${input.column}::${input.plugin}/${input.rule}`;
|
|
19313
19345
|
const JsonReportMode = Literals([
|
|
19314
19346
|
"full",
|
|
19315
19347
|
"diff",
|
|
19316
19348
|
"staged",
|
|
19317
19349
|
"baseline"
|
|
19318
19350
|
]);
|
|
19351
|
+
const Framework = Literals(FRAMEWORK_TOKENS);
|
|
19319
19352
|
var JsonReportSummary = class extends Class("JsonReportSummary")({
|
|
19320
19353
|
errorCount: Number$1,
|
|
19321
19354
|
warningCount: Number$1,
|
|
@@ -19353,13 +19386,22 @@ var JsonReportProjectEntry = class extends Class("JsonReportProjectEntry")({
|
|
|
19353
19386
|
scannedFileCount: optional(Number$1),
|
|
19354
19387
|
elapsedMilliseconds: Number$1
|
|
19355
19388
|
}) {};
|
|
19356
|
-
|
|
19357
|
-
|
|
19358
|
-
|
|
19359
|
-
|
|
19360
|
-
|
|
19361
|
-
|
|
19362
|
-
|
|
19389
|
+
var JsonReportProjectEntryV3 = class extends Class("JsonReportProjectEntryV3")({
|
|
19390
|
+
directory: String$1,
|
|
19391
|
+
packageRoot: String$1,
|
|
19392
|
+
framework: Framework,
|
|
19393
|
+
project: Unknown,
|
|
19394
|
+
diagnostics: ArraySchema(JsonReportDiagnosticV3),
|
|
19395
|
+
score: Unknown,
|
|
19396
|
+
skippedChecks: ArraySchema(String$1),
|
|
19397
|
+
skippedCheckReasons: optional(Record$1(String$1, String$1)),
|
|
19398
|
+
analyzedFiles: ArraySchema(String$1),
|
|
19399
|
+
analyzedFileCount: Number$1,
|
|
19400
|
+
complete: Boolean$1,
|
|
19401
|
+
scannedFileCount: optional(Number$1),
|
|
19402
|
+
elapsedMilliseconds: Number$1
|
|
19403
|
+
}) {};
|
|
19404
|
+
/** Original full, diff, and staged report contract. */
|
|
19363
19405
|
var JsonReportV1 = class extends Class("JsonReportV1")({
|
|
19364
19406
|
schemaVersion: Literal(1),
|
|
19365
19407
|
version: String$1,
|
|
@@ -19420,7 +19462,27 @@ var JsonReportV2 = class extends Class("JsonReportV2")({
|
|
|
19420
19462
|
elapsedMilliseconds: Number$1,
|
|
19421
19463
|
error: NullOr(JsonReportError)
|
|
19422
19464
|
}) {};
|
|
19423
|
-
|
|
19465
|
+
var JsonReportV3 = class extends Class("JsonReportV3")({
|
|
19466
|
+
schemaVersion: Literal(3),
|
|
19467
|
+
version: String$1,
|
|
19468
|
+
ok: Boolean$1,
|
|
19469
|
+
directory: String$1,
|
|
19470
|
+
mode: JsonReportMode,
|
|
19471
|
+
baselineDegraded: optional(Boolean$1),
|
|
19472
|
+
reactDetected: optional(Boolean$1),
|
|
19473
|
+
diff: NullOr(JsonReportDiffInfo),
|
|
19474
|
+
baseline: optional(JsonReportBaseline),
|
|
19475
|
+
projects: ArraySchema(JsonReportProjectEntryV3),
|
|
19476
|
+
diagnostics: ArraySchema(JsonReportDiagnosticV3),
|
|
19477
|
+
summary: JsonReportSummary,
|
|
19478
|
+
elapsedMilliseconds: Number$1,
|
|
19479
|
+
error: NullOr(JsonReportError)
|
|
19480
|
+
}) {};
|
|
19481
|
+
Union([
|
|
19482
|
+
JsonReportV1,
|
|
19483
|
+
JsonReportV2,
|
|
19484
|
+
JsonReportV3
|
|
19485
|
+
]);
|
|
19424
19486
|
//#endregion
|
|
19425
19487
|
//#region ../../node_modules/.pnpm/semver@7.7.4/node_modules/semver/internal/constants.js
|
|
19426
19488
|
var require_constants$1 = /* @__PURE__ */ __commonJSMin$1(((exports, module) => {
|
|
@@ -33890,6 +33952,22 @@ const isPackageJsonReanimatedAware = (packageJson) => {
|
|
|
33890
33952
|
};
|
|
33891
33953
|
return Object.hasOwn(allDependencies, REANIMATED_DEPENDENCY_NAME$1);
|
|
33892
33954
|
};
|
|
33955
|
+
const SSR_DEPENDENCY_NAMES = new Set([
|
|
33956
|
+
"@react-router/cloudflare",
|
|
33957
|
+
"@react-router/node",
|
|
33958
|
+
"@react-router/serve",
|
|
33959
|
+
"vike",
|
|
33960
|
+
"vite-plugin-ssr"
|
|
33961
|
+
]);
|
|
33962
|
+
const isPackageJsonSsrAware = (packageJson) => {
|
|
33963
|
+
const allDependencies = {
|
|
33964
|
+
...packageJson.peerDependencies,
|
|
33965
|
+
...packageJson.dependencies,
|
|
33966
|
+
...packageJson.devDependencies,
|
|
33967
|
+
...packageJson.optionalDependencies
|
|
33968
|
+
};
|
|
33969
|
+
return Object.keys(allDependencies).some((packageName) => SSR_DEPENDENCY_NAMES.has(packageName));
|
|
33970
|
+
};
|
|
33893
33971
|
const getWorkspacePatterns = (rootDirectory, packageJson) => {
|
|
33894
33972
|
const pnpmPatterns = parsePnpmWorkspacePatterns(rootDirectory);
|
|
33895
33973
|
if (pnpmPatterns.length > 0) return pnpmPatterns;
|
|
@@ -34030,6 +34108,7 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
|
|
|
34030
34108
|
}
|
|
34031
34109
|
facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
|
|
34032
34110
|
facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
|
|
34111
|
+
facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
|
|
34033
34112
|
};
|
|
34034
34113
|
const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
|
|
34035
34114
|
const facts = {
|
|
@@ -34051,6 +34130,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
|
|
|
34051
34130
|
},
|
|
34052
34131
|
hasReactNativeAwarePackage: false,
|
|
34053
34132
|
hasReanimatedAwarePackage: false,
|
|
34133
|
+
hasSsrDependency: false,
|
|
34054
34134
|
reanimatedVersion: null
|
|
34055
34135
|
};
|
|
34056
34136
|
evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
|
|
@@ -34290,6 +34370,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
|
|
|
34290
34370
|
hasTypeScript: hasOwnTsConfig,
|
|
34291
34371
|
hasReactCompiler: false,
|
|
34292
34372
|
hasTanStackQuery: false,
|
|
34373
|
+
hasSsrDependency: false,
|
|
34293
34374
|
preactVersion: null,
|
|
34294
34375
|
preactMajorVersion: null,
|
|
34295
34376
|
hasReactNativeWorkspace: false,
|
|
@@ -34409,6 +34490,7 @@ const discoverProject = (directory) => {
|
|
|
34409
34490
|
hasTypeScript,
|
|
34410
34491
|
hasReactCompiler: detectReactCompiler(directory, packageJson),
|
|
34411
34492
|
hasTanStackQuery: hasTanStackQuery(packageJson),
|
|
34493
|
+
hasSsrDependency: workspaceFacts.hasSsrDependency,
|
|
34412
34494
|
preactVersion,
|
|
34413
34495
|
preactMajorVersion: parseReactMajor(preactVersion),
|
|
34414
34496
|
hasReactNativeWorkspace,
|
|
@@ -37227,6 +37309,12 @@ const CLIENT_ONLY_FRAMEWORKS = new Set([
|
|
|
37227
37309
|
"react-native",
|
|
37228
37310
|
"expo"
|
|
37229
37311
|
]);
|
|
37312
|
+
const SSR_FRAMEWORKS = new Set([
|
|
37313
|
+
"nextjs",
|
|
37314
|
+
"remix",
|
|
37315
|
+
"gatsby",
|
|
37316
|
+
"tanstack-start"
|
|
37317
|
+
]);
|
|
37230
37318
|
const addMajorLadder = (capabilities, name, major, earliest, latest) => {
|
|
37231
37319
|
if (major === null) return;
|
|
37232
37320
|
const cappedMajor = Math.min(major, latest);
|
|
@@ -37239,6 +37327,7 @@ const buildCapabilities = (project) => {
|
|
|
37239
37327
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
37240
37328
|
if (project.expoVersion !== null) capabilities.add("expo");
|
|
37241
37329
|
if ((project.framework === "nextjs" || project.framework === "tanstack-start" || project.framework === "remix") && !project.isStaticExport) capabilities.add("server-actions");
|
|
37330
|
+
if (SSR_FRAMEWORKS.has(project.framework) || project.hasSsrDependency) capabilities.add("ssr");
|
|
37242
37331
|
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
37243
37332
|
if (project.isStaticExport) capabilities.add("nextjs:static-export");
|
|
37244
37333
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
@@ -40643,6 +40732,8 @@ const spawnLintBatches = async (input) => {
|
|
|
40643
40732
|
const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
|
|
40644
40733
|
reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
|
|
40645
40734
|
reportSkippedFiles(outcome.deadlineSkippedFiles, (fileListPreview) => `${outcome.deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
|
|
40735
|
+
const unavailableFiles = new Set([...droppedFiles, ...outcome.deadlineSkippedFiles]);
|
|
40736
|
+
input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)))].sort());
|
|
40646
40737
|
return dedupeDiagnostics(diagnostics);
|
|
40647
40738
|
};
|
|
40648
40739
|
let didValidate = false;
|
|
@@ -40899,12 +40990,18 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
40899
40990
|
* 6. always restore disable directives + clean up the temp dir
|
|
40900
40991
|
*/
|
|
40901
40992
|
const runOxlint = async (options) => {
|
|
40902
|
-
const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
|
|
40993
|
+
const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
|
|
40903
40994
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
40904
40995
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
40905
40996
|
validateRuleRegistration();
|
|
40906
40997
|
resetManifestCaches();
|
|
40907
|
-
if (includePaths !== void 0 && includePaths.length === 0)
|
|
40998
|
+
if (includePaths !== void 0 && includePaths.length === 0) {
|
|
40999
|
+
onFileCoverage?.({
|
|
41000
|
+
candidateFiles: [],
|
|
41001
|
+
analyzedFiles: []
|
|
41002
|
+
});
|
|
41003
|
+
return [];
|
|
41004
|
+
}
|
|
40908
41005
|
const pluginPath = resolvePluginPath();
|
|
40909
41006
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
40910
41007
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
@@ -40965,6 +41062,7 @@ const runOxlint = async (options) => {
|
|
|
40965
41062
|
const runConfigOverFiles = async (buildConfigForPass, configFileName, files, fileProgress) => {
|
|
40966
41063
|
if (files.length === 0) return {
|
|
40967
41064
|
diagnostics: [],
|
|
41065
|
+
analyzedFiles: [],
|
|
40968
41066
|
didDropReactHooksJsPlugin: false,
|
|
40969
41067
|
hadPartialFailure: false
|
|
40970
41068
|
};
|
|
@@ -40976,24 +41074,32 @@ const runOxlint = async (options) => {
|
|
|
40976
41074
|
const passConfigPath = Path.join(configDirectory, configFileName);
|
|
40977
41075
|
const passBaseArgs = makeBaseArgs(passConfigPath);
|
|
40978
41076
|
const passFileBatches = buildFileBatches(passBaseArgs, files);
|
|
40979
|
-
|
|
40980
|
-
|
|
40981
|
-
|
|
40982
|
-
|
|
40983
|
-
|
|
40984
|
-
|
|
40985
|
-
|
|
40986
|
-
|
|
40987
|
-
|
|
40988
|
-
|
|
40989
|
-
|
|
40990
|
-
|
|
40991
|
-
|
|
40992
|
-
|
|
41077
|
+
let analyzedFiles = [];
|
|
41078
|
+
const spawnPass = () => {
|
|
41079
|
+
analyzedFiles = [];
|
|
41080
|
+
return spawnLintBatches({
|
|
41081
|
+
baseArgs: passBaseArgs,
|
|
41082
|
+
fileBatches: passFileBatches,
|
|
41083
|
+
rootDirectory,
|
|
41084
|
+
nodeBinaryPath,
|
|
41085
|
+
project,
|
|
41086
|
+
onPartialFailure: reportPartialFailure,
|
|
41087
|
+
onAnalyzedFiles: (filePaths) => {
|
|
41088
|
+
analyzedFiles = filePaths;
|
|
41089
|
+
},
|
|
41090
|
+
onFileProgress: fileProgress,
|
|
41091
|
+
spawnTimeoutMs,
|
|
41092
|
+
outputMaxBytes,
|
|
41093
|
+
concurrency: options.concurrency,
|
|
41094
|
+
signal: options.signal,
|
|
41095
|
+
deadlineEpochMs: options.deadlineEpochMs
|
|
41096
|
+
});
|
|
41097
|
+
};
|
|
40993
41098
|
writeOxlintConfig(passConfigPath, buildConfigForPass({}));
|
|
40994
41099
|
try {
|
|
40995
41100
|
return {
|
|
40996
41101
|
diagnostics: await spawnPass(),
|
|
41102
|
+
analyzedFiles,
|
|
40997
41103
|
didDropReactHooksJsPlugin: false,
|
|
40998
41104
|
hadPartialFailure
|
|
40999
41105
|
};
|
|
@@ -41005,6 +41111,7 @@ const runOxlint = async (options) => {
|
|
|
41005
41111
|
reportPartialFailure(reactHooksJsDropNote);
|
|
41006
41112
|
return {
|
|
41007
41113
|
diagnostics,
|
|
41114
|
+
analyzedFiles,
|
|
41008
41115
|
didDropReactHooksJsPlugin: true,
|
|
41009
41116
|
hadPartialFailure
|
|
41010
41117
|
};
|
|
@@ -41080,6 +41187,7 @@ const runOxlint = async (options) => {
|
|
|
41080
41187
|
const missFileSet = new Set(missFiles);
|
|
41081
41188
|
const hitFiles = candidateFiles.filter((candidateFile) => !missFileSet.has(candidateFile));
|
|
41082
41189
|
const sidecarReplayedDiagnostics = [];
|
|
41190
|
+
const sidecarReplayedFiles = [];
|
|
41083
41191
|
const sidecarLintFiles = [];
|
|
41084
41192
|
if (sidecarCache === null) sidecarLintFiles.push(...hitFiles);
|
|
41085
41193
|
else {
|
|
@@ -41087,8 +41195,10 @@ const runOxlint = async (options) => {
|
|
|
41087
41195
|
for (const hitFile of hitFiles) {
|
|
41088
41196
|
const cacheKey = cacheKeyByFile.get(hitFile);
|
|
41089
41197
|
const entry = cacheKey === void 0 ? null : sidecarCache.lookup(cacheKey);
|
|
41090
|
-
if (entry !== null && entry.probes.every((probe) => probeAnswers.answerFor(probe.kind, probe.path) === probe.answer))
|
|
41091
|
-
|
|
41198
|
+
if (entry !== null && entry.probes.every((probe) => probeAnswers.answerFor(probe.kind, probe.path) === probe.answer)) {
|
|
41199
|
+
sidecarReplayedFiles.push(hitFile);
|
|
41200
|
+
sidecarReplayedDiagnostics.push(...entry.diagnostics);
|
|
41201
|
+
} else sidecarLintFiles.push(hitFile);
|
|
41092
41202
|
if (performance.now() - verifySliceStartedAt >= 12) {
|
|
41093
41203
|
await yieldToEventLoop();
|
|
41094
41204
|
verifySliceStartedAt = performance.now();
|
|
@@ -41114,6 +41224,7 @@ const runOxlint = async (options) => {
|
|
|
41114
41224
|
sidecarRuleIdFilter: new Set(unboundedSidecarRuleIds)
|
|
41115
41225
|
}), "oxlintrc.sidecar-unbounded.json", hitFiles, void 0) : {
|
|
41116
41226
|
diagnostics: [],
|
|
41227
|
+
analyzedFiles: [],
|
|
41117
41228
|
didDropReactHooksJsPlugin: false,
|
|
41118
41229
|
hadPartialFailure: false
|
|
41119
41230
|
};
|
|
@@ -41144,6 +41255,15 @@ const runOxlint = async (options) => {
|
|
|
41144
41255
|
probesByFile: await missProbesTask
|
|
41145
41256
|
}]
|
|
41146
41257
|
});
|
|
41258
|
+
const analyzedFileSet = new Set(fullResult.analyzedFiles);
|
|
41259
|
+
const boundedSidecarAnalyzedFileSet = new Set(boundedSidecarResult.analyzedFiles);
|
|
41260
|
+
const unboundedSidecarAnalyzedFileSet = new Set(unboundedSidecarResult.analyzedFiles);
|
|
41261
|
+
const sidecarReplayedFileSet = new Set(sidecarReplayedFiles);
|
|
41262
|
+
for (const hitFile of hitFiles) if (useSidecarCache ? (sidecarReplayedFileSet.has(hitFile) || boundedSidecarAnalyzedFileSet.has(hitFile)) && (unboundedSidecarRuleIds.length === 0 || unboundedSidecarAnalyzedFileSet.has(hitFile)) : boundedSidecarAnalyzedFileSet.has(hitFile)) analyzedFileSet.add(hitFile);
|
|
41263
|
+
onFileCoverage?.({
|
|
41264
|
+
candidateFiles,
|
|
41265
|
+
analyzedFiles: candidateFiles.filter((candidateFile) => analyzedFileSet.has(candidateFile))
|
|
41266
|
+
});
|
|
41147
41267
|
return dedupeDiagnostics([
|
|
41148
41268
|
...replayedDiagnostics,
|
|
41149
41269
|
...fullResult.diagnostics,
|
|
@@ -41154,6 +41274,7 @@ const runOxlint = async (options) => {
|
|
|
41154
41274
|
}
|
|
41155
41275
|
const baseArgs = makeBaseArgs(configPath);
|
|
41156
41276
|
const fileBatches = buildFileBatches(baseArgs, candidateFiles);
|
|
41277
|
+
let analyzedFiles = [];
|
|
41157
41278
|
const runBatches = () => spawnLintBatches({
|
|
41158
41279
|
baseArgs,
|
|
41159
41280
|
fileBatches,
|
|
@@ -41161,6 +41282,9 @@ const runOxlint = async (options) => {
|
|
|
41161
41282
|
nodeBinaryPath,
|
|
41162
41283
|
project,
|
|
41163
41284
|
onPartialFailure,
|
|
41285
|
+
onAnalyzedFiles: (filePaths) => {
|
|
41286
|
+
analyzedFiles = filePaths;
|
|
41287
|
+
},
|
|
41164
41288
|
onFileProgress: options.onFileProgress,
|
|
41165
41289
|
spawnTimeoutMs,
|
|
41166
41290
|
outputMaxBytes,
|
|
@@ -41170,7 +41294,12 @@ const runOxlint = async (options) => {
|
|
|
41170
41294
|
});
|
|
41171
41295
|
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
41172
41296
|
try {
|
|
41173
|
-
|
|
41297
|
+
const diagnostics = await runBatches();
|
|
41298
|
+
onFileCoverage?.({
|
|
41299
|
+
candidateFiles,
|
|
41300
|
+
analyzedFiles
|
|
41301
|
+
});
|
|
41302
|
+
return diagnostics;
|
|
41174
41303
|
} catch (error) {
|
|
41175
41304
|
const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
|
|
41176
41305
|
if (reactHooksJsDropNote !== null) {
|
|
@@ -41180,11 +41309,20 @@ const runOxlint = async (options) => {
|
|
|
41180
41309
|
}));
|
|
41181
41310
|
const diagnostics = await runBatches();
|
|
41182
41311
|
onPartialFailure?.(reactHooksJsDropNote);
|
|
41312
|
+
onFileCoverage?.({
|
|
41313
|
+
candidateFiles,
|
|
41314
|
+
analyzedFiles
|
|
41315
|
+
});
|
|
41183
41316
|
return diagnostics;
|
|
41184
41317
|
}
|
|
41185
41318
|
if (extendsPaths.length === 0) throw error;
|
|
41186
41319
|
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
41187
|
-
|
|
41320
|
+
const diagnostics = await runBatches();
|
|
41321
|
+
onFileCoverage?.({
|
|
41322
|
+
candidateFiles,
|
|
41323
|
+
analyzedFiles
|
|
41324
|
+
});
|
|
41325
|
+
return diagnostics;
|
|
41188
41326
|
}
|
|
41189
41327
|
} finally {
|
|
41190
41328
|
restoreDisableDirectives();
|
|
@@ -41264,6 +41402,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
41264
41402
|
onPartialFailure: (reason) => {
|
|
41265
41403
|
collectedFailures.push(reason);
|
|
41266
41404
|
},
|
|
41405
|
+
onFileCoverage: input.onFileCoverage,
|
|
41267
41406
|
onFileProgress: input.onFileProgress,
|
|
41268
41407
|
perFileLintCacheEnabled,
|
|
41269
41408
|
sidecarLintCacheEnabled,
|
|
@@ -41971,6 +42110,7 @@ const resolveGithubActionsScoreMetadata = (environment = process.env) => {
|
|
|
41971
42110
|
...actorAssociation !== void 0 ? { githubActorAssociation: actorAssociation } : {}
|
|
41972
42111
|
};
|
|
41973
42112
|
};
|
|
42113
|
+
const toNormalizedRelativePath = (filePath, rootDirectory) => Path.relative(Path.resolve(rootDirectory), Path.resolve(rootDirectory, filePath)).replaceAll("\\", "/") || ".";
|
|
41974
42114
|
const NO_HOOKS = {
|
|
41975
42115
|
beforeLint: () => void_,
|
|
41976
42116
|
afterLint: () => void_
|
|
@@ -42069,7 +42209,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42069
42209
|
repo
|
|
42070
42210
|
}).pipe(orElseSucceed(() => null)) : succeed$2(null));
|
|
42071
42211
|
const lintIncludePaths = (input.skipJsxIncludeFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths], project)) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, project);
|
|
42072
|
-
const
|
|
42212
|
+
const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
|
|
42073
42213
|
const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
|
|
42074
42214
|
const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
|
|
42075
42215
|
yield* beforeLint(project, lintIncludePaths ?? void 0);
|
|
@@ -42174,6 +42314,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42174
42314
|
let deadCodeCacheHit = null;
|
|
42175
42315
|
let deadCodeSummaryCacheHits = null;
|
|
42176
42316
|
let deadCodeSummaryCacheMisses = null;
|
|
42317
|
+
const lintFileCoverageState = { value: null };
|
|
42177
42318
|
const baseLintStream = linterService.run({
|
|
42178
42319
|
rootDirectory: scanDirectory,
|
|
42179
42320
|
project,
|
|
@@ -42189,6 +42330,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42189
42330
|
lastReportedTotalFileCount = totalFileCount;
|
|
42190
42331
|
runSync(scanProgress.update(`Scanning files (${scannedFileCount}/${totalFileCount})${workerCountSuffix}...`));
|
|
42191
42332
|
},
|
|
42333
|
+
onFileCoverage: (coverage) => {
|
|
42334
|
+
lintFileCoverageState.value = coverage;
|
|
42335
|
+
},
|
|
42192
42336
|
onCacheStats: (cacheHitFileCount, totalConsideredFileCount) => {
|
|
42193
42337
|
lintCacheHitFileCount = cacheHitFileCount;
|
|
42194
42338
|
lintCacheTotalFileCount = totalConsideredFileCount;
|
|
@@ -42219,7 +42363,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42219
42363
|
const lintFailureState = yield* get$2(lintFailure);
|
|
42220
42364
|
yield* afterLint(lintFailureState.didFail);
|
|
42221
42365
|
if (lintFailureState.didFail) yield* scanProgress.fail(formatLintFailText(lintFailureState.reasonTag, process.version));
|
|
42222
|
-
const
|
|
42366
|
+
const candidateFiles = lintFileCoverageState.value === null ? [] : [...new Set(lintFileCoverageState.value.candidateFiles.map((filePath) => toNormalizedRelativePath(filePath, scanDirectory)))];
|
|
42367
|
+
const analyzedFiles = lintFileCoverageState.value === null ? [] : [...new Set(lintFileCoverageState.value.analyzedFiles.map((filePath) => toNormalizedRelativePath(filePath, scanDirectory)))].sort();
|
|
42368
|
+
const totalFileCount = candidateFiles.length || lastReportedTotalFileCount || (lintIncludePaths?.length ?? project.sourceFileCount);
|
|
42369
|
+
const scannedFilePaths = input.suppressScanSummary ? candidateFiles.length > 0 ? candidateFiles.map((filePath) => Path.resolve(scanDirectory, filePath)) : fallbackScannedFilePaths : [];
|
|
42223
42370
|
const scannedFilesLabel = `${totalFileCount} ${totalFileCount === 1 ? "file" : "files"}`;
|
|
42224
42371
|
let deadCodeCollected = [];
|
|
42225
42372
|
if (lintFailureState.didFail) {
|
|
@@ -42301,6 +42448,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42301
42448
|
deadCodeOverlapped: shouldOverlapDeadCode,
|
|
42302
42449
|
scannedFileCount: totalFileCount,
|
|
42303
42450
|
scannedFilePaths,
|
|
42451
|
+
analyzedFiles,
|
|
42304
42452
|
scanElapsedMilliseconds,
|
|
42305
42453
|
scanConcurrency,
|
|
42306
42454
|
supplyChainOverlapTimedOut: supplyChainResult.timedOut,
|
|
@@ -42552,7 +42700,7 @@ const buildJsonReportError = (input) => {
|
|
|
42552
42700
|
sentryEventId
|
|
42553
42701
|
};
|
|
42554
42702
|
return {
|
|
42555
|
-
schemaVersion:
|
|
42703
|
+
schemaVersion: 3,
|
|
42556
42704
|
version: input.version,
|
|
42557
42705
|
ok: false,
|
|
42558
42706
|
directory: input.directory,
|
|
@@ -42597,6 +42745,7 @@ const summarizeDiagnostics = (diagnostics, worstScore = null, worstScoreLabel =
|
|
|
42597
42745
|
* React-runtime rule family was gated off for the project.
|
|
42598
42746
|
*/
|
|
42599
42747
|
const hasReactRuntime = (project) => project.reactVersion !== null || project.preactVersion !== null;
|
|
42748
|
+
const isScanComplete = (input) => input.analyzedFileCount !== void 0 && input.scannedFileCount !== void 0 && input.skippedCheckCount === 0 && input.skippedCheckReasonCount === 0 && input.analyzedFileCount === input.scannedFileCount;
|
|
42600
42749
|
const toJsonDiff = (diff) => {
|
|
42601
42750
|
if (!diff) return null;
|
|
42602
42751
|
return {
|
|
@@ -42619,21 +42768,68 @@ const findWorstScoredProject = (projects) => {
|
|
|
42619
42768
|
}
|
|
42620
42769
|
return worst;
|
|
42621
42770
|
};
|
|
42771
|
+
const toJsonReportDiagnostic = (diagnostic, projectRoot, reportRoot) => {
|
|
42772
|
+
const normalizedFilePath = toNormalizedRelativePath(diagnostic.filePath, projectRoot);
|
|
42773
|
+
const reportRelativeFilePath = toNormalizedRelativePath(Path.resolve(projectRoot, diagnostic.filePath), reportRoot);
|
|
42774
|
+
const ruleIdentity = getDiagnosticRuleIdentity(diagnostic);
|
|
42775
|
+
return {
|
|
42776
|
+
...diagnostic,
|
|
42777
|
+
id: buildDiagnosticIdentity({
|
|
42778
|
+
filePath: reportRelativeFilePath,
|
|
42779
|
+
line: diagnostic.line,
|
|
42780
|
+
column: diagnostic.column,
|
|
42781
|
+
plugin: diagnostic.plugin,
|
|
42782
|
+
rule: diagnostic.rule
|
|
42783
|
+
}),
|
|
42784
|
+
normalizedFilePath,
|
|
42785
|
+
category: ruleIdentity.category,
|
|
42786
|
+
tags: [...new Set(ruleIdentity.tags)].sort()
|
|
42787
|
+
};
|
|
42788
|
+
};
|
|
42622
42789
|
const buildJsonReport = (input) => {
|
|
42623
|
-
const projects = input.scans.map(({ directory, result }) =>
|
|
42624
|
-
|
|
42625
|
-
|
|
42626
|
-
|
|
42627
|
-
|
|
42628
|
-
|
|
42629
|
-
|
|
42630
|
-
|
|
42631
|
-
|
|
42632
|
-
|
|
42790
|
+
const projects = input.scans.map(({ directory, result }) => {
|
|
42791
|
+
const skippedChecks = result.skippedChecks ?? [];
|
|
42792
|
+
const analyzedFiles = [...new Set((result.analyzedFiles ?? []).map((filePath) => toNormalizedRelativePath(filePath, result.project.rootDirectory)))].sort();
|
|
42793
|
+
const scannedFileCount = result.scannedFileCount ?? result.project.sourceFileCount;
|
|
42794
|
+
return {
|
|
42795
|
+
directory,
|
|
42796
|
+
packageRoot: result.project.rootDirectory,
|
|
42797
|
+
framework: result.project.framework,
|
|
42798
|
+
project: result.project,
|
|
42799
|
+
diagnostics: result.diagnostics.map((diagnostic) => toJsonReportDiagnostic(diagnostic, result.project.rootDirectory, input.directory)),
|
|
42800
|
+
score: result.score,
|
|
42801
|
+
skippedChecks,
|
|
42802
|
+
...result.skippedCheckReasons ? { skippedCheckReasons: result.skippedCheckReasons } : {},
|
|
42803
|
+
analyzedFiles,
|
|
42804
|
+
analyzedFileCount: analyzedFiles.length,
|
|
42805
|
+
complete: isScanComplete({
|
|
42806
|
+
analyzedFileCount: result.analyzedFiles === void 0 ? void 0 : analyzedFiles.length,
|
|
42807
|
+
scannedFileCount,
|
|
42808
|
+
skippedCheckCount: skippedChecks.length,
|
|
42809
|
+
skippedCheckReasonCount: Object.keys(result.skippedCheckReasons ?? {}).length
|
|
42810
|
+
}),
|
|
42811
|
+
...typeof result.scannedFileCount === "number" ? { scannedFileCount } : {},
|
|
42812
|
+
elapsedMilliseconds: result.elapsedMilliseconds
|
|
42813
|
+
};
|
|
42814
|
+
});
|
|
42633
42815
|
const flattenedDiagnostics = projects.flatMap((entry) => entry.diagnostics);
|
|
42634
42816
|
const worstScoredProject = findWorstScoredProject(projects);
|
|
42635
|
-
const
|
|
42636
|
-
const
|
|
42817
|
+
const diagnosticSummary = summarizeDiagnostics(flattenedDiagnostics, worstScoredProject?.score?.score ?? null, worstScoredProject?.score?.label ?? null);
|
|
42818
|
+
const affectedFileCount = projects.reduce((totalAffectedFileCount, project) => totalAffectedFileCount + new Set(project.diagnostics.map((diagnostic) => diagnostic.normalizedFilePath)).size, 0);
|
|
42819
|
+
const summary = {
|
|
42820
|
+
...diagnosticSummary,
|
|
42821
|
+
affectedFileCount
|
|
42822
|
+
};
|
|
42823
|
+
return {
|
|
42824
|
+
schemaVersion: 3,
|
|
42825
|
+
mode: input.baseline !== void 0 ? "baseline" : input.baselineDegraded && input.mode === "baseline" ? "diff" : input.mode,
|
|
42826
|
+
...input.baseline ? { baseline: {
|
|
42827
|
+
baseRef: input.baseline.baseRef,
|
|
42828
|
+
newCount: summary.totalDiagnosticCount,
|
|
42829
|
+
fixedCount: input.baseline.fixedCount,
|
|
42830
|
+
baseTotalCount: input.baseline.baseTotalCount
|
|
42831
|
+
} } : {},
|
|
42832
|
+
...input.baselineDegraded ? { baselineDegraded: true } : {},
|
|
42637
42833
|
...input.scans.length > 0 ? { reactDetected: input.scans.some((scan) => hasReactRuntime(scan.result.project)) } : {},
|
|
42638
42834
|
version: input.version,
|
|
42639
42835
|
ok: true,
|
|
@@ -42645,39 +42841,26 @@ const buildJsonReport = (input) => {
|
|
|
42645
42841
|
elapsedMilliseconds: input.totalElapsedMilliseconds,
|
|
42646
42842
|
error: null
|
|
42647
42843
|
};
|
|
42648
|
-
if (input.baseline) return {
|
|
42649
|
-
schemaVersion: 2,
|
|
42650
|
-
mode: "baseline",
|
|
42651
|
-
baseline: {
|
|
42652
|
-
baseRef: input.baseline.baseRef,
|
|
42653
|
-
newCount: summary.totalDiagnosticCount,
|
|
42654
|
-
fixedCount: input.baseline.fixedCount,
|
|
42655
|
-
baseTotalCount: input.baseline.baseTotalCount
|
|
42656
|
-
},
|
|
42657
|
-
...shared
|
|
42658
|
-
};
|
|
42659
|
-
return {
|
|
42660
|
-
schemaVersion: 1,
|
|
42661
|
-
mode: input.mode,
|
|
42662
|
-
...input.baselineDegraded ? { baselineDegraded: true } : {},
|
|
42663
|
-
...shared
|
|
42664
|
-
};
|
|
42665
42844
|
};
|
|
42666
42845
|
/**
|
|
42667
42846
|
* Single source of truth for the skipped-check accounting shared by the
|
|
42668
42847
|
* CLI renderer (`react-doctor/src/inspect.ts → finalizeAndRender`) and the
|
|
42669
42848
|
* programmatic shell (`@react-doctor/api → diagnose()`). Both surface a
|
|
42670
|
-
* failed
|
|
42849
|
+
* failed or partial analysis pass instead of a false "all clear", so the
|
|
42671
42850
|
* branch logic lives here once.
|
|
42672
42851
|
*/
|
|
42673
42852
|
const buildSkippedChecks = (input) => {
|
|
42674
42853
|
const skippedChecks = [];
|
|
42675
42854
|
if (input.didLintFail) skippedChecks.push("lint");
|
|
42676
42855
|
if (input.didDeadCodeFail) skippedChecks.push("dead-code");
|
|
42856
|
+
if (input.supplyChainOverlapTimedOut) skippedChecks.push("supply-chain");
|
|
42857
|
+
if (input.securityScanFailed) skippedChecks.push("security-scan");
|
|
42677
42858
|
const skippedCheckReasons = {};
|
|
42678
42859
|
if (input.didLintFail && input.lintFailureReason !== null) skippedCheckReasons.lint = input.lintFailureReason;
|
|
42679
42860
|
else if (input.lintPartialFailures.length > 0) skippedCheckReasons["lint:partial"] = input.lintPartialFailures.join("; ");
|
|
42680
42861
|
if (input.didDeadCodeFail && input.deadCodeFailureReason !== null) skippedCheckReasons["dead-code"] = input.deadCodeFailureReason;
|
|
42862
|
+
if (input.supplyChainOverlapTimedOut) skippedCheckReasons["supply-chain"] = "Supply-chain analysis timed out and was skipped.";
|
|
42863
|
+
if (input.securityScanFailed) skippedCheckReasons["security-scan"] = "Security scan failed and was skipped.";
|
|
42681
42864
|
return {
|
|
42682
42865
|
skippedChecks,
|
|
42683
42866
|
skippedCheckReasons
|
|
@@ -42866,6 +43049,8 @@ const outputToDiagnoseResult = (output, elapsedMilliseconds) => {
|
|
|
42866
43049
|
score: output.score,
|
|
42867
43050
|
skippedChecks,
|
|
42868
43051
|
...Object.keys(skippedCheckReasons).length > 0 ? { skippedCheckReasons } : {},
|
|
43052
|
+
analyzedFiles: output.analyzedFiles,
|
|
43053
|
+
scannedFileCount: output.scannedFileCount,
|
|
42869
43054
|
project: output.project,
|
|
42870
43055
|
reactDetected: hasReactRuntime(output.project),
|
|
42871
43056
|
elapsedMilliseconds
|
|
@@ -42975,6 +43160,8 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
42975
43160
|
score: result.score,
|
|
42976
43161
|
skippedChecks: result.skippedChecks,
|
|
42977
43162
|
...result.skippedCheckReasons ? { skippedCheckReasons: result.skippedCheckReasons } : {},
|
|
43163
|
+
...result.analyzedFiles ? { analyzedFiles: result.analyzedFiles } : {},
|
|
43164
|
+
...typeof result.scannedFileCount === "number" ? { scannedFileCount: result.scannedFileCount } : {},
|
|
42978
43165
|
project: result.project,
|
|
42979
43166
|
elapsedMilliseconds: result.elapsedMilliseconds
|
|
42980
43167
|
}
|
|
@@ -42985,4 +43172,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
42985
43172
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
42986
43173
|
|
|
42987
43174
|
//# sourceMappingURL=index.js.map
|
|
42988
|
-
//# debugId=
|
|
43175
|
+
//# debugId=95e70e55-12b7-5577-81f3-f5331db7ca53
|