react-doctor 0.8.1-dev.c9f2c4b → 0.8.1-dev.cd9ca68

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]="c24708ed-97a3-59cc-81f7-4cf277ab29f2")}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]="434800fc-200b-5a59-aa25-61e682ab57d7")}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";
@@ -36571,10 +36571,10 @@ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"]
36571
36571
  const FRAMEWORK_PACKAGES = {
36572
36572
  next: "nextjs",
36573
36573
  "@tanstack/react-start": "tanstack-start",
36574
- vite: "vite",
36575
- "react-scripts": "cra",
36576
36574
  "@remix-run/react": "remix",
36577
36575
  gatsby: "gatsby",
36576
+ vite: "vite",
36577
+ "react-scripts": "cra",
36578
36578
  expo: "expo",
36579
36579
  "react-native": "react-native"
36580
36580
  };
@@ -37101,19 +37101,6 @@ const getPreactVersion = (packageJson) => {
37101
37101
  ...packageJson.devDependencies
37102
37102
  }.preact ?? null;
37103
37103
  };
37104
- const TANSTACK_QUERY_PACKAGES = new Set([
37105
- "@tanstack/react-query",
37106
- "@tanstack/query-core",
37107
- "react-query"
37108
- ]);
37109
- const hasTanStackQuery = (packageJson) => {
37110
- const allDependencies = {
37111
- ...packageJson.peerDependencies,
37112
- ...packageJson.dependencies,
37113
- ...packageJson.devDependencies
37114
- };
37115
- return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
37116
- };
37117
37104
  const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
37118
37105
  if (version === null || !isCatalogReference(version)) return version;
37119
37106
  const catalogName = extractCatalogName(version);
@@ -37316,7 +37303,60 @@ const listWorkspacePackages = (rootDirectory) => {
37316
37303
  }
37317
37304
  return packages;
37318
37305
  };
37306
+ const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
37307
+ const allDependencies = {
37308
+ ...packageJson.devDependencies,
37309
+ ...packageJson.peerDependencies,
37310
+ ...packageJson.dependencies
37311
+ };
37312
+ for (const packageName of packageNames) {
37313
+ const version = allDependencies[packageName];
37314
+ if (version !== void 0) return version;
37315
+ }
37316
+ return null;
37317
+ };
37318
+ const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
37319
+ const getTanStackQueryVersion = (packageJson) => {
37320
+ return getPreferredDependencyVersion({
37321
+ packageJson,
37322
+ packageNames: TANSTACK_REACT_QUERY_PACKAGES
37323
+ });
37324
+ };
37325
+ const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
37326
+ const getStyledComponentsVersion = (packageJson) => {
37327
+ return getPreferredDependencyVersion({
37328
+ packageJson,
37329
+ packageNames: STYLED_COMPONENTS_PACKAGES
37330
+ });
37331
+ };
37332
+ const I18N_PACKAGES = [
37333
+ "i18next",
37334
+ "react-i18next",
37335
+ "next-i18next",
37336
+ "react-intl",
37337
+ "next-intl",
37338
+ "use-intl",
37339
+ "@formatjs/intl",
37340
+ "@lingui/core",
37341
+ "@lingui/react",
37342
+ "typesafe-i18n",
37343
+ "@tolgee/react",
37344
+ "react-intl-universal"
37345
+ ];
37346
+ const hasI18nDependency = (packageJson) => {
37347
+ const allDependencies = {
37348
+ ...packageJson.peerDependencies,
37349
+ ...packageJson.dependencies,
37350
+ ...packageJson.devDependencies,
37351
+ ...packageJson.optionalDependencies
37352
+ };
37353
+ return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
37354
+ };
37319
37355
  const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
37356
+ const MOBX_REACT_PACKAGE_NAME = "mobx-react";
37357
+ const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
37358
+ const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
37359
+ const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
37320
37360
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
37321
37361
  const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
37322
37362
  const dependencyDeclaration = getDependencyDeclaration({
@@ -37335,7 +37375,26 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
37335
37375
  if (nextMajor === null) return false;
37336
37376
  return nextMajor < currentMajor;
37337
37377
  };
37338
- const evaluateManifestFacts = (facts, packageJson, directory) => {
37378
+ const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSupportedMajor) => {
37379
+ if (currentFact.version === null) return true;
37380
+ if (nextFact.version === null) return false;
37381
+ const currentMajor = getLowestDependencyMajor(currentFact.version);
37382
+ const nextMajor = getLowestDependencyMajor(nextFact.version);
37383
+ if (currentMajor === null) return false;
37384
+ if (nextMajor === null) return true;
37385
+ if (currentMajor > latestSupportedMajor) return false;
37386
+ if (nextMajor > latestSupportedMajor) return true;
37387
+ return nextMajor < currentMajor;
37388
+ };
37389
+ const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
37390
+ if (!currentVersion) return true;
37391
+ const currentMajor = getLowestDependencyMajor(currentVersion);
37392
+ const nextMajor = getLowestDependencyMajor(nextVersion);
37393
+ if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
37394
+ if (nextMajor === null) return currentMajor >= 6;
37395
+ return nextMajor < currentMajor;
37396
+ };
37397
+ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
37339
37398
  if (facts.expo.version === null) {
37340
37399
  const spec = getDependencySpec(packageJson, "expo");
37341
37400
  if (spec !== null) facts.expo = {
@@ -37357,13 +37416,74 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
37357
37416
  sourceDirectory: directory
37358
37417
  };
37359
37418
  }
37419
+ const mobxSpec = getDependencySpec(packageJson, "mobx");
37420
+ if (mobxSpec !== null) {
37421
+ const nextMobxFact = {
37422
+ version: resolveCatalogBackedDependencyVersion({
37423
+ rootDirectory: directory,
37424
+ rootPackageJson: packageJson,
37425
+ packageName: "mobx",
37426
+ version: mobxSpec
37427
+ }),
37428
+ sourceDirectory: directory
37429
+ };
37430
+ if (shouldReplaceSupportedDependencyFact(facts.mobx, nextMobxFact, 6)) facts.mobx = nextMobxFact;
37431
+ }
37432
+ facts.hasMobxReact = facts.hasMobxReact || getDependencySpec(packageJson, MOBX_REACT_PACKAGE_NAME) !== null;
37433
+ facts.hasMobxReactLite = facts.hasMobxReactLite || getDependencySpec(packageJson, MOBX_REACT_LITE_PACKAGE_NAME) !== null;
37434
+ facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
37435
+ facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
37436
+ const zustandSpec = getDependencySpec(packageJson, "zustand");
37437
+ if (zustandSpec !== null) {
37438
+ const nextZustandFact = {
37439
+ version: resolveCatalogBackedDependencyVersion({
37440
+ rootDirectory: directory,
37441
+ rootPackageJson: packageJson,
37442
+ packageName: "zustand",
37443
+ version: zustandSpec
37444
+ }),
37445
+ sourceDirectory: directory
37446
+ };
37447
+ if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
37448
+ }
37360
37449
  if (facts.reanimatedVersion === null) {
37361
37450
  const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
37362
37451
  if (spec !== null) facts.reanimatedVersion = spec;
37363
37452
  }
37453
+ if (facts.valtioVersion === null) {
37454
+ const spec = getDependencySpec(packageJson, "valtio");
37455
+ if (spec !== null) facts.valtioVersion = spec;
37456
+ }
37457
+ facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
37458
+ const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
37459
+ rootDirectory: directory,
37460
+ rootPackageJson: packageJson,
37461
+ packageName: "styled-components",
37462
+ version: getStyledComponentsVersion(packageJson)
37463
+ });
37464
+ if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
37465
+ facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
37364
37466
  facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
37365
37467
  facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
37366
37468
  facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
37469
+ const remotionSpec = getDependencySpec(packageJson, "remotion");
37470
+ if (remotionSpec !== null) {
37471
+ facts.hasRemotionDependency = true;
37472
+ const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
37473
+ rootDirectory,
37474
+ rootPackageJson,
37475
+ packageName: "remotion",
37476
+ version: remotionSpec
37477
+ });
37478
+ const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
37479
+ if (remotionMajorVersion === null) {
37480
+ facts.hasUnknownRemotionVersion = true;
37481
+ facts.remotionVersion = null;
37482
+ } else if (!facts.hasUnknownRemotionVersion) {
37483
+ const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
37484
+ if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
37485
+ }
37486
+ }
37367
37487
  };
37368
37488
  const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
37369
37489
  const facts = {
@@ -37383,12 +37503,31 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37383
37503
  version: null,
37384
37504
  sourceDirectory: null
37385
37505
  },
37506
+ valtioVersion: null,
37507
+ mobx: {
37508
+ version: null,
37509
+ sourceDirectory: null
37510
+ },
37511
+ hasMobxReact: false,
37512
+ hasMobxReactLite: false,
37513
+ hasMobxStateTree: false,
37514
+ hasMobxReactObserver: false,
37515
+ zustand: {
37516
+ version: null,
37517
+ sourceDirectory: null
37518
+ },
37519
+ tanstackQueryVersion: null,
37520
+ styledComponentsVersion: null,
37521
+ hasI18nLibrary: false,
37386
37522
  hasReactNativeAwarePackage: false,
37387
37523
  hasReanimatedAwarePackage: false,
37388
37524
  hasSsrDependency: false,
37525
+ hasRemotionDependency: false,
37526
+ hasUnknownRemotionVersion: false,
37527
+ remotionVersion: null,
37389
37528
  reanimatedVersion: null
37390
37529
  };
37391
- evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
37530
+ evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
37392
37531
  let isReactGroupSettled = !collectReactGroup;
37393
37532
  const visitedDirectories = /* @__PURE__ */ new Set();
37394
37533
  for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
@@ -37397,7 +37536,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37397
37536
  if (visitedDirectories.has(workspaceDirectory)) continue;
37398
37537
  visitedDirectories.add(workspaceDirectory);
37399
37538
  const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
37400
- evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
37539
+ evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory, rootDirectory, rootPackageJson);
37401
37540
  const info = extractDependencyInfo(workspacePackageJson);
37402
37541
  if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
37403
37542
  if (isReactGroupSettled) continue;
@@ -37618,11 +37757,27 @@ const discoverProjectWithoutPackageJson = (directory) => {
37618
37757
  tailwindVersion: null,
37619
37758
  zodVersion: null,
37620
37759
  zodMajorVersion: null,
37760
+ mobxVersion: null,
37761
+ mobxMajorVersion: null,
37762
+ hasMobxReact: false,
37763
+ hasMobxReactLite: false,
37764
+ hasMobxStateTree: false,
37765
+ hasMobxReactObserver: false,
37766
+ zustandVersion: null,
37767
+ zustandMajorVersion: null,
37621
37768
  framework: "unknown",
37622
37769
  hasTypeScript: hasOwnTsConfig,
37623
37770
  hasReactCompiler: false,
37624
37771
  hasReactCompilerLintPlugin: false,
37625
37772
  hasTanStackQuery: false,
37773
+ valtioVersion: null,
37774
+ valtioMajorVersion: null,
37775
+ hasRemotion: false,
37776
+ remotionVersion: null,
37777
+ remotionMajorVersion: null,
37778
+ hasI18nLibrary: false,
37779
+ tanstackQueryVersion: null,
37780
+ styledComponentsVersion: null,
37626
37781
  hasSsrDependency: false,
37627
37782
  preactVersion: null,
37628
37783
  preactMajorVersion: null,
@@ -37721,6 +37876,12 @@ const discoverProject = (directory) => {
37721
37876
  packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
37722
37877
  version: workspaceFacts.shopifyFlashList.version
37723
37878
  }) : null;
37879
+ const zustandVersion = resolveCatalogBackedDependencyVersion({
37880
+ rootDirectory: directory,
37881
+ rootPackageJson: packageJson,
37882
+ packageName: "zustand",
37883
+ version: workspaceFacts.zustand.version
37884
+ });
37724
37885
  const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
37725
37886
  const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
37726
37887
  const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
@@ -37729,7 +37890,21 @@ const discoverProject = (directory) => {
37729
37890
  packageName: "next",
37730
37891
  version: workspaceFacts.next.version
37731
37892
  }) : null;
37893
+ const valtioVersion = resolveCatalogBackedDependencyVersion({
37894
+ rootDirectory: directory,
37895
+ rootPackageJson: packageJson,
37896
+ packageName: "valtio",
37897
+ version: workspaceFacts.valtioVersion
37898
+ });
37899
+ const mobxVersion = resolveCatalogBackedDependencyVersion({
37900
+ rootDirectory: directory,
37901
+ rootPackageJson: packageJson,
37902
+ packageName: "mobx",
37903
+ version: workspaceFacts.mobx.version
37904
+ });
37732
37905
  const preactVersion = getPreactVersion(packageJson);
37906
+ const remotionVersion = workspaceFacts.remotionVersion;
37907
+ const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
37733
37908
  const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
37734
37909
  const projectInfo = {
37735
37910
  rootDirectory: directory,
@@ -37739,11 +37914,27 @@ const discoverProject = (directory) => {
37739
37914
  tailwindVersion,
37740
37915
  zodVersion,
37741
37916
  zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
37917
+ mobxVersion,
37918
+ mobxMajorVersion: mobxVersion === null ? null : getLowestDependencyMajor(mobxVersion),
37919
+ hasMobxReact: workspaceFacts.hasMobxReact,
37920
+ hasMobxReactLite: workspaceFacts.hasMobxReactLite,
37921
+ hasMobxStateTree: workspaceFacts.hasMobxStateTree,
37922
+ hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
37923
+ zustandVersion,
37924
+ zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
37742
37925
  framework,
37743
37926
  hasTypeScript,
37744
37927
  hasReactCompiler: detectReactCompiler(directory, packageJson),
37745
37928
  hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
37746
- hasTanStackQuery: hasTanStackQuery(packageJson),
37929
+ hasTanStackQuery: tanstackQueryVersion !== null,
37930
+ hasI18nLibrary: workspaceFacts.hasI18nLibrary,
37931
+ tanstackQueryVersion,
37932
+ styledComponentsVersion: workspaceFacts.styledComponentsVersion,
37933
+ valtioVersion,
37934
+ valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
37935
+ hasRemotion: workspaceFacts.hasRemotionDependency,
37936
+ remotionVersion,
37937
+ remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
37747
37938
  hasSsrDependency: workspaceFacts.hasSsrDependency,
37748
37939
  preactVersion,
37749
37940
  preactMajorVersion: parseReactMajor(preactVersion),
@@ -37977,7 +38168,6 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
37977
38168
  "react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
37978
38169
  "react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
37979
38170
  "react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
37980
- "react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
37981
38171
  "react/jsx-no-undef": "react-doctor/jsx-no-undef",
37982
38172
  "react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
37983
38173
  "react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
@@ -40299,9 +40489,25 @@ const BABEL_CONFIG_FILE_NAMES = [
40299
40489
  ".babelrc.json"
40300
40490
  ];
40301
40491
  const LEGACY_PRESET_SPEC = "module:metro-react-native-babel-preset";
40492
+ const LEGACY_PRESET_PACKAGE = "metro-react-native-babel-preset";
40493
+ const REACT_NATIVE_PACKAGE = "react-native";
40494
+ const PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION = "0.73.0";
40495
+ const LEGACY_PRESET_REFERENCE = new RegExp(`['"]${LEGACY_PRESET_SPEC}['"]`);
40302
40496
  const MODERN_PRESET_REFERENCE = new RegExp(`['"]module:@react-native/babel-preset['"]`);
40303
40497
  const ENABLE_BABEL_RUNTIME_VERSION = /enableBabelRuntime["']?\s*:\s*['"]/;
40498
+ const isReactNativeVersionAtLeastPresetRename = (rootDirectory, packageJson) => {
40499
+ const installedReactNativeManifestPath = Path.join(rootDirectory, "node_modules", REACT_NATIVE_PACKAGE, "package.json");
40500
+ const reactNativeVersionSpec = (isFile(installedReactNativeManifestPath) ? readPackageJson$1(installedReactNativeManifestPath).version : void 0) ?? getDependencySpec(packageJson, REACT_NATIVE_PACKAGE);
40501
+ if (reactNativeVersionSpec === null || reactNativeVersionSpec === void 0) return false;
40502
+ const normalizedVersionRange = import_semver.validRange(reactNativeVersionSpec);
40503
+ if (normalizedVersionRange === null) return false;
40504
+ const minimumVersion = import_semver.minVersion(normalizedVersionRange);
40505
+ return minimumVersion !== null && import_semver.gte(minimumVersion, PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION);
40506
+ };
40507
+ const canResolveLegacyPreset = (rootDirectory, packageJson) => getDependencySpec(packageJson, LEGACY_PRESET_PACKAGE) !== null || isFile(Path.join(rootDirectory, "node_modules", LEGACY_PRESET_PACKAGE, "package.json"));
40304
40508
  const checkReactNativeMetroBabelPreset = (rootDirectory) => {
40509
+ const packageJson = readPackageJson$1(Path.join(rootDirectory, "package.json"));
40510
+ const shouldReportLegacyPreset = isReactNativeVersionAtLeastPresetRename(rootDirectory, packageJson) && !canResolveLegacyPreset(rootDirectory, packageJson);
40305
40511
  for (const fileName of BABEL_CONFIG_FILE_NAMES) {
40306
40512
  const filePath = Path.join(rootDirectory, fileName);
40307
40513
  if (!isFile(filePath)) continue;
@@ -40311,7 +40517,7 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
40311
40517
  } catch {
40312
40518
  continue;
40313
40519
  }
40314
- if (contents.includes(LEGACY_PRESET_SPEC)) return [buildReactNativeDiagnostic({
40520
+ if (shouldReportLegacyPreset && LEGACY_PRESET_REFERENCE.test(contents)) return [buildReactNativeDiagnostic({
40315
40521
  filePath: fileName,
40316
40522
  rule: "rn-no-metro-babel-preset",
40317
40523
  severity: "error",
@@ -40334,12 +40540,6 @@ const checkReactNativeProject = (rootDirectory, project) => {
40334
40540
  return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
40335
40541
  };
40336
40542
  const RULE_KEY = "no-vulnerable-react-server-components";
40337
- const DEPENDENCY_SECTIONS = [
40338
- "dependencies",
40339
- "devDependencies",
40340
- "peerDependencies",
40341
- "optionalDependencies"
40342
- ];
40343
40543
  const REACT_RSC_ADVISORIES_BY_MINOR = {
40344
40544
  "19.0": {
40345
40545
  rceFixedVersion: "19.0.1",
@@ -40386,20 +40586,13 @@ const enumerateWorkspaceDirectories = (workspaceRoot) => {
40386
40586
  for (const pattern of patterns) for (const directory of resolveWorkspaceDirectories(workspaceRoot, pattern)) directories.add(directory);
40387
40587
  return [...directories];
40388
40588
  };
40389
- const readDeclaredSpec = (packageJson, packageName) => {
40390
- for (const section of DEPENDENCY_SECTIONS) {
40391
- const spec = packageJson[section]?.[packageName];
40392
- if (typeof spec === "string") return spec;
40393
- }
40394
- return null;
40395
- };
40396
40589
  const resolveVersionInDirectory = (directory, packageName, declaredSpecOverride) => {
40397
40590
  const manifestPath = Path.join(directory, "node_modules", packageName, "package.json");
40398
40591
  if (isFile(manifestPath)) {
40399
40592
  const installedVersion = import_semver.valid(readPackageJson$1(manifestPath).version ?? null);
40400
40593
  if (installedVersion !== null) return installedVersion;
40401
40594
  }
40402
- const candidateSpecs = [readDeclaredSpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
40595
+ const candidateSpecs = [getDependencySpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
40403
40596
  for (const spec of candidateSpecs) {
40404
40597
  const pinnedVersion = spec === null ? null : import_semver.valid(spec);
40405
40598
  if (pinnedVersion !== null) return pinnedVersion;
@@ -41067,6 +41260,7 @@ const buildCapabilities = (project) => {
41067
41260
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
41068
41261
  if (project.isStaticExport) capabilities.add("nextjs:static-export");
41069
41262
  if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
41263
+ if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
41070
41264
  addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
41071
41265
  if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
41072
41266
  major: 19,
@@ -41079,9 +41273,30 @@ const buildCapabilities = (project) => {
41079
41273
  })) capabilities.add("tailwind:3.4");
41080
41274
  if (project.zodVersion !== null) capabilities.add("zod");
41081
41275
  if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
41276
+ if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
41277
+ if (project.hasMobxReact === true) capabilities.add("mobx-react");
41278
+ if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
41279
+ if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
41280
+ if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
41281
+ if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
41282
+ if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addMajorLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
41283
+ if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
41284
+ if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addMajorLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
41082
41285
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
41083
41286
  if (project.hasReactCompiler) capabilities.add("react-compiler");
41084
- if (project.hasTanStackQuery) capabilities.add("tanstack-query");
41287
+ if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
41288
+ if (project.styledComponentsVersion) {
41289
+ capabilities.add("styled-components");
41290
+ const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
41291
+ if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
41292
+ }
41293
+ if (project.hasI18nLibrary) capabilities.add("i18n");
41294
+ if (project.valtioVersion !== null) capabilities.add("valtio");
41295
+ addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
41296
+ if (project.hasRemotion) {
41297
+ capabilities.add("remotion");
41298
+ addMajorLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
41299
+ }
41085
41300
  if (project.hasTypeScript) capabilities.add("typescript");
41086
41301
  if (project.preactVersion !== null) capabilities.add("preact");
41087
41302
  addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
@@ -43366,6 +43581,19 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
43366
43581
  }
43367
43582
  };
43368
43583
  };
43584
+ const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
43585
+ const fingerprintFileContents = (filePath, fingerprintLength) => {
43586
+ const fileStats = NFS.statSync(filePath, { bigint: true });
43587
+ const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
43588
+ if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
43589
+ const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
43590
+ fingerprintCacheByFilePath.set(filePath, {
43591
+ fingerprint,
43592
+ modifiedTimeNanoseconds: fileStats.mtimeNs,
43593
+ sizeBytes: fileStats.size
43594
+ });
43595
+ return fingerprint;
43596
+ };
43369
43597
  const bundledRequire$3 = createRequire(import.meta.url);
43370
43598
  const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
43371
43599
  const resolveChildNodeVersion = (nodeBinaryPath) => {
@@ -43389,6 +43617,13 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS$1 = [
43389
43617
  "oxlint-plugin-react-doctor/package.json",
43390
43618
  "eslint-plugin-react-hooks/package.json"
43391
43619
  ];
43620
+ const resolvePluginFingerprint = () => {
43621
+ try {
43622
+ return fingerprintFileContents(bundledRequire$3.resolve("oxlint-plugin-react-doctor"), 16);
43623
+ } catch {
43624
+ return "unresolved";
43625
+ }
43626
+ };
43392
43627
  const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43393
43628
  const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
43394
43629
  for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS$1) try {
@@ -43398,6 +43633,7 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43398
43633
  } catch {
43399
43634
  versions.push(`${specifier}=missing`);
43400
43635
  }
43636
+ versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
43401
43637
  return versions;
43402
43638
  };
43403
43639
  const esmRequire = createRequire(import.meta.url);
@@ -44091,12 +44327,17 @@ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown
44091
44327
  const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
44092
44328
  const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
44093
44329
  const REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION = "It's how the library works, not a bug in your code. Memoize values you pass from it into other memoized components, or suppress it with `// react-doctor-disable-next-line react-hooks-js/incompatible-library`.";
44330
+ const SET_STATE_IN_EFFECT_ACTION = "Prefer deriving or initializing the value before render. If the effect must read a browser API after mount, treat this as advisory or suppress it with `// react-doctor-disable-next-line react-hooks-js/set-state-in-effect`.";
44094
44331
  const REACT_COMPILER_GENERIC_MESSAGE = `${REACT_COMPILER_IMPACT}. ${REACT_COMPILER_ACTION}`;
44095
44332
  const buildReactCompilerMessage = (reasonSummary, action = REACT_COMPILER_ACTION) => {
44096
44333
  const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
44097
44334
  if (!normalizedSummary) return `${REACT_COMPILER_IMPACT}. ${action}`;
44098
44335
  return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${action}`;
44099
44336
  };
44337
+ const buildSetStateInEffectMessage = (reasonSummary) => {
44338
+ const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
44339
+ return `This synchronous effect update causes an extra render${normalizedSummary ? `: ${normalizedSummary}` : ""}. ${SET_STATE_IN_EFFECT_ACTION}`;
44340
+ };
44100
44341
  const PLUGIN_CATEGORY_MAP = {
44101
44342
  react: "Bugs",
44102
44343
  "react-hooks": "Bugs",
@@ -44154,6 +44395,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
44154
44395
  message: REACT_ERROR_BOUNDARY_MESSAGE,
44155
44396
  help: reasonDetail || help
44156
44397
  };
44398
+ if (rule === "set-state-in-effect") return {
44399
+ message: buildSetStateInEffectMessage(reasonSummary.trim()),
44400
+ help: reasonDetail || help
44401
+ };
44157
44402
  return {
44158
44403
  message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
44159
44404
  help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
@@ -47356,7 +47601,7 @@ const makeNoopConsole = () => ({
47356
47601
  });
47357
47602
  //#endregion
47358
47603
  //#region src/cli/utils/version.ts
47359
- const VERSION = "0.8.1-dev.c9f2c4b";
47604
+ const VERSION = "0.8.1-dev.cd9ca68";
47360
47605
  //#endregion
47361
47606
  //#region src/cli/utils/json-mode.ts
47362
47607
  let context = null;
@@ -47527,7 +47772,9 @@ const buildSentryProjectContext = (projectInfo) => ({
47527
47772
  reactMajorVersion: projectInfo.reactMajorVersion,
47528
47773
  hasTypeScript: projectInfo.hasTypeScript,
47529
47774
  hasReactCompiler: projectInfo.hasReactCompiler,
47530
- hasTanStackQuery: projectInfo.hasTanStackQuery,
47775
+ tanstackQueryVersion: projectInfo.tanstackQueryVersion,
47776
+ mobxVersion: projectInfo.mobxVersion,
47777
+ styledComponentsVersion: projectInfo.styledComponentsVersion,
47531
47778
  tailwindVersion: projectInfo.tailwindVersion,
47532
47779
  zodVersion: projectInfo.zodVersion,
47533
47780
  preactVersion: projectInfo.preactVersion,
@@ -47708,13 +47955,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47708
47955
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47709
47956
  * standard `SENTRY_RELEASE` override.
47710
47957
  */
47711
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.c9f2c4b`;
47958
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.cd9ca68`;
47712
47959
  /**
47713
47960
  * Deployment environment shown in Sentry's environment filter. Defaults to
47714
47961
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47715
47962
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47716
47963
  */
47717
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.c9f2c4b") ? "development" : "production");
47964
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.cd9ca68") ? "development" : "production");
47718
47965
  /**
47719
47966
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47720
47967
  * (set to `0` to disable tracing) and falls back to
@@ -66394,4 +66641,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
66394
66641
  export {};
66395
66642
 
66396
66643
  //# sourceMappingURL=cli.js.map
66397
- //# debugId=c24708ed-97a3-59cc-81f7-4cf277ab29f2
66644
+ //# debugId=434800fc-200b-5a59-aa25-61e682ab57d7
package/dist/index.d.ts CHANGED
@@ -9543,11 +9543,38 @@ interface ProjectInfo {
9543
9543
  zodVersion: string | null;
9544
9544
  /** Parsed major from `zodVersion`, or `null` when absent/unparseable. Mirrors `reactMajorVersion`. */
9545
9545
  zodMajorVersion: number | null;
9546
+ /** Declared MobX core version spec. Optional so existing `ProjectInfo` consumers remain source-compatible. */
9547
+ mobxVersion?: string | null;
9548
+ /** Parsed major from `mobxVersion`, or `null` when absent/unparseable. */
9549
+ mobxMajorVersion?: number | null;
9550
+ hasMobxReact?: boolean;
9551
+ hasMobxReactLite?: boolean;
9552
+ hasMobxStateTree?: boolean;
9553
+ hasMobxReactObserver?: boolean;
9554
+ /** Declared Zustand version spec. Optional so existing `ProjectInfo` consumers remain source-compatible. */
9555
+ zustandVersion?: string | null;
9556
+ /** Parsed major from `zustandVersion`, or `null` when absent/unparseable. */
9557
+ zustandMajorVersion?: number | null;
9546
9558
  framework: Framework;
9547
9559
  hasTypeScript: boolean;
9548
9560
  hasReactCompiler: boolean;
9549
9561
  hasReactCompilerLintPlugin?: boolean;
9550
9562
  hasTanStackQuery: boolean;
9563
+ hasRemotion?: boolean;
9564
+ remotionVersion?: string | null;
9565
+ remotionMajorVersion?: number | null;
9566
+ hasI18nLibrary?: boolean;
9567
+ tanstackQueryVersion?: string | null;
9568
+ styledComponentsVersion?: string | null;
9569
+ /**
9570
+ * The declared `valtio` version spec, or `null` when no package in the
9571
+ * analyzed project declares Valtio. `useSnapshot` has kept the same
9572
+ * render-read contract across Valtio 1 and 2, so presence alone drives the
9573
+ * `valtio` capability and its parsed major-version ladder.
9574
+ */
9575
+ valtioVersion: string | null;
9576
+ /** Parsed major from `valtioVersion`, or `null` when absent/unparseable. */
9577
+ valtioMajorVersion: number | null;
9551
9578
  /**
9552
9579
  * `true` when the project or a workspace declares a Vite-based SSR runtime
9553
9580
  * such as React Router's Node adapter, Vike, or vite-plugin-ssr.