react-doctor 0.8.1-dev.26b4a0c → 0.8.1-dev.284b4e4

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]="f42528c1-1dda-59b5-a1a4-34d713fd7d55")}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,79 @@ const listWorkspacePackages = (rootDirectory) => {
37316
37360
  }
37317
37361
  return packages;
37318
37362
  };
37363
+ const PREFERRED_DEPENDENCY_SECTIONS = [
37364
+ "dependencies",
37365
+ "peerDependencies",
37366
+ "devDependencies"
37367
+ ];
37368
+ const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
37369
+ for (const packageName of packageNames) {
37370
+ const declaration = getDependencyDeclaration({
37371
+ packageJson,
37372
+ packageName,
37373
+ sections: PREFERRED_DEPENDENCY_SECTIONS
37374
+ });
37375
+ if (declaration.version !== null) return declaration.version;
37376
+ }
37377
+ return null;
37378
+ };
37379
+ const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
37380
+ const getTanStackQueryVersion = (packageJson) => {
37381
+ return getPreferredDependencyVersion({
37382
+ packageJson,
37383
+ packageNames: TANSTACK_REACT_QUERY_PACKAGES
37384
+ });
37385
+ };
37386
+ const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
37387
+ const getStyledComponentsVersion = (packageJson) => {
37388
+ return getPreferredDependencyVersion({
37389
+ packageJson,
37390
+ packageNames: STYLED_COMPONENTS_PACKAGES
37391
+ });
37392
+ };
37393
+ const I18N_PACKAGES = [
37394
+ "i18next",
37395
+ "react-i18next",
37396
+ "next-i18next",
37397
+ "react-intl",
37398
+ "next-intl",
37399
+ "use-intl",
37400
+ "@formatjs/intl",
37401
+ "@lingui/core",
37402
+ "@lingui/react",
37403
+ "typesafe-i18n",
37404
+ "@tolgee/react",
37405
+ "react-intl-universal"
37406
+ ];
37407
+ const hasI18nDependency = (packageJson) => {
37408
+ const allDependencies = {
37409
+ ...packageJson.peerDependencies,
37410
+ ...packageJson.dependencies,
37411
+ ...packageJson.devDependencies,
37412
+ ...packageJson.optionalDependencies
37413
+ };
37414
+ return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
37415
+ };
37319
37416
  const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
37417
+ const MOBX_REACT_PACKAGE_NAME = "mobx-react";
37418
+ const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
37419
+ const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
37420
+ const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
37421
+ const REACT_THREE_FIBER_DEPENDENCY_NAMES = ["@react-three/fiber", "react-three-fiber"];
37422
+ const REACT_THREE_FIBER_SECTIONS = [
37423
+ "dependencies",
37424
+ "peerDependencies",
37425
+ "optionalDependencies",
37426
+ "devDependencies"
37427
+ ];
37428
+ const THREE_DEPENDENCY_SECTIONS = [
37429
+ "dependencies",
37430
+ "peerDependencies",
37431
+ "optionalDependencies",
37432
+ "devDependencies"
37433
+ ];
37434
+ const REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES = [...REACT_THREE_FIBER_DEPENDENCY_NAMES, "@react-three/drei"];
37435
+ const THREE_DEPENDENCY_NAMES = [...REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES, "three"];
37320
37436
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
37321
37437
  const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
37322
37438
  const dependencyDeclaration = getDependencyDeclaration({
@@ -37327,7 +37443,7 @@ const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootD
37327
37443
  if (!dependencyDeclaration.hasDeclaration) return null;
37328
37444
  return concreteVersion ?? resolveCatalogVersion(workspacePackageJson, packageName, workspaceDirectory, dependencyDeclaration.catalogReference) ?? resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, dependencyDeclaration.catalogReference);
37329
37445
  };
37330
- const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
37446
+ const shouldReplaceWithLowerMajor = (currentVersion, nextVersion) => {
37331
37447
  if (!currentVersion) return true;
37332
37448
  const currentMajor = parseReactMajor(currentVersion);
37333
37449
  const nextMajor = parseReactMajor(nextVersion);
@@ -37335,7 +37451,62 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
37335
37451
  if (nextMajor === null) return false;
37336
37452
  return nextMajor < currentMajor;
37337
37453
  };
37338
- const evaluateManifestFacts = (facts, packageJson, directory) => {
37454
+ const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSupportedMajor) => {
37455
+ if (currentFact.version === null) return true;
37456
+ if (nextFact.version === null) return false;
37457
+ const currentMajor = getLowestDependencyMajor(currentFact.version);
37458
+ const nextMajor = getLowestDependencyMajor(nextFact.version);
37459
+ if (currentMajor === null) return false;
37460
+ if (nextMajor === null) return true;
37461
+ if (currentMajor > latestSupportedMajor) return false;
37462
+ if (nextMajor > latestSupportedMajor) return true;
37463
+ return nextMajor < currentMajor;
37464
+ };
37465
+ const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
37466
+ if (!currentVersion) return true;
37467
+ const currentMajor = getLowestDependencyMajor(currentVersion);
37468
+ const nextMajor = getLowestDependencyMajor(nextVersion);
37469
+ if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
37470
+ if (nextMajor === null) return currentMajor >= 6;
37471
+ return nextMajor < currentMajor;
37472
+ };
37473
+ const selectOldestDependencyVersion = (currentVersion, nextVersion) => {
37474
+ if (currentVersion === null || nextVersion === null) return null;
37475
+ const current = parseDependencyMajorMinor(currentVersion);
37476
+ const next = parseDependencyMajorMinor(nextVersion);
37477
+ if (current === null) return currentVersion;
37478
+ if (next === null) return nextVersion;
37479
+ if (next.major !== current.major) return next.major < current.major ? nextVersion : currentVersion;
37480
+ return next.minor < current.minor ? nextVersion : currentVersion;
37481
+ };
37482
+ const shouldReplaceMobxFact = (currentFact, nextFact) => {
37483
+ if (currentFact.sourceDirectory === null) return true;
37484
+ if (currentFact.version === null) return false;
37485
+ if (nextFact.version === null) return true;
37486
+ const currentMajor = getDependencyMajorWithinSupportedRange(currentFact.version, 6);
37487
+ const nextMajor = getDependencyMajorWithinSupportedRange(nextFact.version, 6);
37488
+ if (currentMajor === null) return false;
37489
+ if (nextMajor === null) return true;
37490
+ return selectOldestDependencyVersion(currentFact.version, nextFact.version) === nextFact.version;
37491
+ };
37492
+ const collectBindingVersion = (facts, packageJson, directory, packageName) => {
37493
+ const version = getDependencySpec(packageJson, packageName);
37494
+ if (version === null) return;
37495
+ const resolvedVersion = resolveCatalogBackedDependencyVersion({
37496
+ rootDirectory: directory,
37497
+ rootPackageJson: packageJson,
37498
+ packageName,
37499
+ version
37500
+ });
37501
+ if (packageName === MOBX_REACT_PACKAGE_NAME) {
37502
+ facts.mobxReactVersion = facts.hasMobxReact ? selectOldestDependencyVersion(facts.mobxReactVersion, resolvedVersion) : resolvedVersion;
37503
+ facts.hasMobxReact = true;
37504
+ return;
37505
+ }
37506
+ facts.mobxReactLiteVersion = facts.hasMobxReactLite ? selectOldestDependencyVersion(facts.mobxReactLiteVersion, resolvedVersion) : resolvedVersion;
37507
+ facts.hasMobxReactLite = true;
37508
+ };
37509
+ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
37339
37510
  if (facts.expo.version === null) {
37340
37511
  const spec = getDependencySpec(packageJson, "expo");
37341
37512
  if (spec !== null) facts.expo = {
@@ -37357,13 +37528,113 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
37357
37528
  sourceDirectory: directory
37358
37529
  };
37359
37530
  }
37531
+ const mobxSpec = getDependencySpec(packageJson, "mobx");
37532
+ if (mobxSpec !== null) {
37533
+ const nextMobxFact = {
37534
+ version: resolveCatalogBackedDependencyVersion({
37535
+ rootDirectory: directory,
37536
+ rootPackageJson: packageJson,
37537
+ packageName: "mobx",
37538
+ version: mobxSpec
37539
+ }),
37540
+ sourceDirectory: directory
37541
+ };
37542
+ if (shouldReplaceMobxFact(facts.mobx, nextMobxFact)) facts.mobx = nextMobxFact;
37543
+ }
37544
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_PACKAGE_NAME);
37545
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_LITE_PACKAGE_NAME);
37546
+ facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
37547
+ facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
37548
+ const zustandSpec = getDependencySpec(packageJson, "zustand");
37549
+ if (zustandSpec !== null) {
37550
+ const nextZustandFact = {
37551
+ version: resolveCatalogBackedDependencyVersion({
37552
+ rootDirectory: directory,
37553
+ rootPackageJson: packageJson,
37554
+ packageName: "zustand",
37555
+ version: zustandSpec
37556
+ }),
37557
+ sourceDirectory: directory
37558
+ };
37559
+ if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
37560
+ }
37360
37561
  if (facts.reanimatedVersion === null) {
37361
37562
  const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
37362
37563
  if (spec !== null) facts.reanimatedVersion = spec;
37363
37564
  }
37565
+ if (facts.valtioVersion === null) {
37566
+ const spec = getDependencySpec(packageJson, "valtio");
37567
+ if (spec !== null) facts.valtioVersion = spec;
37568
+ }
37569
+ facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
37570
+ const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
37571
+ rootDirectory: directory,
37572
+ rootPackageJson: packageJson,
37573
+ packageName: "styled-components",
37574
+ version: getStyledComponentsVersion(packageJson)
37575
+ });
37576
+ if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
37577
+ facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
37578
+ for (const packageName of REACT_THREE_FIBER_DEPENDENCY_NAMES) {
37579
+ const version = resolveCatalogBackedDependencyVersion({
37580
+ rootDirectory,
37581
+ rootPackageJson,
37582
+ sourceDirectory: directory,
37583
+ sourcePackageJson: packageJson,
37584
+ packageName,
37585
+ version: getDependencyDeclaration({
37586
+ packageName,
37587
+ packageJson,
37588
+ sections: REACT_THREE_FIBER_SECTIONS
37589
+ }).version
37590
+ });
37591
+ if (version === null) continue;
37592
+ if (shouldReplaceWithLowerMajor(facts.reactThreeFiber.version, version)) facts.reactThreeFiber = {
37593
+ packageName,
37594
+ version,
37595
+ sourceDirectory: directory
37596
+ };
37597
+ }
37598
+ const threeVersion = resolveCatalogBackedDependencyVersion({
37599
+ rootDirectory,
37600
+ rootPackageJson,
37601
+ sourceDirectory: directory,
37602
+ sourcePackageJson: packageJson,
37603
+ packageName: "three",
37604
+ version: getDependencyDeclaration({
37605
+ packageName: "three",
37606
+ packageJson,
37607
+ sections: THREE_DEPENDENCY_SECTIONS
37608
+ }).version
37609
+ });
37610
+ if (threeVersion !== null) {
37611
+ const currentRelease = parseThreeRelease(facts.threeVersion);
37612
+ const nextRelease = parseThreeRelease(threeVersion);
37613
+ if (facts.threeVersion === null || nextRelease !== null && (currentRelease === null || nextRelease < currentRelease)) facts.threeVersion = threeVersion;
37614
+ }
37364
37615
  facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
37365
37616
  facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
37366
37617
  facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
37618
+ const remotionSpec = getDependencySpec(packageJson, "remotion");
37619
+ if (remotionSpec !== null) {
37620
+ facts.hasRemotionDependency = true;
37621
+ const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
37622
+ rootDirectory,
37623
+ rootPackageJson,
37624
+ packageName: "remotion",
37625
+ version: remotionSpec
37626
+ });
37627
+ const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
37628
+ if (remotionMajorVersion === null) {
37629
+ facts.hasUnknownRemotionVersion = true;
37630
+ facts.remotionVersion = null;
37631
+ } else if (!facts.hasUnknownRemotionVersion) {
37632
+ const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
37633
+ if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
37634
+ }
37635
+ }
37636
+ facts.hasThree = facts.hasThree || THREE_DEPENDENCY_NAMES.some((dependencyName) => getDependencySpec(packageJson, dependencyName) !== null);
37637
+ facts.hasReactThreeFiber = facts.hasReactThreeFiber || REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES.some((dependencyName) => getDependencySpec(packageJson, dependencyName) !== null);
37367
37638
  };
37368
37639
  const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
37369
37640
  const facts = {
@@ -37383,12 +37654,41 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37383
37654
  version: null,
37384
37655
  sourceDirectory: null
37385
37656
  },
37657
+ valtioVersion: null,
37658
+ mobx: {
37659
+ version: null,
37660
+ sourceDirectory: null
37661
+ },
37662
+ hasMobxReact: false,
37663
+ mobxReactVersion: null,
37664
+ hasMobxReactLite: false,
37665
+ mobxReactLiteVersion: null,
37666
+ hasMobxStateTree: false,
37667
+ hasMobxReactObserver: false,
37668
+ zustand: {
37669
+ version: null,
37670
+ sourceDirectory: null
37671
+ },
37672
+ tanstackQueryVersion: null,
37673
+ styledComponentsVersion: null,
37674
+ hasI18nLibrary: false,
37386
37675
  hasReactNativeAwarePackage: false,
37387
37676
  hasReanimatedAwarePackage: false,
37388
37677
  hasSsrDependency: false,
37678
+ hasRemotionDependency: false,
37679
+ hasUnknownRemotionVersion: false,
37680
+ remotionVersion: null,
37681
+ hasThree: false,
37682
+ threeVersion: null,
37683
+ hasReactThreeFiber: false,
37684
+ reactThreeFiber: {
37685
+ packageName: null,
37686
+ version: null,
37687
+ sourceDirectory: null
37688
+ },
37389
37689
  reanimatedVersion: null
37390
37690
  };
37391
- evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
37691
+ evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
37392
37692
  let isReactGroupSettled = !collectReactGroup;
37393
37693
  const visitedDirectories = /* @__PURE__ */ new Set();
37394
37694
  for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
@@ -37397,7 +37697,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37397
37697
  if (visitedDirectories.has(workspaceDirectory)) continue;
37398
37698
  visitedDirectories.add(workspaceDirectory);
37399
37699
  const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
37400
- evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
37700
+ evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory, rootDirectory, rootPackageJson);
37401
37701
  const info = extractDependencyInfo(workspacePackageJson);
37402
37702
  if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
37403
37703
  if (isReactGroupSettled) continue;
@@ -37428,7 +37728,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37428
37728
  workspaceDirectory,
37429
37729
  workspacePackageJson
37430
37730
  });
37431
- if (reactVersion && shouldReplaceReactVersion(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
37731
+ if (reactVersion && shouldReplaceWithLowerMajor(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
37432
37732
  if (tailwindVersion && !facts.tailwindVersion) facts.tailwindVersion = tailwindVersion;
37433
37733
  if (zodVersion && !facts.zodVersion) facts.zodVersion = zodVersion;
37434
37734
  const settledReactMajor = parseReactMajor(facts.reactVersion);
@@ -37618,11 +37918,35 @@ const discoverProjectWithoutPackageJson = (directory) => {
37618
37918
  tailwindVersion: null,
37619
37919
  zodVersion: null,
37620
37920
  zodMajorVersion: null,
37921
+ mobxVersion: null,
37922
+ mobxMajorVersion: null,
37923
+ hasMobxReact: false,
37924
+ mobxReactVersion: null,
37925
+ hasMobxReactLite: false,
37926
+ mobxReactLiteVersion: null,
37927
+ hasMobxStateTree: false,
37928
+ hasMobxReactObserver: false,
37929
+ zustandVersion: null,
37930
+ zustandMajorVersion: null,
37621
37931
  framework: "unknown",
37622
37932
  hasTypeScript: hasOwnTsConfig,
37623
37933
  hasReactCompiler: false,
37624
37934
  hasReactCompilerLintPlugin: false,
37625
37935
  hasTanStackQuery: false,
37936
+ valtioVersion: null,
37937
+ valtioMajorVersion: null,
37938
+ hasRemotion: false,
37939
+ remotionVersion: null,
37940
+ remotionMajorVersion: null,
37941
+ hasI18nLibrary: false,
37942
+ tanstackQueryVersion: null,
37943
+ styledComponentsVersion: null,
37944
+ hasThree: false,
37945
+ threeVersion: null,
37946
+ threeRelease: null,
37947
+ hasReactThreeFiber: false,
37948
+ reactThreeFiberVersion: null,
37949
+ reactThreeFiberMajorVersion: null,
37626
37950
  hasSsrDependency: false,
37627
37951
  preactVersion: null,
37628
37952
  preactMajorVersion: null,
@@ -37721,6 +38045,12 @@ const discoverProject = (directory) => {
37721
38045
  packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
37722
38046
  version: workspaceFacts.shopifyFlashList.version
37723
38047
  }) : null;
38048
+ const zustandVersion = resolveCatalogBackedDependencyVersion({
38049
+ rootDirectory: directory,
38050
+ rootPackageJson: packageJson,
38051
+ packageName: "zustand",
38052
+ version: workspaceFacts.zustand.version
38053
+ });
37724
38054
  const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
37725
38055
  const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
37726
38056
  const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
@@ -37729,7 +38059,33 @@ const discoverProject = (directory) => {
37729
38059
  packageName: "next",
37730
38060
  version: workspaceFacts.next.version
37731
38061
  }) : null;
38062
+ const valtioVersion = resolveCatalogBackedDependencyVersion({
38063
+ rootDirectory: directory,
38064
+ rootPackageJson: packageJson,
38065
+ packageName: "valtio",
38066
+ version: workspaceFacts.valtioVersion
38067
+ });
38068
+ const mobxVersion = resolveCatalogBackedDependencyVersion({
38069
+ rootDirectory: directory,
38070
+ rootPackageJson: packageJson,
38071
+ packageName: "mobx",
38072
+ version: workspaceFacts.mobx.version
38073
+ });
37732
38074
  const preactVersion = getPreactVersion(packageJson);
38075
+ const remotionVersion = workspaceFacts.remotionVersion;
38076
+ const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
38077
+ const reactThreeFiberVersion = workspaceFacts.reactThreeFiber.packageName ? resolveCatalogBackedDependencyVersion({
38078
+ rootDirectory: directory,
38079
+ rootPackageJson: packageJson,
38080
+ packageName: workspaceFacts.reactThreeFiber.packageName,
38081
+ version: workspaceFacts.reactThreeFiber.version
38082
+ }) : null;
38083
+ const threeVersion = resolveCatalogBackedDependencyVersion({
38084
+ rootDirectory: directory,
38085
+ rootPackageJson: packageJson,
38086
+ packageName: "three",
38087
+ version: workspaceFacts.threeVersion
38088
+ });
37733
38089
  const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
37734
38090
  const projectInfo = {
37735
38091
  rootDirectory: directory,
@@ -37739,11 +38095,35 @@ const discoverProject = (directory) => {
37739
38095
  tailwindVersion,
37740
38096
  zodVersion,
37741
38097
  zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
38098
+ mobxVersion,
38099
+ mobxMajorVersion: mobxVersion === null ? null : getDependencyMajorWithinSupportedRange(mobxVersion, 6),
38100
+ hasMobxReact: workspaceFacts.hasMobxReact,
38101
+ mobxReactVersion: workspaceFacts.mobxReactVersion,
38102
+ hasMobxReactLite: workspaceFacts.hasMobxReactLite,
38103
+ mobxReactLiteVersion: workspaceFacts.mobxReactLiteVersion,
38104
+ hasMobxStateTree: workspaceFacts.hasMobxStateTree,
38105
+ hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
38106
+ zustandVersion,
38107
+ zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
37742
38108
  framework,
37743
38109
  hasTypeScript,
37744
38110
  hasReactCompiler: detectReactCompiler(directory, packageJson),
37745
38111
  hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
37746
- hasTanStackQuery: hasTanStackQuery(packageJson),
38112
+ hasTanStackQuery: tanstackQueryVersion !== null,
38113
+ hasI18nLibrary: workspaceFacts.hasI18nLibrary,
38114
+ tanstackQueryVersion,
38115
+ styledComponentsVersion: workspaceFacts.styledComponentsVersion,
38116
+ valtioVersion,
38117
+ valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
38118
+ hasRemotion: workspaceFacts.hasRemotionDependency,
38119
+ remotionVersion,
38120
+ remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
38121
+ hasThree: workspaceFacts.hasThree,
38122
+ threeVersion,
38123
+ threeRelease: parseThreeRelease(threeVersion),
38124
+ hasReactThreeFiber: workspaceFacts.hasReactThreeFiber,
38125
+ reactThreeFiberVersion,
38126
+ reactThreeFiberMajorVersion: reactThreeFiberVersion === null ? null : getLowestDependencyMajor(reactThreeFiberVersion),
37747
38127
  hasSsrDependency: workspaceFacts.hasSsrDependency,
37748
38128
  preactVersion,
37749
38129
  preactMajorVersion: parseReactMajor(preactVersion),
@@ -37977,7 +38357,6 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
37977
38357
  "react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
37978
38358
  "react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
37979
38359
  "react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
37980
- "react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
37981
38360
  "react/jsx-no-undef": "react-doctor/jsx-no-undef",
37982
38361
  "react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
37983
38362
  "react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
@@ -40299,9 +40678,25 @@ const BABEL_CONFIG_FILE_NAMES = [
40299
40678
  ".babelrc.json"
40300
40679
  ];
40301
40680
  const LEGACY_PRESET_SPEC = "module:metro-react-native-babel-preset";
40681
+ const LEGACY_PRESET_PACKAGE = "metro-react-native-babel-preset";
40682
+ const REACT_NATIVE_PACKAGE = "react-native";
40683
+ const PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION = "0.73.0";
40684
+ const LEGACY_PRESET_REFERENCE = new RegExp(`['"]${LEGACY_PRESET_SPEC}['"]`);
40302
40685
  const MODERN_PRESET_REFERENCE = new RegExp(`['"]module:@react-native/babel-preset['"]`);
40303
40686
  const ENABLE_BABEL_RUNTIME_VERSION = /enableBabelRuntime["']?\s*:\s*['"]/;
40687
+ const isReactNativeVersionAtLeastPresetRename = (rootDirectory, packageJson) => {
40688
+ const installedReactNativeManifestPath = Path.join(rootDirectory, "node_modules", REACT_NATIVE_PACKAGE, "package.json");
40689
+ const reactNativeVersionSpec = (isFile(installedReactNativeManifestPath) ? readPackageJson$1(installedReactNativeManifestPath).version : void 0) ?? getDependencySpec(packageJson, REACT_NATIVE_PACKAGE);
40690
+ if (reactNativeVersionSpec === null || reactNativeVersionSpec === void 0) return false;
40691
+ const normalizedVersionRange = import_semver.validRange(reactNativeVersionSpec);
40692
+ if (normalizedVersionRange === null) return false;
40693
+ const minimumVersion = import_semver.minVersion(normalizedVersionRange);
40694
+ return minimumVersion !== null && import_semver.gte(minimumVersion, PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION);
40695
+ };
40696
+ const canResolveLegacyPreset = (rootDirectory, packageJson) => getDependencySpec(packageJson, LEGACY_PRESET_PACKAGE) !== null || isFile(Path.join(rootDirectory, "node_modules", LEGACY_PRESET_PACKAGE, "package.json"));
40304
40697
  const checkReactNativeMetroBabelPreset = (rootDirectory) => {
40698
+ const packageJson = readPackageJson$1(Path.join(rootDirectory, "package.json"));
40699
+ const shouldReportLegacyPreset = isReactNativeVersionAtLeastPresetRename(rootDirectory, packageJson) && !canResolveLegacyPreset(rootDirectory, packageJson);
40305
40700
  for (const fileName of BABEL_CONFIG_FILE_NAMES) {
40306
40701
  const filePath = Path.join(rootDirectory, fileName);
40307
40702
  if (!isFile(filePath)) continue;
@@ -40311,7 +40706,7 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
40311
40706
  } catch {
40312
40707
  continue;
40313
40708
  }
40314
- if (contents.includes(LEGACY_PRESET_SPEC)) return [buildReactNativeDiagnostic({
40709
+ if (shouldReportLegacyPreset && LEGACY_PRESET_REFERENCE.test(contents)) return [buildReactNativeDiagnostic({
40315
40710
  filePath: fileName,
40316
40711
  rule: "rn-no-metro-babel-preset",
40317
40712
  severity: "error",
@@ -40334,12 +40729,6 @@ const checkReactNativeProject = (rootDirectory, project) => {
40334
40729
  return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
40335
40730
  };
40336
40731
  const RULE_KEY = "no-vulnerable-react-server-components";
40337
- const DEPENDENCY_SECTIONS = [
40338
- "dependencies",
40339
- "devDependencies",
40340
- "peerDependencies",
40341
- "optionalDependencies"
40342
- ];
40343
40732
  const REACT_RSC_ADVISORIES_BY_MINOR = {
40344
40733
  "19.0": {
40345
40734
  rceFixedVersion: "19.0.1",
@@ -40386,20 +40775,13 @@ const enumerateWorkspaceDirectories = (workspaceRoot) => {
40386
40775
  for (const pattern of patterns) for (const directory of resolveWorkspaceDirectories(workspaceRoot, pattern)) directories.add(directory);
40387
40776
  return [...directories];
40388
40777
  };
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
40778
  const resolveVersionInDirectory = (directory, packageName, declaredSpecOverride) => {
40397
40779
  const manifestPath = Path.join(directory, "node_modules", packageName, "package.json");
40398
40780
  if (isFile(manifestPath)) {
40399
40781
  const installedVersion = import_semver.valid(readPackageJson$1(manifestPath).version ?? null);
40400
40782
  if (installedVersion !== null) return installedVersion;
40401
40783
  }
40402
- const candidateSpecs = [readDeclaredSpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
40784
+ const candidateSpecs = [getDependencySpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
40403
40785
  for (const spec of candidateSpecs) {
40404
40786
  const pinnedVersion = spec === null ? null : import_semver.valid(spec);
40405
40787
  if (pinnedVersion !== null) return pinnedVersion;
@@ -41051,10 +41433,10 @@ const SSR_FRAMEWORKS = new Set([
41051
41433
  "gatsby",
41052
41434
  "tanstack-start"
41053
41435
  ]);
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}`);
41436
+ const addVersionCapabilityLadder = (capabilities, name, detectedVersion, earliest, latest) => {
41437
+ if (detectedVersion === null) return;
41438
+ const cappedVersion = Math.min(detectedVersion, latest);
41439
+ for (let candidate = earliest; candidate <= cappedVersion; candidate += 1) capabilities.add(`${name}:${candidate}`);
41058
41440
  };
41059
41441
  const buildCapabilities = (project) => {
41060
41442
  const capabilities = /* @__PURE__ */ new Set();
@@ -41067,24 +41449,77 @@ const buildCapabilities = (project) => {
41067
41449
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
41068
41450
  if (project.isStaticExport) capabilities.add("nextjs:static-export");
41069
41451
  if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
41070
- addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
41452
+ if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
41453
+ addVersionCapabilityLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
41071
41454
  if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
41072
41455
  major: 19,
41073
41456
  minor: 2
41074
41457
  })) 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");
41458
+ if (project.tailwindVersion !== null) {
41459
+ capabilities.add("tailwind");
41460
+ const tailwindVersion = parseTailwindMajorMinor(project.tailwindVersion);
41461
+ if (isMajorMinorAtLeast(tailwindVersion, {
41462
+ major: 3,
41463
+ minor: 4
41464
+ })) capabilities.add("tailwind:3.4");
41465
+ if (tailwindVersion !== null && isMajorMinorAtLeast(tailwindVersion, {
41466
+ major: 4,
41467
+ minor: 0
41468
+ })) capabilities.add("tailwind:4");
41469
+ }
41080
41470
  if (project.zodVersion !== null) capabilities.add("zod");
41081
41471
  if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
41472
+ if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
41473
+ if (project.hasMobxReact === true) capabilities.add("mobx-react");
41474
+ if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
41475
+ if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
41476
+ const mobxReactVersion = parseDependencyMajorMinor(project.mobxReactVersion);
41477
+ const mobxReactLiteVersion = parseDependencyMajorMinor(project.mobxReactLiteVersion);
41478
+ const hasMobxReactObserverMemoGuard = mobxReactVersion !== null && isMajorMinorAtLeast(mobxReactVersion, {
41479
+ major: 7,
41480
+ minor: 3
41481
+ });
41482
+ const hasMobxReactLiteObserverMemoGuard = mobxReactLiteVersion !== null && isMajorMinorAtLeast(mobxReactLiteVersion, {
41483
+ major: 3,
41484
+ minor: 3
41485
+ });
41486
+ if (hasMobxReactObserverMemoGuard) capabilities.add("mobx-react-observer-memo-guard");
41487
+ if (hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-lite-observer-memo-guard");
41488
+ if (hasMobxReactObserverMemoGuard || hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-binding-observer-memo-guard");
41489
+ if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
41490
+ if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
41491
+ if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addVersionCapabilityLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
41492
+ const mobxVersion = parseDependencyMajorMinor(project.mobxVersion);
41493
+ if (project.mobxMajorVersion === 6 && mobxVersion !== null && isMajorMinorAtLeast(mobxVersion, {
41494
+ major: 6,
41495
+ minor: 10
41496
+ })) capabilities.add("mobx:6.10");
41497
+ if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
41498
+ if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addVersionCapabilityLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
41082
41499
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
41083
41500
  if (project.hasReactCompiler) capabilities.add("react-compiler");
41084
- if (project.hasTanStackQuery) capabilities.add("tanstack-query");
41501
+ if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
41502
+ if (project.styledComponentsVersion) {
41503
+ capabilities.add("styled-components");
41504
+ const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
41505
+ if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
41506
+ }
41507
+ if (project.hasI18nLibrary) capabilities.add("i18n");
41508
+ if (project.valtioVersion !== null) capabilities.add("valtio");
41509
+ addVersionCapabilityLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
41510
+ if (project.hasRemotion) {
41511
+ capabilities.add("remotion");
41512
+ addVersionCapabilityLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
41513
+ }
41514
+ if (project.hasThree || project.hasReactThreeFiber) capabilities.add("three");
41515
+ addVersionCapabilityLadder(capabilities, "three", project.threeRelease ?? null, 145, 250);
41516
+ if (project.hasReactThreeFiber) {
41517
+ capabilities.add("r3f");
41518
+ addVersionCapabilityLadder(capabilities, "r3f", project.reactThreeFiberMajorVersion ?? null, 3, 10);
41519
+ }
41085
41520
  if (project.hasTypeScript) capabilities.add("typescript");
41086
41521
  if (project.preactVersion !== null) capabilities.add("preact");
41087
- addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
41522
+ addVersionCapabilityLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
41088
41523
  if (project.preactVersion !== null && project.reactVersion === null) capabilities.add("pure-preact");
41089
41524
  return capabilities;
41090
41525
  };
@@ -41096,7 +41531,7 @@ const getCapabilities = (project) => {
41096
41531
  capabilitiesByProject.set(project, capabilities);
41097
41532
  return capabilities;
41098
41533
  };
41099
- const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
41534
+ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen, includedTags) => {
41100
41535
  if (requires) {
41101
41536
  for (const capability of requires) if (!capabilities.has(capability)) return false;
41102
41537
  }
@@ -41107,20 +41542,29 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
41107
41542
  if (tags) {
41108
41543
  for (const tag of tags) if (ignoredTags.has(tag)) return false;
41109
41544
  }
41545
+ if (includedTags && includedTags.size > 0) {
41546
+ if (!tags?.some((tag) => includedTags.has(tag))) return false;
41547
+ }
41110
41548
  return true;
41111
41549
  };
41550
+ const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
41112
41551
  const yieldToEventLoop = () => new Promise((resolve) => {
41113
41552
  setImmediate(resolve);
41114
41553
  });
41115
41554
  const createSecurityScanSession = (rootDirectory, options) => {
41116
41555
  const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
41117
41556
  const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
41557
+ const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
41118
41558
  const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
41119
41559
  const rule = entry.rule;
41120
41560
  const scan = rule.scan;
41121
41561
  if (typeof scan !== "function") return [];
41122
- if (rule.defaultEnabled === false) return [];
41123
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
41562
+ if (!shouldEnableRuleByDefaultStatus({
41563
+ defaultEnabled: rule.defaultEnabled,
41564
+ includeTagDefaults: options.includeTagDefaults === true,
41565
+ hasIncludedTags: includedTags.size > 0
41566
+ })) return [];
41567
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) return [];
41124
41568
  return [{
41125
41569
  entry,
41126
41570
  scan,
@@ -43122,8 +43566,9 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
43122
43566
  }
43123
43567
  return enabled;
43124
43568
  };
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);
43569
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
43570
+ const hasIncludedTags = includedTags.size > 0;
43571
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
43127
43572
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
43128
43573
  const jsPlugins = [];
43129
43574
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -43138,9 +43583,14 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
43138
43583
  if (rule.scan !== void 0) continue;
43139
43584
  if (customRulesOnly && registryEntry.originallyExternal) continue;
43140
43585
  if (rule.framework !== "global" && !rule.requires) continue;
43141
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
43586
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
43142
43587
  const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
43143
- if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
43588
+ if (!shouldEnableRuleByDefaultStatus({
43589
+ defaultEnabled: rule.defaultEnabled,
43590
+ includeTagDefaults,
43591
+ hasIncludedTags,
43592
+ hasExplicitOverride: explicitRuleOverride !== void 0
43593
+ })) continue;
43144
43594
  const severity = resolveRuleSeverityOverride({
43145
43595
  ruleKey: registryEntry.key,
43146
43596
  category: rule.category
@@ -43149,7 +43599,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
43149
43599
  enabledReactDoctorRules[registryEntry.key] = severity;
43150
43600
  }
43151
43601
  const userPluginRules = {};
43152
- if (ruleSelection !== "sidecar") for (const userPlugin of userPlugins) {
43602
+ if (ruleSelection !== "sidecar" && !hasIncludedTags) for (const userPlugin of userPlugins) {
43153
43603
  Object.assign(userPluginRules, buildUserPluginRules(userPlugin, severityControls));
43154
43604
  jsPlugins.push(userPlugin.entry);
43155
43605
  }
@@ -43366,6 +43816,19 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
43366
43816
  }
43367
43817
  };
43368
43818
  };
43819
+ const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
43820
+ const fingerprintFileContents = (filePath, fingerprintLength) => {
43821
+ const fileStats = NFS.statSync(filePath, { bigint: true });
43822
+ const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
43823
+ if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
43824
+ const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
43825
+ fingerprintCacheByFilePath.set(filePath, {
43826
+ fingerprint,
43827
+ modifiedTimeNanoseconds: fileStats.mtimeNs,
43828
+ sizeBytes: fileStats.size
43829
+ });
43830
+ return fingerprint;
43831
+ };
43369
43832
  const bundledRequire$3 = createRequire(import.meta.url);
43370
43833
  const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
43371
43834
  const resolveChildNodeVersion = (nodeBinaryPath) => {
@@ -43389,6 +43852,13 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS$1 = [
43389
43852
  "oxlint-plugin-react-doctor/package.json",
43390
43853
  "eslint-plugin-react-hooks/package.json"
43391
43854
  ];
43855
+ const resolvePluginFingerprint = () => {
43856
+ try {
43857
+ return fingerprintFileContents(bundledRequire$3.resolve("oxlint-plugin-react-doctor"), 16);
43858
+ } catch {
43859
+ return "unresolved";
43860
+ }
43861
+ };
43392
43862
  const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43393
43863
  const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
43394
43864
  for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS$1) try {
@@ -43398,6 +43868,7 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43398
43868
  } catch {
43399
43869
  versions.push(`${specifier}=missing`);
43400
43870
  }
43871
+ versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
43401
43872
  return versions;
43402
43873
  };
43403
43874
  const esmRequire = createRequire(import.meta.url);
@@ -44873,7 +45344,7 @@ const reactHooksJsPluginDropNote = (error) => {
44873
45344
  * 6. always restore disable directives + clean up the temp dir
44874
45345
  */
44875
45346
  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;
45347
+ 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
45348
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
44878
45349
  const severityControls = buildRuleSeverityControls(userConfig);
44879
45350
  validateRuleRegistration();
@@ -44887,13 +45358,15 @@ const runOxlint = async (options) => {
44887
45358
  }
44888
45359
  const pluginPath = resolvePluginPath();
44889
45360
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
44890
- const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
45361
+ const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
44891
45362
  const buildConfig = (overrides) => createOxlintConfig({
44892
45363
  pluginPath,
44893
45364
  project,
44894
45365
  customRulesOnly,
44895
45366
  extendsPaths: overrides.extendsPaths,
44896
45367
  ignoredTags,
45368
+ includedTags,
45369
+ includeTagDefaults,
44897
45370
  serverAuthFunctionNames,
44898
45371
  severityControls,
44899
45372
  userPlugins,
@@ -45282,6 +45755,8 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
45282
45755
  respectInlineDisables: input.respectInlineDisables,
45283
45756
  adoptExistingLintConfig: input.adoptExistingLintConfig,
45284
45757
  ignoredTags: input.ignoredTags,
45758
+ includedTags: input.includedTags,
45759
+ includeTagDefaults: input.includeTagDefaults,
45285
45760
  userConfig: input.userConfig ?? null,
45286
45761
  configSourceDirectory: input.configSourceDirectory,
45287
45762
  onPartialFailure: (reason) => {
@@ -46130,7 +46605,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
46130
46605
  const securityScanFailedRef = yield* make$13(false);
46131
46606
  const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
46132
46607
  project,
46133
- ignoredTags: input.ignoredTags
46608
+ ignoredTags: input.ignoredTags,
46609
+ includedTags: input.includedTags,
46610
+ includeTagDefaults: input.includeTagDefaults
46134
46611
  })).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
46135
46612
  const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
46136
46613
  const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
@@ -46221,6 +46698,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
46221
46698
  respectInlineDisables: input.respectInlineDisables,
46222
46699
  adoptExistingLintConfig: input.adoptExistingLintConfig,
46223
46700
  ignoredTags: input.ignoredTags,
46701
+ includedTags: input.includedTags,
46702
+ includeTagDefaults: input.includeTagDefaults,
46224
46703
  userConfig: resolvedConfig.config ?? void 0,
46225
46704
  configSourceDirectory: resolvedConfig.configSourceDirectory ?? void 0,
46226
46705
  onFileProgress: (scannedFileCount, totalFileCount) => {
@@ -47365,7 +47844,7 @@ const makeNoopConsole = () => ({
47365
47844
  });
47366
47845
  //#endregion
47367
47846
  //#region src/cli/utils/version.ts
47368
- const VERSION = "0.8.1-dev.26b4a0c";
47847
+ const VERSION = "0.8.1-dev.284b4e4";
47369
47848
  //#endregion
47370
47849
  //#region src/cli/utils/json-mode.ts
47371
47850
  let context = null;
@@ -47452,7 +47931,11 @@ const getRunId = () => {
47452
47931
  };
47453
47932
  //#endregion
47454
47933
  //#region src/cli/utils/build-run-context.ts
47455
- const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
47934
+ const ROOT_SUBCOMMANDS = new Set([
47935
+ "design",
47936
+ "install",
47937
+ "setup"
47938
+ ]);
47456
47939
  const detectInvokedVia = () => {
47457
47940
  const userAgent = process.env.npm_config_user_agent;
47458
47941
  if (!userAgent) return "unknown";
@@ -47536,7 +48019,9 @@ const buildSentryProjectContext = (projectInfo) => ({
47536
48019
  reactMajorVersion: projectInfo.reactMajorVersion,
47537
48020
  hasTypeScript: projectInfo.hasTypeScript,
47538
48021
  hasReactCompiler: projectInfo.hasReactCompiler,
47539
- hasTanStackQuery: projectInfo.hasTanStackQuery,
48022
+ tanstackQueryVersion: projectInfo.tanstackQueryVersion,
48023
+ mobxVersion: projectInfo.mobxVersion,
48024
+ styledComponentsVersion: projectInfo.styledComponentsVersion,
47540
48025
  tailwindVersion: projectInfo.tailwindVersion,
47541
48026
  zodVersion: projectInfo.zodVersion,
47542
48027
  preactVersion: projectInfo.preactVersion,
@@ -47717,13 +48202,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47717
48202
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47718
48203
  * standard `SENTRY_RELEASE` override.
47719
48204
  */
47720
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.26b4a0c`;
48205
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.284b4e4`;
47721
48206
  /**
47722
48207
  * Deployment environment shown in Sentry's environment filter. Defaults to
47723
48208
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47724
48209
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47725
48210
  */
47726
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.26b4a0c") ? "development" : "production");
48211
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.284b4e4") ? "development" : "production");
47727
48212
  /**
47728
48213
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47729
48214
  * (set to `0` to disable tracing) and falls back to
@@ -60049,6 +60534,8 @@ const buildScanResultCacheKey = (input) => {
60049
60534
  warnings: input.options.warnings,
60050
60535
  adoptExistingLintConfig: input.options.adoptExistingLintConfig,
60051
60536
  ignoredTags: [...input.options.ignoredTags].sort(),
60537
+ includedTags: [...input.options.includedTags].sort(),
60538
+ includeTagDefaults: input.options.includeTagDefaults,
60052
60539
  concurrency: input.options.concurrency,
60053
60540
  lintBatchOrdering: resolveLintBatchOrdering(),
60054
60541
  baselineRef: input.options.baseline?.ref,
@@ -60875,8 +61362,8 @@ const createDiagnosticEvidenceReader = (rootDirectory, options = {}) => {
60875
61362
  //#endregion
60876
61363
  //#region src/cli/utils/build-no-score-message.ts
60877
61364
  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}`;
61365
+ const buildNoScoreMessage = (isScoreDisabled, disabledMessage) => {
61366
+ return `${isScoreDisabled ? disabledMessage ?? "Score disabled by --no-score." : "Score unavailable (could not reach the score API)."} ${ENTERPRISE_CONTACT_HINT}`;
60880
61367
  };
60881
61368
  //#endregion
60882
61369
  //#region src/cli/utils/render-agent-guidance.ts
@@ -62001,40 +62488,47 @@ const buildChangedLineMatcher = (directory, changedLineRanges) => {
62001
62488
  return diagnosticIntersectsLineRanges(diagnostic, ranges);
62002
62489
  };
62003
62490
  };
62004
- const buildIgnoredTags = (userConfig) => {
62491
+ const buildIgnoredTags = (userConfig, includedTags) => {
62005
62492
  const tags = /* @__PURE__ */ new Set();
62006
62493
  if (userConfig?.ignore?.tags) for (const tag of userConfig.ignore.tags) tags.add(tag);
62494
+ for (const tag of includedTags) tags.delete(tag);
62007
62495
  return tags;
62008
62496
  };
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
- });
62497
+ const mergeInspectOptions = (inputOptions, userConfig) => {
62498
+ const includedTags = inputOptions.includedTags ?? /* @__PURE__ */ new Set();
62499
+ return {
62500
+ lint: inputOptions.lint ?? userConfig?.lint ?? true,
62501
+ deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
62502
+ supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
62503
+ verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
62504
+ outputDirectory: inputOptions.outputDirectory || null,
62505
+ scoreOnly: inputOptions.scoreOnly ?? false,
62506
+ noScore: inputOptions.noScore ?? userConfig?.noScore ?? false,
62507
+ isCi: inputOptions.isCi ?? false,
62508
+ isCiOrCodingAgentEnvironment: isCiOrCodingAgentEnvironment(),
62509
+ isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
62510
+ silent: inputOptions.silent ?? false,
62511
+ includePaths: inputOptions.includePaths ?? [],
62512
+ customRulesOnly: includedTags.size > 0 ? false : userConfig?.customRulesOnly ?? false,
62513
+ share: userConfig?.share ?? true,
62514
+ respectInlineDisables: inputOptions.respectInlineDisables ?? userConfig?.respectInlineDisables ?? true,
62515
+ warnings: inputOptions.warnings ?? userConfig?.warnings ?? true,
62516
+ categoryFilters: new Set(resolveCliCategories(inputOptions.categoryFilters) ?? []),
62517
+ adoptExistingLintConfig: includedTags.size > 0 ? false : userConfig?.adoptExistingLintConfig ?? true,
62518
+ ignoredTags: buildIgnoredTags(userConfig, includedTags),
62519
+ includedTags,
62520
+ includeTagDefaults: inputOptions.includeTagDefaults ?? false,
62521
+ scoreDisabledMessage: inputOptions.scoreDisabledMessage,
62522
+ outputSurface: inputOptions.outputSurface ?? "cli",
62523
+ suppressRendering: inputOptions.suppressRendering ?? false,
62524
+ concurrentScan: inputOptions.concurrentScan ?? false,
62525
+ concurrency: inputOptions.concurrency,
62526
+ maxDurationMs: inputOptions.maxDurationMs ?? null,
62527
+ baseline: inputOptions.baseline ?? null,
62528
+ changedLineRanges: inputOptions.changedLineRanges ?? null,
62529
+ supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
62530
+ };
62531
+ };
62038
62532
  const deriveScope = (options) => {
62039
62533
  if (options.baseline) return "changed";
62040
62534
  if (options.changedLineRanges !== null) return "lines";
@@ -62165,6 +62659,8 @@ const runBaselineComparison = async (params) => {
62165
62659
  warnings: params.options.warnings,
62166
62660
  adoptExistingLintConfig: params.options.adoptExistingLintConfig,
62167
62661
  ignoredTags: params.options.ignoredTags,
62662
+ includedTags: params.options.includedTags,
62663
+ includeTagDefaults: params.options.includeTagDefaults,
62168
62664
  nodeBinaryPath: params.resolvedNodeBinaryPath ?? void 0,
62169
62665
  runDeadCode: false,
62170
62666
  isCi: params.options.isCi,
@@ -62258,6 +62754,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
62258
62754
  warnings: options.warnings,
62259
62755
  adoptExistingLintConfig: options.adoptExistingLintConfig,
62260
62756
  ignoredTags: options.ignoredTags,
62757
+ includedTags: options.includedTags,
62758
+ includeTagDefaults: options.includeTagDefaults,
62261
62759
  nodeBinaryPath: resolvedNodeBinaryPath ?? void 0,
62262
62760
  runDeadCode: options.deadCode,
62263
62761
  isCi: options.isCi,
@@ -62446,7 +62944,7 @@ const finalizeAndRender = (input) => gen(function* () {
62446
62944
  securityScanFailed
62447
62945
  });
62448
62946
  const hasSkippedChecks = skippedChecks.length > 0;
62449
- const noScoreMessage = buildNoScoreMessage(options.noScore);
62947
+ const noScoreMessage = buildNoScoreMessage(options.noScore, options.scoreDisabledMessage);
62450
62948
  const buildResult = () => ({
62451
62949
  diagnostics: [...diagnostics],
62452
62950
  score,
@@ -64551,21 +65049,25 @@ const resolveParallelFlag = (parallel) => parallel === false ? 1 : void 0;
64551
65049
  */
64552
65050
  const resolveCliInspectOptions = (flags, userConfig) => {
64553
65051
  const wantsWarningGate = pickBlockingLevel(flags, userConfig) === "warning";
65052
+ const isDesignScan = flags.design === true;
64554
65053
  return {
64555
65054
  lint: flags.lint,
64556
- deadCode: flags.deadCode,
64557
- supplyChain: flags.supplyChain,
65055
+ deadCode: isDesignScan ? false : flags.deadCode,
65056
+ supplyChain: isDesignScan ? false : flags.supplyChain,
64558
65057
  verbose: flags.verbose,
64559
65058
  outputDirectory: flags.outputDir,
64560
65059
  respectInlineDisables: flags.respectInlineDisables === false ? false : void 0,
64561
65060
  warnings: wantsWarningGate ? true : flags.warnings,
64562
65061
  scoreOnly: flags.score === true,
64563
- noScore: flags.score === false || flags.telemetry === false ? true : void 0,
65062
+ noScore: isDesignScan || flags.score === false || flags.telemetry === false ? true : void 0,
64564
65063
  isCi: isCiEnvironment(),
64565
65064
  silent: Boolean(flags.json),
64566
65065
  concurrency: resolveParallelFlag(flags.parallel),
64567
65066
  maxDurationMs: resolveMaxDurationFlag(flags.maxDuration),
64568
- categoryFilters: resolveCliCategories(flags.category)
65067
+ categoryFilters: resolveCliCategories(flags.category),
65068
+ includedTags: isDesignScan ? new Set(["design"]) : void 0,
65069
+ includeTagDefaults: isDesignScan ? true : void 0,
65070
+ scoreDisabledMessage: isDesignScan ? "Design scans do not affect the React health score." : void 0
64569
65071
  };
64570
65072
  };
64571
65073
  //#endregion
@@ -64983,7 +65485,7 @@ const maybeMigrateLegacyConfig = async (requestedDirectory, { isQuiet, isStaged
64983
65485
  if (!(!isQuiet && !isStaged && process.stdout.isTTY === true && !isCiOrCodingAgentEnvironment())) return;
64984
65486
  await runProjectMigrations(requestedDirectory);
64985
65487
  };
64986
- const inspectAction = async (directory, flags) => {
65488
+ const inspectAction = async (directory, flags, invocationCommand = "inspect") => {
64987
65489
  const isScoreOnly = Boolean(flags.score);
64988
65490
  const isJsonMode = Boolean(flags.json);
64989
65491
  const isQuiet = isScoreOnly || isJsonMode;
@@ -64997,7 +65499,7 @@ const inspectAction = async (directory, flags) => {
64997
65499
  });
64998
65500
  if (flags.jsonOut) recordCount(METRIC.jsonOutUsed, 1);
64999
65501
  }
65000
- recordCount(METRIC.cliInvoked, 1, { command: "inspect" });
65502
+ recordCount(METRIC.cliInvoked, 1, { command: invocationCommand });
65001
65503
  try {
65002
65504
  validateModeFlags(flags);
65003
65505
  if (flags.staged) setJsonReportMode("staged");
@@ -65309,6 +65811,13 @@ const inspectAction = async (directory, flags) => {
65309
65811
  }
65310
65812
  };
65311
65813
  //#endregion
65814
+ //#region src/cli/commands/design.ts
65815
+ const designAction = async (directory, flags) => inspectAction(directory, {
65816
+ ...flags,
65817
+ design: true,
65818
+ lint: flags.lint ?? true
65819
+ }, "design");
65820
+ //#endregion
65312
65821
  //#region src/cli/commands/install.ts
65313
65822
  const installAction = async (options, command) => {
65314
65823
  recordCount(METRIC.cliInvoked, 1, { command: "install" });
@@ -66145,6 +66654,7 @@ const INSTALL_FLAG_SPEC = {
66145
66654
  shortOptionsWithRequiredValues: new Set(["-c"])
66146
66655
  };
66147
66656
  const COMMAND_FLAG_SPECS = new Map([
66657
+ ["design", ROOT_FLAG_SPEC],
66148
66658
  ["install", INSTALL_FLAG_SPEC],
66149
66659
  ["setup", INSTALL_FLAG_SPEC],
66150
66660
  ["version", {
@@ -66301,6 +66811,7 @@ ${formatExampleLines([
66301
66811
  ["react-doctor --scope changed --base main", "scan only new issues vs. main"],
66302
66812
  ["react-doctor --project modules/a,modules/b", "score each module separately (names or paths)"],
66303
66813
  ["react-doctor --staged", "scan staged files (pre-commit hook)"],
66814
+ ["react-doctor design", "run the focused UI design audit"],
66304
66815
  ["react-doctor --category Security", "show only one diagnostic category"],
66305
66816
  ["react-doctor --blocking warning", "fail CI on warnings too (default: error)"],
66306
66817
  ["react-doctor --json > report.json", "write a machine-readable report"],
@@ -66334,6 +66845,20 @@ ${highlighter.dim("Managing CI:")}
66334
66845
  ${highlighter.dim("Learn more:")}
66335
66846
  ${highlighter.info(CANONICAL_GITHUB_URL)}
66336
66847
  `;
66848
+ const renderDesignHelpEpilog = () => `
66849
+ ${highlighter.dim("Examples:")}
66850
+ ${formatExampleLines([
66851
+ ["react-doctor design", "audit UI design in the current project"],
66852
+ ["react-doctor design ./apps/web", "audit one application"],
66853
+ ["react-doctor design --verbose", "show every design finding"],
66854
+ ["react-doctor design --json", "write a design-only JSON report"]
66855
+ ])}
66856
+
66857
+ ${highlighter.dim("Scope:")}
66858
+ Runs only rules tagged ${highlighter.info("design")}, including focused rules that stay opt-in during a general health scan.
66859
+ Dead-code, supply-chain, external lint-config, custom-plugin, and health-score passes are skipped.
66860
+ Standard scan flags such as ${highlighter.info("--scope")}, ${highlighter.info("--project")}, ${highlighter.info("--verbose")}, and ${highlighter.info("--json")} still work.
66861
+ `;
66337
66862
  const renderCiHelpEpilog = () => `
66338
66863
  ${highlighter.dim("Examples:")}
66339
66864
  ${formatExampleLines([
@@ -66355,6 +66880,7 @@ ${highlighter.dim("Learn more:")}
66355
66880
  const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
66356
66881
  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
66882
  program.action(inspectAction);
66883
+ program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
66358
66884
  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
66885
  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
66886
  const providerOption = ["--provider <name>", "ci provider: github-actions or gitlab-ci (auto-detected by default)"];
@@ -66403,4 +66929,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
66403
66929
  export {};
66404
66930
 
66405
66931
  //# sourceMappingURL=cli.js.map
66406
- //# debugId=24153a3f-aef9-53fd-8dff-9b016a9613fb
66932
+ //# debugId=f42528c1-1dda-59b5-a1a4-34d713fd7d55