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/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]="e047abe8-ac42-570c-8465-e0f0dcb0715c")}catch(e){}}();
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 * as 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";
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
- * Versioned JsonReport schema. `JsonReport` is a `Schema.Union` so we
19358
- * can add `schemaVersion: 2` later as one new union member without
19359
- * breaking existing v1 consumers (the GitHub Action keys off the
19360
- * version literal). Today's union is single-arm; the shape is
19361
- * intentional.
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
- Union([JsonReportV1, JsonReportV2]);
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.4";
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, (spec) => bundledRequire$1(spec));
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, args, {
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) return [];
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
- const spawnPass = () => spawnLintBatches({
40971
- baseArgs: passBaseArgs,
40972
- fileBatches: passFileBatches,
40973
- rootDirectory,
40974
- nodeBinaryPath,
40975
- project,
40976
- onPartialFailure: reportPartialFailure,
40977
- onFileProgress: fileProgress,
40978
- spawnTimeoutMs,
40979
- outputMaxBytes,
40980
- concurrency: options.concurrency,
40981
- signal: options.signal,
40982
- deadlineEpochMs: options.deadlineEpochMs
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 && respectInlineDisables && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
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)) sidecarReplayedDiagnostics.push(...entry.diagnostics);
41082
- else sidecarLintFiles.push(hitFile);
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
- return await runBatches();
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
- return await runBatches();
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 ProjectNotFound({ directory }) });
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 scannedFilePaths = input.suppressScanSummary ? (lintIncludePaths ?? (yield* filesService.listSourceFiles(scanDirectory))).map((relativePath) => Path.resolve(scanDirectory, relativePath)) : [];
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 totalFileCount = lastReportedTotalFileCount || (lintIncludePaths?.length ?? project.sourceFileCount);
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: 1,
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
- directory,
42613
- project: result.project,
42614
- diagnostics: result.diagnostics,
42615
- score: result.score,
42616
- skippedChecks: result.skippedChecks,
42617
- ...result.skippedCheckReasons ? { skippedCheckReasons: result.skippedCheckReasons } : {},
42618
- ...typeof result.scannedFileCount === "number" ? { scannedFileCount: result.scannedFileCount } : {},
42619
- elapsedMilliseconds: result.elapsedMilliseconds
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 summary = summarizeDiagnostics(flattenedDiagnostics, worstScoredProject?.score?.score ?? null, worstScoredProject?.score?.label ?? null);
42624
- const shared = {
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 lint / dead-code pass instead of a false "all clear", so the
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=e047abe8-ac42-570c-8465-e0f0dcb0715c
43213
+ //# debugId=1833ffea-5e6b-5c0b-af42-5334f6a8a63b