react-doctor 0.5.8-dev.c16e8ea → 0.5.8-dev.c2af308

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,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1e049c6a-27f7-5c62-8be8-57ce0b987f6f")}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]="83529d8f-2ca3-50ba-a3b9-44622f913549")}catch(e){}}();
3
3
  import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import * as NFS from "node:fs";
@@ -7,7 +7,7 @@ import fs from "node:fs";
7
7
  import * as Path from "node:path";
8
8
  import path from "node:path";
9
9
  import * as NodeChildProcess from "node:child_process";
10
- import { spawn, spawnSync } from "node:child_process";
10
+ import { execFileSync, spawn, spawnSync } from "node:child_process";
11
11
  import * as ts from "typescript";
12
12
  import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
13
13
  import * as OS from "node:os";
@@ -33695,6 +33695,9 @@ const SCORE_API_URL = "https://www.react.doctor/api/score";
33695
33695
  const FETCH_TIMEOUT_MS = 1e4;
33696
33696
  const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
33697
33697
  const SPAWN_ARGS_MAX_LENGTH_CHARS = 24e3;
33698
+ const SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX = 15e5;
33699
+ const SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN = 8e5;
33700
+ const NODE_VERSION_PROBE_TIMEOUT_MS = 5e3;
33698
33701
  const PER_WORKER_MEM_BUDGET_BYTES = 1024 * 1024 * 1024;
33699
33702
  const DEFAULT_BRANCH_CANDIDATES = ["main", "master"];
33700
33703
  const ADOPTABLE_LINT_CONFIG_FILENAMES = [".oxlintrc.json", ".eslintrc.json"];
@@ -34519,7 +34522,7 @@ const tokenizeRuleList = (ruleList) => {
34519
34522
  const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
34520
34523
  const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
34521
34524
  const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
34522
- const buildHint = (tool, token, ruleId) => `oxlint matches plugin rules only by their full name, so \`${token}\` in your ${tool}-disable comment does not silence \`${ruleId}\` — change it to \`${ruleId}\`.`;
34525
+ const buildHint = (tool, token, ruleId) => `oxlint matches plugin rules only by their full name, so \`${token}\` in your ${tool}-disable comment does not silence \`${ruleId}\` — add \`${ruleId}\` to the comment (e.g. \`${token}, ${ruleId}\`).`;
34523
34526
  const tokenMisnamesRule = (token, ruleId) => token !== ruleId && isSameRuleKey(token, ruleId);
34524
34527
  const detectInlineNearMiss = (lines, diagnosticLineIndex, ruleId) => {
34525
34528
  const candidates = [{
@@ -35040,6 +35043,21 @@ const buildDiagnosticPipeline = (input) => {
35040
35043
  const fileLinesCache = /* @__PURE__ */ new Map();
35041
35044
  const fileContextCache = /* @__PURE__ */ new Map();
35042
35045
  const libraryFileCache = /* @__PURE__ */ new Map();
35046
+ const suppressions = /* @__PURE__ */ new Map();
35047
+ const suppress = (diagnostic, source) => {
35048
+ const { ruleKey } = getDiagnosticRuleIdentity(diagnostic);
35049
+ const suppressionKey = `${ruleKey}\u0000${source}`;
35050
+ const existing = suppressions.get(suppressionKey);
35051
+ suppressions.set(suppressionKey, existing ? {
35052
+ ...existing,
35053
+ count: existing.count + 1
35054
+ } : {
35055
+ rule: ruleKey,
35056
+ source,
35057
+ count: 1
35058
+ });
35059
+ return null;
35060
+ };
35043
35061
  const isLibraryFile = (filePath) => {
35044
35062
  let cached = libraryFileCache.get(filePath);
35045
35063
  if (cached === void 0) {
@@ -35094,51 +35112,54 @@ const buildDiagnosticPipeline = (input) => {
35094
35112
  const identifierMatch = JSX_NO_UNDEF_IDENTIFIER_PATTERN.exec(diagnostic.message);
35095
35113
  return identifierMatch !== null && runtimeGlobalNames.has(identifierMatch[1]);
35096
35114
  };
35097
- return { apply: (diagnostic) => {
35098
- if (shouldAutoSuppress(diagnostic)) return null;
35099
- let current = diagnostic;
35100
- let explicitSeverityOverride;
35101
- let explicitRuleOverride;
35102
- if (severityControls) {
35103
- const { ruleKey, category } = getDiagnosticRuleIdentity(current);
35104
- explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey }, severityControls);
35105
- explicitSeverityOverride = resolveRuleSeverityOverride({
35106
- ruleKey,
35107
- category
35108
- }, severityControls);
35109
- if (explicitSeverityOverride === "off") return null;
35110
- if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
35111
- }
35112
- if (explicitRuleOverride === void 0) {
35113
- if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
35114
- }
35115
- if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
35116
- if (userConfig) {
35117
- if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return null;
35118
- if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
35119
- if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return null;
35120
- if (isRnRawTextSuppressedByConfig(current)) return null;
35121
- if (isJsxNoUndefSuppressedByConfig(current)) return null;
35122
- }
35123
- if (respectInlineDisables && current.line > 0) {
35124
- const lines = getFileLines(current.filePath);
35125
- if (lines) {
35126
- const ruleIdentifier = `${current.plugin}/${current.rule}`;
35127
- const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
35128
- if (evaluation.isSuppressed) return null;
35129
- if (evaluation.nearMissHint) current = {
35130
- ...current,
35131
- suppressionHint: evaluation.nearMissHint
35132
- };
35115
+ return {
35116
+ apply: (diagnostic) => {
35117
+ if (shouldAutoSuppress(diagnostic)) return null;
35118
+ let current = diagnostic;
35119
+ let explicitSeverityOverride;
35120
+ let explicitRuleOverride;
35121
+ if (severityControls) {
35122
+ const { ruleKey, category } = getDiagnosticRuleIdentity(current);
35123
+ explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey }, severityControls);
35124
+ explicitSeverityOverride = resolveRuleSeverityOverride({
35125
+ ruleKey,
35126
+ category
35127
+ }, severityControls);
35128
+ if (explicitSeverityOverride === "off") return suppress(current, "config");
35129
+ if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
35133
35130
  }
35134
- }
35135
- const fileContext = getFileContext(current.filePath);
35136
- if (fileContext !== "production") current = {
35137
- ...current,
35138
- fileContext
35139
- };
35140
- return current;
35141
- } };
35131
+ if (explicitRuleOverride === void 0) {
35132
+ if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
35133
+ }
35134
+ if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
35135
+ if (userConfig) {
35136
+ if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return suppress(current, "config");
35137
+ if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
35138
+ if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return suppress(current, "override");
35139
+ if (isRnRawTextSuppressedByConfig(current)) return null;
35140
+ if (isJsxNoUndefSuppressedByConfig(current)) return null;
35141
+ }
35142
+ if (respectInlineDisables && current.line > 0) {
35143
+ const lines = getFileLines(current.filePath);
35144
+ if (lines) {
35145
+ const ruleIdentifier = `${current.plugin}/${current.rule}`;
35146
+ const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
35147
+ if (evaluation.isSuppressed) return suppress(current, "inline");
35148
+ if (evaluation.nearMissHint) current = {
35149
+ ...current,
35150
+ suppressionHint: evaluation.nearMissHint
35151
+ };
35152
+ }
35153
+ }
35154
+ const fileContext = getFileContext(current.filePath);
35155
+ if (fileContext !== "production") current = {
35156
+ ...current,
35157
+ fileContext
35158
+ };
35159
+ return current;
35160
+ },
35161
+ summarizeSuppressions: () => [...suppressions.values()]
35162
+ };
35142
35163
  };
35143
35164
  const OxlintUnavailableKind = Literals(["binary-not-found", "native-binding-missing"]);
35144
35165
  var OxlintUnavailable = class extends TaggedErrorClass()("OxlintUnavailable", {
@@ -35442,13 +35463,7 @@ var ScanDeadlineMs = class extends Reference("react-doctor/ScanDeadlineMs", { de
35442
35463
  * without recompiling react-doctor. Tests override via
35443
35464
  * `Layer.succeed(SupplyChainOverlapTimeoutMs, ...)`.
35444
35465
  */
35445
- var SupplyChainOverlapTimeoutMs = class extends Reference("react-doctor/SupplyChainOverlapTimeoutMs", { defaultValue: () => {
35446
- const raw = process.env["REACT_DOCTOR_SUPPLY_CHAIN_TIMEOUT_MS"];
35447
- if (raw === void 0) return SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS;
35448
- const parsed = Number(raw);
35449
- if (!Number.isFinite(parsed) || parsed <= 0) return SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS;
35450
- return parsed;
35451
- } }) {};
35466
+ var SupplyChainOverlapTimeoutMs = class extends Reference("react-doctor/SupplyChainOverlapTimeoutMs", { defaultValue: () => readPositiveEnvMs("REACT_DOCTOR_SUPPLY_CHAIN_TIMEOUT_MS", SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS) }) {};
35452
35467
  /**
35453
35468
  * Hard cap on combined stdout+stderr bytes per oxlint batch. The
35454
35469
  * subprocess gets SIGKILL'd if it produces more; the recovery path
@@ -37790,7 +37805,6 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
37790
37805
  return yield* tryPromise({
37791
37806
  try: (signal) => checkDeadCode({
37792
37807
  rootDirectory: input.rootDirectory,
37793
- userConfig: input.userConfig,
37794
37808
  parseConcurrency: input.parseConcurrency,
37795
37809
  workerTimeoutMs: input.workerTimeoutMs,
37796
37810
  abortSignal: signal
@@ -37913,6 +37927,11 @@ const isSafeGitRevision = (candidate) => {
37913
37927
  if (candidate.includes("..") || candidate.includes("@{")) return false;
37914
37928
  return SAFE_GIT_REVISION_PATTERN.test(candidate);
37915
37929
  };
37930
+ const resolveSpawnArgsLengthCap = () => {
37931
+ if (process.platform === "win32") return SPAWN_ARGS_MAX_LENGTH_CHARS;
37932
+ if (process.platform === "darwin") return SPAWN_ARGS_MAX_LENGTH_CHARS_DARWIN;
37933
+ return SPAWN_ARGS_MAX_LENGTH_CHARS_POSIX;
37934
+ };
37916
37935
  /**
37917
37936
  * Splits a git revision range into its endpoints: three-dot `A...B`
37918
37937
  * (symmetric, merge-base) or two-dot `A..B` (direct). Returns `null`
@@ -37997,7 +38016,8 @@ var Git = class Git extends Service()("react-doctor/Git") {
37997
38016
  return scoped(gen(function* () {
37998
38017
  if (!isDirectory(input.directory)) return yield* foldSpawnFailure(`spawn ENOTDIR (cwd is not a directory: ${input.directory})`);
37999
38018
  const argvLengthChars = input.command.length + 1 + input.args.reduce((total, arg) => total + arg.length + 1, 0);
38000
- if (argvLengthChars > 24e3) return yield* foldSpawnFailure(`spawn ENAMETOOLONG (${argvLengthChars} argv chars exceed ${SPAWN_ARGS_MAX_LENGTH_CHARS})`);
38019
+ const spawnArgsLengthCap = resolveSpawnArgsLengthCap();
38020
+ if (argvLengthChars > spawnArgsLengthCap) return yield* foldSpawnFailure(`spawn ENAMETOOLONG (${argvLengthChars} argv chars exceed ${spawnArgsLengthCap})`);
38001
38021
  const handle = yield* spawner.spawn(make$1(input.command, [...input.args], {
38002
38022
  cwd: input.directory,
38003
38023
  env: input.env,
@@ -38166,6 +38186,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
38166
38186
  if (resolvedCurrentBranch === null && explicitBaseBranch === void 0) return null;
38167
38187
  const baseBranch = explicitBaseBranch ?? (yield* defaultBranch(directory));
38168
38188
  if (baseBranch === null) return null;
38189
+ if (!isSafeGitRevision(baseBranch)) return null;
38169
38190
  if (explicitBaseBranch !== void 0) {
38170
38191
  if (!(yield* branchExists(directory, explicitBaseBranch))) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchMissing({ branch: explicitBaseBranch }) }));
38171
38192
  }
@@ -38516,7 +38537,7 @@ const normalizeConfigForHash = (config) => {
38516
38537
  if (Array.isArray(clone?.jsPlugins)) clone.jsPlugins = clone.jsPlugins.map((_, index) => `<plugin:${index}>`);
38517
38538
  return clone;
38518
38539
  };
38519
- 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(" ").update(input.tsconfigContent ?? "").digest("hex");
38540
+ 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");
38520
38541
  /**
38521
38542
  * Loads a plugin module via the local require resolver and extracts
38522
38543
  * `(name, ruleNames)` from either `module.exports.meta + rules` or
@@ -38794,24 +38815,38 @@ const createFileLintCache = (cacheDirectory, rulesetHash) => {
38794
38815
  updatedAtMs: Date.now(),
38795
38816
  files: Object.fromEntries(cappedEntries)
38796
38817
  };
38797
- const keptHashes = Object.entries(rulesets).sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8).map(([hash]) => hash);
38798
- const prunedRulesets = {};
38799
- for (const hash of keptHashes) prunedRulesets[hash] = rulesets[hash];
38800
38818
  atomicWriteJson(cacheFilePath, {
38801
38819
  version: 1,
38802
- rulesets: prunedRulesets
38820
+ rulesets: Object.fromEntries(Object.entries(rulesets).filter(([, bucket]) => isRecord(bucket) && typeof bucket.updatedAtMs === "number").sort(([, first], [, second]) => second.updatedAtMs - first.updatedAtMs).slice(0, 8))
38803
38821
  });
38804
38822
  }
38805
38823
  };
38806
38824
  };
38807
38825
  const bundledRequire = createRequire(import.meta.url);
38826
+ const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
38827
+ const resolveChildNodeVersion = (nodeBinaryPath) => {
38828
+ if (nodeBinaryPath === process.execPath) return process.version;
38829
+ const cachedVersion = childNodeVersionByBinaryPath.get(nodeBinaryPath);
38830
+ if (cachedVersion !== void 0) return cachedVersion;
38831
+ let version;
38832
+ try {
38833
+ version = execFileSync(nodeBinaryPath, ["--version"], {
38834
+ encoding: "utf8",
38835
+ timeout: NODE_VERSION_PROBE_TIMEOUT_MS
38836
+ }).trim();
38837
+ } catch {
38838
+ version = `unknown:${nodeBinaryPath}`;
38839
+ }
38840
+ childNodeVersionByBinaryPath.set(nodeBinaryPath, version);
38841
+ return version;
38842
+ };
38808
38843
  const TOOLCHAIN_PACKAGE_SPECIFIERS = [
38809
38844
  "oxlint/package.json",
38810
38845
  "oxlint-plugin-react-doctor/package.json",
38811
38846
  "eslint-plugin-react-hooks/package.json"
38812
38847
  ];
38813
- const resolveOxlintToolchainVersions = () => {
38814
- const versions = [`node=${process.version}`];
38848
+ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
38849
+ const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
38815
38850
  for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS) try {
38816
38851
  const packageJson = bundledRequire(specifier);
38817
38852
  const version = typeof packageJson.version === "string" ? packageJson.version : "unknown";
@@ -39667,21 +39702,27 @@ const spawnLintBatches = async (input) => {
39667
39702
  const allDiagnostics = [];
39668
39703
  const droppedFiles = [];
39669
39704
  let firstDropReason = null;
39670
- const splitDeadlineMs = Date.now() + splitTotalBudgetMs;
39671
- const spawnLintBatch = async (batch, depth) => {
39705
+ const spawnLintBatch = async (batch, depth, splitBudget) => {
39672
39706
  const batchArgs = [...baseArgs, ...batch];
39673
39707
  try {
39674
39708
  return parseOxlintOutput(await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath, spawnTimeoutMs, outputMaxBytes, signal), project, rootDirectory);
39675
39709
  } catch (error) {
39676
39710
  if (!isSplittableReactDoctorError(error)) throw error;
39677
- const splitBudgetExhausted = Date.now() >= splitDeadlineMs || depth >= splitMaxDepth;
39678
- if (batch.length <= 1 || splitBudgetExhausted) {
39711
+ splitBudget.deadlineMs ??= Date.now() + splitTotalBudgetMs;
39712
+ const isBudgetElapsed = Date.now() >= splitBudget.deadlineMs;
39713
+ const isDepthCapReached = depth >= splitMaxDepth;
39714
+ if (batch.length <= 1 || isBudgetElapsed || isDepthCapReached) {
39679
39715
  droppedFiles.push(...batch);
39680
- if (firstDropReason === null) firstDropReason = splitBudgetExhausted && batch.length > 1 ? `${error.message} (split budget exhausted after ${splitMaxDepth} levels / ${splitTotalBudgetMs / MILLISECONDS_PER_SECOND}s)` : error.message;
39716
+ if (firstDropReason === null) {
39717
+ let limitHint = "";
39718
+ if (isDepthCapReached) limitHint = ` (split depth cap of ${splitMaxDepth} levels reached)`;
39719
+ else if (isBudgetElapsed) limitHint = ` (split budget of ${splitTotalBudgetMs / MILLISECONDS_PER_SECOND}s exhausted at depth ${depth})`;
39720
+ firstDropReason = batch.length > 1 ? `${error.message}${limitHint}` : error.message;
39721
+ }
39681
39722
  return [];
39682
39723
  }
39683
39724
  const splitIndex = Math.ceil(batch.length / 2);
39684
- return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1)];
39725
+ return [...await spawnLintBatch(batch.slice(0, splitIndex), depth + 1, splitBudget), ...await spawnLintBatch(batch.slice(splitIndex), depth + 1, splitBudget)];
39685
39726
  }
39686
39727
  };
39687
39728
  let startedFileCount = 0;
@@ -39698,7 +39739,7 @@ const spawnLintBatches = async (input) => {
39698
39739
  try {
39699
39740
  const batchResults = await mapWithConcurrency(fileBatches, concurrency, async (batch) => {
39700
39741
  startedFileCount += batch.length;
39701
- const batchDiagnostics = await spawnLintBatch(batch, 0);
39742
+ const batchDiagnostics = await spawnLintBatch(batch, 0, { deadlineMs: null });
39702
39743
  scannedFileCount += batch.length;
39703
39744
  if (onFileProgress) {
39704
39745
  displayedFileCount = Math.min(Math.max(displayedFileCount, scannedFileCount), totalFileCount);
@@ -39772,7 +39813,14 @@ const resolveReactDoctorCacheDir = (projectDirectory) => {
39772
39813
  if (cacheDirOverride) return Path.join(cacheDirOverride, projectCacheSubdir(projectDirectory));
39773
39814
  const nodeModulesDirectory = Path.join(projectDirectory, "node_modules");
39774
39815
  if (NFS.existsSync(nodeModulesDirectory)) return Path.join(nodeModulesDirectory, ".cache", "react-doctor");
39775
- return Path.join(os.tmpdir(), "react-doctor-cache", projectCacheSubdir(projectDirectory));
39816
+ return Path.join(os.tmpdir(), `react-doctor-cache-${resolveUserCacheScope()}`, projectCacheSubdir(projectDirectory));
39817
+ };
39818
+ const resolveUserCacheScope = () => {
39819
+ try {
39820
+ return String(process.getuid?.() ?? os.userInfo().username);
39821
+ } catch {
39822
+ return "shared";
39823
+ }
39776
39824
  };
39777
39825
  const sortSourceFilesByCost = (entries) => [...entries].sort((left, right) => right.sizeBytes - left.sizeBytes).map((entry) => entry.path);
39778
39826
  /**
@@ -39940,7 +39988,7 @@ const runOxlint = async (options) => {
39940
39988
  extendsPaths: [],
39941
39989
  ruleSelection: "cacheable"
39942
39990
  }),
39943
- toolchainVersions: resolveOxlintToolchainVersions(),
39991
+ toolchainVersions: resolveOxlintToolchainVersions(nodeBinaryPath),
39944
39992
  ignorePatterns: combinedPatterns,
39945
39993
  tsconfigContent
39946
39994
  });
@@ -39954,7 +40002,7 @@ const runOxlint = async (options) => {
39954
40002
  missFiles.push(candidateFile);
39955
40003
  continue;
39956
40004
  }
39957
- const cacheKey = `${candidateFile.replaceAll("\\", "/")}${contentHash}`;
40005
+ const cacheKey = `${candidateFile.replaceAll("\\", "/")}\u0000${contentHash}`;
39958
40006
  cacheKeyByFile.set(candidateFile, cacheKey);
39959
40007
  const cachedDiagnostics = cache.lookup(cacheKey);
39960
40008
  if (cachedDiagnostics === null) missFiles.push(candidateFile);
@@ -40270,7 +40318,7 @@ const ScoreApiResponseSchema = Struct({
40270
40318
  })))
40271
40319
  });
40272
40320
  const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
40273
- const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, ...rest }) => rest);
40321
+ const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
40274
40322
  const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
40275
40323
  const describeFailure = (error) => {
40276
40324
  if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
@@ -40574,7 +40622,10 @@ const ALERT_SEVERITY_RANK = {
40574
40622
  medium: 2,
40575
40623
  low: 1
40576
40624
  };
40577
- const severityRank = (severity) => ALERT_SEVERITY_RANK[severity.toLowerCase()] ?? 0;
40625
+ const severityRank = (severity) => {
40626
+ const normalized = severity.toLowerCase();
40627
+ return Object.hasOwn(ALERT_SEVERITY_RANK, normalized) ? ALERT_SEVERITY_RANK[normalized] : 0;
40628
+ };
40578
40629
  const displaySeverity = (severity) => {
40579
40630
  const normalized = sanitizeTerminalText(severity.toLowerCase());
40580
40631
  return normalized === "middle" ? "medium" : normalized;
@@ -40591,7 +40642,7 @@ const ALERT_TYPE_LABELS = {
40591
40642
  typosquat: "possible typosquat"
40592
40643
  };
40593
40644
  const humanizeAlertType = (type) => type.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").toLowerCase().trim();
40594
- const friendlyAlertType = (type) => ALERT_TYPE_LABELS[type] ?? sanitizeTerminalText(humanizeAlertType(type));
40645
+ const friendlyAlertType = (type) => Object.hasOwn(ALERT_TYPE_LABELS, type) ? ALERT_TYPE_LABELS[type] : sanitizeTerminalText(humanizeAlertType(type));
40595
40646
  const summarizeAlertNote = (note) => {
40596
40647
  const collapsed = sanitizeTerminalText(note.replace(/\s+/g, " ").trim());
40597
40648
  const firstSentence = collapsed.split(/(?<=\.)\s/)[0] || collapsed;
@@ -40686,7 +40737,10 @@ const checkSupplyChain = (input) => gen(function* () {
40686
40737
  * outage.
40687
40738
  */
40688
40739
  var SupplyChain = class SupplyChain extends Service()("react-doctor/SupplyChain") {
40689
- static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(checkSupplyChain(input).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), withSpan("SupplyChain.run"))) }));
40740
+ static layerNode = succeed$3(SupplyChain, SupplyChain.of({ run: (input) => unwrap(flatMap$2(SupplyChainOverlapTimeoutMs, (totalTimeoutMs) => checkSupplyChain({
40741
+ ...input,
40742
+ totalTimeoutMs
40743
+ })).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), withSpan("SupplyChain.run"))) }));
40690
40744
  static layerOf = (diagnostics) => succeed$3(SupplyChain, SupplyChain.of({ run: () => fromIterable$1(diagnostics) }));
40691
40745
  };
40692
40746
  const getObjectProperty = (value, propertyName) => {
@@ -40834,10 +40888,11 @@ const runInspect = (input, hooks = {}) => gen(function* () {
40834
40888
  ...checkExpoProject(scanDirectory, project),
40835
40889
  ...checkReactNativeProject(scanDirectory, project)
40836
40890
  ])));
40837
- const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(promise(() => checkSecurityScanCooperative(scanDirectory, {
40891
+ const securityScanFailedRef = yield* make$13(false);
40892
+ const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
40838
40893
  project,
40839
40894
  ignoredTags: input.ignoredTags
40840
- })).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)))))).pipe(withSpan("SecurityScan.run")));
40895
+ })).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
40841
40896
  const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
40842
40897
  const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
40843
40898
  const supplyChainFiber = yield* forkChild(shouldRunSupplyChain ? runCollect(applyPerElementPipeline(supplyChainService.run({
@@ -40875,7 +40930,6 @@ const runInspect = (input, hooks = {}) => gen(function* () {
40875
40930
  const lintConcurrency = deadCodeParseConcurrency === void 0 ? scanConcurrency : Math.max(1, scanConcurrency - deadCodeParseConcurrency);
40876
40931
  const buildCollectDeadCode = (deadCodeTimeout) => runCollect(applyPerElementPipeline(deadCodeService.run({
40877
40932
  rootDirectory: scanDirectory,
40878
- userConfig: resolvedConfig.config,
40879
40933
  parseConcurrency: deadCodeParseConcurrency,
40880
40934
  workerTimeoutMs: deadCodeTimeout.workerTimeoutMs
40881
40935
  }).pipe(catchTag("ReactDoctorError", (error) => unwrap(gen(function* () {
@@ -41003,6 +41057,7 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41003
41057
  metadata: scoreMetadata
41004
41058
  });
41005
41059
  const lintPartialFailures = yield* get$2(partialFailuresRef);
41060
+ const securityScanFailed = yield* get$2(securityScanFailedRef);
41006
41061
  return {
41007
41062
  project,
41008
41063
  userConfig: resolvedConfig.config,
@@ -41023,8 +41078,10 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41023
41078
  scanElapsedMilliseconds,
41024
41079
  scanConcurrency,
41025
41080
  supplyChainOverlapTimedOut: supplyChainResult.timedOut,
41081
+ securityScanFailed,
41026
41082
  lintCacheHitFileCount,
41027
- lintCacheTotalFileCount
41083
+ lintCacheTotalFileCount,
41084
+ suppressedRuleCounts: transform.summarizeSuppressions()
41028
41085
  };
41029
41086
  }).pipe(withSpan("runInspect", { attributes: {
41030
41087
  "inspect.directory": input.directory,
@@ -41663,4 +41720,4 @@ const toJsonReport = (result, options) => buildJsonReport({
41663
41720
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
41664
41721
 
41665
41722
  //# sourceMappingURL=index.js.map
41666
- //# debugId=1e049c6a-27f7-5c62-8be8-57ce0b987f6f
41723
+ //# debugId=83529d8f-2ca3-50ba-a3b9-44622f913549