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/cli.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]="47338856-c658-5c78-a5e2-e871c2dafaa7")}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]="a8ebd975-0f3b-5218-ad38-b9c8095f6668")}catch(e){}}();
3
3
  import { createRequire } from "node:module";
4
4
  import * as NodeChildProcess from "node:child_process";
5
5
  import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
@@ -9,7 +9,7 @@ import * as NFS from "node:fs";
9
9
  import fs, { mkdtempSync, rmSync } from "node:fs";
10
10
  import process$1 from "node: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, { tmpdir } from "node:os";
15
15
  import { parseJSON5 } from "confbox";
@@ -35968,8 +35968,10 @@ const isFile = (filePath) => {
35968
35968
  };
35969
35969
  const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
35970
35970
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
35971
+ const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
35971
35972
  const MINIFIED_SNIFF_BYTES = 65536;
35972
35973
  const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
35974
+ const SCANNED_DOT_DIRECTORIES = new Set([".dumi", ".storybook"]);
35973
35975
  const IGNORED_DIRECTORIES = new Set([
35974
35976
  ".angular",
35975
35977
  ".astro",
@@ -36144,7 +36146,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
36144
36146
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
36145
36147
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
36146
36148
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
36147
- const CORE_PACKAGE_VERSION = "0.7.1";
36149
+ const CORE_PACKAGE_VERSION = "0.7.2";
36148
36150
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
36149
36151
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
36150
36152
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -36154,8 +36156,9 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
36154
36156
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
36155
36157
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
36156
36158
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
36157
- const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => IGNORED_DIRECTORIES.has(segment));
36158
- const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath);
36159
+ const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
36160
+ const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
36161
+ const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
36159
36162
  const isMinifiedSource = (absolutePath) => {
36160
36163
  let fileDescriptor;
36161
36164
  try {
@@ -36216,7 +36219,7 @@ function* walkSourceTreeFiles(rootDirectory) {
36216
36219
  for (const entry of readDirectoryEntries(currentDirectory)) {
36217
36220
  const absolutePath = Path.join(currentDirectory, entry.name);
36218
36221
  if (entry.isDirectory()) {
36219
- if (!IGNORED_DIRECTORIES.has(entry.name)) stack.push(absolutePath);
36222
+ if (!isIgnoredDirectoryName(entry.name)) stack.push(absolutePath);
36220
36223
  continue;
36221
36224
  }
36222
36225
  if (entry.isFile()) yield {
@@ -37179,6 +37182,10 @@ const normalizeCompilerOptions = (compilerOptions) => {
37179
37182
  hasExplicitLib
37180
37183
  };
37181
37184
  };
37185
+ const normalizeReferencePaths = (references) => {
37186
+ if (!Array.isArray(references)) return [];
37187
+ return references.map((reference) => isPlainObject(reference) && typeof reference.path === "string" ? reference.path : null).filter((referencePath) => referencePath !== null);
37188
+ };
37182
37189
  const readTsConfig = (filePath) => {
37183
37190
  let content;
37184
37191
  try {
@@ -37190,6 +37197,7 @@ const readTsConfig = (filePath) => {
37190
37197
  if (!isPlainObject(parsed.config)) return null;
37191
37198
  return {
37192
37199
  extends: typeof parsed.config.extends === "string" ? parsed.config.extends : void 0,
37200
+ referencePaths: normalizeReferencePaths(parsed.config.references),
37193
37201
  compilerOptions: normalizeCompilerOptions(parsed.config.compilerOptions)
37194
37202
  };
37195
37203
  };
@@ -37230,20 +37238,37 @@ const libEntryIncludesES2023Array = (entry) => {
37230
37238
  };
37231
37239
  const libIncludesES2023 = (lib) => lib.some(libEntryIncludesES2023Array);
37232
37240
  const compilerOptionsArePreES2023 = (compilerOptions) => {
37241
+ if (compilerOptions.target && targetYearIsPreES2023(compilerOptions.target)) return true;
37233
37242
  if (compilerOptions.hasExplicitLib) return !libIncludesES2023(compilerOptions.lib ?? []);
37234
- if (compilerOptions.target) return targetYearIsPreES2023(compilerOptions.target);
37235
37243
  return false;
37236
37244
  };
37237
37245
  const compilerOptionsDeclareTargetOrLib = (compilerOptions) => compilerOptions.hasExplicitLib || compilerOptions.target !== void 0;
37238
- const detectPreES2023FromConfig = (tsConfigPath) => {
37246
+ const detectPreES2023FromConfig = (tsConfigPath, visitedConfigPaths = /* @__PURE__ */ new Set()) => {
37247
+ if (visitedConfigPaths.has(tsConfigPath)) return false;
37239
37248
  const compilerOptions = readResolvedCompilerOptions(tsConfigPath, 0, /* @__PURE__ */ new Set());
37240
37249
  if (!compilerOptions) return false;
37241
- if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) return false;
37250
+ if (!compilerOptionsDeclareTargetOrLib(compilerOptions)) {
37251
+ const tsConfig = readTsConfig(tsConfigPath);
37252
+ if (!tsConfig) return false;
37253
+ const nextVisitedConfigPaths = new Set(visitedConfigPaths);
37254
+ nextVisitedConfigPaths.add(tsConfigPath);
37255
+ const configDirectory = Path.dirname(tsConfigPath);
37256
+ return tsConfig.referencePaths.some((referencePath) => {
37257
+ const resolvedReferencePath = Path.resolve(configDirectory, referencePath);
37258
+ const referencedConfigPath = isFile(resolvedReferencePath) ? resolvedReferencePath : Path.join(resolvedReferencePath, TSCONFIG_FILENAME);
37259
+ return isFile(referencedConfigPath) && detectPreES2023FromConfig(referencedConfigPath, nextVisitedConfigPaths);
37260
+ });
37261
+ }
37242
37262
  return compilerOptionsArePreES2023(compilerOptions);
37243
37263
  };
37264
+ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"];
37244
37265
  const detectPreES2023Target = (directory) => {
37245
37266
  const tsConfigPath = Path.join(directory, TSCONFIG_FILENAME);
37246
37267
  if (isFile(tsConfigPath)) return detectPreES2023FromConfig(tsConfigPath);
37268
+ for (const fallbackFilename of FALLBACK_TSCONFIG_FILENAMES) {
37269
+ const fallbackPath = Path.join(directory, fallbackFilename);
37270
+ if (isFile(fallbackPath)) return detectPreES2023FromConfig(fallbackPath);
37271
+ }
37247
37272
  return false;
37248
37273
  };
37249
37274
  const REACT_DEPENDENCY_NAMES = new Set([
@@ -37402,6 +37427,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
37402
37427
  shopifyFlashListVersion: null,
37403
37428
  shopifyFlashListMajorVersion: null,
37404
37429
  hasReanimated: false,
37430
+ reanimatedVersion: null,
37405
37431
  isPreES2023Target: hasOwnTsConfig && detectPreES2023Target(directory),
37406
37432
  sourceFileCount
37407
37433
  };
@@ -37494,6 +37520,7 @@ const discoverProject = (directory) => {
37494
37520
  version: findShopifyFlashListVersion(directory, packageJson)
37495
37521
  }) : null;
37496
37522
  const hasReanimated = hasReactNativeWorkspace && someWorkspacePackageJson(directory, packageJson, isPackageJsonReanimatedAware);
37523
+ const reanimatedVersion = hasReanimated ? findInWorkspacePackageJsons(directory, packageJson, (workspacePackageJson) => getDependencySpec(workspacePackageJson, REANIMATED_DEPENDENCY_NAME)) : null;
37497
37524
  const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
37498
37525
  rootDirectory: directory,
37499
37526
  rootPackageJson: packageJson,
@@ -37523,6 +37550,7 @@ const discoverProject = (directory) => {
37523
37550
  shopifyFlashListVersion,
37524
37551
  shopifyFlashListMajorVersion: shopifyFlashListVersion === null ? null : getLowestDependencyMajor(shopifyFlashListVersion),
37525
37552
  hasReanimated,
37553
+ reanimatedVersion,
37526
37554
  isPreES2023Target,
37527
37555
  sourceFileCount
37528
37556
  };
@@ -37715,6 +37743,9 @@ const buildRuleSeverityControls = (config) => {
37715
37743
  ...config.buckets !== void 0 ? { buckets: config.buckets } : {}
37716
37744
  };
37717
37745
  };
37746
+ const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
37747
+ const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
37748
+ const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
37718
37749
  const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
37719
37750
  "effect/no-adjust-state-on-prop-change": "react-doctor/no-adjust-state-on-prop-change",
37720
37751
  "effect/no-chain-state-updates": "react-doctor/no-chain-state-updates",
@@ -37792,6 +37823,7 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
37792
37823
  "react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
37793
37824
  "react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
37794
37825
  "react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
37826
+ "react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
37795
37827
  "react/jsx-no-undef": "react-doctor/jsx-no-undef",
37796
37828
  "react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
37797
37829
  "react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
@@ -37876,9 +37908,6 @@ const tokenizeRuleList = (ruleList) => {
37876
37908
  if (!ruleSection) return [];
37877
37909
  return ruleSection.split(/[,\s]+/).map((token) => token.trim()).filter(Boolean);
37878
37910
  };
37879
- const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
37880
- const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
37881
- const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
37882
37911
  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}\`).`;
37883
37912
  const tokenMisnamesRule = (token, ruleId) => token !== ruleId && isSameRuleKey(token, ruleId);
37884
37913
  const detectInlineNearMiss = (lines, diagnosticLineIndex, ruleId) => {
@@ -37932,6 +37961,53 @@ const detectForeignDisableNearMiss = (lines, diagnosticLineIndex, ruleId) => {
37932
37961
  if (!ruleId.startsWith("react-doctor/")) return null;
37933
37962
  return detectInlineNearMiss(lines, diagnosticLineIndex, ruleId) ?? detectBlockNearMiss(lines, diagnosticLineIndex, ruleId);
37934
37963
  };
37964
+ const ESLINT_REACT_HOOKS_PLUGIN_PREFIX = "react-hooks/";
37965
+ const buildAcceptedTokens = (ruleId) => {
37966
+ const shortRuleId = ruleId.slice(15);
37967
+ return new Set([ruleId, `${ESLINT_REACT_HOOKS_PLUGIN_PREFIX}${shortRuleId}`]);
37968
+ };
37969
+ const listNamesRule = (ruleList, acceptedTokens) => tokenizeRuleList(ruleList).some((token) => acceptedTokens.has(token));
37970
+ const isInlineDisabled = (lines, diagnosticLineIndex, acceptedTokens) => {
37971
+ const candidates = [{
37972
+ line: lines[diagnosticLineIndex],
37973
+ requiredScope: "line"
37974
+ }, {
37975
+ line: lines[diagnosticLineIndex - 1],
37976
+ requiredScope: "next-line"
37977
+ }];
37978
+ for (const { line, requiredScope } of candidates) {
37979
+ const match = line?.match(FOREIGN_INLINE_DISABLE_PATTERN);
37980
+ if (!match) continue;
37981
+ const [, , scope, ruleList] = match;
37982
+ if (scope !== requiredScope) continue;
37983
+ if (listNamesRule(ruleList, acceptedTokens)) return true;
37984
+ }
37985
+ return false;
37986
+ };
37987
+ const isBlockDisabled = (lines, diagnosticLineIndex, acceptedTokens) => {
37988
+ let isRangeOpen = false;
37989
+ const lastLineIndex = Math.min(diagnosticLineIndex, lines.length - 1);
37990
+ for (let lineIndex = 0; lineIndex <= lastLineIndex; lineIndex++) {
37991
+ const line = lines[lineIndex];
37992
+ if (line === void 0 || !line.includes("-disable") && !line.includes("-enable")) continue;
37993
+ const disableMatch = line.match(FOREIGN_BLOCK_DISABLE_PATTERN);
37994
+ if (disableMatch && listNamesRule(disableMatch[2], acceptedTokens)) {
37995
+ isRangeOpen = true;
37996
+ continue;
37997
+ }
37998
+ const enableMatch = line.match(FOREIGN_BLOCK_ENABLE_PATTERN);
37999
+ if (enableMatch) {
38000
+ const enabledRules = tokenizeRuleList(enableMatch[1]);
38001
+ if (enabledRules.length === 0 || enabledRules.some((rule) => acceptedTokens.has(rule))) isRangeOpen = false;
38002
+ }
38003
+ }
38004
+ return isRangeOpen;
38005
+ };
38006
+ const isCompilerRuleForeignDisabled = (lines, diagnosticLineIndex, ruleId) => {
38007
+ if (!ruleId.startsWith("react-hooks-js/")) return false;
38008
+ const acceptedTokens = buildAcceptedTokens(ruleId);
38009
+ return isInlineDisabled(lines, diagnosticLineIndex, acceptedTokens) || isBlockDisabled(lines, diagnosticLineIndex, acceptedTokens);
38010
+ };
37935
38011
  const JSX_OPENER_TAG_PATTERN = /<[A-Za-z][\w.]*/g;
37936
38012
  const JSX_TAG_NAME_FOLLOW = /[A-Za-z]/;
37937
38013
  const isOpenerMatchInsideLineComment = (line, openerCharIndex) => {
@@ -38075,6 +38151,11 @@ const evaluateSuppression = (lines, diagnosticLineIndex, ruleId) => {
38075
38151
  isSuppressed: true,
38076
38152
  nearMissHint: null
38077
38153
  };
38154
+ if (isCompilerRuleForeignDisabled(lines, diagnosticLineIndex, ruleId)) return {
38155
+ isSuppressed: true,
38156
+ nearMissHint: null,
38157
+ isForeignDirective: true
38158
+ };
38078
38159
  const directComments = findStackedDisableCommentsAbove(lines, diagnosticLineIndex);
38079
38160
  if (hasChainSuppressor(directComments, ruleId)) return {
38080
38161
  isSuppressed: true,
@@ -38356,12 +38437,18 @@ const collectStringSet = (values) => {
38356
38437
  return new Set(values.filter((value) => typeof value === "string"));
38357
38438
  };
38358
38439
  const JSX_NO_UNDEF_IDENTIFIER_PATTERN = /^`([^`]+)`/;
38440
+ const NODE_CLI_PATH_SEGMENTS = new Set([
38441
+ "scripts",
38442
+ "bin",
38443
+ "tools"
38444
+ ]);
38445
+ const hasNodeCliPathSegment = (filePath) => filePath.split(/[\\/]/).slice(0, -1).some((segment) => NODE_CLI_PATH_SEGMENTS.has(segment));
38359
38446
  /**
38360
38447
  * Pre-compiles every stateful filter and returns a single
38361
38448
  * `apply(diagnostic)` closure that runs (in order):
38362
38449
  *
38363
38450
  * 1. auto-suppress (test-noise rules in test files; `migration-hint`
38364
- * wins over `test-noise`)
38451
+ * wins over `test-noise`; `no-console` on Node CLI scripts)
38365
38452
  * 2. severity overrides (top-level `rules` / `categories`, with
38366
38453
  * `"off"` dropping)
38367
38454
  * 3. warning suppression (only when `showWarnings` is false: drops every
@@ -38459,6 +38546,12 @@ const buildDiagnosticPipeline = (input) => {
38459
38546
  if (hasRawTextWrappers && isInsideStringOnlyWrapper(lines, diagnostic.line, diagnostic.column, rawTextWrapperComponentNames)) return true;
38460
38547
  return false;
38461
38548
  };
38549
+ const isNoConsoleOnNodeCliScript = (diagnostic) => {
38550
+ if (diagnostic.rule !== "no-console") return false;
38551
+ if (hasNodeCliPathSegment(diagnostic.filePath)) return true;
38552
+ const lines = getFileLines(diagnostic.filePath);
38553
+ return lines !== null && Boolean(lines[0]?.startsWith("#!"));
38554
+ };
38462
38555
  const isJsxNoUndefSuppressedByConfig = (diagnostic) => {
38463
38556
  if (!hasRuntimeGlobals) return false;
38464
38557
  if (diagnostic.rule !== "jsx-no-undef") return false;
@@ -38468,6 +38561,7 @@ const buildDiagnosticPipeline = (input) => {
38468
38561
  return {
38469
38562
  apply: (diagnostic) => {
38470
38563
  if (shouldAutoSuppress(diagnostic)) return null;
38564
+ if (isNoConsoleOnNodeCliScript(diagnostic)) return null;
38471
38565
  let current = diagnostic;
38472
38566
  let explicitSeverityOverride;
38473
38567
  let explicitRuleOverride;
@@ -38497,7 +38591,7 @@ const buildDiagnosticPipeline = (input) => {
38497
38591
  if (lines) {
38498
38592
  const ruleIdentifier = `${current.plugin}/${current.rule}`;
38499
38593
  const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
38500
- if (evaluation.isSuppressed) return suppress(current, "inline");
38594
+ if (evaluation.isSuppressed) return suppress(current, evaluation.isForeignDirective ? "foreign-inline" : "inline");
38501
38595
  if (evaluation.nearMissHint) current = {
38502
38596
  ...current,
38503
38597
  suppressionHint: evaluation.nearMissHint
@@ -42673,9 +42767,17 @@ const buildNoSecretsRecommendation = (project, fallbackRecommendation) => {
42673
42767
  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`;
42674
42768
  };
42675
42769
  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";
42770
+ const ACCESSORS_MIN_VERSION = "3.15.0";
42771
+ const supportsAccessors = (reanimatedVersion) => {
42772
+ if (reanimatedVersion === null) return true;
42773
+ const lowerBound = import_semver.validRange(reanimatedVersion) !== null ? import_semver.minVersion(reanimatedVersion) : import_semver.coerce(reanimatedVersion);
42774
+ if (lowerBound === null) return true;
42775
+ return import_semver.gte(lowerBound, ACCESSORS_MIN_VERSION);
42776
+ };
42676
42777
  const appendReanimatedSharedValueHint = (help, rule, project) => {
42677
42778
  if (rule !== "immutability") return help;
42678
42779
  if (!project.hasReanimated) return help;
42780
+ if (!supportsAccessors(project.reanimatedVersion)) return help;
42679
42781
  if (!help) return REANIMATED_SHARED_VALUE_HINT;
42680
42782
  return `${help}\n\n${REANIMATED_SHARED_VALUE_HINT}`;
42681
42783
  };
@@ -42837,13 +42939,13 @@ const REACT_USE_BINDING_RESOLUTION = {
42837
42939
  isReactUseBinding: true,
42838
42940
  isReactNamespaceBinding: false
42839
42941
  };
42840
- const getScriptKind = (filename) => {
42942
+ const getScriptKind$2 = (filename) => {
42841
42943
  if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
42842
42944
  if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
42843
42945
  if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
42844
42946
  return ts.ScriptKind.JS;
42845
42947
  };
42846
- const getUtf16Offset = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
42948
+ const getUtf16Offset$1 = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
42847
42949
  const unwrapExpression = (expression) => {
42848
42950
  let currentExpression = expression;
42849
42951
  while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
@@ -43092,8 +43194,8 @@ const findUseCallIdentifier = (sourceFile, useOffset) => {
43092
43194
  return matchedIdentifier;
43093
43195
  };
43094
43196
  const resolveUseCallBinding = (sourceText, filename, utf8Offset) => {
43095
- const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(filename));
43096
- const useIdentifier = findUseCallIdentifier(sourceFile, getUtf16Offset(sourceText, utf8Offset));
43197
+ const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getScriptKind$2(filename));
43198
+ const useIdentifier = findUseCallIdentifier(sourceFile, getUtf16Offset$1(sourceText, utf8Offset));
43097
43199
  if (!useIdentifier) return null;
43098
43200
  return resolveIdentifierBinding(useIdentifier, collectReactImportBindings(sourceFile), sourceFile);
43099
43201
  };
@@ -43114,6 +43216,201 @@ const shouldSuppressLocalUseHookDiagnostic = (diagnostic, rootDirectory) => {
43114
43216
  const bindingResolution = resolveUseCallBinding(sourceText, absolutePath, primaryLabel.span.offset);
43115
43217
  return bindingResolution !== null && !bindingResolution.isReactUseBinding;
43116
43218
  };
43219
+ const SUPPRESSED_COMPILER_CODES = new Set(["react-hooks-js(immutability)", "react-hooks-js(refs)"]);
43220
+ const WORKLET_DIRECTIVE = "worklet";
43221
+ const WORKLET_ACCEPTING_CALLEES = new Set([
43222
+ "useAnimatedStyle",
43223
+ "useAnimatedProps",
43224
+ "useDerivedValue",
43225
+ "useAnimatedReaction",
43226
+ "useAnimatedScrollHandler",
43227
+ "useAnimatedGestureHandler",
43228
+ "useFrameCallback",
43229
+ "runOnUI",
43230
+ "executeOnUIRuntimeSync"
43231
+ ]);
43232
+ const GESTURE_ROOT_IDENTIFIER = "Gesture";
43233
+ const getScriptKind$1 = (filename) => {
43234
+ if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
43235
+ if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
43236
+ if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
43237
+ return ts.ScriptKind.JS;
43238
+ };
43239
+ const getUtf16Offset = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
43240
+ const hasWorkletDirective = (node) => {
43241
+ if (!ts.isFunctionDeclaration(node) && !ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isMethodDeclaration(node)) return false;
43242
+ const body = node.body;
43243
+ if (!body || !ts.isBlock(body)) return false;
43244
+ for (const statement of body.statements) {
43245
+ if (!ts.isExpressionStatement(statement)) return false;
43246
+ if (!ts.isStringLiteral(statement.expression)) return false;
43247
+ if (statement.expression.text === WORKLET_DIRECTIVE) return true;
43248
+ }
43249
+ return false;
43250
+ };
43251
+ const rootIdentifierOfCallChain = (expression) => {
43252
+ let currentExpression = expression;
43253
+ while (true) {
43254
+ if (ts.isIdentifier(currentExpression)) return currentExpression.text;
43255
+ if (ts.isPropertyAccessExpression(currentExpression)) {
43256
+ currentExpression = currentExpression.expression;
43257
+ continue;
43258
+ }
43259
+ if (ts.isCallExpression(currentExpression)) {
43260
+ currentExpression = currentExpression.expression;
43261
+ continue;
43262
+ }
43263
+ return null;
43264
+ }
43265
+ };
43266
+ const isWorkletAcceptingCall = (callExpression) => {
43267
+ const callee = callExpression.expression;
43268
+ if (ts.isIdentifier(callee)) return WORKLET_ACCEPTING_CALLEES.has(callee.text);
43269
+ if (ts.isPropertyAccessExpression(callee)) {
43270
+ if (WORKLET_ACCEPTING_CALLEES.has(callee.name.text)) return true;
43271
+ return rootIdentifierOfCallChain(callee) === GESTURE_ROOT_IDENTIFIER;
43272
+ }
43273
+ return false;
43274
+ };
43275
+ const isFunctionWorklet = (functionNode) => {
43276
+ if (hasWorkletDirective(functionNode)) return true;
43277
+ const parent = functionNode.parent;
43278
+ return ts.isCallExpression(parent) && parent.arguments.some((argument) => argument === functionNode) && isWorkletAcceptingCall(parent);
43279
+ };
43280
+ const findNodeAtOffset = (sourceFile, targetOffset) => {
43281
+ let matchedNode = null;
43282
+ const visit = (node) => {
43283
+ if (node.getStart(sourceFile) > targetOffset || node.getEnd() <= targetOffset) return;
43284
+ matchedNode = node;
43285
+ ts.forEachChild(node, visit);
43286
+ };
43287
+ visit(sourceFile);
43288
+ return matchedNode;
43289
+ };
43290
+ const isOffsetInsideWorklet = (sourceFile, targetOffset) => {
43291
+ let currentNode = findNodeAtOffset(sourceFile, targetOffset);
43292
+ while (currentNode) {
43293
+ if (ts.isFunctionLike(currentNode) && isFunctionWorklet(currentNode)) return true;
43294
+ currentNode = currentNode.parent;
43295
+ }
43296
+ return false;
43297
+ };
43298
+ const shouldSuppressCompilerFindingInWorklet = (diagnostic, project, rootDirectory) => {
43299
+ if (!SUPPRESSED_COMPILER_CODES.has(diagnostic.code)) return false;
43300
+ if (!project.hasReanimated) return false;
43301
+ const primaryLabel = diagnostic.labels[0];
43302
+ if (!primaryLabel) return false;
43303
+ const absolutePath = Path.isAbsolute(diagnostic.filename) ? diagnostic.filename : Path.join(rootDirectory, diagnostic.filename);
43304
+ let sourceText;
43305
+ try {
43306
+ sourceText = NFS.readFileSync(absolutePath, "utf-8");
43307
+ } catch {
43308
+ return false;
43309
+ }
43310
+ return isOffsetInsideWorklet(ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getScriptKind$1(absolutePath)), getUtf16Offset(sourceText, primaryLabel.span.offset));
43311
+ };
43312
+ const MANUAL_MEMOIZATION_PLUGIN = "react-doctor";
43313
+ const MANUAL_MEMOIZATION_RULE = "react-compiler-no-manual-memoization";
43314
+ const REACT_COMPILER_PLUGIN = "react-hooks-js";
43315
+ const getScriptKind = (filename) => {
43316
+ if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
43317
+ if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
43318
+ if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
43319
+ return ts.ScriptKind.JS;
43320
+ };
43321
+ const isManualMemoizationDiagnostic = (diagnostic) => diagnostic.plugin === MANUAL_MEMOIZATION_PLUGIN && diagnostic.rule === MANUAL_MEMOIZATION_RULE;
43322
+ const nodeLineRange = (sourceFile, node) => ({
43323
+ startLine: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1,
43324
+ endLine: sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line + 1
43325
+ });
43326
+ const findOutermostEnclosingFunctionRange = (sourceFile, targetLine) => {
43327
+ let foundRange = null;
43328
+ const visit = (node) => {
43329
+ if (foundRange) return;
43330
+ if (ts.isFunctionLike(node)) {
43331
+ const range = nodeLineRange(sourceFile, node);
43332
+ if (range.startLine <= targetLine && targetLine <= range.endLine) foundRange = range;
43333
+ return;
43334
+ }
43335
+ ts.forEachChild(node, visit);
43336
+ };
43337
+ visit(sourceFile);
43338
+ return foundRange;
43339
+ };
43340
+ const NEWLINE_BYTE = 10;
43341
+ const lineOfUtf8Offset = (sourceBuffer, utf8Offset) => {
43342
+ let lineNumber = 1;
43343
+ const scanEnd = Math.min(utf8Offset, sourceBuffer.length);
43344
+ for (let byteIndex = 0; byteIndex < scanEnd; byteIndex++) if (sourceBuffer[byteIndex] === NEWLINE_BYTE) lineNumber++;
43345
+ return lineNumber;
43346
+ };
43347
+ /**
43348
+ * Drops `react-doctor/react-compiler-no-manual-memoization` diagnostics
43349
+ * whose enclosing function also carries a `react-hooks-js` (React
43350
+ * Compiler) diagnostic. Every react-hooks-js finding marks a function the
43351
+ * compiler could NOT compile (a bail-out / skip / preserve-manual-
43352
+ * memoization failure), so "React Compiler already caches every value
43353
+ * here" is false for that function and the manual memoization is
43354
+ * load-bearing, not dead weight.
43355
+ *
43356
+ * Matching is per enclosing function, not per file: a bailed-out
43357
+ * component must not silence redundant-memo findings in a sibling
43358
+ * component the compiler did optimize.
43359
+ *
43360
+ * Module-scope `memo(() => …)` wrappers have no enclosing function; for
43361
+ * those the memo call's own span is the containment range, so a bail-out
43362
+ * inside the inline-wrapped component still suppresses. Every failure
43363
+ * path (unreadable file, missing span) fails open and keeps the
43364
+ * diagnostic.
43365
+ */
43366
+ const suppressMemoizationInBailedOutFunctions = (diagnostics, rootDirectory) => {
43367
+ const compilerDiagnosticLinesByFile = /* @__PURE__ */ new Map();
43368
+ let hasManualMemoizationDiagnostic = false;
43369
+ for (const diagnostic of diagnostics) {
43370
+ if (isManualMemoizationDiagnostic(diagnostic)) {
43371
+ hasManualMemoizationDiagnostic = true;
43372
+ continue;
43373
+ }
43374
+ if (diagnostic.plugin !== REACT_COMPILER_PLUGIN || diagnostic.line <= 0) continue;
43375
+ const lines = compilerDiagnosticLinesByFile.get(diagnostic.filePath);
43376
+ if (lines) lines.push(diagnostic.line);
43377
+ else compilerDiagnosticLinesByFile.set(diagnostic.filePath, [diagnostic.line]);
43378
+ }
43379
+ if (!hasManualMemoizationDiagnostic || compilerDiagnosticLinesByFile.size === 0) return diagnostics;
43380
+ const parsedFileCache = /* @__PURE__ */ new Map();
43381
+ const readAndParse = (filePath) => {
43382
+ const cached = parsedFileCache.get(filePath);
43383
+ if (cached !== void 0) return cached;
43384
+ const absolutePath = Path.isAbsolute(filePath) ? filePath : Path.resolve(rootDirectory || ".", filePath);
43385
+ let parsed;
43386
+ try {
43387
+ const buffer = NFS.readFileSync(absolutePath);
43388
+ parsed = {
43389
+ sourceFile: ts.createSourceFile(absolutePath, buffer.toString("utf8"), ts.ScriptTarget.Latest, true, getScriptKind(absolutePath)),
43390
+ buffer
43391
+ };
43392
+ } catch {
43393
+ parsed = null;
43394
+ }
43395
+ parsedFileCache.set(filePath, parsed);
43396
+ return parsed;
43397
+ };
43398
+ const isInsideBailedOutFunction = (diagnostic) => {
43399
+ const compilerLines = compilerDiagnosticLinesByFile.get(diagnostic.filePath);
43400
+ if (!compilerLines || diagnostic.line <= 0) return false;
43401
+ const parsed = readAndParse(diagnostic.filePath);
43402
+ if (!parsed) return false;
43403
+ let containmentRange = findOutermostEnclosingFunctionRange(parsed.sourceFile, diagnostic.line);
43404
+ if (!containmentRange && diagnostic.offset !== void 0 && diagnostic.length !== void 0) containmentRange = {
43405
+ startLine: diagnostic.line,
43406
+ endLine: lineOfUtf8Offset(parsed.buffer, diagnostic.offset + diagnostic.length)
43407
+ };
43408
+ if (!containmentRange) return false;
43409
+ const { startLine, endLine } = containmentRange;
43410
+ return compilerLines.some((compilerLine) => startLine <= compilerLine && compilerLine <= endLine);
43411
+ };
43412
+ return diagnostics.filter((diagnostic) => !isManualMemoizationDiagnostic(diagnostic) || !isInsideBailedOutFunction(diagnostic));
43413
+ };
43117
43414
  const FILEPATH_WITH_LOCATION_PATTERN = /\S+\.\w+:\d+:\d+[\s\S]*$/;
43118
43415
  const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
43119
43416
  const TRAILING_PERIOD_PATTERN = /\.$/;
@@ -43253,7 +43550,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
43253
43550
  minifiedFileCache.set(absolutePath, minified);
43254
43551
  return minified;
43255
43552
  };
43256
- return parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory)).map((diagnostic) => {
43553
+ return suppressMemoizationInBailedOutFunctions(parsed.diagnostics.filter((diagnostic) => diagnostic.code && isLintableSourceFile(diagnostic.filename) && !isMinifiedDiagnosticFile(diagnostic.filename) && !shouldSuppressLocalUseHookDiagnostic(diagnostic, rootDirectory) && !shouldSuppressCompilerFindingInWorklet(diagnostic, project, rootDirectory)).map((diagnostic) => {
43257
43554
  const { plugin, rule } = parseRuleCode(diagnostic.code);
43258
43555
  const primaryLabel = diagnostic.labels[0];
43259
43556
  const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule, project);
@@ -43280,7 +43577,7 @@ const parseOxlintOutput = (stdout, project, rootDirectory) => {
43280
43577
  ...resolveMatchByOccurrence(rule, category) ? { matchByOccurrence: true } : {},
43281
43578
  ...relatedLocations.length > 0 ? { relatedLocations } : {}
43282
43579
  };
43283
- });
43580
+ }), rootDirectory);
43284
43581
  };
43285
43582
  const buildOxlintChildEnv = (sourceEnv) => {
43286
43583
  const childEnv = {};
@@ -43791,6 +44088,7 @@ const runOxlint = async (options) => {
43791
44088
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
43792
44089
  const severityControls = buildRuleSeverityControls(userConfig);
43793
44090
  validateRuleRegistration();
44091
+ resetManifestCaches();
43794
44092
  if (includePaths !== void 0 && includePaths.length === 0) return [];
43795
44093
  const pluginPath = resolvePluginPath();
43796
44094
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
@@ -44453,9 +44751,10 @@ const CONTEXT_AXES = [
44453
44751
  }
44454
44752
  ];
44455
44753
  const SCORE_AXES = [...GATED_AXES, ...CONTEXT_AXES];
44456
- const worstGatedAxis = (score) => {
44457
- let worst = GATED_AXES[0];
44458
- for (const axis of GATED_AXES) if (score[axis.key] < score[worst.key]) worst = axis;
44754
+ const gatedAxesForSection = (section) => section === "devDependencies" ? GATED_AXES.filter((axis) => axis.key !== "vulnerability") : GATED_AXES;
44755
+ const worstGatedAxis = (score, gatedAxes) => {
44756
+ let worst = gatedAxes[0];
44757
+ for (const axis of gatedAxes) if (score[axis.key] < score[worst.key]) worst = axis;
44459
44758
  return worst;
44460
44759
  };
44461
44760
  const clampScore = (value) => {
@@ -44479,6 +44778,69 @@ const resolveConcreteVersion = (spec) => {
44479
44778
  if (range === null || range === "*") return null;
44480
44779
  return import_semver.minVersion(trimmed)?.version ?? null;
44481
44780
  };
44781
+ const readTextFileOrNull = (filePath) => {
44782
+ try {
44783
+ return NFS.readFileSync(filePath, "utf-8");
44784
+ } catch {
44785
+ return null;
44786
+ }
44787
+ };
44788
+ const buildNpmLockLookup = (lockText) => {
44789
+ let parsed;
44790
+ try {
44791
+ parsed = JSON.parse(lockText);
44792
+ } catch {
44793
+ return null;
44794
+ }
44795
+ if (typeof parsed !== "object" || parsed === null) return null;
44796
+ const lock = parsed;
44797
+ return (name) => {
44798
+ const entry = lock.packages?.[`node_modules/${name}`] ?? lock.dependencies?.[name];
44799
+ return typeof entry?.version === "string" ? entry.version : null;
44800
+ };
44801
+ };
44802
+ const buildYarnLockLookup = (lockText) => {
44803
+ const lines = lockText.split(/\r?\n/);
44804
+ return (name, spec) => {
44805
+ const descriptor = `${name}@${spec}`;
44806
+ const berryDescriptor = `${name}@npm:${spec}`;
44807
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
44808
+ const line = lines[lineIndex];
44809
+ if (line.startsWith(" ") || line.startsWith("#") || !line.includes(":")) continue;
44810
+ const descriptors = line.replace(/:\s*$/, "").split(",").map((part) => part.trim().replace(/^"|"$/g, ""));
44811
+ if (!descriptors.includes(descriptor) && !descriptors.includes(berryDescriptor)) continue;
44812
+ for (let bodyIndex = lineIndex + 1; bodyIndex < lines.length && (lines[bodyIndex].startsWith(" ") || lines[bodyIndex] === ""); bodyIndex += 1) {
44813
+ const versionMatch = /^\s+version:?\s+"?([^"\s]+)"?/.exec(lines[bodyIndex]);
44814
+ if (versionMatch) return versionMatch[1];
44815
+ }
44816
+ return null;
44817
+ }
44818
+ return null;
44819
+ };
44820
+ };
44821
+ const buildPnpmLockLookup = (lockText) => {
44822
+ return (name) => {
44823
+ const entryPattern = new RegExp(`^ {4,8}['"]?${name.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&")}['"]?:\\s*$`);
44824
+ const lines = lockText.split(/\r?\n/);
44825
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
44826
+ if (!entryPattern.test(lines[lineIndex])) continue;
44827
+ for (let bodyIndex = lineIndex + 1; bodyIndex < lines.length && /^ {5,}\S/.test(lines[bodyIndex]); bodyIndex += 1) {
44828
+ const versionMatch = /^\s+version:\s+['"]?([^'"\s(]+)/.exec(lines[bodyIndex]);
44829
+ if (versionMatch) return versionMatch[1];
44830
+ }
44831
+ }
44832
+ return null;
44833
+ };
44834
+ };
44835
+ const buildLockedVersionLookup = (rootDirectory) => {
44836
+ const npmLockText = readTextFileOrNull(Path.join(rootDirectory, "package-lock.json"));
44837
+ if (npmLockText !== null) return buildNpmLockLookup(npmLockText);
44838
+ const yarnLockText = readTextFileOrNull(Path.join(rootDirectory, "yarn.lock"));
44839
+ if (yarnLockText !== null) return buildYarnLockLookup(yarnLockText);
44840
+ const pnpmLockText = readTextFileOrNull(Path.join(rootDirectory, "pnpm-lock.yaml"));
44841
+ if (pnpmLockText !== null) return buildPnpmLockLookup(pnpmLockText);
44842
+ return null;
44843
+ };
44482
44844
  const locateDependencyKey = (packageJsonText, section, name) => {
44483
44845
  const needle = `"${name}"`;
44484
44846
  const sectionHeader = new RegExp(`"${section}"\\s*:\\s*\\{`);
@@ -44505,7 +44867,7 @@ const locateDependencyKey = (packageJsonText, section, name) => {
44505
44867
  }
44506
44868
  return null;
44507
44869
  };
44508
- const collectDependenciesToScore = (packageJson, packageJsonText, includeDevDependencies) => {
44870
+ const collectDependenciesToScore = (packageJson, packageJsonText, includeDevDependencies, lockedVersionLookup) => {
44509
44871
  const sectionByName = /* @__PURE__ */ new Map();
44510
44872
  for (const name of Object.keys(packageJson.dependencies ?? {})) sectionByName.set(name, "dependencies");
44511
44873
  if (includeDevDependencies) {
@@ -44515,13 +44877,18 @@ const collectDependenciesToScore = (packageJson, packageJsonText, includeDevDepe
44515
44877
  for (const [name, section] of sectionByName) {
44516
44878
  if (SUPPLY_CHAIN_IGNORED_PACKAGES.has(name)) continue;
44517
44879
  const spec = (packageJson[section] ?? {})[name] ?? "";
44518
- const version = resolveConcreteVersion(spec);
44519
- if (version === null) continue;
44880
+ const floorVersion = resolveConcreteVersion(spec);
44881
+ if (floorVersion === null) continue;
44882
+ const lockedVersion = lockedVersionLookup?.(name, spec) ?? null;
44883
+ const lockSatisfiesSpec = lockedVersion !== null && import_semver.valid(lockedVersion) !== null && import_semver.satisfies(lockedVersion, spec);
44884
+ const isExactPin = import_semver.valid(spec.trim()) !== null;
44520
44885
  const location = locateDependencyKey(packageJsonText, section, name);
44521
44886
  dependencies.push({
44522
44887
  name,
44523
- version,
44888
+ version: lockSatisfiesSpec ? lockedVersion : floorVersion,
44524
44889
  spec,
44890
+ section,
44891
+ resolution: isExactPin ? "pin" : lockSatisfiesSpec ? "locked" : "floor",
44525
44892
  line: location?.line ?? 0,
44526
44893
  column: location?.column ?? 0
44527
44894
  });
@@ -44672,7 +45039,11 @@ const formatAlertReason = (topAlerts, totalCount) => {
44672
45039
  }
44673
45040
  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)}.`;
44674
45041
  };
44675
- const formatDependencyIdentity = (dependency) => import_semver.valid(dependency.spec) !== null ? `${dependency.name}@${dependency.version}` : `${dependency.name}@${dependency.version} (lowest version "${dependency.spec}" allows)`;
45042
+ const formatDependencyIdentity = (dependency) => {
45043
+ if (dependency.resolution === "pin") return `${dependency.name}@${dependency.version}`;
45044
+ if (dependency.resolution === "locked") return `${dependency.name}@${dependency.version} (lockfile resolution of "${dependency.spec}")`;
45045
+ return `${dependency.name}@${dependency.version} (lowest version "${dependency.spec}" allows)`;
45046
+ };
44676
45047
  const buildSupplyChainHelp = (dependency, failingAxis, topAlerts, packagePageUrl, options) => {
44677
45048
  const hasCriticalAlert = topAlerts.some((alert) => alert.severity.toLowerCase() === "critical");
44678
45049
  const entry = `\`"${dependency.name}": "${dependency.spec}"\``;
@@ -44715,7 +45086,7 @@ const buildLowScoreDiagnostic = (dependency, artifact, failingAxis, options) =>
44715
45086
  const checkSupplyChain = (input) => gen(function* () {
44716
45087
  const options = resolveOptions(input.userConfig);
44717
45088
  const packageJsonPath = Path.join(input.rootDirectory, "package.json");
44718
- const dependencies = collectDependenciesToScore(readPackageJson$1(packageJsonPath), readPackageJsonText(packageJsonPath), options.includeDevDependencies);
45089
+ const dependencies = collectDependenciesToScore(readPackageJson$1(packageJsonPath), readPackageJsonText(packageJsonPath), options.includeDevDependencies, buildLockedVersionLookup(input.rootDirectory));
44719
45090
  if (dependencies.length === 0) return [];
44720
45091
  const cacheDirectory = isSupplyChainCacheDisabled() ? null : resolveReactDoctorCacheDir(input.rootDirectory);
44721
45092
  if (cacheDirectory !== null) pruneExpiredSocketCache(cacheDirectory);
@@ -44724,7 +45095,7 @@ const checkSupplyChain = (input) => gen(function* () {
44724
45095
  for (let index = 0; index < dependencies.length; index += 1) {
44725
45096
  const artifact = artifacts[index];
44726
45097
  if (!artifact) continue;
44727
- const worstAxis = worstGatedAxis(artifact.score);
45098
+ const worstAxis = worstGatedAxis(artifact.score, gatedAxesForSection(dependencies[index].section));
44728
45099
  if (toHundred(artifact.score[worstAxis.key]) >= options.minScore) continue;
44729
45100
  diagnostics.push(buildLowScoreDiagnostic(dependencies[index], artifact, worstAxis, options));
44730
45101
  }
@@ -46007,7 +46378,7 @@ const makeNoopConsole = () => ({
46007
46378
  });
46008
46379
  //#endregion
46009
46380
  //#region src/cli/utils/version.ts
46010
- const VERSION = "0.7.1-dev.d353dad";
46381
+ const VERSION = "0.7.2-dev.aa519e5";
46011
46382
  //#endregion
46012
46383
  //#region src/cli/utils/json-mode.ts
46013
46384
  let context = null;
@@ -46376,13 +46747,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
46376
46747
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
46377
46748
  * standard `SENTRY_RELEASE` override.
46378
46749
  */
46379
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.1-dev.d353dad`;
46750
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.2-dev.aa519e5`;
46380
46751
  /**
46381
46752
  * Deployment environment shown in Sentry's environment filter. Defaults to
46382
46753
  * `production` for tagged releases and `development` for dev/unbuilt versions,
46383
46754
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
46384
46755
  */
46385
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.1-dev.d353dad") ? "development" : "production");
46756
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.2-dev.aa519e5") ? "development" : "production");
46386
46757
  /**
46387
46758
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
46388
46759
  * (set to `0` to disable tracing) and falls back to
@@ -58899,13 +59270,15 @@ const buildOutcomeAttributes = (input) => {
58899
59270
  const countBySource = {
58900
59271
  config: 0,
58901
59272
  override: 0,
58902
- inline: 0
59273
+ inline: 0,
59274
+ "foreign-inline": 0
58903
59275
  };
58904
59276
  for (const suppression of input.suppressedRuleCounts) countBySource[suppression.source] += suppression.count;
58905
- suppressionRollup.suppressed = countBySource.config + countBySource.override + countBySource.inline;
59277
+ suppressionRollup.suppressed = countBySource.config + countBySource.override + countBySource.inline + countBySource["foreign-inline"];
58906
59278
  suppressionRollup.suppressedConfig = countBySource.config;
58907
59279
  suppressionRollup.suppressedOverride = countBySource.override;
58908
59280
  suppressionRollup.suppressedInline = countBySource.inline;
59281
+ suppressionRollup.suppressedForeignInline = countBySource["foreign-inline"];
58909
59282
  }
58910
59283
  const attributes = {
58911
59284
  ...withNamespace("outcome", {
@@ -64555,4 +64928,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
64555
64928
  export {};
64556
64929
 
64557
64930
  //# sourceMappingURL=cli.js.map
64558
- //# debugId=47338856-c658-5c78-a5e2-e871c2dafaa7
64931
+ //# debugId=a8ebd975-0f3b-5218-ad38-b9c8095f6668