react-doctor 0.8.1-dev.5332cb6 → 0.8.1-dev.5b468f8

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]="24153a3f-aef9-53fd-8dff-9b016a9613fb")}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]="4d155139-533f-5635-af83-9ee012355893")}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";
@@ -36022,44 +36022,6 @@ var AmbiguousProjectError = class extends Error {
36022
36022
  }
36023
36023
  };
36024
36024
  const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
36025
- const isErrnoException = (error) => error instanceof Error && "code" in error;
36026
- const IGNORABLE_READDIR_ERROR_CODES = new Set([
36027
- "EACCES",
36028
- "EPERM",
36029
- "ENOENT",
36030
- "ENOTDIR",
36031
- "EINVAL",
36032
- "ELOOP",
36033
- "ENAMETOOLONG"
36034
- ]);
36035
- const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
36036
- const readDirectoryEntries = (directoryPath) => {
36037
- try {
36038
- return NFS.readdirSync(directoryPath, { withFileTypes: true });
36039
- } catch (error) {
36040
- if (isIgnorableReaddirError(error)) return [];
36041
- throw error;
36042
- }
36043
- };
36044
- const isFile = (filePath) => {
36045
- try {
36046
- return NFS.statSync(filePath).isFile();
36047
- } catch {
36048
- return false;
36049
- }
36050
- };
36051
- const isDirectory = (directoryPath) => {
36052
- try {
36053
- return NFS.statSync(directoryPath).isDirectory();
36054
- } catch {
36055
- return false;
36056
- }
36057
- };
36058
- const isPlainObject = (value) => {
36059
- if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
36060
- const prototype = Object.getPrototypeOf(value);
36061
- return prototype === null || prototype === Object.prototype;
36062
- };
36063
36025
  const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
36064
36026
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
36065
36027
  const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
@@ -36252,6 +36214,44 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
36252
36214
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
36253
36215
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
36254
36216
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
36217
+ const isErrnoException = (error) => error instanceof Error && "code" in error;
36218
+ const IGNORABLE_READDIR_ERROR_CODES = new Set([
36219
+ "EACCES",
36220
+ "EPERM",
36221
+ "ENOENT",
36222
+ "ENOTDIR",
36223
+ "EINVAL",
36224
+ "ELOOP",
36225
+ "ENAMETOOLONG"
36226
+ ]);
36227
+ const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
36228
+ const readDirectoryEntries = (directoryPath) => {
36229
+ try {
36230
+ return NFS.readdirSync(directoryPath, { withFileTypes: true });
36231
+ } catch (error) {
36232
+ if (isIgnorableReaddirError(error)) return [];
36233
+ throw error;
36234
+ }
36235
+ };
36236
+ const isFile = (filePath) => {
36237
+ try {
36238
+ return NFS.statSync(filePath).isFile();
36239
+ } catch {
36240
+ return false;
36241
+ }
36242
+ };
36243
+ const isDirectory = (directoryPath) => {
36244
+ try {
36245
+ return NFS.statSync(directoryPath).isDirectory();
36246
+ } catch {
36247
+ return false;
36248
+ }
36249
+ };
36250
+ const isPlainObject = (value) => {
36251
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
36252
+ const prototype = Object.getPrototypeOf(value);
36253
+ return prototype === null || prototype === Object.prototype;
36254
+ };
36255
36255
  const lastSourceMappingUrl = (fileContent) => {
36256
36256
  const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
36257
36257
  return lastReference ? lastReference[1] : null;
@@ -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
  };
@@ -36598,11 +36598,17 @@ const NEXT_CONFIG_FILENAMES = [
36598
36598
  ];
36599
36599
  const BABEL_CONFIG_FILENAMES = [
36600
36600
  ".babelrc",
36601
+ ".babelrc.js",
36601
36602
  ".babelrc.json",
36603
+ ".babelrc.cjs",
36604
+ ".babelrc.mjs",
36605
+ ".babelrc.cts",
36602
36606
  "babel.config.js",
36603
36607
  "babel.config.json",
36604
36608
  "babel.config.cjs",
36605
- "babel.config.mjs"
36609
+ "babel.config.mjs",
36610
+ "babel.config.ts",
36611
+ "babel.config.cts"
36606
36612
  ];
36607
36613
  const VITE_CONFIG_FILENAMES = [
36608
36614
  "vite.config.js",
@@ -36614,12 +36620,28 @@ const VITE_CONFIG_FILENAMES = [
36614
36620
  "vitest.config.ts",
36615
36621
  "vitest.config.js"
36616
36622
  ];
36623
+ const RSBUILD_CONFIG_FILENAMES = [
36624
+ "rsbuild.config.ts",
36625
+ "rsbuild.config.js",
36626
+ "rsbuild.config.mts",
36627
+ "rsbuild.config.mjs",
36628
+ "rsbuild.config.cts",
36629
+ "rsbuild.config.cjs"
36630
+ ];
36631
+ const RSPACK_CONFIG_FILENAMES = [
36632
+ "rspack.config.ts",
36633
+ "rspack.config.js",
36634
+ "rspack.config.mts",
36635
+ "rspack.config.mjs",
36636
+ "rspack.config.cts",
36637
+ "rspack.config.cjs"
36638
+ ];
36617
36639
  const EXPO_APP_CONFIG_FILENAMES = [
36618
36640
  "app.json",
36619
36641
  "app.config.js",
36620
36642
  "app.config.ts"
36621
36643
  ];
36622
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
36644
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|reactCompilerPreset\s*\(|["']react-compiler["']/;
36623
36645
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
36624
36646
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
36625
36647
  const hasCompilerPackage = (packageJson, compilerPackages) => {
@@ -36654,6 +36676,8 @@ const detectReactCompiler = (directory, packageJson) => {
36654
36676
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
36655
36677
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
36656
36678
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
36679
+ if (hasCompilerInConfigFiles(directory, RSBUILD_CONFIG_FILENAMES)) return true;
36680
+ if (hasCompilerInConfigFiles(directory, RSPACK_CONFIG_FILENAMES)) return true;
36657
36681
  if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
36658
36682
  return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
36659
36683
  };
@@ -36662,7 +36686,7 @@ const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((file
36662
36686
  const filePath = Path.join(directory, filename);
36663
36687
  return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
36664
36688
  });
36665
- const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:file|git|github|https?|link|patch|portal|workspace|npm):/i;
36689
+ const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:catalog|file|git|github|https?|link|patch|portal|workspace|npm):/i;
36666
36690
  const DIST_TAG_VERSION = /^[a-z][a-z0-9._-]*$/i;
36667
36691
  const WILDCARD_VERSION = /^[*xX](?:\.[*xX])*$/;
36668
36692
  const NPM_ALIAS_VERSION = /^npm:(?:@[^/]+\/[^@]+|[^@]+)@(.+)$/i;
@@ -36795,6 +36819,16 @@ const getLowestDependencyMajor = (version) => {
36795
36819
  }
36796
36820
  return lowestMajor;
36797
36821
  };
36822
+ const getDependencyMajorWithinSupportedRange = (version, latestSupportedMajor) => {
36823
+ const normalizedVersion = normalizeDependencyVersion(version);
36824
+ if (normalizedVersion === null) return null;
36825
+ const validRange = import_semver.validRange(normalizedVersion);
36826
+ if (validRange === null) return null;
36827
+ const minimumVersion = import_semver.minVersion(validRange);
36828
+ if (minimumVersion === null || minimumVersion.major > latestSupportedMajor) return null;
36829
+ if (import_semver.intersects(validRange, `>=${latestSupportedMajor + 1}.0.0`)) return null;
36830
+ return minimumVersion.major;
36831
+ };
36798
36832
  const isConcreteDependencyVersion = (version) => {
36799
36833
  const normalizedVersion = normalizeDependencyVersion(version);
36800
36834
  return normalizedVersion !== null && /\d/.test(normalizedVersion);
@@ -36838,9 +36872,18 @@ const parseReactMajorMinor = (reactVersion) => {
36838
36872
  };
36839
36873
  };
36840
36874
  const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
36841
- const parseTailwindMajorMinor = (tailwindVersion) => {
36842
- if (typeof tailwindVersion !== "string") return null;
36843
- const trimmed = tailwindVersion.trim();
36875
+ const parseThreeRelease = (threeVersion) => {
36876
+ if (typeof threeVersion !== "string") return null;
36877
+ const normalizedVersion = normalizeDependencyVersion(threeVersion);
36878
+ if (normalizedVersion === null) return null;
36879
+ const lowerBound = parseLowerBoundVersion(normalizedVersion);
36880
+ if (lowerBound === null) return null;
36881
+ if (lowerBound.major > 0) return Number.MAX_SAFE_INTEGER;
36882
+ return lowerBound.minor > 0 ? lowerBound.minor : null;
36883
+ };
36884
+ const parseDependencyMajorMinor = (dependencyVersion) => {
36885
+ if (typeof dependencyVersion !== "string") return null;
36886
+ const trimmed = dependencyVersion.trim();
36844
36887
  if (trimmed.length === 0) return null;
36845
36888
  const lowerBound = parseLowerBoundVersion(trimmed);
36846
36889
  if (lowerBound === null || lowerBound.major <= 0) return null;
@@ -36849,6 +36892,7 @@ const parseTailwindMajorMinor = (tailwindVersion) => {
36849
36892
  minor: lowerBound.minor
36850
36893
  };
36851
36894
  };
36895
+ const parseTailwindMajorMinor = (tailwindVersion) => parseDependencyMajorMinor(tailwindVersion);
36852
36896
  const hasUpperBoundOnlyPeerRange = (range) => {
36853
36897
  if (typeof range !== "string") return false;
36854
36898
  const normalizedRange = normalizeDependencyVersion(range);
@@ -36870,7 +36914,7 @@ const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
36870
36914
  if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
36871
36915
  return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
36872
36916
  };
36873
- const isCatalogReference = (version) => version.startsWith("catalog:");
36917
+ const isCatalogReference = (version) => typeof version === "string" && version.startsWith("catalog:");
36874
36918
  const extractCatalogName = (version) => {
36875
36919
  if (!isCatalogReference(version)) return null;
36876
36920
  const name = version.slice(8).trim();
@@ -37020,6 +37064,12 @@ const TAILWIND_ZOD_SECTIONS = [
37020
37064
  "devDependencies",
37021
37065
  "peerDependencies"
37022
37066
  ];
37067
+ const DEPENDENCY_SPEC_SECTIONS = [
37068
+ "dependencies",
37069
+ "devDependencies",
37070
+ "peerDependencies",
37071
+ "optionalDependencies"
37072
+ ];
37023
37073
  const EMPTY_DEPENDENCY_INFO = {
37024
37074
  reactVersion: null,
37025
37075
  tailwindVersion: null,
@@ -37029,7 +37079,7 @@ const EMPTY_DEPENDENCY_INFO = {
37029
37079
  const pickConcreteVersion = (packageJson, packageName, sections) => {
37030
37080
  for (const section of sections) {
37031
37081
  const version = packageJson[section]?.[packageName];
37032
- if (version === void 0) continue;
37082
+ if (typeof version !== "string") continue;
37033
37083
  if (isCatalogReference(version)) return null;
37034
37084
  if (isConcreteDependencyVersion(version)) return version;
37035
37085
  }
@@ -37061,13 +37111,16 @@ const extractDependencyInfo = (packageJson) => {
37061
37111
  };
37062
37112
  };
37063
37113
  const getDependencySpec = (packageJson, packageName) => {
37064
- const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
37065
- return typeof spec === "string" ? spec : null;
37114
+ for (const section of DEPENDENCY_SPEC_SECTIONS) {
37115
+ const spec = packageJson[section]?.[packageName];
37116
+ if (typeof spec === "string") return spec;
37117
+ }
37118
+ return null;
37066
37119
  };
37067
37120
  const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
37068
37121
  for (const section of sections) {
37069
37122
  const version = packageJson[section]?.[packageName];
37070
- if (version === void 0) continue;
37123
+ if (typeof version !== "string") continue;
37071
37124
  return {
37072
37125
  catalogReference: extractCatalogName(version) ?? null,
37073
37126
  hasDeclaration: true,
@@ -37101,24 +37154,15 @@ const getPreactVersion = (packageJson) => {
37101
37154
  ...packageJson.devDependencies
37102
37155
  }.preact ?? null;
37103
37156
  };
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
- const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
37157
+ const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, sourceDirectory = rootDirectory, sourcePackageJson = rootPackageJson, version }) => {
37118
37158
  if (version === null || !isCatalogReference(version)) return version;
37119
37159
  const catalogName = extractCatalogName(version);
37120
- const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
37121
- if (resolvedLocalVersion) return resolvedLocalVersion;
37160
+ const resolvedSourceVersion = resolveCatalogVersion(sourcePackageJson, packageName, sourceDirectory, catalogName);
37161
+ if (resolvedSourceVersion) return resolvedSourceVersion;
37162
+ if (sourceDirectory !== rootDirectory || sourcePackageJson !== rootPackageJson) {
37163
+ const resolvedRootVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
37164
+ if (resolvedRootVersion) return resolvedRootVersion;
37165
+ }
37122
37166
  const monorepoRoot = findMonorepoRoot(rootDirectory);
37123
37167
  if (!monorepoRoot) return version;
37124
37168
  const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
@@ -37316,7 +37360,75 @@ const listWorkspacePackages = (rootDirectory) => {
37316
37360
  }
37317
37361
  return packages;
37318
37362
  };
37363
+ const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
37364
+ const allDependencies = {
37365
+ ...packageJson.devDependencies,
37366
+ ...packageJson.peerDependencies,
37367
+ ...packageJson.dependencies
37368
+ };
37369
+ for (const packageName of packageNames) {
37370
+ const version = allDependencies[packageName];
37371
+ if (version !== void 0) return version;
37372
+ }
37373
+ return null;
37374
+ };
37375
+ const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
37376
+ const getTanStackQueryVersion = (packageJson) => {
37377
+ return getPreferredDependencyVersion({
37378
+ packageJson,
37379
+ packageNames: TANSTACK_REACT_QUERY_PACKAGES
37380
+ });
37381
+ };
37382
+ const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
37383
+ const getStyledComponentsVersion = (packageJson) => {
37384
+ return getPreferredDependencyVersion({
37385
+ packageJson,
37386
+ packageNames: STYLED_COMPONENTS_PACKAGES
37387
+ });
37388
+ };
37389
+ const I18N_PACKAGES = [
37390
+ "i18next",
37391
+ "react-i18next",
37392
+ "next-i18next",
37393
+ "react-intl",
37394
+ "next-intl",
37395
+ "use-intl",
37396
+ "@formatjs/intl",
37397
+ "@lingui/core",
37398
+ "@lingui/react",
37399
+ "typesafe-i18n",
37400
+ "@tolgee/react",
37401
+ "react-intl-universal"
37402
+ ];
37403
+ const hasI18nDependency = (packageJson) => {
37404
+ const allDependencies = {
37405
+ ...packageJson.peerDependencies,
37406
+ ...packageJson.dependencies,
37407
+ ...packageJson.devDependencies,
37408
+ ...packageJson.optionalDependencies
37409
+ };
37410
+ return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
37411
+ };
37319
37412
  const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
37413
+ const MOBX_REACT_PACKAGE_NAME = "mobx-react";
37414
+ const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
37415
+ const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
37416
+ const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
37417
+ const REACT_THREE_FIBER_DEPENDENCY_NAMES = ["@react-three/fiber", "react-three-fiber"];
37418
+ const REACT_THREE_FIBER_SECTIONS = [
37419
+ "dependencies",
37420
+ "peerDependencies",
37421
+ "optionalDependencies",
37422
+ "devDependencies"
37423
+ ];
37424
+ const THREE_DEPENDENCY_SECTIONS = [
37425
+ "dependencies",
37426
+ "peerDependencies",
37427
+ "optionalDependencies",
37428
+ "devDependencies"
37429
+ ];
37430
+ const REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES = [...REACT_THREE_FIBER_DEPENDENCY_NAMES, "@react-three/drei"];
37431
+ const THREE_DEPENDENCY_NAMES = [...REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES, "three"];
37320
37432
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
37321
37433
  const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
37322
37434
  const dependencyDeclaration = getDependencyDeclaration({
@@ -37327,7 +37439,7 @@ const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootD
37327
37439
  if (!dependencyDeclaration.hasDeclaration) return null;
37328
37440
  return concreteVersion ?? resolveCatalogVersion(workspacePackageJson, packageName, workspaceDirectory, dependencyDeclaration.catalogReference) ?? resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, dependencyDeclaration.catalogReference);
37329
37441
  };
37330
- const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
37442
+ const shouldReplaceWithLowerMajor = (currentVersion, nextVersion) => {
37331
37443
  if (!currentVersion) return true;
37332
37444
  const currentMajor = parseReactMajor(currentVersion);
37333
37445
  const nextMajor = parseReactMajor(nextVersion);
@@ -37335,7 +37447,62 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
37335
37447
  if (nextMajor === null) return false;
37336
37448
  return nextMajor < currentMajor;
37337
37449
  };
37338
- const evaluateManifestFacts = (facts, packageJson, directory) => {
37450
+ const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSupportedMajor) => {
37451
+ if (currentFact.version === null) return true;
37452
+ if (nextFact.version === null) return false;
37453
+ const currentMajor = getLowestDependencyMajor(currentFact.version);
37454
+ const nextMajor = getLowestDependencyMajor(nextFact.version);
37455
+ if (currentMajor === null) return false;
37456
+ if (nextMajor === null) return true;
37457
+ if (currentMajor > latestSupportedMajor) return false;
37458
+ if (nextMajor > latestSupportedMajor) return true;
37459
+ return nextMajor < currentMajor;
37460
+ };
37461
+ const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
37462
+ if (!currentVersion) return true;
37463
+ const currentMajor = getLowestDependencyMajor(currentVersion);
37464
+ const nextMajor = getLowestDependencyMajor(nextVersion);
37465
+ if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
37466
+ if (nextMajor === null) return currentMajor >= 6;
37467
+ return nextMajor < currentMajor;
37468
+ };
37469
+ const selectOldestDependencyVersion = (currentVersion, nextVersion) => {
37470
+ if (currentVersion === null || nextVersion === null) return null;
37471
+ const current = parseDependencyMajorMinor(currentVersion);
37472
+ const next = parseDependencyMajorMinor(nextVersion);
37473
+ if (current === null) return currentVersion;
37474
+ if (next === null) return nextVersion;
37475
+ if (next.major !== current.major) return next.major < current.major ? nextVersion : currentVersion;
37476
+ return next.minor < current.minor ? nextVersion : currentVersion;
37477
+ };
37478
+ const shouldReplaceMobxFact = (currentFact, nextFact) => {
37479
+ if (currentFact.sourceDirectory === null) return true;
37480
+ if (currentFact.version === null) return false;
37481
+ if (nextFact.version === null) return true;
37482
+ const currentMajor = getDependencyMajorWithinSupportedRange(currentFact.version, 6);
37483
+ const nextMajor = getDependencyMajorWithinSupportedRange(nextFact.version, 6);
37484
+ if (currentMajor === null) return false;
37485
+ if (nextMajor === null) return true;
37486
+ return selectOldestDependencyVersion(currentFact.version, nextFact.version) === nextFact.version;
37487
+ };
37488
+ const collectBindingVersion = (facts, packageJson, directory, packageName) => {
37489
+ const version = getDependencySpec(packageJson, packageName);
37490
+ if (version === null) return;
37491
+ const resolvedVersion = resolveCatalogBackedDependencyVersion({
37492
+ rootDirectory: directory,
37493
+ rootPackageJson: packageJson,
37494
+ packageName,
37495
+ version
37496
+ });
37497
+ if (packageName === MOBX_REACT_PACKAGE_NAME) {
37498
+ facts.mobxReactVersion = facts.hasMobxReact ? selectOldestDependencyVersion(facts.mobxReactVersion, resolvedVersion) : resolvedVersion;
37499
+ facts.hasMobxReact = true;
37500
+ return;
37501
+ }
37502
+ facts.mobxReactLiteVersion = facts.hasMobxReactLite ? selectOldestDependencyVersion(facts.mobxReactLiteVersion, resolvedVersion) : resolvedVersion;
37503
+ facts.hasMobxReactLite = true;
37504
+ };
37505
+ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
37339
37506
  if (facts.expo.version === null) {
37340
37507
  const spec = getDependencySpec(packageJson, "expo");
37341
37508
  if (spec !== null) facts.expo = {
@@ -37357,13 +37524,113 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
37357
37524
  sourceDirectory: directory
37358
37525
  };
37359
37526
  }
37527
+ const mobxSpec = getDependencySpec(packageJson, "mobx");
37528
+ if (mobxSpec !== null) {
37529
+ const nextMobxFact = {
37530
+ version: resolveCatalogBackedDependencyVersion({
37531
+ rootDirectory: directory,
37532
+ rootPackageJson: packageJson,
37533
+ packageName: "mobx",
37534
+ version: mobxSpec
37535
+ }),
37536
+ sourceDirectory: directory
37537
+ };
37538
+ if (shouldReplaceMobxFact(facts.mobx, nextMobxFact)) facts.mobx = nextMobxFact;
37539
+ }
37540
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_PACKAGE_NAME);
37541
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_LITE_PACKAGE_NAME);
37542
+ facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
37543
+ facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
37544
+ const zustandSpec = getDependencySpec(packageJson, "zustand");
37545
+ if (zustandSpec !== null) {
37546
+ const nextZustandFact = {
37547
+ version: resolveCatalogBackedDependencyVersion({
37548
+ rootDirectory: directory,
37549
+ rootPackageJson: packageJson,
37550
+ packageName: "zustand",
37551
+ version: zustandSpec
37552
+ }),
37553
+ sourceDirectory: directory
37554
+ };
37555
+ if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
37556
+ }
37360
37557
  if (facts.reanimatedVersion === null) {
37361
37558
  const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
37362
37559
  if (spec !== null) facts.reanimatedVersion = spec;
37363
37560
  }
37561
+ if (facts.valtioVersion === null) {
37562
+ const spec = getDependencySpec(packageJson, "valtio");
37563
+ if (spec !== null) facts.valtioVersion = spec;
37564
+ }
37565
+ facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
37566
+ const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
37567
+ rootDirectory: directory,
37568
+ rootPackageJson: packageJson,
37569
+ packageName: "styled-components",
37570
+ version: getStyledComponentsVersion(packageJson)
37571
+ });
37572
+ if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
37573
+ facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
37574
+ for (const packageName of REACT_THREE_FIBER_DEPENDENCY_NAMES) {
37575
+ const version = resolveCatalogBackedDependencyVersion({
37576
+ rootDirectory,
37577
+ rootPackageJson,
37578
+ sourceDirectory: directory,
37579
+ sourcePackageJson: packageJson,
37580
+ packageName,
37581
+ version: getDependencyDeclaration({
37582
+ packageName,
37583
+ packageJson,
37584
+ sections: REACT_THREE_FIBER_SECTIONS
37585
+ }).version
37586
+ });
37587
+ if (version === null) continue;
37588
+ if (shouldReplaceWithLowerMajor(facts.reactThreeFiber.version, version)) facts.reactThreeFiber = {
37589
+ packageName,
37590
+ version,
37591
+ sourceDirectory: directory
37592
+ };
37593
+ }
37594
+ const threeVersion = resolveCatalogBackedDependencyVersion({
37595
+ rootDirectory,
37596
+ rootPackageJson,
37597
+ sourceDirectory: directory,
37598
+ sourcePackageJson: packageJson,
37599
+ packageName: "three",
37600
+ version: getDependencyDeclaration({
37601
+ packageName: "three",
37602
+ packageJson,
37603
+ sections: THREE_DEPENDENCY_SECTIONS
37604
+ }).version
37605
+ });
37606
+ if (threeVersion !== null) {
37607
+ const currentRelease = parseThreeRelease(facts.threeVersion);
37608
+ const nextRelease = parseThreeRelease(threeVersion);
37609
+ if (facts.threeVersion === null || nextRelease !== null && (currentRelease === null || nextRelease < currentRelease)) facts.threeVersion = threeVersion;
37610
+ }
37364
37611
  facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
37365
37612
  facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
37366
37613
  facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
37614
+ const remotionSpec = getDependencySpec(packageJson, "remotion");
37615
+ if (remotionSpec !== null) {
37616
+ facts.hasRemotionDependency = true;
37617
+ const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
37618
+ rootDirectory,
37619
+ rootPackageJson,
37620
+ packageName: "remotion",
37621
+ version: remotionSpec
37622
+ });
37623
+ const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
37624
+ if (remotionMajorVersion === null) {
37625
+ facts.hasUnknownRemotionVersion = true;
37626
+ facts.remotionVersion = null;
37627
+ } else if (!facts.hasUnknownRemotionVersion) {
37628
+ const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
37629
+ if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
37630
+ }
37631
+ }
37632
+ facts.hasThree = facts.hasThree || THREE_DEPENDENCY_NAMES.some((dependencyName) => getDependencySpec(packageJson, dependencyName) !== null);
37633
+ facts.hasReactThreeFiber = facts.hasReactThreeFiber || REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES.some((dependencyName) => getDependencySpec(packageJson, dependencyName) !== null);
37367
37634
  };
37368
37635
  const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
37369
37636
  const facts = {
@@ -37383,12 +37650,41 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37383
37650
  version: null,
37384
37651
  sourceDirectory: null
37385
37652
  },
37653
+ valtioVersion: null,
37654
+ mobx: {
37655
+ version: null,
37656
+ sourceDirectory: null
37657
+ },
37658
+ hasMobxReact: false,
37659
+ mobxReactVersion: null,
37660
+ hasMobxReactLite: false,
37661
+ mobxReactLiteVersion: null,
37662
+ hasMobxStateTree: false,
37663
+ hasMobxReactObserver: false,
37664
+ zustand: {
37665
+ version: null,
37666
+ sourceDirectory: null
37667
+ },
37668
+ tanstackQueryVersion: null,
37669
+ styledComponentsVersion: null,
37670
+ hasI18nLibrary: false,
37386
37671
  hasReactNativeAwarePackage: false,
37387
37672
  hasReanimatedAwarePackage: false,
37388
37673
  hasSsrDependency: false,
37674
+ hasRemotionDependency: false,
37675
+ hasUnknownRemotionVersion: false,
37676
+ remotionVersion: null,
37677
+ hasThree: false,
37678
+ threeVersion: null,
37679
+ hasReactThreeFiber: false,
37680
+ reactThreeFiber: {
37681
+ packageName: null,
37682
+ version: null,
37683
+ sourceDirectory: null
37684
+ },
37389
37685
  reanimatedVersion: null
37390
37686
  };
37391
- evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
37687
+ evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
37392
37688
  let isReactGroupSettled = !collectReactGroup;
37393
37689
  const visitedDirectories = /* @__PURE__ */ new Set();
37394
37690
  for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
@@ -37397,7 +37693,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37397
37693
  if (visitedDirectories.has(workspaceDirectory)) continue;
37398
37694
  visitedDirectories.add(workspaceDirectory);
37399
37695
  const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
37400
- evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
37696
+ evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory, rootDirectory, rootPackageJson);
37401
37697
  const info = extractDependencyInfo(workspacePackageJson);
37402
37698
  if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
37403
37699
  if (isReactGroupSettled) continue;
@@ -37428,7 +37724,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37428
37724
  workspaceDirectory,
37429
37725
  workspacePackageJson
37430
37726
  });
37431
- if (reactVersion && shouldReplaceReactVersion(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
37727
+ if (reactVersion && shouldReplaceWithLowerMajor(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
37432
37728
  if (tailwindVersion && !facts.tailwindVersion) facts.tailwindVersion = tailwindVersion;
37433
37729
  if (zodVersion && !facts.zodVersion) facts.zodVersion = zodVersion;
37434
37730
  const settledReactMajor = parseReactMajor(facts.reactVersion);
@@ -37618,11 +37914,35 @@ const discoverProjectWithoutPackageJson = (directory) => {
37618
37914
  tailwindVersion: null,
37619
37915
  zodVersion: null,
37620
37916
  zodMajorVersion: null,
37917
+ mobxVersion: null,
37918
+ mobxMajorVersion: null,
37919
+ hasMobxReact: false,
37920
+ mobxReactVersion: null,
37921
+ hasMobxReactLite: false,
37922
+ mobxReactLiteVersion: null,
37923
+ hasMobxStateTree: false,
37924
+ hasMobxReactObserver: false,
37925
+ zustandVersion: null,
37926
+ zustandMajorVersion: null,
37621
37927
  framework: "unknown",
37622
37928
  hasTypeScript: hasOwnTsConfig,
37623
37929
  hasReactCompiler: false,
37624
37930
  hasReactCompilerLintPlugin: false,
37625
37931
  hasTanStackQuery: false,
37932
+ valtioVersion: null,
37933
+ valtioMajorVersion: null,
37934
+ hasRemotion: false,
37935
+ remotionVersion: null,
37936
+ remotionMajorVersion: null,
37937
+ hasI18nLibrary: false,
37938
+ tanstackQueryVersion: null,
37939
+ styledComponentsVersion: null,
37940
+ hasThree: false,
37941
+ threeVersion: null,
37942
+ threeRelease: null,
37943
+ hasReactThreeFiber: false,
37944
+ reactThreeFiberVersion: null,
37945
+ reactThreeFiberMajorVersion: null,
37626
37946
  hasSsrDependency: false,
37627
37947
  preactVersion: null,
37628
37948
  preactMajorVersion: null,
@@ -37721,6 +38041,12 @@ const discoverProject = (directory) => {
37721
38041
  packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
37722
38042
  version: workspaceFacts.shopifyFlashList.version
37723
38043
  }) : null;
38044
+ const zustandVersion = resolveCatalogBackedDependencyVersion({
38045
+ rootDirectory: directory,
38046
+ rootPackageJson: packageJson,
38047
+ packageName: "zustand",
38048
+ version: workspaceFacts.zustand.version
38049
+ });
37724
38050
  const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
37725
38051
  const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
37726
38052
  const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
@@ -37729,7 +38055,33 @@ const discoverProject = (directory) => {
37729
38055
  packageName: "next",
37730
38056
  version: workspaceFacts.next.version
37731
38057
  }) : null;
38058
+ const valtioVersion = resolveCatalogBackedDependencyVersion({
38059
+ rootDirectory: directory,
38060
+ rootPackageJson: packageJson,
38061
+ packageName: "valtio",
38062
+ version: workspaceFacts.valtioVersion
38063
+ });
38064
+ const mobxVersion = resolveCatalogBackedDependencyVersion({
38065
+ rootDirectory: directory,
38066
+ rootPackageJson: packageJson,
38067
+ packageName: "mobx",
38068
+ version: workspaceFacts.mobx.version
38069
+ });
37732
38070
  const preactVersion = getPreactVersion(packageJson);
38071
+ const remotionVersion = workspaceFacts.remotionVersion;
38072
+ const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
38073
+ const reactThreeFiberVersion = workspaceFacts.reactThreeFiber.packageName ? resolveCatalogBackedDependencyVersion({
38074
+ rootDirectory: directory,
38075
+ rootPackageJson: packageJson,
38076
+ packageName: workspaceFacts.reactThreeFiber.packageName,
38077
+ version: workspaceFacts.reactThreeFiber.version
38078
+ }) : null;
38079
+ const threeVersion = resolveCatalogBackedDependencyVersion({
38080
+ rootDirectory: directory,
38081
+ rootPackageJson: packageJson,
38082
+ packageName: "three",
38083
+ version: workspaceFacts.threeVersion
38084
+ });
37733
38085
  const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
37734
38086
  const projectInfo = {
37735
38087
  rootDirectory: directory,
@@ -37739,11 +38091,35 @@ const discoverProject = (directory) => {
37739
38091
  tailwindVersion,
37740
38092
  zodVersion,
37741
38093
  zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
38094
+ mobxVersion,
38095
+ mobxMajorVersion: mobxVersion === null ? null : getDependencyMajorWithinSupportedRange(mobxVersion, 6),
38096
+ hasMobxReact: workspaceFacts.hasMobxReact,
38097
+ mobxReactVersion: workspaceFacts.mobxReactVersion,
38098
+ hasMobxReactLite: workspaceFacts.hasMobxReactLite,
38099
+ mobxReactLiteVersion: workspaceFacts.mobxReactLiteVersion,
38100
+ hasMobxStateTree: workspaceFacts.hasMobxStateTree,
38101
+ hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
38102
+ zustandVersion,
38103
+ zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
37742
38104
  framework,
37743
38105
  hasTypeScript,
37744
38106
  hasReactCompiler: detectReactCompiler(directory, packageJson),
37745
38107
  hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
37746
- hasTanStackQuery: hasTanStackQuery(packageJson),
38108
+ hasTanStackQuery: tanstackQueryVersion !== null,
38109
+ hasI18nLibrary: workspaceFacts.hasI18nLibrary,
38110
+ tanstackQueryVersion,
38111
+ styledComponentsVersion: workspaceFacts.styledComponentsVersion,
38112
+ valtioVersion,
38113
+ valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
38114
+ hasRemotion: workspaceFacts.hasRemotionDependency,
38115
+ remotionVersion,
38116
+ remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
38117
+ hasThree: workspaceFacts.hasThree,
38118
+ threeVersion,
38119
+ threeRelease: parseThreeRelease(threeVersion),
38120
+ hasReactThreeFiber: workspaceFacts.hasReactThreeFiber,
38121
+ reactThreeFiberVersion,
38122
+ reactThreeFiberMajorVersion: reactThreeFiberVersion === null ? null : getLowestDependencyMajor(reactThreeFiberVersion),
37747
38123
  hasSsrDependency: workspaceFacts.hasSsrDependency,
37748
38124
  preactVersion,
37749
38125
  preactMajorVersion: parseReactMajor(preactVersion),
@@ -37977,7 +38353,6 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
37977
38353
  "react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
37978
38354
  "react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
37979
38355
  "react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
37980
- "react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
37981
38356
  "react/jsx-no-undef": "react-doctor/jsx-no-undef",
37982
38357
  "react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
37983
38358
  "react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
@@ -40299,9 +40674,25 @@ const BABEL_CONFIG_FILE_NAMES = [
40299
40674
  ".babelrc.json"
40300
40675
  ];
40301
40676
  const LEGACY_PRESET_SPEC = "module:metro-react-native-babel-preset";
40677
+ const LEGACY_PRESET_PACKAGE = "metro-react-native-babel-preset";
40678
+ const REACT_NATIVE_PACKAGE = "react-native";
40679
+ const PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION = "0.73.0";
40680
+ const LEGACY_PRESET_REFERENCE = new RegExp(`['"]${LEGACY_PRESET_SPEC}['"]`);
40302
40681
  const MODERN_PRESET_REFERENCE = new RegExp(`['"]module:@react-native/babel-preset['"]`);
40303
40682
  const ENABLE_BABEL_RUNTIME_VERSION = /enableBabelRuntime["']?\s*:\s*['"]/;
40683
+ const isReactNativeVersionAtLeastPresetRename = (rootDirectory, packageJson) => {
40684
+ const installedReactNativeManifestPath = Path.join(rootDirectory, "node_modules", REACT_NATIVE_PACKAGE, "package.json");
40685
+ const reactNativeVersionSpec = (isFile(installedReactNativeManifestPath) ? readPackageJson$1(installedReactNativeManifestPath).version : void 0) ?? getDependencySpec(packageJson, REACT_NATIVE_PACKAGE);
40686
+ if (reactNativeVersionSpec === null || reactNativeVersionSpec === void 0) return false;
40687
+ const normalizedVersionRange = import_semver.validRange(reactNativeVersionSpec);
40688
+ if (normalizedVersionRange === null) return false;
40689
+ const minimumVersion = import_semver.minVersion(normalizedVersionRange);
40690
+ return minimumVersion !== null && import_semver.gte(minimumVersion, PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION);
40691
+ };
40692
+ const canResolveLegacyPreset = (rootDirectory, packageJson) => getDependencySpec(packageJson, LEGACY_PRESET_PACKAGE) !== null || isFile(Path.join(rootDirectory, "node_modules", LEGACY_PRESET_PACKAGE, "package.json"));
40304
40693
  const checkReactNativeMetroBabelPreset = (rootDirectory) => {
40694
+ const packageJson = readPackageJson$1(Path.join(rootDirectory, "package.json"));
40695
+ const shouldReportLegacyPreset = isReactNativeVersionAtLeastPresetRename(rootDirectory, packageJson) && !canResolveLegacyPreset(rootDirectory, packageJson);
40305
40696
  for (const fileName of BABEL_CONFIG_FILE_NAMES) {
40306
40697
  const filePath = Path.join(rootDirectory, fileName);
40307
40698
  if (!isFile(filePath)) continue;
@@ -40311,7 +40702,7 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
40311
40702
  } catch {
40312
40703
  continue;
40313
40704
  }
40314
- if (contents.includes(LEGACY_PRESET_SPEC)) return [buildReactNativeDiagnostic({
40705
+ if (shouldReportLegacyPreset && LEGACY_PRESET_REFERENCE.test(contents)) return [buildReactNativeDiagnostic({
40315
40706
  filePath: fileName,
40316
40707
  rule: "rn-no-metro-babel-preset",
40317
40708
  severity: "error",
@@ -40334,12 +40725,6 @@ const checkReactNativeProject = (rootDirectory, project) => {
40334
40725
  return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
40335
40726
  };
40336
40727
  const RULE_KEY = "no-vulnerable-react-server-components";
40337
- const DEPENDENCY_SECTIONS = [
40338
- "dependencies",
40339
- "devDependencies",
40340
- "peerDependencies",
40341
- "optionalDependencies"
40342
- ];
40343
40728
  const REACT_RSC_ADVISORIES_BY_MINOR = {
40344
40729
  "19.0": {
40345
40730
  rceFixedVersion: "19.0.1",
@@ -40386,20 +40771,13 @@ const enumerateWorkspaceDirectories = (workspaceRoot) => {
40386
40771
  for (const pattern of patterns) for (const directory of resolveWorkspaceDirectories(workspaceRoot, pattern)) directories.add(directory);
40387
40772
  return [...directories];
40388
40773
  };
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
40774
  const resolveVersionInDirectory = (directory, packageName, declaredSpecOverride) => {
40397
40775
  const manifestPath = Path.join(directory, "node_modules", packageName, "package.json");
40398
40776
  if (isFile(manifestPath)) {
40399
40777
  const installedVersion = import_semver.valid(readPackageJson$1(manifestPath).version ?? null);
40400
40778
  if (installedVersion !== null) return installedVersion;
40401
40779
  }
40402
- const candidateSpecs = [readDeclaredSpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
40780
+ const candidateSpecs = [getDependencySpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
40403
40781
  for (const spec of candidateSpecs) {
40404
40782
  const pinnedVersion = spec === null ? null : import_semver.valid(spec);
40405
40783
  if (pinnedVersion !== null) return pinnedVersion;
@@ -41051,10 +41429,10 @@ const SSR_FRAMEWORKS = new Set([
41051
41429
  "gatsby",
41052
41430
  "tanstack-start"
41053
41431
  ]);
41054
- const addMajorLadder = (capabilities, name, major, earliest, latest) => {
41055
- if (major === null) return;
41056
- const cappedMajor = Math.min(major, latest);
41057
- for (let candidate = earliest; candidate <= cappedMajor; candidate += 1) capabilities.add(`${name}:${candidate}`);
41432
+ const addVersionCapabilityLadder = (capabilities, name, detectedVersion, earliest, latest) => {
41433
+ if (detectedVersion === null) return;
41434
+ const cappedVersion = Math.min(detectedVersion, latest);
41435
+ for (let candidate = earliest; candidate <= cappedVersion; candidate += 1) capabilities.add(`${name}:${candidate}`);
41058
41436
  };
41059
41437
  const buildCapabilities = (project) => {
41060
41438
  const capabilities = /* @__PURE__ */ new Set();
@@ -41067,24 +41445,77 @@ const buildCapabilities = (project) => {
41067
41445
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
41068
41446
  if (project.isStaticExport) capabilities.add("nextjs:static-export");
41069
41447
  if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
41070
- addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
41448
+ if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
41449
+ addVersionCapabilityLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
41071
41450
  if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
41072
41451
  major: 19,
41073
41452
  minor: 2
41074
41453
  })) capabilities.add("react:19.2");
41075
- if (project.tailwindVersion !== null) capabilities.add("tailwind");
41076
- if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
41077
- major: 3,
41078
- minor: 4
41079
- })) capabilities.add("tailwind:3.4");
41454
+ if (project.tailwindVersion !== null) {
41455
+ capabilities.add("tailwind");
41456
+ const tailwindVersion = parseTailwindMajorMinor(project.tailwindVersion);
41457
+ if (isMajorMinorAtLeast(tailwindVersion, {
41458
+ major: 3,
41459
+ minor: 4
41460
+ })) capabilities.add("tailwind:3.4");
41461
+ if (tailwindVersion !== null && isMajorMinorAtLeast(tailwindVersion, {
41462
+ major: 4,
41463
+ minor: 0
41464
+ })) capabilities.add("tailwind:4");
41465
+ }
41080
41466
  if (project.zodVersion !== null) capabilities.add("zod");
41081
41467
  if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
41468
+ if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
41469
+ if (project.hasMobxReact === true) capabilities.add("mobx-react");
41470
+ if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
41471
+ if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
41472
+ const mobxReactVersion = parseDependencyMajorMinor(project.mobxReactVersion);
41473
+ const mobxReactLiteVersion = parseDependencyMajorMinor(project.mobxReactLiteVersion);
41474
+ const hasMobxReactObserverMemoGuard = mobxReactVersion !== null && isMajorMinorAtLeast(mobxReactVersion, {
41475
+ major: 7,
41476
+ minor: 3
41477
+ });
41478
+ const hasMobxReactLiteObserverMemoGuard = mobxReactLiteVersion !== null && isMajorMinorAtLeast(mobxReactLiteVersion, {
41479
+ major: 3,
41480
+ minor: 3
41481
+ });
41482
+ if (hasMobxReactObserverMemoGuard) capabilities.add("mobx-react-observer-memo-guard");
41483
+ if (hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-lite-observer-memo-guard");
41484
+ if (hasMobxReactObserverMemoGuard || hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-binding-observer-memo-guard");
41485
+ if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
41486
+ if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
41487
+ if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addVersionCapabilityLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
41488
+ const mobxVersion = parseDependencyMajorMinor(project.mobxVersion);
41489
+ if (project.mobxMajorVersion === 6 && mobxVersion !== null && isMajorMinorAtLeast(mobxVersion, {
41490
+ major: 6,
41491
+ minor: 10
41492
+ })) capabilities.add("mobx:6.10");
41493
+ if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
41494
+ if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addVersionCapabilityLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
41082
41495
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
41083
41496
  if (project.hasReactCompiler) capabilities.add("react-compiler");
41084
- if (project.hasTanStackQuery) capabilities.add("tanstack-query");
41497
+ if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
41498
+ if (project.styledComponentsVersion) {
41499
+ capabilities.add("styled-components");
41500
+ const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
41501
+ if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
41502
+ }
41503
+ if (project.hasI18nLibrary) capabilities.add("i18n");
41504
+ if (project.valtioVersion !== null) capabilities.add("valtio");
41505
+ addVersionCapabilityLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
41506
+ if (project.hasRemotion) {
41507
+ capabilities.add("remotion");
41508
+ addVersionCapabilityLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
41509
+ }
41510
+ if (project.hasThree || project.hasReactThreeFiber) capabilities.add("three");
41511
+ addVersionCapabilityLadder(capabilities, "three", project.threeRelease ?? null, 145, 250);
41512
+ if (project.hasReactThreeFiber) {
41513
+ capabilities.add("r3f");
41514
+ addVersionCapabilityLadder(capabilities, "r3f", project.reactThreeFiberMajorVersion ?? null, 3, 10);
41515
+ }
41085
41516
  if (project.hasTypeScript) capabilities.add("typescript");
41086
41517
  if (project.preactVersion !== null) capabilities.add("preact");
41087
- addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
41518
+ addVersionCapabilityLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
41088
41519
  if (project.preactVersion !== null && project.reactVersion === null) capabilities.add("pure-preact");
41089
41520
  return capabilities;
41090
41521
  };
@@ -41096,7 +41527,7 @@ const getCapabilities = (project) => {
41096
41527
  capabilitiesByProject.set(project, capabilities);
41097
41528
  return capabilities;
41098
41529
  };
41099
- const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
41530
+ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen, includedTags) => {
41100
41531
  if (requires) {
41101
41532
  for (const capability of requires) if (!capabilities.has(capability)) return false;
41102
41533
  }
@@ -41107,20 +41538,29 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
41107
41538
  if (tags) {
41108
41539
  for (const tag of tags) if (ignoredTags.has(tag)) return false;
41109
41540
  }
41541
+ if (includedTags && includedTags.size > 0) {
41542
+ if (!tags?.some((tag) => includedTags.has(tag))) return false;
41543
+ }
41110
41544
  return true;
41111
41545
  };
41546
+ const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
41112
41547
  const yieldToEventLoop = () => new Promise((resolve) => {
41113
41548
  setImmediate(resolve);
41114
41549
  });
41115
41550
  const createSecurityScanSession = (rootDirectory, options) => {
41116
41551
  const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
41117
41552
  const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
41553
+ const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
41118
41554
  const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
41119
41555
  const rule = entry.rule;
41120
41556
  const scan = rule.scan;
41121
41557
  if (typeof scan !== "function") return [];
41122
- if (rule.defaultEnabled === false) return [];
41123
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
41558
+ if (!shouldEnableRuleByDefaultStatus({
41559
+ defaultEnabled: rule.defaultEnabled,
41560
+ includeTagDefaults: options.includeTagDefaults === true,
41561
+ hasIncludedTags: includedTags.size > 0
41562
+ })) return [];
41563
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) return [];
41124
41564
  return [{
41125
41565
  entry,
41126
41566
  scan,
@@ -43122,8 +43562,9 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
43122
43562
  }
43123
43563
  return enabled;
43124
43564
  };
43125
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
43126
- const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
43565
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
43566
+ const hasIncludedTags = includedTags.size > 0;
43567
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
43127
43568
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
43128
43569
  const jsPlugins = [];
43129
43570
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -43138,9 +43579,14 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
43138
43579
  if (rule.scan !== void 0) continue;
43139
43580
  if (customRulesOnly && registryEntry.originallyExternal) continue;
43140
43581
  if (rule.framework !== "global" && !rule.requires) continue;
43141
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
43582
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
43142
43583
  const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
43143
- if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
43584
+ if (!shouldEnableRuleByDefaultStatus({
43585
+ defaultEnabled: rule.defaultEnabled,
43586
+ includeTagDefaults,
43587
+ hasIncludedTags,
43588
+ hasExplicitOverride: explicitRuleOverride !== void 0
43589
+ })) continue;
43144
43590
  const severity = resolveRuleSeverityOverride({
43145
43591
  ruleKey: registryEntry.key,
43146
43592
  category: rule.category
@@ -43149,7 +43595,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
43149
43595
  enabledReactDoctorRules[registryEntry.key] = severity;
43150
43596
  }
43151
43597
  const userPluginRules = {};
43152
- if (ruleSelection !== "sidecar") for (const userPlugin of userPlugins) {
43598
+ if (ruleSelection !== "sidecar" && !hasIncludedTags) for (const userPlugin of userPlugins) {
43153
43599
  Object.assign(userPluginRules, buildUserPluginRules(userPlugin, severityControls));
43154
43600
  jsPlugins.push(userPlugin.entry);
43155
43601
  }
@@ -43366,6 +43812,19 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
43366
43812
  }
43367
43813
  };
43368
43814
  };
43815
+ const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
43816
+ const fingerprintFileContents = (filePath, fingerprintLength) => {
43817
+ const fileStats = NFS.statSync(filePath, { bigint: true });
43818
+ const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
43819
+ if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
43820
+ const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
43821
+ fingerprintCacheByFilePath.set(filePath, {
43822
+ fingerprint,
43823
+ modifiedTimeNanoseconds: fileStats.mtimeNs,
43824
+ sizeBytes: fileStats.size
43825
+ });
43826
+ return fingerprint;
43827
+ };
43369
43828
  const bundledRequire$3 = createRequire(import.meta.url);
43370
43829
  const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
43371
43830
  const resolveChildNodeVersion = (nodeBinaryPath) => {
@@ -43389,6 +43848,13 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS$1 = [
43389
43848
  "oxlint-plugin-react-doctor/package.json",
43390
43849
  "eslint-plugin-react-hooks/package.json"
43391
43850
  ];
43851
+ const resolvePluginFingerprint = () => {
43852
+ try {
43853
+ return fingerprintFileContents(bundledRequire$3.resolve("oxlint-plugin-react-doctor"), 16);
43854
+ } catch {
43855
+ return "unresolved";
43856
+ }
43857
+ };
43392
43858
  const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43393
43859
  const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
43394
43860
  for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS$1) try {
@@ -43398,6 +43864,7 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43398
43864
  } catch {
43399
43865
  versions.push(`${specifier}=missing`);
43400
43866
  }
43867
+ versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
43401
43868
  return versions;
43402
43869
  };
43403
43870
  const esmRequire = createRequire(import.meta.url);
@@ -44873,7 +45340,7 @@ const reactHooksJsPluginDropNote = (error) => {
44873
45340
  * 6. always restore disable directives + clean up the temp dir
44874
45341
  */
44875
45342
  const runOxlint = async (options) => {
44876
- 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;
45343
+ 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;
44877
45344
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
44878
45345
  const severityControls = buildRuleSeverityControls(userConfig);
44879
45346
  validateRuleRegistration();
@@ -44887,13 +45354,15 @@ const runOxlint = async (options) => {
44887
45354
  }
44888
45355
  const pluginPath = resolvePluginPath();
44889
45356
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
44890
- const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
45357
+ const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
44891
45358
  const buildConfig = (overrides) => createOxlintConfig({
44892
45359
  pluginPath,
44893
45360
  project,
44894
45361
  customRulesOnly,
44895
45362
  extendsPaths: overrides.extendsPaths,
44896
45363
  ignoredTags,
45364
+ includedTags,
45365
+ includeTagDefaults,
44897
45366
  serverAuthFunctionNames,
44898
45367
  severityControls,
44899
45368
  userPlugins,
@@ -45282,6 +45751,8 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
45282
45751
  respectInlineDisables: input.respectInlineDisables,
45283
45752
  adoptExistingLintConfig: input.adoptExistingLintConfig,
45284
45753
  ignoredTags: input.ignoredTags,
45754
+ includedTags: input.includedTags,
45755
+ includeTagDefaults: input.includeTagDefaults,
45285
45756
  userConfig: input.userConfig ?? null,
45286
45757
  configSourceDirectory: input.configSourceDirectory,
45287
45758
  onPartialFailure: (reason) => {
@@ -46130,7 +46601,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
46130
46601
  const securityScanFailedRef = yield* make$13(false);
46131
46602
  const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
46132
46603
  project,
46133
- ignoredTags: input.ignoredTags
46604
+ ignoredTags: input.ignoredTags,
46605
+ includedTags: input.includedTags,
46606
+ includeTagDefaults: input.includeTagDefaults
46134
46607
  })).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
46135
46608
  const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
46136
46609
  const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
@@ -46221,6 +46694,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
46221
46694
  respectInlineDisables: input.respectInlineDisables,
46222
46695
  adoptExistingLintConfig: input.adoptExistingLintConfig,
46223
46696
  ignoredTags: input.ignoredTags,
46697
+ includedTags: input.includedTags,
46698
+ includeTagDefaults: input.includeTagDefaults,
46224
46699
  userConfig: resolvedConfig.config ?? void 0,
46225
46700
  configSourceDirectory: resolvedConfig.configSourceDirectory ?? void 0,
46226
46701
  onFileProgress: (scannedFileCount, totalFileCount) => {
@@ -47365,7 +47840,7 @@ const makeNoopConsole = () => ({
47365
47840
  });
47366
47841
  //#endregion
47367
47842
  //#region src/cli/utils/version.ts
47368
- const VERSION = "0.8.1-dev.5332cb6";
47843
+ const VERSION = "0.8.1-dev.5b468f8";
47369
47844
  //#endregion
47370
47845
  //#region src/cli/utils/json-mode.ts
47371
47846
  let context = null;
@@ -47452,7 +47927,11 @@ const getRunId = () => {
47452
47927
  };
47453
47928
  //#endregion
47454
47929
  //#region src/cli/utils/build-run-context.ts
47455
- const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
47930
+ const ROOT_SUBCOMMANDS = new Set([
47931
+ "design",
47932
+ "install",
47933
+ "setup"
47934
+ ]);
47456
47935
  const detectInvokedVia = () => {
47457
47936
  const userAgent = process.env.npm_config_user_agent;
47458
47937
  if (!userAgent) return "unknown";
@@ -47536,7 +48015,9 @@ const buildSentryProjectContext = (projectInfo) => ({
47536
48015
  reactMajorVersion: projectInfo.reactMajorVersion,
47537
48016
  hasTypeScript: projectInfo.hasTypeScript,
47538
48017
  hasReactCompiler: projectInfo.hasReactCompiler,
47539
- hasTanStackQuery: projectInfo.hasTanStackQuery,
48018
+ tanstackQueryVersion: projectInfo.tanstackQueryVersion,
48019
+ mobxVersion: projectInfo.mobxVersion,
48020
+ styledComponentsVersion: projectInfo.styledComponentsVersion,
47540
48021
  tailwindVersion: projectInfo.tailwindVersion,
47541
48022
  zodVersion: projectInfo.zodVersion,
47542
48023
  preactVersion: projectInfo.preactVersion,
@@ -47717,13 +48198,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47717
48198
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47718
48199
  * standard `SENTRY_RELEASE` override.
47719
48200
  */
47720
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.5332cb6`;
48201
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.5b468f8`;
47721
48202
  /**
47722
48203
  * Deployment environment shown in Sentry's environment filter. Defaults to
47723
48204
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47724
48205
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47725
48206
  */
47726
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.5332cb6") ? "development" : "production");
48207
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.5b468f8") ? "development" : "production");
47727
48208
  /**
47728
48209
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47729
48210
  * (set to `0` to disable tracing) and falls back to
@@ -60049,6 +60530,8 @@ const buildScanResultCacheKey = (input) => {
60049
60530
  warnings: input.options.warnings,
60050
60531
  adoptExistingLintConfig: input.options.adoptExistingLintConfig,
60051
60532
  ignoredTags: [...input.options.ignoredTags].sort(),
60533
+ includedTags: [...input.options.includedTags].sort(),
60534
+ includeTagDefaults: input.options.includeTagDefaults,
60052
60535
  concurrency: input.options.concurrency,
60053
60536
  lintBatchOrdering: resolveLintBatchOrdering(),
60054
60537
  baselineRef: input.options.baseline?.ref,
@@ -60875,8 +61358,8 @@ const createDiagnosticEvidenceReader = (rootDirectory, options = {}) => {
60875
61358
  //#endregion
60876
61359
  //#region src/cli/utils/build-no-score-message.ts
60877
61360
  const ENTERPRISE_CONTACT_HINT = `Want something custom to your company? Contact us at ${ENTERPRISE_CONTACT_URL}.`;
60878
- const buildNoScoreMessage = (isScoreDisabled) => {
60879
- return `${isScoreDisabled ? "Score disabled by --no-score." : "Score unavailable (could not reach the score API)."} ${ENTERPRISE_CONTACT_HINT}`;
61361
+ const buildNoScoreMessage = (isScoreDisabled, disabledMessage) => {
61362
+ return `${isScoreDisabled ? disabledMessage ?? "Score disabled by --no-score." : "Score unavailable (could not reach the score API)."} ${ENTERPRISE_CONTACT_HINT}`;
60880
61363
  };
60881
61364
  //#endregion
60882
61365
  //#region src/cli/utils/render-agent-guidance.ts
@@ -62001,40 +62484,47 @@ const buildChangedLineMatcher = (directory, changedLineRanges) => {
62001
62484
  return diagnosticIntersectsLineRanges(diagnostic, ranges);
62002
62485
  };
62003
62486
  };
62004
- const buildIgnoredTags = (userConfig) => {
62487
+ const buildIgnoredTags = (userConfig, includedTags) => {
62005
62488
  const tags = /* @__PURE__ */ new Set();
62006
62489
  if (userConfig?.ignore?.tags) for (const tag of userConfig.ignore.tags) tags.add(tag);
62490
+ for (const tag of includedTags) tags.delete(tag);
62007
62491
  return tags;
62008
62492
  };
62009
- const mergeInspectOptions = (inputOptions, userConfig) => ({
62010
- lint: inputOptions.lint ?? userConfig?.lint ?? true,
62011
- deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
62012
- supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
62013
- verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
62014
- outputDirectory: inputOptions.outputDirectory || null,
62015
- scoreOnly: inputOptions.scoreOnly ?? false,
62016
- noScore: inputOptions.noScore ?? userConfig?.noScore ?? false,
62017
- isCi: inputOptions.isCi ?? false,
62018
- isCiOrCodingAgentEnvironment: isCiOrCodingAgentEnvironment(),
62019
- isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
62020
- silent: inputOptions.silent ?? false,
62021
- includePaths: inputOptions.includePaths ?? [],
62022
- customRulesOnly: userConfig?.customRulesOnly ?? false,
62023
- share: userConfig?.share ?? true,
62024
- respectInlineDisables: inputOptions.respectInlineDisables ?? userConfig?.respectInlineDisables ?? true,
62025
- warnings: inputOptions.warnings ?? userConfig?.warnings ?? true,
62026
- categoryFilters: new Set(resolveCliCategories(inputOptions.categoryFilters) ?? []),
62027
- adoptExistingLintConfig: userConfig?.adoptExistingLintConfig ?? true,
62028
- ignoredTags: buildIgnoredTags(userConfig),
62029
- outputSurface: inputOptions.outputSurface ?? "cli",
62030
- suppressRendering: inputOptions.suppressRendering ?? false,
62031
- concurrentScan: inputOptions.concurrentScan ?? false,
62032
- concurrency: inputOptions.concurrency,
62033
- maxDurationMs: inputOptions.maxDurationMs ?? null,
62034
- baseline: inputOptions.baseline ?? null,
62035
- changedLineRanges: inputOptions.changedLineRanges ?? null,
62036
- supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
62037
- });
62493
+ const mergeInspectOptions = (inputOptions, userConfig) => {
62494
+ const includedTags = inputOptions.includedTags ?? /* @__PURE__ */ new Set();
62495
+ return {
62496
+ lint: inputOptions.lint ?? userConfig?.lint ?? true,
62497
+ deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
62498
+ supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
62499
+ verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
62500
+ outputDirectory: inputOptions.outputDirectory || null,
62501
+ scoreOnly: inputOptions.scoreOnly ?? false,
62502
+ noScore: inputOptions.noScore ?? userConfig?.noScore ?? false,
62503
+ isCi: inputOptions.isCi ?? false,
62504
+ isCiOrCodingAgentEnvironment: isCiOrCodingAgentEnvironment(),
62505
+ isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
62506
+ silent: inputOptions.silent ?? false,
62507
+ includePaths: inputOptions.includePaths ?? [],
62508
+ customRulesOnly: includedTags.size > 0 ? false : userConfig?.customRulesOnly ?? false,
62509
+ share: userConfig?.share ?? true,
62510
+ respectInlineDisables: inputOptions.respectInlineDisables ?? userConfig?.respectInlineDisables ?? true,
62511
+ warnings: inputOptions.warnings ?? userConfig?.warnings ?? true,
62512
+ categoryFilters: new Set(resolveCliCategories(inputOptions.categoryFilters) ?? []),
62513
+ adoptExistingLintConfig: includedTags.size > 0 ? false : userConfig?.adoptExistingLintConfig ?? true,
62514
+ ignoredTags: buildIgnoredTags(userConfig, includedTags),
62515
+ includedTags,
62516
+ includeTagDefaults: inputOptions.includeTagDefaults ?? false,
62517
+ scoreDisabledMessage: inputOptions.scoreDisabledMessage,
62518
+ outputSurface: inputOptions.outputSurface ?? "cli",
62519
+ suppressRendering: inputOptions.suppressRendering ?? false,
62520
+ concurrentScan: inputOptions.concurrentScan ?? false,
62521
+ concurrency: inputOptions.concurrency,
62522
+ maxDurationMs: inputOptions.maxDurationMs ?? null,
62523
+ baseline: inputOptions.baseline ?? null,
62524
+ changedLineRanges: inputOptions.changedLineRanges ?? null,
62525
+ supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
62526
+ };
62527
+ };
62038
62528
  const deriveScope = (options) => {
62039
62529
  if (options.baseline) return "changed";
62040
62530
  if (options.changedLineRanges !== null) return "lines";
@@ -62165,6 +62655,8 @@ const runBaselineComparison = async (params) => {
62165
62655
  warnings: params.options.warnings,
62166
62656
  adoptExistingLintConfig: params.options.adoptExistingLintConfig,
62167
62657
  ignoredTags: params.options.ignoredTags,
62658
+ includedTags: params.options.includedTags,
62659
+ includeTagDefaults: params.options.includeTagDefaults,
62168
62660
  nodeBinaryPath: params.resolvedNodeBinaryPath ?? void 0,
62169
62661
  runDeadCode: false,
62170
62662
  isCi: params.options.isCi,
@@ -62258,6 +62750,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
62258
62750
  warnings: options.warnings,
62259
62751
  adoptExistingLintConfig: options.adoptExistingLintConfig,
62260
62752
  ignoredTags: options.ignoredTags,
62753
+ includedTags: options.includedTags,
62754
+ includeTagDefaults: options.includeTagDefaults,
62261
62755
  nodeBinaryPath: resolvedNodeBinaryPath ?? void 0,
62262
62756
  runDeadCode: options.deadCode,
62263
62757
  isCi: options.isCi,
@@ -62446,7 +62940,7 @@ const finalizeAndRender = (input) => gen(function* () {
62446
62940
  securityScanFailed
62447
62941
  });
62448
62942
  const hasSkippedChecks = skippedChecks.length > 0;
62449
- const noScoreMessage = buildNoScoreMessage(options.noScore);
62943
+ const noScoreMessage = buildNoScoreMessage(options.noScore, options.scoreDisabledMessage);
62450
62944
  const buildResult = () => ({
62451
62945
  diagnostics: [...diagnostics],
62452
62946
  score,
@@ -64551,21 +65045,25 @@ const resolveParallelFlag = (parallel) => parallel === false ? 1 : void 0;
64551
65045
  */
64552
65046
  const resolveCliInspectOptions = (flags, userConfig) => {
64553
65047
  const wantsWarningGate = pickBlockingLevel(flags, userConfig) === "warning";
65048
+ const isDesignScan = flags.design === true;
64554
65049
  return {
64555
65050
  lint: flags.lint,
64556
- deadCode: flags.deadCode,
64557
- supplyChain: flags.supplyChain,
65051
+ deadCode: isDesignScan ? false : flags.deadCode,
65052
+ supplyChain: isDesignScan ? false : flags.supplyChain,
64558
65053
  verbose: flags.verbose,
64559
65054
  outputDirectory: flags.outputDir,
64560
65055
  respectInlineDisables: flags.respectInlineDisables === false ? false : void 0,
64561
65056
  warnings: wantsWarningGate ? true : flags.warnings,
64562
65057
  scoreOnly: flags.score === true,
64563
- noScore: flags.score === false || flags.telemetry === false ? true : void 0,
65058
+ noScore: isDesignScan || flags.score === false || flags.telemetry === false ? true : void 0,
64564
65059
  isCi: isCiEnvironment(),
64565
65060
  silent: Boolean(flags.json),
64566
65061
  concurrency: resolveParallelFlag(flags.parallel),
64567
65062
  maxDurationMs: resolveMaxDurationFlag(flags.maxDuration),
64568
- categoryFilters: resolveCliCategories(flags.category)
65063
+ categoryFilters: resolveCliCategories(flags.category),
65064
+ includedTags: isDesignScan ? new Set(["design"]) : void 0,
65065
+ includeTagDefaults: isDesignScan ? true : void 0,
65066
+ scoreDisabledMessage: isDesignScan ? "Design scans do not affect the React health score." : void 0
64569
65067
  };
64570
65068
  };
64571
65069
  //#endregion
@@ -64983,7 +65481,7 @@ const maybeMigrateLegacyConfig = async (requestedDirectory, { isQuiet, isStaged
64983
65481
  if (!(!isQuiet && !isStaged && process.stdout.isTTY === true && !isCiOrCodingAgentEnvironment())) return;
64984
65482
  await runProjectMigrations(requestedDirectory);
64985
65483
  };
64986
- const inspectAction = async (directory, flags) => {
65484
+ const inspectAction = async (directory, flags, invocationCommand = "inspect") => {
64987
65485
  const isScoreOnly = Boolean(flags.score);
64988
65486
  const isJsonMode = Boolean(flags.json);
64989
65487
  const isQuiet = isScoreOnly || isJsonMode;
@@ -64997,7 +65495,7 @@ const inspectAction = async (directory, flags) => {
64997
65495
  });
64998
65496
  if (flags.jsonOut) recordCount(METRIC.jsonOutUsed, 1);
64999
65497
  }
65000
- recordCount(METRIC.cliInvoked, 1, { command: "inspect" });
65498
+ recordCount(METRIC.cliInvoked, 1, { command: invocationCommand });
65001
65499
  try {
65002
65500
  validateModeFlags(flags);
65003
65501
  if (flags.staged) setJsonReportMode("staged");
@@ -65309,6 +65807,13 @@ const inspectAction = async (directory, flags) => {
65309
65807
  }
65310
65808
  };
65311
65809
  //#endregion
65810
+ //#region src/cli/commands/design.ts
65811
+ const designAction = async (directory, flags) => inspectAction(directory, {
65812
+ ...flags,
65813
+ design: true,
65814
+ lint: flags.lint ?? true
65815
+ }, "design");
65816
+ //#endregion
65312
65817
  //#region src/cli/commands/install.ts
65313
65818
  const installAction = async (options, command) => {
65314
65819
  recordCount(METRIC.cliInvoked, 1, { command: "install" });
@@ -66145,6 +66650,7 @@ const INSTALL_FLAG_SPEC = {
66145
66650
  shortOptionsWithRequiredValues: new Set(["-c"])
66146
66651
  };
66147
66652
  const COMMAND_FLAG_SPECS = new Map([
66653
+ ["design", ROOT_FLAG_SPEC],
66148
66654
  ["install", INSTALL_FLAG_SPEC],
66149
66655
  ["setup", INSTALL_FLAG_SPEC],
66150
66656
  ["version", {
@@ -66301,6 +66807,7 @@ ${formatExampleLines([
66301
66807
  ["react-doctor --scope changed --base main", "scan only new issues vs. main"],
66302
66808
  ["react-doctor --project modules/a,modules/b", "score each module separately (names or paths)"],
66303
66809
  ["react-doctor --staged", "scan staged files (pre-commit hook)"],
66810
+ ["react-doctor design", "run the focused UI design audit"],
66304
66811
  ["react-doctor --category Security", "show only one diagnostic category"],
66305
66812
  ["react-doctor --blocking warning", "fail CI on warnings too (default: error)"],
66306
66813
  ["react-doctor --json > report.json", "write a machine-readable report"],
@@ -66334,6 +66841,20 @@ ${highlighter.dim("Managing CI:")}
66334
66841
  ${highlighter.dim("Learn more:")}
66335
66842
  ${highlighter.info(CANONICAL_GITHUB_URL)}
66336
66843
  `;
66844
+ const renderDesignHelpEpilog = () => `
66845
+ ${highlighter.dim("Examples:")}
66846
+ ${formatExampleLines([
66847
+ ["react-doctor design", "audit UI design in the current project"],
66848
+ ["react-doctor design ./apps/web", "audit one application"],
66849
+ ["react-doctor design --verbose", "show every design finding"],
66850
+ ["react-doctor design --json", "write a design-only JSON report"]
66851
+ ])}
66852
+
66853
+ ${highlighter.dim("Scope:")}
66854
+ Runs only rules tagged ${highlighter.info("design")}, including focused rules that stay opt-in during a general health scan.
66855
+ Dead-code, supply-chain, external lint-config, custom-plugin, and health-score passes are skipped.
66856
+ Standard scan flags such as ${highlighter.info("--scope")}, ${highlighter.info("--project")}, ${highlighter.info("--verbose")}, and ${highlighter.info("--json")} still work.
66857
+ `;
66337
66858
  const renderCiHelpEpilog = () => `
66338
66859
  ${highlighter.dim("Examples:")}
66339
66860
  ${formatExampleLines([
@@ -66355,6 +66876,7 @@ ${highlighter.dim("Learn more:")}
66355
66876
  const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
66356
66877
  const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").option("--include-untracked", "with --scope files/changed/lines, also scan ordinary untracked files (respects .gitignore)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
66357
66878
  program.action(inspectAction);
66879
+ program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
66358
66880
  program.command("why <location>").description("Explain why a rule fired (or why a suppression didn't apply) at a file:line").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple)").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").action((location, options) => whyAction(location, options));
66359
66881
  program.command("install").alias("setup").description("Install the react-doctor skill into your coding agents and optional git hook").option("-y, --yes", "skip prompts, install for all detected agents").option("--dry-run", "show what would be installed without writing files").option("--agent-hooks", "install native non-blocking agent hooks for Claude Code and Cursor").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderInstallHelpEpilog).action(installAction);
66360
66882
  const providerOption = ["--provider <name>", "ci provider: github-actions or gitlab-ci (auto-detected by default)"];
@@ -66403,4 +66925,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
66403
66925
  export {};
66404
66926
 
66405
66927
  //# sourceMappingURL=cli.js.map
66406
- //# debugId=24153a3f-aef9-53fd-8dff-9b016a9613fb
66928
+ //# debugId=4d155139-533f-5635-af83-9ee012355893