react-doctor 0.8.1-dev.e6a1557 → 0.8.1-dev.f5f13b8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6aa1c6e1-8fcc-50d4-a076-3e864425bdc5")}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]="c65f1825-0401-518f-840a-c33df84ebafc")}catch(e){}}();
3
3
  import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
@@ -32854,44 +32854,6 @@ var AmbiguousProjectError = class extends Error {
32854
32854
  }
32855
32855
  };
32856
32856
  const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
32857
- const isErrnoException = (error) => error instanceof Error && "code" in error;
32858
- const IGNORABLE_READDIR_ERROR_CODES = new Set([
32859
- "EACCES",
32860
- "EPERM",
32861
- "ENOENT",
32862
- "ENOTDIR",
32863
- "EINVAL",
32864
- "ELOOP",
32865
- "ENAMETOOLONG"
32866
- ]);
32867
- const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
32868
- const readDirectoryEntries = (directoryPath) => {
32869
- try {
32870
- return NFS.readdirSync(directoryPath, { withFileTypes: true });
32871
- } catch (error) {
32872
- if (isIgnorableReaddirError(error)) return [];
32873
- throw error;
32874
- }
32875
- };
32876
- const isFile = (filePath) => {
32877
- try {
32878
- return NFS.statSync(filePath).isFile();
32879
- } catch {
32880
- return false;
32881
- }
32882
- };
32883
- const isDirectory = (directoryPath) => {
32884
- try {
32885
- return NFS.statSync(directoryPath).isDirectory();
32886
- } catch {
32887
- return false;
32888
- }
32889
- };
32890
- const isPlainObject = (value) => {
32891
- if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
32892
- const prototype = Object.getPrototypeOf(value);
32893
- return prototype === null || prototype === Object.prototype;
32894
- };
32895
32857
  const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
32896
32858
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
32897
32859
  const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
@@ -32932,6 +32894,58 @@ const IGNORED_DIRECTORIES = new Set([
32932
32894
  "storybook-static"
32933
32895
  ]);
32934
32896
  const MILLISECONDS_PER_SECOND = 1e3;
32897
+ const REACT_ROUTER_CAPABILITY_THRESHOLDS = [
32898
+ {
32899
+ capability: "react-router:6.4",
32900
+ major: 6,
32901
+ minor: 4
32902
+ },
32903
+ {
32904
+ capability: "react-router:6.7",
32905
+ major: 6,
32906
+ minor: 7
32907
+ },
32908
+ {
32909
+ capability: "react-router:6.9",
32910
+ major: 6,
32911
+ minor: 9
32912
+ },
32913
+ {
32914
+ capability: "react-router:6.19",
32915
+ major: 6,
32916
+ minor: 19
32917
+ },
32918
+ {
32919
+ capability: "react-router:7",
32920
+ major: 7,
32921
+ minor: 0
32922
+ },
32923
+ {
32924
+ capability: "react-router:7.8",
32925
+ major: 7,
32926
+ minor: 8
32927
+ },
32928
+ {
32929
+ capability: "react-router:7.9",
32930
+ major: 7,
32931
+ minor: 9
32932
+ },
32933
+ {
32934
+ capability: "react-router:7.10",
32935
+ major: 7,
32936
+ minor: 10
32937
+ },
32938
+ {
32939
+ capability: "react-router:7.15",
32940
+ major: 7,
32941
+ minor: 15
32942
+ },
32943
+ {
32944
+ capability: "react-router:8",
32945
+ major: 8,
32946
+ minor: 0
32947
+ }
32948
+ ];
32935
32949
  const SCORE_API_URL = "https://www.react.doctor/api/score";
32936
32950
  const FETCH_TIMEOUT_MS = 1e4;
32937
32951
  const GITHUB_VIEWER_PERMISSION_TIMEOUT_MS = 2e3;
@@ -33050,6 +33064,44 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
33050
33064
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
33051
33065
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
33052
33066
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
33067
+ const isErrnoException = (error) => error instanceof Error && "code" in error;
33068
+ const IGNORABLE_READDIR_ERROR_CODES = new Set([
33069
+ "EACCES",
33070
+ "EPERM",
33071
+ "ENOENT",
33072
+ "ENOTDIR",
33073
+ "EINVAL",
33074
+ "ELOOP",
33075
+ "ENAMETOOLONG"
33076
+ ]);
33077
+ const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
33078
+ const readDirectoryEntries = (directoryPath) => {
33079
+ try {
33080
+ return NFS.readdirSync(directoryPath, { withFileTypes: true });
33081
+ } catch (error) {
33082
+ if (isIgnorableReaddirError(error)) return [];
33083
+ throw error;
33084
+ }
33085
+ };
33086
+ const isFile = (filePath) => {
33087
+ try {
33088
+ return NFS.statSync(filePath).isFile();
33089
+ } catch {
33090
+ return false;
33091
+ }
33092
+ };
33093
+ const isDirectory = (directoryPath) => {
33094
+ try {
33095
+ return NFS.statSync(directoryPath).isDirectory();
33096
+ } catch {
33097
+ return false;
33098
+ }
33099
+ };
33100
+ const isPlainObject = (value) => {
33101
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
33102
+ const prototype = Object.getPrototypeOf(value);
33103
+ return prototype === null || prototype === Object.prototype;
33104
+ };
33053
33105
  const lastSourceMappingUrl = (fileContent) => {
33054
33106
  const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
33055
33107
  return lastReference ? lastReference[1] : null;
@@ -33375,10 +33427,10 @@ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"]
33375
33427
  const FRAMEWORK_PACKAGES = {
33376
33428
  next: "nextjs",
33377
33429
  "@tanstack/react-start": "tanstack-start",
33378
- vite: "vite",
33379
- "react-scripts": "cra",
33380
33430
  "@remix-run/react": "remix",
33381
33431
  gatsby: "gatsby",
33432
+ vite: "vite",
33433
+ "react-scripts": "cra",
33382
33434
  expo: "expo",
33383
33435
  "react-native": "react-native"
33384
33436
  };
@@ -33402,11 +33454,17 @@ const NEXT_CONFIG_FILENAMES = [
33402
33454
  ];
33403
33455
  const BABEL_CONFIG_FILENAMES = [
33404
33456
  ".babelrc",
33457
+ ".babelrc.js",
33405
33458
  ".babelrc.json",
33459
+ ".babelrc.cjs",
33460
+ ".babelrc.mjs",
33461
+ ".babelrc.cts",
33406
33462
  "babel.config.js",
33407
33463
  "babel.config.json",
33408
33464
  "babel.config.cjs",
33409
- "babel.config.mjs"
33465
+ "babel.config.mjs",
33466
+ "babel.config.ts",
33467
+ "babel.config.cts"
33410
33468
  ];
33411
33469
  const VITE_CONFIG_FILENAMES = [
33412
33470
  "vite.config.js",
@@ -33418,12 +33476,28 @@ const VITE_CONFIG_FILENAMES = [
33418
33476
  "vitest.config.ts",
33419
33477
  "vitest.config.js"
33420
33478
  ];
33479
+ const RSBUILD_CONFIG_FILENAMES = [
33480
+ "rsbuild.config.ts",
33481
+ "rsbuild.config.js",
33482
+ "rsbuild.config.mts",
33483
+ "rsbuild.config.mjs",
33484
+ "rsbuild.config.cts",
33485
+ "rsbuild.config.cjs"
33486
+ ];
33487
+ const RSPACK_CONFIG_FILENAMES = [
33488
+ "rspack.config.ts",
33489
+ "rspack.config.js",
33490
+ "rspack.config.mts",
33491
+ "rspack.config.mjs",
33492
+ "rspack.config.cts",
33493
+ "rspack.config.cjs"
33494
+ ];
33421
33495
  const EXPO_APP_CONFIG_FILENAMES = [
33422
33496
  "app.json",
33423
33497
  "app.config.js",
33424
33498
  "app.config.ts"
33425
33499
  ];
33426
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
33500
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|reactCompilerPreset\s*\(|["']react-compiler["']/;
33427
33501
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
33428
33502
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
33429
33503
  const hasCompilerPackage = (packageJson, compilerPackages) => {
@@ -33458,6 +33532,8 @@ const detectReactCompiler = (directory, packageJson) => {
33458
33532
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
33459
33533
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
33460
33534
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
33535
+ if (hasCompilerInConfigFiles(directory, RSBUILD_CONFIG_FILENAMES)) return true;
33536
+ if (hasCompilerInConfigFiles(directory, RSPACK_CONFIG_FILENAMES)) return true;
33461
33537
  if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
33462
33538
  return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
33463
33539
  };
@@ -33466,7 +33542,7 @@ const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((file
33466
33542
  const filePath = Path.join(directory, filename);
33467
33543
  return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
33468
33544
  });
33469
- const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:file|git|github|https?|link|patch|portal|workspace|npm):/i;
33545
+ const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:catalog|file|git|github|https?|link|patch|portal|workspace|npm):/i;
33470
33546
  const DIST_TAG_VERSION = /^[a-z][a-z0-9._-]*$/i;
33471
33547
  const WILDCARD_VERSION = /^[*xX](?:\.[*xX])*$/;
33472
33548
  const NPM_ALIAS_VERSION = /^npm:(?:@[^/]+\/[^@]+|[^@]+)@(.+)$/i;
@@ -33599,6 +33675,16 @@ const getLowestDependencyMajor = (version) => {
33599
33675
  }
33600
33676
  return lowestMajor;
33601
33677
  };
33678
+ const getDependencyMajorWithinSupportedRange = (version, latestSupportedMajor) => {
33679
+ const normalizedVersion = normalizeDependencyVersion(version);
33680
+ if (normalizedVersion === null) return null;
33681
+ const validRange = import_semver.validRange(normalizedVersion);
33682
+ if (validRange === null) return null;
33683
+ const minimumVersion = import_semver.minVersion(validRange);
33684
+ if (minimumVersion === null || minimumVersion.major > latestSupportedMajor) return null;
33685
+ if (import_semver.intersects(validRange, `>=${latestSupportedMajor + 1}.0.0`)) return null;
33686
+ return minimumVersion.major;
33687
+ };
33602
33688
  const isConcreteDependencyVersion = (version) => {
33603
33689
  const normalizedVersion = normalizeDependencyVersion(version);
33604
33690
  return normalizedVersion !== null && /\d/.test(normalizedVersion);
@@ -33642,9 +33728,18 @@ const parseReactMajorMinor = (reactVersion) => {
33642
33728
  };
33643
33729
  };
33644
33730
  const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
33645
- const parseTailwindMajorMinor = (tailwindVersion) => {
33646
- if (typeof tailwindVersion !== "string") return null;
33647
- const trimmed = tailwindVersion.trim();
33731
+ const parseThreeRelease = (threeVersion) => {
33732
+ if (typeof threeVersion !== "string") return null;
33733
+ const normalizedVersion = normalizeDependencyVersion(threeVersion);
33734
+ if (normalizedVersion === null) return null;
33735
+ const lowerBound = parseLowerBoundVersion(normalizedVersion);
33736
+ if (lowerBound === null) return null;
33737
+ if (lowerBound.major > 0) return Number.MAX_SAFE_INTEGER;
33738
+ return lowerBound.minor > 0 ? lowerBound.minor : null;
33739
+ };
33740
+ const parseDependencyMajorMinor = (dependencyVersion) => {
33741
+ if (typeof dependencyVersion !== "string") return null;
33742
+ const trimmed = dependencyVersion.trim();
33648
33743
  if (trimmed.length === 0) return null;
33649
33744
  const lowerBound = parseLowerBoundVersion(trimmed);
33650
33745
  if (lowerBound === null || lowerBound.major <= 0) return null;
@@ -33653,6 +33748,7 @@ const parseTailwindMajorMinor = (tailwindVersion) => {
33653
33748
  minor: lowerBound.minor
33654
33749
  };
33655
33750
  };
33751
+ const parseTailwindMajorMinor = (tailwindVersion) => parseDependencyMajorMinor(tailwindVersion);
33656
33752
  const hasUpperBoundOnlyPeerRange = (range) => {
33657
33753
  if (typeof range !== "string") return false;
33658
33754
  const normalizedRange = normalizeDependencyVersion(range);
@@ -33674,7 +33770,7 @@ const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
33674
33770
  if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
33675
33771
  return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
33676
33772
  };
33677
- const isCatalogReference = (version) => version.startsWith("catalog:");
33773
+ const isCatalogReference = (version) => typeof version === "string" && version.startsWith("catalog:");
33678
33774
  const extractCatalogName = (version) => {
33679
33775
  if (!isCatalogReference(version)) return null;
33680
33776
  const name = version.slice(8).trim();
@@ -33824,6 +33920,12 @@ const TAILWIND_ZOD_SECTIONS = [
33824
33920
  "devDependencies",
33825
33921
  "peerDependencies"
33826
33922
  ];
33923
+ const DEPENDENCY_SPEC_SECTIONS = [
33924
+ "dependencies",
33925
+ "devDependencies",
33926
+ "peerDependencies",
33927
+ "optionalDependencies"
33928
+ ];
33827
33929
  const EMPTY_DEPENDENCY_INFO = {
33828
33930
  reactVersion: null,
33829
33931
  tailwindVersion: null,
@@ -33833,7 +33935,7 @@ const EMPTY_DEPENDENCY_INFO = {
33833
33935
  const pickConcreteVersion = (packageJson, packageName, sections) => {
33834
33936
  for (const section of sections) {
33835
33937
  const version = packageJson[section]?.[packageName];
33836
- if (version === void 0) continue;
33938
+ if (typeof version !== "string") continue;
33837
33939
  if (isCatalogReference(version)) return null;
33838
33940
  if (isConcreteDependencyVersion(version)) return version;
33839
33941
  }
@@ -33865,13 +33967,16 @@ const extractDependencyInfo = (packageJson) => {
33865
33967
  };
33866
33968
  };
33867
33969
  const getDependencySpec = (packageJson, packageName) => {
33868
- const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
33869
- return typeof spec === "string" ? spec : null;
33970
+ for (const section of DEPENDENCY_SPEC_SECTIONS) {
33971
+ const spec = packageJson[section]?.[packageName];
33972
+ if (typeof spec === "string") return spec;
33973
+ }
33974
+ return null;
33870
33975
  };
33871
33976
  const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
33872
33977
  for (const section of sections) {
33873
33978
  const version = packageJson[section]?.[packageName];
33874
- if (version === void 0) continue;
33979
+ if (typeof version !== "string") continue;
33875
33980
  return {
33876
33981
  catalogReference: extractCatalogName(version) ?? null,
33877
33982
  hasDeclaration: true,
@@ -33905,24 +34010,15 @@ const getPreactVersion = (packageJson) => {
33905
34010
  ...packageJson.devDependencies
33906
34011
  }.preact ?? null;
33907
34012
  };
33908
- const TANSTACK_QUERY_PACKAGES = new Set([
33909
- "@tanstack/react-query",
33910
- "@tanstack/query-core",
33911
- "react-query"
33912
- ]);
33913
- const hasTanStackQuery = (packageJson) => {
33914
- const allDependencies = {
33915
- ...packageJson.peerDependencies,
33916
- ...packageJson.dependencies,
33917
- ...packageJson.devDependencies
33918
- };
33919
- return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
33920
- };
33921
- const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
34013
+ const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, sourceDirectory = rootDirectory, sourcePackageJson = rootPackageJson, version }) => {
33922
34014
  if (version === null || !isCatalogReference(version)) return version;
33923
34015
  const catalogName = extractCatalogName(version);
33924
- const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
33925
- if (resolvedLocalVersion) return resolvedLocalVersion;
34016
+ const resolvedSourceVersion = resolveCatalogVersion(sourcePackageJson, packageName, sourceDirectory, catalogName);
34017
+ if (resolvedSourceVersion) return resolvedSourceVersion;
34018
+ if (sourceDirectory !== rootDirectory || sourcePackageJson !== rootPackageJson) {
34019
+ const resolvedRootVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
34020
+ if (resolvedRootVersion) return resolvedRootVersion;
34021
+ }
33926
34022
  const monorepoRoot = findMonorepoRoot(rootDirectory);
33927
34023
  if (!monorepoRoot) return version;
33928
34024
  const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
@@ -34120,11 +34216,84 @@ const listWorkspacePackages = (rootDirectory) => {
34120
34216
  }
34121
34217
  return packages;
34122
34218
  };
34219
+ const PREFERRED_DEPENDENCY_SECTIONS = [
34220
+ "dependencies",
34221
+ "peerDependencies",
34222
+ "devDependencies"
34223
+ ];
34224
+ const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
34225
+ for (const packageName of packageNames) {
34226
+ const declaration = getDependencyDeclaration({
34227
+ packageJson,
34228
+ packageName,
34229
+ sections: PREFERRED_DEPENDENCY_SECTIONS
34230
+ });
34231
+ if (declaration.version !== null) return declaration.version;
34232
+ }
34233
+ return null;
34234
+ };
34235
+ const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
34236
+ const getTanStackQueryVersion = (packageJson) => {
34237
+ return getPreferredDependencyVersion({
34238
+ packageJson,
34239
+ packageNames: TANSTACK_REACT_QUERY_PACKAGES
34240
+ });
34241
+ };
34242
+ const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
34243
+ const getStyledComponentsVersion = (packageJson) => {
34244
+ return getPreferredDependencyVersion({
34245
+ packageJson,
34246
+ packageNames: STYLED_COMPONENTS_PACKAGES
34247
+ });
34248
+ };
34249
+ const I18N_PACKAGES = [
34250
+ "i18next",
34251
+ "react-i18next",
34252
+ "next-i18next",
34253
+ "react-intl",
34254
+ "next-intl",
34255
+ "use-intl",
34256
+ "@formatjs/intl",
34257
+ "@lingui/core",
34258
+ "@lingui/react",
34259
+ "typesafe-i18n",
34260
+ "@tolgee/react",
34261
+ "react-intl-universal"
34262
+ ];
34263
+ const hasI18nDependency = (packageJson) => {
34264
+ const allDependencies = {
34265
+ ...packageJson.peerDependencies,
34266
+ ...packageJson.dependencies,
34267
+ ...packageJson.devDependencies,
34268
+ ...packageJson.optionalDependencies
34269
+ };
34270
+ return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
34271
+ };
34123
34272
  const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
34124
34273
  const MOBX_REACT_PACKAGE_NAME = "mobx-react";
34125
34274
  const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
34126
34275
  const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
34127
34276
  const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
34277
+ const REACT_THREE_FIBER_DEPENDENCY_NAMES = ["@react-three/fiber", "react-three-fiber"];
34278
+ const REACT_THREE_FIBER_SECTIONS = [
34279
+ "dependencies",
34280
+ "peerDependencies",
34281
+ "optionalDependencies",
34282
+ "devDependencies"
34283
+ ];
34284
+ const THREE_DEPENDENCY_SECTIONS = [
34285
+ "dependencies",
34286
+ "peerDependencies",
34287
+ "optionalDependencies",
34288
+ "devDependencies"
34289
+ ];
34290
+ const REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES = [...REACT_THREE_FIBER_DEPENDENCY_NAMES, "@react-three/drei"];
34291
+ const THREE_DEPENDENCY_NAMES = [...REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES, "three"];
34292
+ const REACT_ROUTER_DEPENDENCY_NAMES = [
34293
+ "@react-router/dev",
34294
+ "react-router-dom",
34295
+ "react-router"
34296
+ ];
34128
34297
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
34129
34298
  const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
34130
34299
  const dependencyDeclaration = getDependencyDeclaration({
@@ -34135,7 +34304,7 @@ const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootD
34135
34304
  if (!dependencyDeclaration.hasDeclaration) return null;
34136
34305
  return concreteVersion ?? resolveCatalogVersion(workspacePackageJson, packageName, workspaceDirectory, dependencyDeclaration.catalogReference) ?? resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, dependencyDeclaration.catalogReference);
34137
34306
  };
34138
- const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
34307
+ const shouldReplaceWithLowerMajor = (currentVersion, nextVersion) => {
34139
34308
  if (!currentVersion) return true;
34140
34309
  const currentMajor = parseReactMajor(currentVersion);
34141
34310
  const nextMajor = parseReactMajor(nextVersion);
@@ -34154,6 +34323,59 @@ const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSuppo
34154
34323
  if (nextMajor > latestSupportedMajor) return true;
34155
34324
  return nextMajor < currentMajor;
34156
34325
  };
34326
+ const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
34327
+ if (!currentVersion) return true;
34328
+ const currentMajor = getLowestDependencyMajor(currentVersion);
34329
+ const nextMajor = getLowestDependencyMajor(nextVersion);
34330
+ if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
34331
+ if (nextMajor === null) return currentMajor >= 6;
34332
+ return nextMajor < currentMajor;
34333
+ };
34334
+ const selectOldestDependencyVersion = (currentVersion, nextVersion) => {
34335
+ if (currentVersion === null || nextVersion === null) return null;
34336
+ const current = parseDependencyMajorMinor(currentVersion);
34337
+ const next = parseDependencyMajorMinor(nextVersion);
34338
+ if (current === null) return currentVersion;
34339
+ if (next === null) return nextVersion;
34340
+ if (next.major !== current.major) return next.major < current.major ? nextVersion : currentVersion;
34341
+ return next.minor < current.minor ? nextVersion : currentVersion;
34342
+ };
34343
+ const shouldReplaceMobxFact = (currentFact, nextFact) => {
34344
+ if (currentFact.sourceDirectory === null) return true;
34345
+ if (currentFact.version === null) return false;
34346
+ if (nextFact.version === null) return true;
34347
+ const currentMajor = getDependencyMajorWithinSupportedRange(currentFact.version, 6);
34348
+ const nextMajor = getDependencyMajorWithinSupportedRange(nextFact.version, 6);
34349
+ if (currentMajor === null) return false;
34350
+ if (nextMajor === null) return true;
34351
+ return selectOldestDependencyVersion(currentFact.version, nextFact.version) === nextFact.version;
34352
+ };
34353
+ const collectBindingVersion = (facts, packageJson, directory, packageName) => {
34354
+ const version = getDependencySpec(packageJson, packageName);
34355
+ if (version === null) return;
34356
+ const resolvedVersion = resolveCatalogBackedDependencyVersion({
34357
+ rootDirectory: directory,
34358
+ rootPackageJson: packageJson,
34359
+ packageName,
34360
+ version
34361
+ });
34362
+ if (packageName === MOBX_REACT_PACKAGE_NAME) {
34363
+ facts.mobxReactVersion = facts.hasMobxReact ? selectOldestDependencyVersion(facts.mobxReactVersion, resolvedVersion) : resolvedVersion;
34364
+ facts.hasMobxReact = true;
34365
+ return;
34366
+ }
34367
+ facts.mobxReactLiteVersion = facts.hasMobxReactLite ? selectOldestDependencyVersion(facts.mobxReactLiteVersion, resolvedVersion) : resolvedVersion;
34368
+ facts.hasMobxReactLite = true;
34369
+ };
34370
+ const shouldReplaceReactRouterVersion = (currentVersion, nextVersion) => {
34371
+ if (currentVersion === null) return true;
34372
+ const current = parseReactMajorMinor(currentVersion);
34373
+ const next = parseReactMajorMinor(nextVersion);
34374
+ if (current === null) return next !== null;
34375
+ if (next === null) return false;
34376
+ if (next.major !== current.major) return next.major < current.major;
34377
+ return next.minor < current.minor;
34378
+ };
34157
34379
  const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
34158
34380
  if (facts.expo.version === null) {
34159
34381
  const spec = getDependencySpec(packageJson, "expo");
@@ -34169,6 +34391,23 @@ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, roo
34169
34391
  sourceDirectory: directory
34170
34392
  };
34171
34393
  }
34394
+ for (const packageName of REACT_ROUTER_DEPENDENCY_NAMES) {
34395
+ const resolvedSpec = resolveCatalogBackedDependencyVersion({
34396
+ rootDirectory,
34397
+ rootPackageJson,
34398
+ sourceDirectory: directory,
34399
+ sourcePackageJson: packageJson,
34400
+ packageName,
34401
+ version: getDependencySpec(packageJson, packageName)
34402
+ });
34403
+ if (resolvedSpec === null || !shouldReplaceReactRouterVersion(facts.reactRouter.version, resolvedSpec)) continue;
34404
+ facts.reactRouter = {
34405
+ version: resolvedSpec,
34406
+ sourceDirectory: directory,
34407
+ packageName
34408
+ };
34409
+ }
34410
+ facts.hasReactRouterFramework = facts.hasReactRouterFramework || getDependencySpec(packageJson, "@react-router/dev") !== null;
34172
34411
  if (facts.shopifyFlashList.version === null) {
34173
34412
  const spec = getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME);
34174
34413
  if (spec !== null) facts.shopifyFlashList = {
@@ -34187,10 +34426,10 @@ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, roo
34187
34426
  }),
34188
34427
  sourceDirectory: directory
34189
34428
  };
34190
- if (shouldReplaceSupportedDependencyFact(facts.mobx, nextMobxFact, 6)) facts.mobx = nextMobxFact;
34429
+ if (shouldReplaceMobxFact(facts.mobx, nextMobxFact)) facts.mobx = nextMobxFact;
34191
34430
  }
34192
- facts.hasMobxReact = facts.hasMobxReact || getDependencySpec(packageJson, MOBX_REACT_PACKAGE_NAME) !== null;
34193
- facts.hasMobxReactLite = facts.hasMobxReactLite || getDependencySpec(packageJson, MOBX_REACT_LITE_PACKAGE_NAME) !== null;
34431
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_PACKAGE_NAME);
34432
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_LITE_PACKAGE_NAME);
34194
34433
  facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
34195
34434
  facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
34196
34435
  const zustandSpec = getDependencySpec(packageJson, "zustand");
@@ -34214,6 +34453,52 @@ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, roo
34214
34453
  const spec = getDependencySpec(packageJson, "valtio");
34215
34454
  if (spec !== null) facts.valtioVersion = spec;
34216
34455
  }
34456
+ facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
34457
+ const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
34458
+ rootDirectory: directory,
34459
+ rootPackageJson: packageJson,
34460
+ packageName: "styled-components",
34461
+ version: getStyledComponentsVersion(packageJson)
34462
+ });
34463
+ if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
34464
+ facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
34465
+ for (const packageName of REACT_THREE_FIBER_DEPENDENCY_NAMES) {
34466
+ const version = resolveCatalogBackedDependencyVersion({
34467
+ rootDirectory,
34468
+ rootPackageJson,
34469
+ sourceDirectory: directory,
34470
+ sourcePackageJson: packageJson,
34471
+ packageName,
34472
+ version: getDependencyDeclaration({
34473
+ packageName,
34474
+ packageJson,
34475
+ sections: REACT_THREE_FIBER_SECTIONS
34476
+ }).version
34477
+ });
34478
+ if (version === null) continue;
34479
+ if (shouldReplaceWithLowerMajor(facts.reactThreeFiber.version, version)) facts.reactThreeFiber = {
34480
+ packageName,
34481
+ version,
34482
+ sourceDirectory: directory
34483
+ };
34484
+ }
34485
+ const threeVersion = resolveCatalogBackedDependencyVersion({
34486
+ rootDirectory,
34487
+ rootPackageJson,
34488
+ sourceDirectory: directory,
34489
+ sourcePackageJson: packageJson,
34490
+ packageName: "three",
34491
+ version: getDependencyDeclaration({
34492
+ packageName: "three",
34493
+ packageJson,
34494
+ sections: THREE_DEPENDENCY_SECTIONS
34495
+ }).version
34496
+ });
34497
+ if (threeVersion !== null) {
34498
+ const currentRelease = parseThreeRelease(facts.threeVersion);
34499
+ const nextRelease = parseThreeRelease(threeVersion);
34500
+ if (facts.threeVersion === null || nextRelease !== null && (currentRelease === null || nextRelease < currentRelease)) facts.threeVersion = threeVersion;
34501
+ }
34217
34502
  facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
34218
34503
  facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
34219
34504
  facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
@@ -34235,6 +34520,8 @@ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, roo
34235
34520
  if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
34236
34521
  }
34237
34522
  }
34523
+ facts.hasThree = facts.hasThree || THREE_DEPENDENCY_NAMES.some((dependencyName) => getDependencySpec(packageJson, dependencyName) !== null);
34524
+ facts.hasReactThreeFiber = facts.hasReactThreeFiber || REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES.some((dependencyName) => getDependencySpec(packageJson, dependencyName) !== null);
34238
34525
  };
34239
34526
  const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
34240
34527
  const facts = {
@@ -34250,6 +34537,11 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
34250
34537
  version: null,
34251
34538
  sourceDirectory: null
34252
34539
  },
34540
+ reactRouter: {
34541
+ version: null,
34542
+ sourceDirectory: null,
34543
+ packageName: null
34544
+ },
34253
34545
  shopifyFlashList: {
34254
34546
  version: null,
34255
34547
  sourceDirectory: null
@@ -34260,26 +34552,40 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
34260
34552
  sourceDirectory: null
34261
34553
  },
34262
34554
  hasMobxReact: false,
34555
+ mobxReactVersion: null,
34263
34556
  hasMobxReactLite: false,
34557
+ mobxReactLiteVersion: null,
34264
34558
  hasMobxStateTree: false,
34265
34559
  hasMobxReactObserver: false,
34266
34560
  zustand: {
34267
34561
  version: null,
34268
34562
  sourceDirectory: null
34269
34563
  },
34564
+ tanstackQueryVersion: null,
34565
+ styledComponentsVersion: null,
34566
+ hasI18nLibrary: false,
34270
34567
  hasReactNativeAwarePackage: false,
34271
34568
  hasReanimatedAwarePackage: false,
34272
34569
  hasSsrDependency: false,
34273
34570
  hasRemotionDependency: false,
34274
34571
  hasUnknownRemotionVersion: false,
34275
34572
  remotionVersion: null,
34573
+ hasThree: false,
34574
+ threeVersion: null,
34575
+ hasReactThreeFiber: false,
34576
+ reactThreeFiber: {
34577
+ packageName: null,
34578
+ version: null,
34579
+ sourceDirectory: null
34580
+ },
34581
+ hasReactRouterFramework: false,
34276
34582
  reanimatedVersion: null
34277
34583
  };
34278
34584
  evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
34279
34585
  let isReactGroupSettled = !collectReactGroup;
34280
34586
  const visitedDirectories = /* @__PURE__ */ new Set();
34281
34587
  for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
34282
- const directories = [...resolveWorkspaceDirectories(rootDirectory, pattern)].sort();
34588
+ const directories = resolveWorkspaceDirectories(rootDirectory, pattern).toSorted();
34283
34589
  for (const workspaceDirectory of directories) {
34284
34590
  if (visitedDirectories.has(workspaceDirectory)) continue;
34285
34591
  visitedDirectories.add(workspaceDirectory);
@@ -34315,7 +34621,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
34315
34621
  workspaceDirectory,
34316
34622
  workspacePackageJson
34317
34623
  });
34318
- if (reactVersion && shouldReplaceReactVersion(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
34624
+ if (reactVersion && shouldReplaceWithLowerMajor(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
34319
34625
  if (tailwindVersion && !facts.tailwindVersion) facts.tailwindVersion = tailwindVersion;
34320
34626
  if (zodVersion && !facts.zodVersion) facts.zodVersion = zodVersion;
34321
34627
  const settledReactMajor = parseReactMajor(facts.reactVersion);
@@ -34511,7 +34817,9 @@ const discoverProjectWithoutPackageJson = (directory) => {
34511
34817
  mobxVersion: null,
34512
34818
  mobxMajorVersion: null,
34513
34819
  hasMobxReact: false,
34820
+ mobxReactVersion: null,
34514
34821
  hasMobxReactLite: false,
34822
+ mobxReactLiteVersion: null,
34515
34823
  hasMobxStateTree: false,
34516
34824
  hasMobxReactObserver: false,
34517
34825
  zustandVersion: null,
@@ -34526,12 +34834,23 @@ const discoverProjectWithoutPackageJson = (directory) => {
34526
34834
  hasRemotion: false,
34527
34835
  remotionVersion: null,
34528
34836
  remotionMajorVersion: null,
34837
+ hasI18nLibrary: false,
34838
+ tanstackQueryVersion: null,
34839
+ styledComponentsVersion: null,
34840
+ hasThree: false,
34841
+ threeVersion: null,
34842
+ threeRelease: null,
34843
+ hasReactThreeFiber: false,
34844
+ reactThreeFiberVersion: null,
34845
+ reactThreeFiberMajorVersion: null,
34529
34846
  hasSsrDependency: false,
34530
34847
  preactVersion: null,
34531
34848
  preactMajorVersion: null,
34532
34849
  hasReactNativeWorkspace: false,
34533
34850
  nextjsVersion: null,
34534
34851
  nextjsMajorVersion: null,
34852
+ reactRouterVersion: null,
34853
+ hasReactRouterFramework: false,
34535
34854
  expoVersion: null,
34536
34855
  shopifyFlashListVersion: null,
34537
34856
  shopifyFlashListMajorVersion: null,
@@ -34650,8 +34969,27 @@ const discoverProject = (directory) => {
34650
34969
  packageName: "mobx",
34651
34970
  version: workspaceFacts.mobx.version
34652
34971
  });
34972
+ const reactRouterVersion = workspaceFacts.reactRouter.packageName === null ? null : resolveCatalogBackedDependencyVersion({
34973
+ rootDirectory: directory,
34974
+ rootPackageJson: packageJson,
34975
+ packageName: workspaceFacts.reactRouter.packageName,
34976
+ version: workspaceFacts.reactRouter.version
34977
+ });
34653
34978
  const preactVersion = getPreactVersion(packageJson);
34654
34979
  const remotionVersion = workspaceFacts.remotionVersion;
34980
+ const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
34981
+ const reactThreeFiberVersion = workspaceFacts.reactThreeFiber.packageName ? resolveCatalogBackedDependencyVersion({
34982
+ rootDirectory: directory,
34983
+ rootPackageJson: packageJson,
34984
+ packageName: workspaceFacts.reactThreeFiber.packageName,
34985
+ version: workspaceFacts.reactThreeFiber.version
34986
+ }) : null;
34987
+ const threeVersion = resolveCatalogBackedDependencyVersion({
34988
+ rootDirectory: directory,
34989
+ rootPackageJson: packageJson,
34990
+ packageName: "three",
34991
+ version: workspaceFacts.threeVersion
34992
+ });
34655
34993
  const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
34656
34994
  const projectInfo = {
34657
34995
  rootDirectory: directory,
@@ -34662,9 +35000,11 @@ const discoverProject = (directory) => {
34662
35000
  zodVersion,
34663
35001
  zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
34664
35002
  mobxVersion,
34665
- mobxMajorVersion: mobxVersion === null ? null : getLowestDependencyMajor(mobxVersion),
35003
+ mobxMajorVersion: mobxVersion === null ? null : getDependencyMajorWithinSupportedRange(mobxVersion, 6),
34666
35004
  hasMobxReact: workspaceFacts.hasMobxReact,
35005
+ mobxReactVersion: workspaceFacts.mobxReactVersion,
34667
35006
  hasMobxReactLite: workspaceFacts.hasMobxReactLite,
35007
+ mobxReactLiteVersion: workspaceFacts.mobxReactLiteVersion,
34668
35008
  hasMobxStateTree: workspaceFacts.hasMobxStateTree,
34669
35009
  hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
34670
35010
  zustandVersion,
@@ -34673,18 +35013,29 @@ const discoverProject = (directory) => {
34673
35013
  hasTypeScript,
34674
35014
  hasReactCompiler: detectReactCompiler(directory, packageJson),
34675
35015
  hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
34676
- hasTanStackQuery: hasTanStackQuery(packageJson),
35016
+ hasTanStackQuery: tanstackQueryVersion !== null,
35017
+ hasI18nLibrary: workspaceFacts.hasI18nLibrary,
35018
+ tanstackQueryVersion,
35019
+ styledComponentsVersion: workspaceFacts.styledComponentsVersion,
34677
35020
  valtioVersion,
34678
35021
  valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
34679
35022
  hasRemotion: workspaceFacts.hasRemotionDependency,
34680
35023
  remotionVersion,
34681
35024
  remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
35025
+ hasThree: workspaceFacts.hasThree,
35026
+ threeVersion,
35027
+ threeRelease: parseThreeRelease(threeVersion),
35028
+ hasReactThreeFiber: workspaceFacts.hasReactThreeFiber,
35029
+ reactThreeFiberVersion,
35030
+ reactThreeFiberMajorVersion: reactThreeFiberVersion === null ? null : getLowestDependencyMajor(reactThreeFiberVersion),
34682
35031
  hasSsrDependency: workspaceFacts.hasSsrDependency,
34683
35032
  preactVersion,
34684
35033
  preactMajorVersion: parseReactMajor(preactVersion),
34685
35034
  hasReactNativeWorkspace,
34686
35035
  nextjsVersion,
34687
35036
  nextjsMajorVersion: nextjsVersion === null ? null : getLowestDependencyMajor(nextjsVersion),
35037
+ reactRouterVersion,
35038
+ hasReactRouterFramework: workspaceFacts.hasReactRouterFramework,
34688
35039
  expoVersion,
34689
35040
  shopifyFlashListVersion,
34690
35041
  shopifyFlashListMajorVersion: shopifyFlashListVersion === null ? null : getLowestDependencyMajor(shopifyFlashListVersion),
@@ -37953,10 +38304,10 @@ const SSR_FRAMEWORKS = new Set([
37953
38304
  "gatsby",
37954
38305
  "tanstack-start"
37955
38306
  ]);
37956
- const addMajorLadder = (capabilities, name, major, earliest, latest) => {
37957
- if (major === null) return;
37958
- const cappedMajor = Math.min(major, latest);
37959
- for (let candidate = earliest; candidate <= cappedMajor; candidate += 1) capabilities.add(`${name}:${candidate}`);
38307
+ const addVersionCapabilityLadder = (capabilities, name, detectedVersion, earliest, latest) => {
38308
+ if (detectedVersion === null) return;
38309
+ const cappedVersion = Math.min(detectedVersion, latest);
38310
+ for (let candidate = earliest; candidate <= cappedVersion; candidate += 1) capabilities.add(`${name}:${candidate}`);
37960
38311
  };
37961
38312
  const buildCapabilities = (project) => {
37962
38313
  const capabilities = /* @__PURE__ */ new Set();
@@ -37969,39 +38320,86 @@ const buildCapabilities = (project) => {
37969
38320
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
37970
38321
  if (project.isStaticExport) capabilities.add("nextjs:static-export");
37971
38322
  if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
37972
- addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
38323
+ if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
38324
+ const reactRouterVersion = project.reactRouterVersion ?? null;
38325
+ if (reactRouterVersion !== null) {
38326
+ capabilities.add("react-router");
38327
+ if (project.hasReactRouterFramework === true) capabilities.add("react-router-framework");
38328
+ const detectedVersion = parseReactMajorMinor(reactRouterVersion);
38329
+ if (detectedVersion !== null) {
38330
+ for (const threshold of REACT_ROUTER_CAPABILITY_THRESHOLDS) if (isMajorMinorAtLeast(detectedVersion, threshold)) capabilities.add(threshold.capability);
38331
+ }
38332
+ }
38333
+ addVersionCapabilityLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
37973
38334
  if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
37974
38335
  major: 19,
37975
38336
  minor: 2
37976
38337
  })) capabilities.add("react:19.2");
37977
- if (project.tailwindVersion !== null) capabilities.add("tailwind");
37978
- if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
37979
- major: 3,
37980
- minor: 4
37981
- })) capabilities.add("tailwind:3.4");
38338
+ if (project.tailwindVersion !== null) {
38339
+ capabilities.add("tailwind");
38340
+ const tailwindVersion = parseTailwindMajorMinor(project.tailwindVersion);
38341
+ if (isMajorMinorAtLeast(tailwindVersion, {
38342
+ major: 3,
38343
+ minor: 4
38344
+ })) capabilities.add("tailwind:3.4");
38345
+ if (tailwindVersion !== null && isMajorMinorAtLeast(tailwindVersion, {
38346
+ major: 4,
38347
+ minor: 0
38348
+ })) capabilities.add("tailwind:4");
38349
+ }
37982
38350
  if (project.zodVersion !== null) capabilities.add("zod");
37983
38351
  if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
37984
38352
  if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
37985
38353
  if (project.hasMobxReact === true) capabilities.add("mobx-react");
37986
38354
  if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
37987
38355
  if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
38356
+ const mobxReactVersion = parseDependencyMajorMinor(project.mobxReactVersion);
38357
+ const mobxReactLiteVersion = parseDependencyMajorMinor(project.mobxReactLiteVersion);
38358
+ const hasMobxReactObserverMemoGuard = mobxReactVersion !== null && isMajorMinorAtLeast(mobxReactVersion, {
38359
+ major: 7,
38360
+ minor: 3
38361
+ });
38362
+ const hasMobxReactLiteObserverMemoGuard = mobxReactLiteVersion !== null && isMajorMinorAtLeast(mobxReactLiteVersion, {
38363
+ major: 3,
38364
+ minor: 3
38365
+ });
38366
+ if (hasMobxReactObserverMemoGuard) capabilities.add("mobx-react-observer-memo-guard");
38367
+ if (hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-lite-observer-memo-guard");
38368
+ if (hasMobxReactObserverMemoGuard || hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-binding-observer-memo-guard");
37988
38369
  if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
37989
38370
  if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
37990
- if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addMajorLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
38371
+ if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addVersionCapabilityLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
38372
+ const mobxVersion = parseDependencyMajorMinor(project.mobxVersion);
38373
+ if (project.mobxMajorVersion === 6 && mobxVersion !== null && isMajorMinorAtLeast(mobxVersion, {
38374
+ major: 6,
38375
+ minor: 10
38376
+ })) capabilities.add("mobx:6.10");
37991
38377
  if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
37992
- if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addMajorLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
38378
+ if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addVersionCapabilityLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
37993
38379
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
37994
38380
  if (project.hasReactCompiler) capabilities.add("react-compiler");
37995
- if (project.hasTanStackQuery) capabilities.add("tanstack-query");
38381
+ if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
38382
+ if (project.styledComponentsVersion) {
38383
+ capabilities.add("styled-components");
38384
+ const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
38385
+ if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
38386
+ }
38387
+ if (project.hasI18nLibrary) capabilities.add("i18n");
37996
38388
  if (project.valtioVersion !== null) capabilities.add("valtio");
37997
- addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
38389
+ addVersionCapabilityLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
37998
38390
  if (project.hasRemotion) {
37999
38391
  capabilities.add("remotion");
38000
- addMajorLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
38392
+ addVersionCapabilityLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
38393
+ }
38394
+ if (project.hasThree || project.hasReactThreeFiber) capabilities.add("three");
38395
+ addVersionCapabilityLadder(capabilities, "three", project.threeRelease ?? null, 145, 250);
38396
+ if (project.hasReactThreeFiber) {
38397
+ capabilities.add("r3f");
38398
+ addVersionCapabilityLadder(capabilities, "r3f", project.reactThreeFiberMajorVersion ?? null, 3, 10);
38001
38399
  }
38002
38400
  if (project.hasTypeScript) capabilities.add("typescript");
38003
38401
  if (project.preactVersion !== null) capabilities.add("preact");
38004
- addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
38402
+ addVersionCapabilityLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
38005
38403
  if (project.preactVersion !== null && project.reactVersion === null) capabilities.add("pure-preact");
38006
38404
  return capabilities;
38007
38405
  };
@@ -38013,7 +38411,7 @@ const getCapabilities = (project) => {
38013
38411
  capabilitiesByProject.set(project, capabilities);
38014
38412
  return capabilities;
38015
38413
  };
38016
- const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
38414
+ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen, includedTags) => {
38017
38415
  if (requires) {
38018
38416
  for (const capability of requires) if (!capabilities.has(capability)) return false;
38019
38417
  }
@@ -38024,20 +38422,29 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
38024
38422
  if (tags) {
38025
38423
  for (const tag of tags) if (ignoredTags.has(tag)) return false;
38026
38424
  }
38425
+ if (includedTags && includedTags.size > 0) {
38426
+ if (!tags?.some((tag) => includedTags.has(tag))) return false;
38427
+ }
38027
38428
  return true;
38028
38429
  };
38430
+ const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
38029
38431
  const yieldToEventLoop = () => new Promise((resolve) => {
38030
38432
  setImmediate(resolve);
38031
38433
  });
38032
38434
  const createSecurityScanSession = (rootDirectory, options) => {
38033
38435
  const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
38034
38436
  const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
38437
+ const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
38035
38438
  const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
38036
38439
  const rule = entry.rule;
38037
38440
  const scan = rule.scan;
38038
38441
  if (typeof scan !== "function") return [];
38039
- if (rule.defaultEnabled === false) return [];
38040
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
38442
+ if (!shouldEnableRuleByDefaultStatus({
38443
+ defaultEnabled: rule.defaultEnabled,
38444
+ includeTagDefaults: options.includeTagDefaults === true,
38445
+ hasIncludedTags: includedTags.size > 0
38446
+ })) return [];
38447
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) return [];
38041
38448
  return [{
38042
38449
  entry,
38043
38450
  scan,
@@ -40023,8 +40430,9 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
40023
40430
  }
40024
40431
  return enabled;
40025
40432
  };
40026
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
40027
- const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
40433
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
40434
+ const hasIncludedTags = includedTags.size > 0;
40435
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
40028
40436
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
40029
40437
  const jsPlugins = [];
40030
40438
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -40039,9 +40447,14 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
40039
40447
  if (rule.scan !== void 0) continue;
40040
40448
  if (customRulesOnly && registryEntry.originallyExternal) continue;
40041
40449
  if (rule.framework !== "global" && !rule.requires) continue;
40042
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
40450
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
40043
40451
  const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
40044
- if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
40452
+ if (!shouldEnableRuleByDefaultStatus({
40453
+ defaultEnabled: rule.defaultEnabled,
40454
+ includeTagDefaults,
40455
+ hasIncludedTags,
40456
+ hasExplicitOverride: explicitRuleOverride !== void 0
40457
+ })) continue;
40045
40458
  const severity = resolveRuleSeverityOverride({
40046
40459
  ruleKey: registryEntry.key,
40047
40460
  category: rule.category
@@ -40050,7 +40463,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
40050
40463
  enabledReactDoctorRules[registryEntry.key] = severity;
40051
40464
  }
40052
40465
  const userPluginRules = {};
40053
- if (ruleSelection !== "sidecar") for (const userPlugin of userPlugins) {
40466
+ if (ruleSelection !== "sidecar" && !hasIncludedTags) for (const userPlugin of userPlugins) {
40054
40467
  Object.assign(userPluginRules, buildUserPluginRules(userPlugin, severityControls));
40055
40468
  jsPlugins.push(userPlugin.entry);
40056
40469
  }
@@ -40267,6 +40680,19 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
40267
40680
  }
40268
40681
  };
40269
40682
  };
40683
+ const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
40684
+ const fingerprintFileContents = (filePath, fingerprintLength) => {
40685
+ const fileStats = NFS.statSync(filePath, { bigint: true });
40686
+ const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
40687
+ if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
40688
+ const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
40689
+ fingerprintCacheByFilePath.set(filePath, {
40690
+ fingerprint,
40691
+ modifiedTimeNanoseconds: fileStats.mtimeNs,
40692
+ sizeBytes: fileStats.size
40693
+ });
40694
+ return fingerprint;
40695
+ };
40270
40696
  const bundledRequire = createRequire(import.meta.url);
40271
40697
  const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
40272
40698
  const resolveChildNodeVersion = (nodeBinaryPath) => {
@@ -40290,6 +40716,13 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS = [
40290
40716
  "oxlint-plugin-react-doctor/package.json",
40291
40717
  "eslint-plugin-react-hooks/package.json"
40292
40718
  ];
40719
+ const resolvePluginFingerprint = () => {
40720
+ try {
40721
+ return fingerprintFileContents(bundledRequire.resolve("oxlint-plugin-react-doctor"), 16);
40722
+ } catch {
40723
+ return "unresolved";
40724
+ }
40725
+ };
40293
40726
  const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
40294
40727
  const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
40295
40728
  for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS) try {
@@ -40299,6 +40732,7 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
40299
40732
  } catch {
40300
40733
  versions.push(`${specifier}=missing`);
40301
40734
  }
40735
+ versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
40302
40736
  return versions;
40303
40737
  };
40304
40738
  const esmRequire = createRequire(import.meta.url);
@@ -41774,7 +42208,7 @@ const reactHooksJsPluginDropNote = (error) => {
41774
42208
  * 6. always restore disable directives + clean up the temp dir
41775
42209
  */
41776
42210
  const runOxlint = async (options) => {
41777
- const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
42211
+ const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
41778
42212
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
41779
42213
  const severityControls = buildRuleSeverityControls(userConfig);
41780
42214
  validateRuleRegistration();
@@ -41788,13 +42222,15 @@ const runOxlint = async (options) => {
41788
42222
  }
41789
42223
  const pluginPath = resolvePluginPath();
41790
42224
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
41791
- const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
42225
+ const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
41792
42226
  const buildConfig = (overrides) => createOxlintConfig({
41793
42227
  pluginPath,
41794
42228
  project,
41795
42229
  customRulesOnly,
41796
42230
  extendsPaths: overrides.extendsPaths,
41797
42231
  ignoredTags,
42232
+ includedTags,
42233
+ includeTagDefaults,
41798
42234
  serverAuthFunctionNames,
41799
42235
  severityControls,
41800
42236
  userPlugins,
@@ -42183,6 +42619,8 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
42183
42619
  respectInlineDisables: input.respectInlineDisables,
42184
42620
  adoptExistingLintConfig: input.adoptExistingLintConfig,
42185
42621
  ignoredTags: input.ignoredTags,
42622
+ includedTags: input.includedTags,
42623
+ includeTagDefaults: input.includeTagDefaults,
42186
42624
  userConfig: input.userConfig ?? null,
42187
42625
  configSourceDirectory: input.configSourceDirectory,
42188
42626
  onPartialFailure: (reason) => {
@@ -43031,7 +43469,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
43031
43469
  const securityScanFailedRef = yield* make$13(false);
43032
43470
  const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
43033
43471
  project,
43034
- ignoredTags: input.ignoredTags
43472
+ ignoredTags: input.ignoredTags,
43473
+ includedTags: input.includedTags,
43474
+ includeTagDefaults: input.includeTagDefaults
43035
43475
  })).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
43036
43476
  const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
43037
43477
  const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
@@ -43122,6 +43562,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
43122
43562
  respectInlineDisables: input.respectInlineDisables,
43123
43563
  adoptExistingLintConfig: input.adoptExistingLintConfig,
43124
43564
  ignoredTags: input.ignoredTags,
43565
+ includedTags: input.includedTags,
43566
+ includeTagDefaults: input.includeTagDefaults,
43125
43567
  userConfig: resolvedConfig.config ?? void 0,
43126
43568
  configSourceDirectory: resolvedConfig.configSourceDirectory ?? void 0,
43127
43569
  onFileProgress: (scannedFileCount, totalFileCount) => {
@@ -43982,4 +44424,4 @@ const toJsonReport = (result, options) => buildJsonReport({
43982
44424
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
43983
44425
 
43984
44426
  //# sourceMappingURL=index.js.map
43985
- //# debugId=6aa1c6e1-8fcc-50d4-a076-3e864425bdc5
44427
+ //# debugId=c65f1825-0401-518f-840a-c33df84ebafc