react-doctor 0.7.1-dev.d353dad → 0.7.2-dev.aa519e5

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]="f00947fe-3794-5d73-a491-232b535dc962")}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]="10e3e1b0-f291-5306-b5fd-79b158b00159")}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";
@@ -9,7 +9,7 @@ import path from "node:path";
9
9
  import * as NodeChildProcess from "node:child_process";
10
10
  import { execFileSync, spawn, spawnSync } from "node:child_process";
11
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, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
12
+ import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
13
13
  import * as OS from "node:os";
14
14
  import os from "node:os";
15
15
  import { parseJSON5 } from "confbox";
@@ -32800,8 +32800,10 @@ const isFile = (filePath) => {
32800
32800
  };
32801
32801
  const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
32802
32802
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
32803
+ const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
32803
32804
  const MINIFIED_SNIFF_BYTES = 65536;
32804
32805
  const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
32806
+ const SCANNED_DOT_DIRECTORIES = new Set([".dumi", ".storybook"]);
32805
32807
  const IGNORED_DIRECTORIES = new Set([
32806
32808
  ".angular",
32807
32809
  ".astro",
@@ -32943,7 +32945,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
32943
32945
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
32944
32946
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
32945
32947
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
32946
- const CORE_PACKAGE_VERSION = "0.7.1";
32948
+ const CORE_PACKAGE_VERSION = "0.7.2";
32947
32949
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
32948
32950
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
32949
32951
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -32953,8 +32955,9 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
32953
32955
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
32954
32956
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
32955
32957
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
32956
- const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => IGNORED_DIRECTORIES.has(segment));
32957
- const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath);
32958
+ const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
32959
+ const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
32960
+ const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
32958
32961
  const isMinifiedSource = (absolutePath) => {
32959
32962
  let fileDescriptor;
32960
32963
  try {
@@ -33018,7 +33021,7 @@ function* walkSourceTreeFiles(rootDirectory) {
33018
33021
  for (const entry of readDirectoryEntries(currentDirectory)) {
33019
33022
  const absolutePath = Path.join(currentDirectory, entry.name);
33020
33023
  if (entry.isDirectory()) {
33021
- if (!IGNORED_DIRECTORIES.has(entry.name)) stack.push(absolutePath);
33024
+ if (!isIgnoredDirectoryName(entry.name)) stack.push(absolutePath);
33022
33025
  continue;
33023
33026
  }
33024
33027
  if (entry.isFile()) yield {
@@ -33984,6 +33987,10 @@ const normalizeCompilerOptions = (compilerOptions) => {
33984
33987
  hasExplicitLib
33985
33988
  };
33986
33989
  };
33990
+ const normalizeReferencePaths = (references) => {
33991
+ if (!Array.isArray(references)) return [];
33992
+ return references.map((reference) => isPlainObject(reference) && typeof reference.path === "string" ? reference.path : null).filter((referencePath) => referencePath !== null);
33993
+ };
33987
33994
  const readTsConfig = (filePath) => {
33988
33995
  let content;
33989
33996
  try {
@@ -33995,6 +34002,7 @@ const readTsConfig = (filePath) => {
33995
34002
  if (!isPlainObject(parsed.config)) return null;
33996
34003
  return {
33997
34004
  extends: typeof parsed.config.extends === "string" ? parsed.config.extends : void 0,
34005
+ referencePaths: normalizeReferencePaths(parsed.config.references),
33998
34006
  compilerOptions: normalizeCompilerOptions(parsed.config.compilerOptions)
33999
34007
  };
34000
34008
  };
@@ -34035,20 +34043,37 @@ const libEntryIncludesES2023Array = (entry) => {
34035
34043
  };
34036
34044
  const libIncludesES2023 = (lib) => lib.some(libEntryIncludesES2023Array);
34037
34045
  const compilerOptionsArePreES2023 = (compilerOptions) => {
34046
+ if (compilerOptions.target && targetYearIsPreES2023(compilerOptions.target)) return true;
34038
34047
  if (compilerOptions.hasExplicitLib) return !libIncludesES2023(compilerOptions.lib ?? []);
34039
- if (compilerOptions.target) return targetYearIsPreES2023(compilerOptions.target);
34040
34048
  return false;
34041
34049
  };
34042
34050
  const compilerOptionsDeclareTargetOrLib = (compilerOptions) => compilerOptions.hasExplicitLib || compilerOptions.target !== void 0;
34043
- const detectPreES2023FromConfig = (tsConfigPath) => {
34051
+ const detectPreES2023FromConfig = (tsConfigPath, visitedConfigPaths = /* @__PURE__ */ new Set()) => {
34052
+ if (visitedConfigPaths.has(tsConfigPath)) return false;
34044
34053
  const compilerOptions = readResolvedCompilerOptions(tsConfigPath, 0, /* @__PURE__ */ new Set());
34045
34054
  if (!compilerOptions) return false;
34046
- if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) return false;
34055
+ if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) {
34056
+ const tsConfig = readTsConfig(tsConfigPath);
34057
+ if (!tsConfig) return false;
34058
+ const nextVisitedConfigPaths = new Set(visitedConfigPaths);
34059
+ nextVisitedConfigPaths.add(tsConfigPath);
34060
+ const configDirectory = Path.dirname(tsConfigPath);
34061
+ return tsConfig.referencePaths.some((referencePath) => {
34062
+ const resolvedReferencePath = Path.resolve(configDirectory, referencePath);
34063
+ const referencedConfigPath = isFile(resolvedReferencePath) ? resolvedReferencePath : Path.join(resolvedReferencePath, TSCONFIG_FILENAME);
34064
+ return isFile(referencedConfigPath) && detectPreES2023FromConfig(referencedConfigPath, nextVisitedConfigPaths);
34065
+ });
34066
+ }
34047
34067
  return compilerOptionsArePreES2023(compilerOptions);
34048
34068
  };
34069
+ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"];
34049
34070
  const detectPreES2023Target = (directory) => {
34050
34071
  const tsConfigPath = Path.join(directory, TSCONFIG_FILENAME);
34051
34072
  if (isFile(tsConfigPath)) return detectPreES2023FromConfig(tsConfigPath);
34073
+ for (const fallbackFilename of FALLBACK_TSCONFIG_FILENAMES) {
34074
+ const fallbackPath = Path.join(directory, fallbackFilename);
34075
+ if (isFile(fallbackPath)) return detectPreES2023FromConfig(fallbackPath);
34076
+ }
34052
34077
  return false;
34053
34078
  };
34054
34079
  const REACT_DEPENDENCY_NAMES = new Set([
@@ -34210,6 +34235,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
34210
34235
  shopifyFlashListVersion: null,
34211
34236
  shopifyFlashListMajorVersion: null,
34212
34237
  hasReanimated: false,
34238
+ reanimatedVersion: null,
34213
34239
  isPreES2023Target: hasOwnTsConfig && detectPreES2023Target(directory),
34214
34240
  sourceFileCount
34215
34241
  };
@@ -34302,6 +34328,7 @@ const discoverProject = (directory) => {
34302
34328
  version: findShopifyFlashListVersion(directory, packageJson)
34303
34329
  }) : null;
34304
34330
  const hasReanimated = hasReactNativeWorkspace && someWorkspacePackageJson(directory, packageJson, isPackageJsonReanimatedAware);
34331
+ const reanimatedVersion = hasReanimated ? findInWorkspacePackageJsons(directory, packageJson, (workspacePackageJson) => getDependencySpec(workspacePackageJson, REANIMATED_DEPENDENCY_NAME)) : null;
34305
34332
  const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
34306
34333
  rootDirectory: directory,
34307
34334
  rootPackageJson: packageJson,
@@ -34331,6 +34358,7 @@ const discoverProject = (directory) => {
34331
34358
  shopifyFlashListVersion,
34332
34359
  shopifyFlashListMajorVersion: shopifyFlashListVersion === null ? null : getLowestDependencyMajor(shopifyFlashListVersion),
34333
34360
  hasReanimated,
34361
+ reanimatedVersion,
34334
34362
  isPreES2023Target,
34335
34363
  sourceFileCount
34336
34364
  };
@@ -34523,6 +34551,9 @@ const buildRuleSeverityControls = (config) => {
34523
34551
  ...config.buckets !== void 0 ? { buckets: config.buckets } : {}
34524
34552
  };
34525
34553
  };
34554
+ const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
34555
+ const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
34556
+ const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
34526
34557
  const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
34527
34558
  "effect/no-adjust-state-on-prop-change": "react-doctor/no-adjust-state-on-prop-change",
34528
34559
  "effect/no-chain-state-updates": "react-doctor/no-chain-state-updates",
@@ -34600,6 +34631,7 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
34600
34631
  "react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
34601
34632
  "react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
34602
34633
  "react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
34634
+ "react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
34603
34635
  "react/jsx-no-undef": "react-doctor/jsx-no-undef",
34604
34636
  "react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
34605
34637
  "react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
@@ -34673,9 +34705,6 @@ const tokenizeRuleList = (ruleList) => {
34673
34705
  if (!ruleSection) return [];
34674
34706
  return ruleSection.split(/[,\s]+/).map((token) => token.trim()).filter(Boolean);
34675
34707
  };
34676
- const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
34677
- const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
34678
- const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
34679
34708
  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}\`).`;
34680
34709
  const tokenMisnamesRule = (token, ruleId) => token !== ruleId && isSameRuleKey(token, ruleId);
34681
34710
  const detectInlineNearMiss = (lines, diagnosticLineIndex, ruleId) => {
@@ -34729,6 +34758,53 @@ const detectForeignDisableNearMiss = (lines, diagnosticLineIndex, ruleId) => {
34729
34758
  if (!ruleId.startsWith("react-doctor/")) return null;
34730
34759
  return detectInlineNearMiss(lines, diagnosticLineIndex, ruleId) ?? detectBlockNearMiss(lines, diagnosticLineIndex, ruleId);
34731
34760
  };
34761
+ const ESLINT_REACT_HOOKS_PLUGIN_PREFIX = "react-hooks/";
34762
+ const buildAcceptedTokens = (ruleId) => {
34763
+ const shortRuleId = ruleId.slice(15);
34764
+ return new Set([ruleId, `${ESLINT_REACT_HOOKS_PLUGIN_PREFIX}${shortRuleId}`]);
34765
+ };
34766
+ const listNamesRule = (ruleList, acceptedTokens) => tokenizeRuleList(ruleList).some((token) => acceptedTokens.has(token));
34767
+ const isInlineDisabled = (lines, diagnosticLineIndex, acceptedTokens) => {
34768
+ const candidates = [{
34769
+ line: lines[diagnosticLineIndex],
34770
+ requiredScope: "line"
34771
+ }, {
34772
+ line: lines[diagnosticLineIndex - 1],
34773
+ requiredScope: "next-line"
34774
+ }];
34775
+ for (const { line, requiredScope } of candidates) {
34776
+ const match = line?.match(FOREIGN_INLINE_DISABLE_PATTERN);
34777
+ if (!match) continue;
34778
+ const [, , scope, ruleList] = match;
34779
+ if (scope !== requiredScope) continue;
34780
+ if (listNamesRule(ruleList, acceptedTokens)) return true;
34781
+ }
34782
+ return false;
34783
+ };
34784
+ const isBlockDisabled = (lines, diagnosticLineIndex, acceptedTokens) => {
34785
+ let isRangeOpen = false;
34786
+ const lastLineIndex = Math.min(diagnosticLineIndex, lines.length - 1);
34787
+ for (let lineIndex = 0; lineIndex <= lastLineIndex; lineIndex++) {
34788
+ const line = lines[lineIndex];
34789
+ if (line === void 0 || !line.includes("-disable") && !line.includes("-enable")) continue;
34790
+ const disableMatch = line.match(FOREIGN_BLOCK_DISABLE_PATTERN);
34791
+ if (disableMatch && listNamesRule(disableMatch[2], acceptedTokens)) {
34792
+ isRangeOpen = true;
34793
+ continue;
34794
+ }
34795
+ const enableMatch = line.match(FOREIGN_BLOCK_ENABLE_PATTERN);
34796
+ if (enableMatch) {
34797
+ const enabledRules = tokenizeRuleList(enableMatch[1]);
34798
+ if (enabledRules.length === 0 || enabledRules.some((rule) => acceptedTokens.has(rule))) isRangeOpen = false;
34799
+ }
34800
+ }
34801
+ return isRangeOpen;
34802
+ };
34803
+ const isCompilerRuleForeignDisabled = (lines, diagnosticLineIndex, ruleId) => {
34804
+ if (!ruleId.startsWith("react-hooks-js/")) return false;
34805
+ const acceptedTokens = buildAcceptedTokens(ruleId);
34806
+ return isInlineDisabled(lines, diagnosticLineIndex, acceptedTokens) || isBlockDisabled(lines, diagnosticLineIndex, acceptedTokens);
34807
+ };
34732
34808
  const JSX_OPENER_TAG_PATTERN = /<[A-Za-z][\w.]*/g;
34733
34809
  const JSX_TAG_NAME_FOLLOW = /[A-Za-z]/;
34734
34810
  const isOpenerMatchInsideLineComment = (line, openerCharIndex) => {
@@ -34872,6 +34948,11 @@ const evaluateSuppression = (lines, diagnosticLineIndex, ruleId) => {
34872
34948
  isSuppressed: true,
34873
34949
  nearMissHint: null
34874
34950
  };
34951
+ if (isCompilerRuleForeignDisabled(lines, diagnosticLineIndex, ruleId)) return {
34952
+ isSuppressed: true,
34953
+ nearMissHint: null,
34954
+ isForeignDirective: true
34955
+ };
34875
34956
  const directComments = findStackedDisableCommentsAbove(lines, diagnosticLineIndex);
34876
34957
  if (hasChainSuppressor(directComments, ruleId)) return {
34877
34958
  isSuppressed: true,
@@ -35157,12 +35238,18 @@ const collectStringSet = (values) => {
35157
35238
  return new Set(values.filter((value) => typeof value === "string"));
35158
35239
  };
35159
35240
  const JSX_NO_UNDEF_IDENTIFIER_PATTERN = /^`([^`]+)`/;
35241
+ const NODE_CLI_PATH_SEGMENTS = new Set([
35242
+ "scripts",
35243
+ "bin",
35244
+ "tools"
35245
+ ]);
35246
+ const hasNodeCliPathSegment = (filePath) => filePath.split(/[\\/]/).slice(0, -1).some((segment) => NODE_CLI_PATH_SEGMENTS.has(segment));
35160
35247
  /**
35161
35248
  * Pre-compiles every stateful filter and returns a single
35162
35249
  * `apply(diagnostic)` closure that runs (in order):
35163
35250
  *
35164
35251
  * 1. auto-suppress (test-noise rules in test files; `migration-hint`
35165
- * wins over `test-noise`)
35252
+ * wins over `test-noise`; `no-console` on Node CLI scripts)
35166
35253
  * 2. severity overrides (top-level `rules` / `categories`, with
35167
35254
  * `"off"` dropping)
35168
35255
  * 3. warning suppression (only when `showWarnings` is false: drops every
@@ -35260,6 +35347,12 @@ const buildDiagnosticPipeline = (input) => {
35260
35347
  if (hasRawTextWrappers && isInsideStringOnlyWrapper(lines, diagnostic.line, diagnostic.column, rawTextWrapperComponentNames)) return true;
35261
35348
  return false;
35262
35349
  };
35350
+ const isNoConsoleOnNodeCliScript = (diagnostic) => {
35351
+ if (diagnostic.rule !== "no-console") return false;
35352
+ if (hasNodeCliPathSegment(diagnostic.filePath)) return true;
35353
+ const lines = getFileLines(diagnostic.filePath);
35354
+ return lines !== null && Boolean(lines[0]?.startsWith("#!"));
35355
+ };
35263
35356
  const isJsxNoUndefSuppressedByConfig = (diagnostic) => {
35264
35357
  if (!hasRuntimeGlobals) return false;
35265
35358
  if (diagnostic.rule !== "jsx-no-undef") return false;
@@ -35269,6 +35362,7 @@ const buildDiagnosticPipeline = (input) => {
35269
35362
  return {
35270
35363
  apply: (diagnostic) => {
35271
35364
  if (shouldAutoSuppress(diagnostic)) return null;
35365
+ if (isNoConsoleOnNodeCliScript(diagnostic)) return null;
35272
35366
  let current = diagnostic;
35273
35367
  let explicitSeverityOverride;
35274
35368
  let explicitRuleOverride;
@@ -35298,7 +35392,7 @@ const buildDiagnosticPipeline = (input) => {
35298
35392
  if (lines) {
35299
35393
  const ruleIdentifier = `${current.plugin}/${current.rule}`;
35300
35394
  const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
35301
- if (evaluation.isSuppressed) return suppress(current, "inline");
35395
+ if (evaluation.isSuppressed) return suppress(current, evaluation.isForeignDirective ? "foreign-inline" : "inline");
35302
35396
  if (evaluation.nearMissHint) current = {
35303
35397
  ...current,
35304
35398
  suppressionHint: evaluation.nearMissHint
@@ -39430,9 +39524,17 @@ const buildNoSecretsRecommendation = (project, fallbackRecommendation) => {
39430
39524
  return `Move secrets to server-only code. In ${formatFrameworkName(project.framework)}, only \`${publicEnvPrefix}\` env vars are exposed to the browser, and they must not contain secrets`;
39431
39525
  };
39432
39526
  const REANIMATED_SHARED_VALUE_HINT = "If this is a Reanimated shared value, prefer its React Compiler-compatible `.get()` / `.set()` accessors over `.value` — https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue/#react-compiler-support";
39527
+ const ACCESSORS_MIN_VERSION = "3.15.0";
39528
+ const supportsAccessors = (reanimatedVersion) => {
39529
+ if (reanimatedVersion === null) return true;
39530
+ const lowerBound = import_semver.validRange(reanimatedVersion) !== null ? import_semver.minVersion(reanimatedVersion) : import_semver.coerce(reanimatedVersion);
39531
+ if (lowerBound === null) return true;
39532
+ return import_semver.gte(lowerBound, ACCESSORS_MIN_VERSION);
39533
+ };
39433
39534
  const appendReanimatedSharedValueHint = (help, rule, project) => {
39434
39535
  if (rule !== "immutability") return help;
39435
39536
  if (!project.hasReanimated) return help;
39537
+ if (!supportsAccessors(project.reanimatedVersion)) return help;
39436
39538
  if (!help) return REANIMATED_SHARED_VALUE_HINT;
39437
39539
  return `${help}\n\n${REANIMATED_SHARED_VALUE_HINT}`;
39438
39540
  };
@@ -39594,13 +39696,13 @@ const REACT_USE_BINDING_RESOLUTION = {
39594
39696
  isReactUseBinding: true,
39595
39697
  isReactNamespaceBinding: false
39596
39698
  };
39597
- const getScriptKind = (filename) => {
39699
+ const getScriptKind$2 = (filename) => {
39598
39700
  if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
39599
39701
  if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
39600
39702
  if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
39601
39703
  return ts.ScriptKind.JS;
39602
39704
  };
39603
- const getUtf16Offset = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
39705
+ const getUtf16Offset$1 = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
39604
39706
  const unwrapExpression = (expression) => {
39605
39707
  let currentExpression = expression;
39606
39708
  while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
@@ -39849,8 +39951,8 @@ const findUseCallIdentifier = (sourceFile, useOffset) => {
39849
39951
  return matchedIdentifier;
39850
39952
  };
39851
39953
  const resolveUseCallBinding = (sourceText, filename, utf8Offset) => {
39852
- const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(filename));
39853
- const useIdentifier = findUseCallIdentifier(sourceFile, getUtf16Offset(sourceText, utf8Offset));
39954
+ const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getScriptKind$2(filename));
39955
+ const useIdentifier = findUseCallIdentifier(sourceFile, getUtf16Offset$1(sourceText, utf8Offset));
39854
39956
  if (!useIdentifier) return null;
39855
39957
  return resolveIdentifierBinding(useIdentifier, collectReactImportBindings(sourceFile), sourceFile);
39856
39958
  };
@@ -39871,6 +39973,201 @@ const shouldSuppressLocalUseHookDiagnostic = (diagnostic, rootDirectory) => {
39871
39973
  const bindingResolution = resolveUseCallBinding(sourceText, absolutePath, primaryLabel.span.offset);
39872
39974
  return bindingResolution !== null && !bindingResolution.isReactUseBinding;
39873
39975
  };
39976
+ const SUPPRESSED_COMPILER_CODES = new Set(["react-hooks-js(immutability)", "react-hooks-js(refs)"]);
39977
+ const WORKLET_DIRECTIVE = "worklet";
39978
+ const WORKLET_ACCEPTING_CALLEES = new Set([
39979
+ "useAnimatedStyle",
39980
+ "useAnimatedProps",
39981
+ "useDerivedValue",
39982
+ "useAnimatedReaction",
39983
+ "useAnimatedScrollHandler",
39984
+ "useAnimatedGestureHandler",
39985
+ "useFrameCallback",
39986
+ "runOnUI",
39987
+ "executeOnUIRuntimeSync"
39988
+ ]);
39989
+ const GESTURE_ROOT_IDENTIFIER = "Gesture";
39990
+ const getScriptKind$1 = (filename) => {
39991
+ if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
39992
+ if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
39993
+ if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
39994
+ return ts.ScriptKind.JS;
39995
+ };
39996
+ const getUtf16Offset = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
39997
+ const hasWorkletDirective = (node) => {
39998
+ if (!ts.isFunctionDeclaration(node) && !ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isMethodDeclaration(node)) return false;
39999
+ const body = node.body;
40000
+ if (!body || !ts.isBlock(body)) return false;
40001
+ for (const statement of body.statements) {
40002
+ if (!ts.isExpressionStatement(statement)) return false;
40003
+ if (!ts.isStringLiteral(statement.expression)) return false;
40004
+ if (statement.expression.text === WORKLET_DIRECTIVE) return true;
40005
+ }
40006
+ return false;
40007
+ };
40008
+ const rootIdentifierOfCallChain = (expression) => {
40009
+ let currentExpression = expression;
40010
+ while (true) {
40011
+ if (ts.isIdentifier(currentExpression)) return currentExpression.text;
40012
+ if (ts.isPropertyAccessExpression(currentExpression)) {
40013
+ currentExpression = currentExpression.expression;
40014
+ continue;
40015
+ }
40016
+ if (ts.isCallExpression(currentExpression)) {
40017
+ currentExpression = currentExpression.expression;
40018
+ continue;
40019
+ }
40020
+ return null;
40021
+ }
40022
+ };
40023
+ const isWorkletAcceptingCall = (callExpression) => {
40024
+ const callee = callExpression.expression;
40025
+ if (ts.isIdentifier(callee)) return WORKLET_ACCEPTING_CALLEES.has(callee.text);
40026
+ if (ts.isPropertyAccessExpression(callee)) {
40027
+ if (WORKLET_ACCEPTING_CALLEES.has(callee.name.text)) return true;
40028
+ return rootIdentifierOfCallChain(callee) === GESTURE_ROOT_IDENTIFIER;
40029
+ }
40030
+ return false;
40031
+ };
40032
+ const isFunctionWorklet = (functionNode) => {
40033
+ if (hasWorkletDirective(functionNode)) return true;
40034
+ const parent = functionNode.parent;
40035
+ return ts.isCallExpression(parent) && parent.arguments.some((argument) => argument === functionNode) && isWorkletAcceptingCall(parent);
40036
+ };
40037
+ const findNodeAtOffset = (sourceFile, targetOffset) => {
40038
+ let matchedNode = null;
40039
+ const visit = (node) => {
40040
+ if (node.getStart(sourceFile) > targetOffset || node.getEnd() <= targetOffset) return;
40041
+ matchedNode = node;
40042
+ ts.forEachChild(node, visit);
40043
+ };
40044
+ visit(sourceFile);
40045
+ return matchedNode;
40046
+ };
40047
+ const isOffsetInsideWorklet = (sourceFile, targetOffset) => {
40048
+ let currentNode = findNodeAtOffset(sourceFile, targetOffset);
40049
+ while (currentNode) {
40050
+ if (ts.isFunctionLike(currentNode) && isFunctionWorklet(currentNode)) return true;
40051
+ currentNode = currentNode.parent;
40052
+ }
40053
+ return false;
40054
+ };
40055
+ const shouldSuppressCompilerFindingInWorklet = (diagnostic, project, rootDirectory) => {
40056
+ if (!SUPPRESSED_COMPILER_CODES.has(diagnostic.code)) return false;
40057
+ if (!project.hasReanimated) return false;
40058
+ const primaryLabel = diagnostic.labels[0];
40059
+ if (!primaryLabel) return false;
40060
+ const absolutePath = Path.isAbsolute(diagnostic.filename) ? diagnostic.filename : Path.join(rootDirectory, diagnostic.filename);
40061
+ let sourceText;
40062
+ try {
40063
+ sourceText = NFS.readFileSync(absolutePath, "utf-8");
40064
+ } catch {
40065
+ return false;
40066
+ }
40067
+ return isOffsetInsideWorklet(ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getScriptKind$1(absolutePath)), getUtf16Offset(sourceText, primaryLabel.span.offset));
40068
+ };
40069
+ const MANUAL_MEMOIZATION_PLUGIN = "react-doctor";
40070
+ const MANUAL_MEMOIZATION_RULE = "react-compiler-no-manual-memoization";
40071
+ const REACT_COMPILER_PLUGIN = "react-hooks-js";
40072
+ const getScriptKind = (filename) => {
40073
+ if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
40074
+ if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
40075
+ if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
40076
+ return ts.ScriptKind.JS;
40077
+ };
40078
+ const isManualMemoizationDiagnostic = (diagnostic) => diagnostic.plugin === MANUAL_MEMOIZATION_PLUGIN && diagnostic.rule === MANUAL_MEMOIZATION_RULE;
40079
+ const nodeLineRange = (sourceFile, node) => ({
40080
+ startLine: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1,
40081
+ endLine: sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line + 1
40082
+ });
40083
+ const findOutermostEnclosingFunctionRange = (sourceFile, targetLine) => {
40084
+ let foundRange = null;
40085
+ const visit = (node) => {
40086
+ if (foundRange) return;
40087
+ if (ts.isFunctionLike(node)) {
40088
+ const range = nodeLineRange(sourceFile, node);
40089
+ if (range.startLine <= targetLine && targetLine <= range.endLine) foundRange = range;
40090
+ return;
40091
+ }
40092
+ ts.forEachChild(node, visit);
40093
+ };
40094
+ visit(sourceFile);
40095
+ return foundRange;
40096
+ };
40097
+ const NEWLINE_BYTE = 10;
40098
+ const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
40099
+ let lineNumber = 1;
40100
+ const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
40101
+ for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === NEWLINE_BYTE) lineNumber++;
40102
+ return lineNumber;
40103
+ };
40104
+ /**
40105
+ * Drops `react-doctor/react-compiler-no-manual-memoization` diagnostics
40106
+ * whose enclosing function also carries a `react-hooks-js` (React
40107
+ * Compiler) diagnostic. Every react-hooks-js finding marks a function the
40108
+ * compiler could NOT compile (a bail-out / skip / preserve-manual-
40109
+ * memoization failure), so "React Compiler already caches every value
40110
+ * here" is false for that function and the manual memoization is
40111
+ * load-bearing, not dead weight.
40112
+ *
40113
+ * Matching is per enclosing function, not per file: a bailed-out
40114
+ * component must not silence redundant-memo findings in a sibling
40115
+ * component the compiler did optimize.
40116
+ *
40117
+ * Module-scope `memo(() => …)` wrappers have no enclosing function; for
40118
+ * those the memo call's own span is the containment range, so a bail-out
40119
+ * inside the inline-wrapped component still suppresses. Every failure
40120
+ * path (unreadable file, missing span) fails open and keeps the
40121
+ * diagnostic.
40122
+ */
40123
+ const suppressMemoizationInBailedOutFunctions = (diagnostics, rootDirectory) => {
40124
+ const compilerDiagnosticLinesByFile = /* @__PURE__ */ new Map();
40125
+ let hasManualMemoizationDiagnostic = false;
40126
+ for (const diagnostic of diagnostics) {
40127
+ if (isManualMemoizationDiagnostic(diagnostic)) {
40128
+ hasManualMemoizationDiagnostic = true;
40129
+ continue;
40130
+ }
40131
+ if (diagnostic.plugin !== REACT_COMPILER_PLUGIN || diagnostic.line <= 0) continue;
40132
+ const lines = compilerDiagnosticLinesByFile.get(diagnostic.filePath);
40133
+ if (lines) lines.push(diagnostic.line);
40134
+ else compilerDiagnosticLinesByFile.set(diagnostic.filePath, [diagnostic.line]);
40135
+ }
40136
+ if (!hasManualMemoizationDiagnostic || compilerDiagnosticLinesByFile.size === 0) return diagnostics;
40137
+ const parsedFileCache = /* @__PURE__ */ new Map();
40138
+ const readAndParse = (filePath) => {
40139
+ const cached = parsedFileCache.get(filePath);
40140
+ if (cached !== void 0) return cached;
40141
+ const absolutePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory || ".", filePath);
40142
+ let parsed;
40143
+ try {
40144
+ const buffer = NFS.readFileSync(absolutePath);
40145
+ parsed = {
40146
+ sourceFile: ts.createSourceFile(absolutePath, buffer.toString("utf8"), ts.ScriptTarget.Latest, true, getScriptKind(absolutePath)),
40147
+ buffer
40148
+ };
40149
+ } catch {
40150
+ parsed = null;
40151
+ }
40152
+ parsedFileCache.set(filePath, parsed);
40153
+ return parsed;
40154
+ };
40155
+ const isInsideBailedOutFunction = (diagnostic) => {
40156
+ const compilerLines = compilerDiagnosticLinesByFile.get(diagnostic.filePath);
40157
+ if (!compilerLines || diagnostic.line <= 0) return false;
40158
+ const parsed = readAndParse(diagnostic.filePath);
40159
+ if (!parsed) return false;
40160
+ let containmentRange = findOutermostEnclosingFunctionRange(parsed.sourceFile, diagnostic.line);
40161
+ if (!containmentRange && diagnostic.offset !== void 0 && diagnostic.length !== void 0) containmentRange = {
40162
+ startLine: diagnostic.line,
40163
+ endLine: lineOfUtf8Offset(parsed.buffer, diagnostic.offset + diagnostic.length)
40164
+ };
40165
+ if (!containmentRange) return false;
40166
+ const { startLine, endLine } = containmentRange;
40167
+ return compilerLines.some((compilerLine) => startLine <= compilerLine && compilerLine <= endLine);
40168
+ };
40169
+ return diagnostics.filter((diagnostic) => !isManualMemoizationDiagnostic(diagnostic) || !isInsideBailedOutFunction(diagnostic));
40170
+ };
39874
40171
  const FILEPATH_WITH_LOCATION_PATTERN = /\S+\.\w+:\d+:\d+[\s\S]*$/;
39875
40172
  const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
39876
40173
  const TRAILING_PERIOD_PATTERN = /\.$/;
@@ -40010,7 +40307,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
40010
40307
  minifiedFileCache.set(absolutePath, minified);
40011
40308
  return minified;
40012
40309
  };
40013
- return parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory)).map((diagnostic) => {
40310
+ return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
40014
40311
  const { plugin, rule } = parseRuleCode(diagnostic.code);
40015
40312
  const primaryLabel = diagnostic.labels[0];
40016
40313
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
@@ -40037,7 +40334,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
40037
40334
  ...resolveMatchByOccurrence(rule, category) ? { matchByOccurrence: true } : {},
40038
40335
  ...relatedLocations.length > 0 ? { relatedLocations } : {}
40039
40336
  };
40040
- });
40337
+ }), rootDirectory);
40041
40338
  };
40042
40339
  const buildOxlintChildEnv = (sourceEnv) => {
40043
40340
  const childEnv = {};
@@ -40548,6 +40845,7 @@ const runOxlint = async (options) => {
40548
40845
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
40549
40846
  const severityControls = buildRuleSeverityControls(userConfig);
40550
40847
  validateRuleRegistration();
40848
+ resetManifestCaches();
40551
40849
  if (includePaths !== void 0 && includePaths.length === 0) return [];
40552
40850
  const pluginPath = resolvePluginPath();
40553
40851
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
@@ -41210,9 +41508,10 @@ const CONTEXT_AXES = [
41210
41508
  }
41211
41509
  ];
41212
41510
  const SCORE_AXES = [...GATED_AXES, ...CONTEXT_AXES];
41213
- const worstGatedAxis = (score) => {
41214
- let worst = GATED_AXES[0];
41215
- for (const axis of GATED_AXES) if (score[axis.key] < score[worst.key]) worst = axis;
41511
+ const gatedAxesForSection = (section) => section === "devDependencies" ? GATED_AXES.filter((axis) => axis.key !== "vulnerability") : GATED_AXES;
41512
+ const worstGatedAxis = (score, gatedAxes) => {
41513
+ let worst = gatedAxes[0];
41514
+ for (const axis of gatedAxes) if (score[axis.key] < score[worst.key]) worst = axis;
41216
41515
  return worst;
41217
41516
  };
41218
41517
  const clampScore = (value) => {
@@ -41236,6 +41535,69 @@ const resolveConcreteVersion = (spec) => {
41236
41535
  if (range === null || range === "*") return null;
41237
41536
  return import_semver.minVersion(trimmed)?.version ?? null;
41238
41537
  };
41538
+ const readTextFileOrNull = (filePath) => {
41539
+ try {
41540
+ return NFS.readFileSync(filePath, "utf-8");
41541
+ } catch {
41542
+ return null;
41543
+ }
41544
+ };
41545
+ const buildNpmLockLookup = (lockText) => {
41546
+ let parsed;
41547
+ try {
41548
+ parsed = JSON.parse(lockText);
41549
+ } catch {
41550
+ return null;
41551
+ }
41552
+ if (typeof parsed !== "object" || parsed === null) return null;
41553
+ const lock = parsed;
41554
+ return (name) => {
41555
+ const entry = lock.packages?.[`node_modules/${name}`] ?? lock.dependencies?.[name];
41556
+ return typeof entry?.version === "string" ? entry.version : null;
41557
+ };
41558
+ };
41559
+ const buildYarnLockLookup = (lockText) => {
41560
+ const lines = lockText.split(/\r?\n/);
41561
+ return (name, spec) => {
41562
+ const descriptor = `${name}@${spec}`;
41563
+ const berryDescriptor = `${name}@npm:${spec}`;
41564
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
41565
+ const line = lines[lineIndex];
41566
+ if (line.startsWith(" ") || line.startsWith("#") || !line.includes(":")) continue;
41567
+ const descriptors = line.replace(/:\s*$/, "").split(",").map((part) => part.trim().replace(/^"|"$/g, ""));
41568
+ if (!descriptors.includes(descriptor) && !descriptors.includes(berryDescriptor)) continue;
41569
+ for (let bodyIndex = lineIndex + 1; bodyIndex < lines.length && (lines[bodyIndex].startsWith(" ") || lines[bodyIndex] === ""); bodyIndex += 1) {
41570
+ const versionMatch = /^\s+version:?\s+"?([^"\s]+)"?/.exec(lines[bodyIndex]);
41571
+ if (versionMatch) return versionMatch[1];
41572
+ }
41573
+ return null;
41574
+ }
41575
+ return null;
41576
+ };
41577
+ };
41578
+ const buildPnpmLockLookup = (lockText) => {
41579
+ return (name) => {
41580
+ const entryPattern = new RegExp(`^ {4,8}['"]?${name.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&")}['"]?:\\s*$`);
41581
+ const lines = lockText.split(/\r?\n/);
41582
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
41583
+ if (!entryPattern.test(lines[lineIndex])) continue;
41584
+ for (let bodyIndex = lineIndex + 1; bodyIndex < lines.length && /^ {5,}\S/.test(lines[bodyIndex]); bodyIndex += 1) {
41585
+ const versionMatch = /^\s+version:\s+['"]?([^'"\s(]+)/.exec(lines[bodyIndex]);
41586
+ if (versionMatch) return versionMatch[1];
41587
+ }
41588
+ }
41589
+ return null;
41590
+ };
41591
+ };
41592
+ const buildLockedVersionLookup = (rootDirectory) => {
41593
+ const npmLockText = readTextFileOrNull(Path.join(rootDirectory, "package-lock.json"));
41594
+ if (npmLockText !== null) return buildNpmLockLookup(npmLockText);
41595
+ const yarnLockText = readTextFileOrNull(Path.join(rootDirectory, "yarn.lock"));
41596
+ if (yarnLockText !== null) return buildYarnLockLookup(yarnLockText);
41597
+ const pnpmLockText = readTextFileOrNull(Path.join(rootDirectory, "pnpm-lock.yaml"));
41598
+ if (pnpmLockText !== null) return buildPnpmLockLookup(pnpmLockText);
41599
+ return null;
41600
+ };
41239
41601
  const locateDependencyKey = (packageJsonText, section, name) => {
41240
41602
  const needle = `"${name}"`;
41241
41603
  const sectionHeader = new RegExp(`"${section}"\\s*:\\s*\\{`);
@@ -41262,7 +41624,7 @@ const locateDependencyKey = (packageJsonText, section, name) => {
41262
41624
  }
41263
41625
  return null;
41264
41626
  };
41265
- const collectDependenciesToScore = (packageJson, packageJsonText, includeDevDependencies) => {
41627
+ const collectDependenciesToScore = (packageJson, packageJsonText, includeDevDependencies, lockedVersionLookup) => {
41266
41628
  const sectionByName = /* @__PURE__ */ new Map();
41267
41629
  for (const name of Object.keys(packageJson.dependencies ?? {})) sectionByName.set(name, "dependencies");
41268
41630
  if (includeDevDependencies) {
@@ -41272,13 +41634,18 @@ const collectDependenciesToScore = (packageJson, packageJsonText, includeDevDepe
41272
41634
  for (const [name, section] of sectionByName) {
41273
41635
  if (SUPPLY_CHAIN_IGNORED_PACKAGES.has(name)) continue;
41274
41636
  const spec = (packageJson[section] ?? {})[name] ?? "";
41275
- const version = resolveConcreteVersion(spec);
41276
- if (version === null) continue;
41637
+ const floorVersion = resolveConcreteVersion(spec);
41638
+ if (floorVersion === null) continue;
41639
+ const lockedVersion = lockedVersionLookup?.(name, spec) ?? null;
41640
+ const lockSatisfiesSpec = lockedVersion !== null && import_semver.valid(lockedVersion) !== null && import_semver.satisfies(lockedVersion, spec);
41641
+ const isExactPin = import_semver.valid(spec.trim()) !== null;
41277
41642
  const location = locateDependencyKey(packageJsonText, section, name);
41278
41643
  dependencies.push({
41279
41644
  name,
41280
- version,
41645
+ version: lockSatisfiesSpec ? lockedVersion : floorVersion,
41281
41646
  spec,
41647
+ section,
41648
+ resolution: isExactPin ? "pin" : lockSatisfiesSpec ? "locked" : "floor",
41282
41649
  line: location?.line ?? 0,
41283
41650
  column: location?.column ?? 0
41284
41651
  });
@@ -41429,7 +41796,11 @@ const formatAlertReason = (topAlerts, totalCount) => {
41429
41796
  }
41430
41797
  return `Socket flagged ${totalCount} alerts (${topAlerts.map((alert) => friendlyAlertType(alert.type)).join(", ")}${totalCount > topAlerts.length ? ` (+${totalCount - topAlerts.length} more)` : ""}); most severe: ${displaySeverity(topAlerts[0].severity)}.`;
41431
41798
  };
41432
- const formatDependencyIdentity = (dependency) => import_semver.valid(dependency.spec) !== null ? `${dependency.name}@${dependency.version}` : `${dependency.name}@${dependency.version} (lowest version "${dependency.spec}" allows)`;
41799
+ const formatDependencyIdentity = (dependency) => {
41800
+ if (dependency.resolution === "pin") return `${dependency.name}@${dependency.version}`;
41801
+ if (dependency.resolution === "locked") return `${dependency.name}@${dependency.version} (lockfile resolution of "${dependency.spec}")`;
41802
+ return `${dependency.name}@${dependency.version} (lowest version "${dependency.spec}" allows)`;
41803
+ };
41433
41804
  const buildSupplyChainHelp = (dependency, failingAxis, topAlerts, packagePageUrl, options) => {
41434
41805
  const hasCriticalAlert = topAlerts.some((alert) => alert.severity.toLowerCase() === "critical");
41435
41806
  const entry = `\`"${dependency.name}": "${dependency.spec}"\``;
@@ -41472,7 +41843,7 @@ const buildLowScoreDiagnostic = (dependency, artifact, failingAxis, options) =>
41472
41843
  const checkSupplyChain = (input) => gen(function* () {
41473
41844
  const options = resolveOptions(input.userConfig);
41474
41845
  const packageJsonPath = Path.join(input.rootDirectory, "package.json");
41475
- const dependencies = collectDependenciesToScore(readPackageJson(packageJsonPath), readPackageJsonText(packageJsonPath), options.includeDevDependencies);
41846
+ const dependencies = collectDependenciesToScore(readPackageJson(packageJsonPath), readPackageJsonText(packageJsonPath), options.includeDevDependencies, buildLockedVersionLookup(input.rootDirectory));
41476
41847
  if (dependencies.length === 0) return [];
41477
41848
  const cacheDirectory = isSupplyChainCacheDisabled() ? null : resolveReactDoctorCacheDir(input.rootDirectory);
41478
41849
  if (cacheDirectory !== null) pruneExpiredSocketCache(cacheDirectory);
@@ -41481,7 +41852,7 @@ const checkSupplyChain = (input) => gen(function* () {
41481
41852
  for (let index = 0; index < dependencies.length; index += 1) {
41482
41853
  const artifact = artifacts[index];
41483
41854
  if (!artifact) continue;
41484
- const worstAxis = worstGatedAxis(artifact.score);
41855
+ const worstAxis = worstGatedAxis(artifact.score, gatedAxesForSection(dependencies[index].section));
41485
41856
  if (toHundred(artifact.score[worstAxis.key]) >= options.minScore) continue;
41486
41857
  diagnostics.push(buildLowScoreDiagnostic(dependencies[index], artifact, worstAxis, options));
41487
41858
  }
@@ -42524,4 +42895,4 @@ const toJsonReport = (result, options) => buildJsonReport({
42524
42895
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
42525
42896
 
42526
42897
  //# sourceMappingURL=index.js.map
42527
- //# debugId=f00947fe-3794-5d73-a491-232b535dc962
42898
+ //# debugId=10e3e1b0-f291-5306-b5fd-79b158b00159