react-doctor 0.7.4 → 0.7.5-dev.037bd56
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 +335 -88
- package/dist/index.d.ts +58 -9
- package/dist/index.js +310 -73
- package/dist/lsp.js +234 -43
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
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]="1833ffea-5e6b-5c0b-af42-5334f6a8a63b")}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";
|
|
8
9
|
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
|
-
import
|
|
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";
|
|
12
|
+
import ts from "typescript";
|
|
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) => {
|
|
@@ -32978,7 +33040,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
32978
33040
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
32979
33041
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
32980
33042
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
32981
|
-
const CORE_PACKAGE_VERSION = "0.7.
|
|
33043
|
+
const CORE_PACKAGE_VERSION = "0.7.5";
|
|
32982
33044
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
32983
33045
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
32984
33046
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -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,
|
|
@@ -35488,6 +35570,14 @@ var AmbiguousProject = class extends TaggedErrorClass()("AmbiguousProject", {
|
|
|
35488
35570
|
return `Ambiguous project at ${this.directory}: found ${this.candidates.length} candidates (${this.candidates.join(", ")})`;
|
|
35489
35571
|
}
|
|
35490
35572
|
};
|
|
35573
|
+
var ProjectDiscoveryFailed = class extends TaggedErrorClass()("ProjectDiscoveryFailed", {
|
|
35574
|
+
directory: String$1,
|
|
35575
|
+
cause: Unknown
|
|
35576
|
+
}) {
|
|
35577
|
+
get message() {
|
|
35578
|
+
return `Project discovery failed for ${this.directory}: ${pretty(fail$6(this.cause))}`;
|
|
35579
|
+
}
|
|
35580
|
+
};
|
|
35491
35581
|
var DeadCodeAnalysisFailed = class extends TaggedErrorClass()("DeadCodeAnalysisFailed", { cause: Unknown }) {
|
|
35492
35582
|
get message() {
|
|
35493
35583
|
return `Dead-code analysis failed: ${pretty(fail$6(this.cause))}`;
|
|
@@ -35522,6 +35612,7 @@ const ReactDoctorErrorReason = Union([
|
|
|
35522
35612
|
ProjectNotFound,
|
|
35523
35613
|
NoReactDependency,
|
|
35524
35614
|
AmbiguousProject,
|
|
35615
|
+
ProjectDiscoveryFailed,
|
|
35525
35616
|
DeadCodeAnalysisFailed,
|
|
35526
35617
|
GitInvocationFailed,
|
|
35527
35618
|
GitBaseBranchMissing,
|
|
@@ -37218,6 +37309,12 @@ const CLIENT_ONLY_FRAMEWORKS = new Set([
|
|
|
37218
37309
|
"react-native",
|
|
37219
37310
|
"expo"
|
|
37220
37311
|
]);
|
|
37312
|
+
const SSR_FRAMEWORKS = new Set([
|
|
37313
|
+
"nextjs",
|
|
37314
|
+
"remix",
|
|
37315
|
+
"gatsby",
|
|
37316
|
+
"tanstack-start"
|
|
37317
|
+
]);
|
|
37221
37318
|
const addMajorLadder = (capabilities, name, major, earliest, latest) => {
|
|
37222
37319
|
if (major === null) return;
|
|
37223
37320
|
const cappedMajor = Math.min(major, latest);
|
|
@@ -37230,6 +37327,7 @@ const buildCapabilities = (project) => {
|
|
|
37230
37327
|
if (project.framework === "expo" || project.framework === "react-native" || project.hasReactNativeWorkspace) capabilities.add("react-native");
|
|
37231
37328
|
if (project.expoVersion !== null) capabilities.add("expo");
|
|
37232
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");
|
|
37233
37331
|
if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
|
|
37234
37332
|
if (project.isStaticExport) capabilities.add("nextjs:static-export");
|
|
37235
37333
|
if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
|
|
@@ -39027,7 +39125,7 @@ const normalizeConfigForHash = (config) => {
|
|
|
39027
39125
|
if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
|
|
39028
39126
|
return clone;
|
|
39029
39127
|
};
|
|
39030
|
-
const computeRulesetHash = (input) => crypto.createHash("sha1").update(JSON.stringify(normalizeConfigForHash(input.config))).update("\0").update([...input.toolchainVersions].join("\0")).update("\0").update([...input.ignorePatterns].join("\n")).update("\0").update(input.tsconfigContent ?? "").digest("hex");
|
|
39128
|
+
const computeRulesetHash = (input) => crypto.createHash("sha1").update(JSON.stringify(normalizeConfigForHash(input.config))).update("\0").update([...input.toolchainVersions].join("\0")).update("\0").update([...input.ignorePatterns].join("\n")).update("\0").update(input.tsconfigContent ?? "").update("\0").update(input.respectInlineDisables ? "respect-inline-disables" : "audit-mode").digest("hex");
|
|
39031
39129
|
/**
|
|
39032
39130
|
* Loads a plugin module via the local require resolver and extracts
|
|
39033
39131
|
* `(name, ruleNames)` from either `module.exports.meta + rules` or
|
|
@@ -39063,7 +39161,7 @@ const resolveReactHooksJsPlugin = (hasReactCompiler, customRulesOnly) => {
|
|
|
39063
39161
|
} catch {
|
|
39064
39162
|
return null;
|
|
39065
39163
|
}
|
|
39066
|
-
const { ruleNames } = readPluginShape(pluginSpecifier, (
|
|
39164
|
+
const { ruleNames } = readPluginShape(pluginSpecifier, (specifier) => bundledRequire$1(specifier));
|
|
39067
39165
|
return {
|
|
39068
39166
|
entry: {
|
|
39069
39167
|
name: "react-hooks-js",
|
|
@@ -39471,6 +39569,23 @@ const resolveTsConfigRelativePath = (rootDirectory) => {
|
|
|
39471
39569
|
for (const filename of TSCONFIG_FILENAMES) if (NFS.existsSync(Path.join(rootDirectory, filename))) return `./${filename}`;
|
|
39472
39570
|
return null;
|
|
39473
39571
|
};
|
|
39572
|
+
const DERIVED_STATE_RULE_PRIORITY = new Map([
|
|
39573
|
+
["no-initialize-state", 0],
|
|
39574
|
+
["no-adjust-state-on-prop-change", 1],
|
|
39575
|
+
["no-derived-state", 2],
|
|
39576
|
+
["no-derived-state-effect", 3]
|
|
39577
|
+
]);
|
|
39578
|
+
const doDiagnosticSpansOverlap = (first, second) => {
|
|
39579
|
+
if (first.filePath !== second.filePath || first.plugin !== second.plugin) return false;
|
|
39580
|
+
if (first.offset !== void 0 && second.offset !== void 0) {
|
|
39581
|
+
const firstEnd = first.offset + Math.max(first.length ?? 1, 1);
|
|
39582
|
+
const secondEnd = second.offset + Math.max(second.length ?? 1, 1);
|
|
39583
|
+
return first.offset < secondEnd && second.offset < firstEnd;
|
|
39584
|
+
}
|
|
39585
|
+
const firstEndLine = first.endLine ?? first.line;
|
|
39586
|
+
const secondEndLine = second.endLine ?? second.line;
|
|
39587
|
+
return first.line <= secondEndLine && second.line <= firstEndLine;
|
|
39588
|
+
};
|
|
39474
39589
|
const dedupeDiagnostics = (diagnostics) => {
|
|
39475
39590
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
39476
39591
|
const uniqueDiagnostics = [];
|
|
@@ -39478,6 +39593,16 @@ const dedupeDiagnostics = (diagnostics) => {
|
|
|
39478
39593
|
const key = `${diagnostic.filePath}\u0000${diagnostic.line}\u0000${diagnostic.column}\u0000${diagnostic.plugin}\u0000${diagnostic.rule}\u0000${diagnostic.severity}\u0000${diagnostic.message}`;
|
|
39479
39594
|
if (seenKeys.has(key)) continue;
|
|
39480
39595
|
seenKeys.add(key);
|
|
39596
|
+
const priority = DERIVED_STATE_RULE_PRIORITY.get(diagnostic.rule);
|
|
39597
|
+
if (priority !== void 0) {
|
|
39598
|
+
const overlappingDiagnosticIndex = uniqueDiagnostics.findIndex((candidate) => candidate.rule !== diagnostic.rule && candidate.severity === diagnostic.severity && DERIVED_STATE_RULE_PRIORITY.has(candidate.rule) && doDiagnosticSpansOverlap(candidate, diagnostic));
|
|
39599
|
+
if (overlappingDiagnosticIndex >= 0) {
|
|
39600
|
+
const existingDiagnostic = uniqueDiagnostics[overlappingDiagnosticIndex];
|
|
39601
|
+
const existingPriority = existingDiagnostic ? DERIVED_STATE_RULE_PRIORITY.get(existingDiagnostic.rule) : void 0;
|
|
39602
|
+
if (existingPriority !== void 0 && priority < existingPriority) uniqueDiagnostics[overlappingDiagnosticIndex] = diagnostic;
|
|
39603
|
+
continue;
|
|
39604
|
+
}
|
|
39605
|
+
}
|
|
39481
39606
|
uniqueDiagnostics.push(diagnostic);
|
|
39482
39607
|
}
|
|
39483
39608
|
return uniqueDiagnostics;
|
|
@@ -40351,6 +40476,11 @@ const buildOxlintChildEnv = (sourceEnv) => {
|
|
|
40351
40476
|
if (!isCompileCacheDisabled && !isCompileCacheAlreadySet) childEnv.NODE_COMPILE_CACHE = Path.join(os.tmpdir(), NODE_COMPILE_CACHE_DIR_NAME);
|
|
40352
40477
|
return childEnv;
|
|
40353
40478
|
};
|
|
40479
|
+
const buildProfiledNodeArguments = (input) => [
|
|
40480
|
+
...input.cpuProfileDirectory ? ["--cpu-prof", `--cpu-prof-dir=${input.cpuProfileDirectory}`] : [],
|
|
40481
|
+
...input.heapProfileDirectory ? ["--heap-prof", `--heap-prof-dir=${input.heapProfileDirectory}`] : [],
|
|
40482
|
+
...input.argumentsList
|
|
40483
|
+
];
|
|
40354
40484
|
const SANITIZED_ENV = buildOxlintChildEnv(process.env);
|
|
40355
40485
|
/**
|
|
40356
40486
|
* Spawn one oxlint subprocess with hard ceilings on wall time and
|
|
@@ -40375,7 +40505,11 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
|
|
|
40375
40505
|
reject(new ReactDoctorError({ reason: new OxlintSpawnFailed({ cause: "lint phase aborted" }) }));
|
|
40376
40506
|
return;
|
|
40377
40507
|
}
|
|
40378
|
-
const child = spawn(nodeBinaryPath,
|
|
40508
|
+
const child = spawn(nodeBinaryPath, buildProfiledNodeArguments({
|
|
40509
|
+
argumentsList: args,
|
|
40510
|
+
cpuProfileDirectory: SANITIZED_ENV.REACT_DOCTOR_CPU_PROFILE_DIR,
|
|
40511
|
+
heapProfileDirectory: SANITIZED_ENV.REACT_DOCTOR_HEAP_PROFILE_DIR
|
|
40512
|
+
}), {
|
|
40379
40513
|
cwd: rootDirectory,
|
|
40380
40514
|
env: SANITIZED_ENV,
|
|
40381
40515
|
stdio: [
|
|
@@ -40634,6 +40768,8 @@ const spawnLintBatches = async (input) => {
|
|
|
40634
40768
|
const reasonHint = firstDropReason ? ` — first failure: ${firstDropReason}` : "";
|
|
40635
40769
|
reportSkippedFiles(droppedFiles, (fileListPreview) => `${droppedFiles.length} file(s) failed to lint and were skipped (${fileListPreview})${reasonHint}`);
|
|
40636
40770
|
reportSkippedFiles(outcome.deadlineSkippedFiles, (fileListPreview) => `${outcome.deadlineSkippedFiles.length} file(s) skipped — max scan duration reached before they were linted (${fileListPreview})`);
|
|
40771
|
+
const unavailableFiles = new Set([...droppedFiles, ...outcome.deadlineSkippedFiles]);
|
|
40772
|
+
input.onAnalyzedFiles?.([...new Set(fileBatches.flat().filter((filePath) => !unavailableFiles.has(filePath)))].sort());
|
|
40637
40773
|
return dedupeDiagnostics(diagnostics);
|
|
40638
40774
|
};
|
|
40639
40775
|
let didValidate = false;
|
|
@@ -40890,12 +41026,18 @@ const reactHooksJsPluginDropNote = (error) => {
|
|
|
40890
41026
|
* 6. always restore disable directives + clean up the temp dir
|
|
40891
41027
|
*/
|
|
40892
41028
|
const runOxlint = async (options) => {
|
|
40893
|
-
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;
|
|
41029
|
+
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;
|
|
40894
41030
|
const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
|
|
40895
41031
|
const severityControls = buildRuleSeverityControls(userConfig);
|
|
40896
41032
|
validateRuleRegistration();
|
|
40897
41033
|
resetManifestCaches();
|
|
40898
|
-
if (includePaths !== void 0 && includePaths.length === 0)
|
|
41034
|
+
if (includePaths !== void 0 && includePaths.length === 0) {
|
|
41035
|
+
onFileCoverage?.({
|
|
41036
|
+
candidateFiles: [],
|
|
41037
|
+
analyzedFiles: []
|
|
41038
|
+
});
|
|
41039
|
+
return [];
|
|
41040
|
+
}
|
|
40899
41041
|
const pluginPath = resolvePluginPath();
|
|
40900
41042
|
const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
|
|
40901
41043
|
const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
|
|
@@ -40956,6 +41098,7 @@ const runOxlint = async (options) => {
|
|
|
40956
41098
|
const runConfigOverFiles = async (buildConfigForPass, configFileName, files, fileProgress) => {
|
|
40957
41099
|
if (files.length === 0) return {
|
|
40958
41100
|
diagnostics: [],
|
|
41101
|
+
analyzedFiles: [],
|
|
40959
41102
|
didDropReactHooksJsPlugin: false,
|
|
40960
41103
|
hadPartialFailure: false
|
|
40961
41104
|
};
|
|
@@ -40967,24 +41110,32 @@ const runOxlint = async (options) => {
|
|
|
40967
41110
|
const passConfigPath = Path.join(configDirectory, configFileName);
|
|
40968
41111
|
const passBaseArgs = makeBaseArgs(passConfigPath);
|
|
40969
41112
|
const passFileBatches = buildFileBatches(passBaseArgs, files);
|
|
40970
|
-
|
|
40971
|
-
|
|
40972
|
-
|
|
40973
|
-
|
|
40974
|
-
|
|
40975
|
-
|
|
40976
|
-
|
|
40977
|
-
|
|
40978
|
-
|
|
40979
|
-
|
|
40980
|
-
|
|
40981
|
-
|
|
40982
|
-
|
|
40983
|
-
|
|
41113
|
+
let analyzedFiles = [];
|
|
41114
|
+
const spawnPass = () => {
|
|
41115
|
+
analyzedFiles = [];
|
|
41116
|
+
return spawnLintBatches({
|
|
41117
|
+
baseArgs: passBaseArgs,
|
|
41118
|
+
fileBatches: passFileBatches,
|
|
41119
|
+
rootDirectory,
|
|
41120
|
+
nodeBinaryPath,
|
|
41121
|
+
project,
|
|
41122
|
+
onPartialFailure: reportPartialFailure,
|
|
41123
|
+
onAnalyzedFiles: (filePaths) => {
|
|
41124
|
+
analyzedFiles = filePaths;
|
|
41125
|
+
},
|
|
41126
|
+
onFileProgress: fileProgress,
|
|
41127
|
+
spawnTimeoutMs,
|
|
41128
|
+
outputMaxBytes,
|
|
41129
|
+
concurrency: options.concurrency,
|
|
41130
|
+
signal: options.signal,
|
|
41131
|
+
deadlineEpochMs: options.deadlineEpochMs
|
|
41132
|
+
});
|
|
41133
|
+
};
|
|
40984
41134
|
writeOxlintConfig(passConfigPath, buildConfigForPass({}));
|
|
40985
41135
|
try {
|
|
40986
41136
|
return {
|
|
40987
41137
|
diagnostics: await spawnPass(),
|
|
41138
|
+
analyzedFiles,
|
|
40988
41139
|
didDropReactHooksJsPlugin: false,
|
|
40989
41140
|
hadPartialFailure
|
|
40990
41141
|
};
|
|
@@ -40996,12 +41147,13 @@ const runOxlint = async (options) => {
|
|
|
40996
41147
|
reportPartialFailure(reactHooksJsDropNote);
|
|
40997
41148
|
return {
|
|
40998
41149
|
diagnostics,
|
|
41150
|
+
analyzedFiles,
|
|
40999
41151
|
didDropReactHooksJsPlugin: true,
|
|
41000
41152
|
hadPartialFailure
|
|
41001
41153
|
};
|
|
41002
41154
|
}
|
|
41003
41155
|
};
|
|
41004
|
-
if (perFileLintCacheEnabled &&
|
|
41156
|
+
if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
|
|
41005
41157
|
const rulesetHash = computeRulesetHash({
|
|
41006
41158
|
config: buildConfig({
|
|
41007
41159
|
extendsPaths: [],
|
|
@@ -41009,7 +41161,8 @@ const runOxlint = async (options) => {
|
|
|
41009
41161
|
}),
|
|
41010
41162
|
toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
|
|
41011
41163
|
ignorePatterns: combinedPatterns,
|
|
41012
|
-
tsconfigContent
|
|
41164
|
+
tsconfigContent,
|
|
41165
|
+
respectInlineDisables
|
|
41013
41166
|
});
|
|
41014
41167
|
const cache = createFileLintCache(resolveReactDoctorCacheDir(rootDirectory), rulesetHash);
|
|
41015
41168
|
const cacheKeyByFile = /* @__PURE__ */ new Map();
|
|
@@ -41052,7 +41205,8 @@ const runOxlint = async (options) => {
|
|
|
41052
41205
|
}),
|
|
41053
41206
|
toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
|
|
41054
41207
|
ignorePatterns: combinedPatterns,
|
|
41055
|
-
tsconfigContent
|
|
41208
|
+
tsconfigContent,
|
|
41209
|
+
respectInlineDisables
|
|
41056
41210
|
})) : null;
|
|
41057
41211
|
const probeAnswers = createSidecarProbeAnswerResolver({
|
|
41058
41212
|
rootDirectory,
|
|
@@ -41071,6 +41225,7 @@ const runOxlint = async (options) => {
|
|
|
41071
41225
|
const missFileSet = new Set(missFiles);
|
|
41072
41226
|
const hitFiles = candidateFiles.filter((candidateFile) => !missFileSet.has(candidateFile));
|
|
41073
41227
|
const sidecarReplayedDiagnostics = [];
|
|
41228
|
+
const sidecarReplayedFiles = [];
|
|
41074
41229
|
const sidecarLintFiles = [];
|
|
41075
41230
|
if (sidecarCache === null) sidecarLintFiles.push(...hitFiles);
|
|
41076
41231
|
else {
|
|
@@ -41078,8 +41233,10 @@ const runOxlint = async (options) => {
|
|
|
41078
41233
|
for (const hitFile of hitFiles) {
|
|
41079
41234
|
const cacheKey = cacheKeyByFile.get(hitFile);
|
|
41080
41235
|
const entry = cacheKey === void 0 ? null : sidecarCache.lookup(cacheKey);
|
|
41081
|
-
if (entry !== null && entry.probes.every((probe) => probeAnswers.answerFor(probe.kind, probe.path) === probe.answer))
|
|
41082
|
-
|
|
41236
|
+
if (entry !== null && entry.probes.every((probe) => probeAnswers.answerFor(probe.kind, probe.path) === probe.answer)) {
|
|
41237
|
+
sidecarReplayedFiles.push(hitFile);
|
|
41238
|
+
sidecarReplayedDiagnostics.push(...entry.diagnostics);
|
|
41239
|
+
} else sidecarLintFiles.push(hitFile);
|
|
41083
41240
|
if (performance.now() - verifySliceStartedAt >= 12) {
|
|
41084
41241
|
await yieldToEventLoop();
|
|
41085
41242
|
verifySliceStartedAt = performance.now();
|
|
@@ -41105,6 +41262,7 @@ const runOxlint = async (options) => {
|
|
|
41105
41262
|
sidecarRuleIdFilter: new Set(unboundedSidecarRuleIds)
|
|
41106
41263
|
}), "oxlintrc.sidecar-unbounded.json", hitFiles, void 0) : {
|
|
41107
41264
|
diagnostics: [],
|
|
41265
|
+
analyzedFiles: [],
|
|
41108
41266
|
didDropReactHooksJsPlugin: false,
|
|
41109
41267
|
hadPartialFailure: false
|
|
41110
41268
|
};
|
|
@@ -41135,6 +41293,15 @@ const runOxlint = async (options) => {
|
|
|
41135
41293
|
probesByFile: await missProbesTask
|
|
41136
41294
|
}]
|
|
41137
41295
|
});
|
|
41296
|
+
const analyzedFileSet = new Set(fullResult.analyzedFiles);
|
|
41297
|
+
const boundedSidecarAnalyzedFileSet = new Set(boundedSidecarResult.analyzedFiles);
|
|
41298
|
+
const unboundedSidecarAnalyzedFileSet = new Set(unboundedSidecarResult.analyzedFiles);
|
|
41299
|
+
const sidecarReplayedFileSet = new Set(sidecarReplayedFiles);
|
|
41300
|
+
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);
|
|
41301
|
+
onFileCoverage?.({
|
|
41302
|
+
candidateFiles,
|
|
41303
|
+
analyzedFiles: candidateFiles.filter((candidateFile) => analyzedFileSet.has(candidateFile))
|
|
41304
|
+
});
|
|
41138
41305
|
return dedupeDiagnostics([
|
|
41139
41306
|
...replayedDiagnostics,
|
|
41140
41307
|
...fullResult.diagnostics,
|
|
@@ -41145,6 +41312,7 @@ const runOxlint = async (options) => {
|
|
|
41145
41312
|
}
|
|
41146
41313
|
const baseArgs = makeBaseArgs(configPath);
|
|
41147
41314
|
const fileBatches = buildFileBatches(baseArgs, candidateFiles);
|
|
41315
|
+
let analyzedFiles = [];
|
|
41148
41316
|
const runBatches = () => spawnLintBatches({
|
|
41149
41317
|
baseArgs,
|
|
41150
41318
|
fileBatches,
|
|
@@ -41152,6 +41320,9 @@ const runOxlint = async (options) => {
|
|
|
41152
41320
|
nodeBinaryPath,
|
|
41153
41321
|
project,
|
|
41154
41322
|
onPartialFailure,
|
|
41323
|
+
onAnalyzedFiles: (filePaths) => {
|
|
41324
|
+
analyzedFiles = filePaths;
|
|
41325
|
+
},
|
|
41155
41326
|
onFileProgress: options.onFileProgress,
|
|
41156
41327
|
spawnTimeoutMs,
|
|
41157
41328
|
outputMaxBytes,
|
|
@@ -41161,7 +41332,12 @@ const runOxlint = async (options) => {
|
|
|
41161
41332
|
});
|
|
41162
41333
|
writeOxlintConfig(configPath, buildConfig({ extendsPaths }));
|
|
41163
41334
|
try {
|
|
41164
|
-
|
|
41335
|
+
const diagnostics = await runBatches();
|
|
41336
|
+
onFileCoverage?.({
|
|
41337
|
+
candidateFiles,
|
|
41338
|
+
analyzedFiles
|
|
41339
|
+
});
|
|
41340
|
+
return diagnostics;
|
|
41165
41341
|
} catch (error) {
|
|
41166
41342
|
const reactHooksJsDropNote = reactHooksJsPluginDropNote(error);
|
|
41167
41343
|
if (reactHooksJsDropNote !== null) {
|
|
@@ -41171,11 +41347,20 @@ const runOxlint = async (options) => {
|
|
|
41171
41347
|
}));
|
|
41172
41348
|
const diagnostics = await runBatches();
|
|
41173
41349
|
onPartialFailure?.(reactHooksJsDropNote);
|
|
41350
|
+
onFileCoverage?.({
|
|
41351
|
+
candidateFiles,
|
|
41352
|
+
analyzedFiles
|
|
41353
|
+
});
|
|
41174
41354
|
return diagnostics;
|
|
41175
41355
|
}
|
|
41176
41356
|
if (extendsPaths.length === 0) throw error;
|
|
41177
41357
|
writeOxlintConfig(configPath, buildConfig({ extendsPaths: [] }));
|
|
41178
|
-
|
|
41358
|
+
const diagnostics = await runBatches();
|
|
41359
|
+
onFileCoverage?.({
|
|
41360
|
+
candidateFiles,
|
|
41361
|
+
analyzedFiles
|
|
41362
|
+
});
|
|
41363
|
+
return diagnostics;
|
|
41179
41364
|
}
|
|
41180
41365
|
} finally {
|
|
41181
41366
|
restoreDisableDirectives();
|
|
@@ -41255,6 +41440,7 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
|
|
|
41255
41440
|
onPartialFailure: (reason) => {
|
|
41256
41441
|
collectedFailures.push(reason);
|
|
41257
41442
|
},
|
|
41443
|
+
onFileCoverage: input.onFileCoverage,
|
|
41258
41444
|
onFileProgress: input.onFileProgress,
|
|
41259
41445
|
perFileLintCacheEnabled,
|
|
41260
41446
|
sidecarLintCacheEnabled,
|
|
@@ -41347,7 +41533,10 @@ const translateProjectInfoError = (cause, directory) => {
|
|
|
41347
41533
|
directory: cause.directory,
|
|
41348
41534
|
candidates: cause.candidates
|
|
41349
41535
|
}) });
|
|
41350
|
-
return new ReactDoctorError({ reason: new
|
|
41536
|
+
return new ReactDoctorError({ reason: new ProjectDiscoveryFailed({
|
|
41537
|
+
directory,
|
|
41538
|
+
cause
|
|
41539
|
+
}) });
|
|
41351
41540
|
};
|
|
41352
41541
|
var Project = class Project extends Service()("react-doctor/Project") {
|
|
41353
41542
|
static layerNode = succeed$3(Project, Project.of({ discover: fn("Project.discover")(function* (directory) {
|
|
@@ -41959,6 +42148,7 @@ const resolveGithubActionsScoreMetadata = (environment = process.env) => {
|
|
|
41959
42148
|
...actorAssociation !== void 0 ? { githubActorAssociation: actorAssociation } : {}
|
|
41960
42149
|
};
|
|
41961
42150
|
};
|
|
42151
|
+
const toNormalizedRelativePath = (filePath, rootDirectory) => Path.relative(Path.resolve(rootDirectory), Path.resolve(rootDirectory, filePath)).replaceAll("\\", "/") || ".";
|
|
41962
42152
|
const NO_HOOKS = {
|
|
41963
42153
|
beforeLint: () => void_,
|
|
41964
42154
|
afterLint: () => void_
|
|
@@ -42057,7 +42247,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42057
42247
|
repo
|
|
42058
42248
|
}).pipe(orElseSucceed(() => null)) : succeed$2(null));
|
|
42059
42249
|
const lintIncludePaths = (input.skipJsxIncludeFilter ? input.includePaths.length > 0 ? [...input.includePaths] : void 0 : computeExplicitLintIncludePaths([...input.includePaths], project)) ?? resolveLintIncludePaths(scanDirectory, resolvedConfig.config, project);
|
|
42060
|
-
const
|
|
42250
|
+
const fallbackScannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
|
|
42061
42251
|
const beforeLint = hooks.beforeLint ?? NO_HOOKS.beforeLint;
|
|
42062
42252
|
const afterLint = hooks.afterLint ?? NO_HOOKS.afterLint;
|
|
42063
42253
|
yield* beforeLint(project, lintIncludePaths ?? void 0);
|
|
@@ -42162,6 +42352,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42162
42352
|
let deadCodeCacheHit = null;
|
|
42163
42353
|
let deadCodeSummaryCacheHits = null;
|
|
42164
42354
|
let deadCodeSummaryCacheMisses = null;
|
|
42355
|
+
const lintFileCoverageState = { value: null };
|
|
42165
42356
|
const baseLintStream = linterService.run({
|
|
42166
42357
|
rootDirectory: scanDirectory,
|
|
42167
42358
|
project,
|
|
@@ -42177,6 +42368,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42177
42368
|
lastReportedTotalFileCount = totalFileCount;
|
|
42178
42369
|
runSync(scanProgress.update(`Scanning files (${scannedFileCount}/${totalFileCount})${workerCountSuffix}...`));
|
|
42179
42370
|
},
|
|
42371
|
+
onFileCoverage: (coverage) => {
|
|
42372
|
+
lintFileCoverageState.value = coverage;
|
|
42373
|
+
},
|
|
42180
42374
|
onCacheStats: (cacheHitFileCount, totalConsideredFileCount) => {
|
|
42181
42375
|
lintCacheHitFileCount = cacheHitFileCount;
|
|
42182
42376
|
lintCacheTotalFileCount = totalConsideredFileCount;
|
|
@@ -42207,7 +42401,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42207
42401
|
const lintFailureState = yield* get$2(lintFailure);
|
|
42208
42402
|
yield* afterLint(lintFailureState.didFail);
|
|
42209
42403
|
if (lintFailureState.didFail) yield* scanProgress.fail(formatLintFailText(lintFailureState.reasonTag, process.version));
|
|
42210
|
-
const
|
|
42404
|
+
const candidateFiles = lintFileCoverageState.value === null ? [] : [...new Set(lintFileCoverageState.value.candidateFiles.map((filePath) => toNormalizedRelativePath(filePath, scanDirectory)))];
|
|
42405
|
+
const analyzedFiles = lintFileCoverageState.value === null ? [] : [...new Set(lintFileCoverageState.value.analyzedFiles.map((filePath) => toNormalizedRelativePath(filePath, scanDirectory)))].sort();
|
|
42406
|
+
const totalFileCount = candidateFiles.length || lastReportedTotalFileCount || (lintIncludePaths?.length ?? project.sourceFileCount);
|
|
42407
|
+
const scannedFilePaths = input.suppressScanSummary ? candidateFiles.length > 0 ? candidateFiles.map((filePath) => Path.resolve(scanDirectory, filePath)) : fallbackScannedFilePaths : [];
|
|
42211
42408
|
const scannedFilesLabel = `${totalFileCount} ${totalFileCount === 1 ? "file" : "files"}`;
|
|
42212
42409
|
let deadCodeCollected = [];
|
|
42213
42410
|
if (lintFailureState.didFail) {
|
|
@@ -42289,6 +42486,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
|
|
|
42289
42486
|
deadCodeOverlapped: shouldOverlapDeadCode,
|
|
42290
42487
|
scannedFileCount: totalFileCount,
|
|
42291
42488
|
scannedFilePaths,
|
|
42489
|
+
analyzedFiles,
|
|
42292
42490
|
scanElapsedMilliseconds,
|
|
42293
42491
|
scanConcurrency,
|
|
42294
42492
|
supplyChainOverlapTimedOut: supplyChainResult.timedOut,
|
|
@@ -42540,7 +42738,7 @@ const buildJsonReportError = (input) => {
|
|
|
42540
42738
|
sentryEventId
|
|
42541
42739
|
};
|
|
42542
42740
|
return {
|
|
42543
|
-
schemaVersion:
|
|
42741
|
+
schemaVersion: 3,
|
|
42544
42742
|
version: input.version,
|
|
42545
42743
|
ok: false,
|
|
42546
42744
|
directory: input.directory,
|
|
@@ -42585,6 +42783,7 @@ const summarizeDiagnostics = (diagnostics, worstScore = null, worstScoreLabel =
|
|
|
42585
42783
|
* React-runtime rule family was gated off for the project.
|
|
42586
42784
|
*/
|
|
42587
42785
|
const hasReactRuntime = (project) => project.reactVersion !== null || project.preactVersion !== null;
|
|
42786
|
+
const isScanComplete = (input) => input.analyzedFileCount !== void 0 && input.scannedFileCount !== void 0 && input.skippedCheckCount === 0 && input.skippedCheckReasonCount === 0 && input.analyzedFileCount === input.scannedFileCount;
|
|
42588
42787
|
const toJsonDiff = (diff) => {
|
|
42589
42788
|
if (!diff) return null;
|
|
42590
42789
|
return {
|
|
@@ -42607,21 +42806,68 @@ const findWorstScoredProject = (projects) => {
|
|
|
42607
42806
|
}
|
|
42608
42807
|
return worst;
|
|
42609
42808
|
};
|
|
42809
|
+
const toJsonReportDiagnostic = (diagnostic, projectRoot, reportRoot) => {
|
|
42810
|
+
const normalizedFilePath = toNormalizedRelativePath(diagnostic.filePath, projectRoot);
|
|
42811
|
+
const reportRelativeFilePath = toNormalizedRelativePath(Path.resolve(projectRoot, diagnostic.filePath), reportRoot);
|
|
42812
|
+
const ruleIdentity = getDiagnosticRuleIdentity(diagnostic);
|
|
42813
|
+
return {
|
|
42814
|
+
...diagnostic,
|
|
42815
|
+
id: buildDiagnosticIdentity({
|
|
42816
|
+
filePath: reportRelativeFilePath,
|
|
42817
|
+
line: diagnostic.line,
|
|
42818
|
+
column: diagnostic.column,
|
|
42819
|
+
plugin: diagnostic.plugin,
|
|
42820
|
+
rule: diagnostic.rule
|
|
42821
|
+
}),
|
|
42822
|
+
normalizedFilePath,
|
|
42823
|
+
category: ruleIdentity.category,
|
|
42824
|
+
tags: [...new Set(ruleIdentity.tags)].sort()
|
|
42825
|
+
};
|
|
42826
|
+
};
|
|
42610
42827
|
const buildJsonReport = (input) => {
|
|
42611
|
-
const projects = input.scans.map(({ directory, result }) =>
|
|
42612
|
-
|
|
42613
|
-
|
|
42614
|
-
|
|
42615
|
-
|
|
42616
|
-
|
|
42617
|
-
|
|
42618
|
-
|
|
42619
|
-
|
|
42620
|
-
|
|
42828
|
+
const projects = input.scans.map(({ directory, result }) => {
|
|
42829
|
+
const skippedChecks = result.skippedChecks ?? [];
|
|
42830
|
+
const analyzedFiles = [...new Set((result.analyzedFiles ?? []).map((filePath) => toNormalizedRelativePath(filePath, result.project.rootDirectory)))].sort();
|
|
42831
|
+
const scannedFileCount = result.scannedFileCount ?? result.project.sourceFileCount;
|
|
42832
|
+
return {
|
|
42833
|
+
directory,
|
|
42834
|
+
packageRoot: result.project.rootDirectory,
|
|
42835
|
+
framework: result.project.framework,
|
|
42836
|
+
project: result.project,
|
|
42837
|
+
diagnostics: result.diagnostics.map((diagnostic) => toJsonReportDiagnostic(diagnostic, result.project.rootDirectory, input.directory)),
|
|
42838
|
+
score: result.score,
|
|
42839
|
+
skippedChecks,
|
|
42840
|
+
...result.skippedCheckReasons ? { skippedCheckReasons: result.skippedCheckReasons } : {},
|
|
42841
|
+
analyzedFiles,
|
|
42842
|
+
analyzedFileCount: analyzedFiles.length,
|
|
42843
|
+
complete: isScanComplete({
|
|
42844
|
+
analyzedFileCount: result.analyzedFiles === void 0 ? void 0 : analyzedFiles.length,
|
|
42845
|
+
scannedFileCount,
|
|
42846
|
+
skippedCheckCount: skippedChecks.length,
|
|
42847
|
+
skippedCheckReasonCount: Object.keys(result.skippedCheckReasons ?? {}).length
|
|
42848
|
+
}),
|
|
42849
|
+
...typeof result.scannedFileCount === "number" ? { scannedFileCount } : {},
|
|
42850
|
+
elapsedMilliseconds: result.elapsedMilliseconds
|
|
42851
|
+
};
|
|
42852
|
+
});
|
|
42621
42853
|
const flattenedDiagnostics = projects.flatMap((entry) => entry.diagnostics);
|
|
42622
42854
|
const worstScoredProject = findWorstScoredProject(projects);
|
|
42623
|
-
const
|
|
42624
|
-
const
|
|
42855
|
+
const diagnosticSummary = summarizeDiagnostics(flattenedDiagnostics, worstScoredProject?.score?.score ?? null, worstScoredProject?.score?.label ?? null);
|
|
42856
|
+
const affectedFileCount = projects.reduce((totalAffectedFileCount, project) => totalAffectedFileCount + new Set(project.diagnostics.map((diagnostic) => diagnostic.normalizedFilePath)).size, 0);
|
|
42857
|
+
const summary = {
|
|
42858
|
+
...diagnosticSummary,
|
|
42859
|
+
affectedFileCount
|
|
42860
|
+
};
|
|
42861
|
+
return {
|
|
42862
|
+
schemaVersion: 3,
|
|
42863
|
+
mode: input.baseline !== void 0 ? "baseline" : input.baselineDegraded && input.mode === "baseline" ? "diff" : input.mode,
|
|
42864
|
+
...input.baseline ? { baseline: {
|
|
42865
|
+
baseRef: input.baseline.baseRef,
|
|
42866
|
+
newCount: summary.totalDiagnosticCount,
|
|
42867
|
+
fixedCount: input.baseline.fixedCount,
|
|
42868
|
+
baseTotalCount: input.baseline.baseTotalCount
|
|
42869
|
+
} } : {},
|
|
42870
|
+
...input.baselineDegraded ? { baselineDegraded: true } : {},
|
|
42625
42871
|
...input.scans.length > 0 ? { reactDetected: input.scans.some((scan) => hasReactRuntime(scan.result.project)) } : {},
|
|
42626
42872
|
version: input.version,
|
|
42627
42873
|
ok: true,
|
|
@@ -42633,39 +42879,26 @@ const buildJsonReport = (input) => {
|
|
|
42633
42879
|
elapsedMilliseconds: input.totalElapsedMilliseconds,
|
|
42634
42880
|
error: null
|
|
42635
42881
|
};
|
|
42636
|
-
if (input.baseline) return {
|
|
42637
|
-
schemaVersion: 2,
|
|
42638
|
-
mode: "baseline",
|
|
42639
|
-
baseline: {
|
|
42640
|
-
baseRef: input.baseline.baseRef,
|
|
42641
|
-
newCount: summary.totalDiagnosticCount,
|
|
42642
|
-
fixedCount: input.baseline.fixedCount,
|
|
42643
|
-
baseTotalCount: input.baseline.baseTotalCount
|
|
42644
|
-
},
|
|
42645
|
-
...shared
|
|
42646
|
-
};
|
|
42647
|
-
return {
|
|
42648
|
-
schemaVersion: 1,
|
|
42649
|
-
mode: input.mode,
|
|
42650
|
-
...input.baselineDegraded ? { baselineDegraded: true } : {},
|
|
42651
|
-
...shared
|
|
42652
|
-
};
|
|
42653
42882
|
};
|
|
42654
42883
|
/**
|
|
42655
42884
|
* Single source of truth for the skipped-check accounting shared by the
|
|
42656
42885
|
* CLI renderer (`react-doctor/src/inspect.ts → finalizeAndRender`) and the
|
|
42657
42886
|
* programmatic shell (`@react-doctor/api → diagnose()`). Both surface a
|
|
42658
|
-
* failed
|
|
42887
|
+
* failed or partial analysis pass instead of a false "all clear", so the
|
|
42659
42888
|
* branch logic lives here once.
|
|
42660
42889
|
*/
|
|
42661
42890
|
const buildSkippedChecks = (input) => {
|
|
42662
42891
|
const skippedChecks = [];
|
|
42663
42892
|
if (input.didLintFail) skippedChecks.push("lint");
|
|
42664
42893
|
if (input.didDeadCodeFail) skippedChecks.push("dead-code");
|
|
42894
|
+
if (input.supplyChainOverlapTimedOut) skippedChecks.push("supply-chain");
|
|
42895
|
+
if (input.securityScanFailed) skippedChecks.push("security-scan");
|
|
42665
42896
|
const skippedCheckReasons = {};
|
|
42666
42897
|
if (input.didLintFail && input.lintFailureReason !== null) skippedCheckReasons.lint = input.lintFailureReason;
|
|
42667
42898
|
else if (input.lintPartialFailures.length > 0) skippedCheckReasons["lint:partial"] = input.lintPartialFailures.join("; ");
|
|
42668
42899
|
if (input.didDeadCodeFail && input.deadCodeFailureReason !== null) skippedCheckReasons["dead-code"] = input.deadCodeFailureReason;
|
|
42900
|
+
if (input.supplyChainOverlapTimedOut) skippedCheckReasons["supply-chain"] = "Supply-chain analysis timed out and was skipped.";
|
|
42901
|
+
if (input.securityScanFailed) skippedCheckReasons["security-scan"] = "Security scan failed and was skipped.";
|
|
42669
42902
|
return {
|
|
42670
42903
|
skippedChecks,
|
|
42671
42904
|
skippedCheckReasons
|
|
@@ -42854,6 +43087,8 @@ const outputToDiagnoseResult = (output, elapsedMilliseconds) => {
|
|
|
42854
43087
|
score: output.score,
|
|
42855
43088
|
skippedChecks,
|
|
42856
43089
|
...Object.keys(skippedCheckReasons).length > 0 ? { skippedCheckReasons } : {},
|
|
43090
|
+
analyzedFiles: output.analyzedFiles,
|
|
43091
|
+
scannedFileCount: output.scannedFileCount,
|
|
42857
43092
|
project: output.project,
|
|
42858
43093
|
reactDetected: hasReactRuntime(output.project),
|
|
42859
43094
|
elapsedMilliseconds
|
|
@@ -42963,6 +43198,8 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
42963
43198
|
score: result.score,
|
|
42964
43199
|
skippedChecks: result.skippedChecks,
|
|
42965
43200
|
...result.skippedCheckReasons ? { skippedCheckReasons: result.skippedCheckReasons } : {},
|
|
43201
|
+
...result.analyzedFiles ? { analyzedFiles: result.analyzedFiles } : {},
|
|
43202
|
+
...typeof result.scannedFileCount === "number" ? { scannedFileCount: result.scannedFileCount } : {},
|
|
42966
43203
|
project: result.project,
|
|
42967
43204
|
elapsedMilliseconds: result.elapsedMilliseconds
|
|
42968
43205
|
}
|
|
@@ -42973,4 +43210,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
42973
43210
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
42974
43211
|
|
|
42975
43212
|
//# sourceMappingURL=index.js.map
|
|
42976
|
-
//# debugId=
|
|
43213
|
+
//# debugId=1833ffea-5e6b-5c0b-af42-5334f6a8a63b
|