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/lsp.js CHANGED
@@ -8,7 +8,7 @@ import path from "node:path";
8
8
  import * as NodeChildProcess from "node:child_process";
9
9
  import { execFileSync, spawn, spawnSync } from "node:child_process";
10
10
  import * as ts from "typescript";
11
- 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";
11
+ 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
12
  import { parseJSON5 } from "confbox";
13
13
  import * as NodeUrl from "node:url";
14
14
  import { fileURLToPath } from "node:url";
@@ -32836,8 +32836,10 @@ const isFile = (filePath) => {
32836
32836
  };
32837
32837
  const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
32838
32838
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
32839
+ const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
32839
32840
  const MINIFIED_SNIFF_BYTES = 65536;
32840
32841
  const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
32842
+ const SCANNED_DOT_DIRECTORIES = new Set([".dumi", ".storybook"]);
32841
32843
  const IGNORED_DIRECTORIES = new Set([
32842
32844
  ".angular",
32843
32845
  ".astro",
@@ -33002,7 +33004,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
33002
33004
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
33003
33005
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
33004
33006
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
33005
- const CORE_PACKAGE_VERSION = "0.7.1";
33007
+ const CORE_PACKAGE_VERSION = "0.7.2";
33006
33008
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
33007
33009
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
33008
33010
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -33012,8 +33014,9 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
33012
33014
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
33013
33015
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
33014
33016
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
33015
- const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => IGNORED_DIRECTORIES.has(segment));
33016
- const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath);
33017
+ const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
33018
+ const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
33019
+ const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
33017
33020
  const isMinifiedSource = (absolutePath) => {
33018
33021
  let fileDescriptor;
33019
33022
  try {
@@ -33077,7 +33080,7 @@ function* walkSourceTreeFiles(rootDirectory) {
33077
33080
  for (const entry of readDirectoryEntries(currentDirectory)) {
33078
33081
  const absolutePath = Path.join(currentDirectory, entry.name);
33079
33082
  if (entry.isDirectory()) {
33080
- if (!IGNORED_DIRECTORIES.has(entry.name)) stack.push(absolutePath);
33083
+ if (!isIgnoredDirectoryName(entry.name)) stack.push(absolutePath);
33081
33084
  continue;
33082
33085
  }
33083
33086
  if (entry.isFile()) yield {
@@ -34043,6 +34046,10 @@ const normalizeCompilerOptions = (compilerOptions) => {
34043
34046
  hasExplicitLib
34044
34047
  };
34045
34048
  };
34049
+ const normalizeReferencePaths = (references) => {
34050
+ if (!Array.isArray(references)) return [];
34051
+ return references.map((reference) => isPlainObject(reference) && typeof reference.path === "string" ? reference.path : null).filter((referencePath) => referencePath !== null);
34052
+ };
34046
34053
  const readTsConfig = (filePath) => {
34047
34054
  let content;
34048
34055
  try {
@@ -34054,6 +34061,7 @@ const readTsConfig = (filePath) => {
34054
34061
  if (!isPlainObject(parsed.config)) return null;
34055
34062
  return {
34056
34063
  extends: typeof parsed.config.extends === "string" ? parsed.config.extends : void 0,
34064
+ referencePaths: normalizeReferencePaths(parsed.config.references),
34057
34065
  compilerOptions: normalizeCompilerOptions(parsed.config.compilerOptions)
34058
34066
  };
34059
34067
  };
@@ -34094,20 +34102,37 @@ const libEntryIncludesES2023Array = (entry) => {
34094
34102
  };
34095
34103
  const libIncludesES2023 = (lib) => lib.some(libEntryIncludesES2023Array);
34096
34104
  const compilerOptionsArePreES2023 = (compilerOptions) => {
34105
+ if (compilerOptions.target && targetYearIsPreES2023(compilerOptions.target)) return true;
34097
34106
  if (compilerOptions.hasExplicitLib) return !libIncludesES2023(compilerOptions.lib ?? []);
34098
- if (compilerOptions.target) return targetYearIsPreES2023(compilerOptions.target);
34099
34107
  return false;
34100
34108
  };
34101
34109
  const compilerOptionsDeclareTargetOrLib = (compilerOptions) => compilerOptions.hasExplicitLib || compilerOptions.target !== void 0;
34102
- const detectPreES2023FromConfig = (tsConfigPath) => {
34110
+ const detectPreES2023FromConfig = (tsConfigPath, visitedConfigPaths = /* @__PURE__ */ new Set()) => {
34111
+ if (visitedConfigPaths.has(tsConfigPath)) return false;
34103
34112
  const compilerOptions = readResolvedCompilerOptions(tsConfigPath, 0, /* @__PURE__ */ new Set());
34104
34113
  if (!compilerOptions) return false;
34105
- if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) return false;
34114
+ if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) {
34115
+ const tsConfig = readTsConfig(tsConfigPath);
34116
+ if (!tsConfig) return false;
34117
+ const nextVisitedConfigPaths = new Set(visitedConfigPaths);
34118
+ nextVisitedConfigPaths.add(tsConfigPath);
34119
+ const configDirectory = Path.dirname(tsConfigPath);
34120
+ return tsConfig.referencePaths.some((referencePath) => {
34121
+ const resolvedReferencePath = Path.resolve(configDirectory, referencePath);
34122
+ const referencedConfigPath = isFile(resolvedReferencePath) ? resolvedReferencePath : Path.join(resolvedReferencePath, TSCONFIG_FILENAME);
34123
+ return isFile(referencedConfigPath) && detectPreES2023FromConfig(referencedConfigPath, nextVisitedConfigPaths);
34124
+ });
34125
+ }
34106
34126
  return compilerOptionsArePreES2023(compilerOptions);
34107
34127
  };
34128
+ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"];
34108
34129
  const detectPreES2023Target = (directory) => {
34109
34130
  const tsConfigPath = Path.join(directory, TSCONFIG_FILENAME);
34110
34131
  if (isFile(tsConfigPath)) return detectPreES2023FromConfig(tsConfigPath);
34132
+ for (const fallbackFilename of FALLBACK_TSCONFIG_FILENAMES) {
34133
+ const fallbackPath = Path.join(directory, fallbackFilename);
34134
+ if (isFile(fallbackPath)) return detectPreES2023FromConfig(fallbackPath);
34135
+ }
34111
34136
  return false;
34112
34137
  };
34113
34138
  const REACT_DEPENDENCY_NAMES = new Set([
@@ -34269,6 +34294,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
34269
34294
  shopifyFlashListVersion: null,
34270
34295
  shopifyFlashListMajorVersion: null,
34271
34296
  hasReanimated: false,
34297
+ reanimatedVersion: null,
34272
34298
  isPreES2023Target: hasOwnTsConfig && detectPreES2023Target(directory),
34273
34299
  sourceFileCount
34274
34300
  };
@@ -34361,6 +34387,7 @@ const discoverProject = (directory) => {
34361
34387
  version: findShopifyFlashListVersion(directory, packageJson)
34362
34388
  }) : null;
34363
34389
  const hasReanimated = hasReactNativeWorkspace && someWorkspacePackageJson(directory, packageJson, isPackageJsonReanimatedAware);
34390
+ const reanimatedVersion = hasReanimated ? findInWorkspacePackageJsons(directory, packageJson, (workspacePackageJson) => getDependencySpec(workspacePackageJson, REANIMATED_DEPENDENCY_NAME)) : null;
34364
34391
  const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
34365
34392
  rootDirectory: directory,
34366
34393
  rootPackageJson: packageJson,
@@ -34390,6 +34417,7 @@ const discoverProject = (directory) => {
34390
34417
  shopifyFlashListVersion,
34391
34418
  shopifyFlashListMajorVersion: shopifyFlashListVersion === null ? null : getLowestDependencyMajor(shopifyFlashListVersion),
34392
34419
  hasReanimated,
34420
+ reanimatedVersion,
34393
34421
  isPreES2023Target,
34394
34422
  sourceFileCount
34395
34423
  };
@@ -34582,6 +34610,9 @@ const buildRuleSeverityControls = (config) => {
34582
34610
  ...config.buckets !== void 0 ? { buckets: config.buckets } : {}
34583
34611
  };
34584
34612
  };
34613
+ const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
34614
+ const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
34615
+ const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
34585
34616
  const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
34586
34617
  "effect/no-adjust-state-on-prop-change": "react-doctor/no-adjust-state-on-prop-change",
34587
34618
  "effect/no-chain-state-updates": "react-doctor/no-chain-state-updates",
@@ -34659,6 +34690,7 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
34659
34690
  "react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
34660
34691
  "react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
34661
34692
  "react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
34693
+ "react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
34662
34694
  "react/jsx-no-undef": "react-doctor/jsx-no-undef",
34663
34695
  "react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
34664
34696
  "react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
@@ -34732,9 +34764,6 @@ const tokenizeRuleList = (ruleList) => {
34732
34764
  if (!ruleSection) return [];
34733
34765
  return ruleSection.split(/[,\s]+/).map((token) => token.trim()).filter(Boolean);
34734
34766
  };
34735
- const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
34736
- const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
34737
- const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
34738
34767
  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}\`).`;
34739
34768
  const tokenMisnamesRule = (token, ruleId) => token !== ruleId && isSameRuleKey(token, ruleId);
34740
34769
  const detectInlineNearMiss = (lines, diagnosticLineIndex, ruleId) => {
@@ -34788,6 +34817,53 @@ const detectForeignDisableNearMiss = (lines, diagnosticLineIndex, ruleId) => {
34788
34817
  if (!ruleId.startsWith("react-doctor/")) return null;
34789
34818
  return detectInlineNearMiss(lines, diagnosticLineIndex, ruleId) ?? detectBlockNearMiss(lines, diagnosticLineIndex, ruleId);
34790
34819
  };
34820
+ const ESLINT_REACT_HOOKS_PLUGIN_PREFIX = "react-hooks/";
34821
+ const buildAcceptedTokens = (ruleId) => {
34822
+ const shortRuleId = ruleId.slice(15);
34823
+ return new Set([ruleId, `${ESLINT_REACT_HOOKS_PLUGIN_PREFIX}${shortRuleId}`]);
34824
+ };
34825
+ const listNamesRule = (ruleList, acceptedTokens) => tokenizeRuleList(ruleList).some((token) => acceptedTokens.has(token));
34826
+ const isInlineDisabled = (lines, diagnosticLineIndex, acceptedTokens) => {
34827
+ const candidates = [{
34828
+ line: lines[diagnosticLineIndex],
34829
+ requiredScope: "line"
34830
+ }, {
34831
+ line: lines[diagnosticLineIndex - 1],
34832
+ requiredScope: "next-line"
34833
+ }];
34834
+ for (const { line, requiredScope } of candidates) {
34835
+ const match = line?.match(FOREIGN_INLINE_DISABLE_PATTERN);
34836
+ if (!match) continue;
34837
+ const [, , scope, ruleList] = match;
34838
+ if (scope !== requiredScope) continue;
34839
+ if (listNamesRule(ruleList, acceptedTokens)) return true;
34840
+ }
34841
+ return false;
34842
+ };
34843
+ const isBlockDisabled = (lines, diagnosticLineIndex, acceptedTokens) => {
34844
+ let isRangeOpen = false;
34845
+ const lastLineIndex = Math.min(diagnosticLineIndex, lines.length - 1);
34846
+ for (let lineIndex = 0; lineIndex <= lastLineIndex; lineIndex++) {
34847
+ const line = lines[lineIndex];
34848
+ if (line === void 0 || !line.includes("-disable") && !line.includes("-enable")) continue;
34849
+ const disableMatch = line.match(FOREIGN_BLOCK_DISABLE_PATTERN);
34850
+ if (disableMatch && listNamesRule(disableMatch[2], acceptedTokens)) {
34851
+ isRangeOpen = true;
34852
+ continue;
34853
+ }
34854
+ const enableMatch = line.match(FOREIGN_BLOCK_ENABLE_PATTERN);
34855
+ if (enableMatch) {
34856
+ const enabledRules = tokenizeRuleList(enableMatch[1]);
34857
+ if (enabledRules.length === 0 || enabledRules.some((rule) => acceptedTokens.has(rule))) isRangeOpen = false;
34858
+ }
34859
+ }
34860
+ return isRangeOpen;
34861
+ };
34862
+ const isCompilerRuleForeignDisabled = (lines, diagnosticLineIndex, ruleId) => {
34863
+ if (!ruleId.startsWith("react-hooks-js/")) return false;
34864
+ const acceptedTokens = buildAcceptedTokens(ruleId);
34865
+ return isInlineDisabled(lines, diagnosticLineIndex, acceptedTokens) || isBlockDisabled(lines, diagnosticLineIndex, acceptedTokens);
34866
+ };
34791
34867
  const JSX_OPENER_TAG_PATTERN = /<[A-Za-z][\w.]*/g;
34792
34868
  const JSX_TAG_NAME_FOLLOW = /[A-Za-z]/;
34793
34869
  const isOpenerMatchInsideLineComment = (line, openerCharIndex) => {
@@ -34931,6 +35007,11 @@ const evaluateSuppression = (lines, diagnosticLineIndex, ruleId) => {
34931
35007
  isSuppressed: true,
34932
35008
  nearMissHint: null
34933
35009
  };
35010
+ if (isCompilerRuleForeignDisabled(lines, diagnosticLineIndex, ruleId)) return {
35011
+ isSuppressed: true,
35012
+ nearMissHint: null,
35013
+ isForeignDirective: true
35014
+ };
34934
35015
  const directComments = findStackedDisableCommentsAbove(lines, diagnosticLineIndex);
34935
35016
  if (hasChainSuppressor(directComments, ruleId)) return {
34936
35017
  isSuppressed: true,
@@ -35212,12 +35293,18 @@ const collectStringSet = (values) => {
35212
35293
  return new Set(values.filter((value) => typeof value === "string"));
35213
35294
  };
35214
35295
  const JSX_NO_UNDEF_IDENTIFIER_PATTERN = /^`([^`]+)`/;
35296
+ const NODE_CLI_PATH_SEGMENTS = new Set([
35297
+ "scripts",
35298
+ "bin",
35299
+ "tools"
35300
+ ]);
35301
+ const hasNodeCliPathSegment = (filePath) => filePath.split(/[\\/]/).slice(0, -1).some((segment) => NODE_CLI_PATH_SEGMENTS.has(segment));
35215
35302
  /**
35216
35303
  * Pre-compiles every stateful filter and returns a single
35217
35304
  * `apply(diagnostic)` closure that runs (in order):
35218
35305
  *
35219
35306
  * 1. auto-suppress (test-noise rules in test files; `migration-hint`
35220
- * wins over `test-noise`)
35307
+ * wins over `test-noise`; `no-console` on Node CLI scripts)
35221
35308
  * 2. severity overrides (top-level `rules` / `categories`, with
35222
35309
  * `"off"` dropping)
35223
35310
  * 3. warning suppression (only when `showWarnings` is false: drops every
@@ -35315,6 +35402,12 @@ const buildDiagnosticPipeline = (input) => {
35315
35402
  if (hasRawTextWrappers && isInsideStringOnlyWrapper(lines, diagnostic.line, diagnostic.column, rawTextWrapperComponentNames)) return true;
35316
35403
  return false;
35317
35404
  };
35405
+ const isNoConsoleOnNodeCliScript = (diagnostic) => {
35406
+ if (diagnostic.rule !== "no-console") return false;
35407
+ if (hasNodeCliPathSegment(diagnostic.filePath)) return true;
35408
+ const lines = getFileLines(diagnostic.filePath);
35409
+ return lines !== null && Boolean(lines[0]?.startsWith("#!"));
35410
+ };
35318
35411
  const isJsxNoUndefSuppressedByConfig = (diagnostic) => {
35319
35412
  if (!hasRuntimeGlobals) return false;
35320
35413
  if (diagnostic.rule !== "jsx-no-undef") return false;
@@ -35324,6 +35417,7 @@ const buildDiagnosticPipeline = (input) => {
35324
35417
  return {
35325
35418
  apply: (diagnostic) => {
35326
35419
  if (shouldAutoSuppress(diagnostic)) return null;
35420
+ if (isNoConsoleOnNodeCliScript(diagnostic)) return null;
35327
35421
  let current = diagnostic;
35328
35422
  let explicitSeverityOverride;
35329
35423
  let explicitRuleOverride;
@@ -35353,7 +35447,7 @@ const buildDiagnosticPipeline = (input) => {
35353
35447
  if (lines) {
35354
35448
  const ruleIdentifier = `${current.plugin}/${current.rule}`;
35355
35449
  const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
35356
- if (evaluation.isSuppressed) return suppress(current, "inline");
35450
+ if (evaluation.isSuppressed) return suppress(current, evaluation.isForeignDirective ? "foreign-inline" : "inline");
35357
35451
  if (evaluation.nearMissHint) current = {
35358
35452
  ...current,
35359
35453
  suppressionHint: evaluation.nearMissHint
@@ -39415,9 +39509,17 @@ const buildNoSecretsRecommendation = (project, fallbackRecommendation) => {
39415
39509
  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`;
39416
39510
  };
39417
39511
  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";
39512
+ const ACCESSORS_MIN_VERSION = "3.15.0";
39513
+ const supportsAccessors = (reanimatedVersion) => {
39514
+ if (reanimatedVersion === null) return true;
39515
+ const lowerBound = import_semver.validRange(reanimatedVersion) !== null ? import_semver.minVersion(reanimatedVersion) : import_semver.coerce(reanimatedVersion);
39516
+ if (lowerBound === null) return true;
39517
+ return import_semver.gte(lowerBound, ACCESSORS_MIN_VERSION);
39518
+ };
39418
39519
  const appendReanimatedSharedValueHint = (help, rule, project) => {
39419
39520
  if (rule !== "immutability") return help;
39420
39521
  if (!project.hasReanimated) return help;
39522
+ if (!supportsAccessors(project.reanimatedVersion)) return help;
39421
39523
  if (!help) return REANIMATED_SHARED_VALUE_HINT;
39422
39524
  return `${help}\n\n${REANIMATED_SHARED_VALUE_HINT}`;
39423
39525
  };
@@ -39579,13 +39681,13 @@ const REACT_USE_BINDING_RESOLUTION = {
39579
39681
  isReactUseBinding: true,
39580
39682
  isReactNamespaceBinding: false
39581
39683
  };
39582
- const getScriptKind = (filename) => {
39684
+ const getScriptKind$2 = (filename) => {
39583
39685
  if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
39584
39686
  if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
39585
39687
  if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
39586
39688
  return ts.ScriptKind.JS;
39587
39689
  };
39588
- const getUtf16Offset = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
39690
+ const getUtf16Offset$1 = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
39589
39691
  const unwrapExpression = (expression) => {
39590
39692
  let currentExpression = expression;
39591
39693
  while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
@@ -39834,8 +39936,8 @@ const findUseCallIdentifier = (sourceFile, useOffset) => {
39834
39936
  return matchedIdentifier;
39835
39937
  };
39836
39938
  const resolveUseCallBinding = (sourceText, filename, utf8Offset) => {
39837
- const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(filename));
39838
- const useIdentifier = findUseCallIdentifier(sourceFile, getUtf16Offset(sourceText, utf8Offset));
39939
+ const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getScriptKind$2(filename));
39940
+ const useIdentifier = findUseCallIdentifier(sourceFile, getUtf16Offset$1(sourceText, utf8Offset));
39839
39941
  if (!useIdentifier) return null;
39840
39942
  return resolveIdentifierBinding(useIdentifier, collectReactImportBindings(sourceFile), sourceFile);
39841
39943
  };
@@ -39856,6 +39958,201 @@ const shouldSuppressLocalUseHookDiagnostic = (diagnostic, rootDirectory) => {
39856
39958
  const bindingResolution = resolveUseCallBinding(sourceText, absolutePath, primaryLabel.span.offset);
39857
39959
  return bindingResolution !== null && !bindingResolution.isReactUseBinding;
39858
39960
  };
39961
+ const SUPPRESSED_COMPILER_CODES = new Set(["react-hooks-js(immutability)", "react-hooks-js(refs)"]);
39962
+ const WORKLET_DIRECTIVE = "worklet";
39963
+ const WORKLET_ACCEPTING_CALLEES = new Set([
39964
+ "useAnimatedStyle",
39965
+ "useAnimatedProps",
39966
+ "useDerivedValue",
39967
+ "useAnimatedReaction",
39968
+ "useAnimatedScrollHandler",
39969
+ "useAnimatedGestureHandler",
39970
+ "useFrameCallback",
39971
+ "runOnUI",
39972
+ "executeOnUIRuntimeSync"
39973
+ ]);
39974
+ const GESTURE_ROOT_IDENTIFIER = "Gesture";
39975
+ const getScriptKind$1 = (filename) => {
39976
+ if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
39977
+ if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
39978
+ if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
39979
+ return ts.ScriptKind.JS;
39980
+ };
39981
+ const getUtf16Offset = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
39982
+ const hasWorkletDirective = (node) => {
39983
+ if (!ts.isFunctionDeclaration(node) && !ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isMethodDeclaration(node)) return false;
39984
+ const body = node.body;
39985
+ if (!body || !ts.isBlock(body)) return false;
39986
+ for (const statement of body.statements) {
39987
+ if (!ts.isExpressionStatement(statement)) return false;
39988
+ if (!ts.isStringLiteral(statement.expression)) return false;
39989
+ if (statement.expression.text === WORKLET_DIRECTIVE) return true;
39990
+ }
39991
+ return false;
39992
+ };
39993
+ const rootIdentifierOfCallChain = (expression) => {
39994
+ let currentExpression = expression;
39995
+ while (true) {
39996
+ if (ts.isIdentifier(currentExpression)) return currentExpression.text;
39997
+ if (ts.isPropertyAccessExpression(currentExpression)) {
39998
+ currentExpression = currentExpression.expression;
39999
+ continue;
40000
+ }
40001
+ if (ts.isCallExpression(currentExpression)) {
40002
+ currentExpression = currentExpression.expression;
40003
+ continue;
40004
+ }
40005
+ return null;
40006
+ }
40007
+ };
40008
+ const isWorkletAcceptingCall = (callExpression) => {
40009
+ const callee = callExpression.expression;
40010
+ if (ts.isIdentifier(callee)) return WORKLET_ACCEPTING_CALLEES.has(callee.text);
40011
+ if (ts.isPropertyAccessExpression(callee)) {
40012
+ if (WORKLET_ACCEPTING_CALLEES.has(callee.name.text)) return true;
40013
+ return rootIdentifierOfCallChain(callee) === GESTURE_ROOT_IDENTIFIER;
40014
+ }
40015
+ return false;
40016
+ };
40017
+ const isFunctionWorklet = (functionNode) => {
40018
+ if (hasWorkletDirective(functionNode)) return true;
40019
+ const parent = functionNode.parent;
40020
+ return ts.isCallExpression(parent) && parent.arguments.some((argument) => argument === functionNode) && isWorkletAcceptingCall(parent);
40021
+ };
40022
+ const findNodeAtOffset = (sourceFile, targetOffset) => {
40023
+ let matchedNode = null;
40024
+ const visit = (node) => {
40025
+ if (node.getStart(sourceFile) > targetOffset || node.getEnd() <= targetOffset) return;
40026
+ matchedNode = node;
40027
+ ts.forEachChild(node, visit);
40028
+ };
40029
+ visit(sourceFile);
40030
+ return matchedNode;
40031
+ };
40032
+ const isOffsetInsideWorklet = (sourceFile, targetOffset) => {
40033
+ let currentNode = findNodeAtOffset(sourceFile, targetOffset);
40034
+ while (currentNode) {
40035
+ if (ts.isFunctionLike(currentNode) && isFunctionWorklet(currentNode)) return true;
40036
+ currentNode = currentNode.parent;
40037
+ }
40038
+ return false;
40039
+ };
40040
+ const shouldSuppressCompilerFindingInWorklet = (diagnostic, project, rootDirectory) => {
40041
+ if (!SUPPRESSED_COMPILER_CODES.has(diagnostic.code)) return false;
40042
+ if (!project.hasReanimated) return false;
40043
+ const primaryLabel = diagnostic.labels[0];
40044
+ if (!primaryLabel) return false;
40045
+ const absolutePath = Path.isAbsolute(diagnostic.filename) ? diagnostic.filename : Path.join(rootDirectory, diagnostic.filename);
40046
+ let sourceText;
40047
+ try {
40048
+ sourceText = NFS.readFileSync(absolutePath, "utf-8");
40049
+ } catch {
40050
+ return false;
40051
+ }
40052
+ return isOffsetInsideWorklet(ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getScriptKind$1(absolutePath)), getUtf16Offset(sourceText, primaryLabel.span.offset));
40053
+ };
40054
+ const MANUAL_MEMOIZATION_PLUGIN = "react-doctor";
40055
+ const MANUAL_MEMOIZATION_RULE = "react-compiler-no-manual-memoization";
40056
+ const REACT_COMPILER_PLUGIN = "react-hooks-js";
40057
+ const getScriptKind = (filename) => {
40058
+ if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
40059
+ if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
40060
+ if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
40061
+ return ts.ScriptKind.JS;
40062
+ };
40063
+ const isManualMemoizationDiagnostic = (diagnostic) => diagnostic.plugin === MANUAL_MEMOIZATION_PLUGIN && diagnostic.rule === MANUAL_MEMOIZATION_RULE;
40064
+ const nodeLineRange = (sourceFile, node) => ({
40065
+ startLine: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1,
40066
+ endLine: sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line + 1
40067
+ });
40068
+ const findOutermostEnclosingFunctionRange = (sourceFile, targetLine) => {
40069
+ let foundRange = null;
40070
+ const visit = (node) => {
40071
+ if (foundRange) return;
40072
+ if (ts.isFunctionLike(node)) {
40073
+ const range = nodeLineRange(sourceFile, node);
40074
+ if (range.startLine <= targetLine && targetLine <= range.endLine) foundRange = range;
40075
+ return;
40076
+ }
40077
+ ts.forEachChild(node, visit);
40078
+ };
40079
+ visit(sourceFile);
40080
+ return foundRange;
40081
+ };
40082
+ const NEWLINE_BYTE = 10;
40083
+ const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
40084
+ let lineNumber = 1;
40085
+ const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
40086
+ for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === NEWLINE_BYTE) lineNumber++;
40087
+ return lineNumber;
40088
+ };
40089
+ /**
40090
+ * Drops `react-doctor/react-compiler-no-manual-memoization` diagnostics
40091
+ * whose enclosing function also carries a `react-hooks-js` (React
40092
+ * Compiler) diagnostic. Every react-hooks-js finding marks a function the
40093
+ * compiler could NOT compile (a bail-out / skip / preserve-manual-
40094
+ * memoization failure), so "React Compiler already caches every value
40095
+ * here" is false for that function and the manual memoization is
40096
+ * load-bearing, not dead weight.
40097
+ *
40098
+ * Matching is per enclosing function, not per file: a bailed-out
40099
+ * component must not silence redundant-memo findings in a sibling
40100
+ * component the compiler did optimize.
40101
+ *
40102
+ * Module-scope `memo(() => …)` wrappers have no enclosing function; for
40103
+ * those the memo call's own span is the containment range, so a bail-out
40104
+ * inside the inline-wrapped component still suppresses. Every failure
40105
+ * path (unreadable file, missing span) fails open and keeps the
40106
+ * diagnostic.
40107
+ */
40108
+ const suppressMemoizationInBailedOutFunctions = (diagnostics, rootDirectory) => {
40109
+ const compilerDiagnosticLinesByFile = /* @__PURE__ */ new Map();
40110
+ let hasManualMemoizationDiagnostic = false;
40111
+ for (const diagnostic of diagnostics) {
40112
+ if (isManualMemoizationDiagnostic(diagnostic)) {
40113
+ hasManualMemoizationDiagnostic = true;
40114
+ continue;
40115
+ }
40116
+ if (diagnostic.plugin !== REACT_COMPILER_PLUGIN || diagnostic.line <= 0) continue;
40117
+ const lines = compilerDiagnosticLinesByFile.get(diagnostic.filePath);
40118
+ if (lines) lines.push(diagnostic.line);
40119
+ else compilerDiagnosticLinesByFile.set(diagnostic.filePath, [diagnostic.line]);
40120
+ }
40121
+ if (!hasManualMemoizationDiagnostic || compilerDiagnosticLinesByFile.size === 0) return diagnostics;
40122
+ const parsedFileCache = /* @__PURE__ */ new Map();
40123
+ const readAndParse = (filePath) => {
40124
+ const cached = parsedFileCache.get(filePath);
40125
+ if (cached !== void 0) return cached;
40126
+ const absolutePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory || ".", filePath);
40127
+ let parsed;
40128
+ try {
40129
+ const buffer = NFS.readFileSync(absolutePath);
40130
+ parsed = {
40131
+ sourceFile: ts.createSourceFile(absolutePath, buffer.toString("utf8"), ts.ScriptTarget.Latest, true, getScriptKind(absolutePath)),
40132
+ buffer
40133
+ };
40134
+ } catch {
40135
+ parsed = null;
40136
+ }
40137
+ parsedFileCache.set(filePath, parsed);
40138
+ return parsed;
40139
+ };
40140
+ const isInsideBailedOutFunction = (diagnostic) => {
40141
+ const compilerLines = compilerDiagnosticLinesByFile.get(diagnostic.filePath);
40142
+ if (!compilerLines || diagnostic.line <= 0) return false;
40143
+ const parsed = readAndParse(diagnostic.filePath);
40144
+ if (!parsed) return false;
40145
+ let containmentRange = findOutermostEnclosingFunctionRange(parsed.sourceFile, diagnostic.line);
40146
+ if (!containmentRange && diagnostic.offset !== void 0 && diagnostic.length !== void 0) containmentRange = {
40147
+ startLine: diagnostic.line,
40148
+ endLine: lineOfUtf8Offset(parsed.buffer, diagnostic.offset + diagnostic.length)
40149
+ };
40150
+ if (!containmentRange) return false;
40151
+ const { startLine, endLine } = containmentRange;
40152
+ return compilerLines.some((compilerLine) => startLine <= compilerLine && compilerLine <= endLine);
40153
+ };
40154
+ return diagnostics.filter((diagnostic) => !isManualMemoizationDiagnostic(diagnostic) || !isInsideBailedOutFunction(diagnostic));
40155
+ };
39859
40156
  const FILEPATH_WITH_LOCATION_PATTERN = /\S+\.\w+:\d+:\d+[\s\S]*$/;
39860
40157
  const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
39861
40158
  const TRAILING_PERIOD_PATTERN = /\.$/;
@@ -39995,7 +40292,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
39995
40292
  minifiedFileCache.set(absolutePath, minified);
39996
40293
  return minified;
39997
40294
  };
39998
- return parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory)).map((diagnostic) => {
40295
+ return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
39999
40296
  const { plugin, rule } = parseRuleCode(diagnostic.code);
40000
40297
  const primaryLabel = diagnostic.labels[0];
40001
40298
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
@@ -40022,7 +40319,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
40022
40319
  ...resolveMatchByOccurrence(rule, category) ? { matchByOccurrence: true } : {},
40023
40320
  ...relatedLocations.length > 0 ? { relatedLocations } : {}
40024
40321
  };
40025
- });
40322
+ }), rootDirectory);
40026
40323
  };
40027
40324
  const buildOxlintChildEnv = (sourceEnv) => {
40028
40325
  const childEnv = {};
@@ -40533,6 +40830,7 @@ const runOxlint = async (options) => {
40533
40830
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
40534
40831
  const severityControls = buildRuleSeverityControls(userConfig);
40535
40832
  validateRuleRegistration();
40833
+ resetManifestCaches();
40536
40834
  if (includePaths !== void 0 && includePaths.length === 0) return [];
40537
40835
  const pluginPath = resolvePluginPath();
40538
40836
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
@@ -41195,9 +41493,10 @@ const CONTEXT_AXES = [
41195
41493
  }
41196
41494
  ];
41197
41495
  const SCORE_AXES = [...GATED_AXES, ...CONTEXT_AXES];
41198
- const worstGatedAxis = (score) => {
41199
- let worst = GATED_AXES[0];
41200
- for (const axis of GATED_AXES) if (score[axis.key] < score[worst.key]) worst = axis;
41496
+ const gatedAxesForSection = (section) => section === "devDependencies" ? GATED_AXES.filter((axis) => axis.key !== "vulnerability") : GATED_AXES;
41497
+ const worstGatedAxis = (score, gatedAxes) => {
41498
+ let worst = gatedAxes[0];
41499
+ for (const axis of gatedAxes) if (score[axis.key] < score[worst.key]) worst = axis;
41201
41500
  return worst;
41202
41501
  };
41203
41502
  const clampScore = (value) => {
@@ -41221,6 +41520,69 @@ const resolveConcreteVersion = (spec) => {
41221
41520
  if (range === null || range === "*") return null;
41222
41521
  return import_semver.minVersion(trimmed)?.version ?? null;
41223
41522
  };
41523
+ const readTextFileOrNull = (filePath) => {
41524
+ try {
41525
+ return NFS.readFileSync(filePath, "utf-8");
41526
+ } catch {
41527
+ return null;
41528
+ }
41529
+ };
41530
+ const buildNpmLockLookup = (lockText) => {
41531
+ let parsed;
41532
+ try {
41533
+ parsed = JSON.parse(lockText);
41534
+ } catch {
41535
+ return null;
41536
+ }
41537
+ if (typeof parsed !== "object" || parsed === null) return null;
41538
+ const lock = parsed;
41539
+ return (name) => {
41540
+ const entry = lock.packages?.[`node_modules/${name}`] ?? lock.dependencies?.[name];
41541
+ return typeof entry?.version === "string" ? entry.version : null;
41542
+ };
41543
+ };
41544
+ const buildYarnLockLookup = (lockText) => {
41545
+ const lines = lockText.split(/\r?\n/);
41546
+ return (name, spec) => {
41547
+ const descriptor = `${name}@${spec}`;
41548
+ const berryDescriptor = `${name}@npm:${spec}`;
41549
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
41550
+ const line = lines[lineIndex];
41551
+ if (line.startsWith(" ") || line.startsWith("#") || !line.includes(":")) continue;
41552
+ const descriptors = line.replace(/:\s*$/, "").split(",").map((part) => part.trim().replace(/^"|"$/g, ""));
41553
+ if (!descriptors.includes(descriptor) && !descriptors.includes(berryDescriptor)) continue;
41554
+ for (let bodyIndex = lineIndex + 1; bodyIndex < lines.length && (lines[bodyIndex].startsWith(" ") || lines[bodyIndex] === ""); bodyIndex += 1) {
41555
+ const versionMatch = /^\s+version:?\s+"?([^"\s]+)"?/.exec(lines[bodyIndex]);
41556
+ if (versionMatch) return versionMatch[1];
41557
+ }
41558
+ return null;
41559
+ }
41560
+ return null;
41561
+ };
41562
+ };
41563
+ const buildPnpmLockLookup = (lockText) => {
41564
+ return (name) => {
41565
+ const entryPattern = new RegExp(`^ {4,8}['"]?${name.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&")}['"]?:\\s*$`);
41566
+ const lines = lockText.split(/\r?\n/);
41567
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
41568
+ if (!entryPattern.test(lines[lineIndex])) continue;
41569
+ for (let bodyIndex = lineIndex + 1; bodyIndex < lines.length && /^ {5,}\S/.test(lines[bodyIndex]); bodyIndex += 1) {
41570
+ const versionMatch = /^\s+version:\s+['"]?([^'"\s(]+)/.exec(lines[bodyIndex]);
41571
+ if (versionMatch) return versionMatch[1];
41572
+ }
41573
+ }
41574
+ return null;
41575
+ };
41576
+ };
41577
+ const buildLockedVersionLookup = (rootDirectory) => {
41578
+ const npmLockText = readTextFileOrNull(Path.join(rootDirectory, "package-lock.json"));
41579
+ if (npmLockText !== null) return buildNpmLockLookup(npmLockText);
41580
+ const yarnLockText = readTextFileOrNull(Path.join(rootDirectory, "yarn.lock"));
41581
+ if (yarnLockText !== null) return buildYarnLockLookup(yarnLockText);
41582
+ const pnpmLockText = readTextFileOrNull(Path.join(rootDirectory, "pnpm-lock.yaml"));
41583
+ if (pnpmLockText !== null) return buildPnpmLockLookup(pnpmLockText);
41584
+ return null;
41585
+ };
41224
41586
  const locateDependencyKey = (packageJsonText, section, name) => {
41225
41587
  const needle = `"${name}"`;
41226
41588
  const sectionHeader = new RegExp(`"${section}"\\s*:\\s*\\{`);
@@ -41247,7 +41609,7 @@ const locateDependencyKey = (packageJsonText, section, name) => {
41247
41609
  }
41248
41610
  return null;
41249
41611
  };
41250
- const collectDependenciesToScore = (packageJson, packageJsonText, includeDevDependencies) => {
41612
+ const collectDependenciesToScore = (packageJson, packageJsonText, includeDevDependencies, lockedVersionLookup) => {
41251
41613
  const sectionByName = /* @__PURE__ */ new Map();
41252
41614
  for (const name of Object.keys(packageJson.dependencies ?? {})) sectionByName.set(name, "dependencies");
41253
41615
  if (includeDevDependencies) {
@@ -41257,13 +41619,18 @@ const collectDependenciesToScore = (packageJson, packageJsonText, includeDevDepe
41257
41619
  for (const [name, section] of sectionByName) {
41258
41620
  if (SUPPLY_CHAIN_IGNORED_PACKAGES.has(name)) continue;
41259
41621
  const spec = (packageJson[section] ?? {})[name] ?? "";
41260
- const version = resolveConcreteVersion(spec);
41261
- if (version === null) continue;
41622
+ const floorVersion = resolveConcreteVersion(spec);
41623
+ if (floorVersion === null) continue;
41624
+ const lockedVersion = lockedVersionLookup?.(name, spec) ?? null;
41625
+ const lockSatisfiesSpec = lockedVersion !== null && import_semver.valid(lockedVersion) !== null && import_semver.satisfies(lockedVersion, spec);
41626
+ const isExactPin = import_semver.valid(spec.trim()) !== null;
41262
41627
  const location = locateDependencyKey(packageJsonText, section, name);
41263
41628
  dependencies.push({
41264
41629
  name,
41265
- version,
41630
+ version: lockSatisfiesSpec ? lockedVersion : floorVersion,
41266
41631
  spec,
41632
+ section,
41633
+ resolution: isExactPin ? "pin" : lockSatisfiesSpec ? "locked" : "floor",
41267
41634
  line: location?.line ?? 0,
41268
41635
  column: location?.column ?? 0
41269
41636
  });
@@ -41414,7 +41781,11 @@ const formatAlertReason = (topAlerts, totalCount) => {
41414
41781
  }
41415
41782
  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)}.`;
41416
41783
  };
41417
- const formatDependencyIdentity = (dependency) => import_semver.valid(dependency.spec) !== null ? `${dependency.name}@${dependency.version}` : `${dependency.name}@${dependency.version} (lowest version "${dependency.spec}" allows)`;
41784
+ const formatDependencyIdentity = (dependency) => {
41785
+ if (dependency.resolution === "pin") return `${dependency.name}@${dependency.version}`;
41786
+ if (dependency.resolution === "locked") return `${dependency.name}@${dependency.version} (lockfile resolution of "${dependency.spec}")`;
41787
+ return `${dependency.name}@${dependency.version} (lowest version "${dependency.spec}" allows)`;
41788
+ };
41418
41789
  const buildSupplyChainHelp = (dependency, failingAxis, topAlerts, packagePageUrl, options) => {
41419
41790
  const hasCriticalAlert = topAlerts.some((alert) => alert.severity.toLowerCase() === "critical");
41420
41791
  const entry = `\`"${dependency.name}": "${dependency.spec}"\``;
@@ -41457,7 +41828,7 @@ const buildLowScoreDiagnostic = (dependency, artifact, failingAxis, options) =>
41457
41828
  const checkSupplyChain = (input) => gen(function* () {
41458
41829
  const options = resolveOptions(input.userConfig);
41459
41830
  const packageJsonPath = Path.join(input.rootDirectory, "package.json");
41460
- const dependencies = collectDependenciesToScore(readPackageJson(packageJsonPath), readPackageJsonText(packageJsonPath), options.includeDevDependencies);
41831
+ const dependencies = collectDependenciesToScore(readPackageJson(packageJsonPath), readPackageJsonText(packageJsonPath), options.includeDevDependencies, buildLockedVersionLookup(input.rootDirectory));
41461
41832
  if (dependencies.length === 0) return [];
41462
41833
  const cacheDirectory = isSupplyChainCacheDisabled() ? null : resolveReactDoctorCacheDir(input.rootDirectory);
41463
41834
  if (cacheDirectory !== null) pruneExpiredSocketCache(cacheDirectory);
@@ -41466,7 +41837,7 @@ const checkSupplyChain = (input) => gen(function* () {
41466
41837
  for (let index = 0; index < dependencies.length; index += 1) {
41467
41838
  const artifact = artifacts[index];
41468
41839
  if (!artifact) continue;
41469
- const worstAxis = worstGatedAxis(artifact.score);
41840
+ const worstAxis = worstGatedAxis(artifact.score, gatedAxesForSection(dependencies[index].section));
41470
41841
  if (toHundred(artifact.score[worstAxis.key]) >= options.minScore) continue;
41471
41842
  diagnostics.push(buildLowScoreDiagnostic(dependencies[index], artifact, worstAxis, options));
41472
41843
  }
@@ -42192,7 +42563,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
42192
42563
  /** Display name used in client-facing messages and progress titles. */
42193
42564
  const SERVER_DISPLAY_NAME = "React Doctor";
42194
42565
  /** Server version reported in `serverInfo`; injected at build, `dev` from source. */
42195
- const SERVER_VERSION = "0.7.1";
42566
+ const SERVER_VERSION = "0.7.2";
42196
42567
  /** `Diagnostic.source` shown next to every published diagnostic. */
42197
42568
  const DIAGNOSTIC_SOURCE = "react-doctor";
42198
42569
  /**
@@ -44243,5 +44614,5 @@ const startLanguageServer = () => {
44243
44614
  };
44244
44615
  //#endregion
44245
44616
  export { startLanguageServer };
44246
- !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]="8bc40ab2-982a-5d5d-a65c-9733ec980391")}catch(e){}}();
44247
- //# debugId=8bc40ab2-982a-5d5d-a65c-9733ec980391
44617
+ !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]="30e226f8-fb2c-5784-b48c-95e8d218d035")}catch(e){}}();
44618
+ //# debugId=30e226f8-fb2c-5784-b48c-95e8d218d035