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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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]="81bdc95e-12f2-565f-a05c-7b8a60a98f81")}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]="87efffda-8fc4-5b52-80e1-7ec503c85206")}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__\//;
@@ -36101,6 +36063,58 @@ const IGNORED_DIRECTORIES = new Set([
36101
36063
  ]);
36102
36064
  const JSX_FILE_PATTERN = /\.(tsx|jsx)$/;
36103
36065
  const MILLISECONDS_PER_SECOND = 1e3;
36066
+ const REACT_ROUTER_CAPABILITY_THRESHOLDS = [
36067
+ {
36068
+ capability: "react-router:6.4",
36069
+ major: 6,
36070
+ minor: 4
36071
+ },
36072
+ {
36073
+ capability: "react-router:6.7",
36074
+ major: 6,
36075
+ minor: 7
36076
+ },
36077
+ {
36078
+ capability: "react-router:6.9",
36079
+ major: 6,
36080
+ minor: 9
36081
+ },
36082
+ {
36083
+ capability: "react-router:6.19",
36084
+ major: 6,
36085
+ minor: 19
36086
+ },
36087
+ {
36088
+ capability: "react-router:7",
36089
+ major: 7,
36090
+ minor: 0
36091
+ },
36092
+ {
36093
+ capability: "react-router:7.8",
36094
+ major: 7,
36095
+ minor: 8
36096
+ },
36097
+ {
36098
+ capability: "react-router:7.9",
36099
+ major: 7,
36100
+ minor: 9
36101
+ },
36102
+ {
36103
+ capability: "react-router:7.10",
36104
+ major: 7,
36105
+ minor: 10
36106
+ },
36107
+ {
36108
+ capability: "react-router:7.15",
36109
+ major: 7,
36110
+ minor: 15
36111
+ },
36112
+ {
36113
+ capability: "react-router:8",
36114
+ major: 8,
36115
+ minor: 0
36116
+ }
36117
+ ];
36104
36118
  const SCORE_API_URL = "https://www.react.doctor/api/score";
36105
36119
  const ENTERPRISE_CONTACT_URL = "https://react.doctor/enterprise";
36106
36120
  const SHARE_BASE_URL = "https://react.doctor/share";
@@ -36252,6 +36266,44 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
36252
36266
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
36253
36267
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
36254
36268
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
36269
+ const isErrnoException = (error) => error instanceof Error && "code" in error;
36270
+ const IGNORABLE_READDIR_ERROR_CODES = new Set([
36271
+ "EACCES",
36272
+ "EPERM",
36273
+ "ENOENT",
36274
+ "ENOTDIR",
36275
+ "EINVAL",
36276
+ "ELOOP",
36277
+ "ENAMETOOLONG"
36278
+ ]);
36279
+ const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
36280
+ const readDirectoryEntries = (directoryPath) => {
36281
+ try {
36282
+ return NFS.readdirSync(directoryPath, { withFileTypes: true });
36283
+ } catch (error) {
36284
+ if (isIgnorableReaddirError(error)) return [];
36285
+ throw error;
36286
+ }
36287
+ };
36288
+ const isFile = (filePath) => {
36289
+ try {
36290
+ return NFS.statSync(filePath).isFile();
36291
+ } catch {
36292
+ return false;
36293
+ }
36294
+ };
36295
+ const isDirectory = (directoryPath) => {
36296
+ try {
36297
+ return NFS.statSync(directoryPath).isDirectory();
36298
+ } catch {
36299
+ return false;
36300
+ }
36301
+ };
36302
+ const isPlainObject = (value) => {
36303
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
36304
+ const prototype = Object.getPrototypeOf(value);
36305
+ return prototype === null || prototype === Object.prototype;
36306
+ };
36255
36307
  const lastSourceMappingUrl = (fileContent) => {
36256
36308
  const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
36257
36309
  return lastReference ? lastReference[1] : null;
@@ -36571,10 +36623,10 @@ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"]
36571
36623
  const FRAMEWORK_PACKAGES = {
36572
36624
  next: "nextjs",
36573
36625
  "@tanstack/react-start": "tanstack-start",
36574
- vite: "vite",
36575
- "react-scripts": "cra",
36576
36626
  "@remix-run/react": "remix",
36577
36627
  gatsby: "gatsby",
36628
+ vite: "vite",
36629
+ "react-scripts": "cra",
36578
36630
  expo: "expo",
36579
36631
  "react-native": "react-native"
36580
36632
  };
@@ -36598,11 +36650,17 @@ const NEXT_CONFIG_FILENAMES = [
36598
36650
  ];
36599
36651
  const BABEL_CONFIG_FILENAMES = [
36600
36652
  ".babelrc",
36653
+ ".babelrc.js",
36601
36654
  ".babelrc.json",
36655
+ ".babelrc.cjs",
36656
+ ".babelrc.mjs",
36657
+ ".babelrc.cts",
36602
36658
  "babel.config.js",
36603
36659
  "babel.config.json",
36604
36660
  "babel.config.cjs",
36605
- "babel.config.mjs"
36661
+ "babel.config.mjs",
36662
+ "babel.config.ts",
36663
+ "babel.config.cts"
36606
36664
  ];
36607
36665
  const VITE_CONFIG_FILENAMES = [
36608
36666
  "vite.config.js",
@@ -36614,12 +36672,28 @@ const VITE_CONFIG_FILENAMES = [
36614
36672
  "vitest.config.ts",
36615
36673
  "vitest.config.js"
36616
36674
  ];
36675
+ const RSBUILD_CONFIG_FILENAMES = [
36676
+ "rsbuild.config.ts",
36677
+ "rsbuild.config.js",
36678
+ "rsbuild.config.mts",
36679
+ "rsbuild.config.mjs",
36680
+ "rsbuild.config.cts",
36681
+ "rsbuild.config.cjs"
36682
+ ];
36683
+ const RSPACK_CONFIG_FILENAMES = [
36684
+ "rspack.config.ts",
36685
+ "rspack.config.js",
36686
+ "rspack.config.mts",
36687
+ "rspack.config.mjs",
36688
+ "rspack.config.cts",
36689
+ "rspack.config.cjs"
36690
+ ];
36617
36691
  const EXPO_APP_CONFIG_FILENAMES = [
36618
36692
  "app.json",
36619
36693
  "app.config.js",
36620
36694
  "app.config.ts"
36621
36695
  ];
36622
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
36696
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|reactCompilerPreset\s*\(|["']react-compiler["']/;
36623
36697
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
36624
36698
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
36625
36699
  const hasCompilerPackage = (packageJson, compilerPackages) => {
@@ -36654,6 +36728,8 @@ const detectReactCompiler = (directory, packageJson) => {
36654
36728
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
36655
36729
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
36656
36730
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
36731
+ if (hasCompilerInConfigFiles(directory, RSBUILD_CONFIG_FILENAMES)) return true;
36732
+ if (hasCompilerInConfigFiles(directory, RSPACK_CONFIG_FILENAMES)) return true;
36657
36733
  if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
36658
36734
  return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
36659
36735
  };
@@ -36662,7 +36738,7 @@ const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((file
36662
36738
  const filePath = Path.join(directory, filename);
36663
36739
  return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
36664
36740
  });
36665
- const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:file|git|github|https?|link|patch|portal|workspace|npm):/i;
36741
+ const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:catalog|file|git|github|https?|link|patch|portal|workspace|npm):/i;
36666
36742
  const DIST_TAG_VERSION = /^[a-z][a-z0-9._-]*$/i;
36667
36743
  const WILDCARD_VERSION = /^[*xX](?:\.[*xX])*$/;
36668
36744
  const NPM_ALIAS_VERSION = /^npm:(?:@[^/]+\/[^@]+|[^@]+)@(.+)$/i;
@@ -36795,6 +36871,16 @@ const getLowestDependencyMajor = (version) => {
36795
36871
  }
36796
36872
  return lowestMajor;
36797
36873
  };
36874
+ const getDependencyMajorWithinSupportedRange = (version, latestSupportedMajor) => {
36875
+ const normalizedVersion = normalizeDependencyVersion(version);
36876
+ if (normalizedVersion === null) return null;
36877
+ const validRange = import_semver.validRange(normalizedVersion);
36878
+ if (validRange === null) return null;
36879
+ const minimumVersion = import_semver.minVersion(validRange);
36880
+ if (minimumVersion === null || minimumVersion.major > latestSupportedMajor) return null;
36881
+ if (import_semver.intersects(validRange, `>=${latestSupportedMajor + 1}.0.0`)) return null;
36882
+ return minimumVersion.major;
36883
+ };
36798
36884
  const isConcreteDependencyVersion = (version) => {
36799
36885
  const normalizedVersion = normalizeDependencyVersion(version);
36800
36886
  return normalizedVersion !== null && /\d/.test(normalizedVersion);
@@ -36838,9 +36924,18 @@ const parseReactMajorMinor = (reactVersion) => {
36838
36924
  };
36839
36925
  };
36840
36926
  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();
36927
+ const parseThreeRelease = (threeVersion) => {
36928
+ if (typeof threeVersion !== "string") return null;
36929
+ const normalizedVersion = normalizeDependencyVersion(threeVersion);
36930
+ if (normalizedVersion === null) return null;
36931
+ const lowerBound = parseLowerBoundVersion(normalizedVersion);
36932
+ if (lowerBound === null) return null;
36933
+ if (lowerBound.major > 0) return Number.MAX_SAFE_INTEGER;
36934
+ return lowerBound.minor > 0 ? lowerBound.minor : null;
36935
+ };
36936
+ const parseDependencyMajorMinor = (dependencyVersion) => {
36937
+ if (typeof dependencyVersion !== "string") return null;
36938
+ const trimmed = dependencyVersion.trim();
36844
36939
  if (trimmed.length === 0) return null;
36845
36940
  const lowerBound = parseLowerBoundVersion(trimmed);
36846
36941
  if (lowerBound === null || lowerBound.major <= 0) return null;
@@ -36849,6 +36944,7 @@ const parseTailwindMajorMinor = (tailwindVersion) => {
36849
36944
  minor: lowerBound.minor
36850
36945
  };
36851
36946
  };
36947
+ const parseTailwindMajorMinor = (tailwindVersion) => parseDependencyMajorMinor(tailwindVersion);
36852
36948
  const hasUpperBoundOnlyPeerRange = (range) => {
36853
36949
  if (typeof range !== "string") return false;
36854
36950
  const normalizedRange = normalizeDependencyVersion(range);
@@ -36870,7 +36966,7 @@ const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
36870
36966
  if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
36871
36967
  return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
36872
36968
  };
36873
- const isCatalogReference = (version) => version.startsWith("catalog:");
36969
+ const isCatalogReference = (version) => typeof version === "string" && version.startsWith("catalog:");
36874
36970
  const extractCatalogName = (version) => {
36875
36971
  if (!isCatalogReference(version)) return null;
36876
36972
  const name = version.slice(8).trim();
@@ -37020,6 +37116,12 @@ const TAILWIND_ZOD_SECTIONS = [
37020
37116
  "devDependencies",
37021
37117
  "peerDependencies"
37022
37118
  ];
37119
+ const DEPENDENCY_SPEC_SECTIONS = [
37120
+ "dependencies",
37121
+ "devDependencies",
37122
+ "peerDependencies",
37123
+ "optionalDependencies"
37124
+ ];
37023
37125
  const EMPTY_DEPENDENCY_INFO = {
37024
37126
  reactVersion: null,
37025
37127
  tailwindVersion: null,
@@ -37029,7 +37131,7 @@ const EMPTY_DEPENDENCY_INFO = {
37029
37131
  const pickConcreteVersion = (packageJson, packageName, sections) => {
37030
37132
  for (const section of sections) {
37031
37133
  const version = packageJson[section]?.[packageName];
37032
- if (version === void 0) continue;
37134
+ if (typeof version !== "string") continue;
37033
37135
  if (isCatalogReference(version)) return null;
37034
37136
  if (isConcreteDependencyVersion(version)) return version;
37035
37137
  }
@@ -37061,13 +37163,16 @@ const extractDependencyInfo = (packageJson) => {
37061
37163
  };
37062
37164
  };
37063
37165
  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;
37166
+ for (const section of DEPENDENCY_SPEC_SECTIONS) {
37167
+ const spec = packageJson[section]?.[packageName];
37168
+ if (typeof spec === "string") return spec;
37169
+ }
37170
+ return null;
37066
37171
  };
37067
37172
  const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
37068
37173
  for (const section of sections) {
37069
37174
  const version = packageJson[section]?.[packageName];
37070
- if (version === void 0) continue;
37175
+ if (typeof version !== "string") continue;
37071
37176
  return {
37072
37177
  catalogReference: extractCatalogName(version) ?? null,
37073
37178
  hasDeclaration: true,
@@ -37101,24 +37206,15 @@ const getPreactVersion = (packageJson) => {
37101
37206
  ...packageJson.devDependencies
37102
37207
  }.preact ?? null;
37103
37208
  };
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 }) => {
37209
+ const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, sourceDirectory = rootDirectory, sourcePackageJson = rootPackageJson, version }) => {
37118
37210
  if (version === null || !isCatalogReference(version)) return version;
37119
37211
  const catalogName = extractCatalogName(version);
37120
- const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
37121
- if (resolvedLocalVersion) return resolvedLocalVersion;
37212
+ const resolvedSourceVersion = resolveCatalogVersion(sourcePackageJson, packageName, sourceDirectory, catalogName);
37213
+ if (resolvedSourceVersion) return resolvedSourceVersion;
37214
+ if (sourceDirectory !== rootDirectory || sourcePackageJson !== rootPackageJson) {
37215
+ const resolvedRootVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
37216
+ if (resolvedRootVersion) return resolvedRootVersion;
37217
+ }
37122
37218
  const monorepoRoot = findMonorepoRoot(rootDirectory);
37123
37219
  if (!monorepoRoot) return version;
37124
37220
  const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
@@ -37316,11 +37412,84 @@ const listWorkspacePackages = (rootDirectory) => {
37316
37412
  }
37317
37413
  return packages;
37318
37414
  };
37415
+ const PREFERRED_DEPENDENCY_SECTIONS = [
37416
+ "dependencies",
37417
+ "peerDependencies",
37418
+ "devDependencies"
37419
+ ];
37420
+ const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
37421
+ for (const packageName of packageNames) {
37422
+ const declaration = getDependencyDeclaration({
37423
+ packageJson,
37424
+ packageName,
37425
+ sections: PREFERRED_DEPENDENCY_SECTIONS
37426
+ });
37427
+ if (declaration.version !== null) return declaration.version;
37428
+ }
37429
+ return null;
37430
+ };
37431
+ const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
37432
+ const getTanStackQueryVersion = (packageJson) => {
37433
+ return getPreferredDependencyVersion({
37434
+ packageJson,
37435
+ packageNames: TANSTACK_REACT_QUERY_PACKAGES
37436
+ });
37437
+ };
37438
+ const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
37439
+ const getStyledComponentsVersion = (packageJson) => {
37440
+ return getPreferredDependencyVersion({
37441
+ packageJson,
37442
+ packageNames: STYLED_COMPONENTS_PACKAGES
37443
+ });
37444
+ };
37445
+ const I18N_PACKAGES = [
37446
+ "i18next",
37447
+ "react-i18next",
37448
+ "next-i18next",
37449
+ "react-intl",
37450
+ "next-intl",
37451
+ "use-intl",
37452
+ "@formatjs/intl",
37453
+ "@lingui/core",
37454
+ "@lingui/react",
37455
+ "typesafe-i18n",
37456
+ "@tolgee/react",
37457
+ "react-intl-universal"
37458
+ ];
37459
+ const hasI18nDependency = (packageJson) => {
37460
+ const allDependencies = {
37461
+ ...packageJson.peerDependencies,
37462
+ ...packageJson.dependencies,
37463
+ ...packageJson.devDependencies,
37464
+ ...packageJson.optionalDependencies
37465
+ };
37466
+ return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
37467
+ };
37319
37468
  const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
37320
37469
  const MOBX_REACT_PACKAGE_NAME = "mobx-react";
37321
37470
  const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
37322
37471
  const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
37323
37472
  const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
37473
+ const REACT_THREE_FIBER_DEPENDENCY_NAMES = ["@react-three/fiber", "react-three-fiber"];
37474
+ const REACT_THREE_FIBER_SECTIONS = [
37475
+ "dependencies",
37476
+ "peerDependencies",
37477
+ "optionalDependencies",
37478
+ "devDependencies"
37479
+ ];
37480
+ const THREE_DEPENDENCY_SECTIONS = [
37481
+ "dependencies",
37482
+ "peerDependencies",
37483
+ "optionalDependencies",
37484
+ "devDependencies"
37485
+ ];
37486
+ const REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES = [...REACT_THREE_FIBER_DEPENDENCY_NAMES, "@react-three/drei"];
37487
+ const THREE_DEPENDENCY_NAMES = [...REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES, "three"];
37488
+ const REACT_ROUTER_DEPENDENCY_NAMES = [
37489
+ "@react-router/dev",
37490
+ "react-router-dom",
37491
+ "react-router"
37492
+ ];
37324
37493
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
37325
37494
  const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
37326
37495
  const dependencyDeclaration = getDependencyDeclaration({
@@ -37331,7 +37500,7 @@ const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootD
37331
37500
  if (!dependencyDeclaration.hasDeclaration) return null;
37332
37501
  return concreteVersion ?? resolveCatalogVersion(workspacePackageJson, packageName, workspaceDirectory, dependencyDeclaration.catalogReference) ?? resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, dependencyDeclaration.catalogReference);
37333
37502
  };
37334
- const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
37503
+ const shouldReplaceWithLowerMajor = (currentVersion, nextVersion) => {
37335
37504
  if (!currentVersion) return true;
37336
37505
  const currentMajor = parseReactMajor(currentVersion);
37337
37506
  const nextMajor = parseReactMajor(nextVersion);
@@ -37350,6 +37519,59 @@ const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSuppo
37350
37519
  if (nextMajor > latestSupportedMajor) return true;
37351
37520
  return nextMajor < currentMajor;
37352
37521
  };
37522
+ const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
37523
+ if (!currentVersion) return true;
37524
+ const currentMajor = getLowestDependencyMajor(currentVersion);
37525
+ const nextMajor = getLowestDependencyMajor(nextVersion);
37526
+ if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
37527
+ if (nextMajor === null) return currentMajor >= 6;
37528
+ return nextMajor < currentMajor;
37529
+ };
37530
+ const selectOldestDependencyVersion = (currentVersion, nextVersion) => {
37531
+ if (currentVersion === null || nextVersion === null) return null;
37532
+ const current = parseDependencyMajorMinor(currentVersion);
37533
+ const next = parseDependencyMajorMinor(nextVersion);
37534
+ if (current === null) return currentVersion;
37535
+ if (next === null) return nextVersion;
37536
+ if (next.major !== current.major) return next.major < current.major ? nextVersion : currentVersion;
37537
+ return next.minor < current.minor ? nextVersion : currentVersion;
37538
+ };
37539
+ const shouldReplaceMobxFact = (currentFact, nextFact) => {
37540
+ if (currentFact.sourceDirectory === null) return true;
37541
+ if (currentFact.version === null) return false;
37542
+ if (nextFact.version === null) return true;
37543
+ const currentMajor = getDependencyMajorWithinSupportedRange(currentFact.version, 6);
37544
+ const nextMajor = getDependencyMajorWithinSupportedRange(nextFact.version, 6);
37545
+ if (currentMajor === null) return false;
37546
+ if (nextMajor === null) return true;
37547
+ return selectOldestDependencyVersion(currentFact.version, nextFact.version) === nextFact.version;
37548
+ };
37549
+ const collectBindingVersion = (facts, packageJson, directory, packageName) => {
37550
+ const version = getDependencySpec(packageJson, packageName);
37551
+ if (version === null) return;
37552
+ const resolvedVersion = resolveCatalogBackedDependencyVersion({
37553
+ rootDirectory: directory,
37554
+ rootPackageJson: packageJson,
37555
+ packageName,
37556
+ version
37557
+ });
37558
+ if (packageName === MOBX_REACT_PACKAGE_NAME) {
37559
+ facts.mobxReactVersion = facts.hasMobxReact ? selectOldestDependencyVersion(facts.mobxReactVersion, resolvedVersion) : resolvedVersion;
37560
+ facts.hasMobxReact = true;
37561
+ return;
37562
+ }
37563
+ facts.mobxReactLiteVersion = facts.hasMobxReactLite ? selectOldestDependencyVersion(facts.mobxReactLiteVersion, resolvedVersion) : resolvedVersion;
37564
+ facts.hasMobxReactLite = true;
37565
+ };
37566
+ const shouldReplaceReactRouterVersion = (currentVersion, nextVersion) => {
37567
+ if (currentVersion === null) return true;
37568
+ const current = parseReactMajorMinor(currentVersion);
37569
+ const next = parseReactMajorMinor(nextVersion);
37570
+ if (current === null) return next !== null;
37571
+ if (next === null) return false;
37572
+ if (next.major !== current.major) return next.major < current.major;
37573
+ return next.minor < current.minor;
37574
+ };
37353
37575
  const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
37354
37576
  if (facts.expo.version === null) {
37355
37577
  const spec = getDependencySpec(packageJson, "expo");
@@ -37365,6 +37587,23 @@ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, roo
37365
37587
  sourceDirectory: directory
37366
37588
  };
37367
37589
  }
37590
+ for (const packageName of REACT_ROUTER_DEPENDENCY_NAMES) {
37591
+ const resolvedSpec = resolveCatalogBackedDependencyVersion({
37592
+ rootDirectory,
37593
+ rootPackageJson,
37594
+ sourceDirectory: directory,
37595
+ sourcePackageJson: packageJson,
37596
+ packageName,
37597
+ version: getDependencySpec(packageJson, packageName)
37598
+ });
37599
+ if (resolvedSpec === null || !shouldReplaceReactRouterVersion(facts.reactRouter.version, resolvedSpec)) continue;
37600
+ facts.reactRouter = {
37601
+ version: resolvedSpec,
37602
+ sourceDirectory: directory,
37603
+ packageName
37604
+ };
37605
+ }
37606
+ facts.hasReactRouterFramework = facts.hasReactRouterFramework || getDependencySpec(packageJson, "@react-router/dev") !== null;
37368
37607
  if (facts.shopifyFlashList.version === null) {
37369
37608
  const spec = getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME);
37370
37609
  if (spec !== null) facts.shopifyFlashList = {
@@ -37383,10 +37622,10 @@ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, roo
37383
37622
  }),
37384
37623
  sourceDirectory: directory
37385
37624
  };
37386
- if (shouldReplaceSupportedDependencyFact(facts.mobx, nextMobxFact, 6)) facts.mobx = nextMobxFact;
37625
+ if (shouldReplaceMobxFact(facts.mobx, nextMobxFact)) facts.mobx = nextMobxFact;
37387
37626
  }
37388
- facts.hasMobxReact = facts.hasMobxReact || getDependencySpec(packageJson, MOBX_REACT_PACKAGE_NAME) !== null;
37389
- facts.hasMobxReactLite = facts.hasMobxReactLite || getDependencySpec(packageJson, MOBX_REACT_LITE_PACKAGE_NAME) !== null;
37627
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_PACKAGE_NAME);
37628
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_LITE_PACKAGE_NAME);
37390
37629
  facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
37391
37630
  facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
37392
37631
  const zustandSpec = getDependencySpec(packageJson, "zustand");
@@ -37410,6 +37649,52 @@ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, roo
37410
37649
  const spec = getDependencySpec(packageJson, "valtio");
37411
37650
  if (spec !== null) facts.valtioVersion = spec;
37412
37651
  }
37652
+ facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
37653
+ const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
37654
+ rootDirectory: directory,
37655
+ rootPackageJson: packageJson,
37656
+ packageName: "styled-components",
37657
+ version: getStyledComponentsVersion(packageJson)
37658
+ });
37659
+ if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
37660
+ facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
37661
+ for (const packageName of REACT_THREE_FIBER_DEPENDENCY_NAMES) {
37662
+ const version = resolveCatalogBackedDependencyVersion({
37663
+ rootDirectory,
37664
+ rootPackageJson,
37665
+ sourceDirectory: directory,
37666
+ sourcePackageJson: packageJson,
37667
+ packageName,
37668
+ version: getDependencyDeclaration({
37669
+ packageName,
37670
+ packageJson,
37671
+ sections: REACT_THREE_FIBER_SECTIONS
37672
+ }).version
37673
+ });
37674
+ if (version === null) continue;
37675
+ if (shouldReplaceWithLowerMajor(facts.reactThreeFiber.version, version)) facts.reactThreeFiber = {
37676
+ packageName,
37677
+ version,
37678
+ sourceDirectory: directory
37679
+ };
37680
+ }
37681
+ const threeVersion = resolveCatalogBackedDependencyVersion({
37682
+ rootDirectory,
37683
+ rootPackageJson,
37684
+ sourceDirectory: directory,
37685
+ sourcePackageJson: packageJson,
37686
+ packageName: "three",
37687
+ version: getDependencyDeclaration({
37688
+ packageName: "three",
37689
+ packageJson,
37690
+ sections: THREE_DEPENDENCY_SECTIONS
37691
+ }).version
37692
+ });
37693
+ if (threeVersion !== null) {
37694
+ const currentRelease = parseThreeRelease(facts.threeVersion);
37695
+ const nextRelease = parseThreeRelease(threeVersion);
37696
+ if (facts.threeVersion === null || nextRelease !== null && (currentRelease === null || nextRelease < currentRelease)) facts.threeVersion = threeVersion;
37697
+ }
37413
37698
  facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
37414
37699
  facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
37415
37700
  facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
@@ -37431,6 +37716,8 @@ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, roo
37431
37716
  if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
37432
37717
  }
37433
37718
  }
37719
+ facts.hasThree = facts.hasThree || THREE_DEPENDENCY_NAMES.some((dependencyName) => getDependencySpec(packageJson, dependencyName) !== null);
37720
+ facts.hasReactThreeFiber = facts.hasReactThreeFiber || REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES.some((dependencyName) => getDependencySpec(packageJson, dependencyName) !== null);
37434
37721
  };
37435
37722
  const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
37436
37723
  const facts = {
@@ -37446,6 +37733,11 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37446
37733
  version: null,
37447
37734
  sourceDirectory: null
37448
37735
  },
37736
+ reactRouter: {
37737
+ version: null,
37738
+ sourceDirectory: null,
37739
+ packageName: null
37740
+ },
37449
37741
  shopifyFlashList: {
37450
37742
  version: null,
37451
37743
  sourceDirectory: null
@@ -37456,26 +37748,40 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37456
37748
  sourceDirectory: null
37457
37749
  },
37458
37750
  hasMobxReact: false,
37751
+ mobxReactVersion: null,
37459
37752
  hasMobxReactLite: false,
37753
+ mobxReactLiteVersion: null,
37460
37754
  hasMobxStateTree: false,
37461
37755
  hasMobxReactObserver: false,
37462
37756
  zustand: {
37463
37757
  version: null,
37464
37758
  sourceDirectory: null
37465
37759
  },
37760
+ tanstackQueryVersion: null,
37761
+ styledComponentsVersion: null,
37762
+ hasI18nLibrary: false,
37466
37763
  hasReactNativeAwarePackage: false,
37467
37764
  hasReanimatedAwarePackage: false,
37468
37765
  hasSsrDependency: false,
37469
37766
  hasRemotionDependency: false,
37470
37767
  hasUnknownRemotionVersion: false,
37471
37768
  remotionVersion: null,
37769
+ hasThree: false,
37770
+ threeVersion: null,
37771
+ hasReactThreeFiber: false,
37772
+ reactThreeFiber: {
37773
+ packageName: null,
37774
+ version: null,
37775
+ sourceDirectory: null
37776
+ },
37777
+ hasReactRouterFramework: false,
37472
37778
  reanimatedVersion: null
37473
37779
  };
37474
37780
  evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
37475
37781
  let isReactGroupSettled = !collectReactGroup;
37476
37782
  const visitedDirectories = /* @__PURE__ */ new Set();
37477
37783
  for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
37478
- const directories = [...resolveWorkspaceDirectories(rootDirectory, pattern)].sort();
37784
+ const directories = resolveWorkspaceDirectories(rootDirectory, pattern).toSorted();
37479
37785
  for (const workspaceDirectory of directories) {
37480
37786
  if (visitedDirectories.has(workspaceDirectory)) continue;
37481
37787
  visitedDirectories.add(workspaceDirectory);
@@ -37511,7 +37817,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37511
37817
  workspaceDirectory,
37512
37818
  workspacePackageJson
37513
37819
  });
37514
- if (reactVersion && shouldReplaceReactVersion(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
37820
+ if (reactVersion && shouldReplaceWithLowerMajor(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
37515
37821
  if (tailwindVersion && !facts.tailwindVersion) facts.tailwindVersion = tailwindVersion;
37516
37822
  if (zodVersion && !facts.zodVersion) facts.zodVersion = zodVersion;
37517
37823
  const settledReactMajor = parseReactMajor(facts.reactVersion);
@@ -37704,7 +38010,9 @@ const discoverProjectWithoutPackageJson = (directory) => {
37704
38010
  mobxVersion: null,
37705
38011
  mobxMajorVersion: null,
37706
38012
  hasMobxReact: false,
38013
+ mobxReactVersion: null,
37707
38014
  hasMobxReactLite: false,
38015
+ mobxReactLiteVersion: null,
37708
38016
  hasMobxStateTree: false,
37709
38017
  hasMobxReactObserver: false,
37710
38018
  zustandVersion: null,
@@ -37719,12 +38027,23 @@ const discoverProjectWithoutPackageJson = (directory) => {
37719
38027
  hasRemotion: false,
37720
38028
  remotionVersion: null,
37721
38029
  remotionMajorVersion: null,
38030
+ hasI18nLibrary: false,
38031
+ tanstackQueryVersion: null,
38032
+ styledComponentsVersion: null,
38033
+ hasThree: false,
38034
+ threeVersion: null,
38035
+ threeRelease: null,
38036
+ hasReactThreeFiber: false,
38037
+ reactThreeFiberVersion: null,
38038
+ reactThreeFiberMajorVersion: null,
37722
38039
  hasSsrDependency: false,
37723
38040
  preactVersion: null,
37724
38041
  preactMajorVersion: null,
37725
38042
  hasReactNativeWorkspace: false,
37726
38043
  nextjsVersion: null,
37727
38044
  nextjsMajorVersion: null,
38045
+ reactRouterVersion: null,
38046
+ hasReactRouterFramework: false,
37728
38047
  expoVersion: null,
37729
38048
  shopifyFlashListVersion: null,
37730
38049
  shopifyFlashListMajorVersion: null,
@@ -37843,8 +38162,27 @@ const discoverProject = (directory) => {
37843
38162
  packageName: "mobx",
37844
38163
  version: workspaceFacts.mobx.version
37845
38164
  });
38165
+ const reactRouterVersion = workspaceFacts.reactRouter.packageName === null ? null : resolveCatalogBackedDependencyVersion({
38166
+ rootDirectory: directory,
38167
+ rootPackageJson: packageJson,
38168
+ packageName: workspaceFacts.reactRouter.packageName,
38169
+ version: workspaceFacts.reactRouter.version
38170
+ });
37846
38171
  const preactVersion = getPreactVersion(packageJson);
37847
38172
  const remotionVersion = workspaceFacts.remotionVersion;
38173
+ const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
38174
+ const reactThreeFiberVersion = workspaceFacts.reactThreeFiber.packageName ? resolveCatalogBackedDependencyVersion({
38175
+ rootDirectory: directory,
38176
+ rootPackageJson: packageJson,
38177
+ packageName: workspaceFacts.reactThreeFiber.packageName,
38178
+ version: workspaceFacts.reactThreeFiber.version
38179
+ }) : null;
38180
+ const threeVersion = resolveCatalogBackedDependencyVersion({
38181
+ rootDirectory: directory,
38182
+ rootPackageJson: packageJson,
38183
+ packageName: "three",
38184
+ version: workspaceFacts.threeVersion
38185
+ });
37848
38186
  const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
37849
38187
  const projectInfo = {
37850
38188
  rootDirectory: directory,
@@ -37855,9 +38193,11 @@ const discoverProject = (directory) => {
37855
38193
  zodVersion,
37856
38194
  zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
37857
38195
  mobxVersion,
37858
- mobxMajorVersion: mobxVersion === null ? null : getLowestDependencyMajor(mobxVersion),
38196
+ mobxMajorVersion: mobxVersion === null ? null : getDependencyMajorWithinSupportedRange(mobxVersion, 6),
37859
38197
  hasMobxReact: workspaceFacts.hasMobxReact,
38198
+ mobxReactVersion: workspaceFacts.mobxReactVersion,
37860
38199
  hasMobxReactLite: workspaceFacts.hasMobxReactLite,
38200
+ mobxReactLiteVersion: workspaceFacts.mobxReactLiteVersion,
37861
38201
  hasMobxStateTree: workspaceFacts.hasMobxStateTree,
37862
38202
  hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
37863
38203
  zustandVersion,
@@ -37866,18 +38206,29 @@ const discoverProject = (directory) => {
37866
38206
  hasTypeScript,
37867
38207
  hasReactCompiler: detectReactCompiler(directory, packageJson),
37868
38208
  hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
37869
- hasTanStackQuery: hasTanStackQuery(packageJson),
38209
+ hasTanStackQuery: tanstackQueryVersion !== null,
38210
+ hasI18nLibrary: workspaceFacts.hasI18nLibrary,
38211
+ tanstackQueryVersion,
38212
+ styledComponentsVersion: workspaceFacts.styledComponentsVersion,
37870
38213
  valtioVersion,
37871
38214
  valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
37872
38215
  hasRemotion: workspaceFacts.hasRemotionDependency,
37873
38216
  remotionVersion,
37874
38217
  remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
38218
+ hasThree: workspaceFacts.hasThree,
38219
+ threeVersion,
38220
+ threeRelease: parseThreeRelease(threeVersion),
38221
+ hasReactThreeFiber: workspaceFacts.hasReactThreeFiber,
38222
+ reactThreeFiberVersion,
38223
+ reactThreeFiberMajorVersion: reactThreeFiberVersion === null ? null : getLowestDependencyMajor(reactThreeFiberVersion),
37875
38224
  hasSsrDependency: workspaceFacts.hasSsrDependency,
37876
38225
  preactVersion,
37877
38226
  preactMajorVersion: parseReactMajor(preactVersion),
37878
38227
  hasReactNativeWorkspace,
37879
38228
  nextjsVersion,
37880
38229
  nextjsMajorVersion: nextjsVersion === null ? null : getLowestDependencyMajor(nextjsVersion),
38230
+ reactRouterVersion,
38231
+ hasReactRouterFramework: workspaceFacts.hasReactRouterFramework,
37881
38232
  expoVersion,
37882
38233
  shopifyFlashListVersion,
37883
38234
  shopifyFlashListMajorVersion: shopifyFlashListVersion === null ? null : getLowestDependencyMajor(shopifyFlashListVersion),
@@ -41181,10 +41532,10 @@ const SSR_FRAMEWORKS = new Set([
41181
41532
  "gatsby",
41182
41533
  "tanstack-start"
41183
41534
  ]);
41184
- const addMajorLadder = (capabilities, name, major, earliest, latest) => {
41185
- if (major === null) return;
41186
- const cappedMajor = Math.min(major, latest);
41187
- for (let candidate = earliest; candidate <= cappedMajor; candidate += 1) capabilities.add(`${name}:${candidate}`);
41535
+ const addVersionCapabilityLadder = (capabilities, name, detectedVersion, earliest, latest) => {
41536
+ if (detectedVersion === null) return;
41537
+ const cappedVersion = Math.min(detectedVersion, latest);
41538
+ for (let candidate = earliest; candidate <= cappedVersion; candidate += 1) capabilities.add(`${name}:${candidate}`);
41188
41539
  };
41189
41540
  const buildCapabilities = (project) => {
41190
41541
  const capabilities = /* @__PURE__ */ new Set();
@@ -41197,39 +41548,86 @@ const buildCapabilities = (project) => {
41197
41548
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
41198
41549
  if (project.isStaticExport) capabilities.add("nextjs:static-export");
41199
41550
  if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
41200
- addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
41551
+ if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
41552
+ const reactRouterVersion = project.reactRouterVersion ?? null;
41553
+ if (reactRouterVersion !== null) {
41554
+ capabilities.add("react-router");
41555
+ if (project.hasReactRouterFramework === true) capabilities.add("react-router-framework");
41556
+ const detectedVersion = parseReactMajorMinor(reactRouterVersion);
41557
+ if (detectedVersion !== null) {
41558
+ for (const threshold of REACT_ROUTER_CAPABILITY_THRESHOLDS) if (isMajorMinorAtLeast(detectedVersion, threshold)) capabilities.add(threshold.capability);
41559
+ }
41560
+ }
41561
+ addVersionCapabilityLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
41201
41562
  if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
41202
41563
  major: 19,
41203
41564
  minor: 2
41204
41565
  })) capabilities.add("react:19.2");
41205
- if (project.tailwindVersion !== null) capabilities.add("tailwind");
41206
- if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
41207
- major: 3,
41208
- minor: 4
41209
- })) capabilities.add("tailwind:3.4");
41566
+ if (project.tailwindVersion !== null) {
41567
+ capabilities.add("tailwind");
41568
+ const tailwindVersion = parseTailwindMajorMinor(project.tailwindVersion);
41569
+ if (isMajorMinorAtLeast(tailwindVersion, {
41570
+ major: 3,
41571
+ minor: 4
41572
+ })) capabilities.add("tailwind:3.4");
41573
+ if (tailwindVersion !== null && isMajorMinorAtLeast(tailwindVersion, {
41574
+ major: 4,
41575
+ minor: 0
41576
+ })) capabilities.add("tailwind:4");
41577
+ }
41210
41578
  if (project.zodVersion !== null) capabilities.add("zod");
41211
41579
  if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
41212
41580
  if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
41213
41581
  if (project.hasMobxReact === true) capabilities.add("mobx-react");
41214
41582
  if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
41215
41583
  if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
41584
+ const mobxReactVersion = parseDependencyMajorMinor(project.mobxReactVersion);
41585
+ const mobxReactLiteVersion = parseDependencyMajorMinor(project.mobxReactLiteVersion);
41586
+ const hasMobxReactObserverMemoGuard = mobxReactVersion !== null && isMajorMinorAtLeast(mobxReactVersion, {
41587
+ major: 7,
41588
+ minor: 3
41589
+ });
41590
+ const hasMobxReactLiteObserverMemoGuard = mobxReactLiteVersion !== null && isMajorMinorAtLeast(mobxReactLiteVersion, {
41591
+ major: 3,
41592
+ minor: 3
41593
+ });
41594
+ if (hasMobxReactObserverMemoGuard) capabilities.add("mobx-react-observer-memo-guard");
41595
+ if (hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-lite-observer-memo-guard");
41596
+ if (hasMobxReactObserverMemoGuard || hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-binding-observer-memo-guard");
41216
41597
  if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
41217
41598
  if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
41218
- if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addMajorLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
41599
+ if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addVersionCapabilityLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
41600
+ const mobxVersion = parseDependencyMajorMinor(project.mobxVersion);
41601
+ if (project.mobxMajorVersion === 6 && mobxVersion !== null && isMajorMinorAtLeast(mobxVersion, {
41602
+ major: 6,
41603
+ minor: 10
41604
+ })) capabilities.add("mobx:6.10");
41219
41605
  if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
41220
- if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addMajorLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
41606
+ if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addVersionCapabilityLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
41221
41607
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
41222
41608
  if (project.hasReactCompiler) capabilities.add("react-compiler");
41223
- if (project.hasTanStackQuery) capabilities.add("tanstack-query");
41609
+ if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
41610
+ if (project.styledComponentsVersion) {
41611
+ capabilities.add("styled-components");
41612
+ const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
41613
+ if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
41614
+ }
41615
+ if (project.hasI18nLibrary) capabilities.add("i18n");
41224
41616
  if (project.valtioVersion !== null) capabilities.add("valtio");
41225
- addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
41617
+ addVersionCapabilityLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
41226
41618
  if (project.hasRemotion) {
41227
41619
  capabilities.add("remotion");
41228
- addMajorLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
41620
+ addVersionCapabilityLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
41621
+ }
41622
+ if (project.hasThree || project.hasReactThreeFiber) capabilities.add("three");
41623
+ addVersionCapabilityLadder(capabilities, "three", project.threeRelease ?? null, 145, 250);
41624
+ if (project.hasReactThreeFiber) {
41625
+ capabilities.add("r3f");
41626
+ addVersionCapabilityLadder(capabilities, "r3f", project.reactThreeFiberMajorVersion ?? null, 3, 10);
41229
41627
  }
41230
41628
  if (project.hasTypeScript) capabilities.add("typescript");
41231
41629
  if (project.preactVersion !== null) capabilities.add("preact");
41232
- addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
41630
+ addVersionCapabilityLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
41233
41631
  if (project.preactVersion !== null && project.reactVersion === null) capabilities.add("pure-preact");
41234
41632
  return capabilities;
41235
41633
  };
@@ -41241,7 +41639,7 @@ const getCapabilities = (project) => {
41241
41639
  capabilitiesByProject.set(project, capabilities);
41242
41640
  return capabilities;
41243
41641
  };
41244
- const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
41642
+ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen, includedTags) => {
41245
41643
  if (requires) {
41246
41644
  for (const capability of requires) if (!capabilities.has(capability)) return false;
41247
41645
  }
@@ -41252,20 +41650,29 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
41252
41650
  if (tags) {
41253
41651
  for (const tag of tags) if (ignoredTags.has(tag)) return false;
41254
41652
  }
41653
+ if (includedTags && includedTags.size > 0) {
41654
+ if (!tags?.some((tag) => includedTags.has(tag))) return false;
41655
+ }
41255
41656
  return true;
41256
41657
  };
41658
+ const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
41257
41659
  const yieldToEventLoop = () => new Promise((resolve) => {
41258
41660
  setImmediate(resolve);
41259
41661
  });
41260
41662
  const createSecurityScanSession = (rootDirectory, options) => {
41261
41663
  const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
41262
41664
  const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
41665
+ const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
41263
41666
  const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
41264
41667
  const rule = entry.rule;
41265
41668
  const scan = rule.scan;
41266
41669
  if (typeof scan !== "function") return [];
41267
- if (rule.defaultEnabled === false) return [];
41268
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
41670
+ if (!shouldEnableRuleByDefaultStatus({
41671
+ defaultEnabled: rule.defaultEnabled,
41672
+ includeTagDefaults: options.includeTagDefaults === true,
41673
+ hasIncludedTags: includedTags.size > 0
41674
+ })) return [];
41675
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) return [];
41269
41676
  return [{
41270
41677
  entry,
41271
41678
  scan,
@@ -43267,8 +43674,9 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
43267
43674
  }
43268
43675
  return enabled;
43269
43676
  };
43270
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
43271
- const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
43677
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
43678
+ const hasIncludedTags = includedTags.size > 0;
43679
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
43272
43680
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
43273
43681
  const jsPlugins = [];
43274
43682
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -43283,9 +43691,14 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
43283
43691
  if (rule.scan !== void 0) continue;
43284
43692
  if (customRulesOnly && registryEntry.originallyExternal) continue;
43285
43693
  if (rule.framework !== "global" && !rule.requires) continue;
43286
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
43694
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
43287
43695
  const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
43288
- if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
43696
+ if (!shouldEnableRuleByDefaultStatus({
43697
+ defaultEnabled: rule.defaultEnabled,
43698
+ includeTagDefaults,
43699
+ hasIncludedTags,
43700
+ hasExplicitOverride: explicitRuleOverride !== void 0
43701
+ })) continue;
43289
43702
  const severity = resolveRuleSeverityOverride({
43290
43703
  ruleKey: registryEntry.key,
43291
43704
  category: rule.category
@@ -43294,7 +43707,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
43294
43707
  enabledReactDoctorRules[registryEntry.key] = severity;
43295
43708
  }
43296
43709
  const userPluginRules = {};
43297
- if (ruleSelection !== "sidecar") for (const userPlugin of userPlugins) {
43710
+ if (ruleSelection !== "sidecar" && !hasIncludedTags) for (const userPlugin of userPlugins) {
43298
43711
  Object.assign(userPluginRules, buildUserPluginRules(userPlugin, severityControls));
43299
43712
  jsPlugins.push(userPlugin.entry);
43300
43713
  }
@@ -43511,6 +43924,19 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
43511
43924
  }
43512
43925
  };
43513
43926
  };
43927
+ const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
43928
+ const fingerprintFileContents = (filePath, fingerprintLength) => {
43929
+ const fileStats = NFS.statSync(filePath, { bigint: true });
43930
+ const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
43931
+ if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
43932
+ const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
43933
+ fingerprintCacheByFilePath.set(filePath, {
43934
+ fingerprint,
43935
+ modifiedTimeNanoseconds: fileStats.mtimeNs,
43936
+ sizeBytes: fileStats.size
43937
+ });
43938
+ return fingerprint;
43939
+ };
43514
43940
  const bundledRequire$3 = createRequire(import.meta.url);
43515
43941
  const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
43516
43942
  const resolveChildNodeVersion = (nodeBinaryPath) => {
@@ -43534,6 +43960,13 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS$1 = [
43534
43960
  "oxlint-plugin-react-doctor/package.json",
43535
43961
  "eslint-plugin-react-hooks/package.json"
43536
43962
  ];
43963
+ const resolvePluginFingerprint = () => {
43964
+ try {
43965
+ return fingerprintFileContents(bundledRequire$3.resolve("oxlint-plugin-react-doctor"), 16);
43966
+ } catch {
43967
+ return "unresolved";
43968
+ }
43969
+ };
43537
43970
  const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43538
43971
  const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
43539
43972
  for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS$1) try {
@@ -43543,6 +43976,7 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43543
43976
  } catch {
43544
43977
  versions.push(`${specifier}=missing`);
43545
43978
  }
43979
+ versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
43546
43980
  return versions;
43547
43981
  };
43548
43982
  const esmRequire = createRequire(import.meta.url);
@@ -45018,7 +45452,7 @@ const reactHooksJsPluginDropNote = (error) => {
45018
45452
  * 6. always restore disable directives + clean up the temp dir
45019
45453
  */
45020
45454
  const runOxlint = async (options) => {
45021
- 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;
45455
+ 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;
45022
45456
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
45023
45457
  const severityControls = buildRuleSeverityControls(userConfig);
45024
45458
  validateRuleRegistration();
@@ -45032,13 +45466,15 @@ const runOxlint = async (options) => {
45032
45466
  }
45033
45467
  const pluginPath = resolvePluginPath();
45034
45468
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
45035
- const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
45469
+ const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
45036
45470
  const buildConfig = (overrides) => createOxlintConfig({
45037
45471
  pluginPath,
45038
45472
  project,
45039
45473
  customRulesOnly,
45040
45474
  extendsPaths: overrides.extendsPaths,
45041
45475
  ignoredTags,
45476
+ includedTags,
45477
+ includeTagDefaults,
45042
45478
  serverAuthFunctionNames,
45043
45479
  severityControls,
45044
45480
  userPlugins,
@@ -45427,6 +45863,8 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
45427
45863
  respectInlineDisables: input.respectInlineDisables,
45428
45864
  adoptExistingLintConfig: input.adoptExistingLintConfig,
45429
45865
  ignoredTags: input.ignoredTags,
45866
+ includedTags: input.includedTags,
45867
+ includeTagDefaults: input.includeTagDefaults,
45430
45868
  userConfig: input.userConfig ?? null,
45431
45869
  configSourceDirectory: input.configSourceDirectory,
45432
45870
  onPartialFailure: (reason) => {
@@ -46275,7 +46713,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
46275
46713
  const securityScanFailedRef = yield* make$13(false);
46276
46714
  const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
46277
46715
  project,
46278
- ignoredTags: input.ignoredTags
46716
+ ignoredTags: input.ignoredTags,
46717
+ includedTags: input.includedTags,
46718
+ includeTagDefaults: input.includeTagDefaults
46279
46719
  })).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
46280
46720
  const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
46281
46721
  const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
@@ -46366,6 +46806,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
46366
46806
  respectInlineDisables: input.respectInlineDisables,
46367
46807
  adoptExistingLintConfig: input.adoptExistingLintConfig,
46368
46808
  ignoredTags: input.ignoredTags,
46809
+ includedTags: input.includedTags,
46810
+ includeTagDefaults: input.includeTagDefaults,
46369
46811
  userConfig: resolvedConfig.config ?? void 0,
46370
46812
  configSourceDirectory: resolvedConfig.configSourceDirectory ?? void 0,
46371
46813
  onFileProgress: (scannedFileCount, totalFileCount) => {
@@ -47510,7 +47952,7 @@ const makeNoopConsole = () => ({
47510
47952
  });
47511
47953
  //#endregion
47512
47954
  //#region src/cli/utils/version.ts
47513
- const VERSION = "0.8.1-dev.e6a1557";
47955
+ const VERSION = "0.8.1-dev.f5f13b8";
47514
47956
  //#endregion
47515
47957
  //#region src/cli/utils/json-mode.ts
47516
47958
  let context = null;
@@ -47597,7 +48039,11 @@ const getRunId = () => {
47597
48039
  };
47598
48040
  //#endregion
47599
48041
  //#region src/cli/utils/build-run-context.ts
47600
- const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
48042
+ const ROOT_SUBCOMMANDS = new Set([
48043
+ "design",
48044
+ "install",
48045
+ "setup"
48046
+ ]);
47601
48047
  const detectInvokedVia = () => {
47602
48048
  const userAgent = process.env.npm_config_user_agent;
47603
48049
  if (!userAgent) return "unknown";
@@ -47681,7 +48127,9 @@ const buildSentryProjectContext = (projectInfo) => ({
47681
48127
  reactMajorVersion: projectInfo.reactMajorVersion,
47682
48128
  hasTypeScript: projectInfo.hasTypeScript,
47683
48129
  hasReactCompiler: projectInfo.hasReactCompiler,
47684
- hasTanStackQuery: projectInfo.hasTanStackQuery,
48130
+ tanstackQueryVersion: projectInfo.tanstackQueryVersion,
48131
+ mobxVersion: projectInfo.mobxVersion,
48132
+ styledComponentsVersion: projectInfo.styledComponentsVersion,
47685
48133
  tailwindVersion: projectInfo.tailwindVersion,
47686
48134
  zodVersion: projectInfo.zodVersion,
47687
48135
  preactVersion: projectInfo.preactVersion,
@@ -47862,13 +48310,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47862
48310
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47863
48311
  * standard `SENTRY_RELEASE` override.
47864
48312
  */
47865
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.e6a1557`;
48313
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.f5f13b8`;
47866
48314
  /**
47867
48315
  * Deployment environment shown in Sentry's environment filter. Defaults to
47868
48316
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47869
48317
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47870
48318
  */
47871
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.e6a1557") ? "development" : "production");
48319
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.f5f13b8") ? "development" : "production");
47872
48320
  /**
47873
48321
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47874
48322
  * (set to `0` to disable tracing) and falls back to
@@ -60194,6 +60642,8 @@ const buildScanResultCacheKey = (input) => {
60194
60642
  warnings: input.options.warnings,
60195
60643
  adoptExistingLintConfig: input.options.adoptExistingLintConfig,
60196
60644
  ignoredTags: [...input.options.ignoredTags].sort(),
60645
+ includedTags: [...input.options.includedTags].sort(),
60646
+ includeTagDefaults: input.options.includeTagDefaults,
60197
60647
  concurrency: input.options.concurrency,
60198
60648
  lintBatchOrdering: resolveLintBatchOrdering(),
60199
60649
  baselineRef: input.options.baseline?.ref,
@@ -61020,8 +61470,8 @@ const createDiagnosticEvidenceReader = (rootDirectory, options = {}) => {
61020
61470
  //#endregion
61021
61471
  //#region src/cli/utils/build-no-score-message.ts
61022
61472
  const ENTERPRISE_CONTACT_HINT = `Want something custom to your company? Contact us at ${ENTERPRISE_CONTACT_URL}.`;
61023
- const buildNoScoreMessage = (isScoreDisabled) => {
61024
- return `${isScoreDisabled ? "Score disabled by --no-score." : "Score unavailable (could not reach the score API)."} ${ENTERPRISE_CONTACT_HINT}`;
61473
+ const buildNoScoreMessage = (isScoreDisabled, disabledMessage) => {
61474
+ return `${isScoreDisabled ? disabledMessage ?? "Score disabled by --no-score." : "Score unavailable (could not reach the score API)."} ${ENTERPRISE_CONTACT_HINT}`;
61025
61475
  };
61026
61476
  //#endregion
61027
61477
  //#region src/cli/utils/render-agent-guidance.ts
@@ -62146,40 +62596,47 @@ const buildChangedLineMatcher = (directory, changedLineRanges) => {
62146
62596
  return diagnosticIntersectsLineRanges(diagnostic, ranges);
62147
62597
  };
62148
62598
  };
62149
- const buildIgnoredTags = (userConfig) => {
62599
+ const buildIgnoredTags = (userConfig, includedTags) => {
62150
62600
  const tags = /* @__PURE__ */ new Set();
62151
62601
  if (userConfig?.ignore?.tags) for (const tag of userConfig.ignore.tags) tags.add(tag);
62602
+ for (const tag of includedTags) tags.delete(tag);
62152
62603
  return tags;
62153
62604
  };
62154
- const mergeInspectOptions = (inputOptions, userConfig) => ({
62155
- lint: inputOptions.lint ?? userConfig?.lint ?? true,
62156
- deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
62157
- supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
62158
- verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
62159
- outputDirectory: inputOptions.outputDirectory || null,
62160
- scoreOnly: inputOptions.scoreOnly ?? false,
62161
- noScore: inputOptions.noScore ?? userConfig?.noScore ?? false,
62162
- isCi: inputOptions.isCi ?? false,
62163
- isCiOrCodingAgentEnvironment: isCiOrCodingAgentEnvironment(),
62164
- isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
62165
- silent: inputOptions.silent ?? false,
62166
- includePaths: inputOptions.includePaths ?? [],
62167
- customRulesOnly: userConfig?.customRulesOnly ?? false,
62168
- share: userConfig?.share ?? true,
62169
- respectInlineDisables: inputOptions.respectInlineDisables ?? userConfig?.respectInlineDisables ?? true,
62170
- warnings: inputOptions.warnings ?? userConfig?.warnings ?? true,
62171
- categoryFilters: new Set(resolveCliCategories(inputOptions.categoryFilters) ?? []),
62172
- adoptExistingLintConfig: userConfig?.adoptExistingLintConfig ?? true,
62173
- ignoredTags: buildIgnoredTags(userConfig),
62174
- outputSurface: inputOptions.outputSurface ?? "cli",
62175
- suppressRendering: inputOptions.suppressRendering ?? false,
62176
- concurrentScan: inputOptions.concurrentScan ?? false,
62177
- concurrency: inputOptions.concurrency,
62178
- maxDurationMs: inputOptions.maxDurationMs ?? null,
62179
- baseline: inputOptions.baseline ?? null,
62180
- changedLineRanges: inputOptions.changedLineRanges ?? null,
62181
- supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
62182
- });
62605
+ const mergeInspectOptions = (inputOptions, userConfig) => {
62606
+ const includedTags = inputOptions.includedTags ?? /* @__PURE__ */ new Set();
62607
+ return {
62608
+ lint: inputOptions.lint ?? userConfig?.lint ?? true,
62609
+ deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
62610
+ supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
62611
+ verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
62612
+ outputDirectory: inputOptions.outputDirectory || null,
62613
+ scoreOnly: inputOptions.scoreOnly ?? false,
62614
+ noScore: inputOptions.noScore ?? userConfig?.noScore ?? false,
62615
+ isCi: inputOptions.isCi ?? false,
62616
+ isCiOrCodingAgentEnvironment: isCiOrCodingAgentEnvironment(),
62617
+ isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
62618
+ silent: inputOptions.silent ?? false,
62619
+ includePaths: inputOptions.includePaths ?? [],
62620
+ customRulesOnly: includedTags.size > 0 ? false : userConfig?.customRulesOnly ?? false,
62621
+ share: userConfig?.share ?? true,
62622
+ respectInlineDisables: inputOptions.respectInlineDisables ?? userConfig?.respectInlineDisables ?? true,
62623
+ warnings: inputOptions.warnings ?? userConfig?.warnings ?? true,
62624
+ categoryFilters: new Set(resolveCliCategories(inputOptions.categoryFilters) ?? []),
62625
+ adoptExistingLintConfig: includedTags.size > 0 ? false : userConfig?.adoptExistingLintConfig ?? true,
62626
+ ignoredTags: buildIgnoredTags(userConfig, includedTags),
62627
+ includedTags,
62628
+ includeTagDefaults: inputOptions.includeTagDefaults ?? false,
62629
+ scoreDisabledMessage: inputOptions.scoreDisabledMessage,
62630
+ outputSurface: inputOptions.outputSurface ?? "cli",
62631
+ suppressRendering: inputOptions.suppressRendering ?? false,
62632
+ concurrentScan: inputOptions.concurrentScan ?? false,
62633
+ concurrency: inputOptions.concurrency,
62634
+ maxDurationMs: inputOptions.maxDurationMs ?? null,
62635
+ baseline: inputOptions.baseline ?? null,
62636
+ changedLineRanges: inputOptions.changedLineRanges ?? null,
62637
+ supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
62638
+ };
62639
+ };
62183
62640
  const deriveScope = (options) => {
62184
62641
  if (options.baseline) return "changed";
62185
62642
  if (options.changedLineRanges !== null) return "lines";
@@ -62310,6 +62767,8 @@ const runBaselineComparison = async (params) => {
62310
62767
  warnings: params.options.warnings,
62311
62768
  adoptExistingLintConfig: params.options.adoptExistingLintConfig,
62312
62769
  ignoredTags: params.options.ignoredTags,
62770
+ includedTags: params.options.includedTags,
62771
+ includeTagDefaults: params.options.includeTagDefaults,
62313
62772
  nodeBinaryPath: params.resolvedNodeBinaryPath ?? void 0,
62314
62773
  runDeadCode: false,
62315
62774
  isCi: params.options.isCi,
@@ -62403,6 +62862,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
62403
62862
  warnings: options.warnings,
62404
62863
  adoptExistingLintConfig: options.adoptExistingLintConfig,
62405
62864
  ignoredTags: options.ignoredTags,
62865
+ includedTags: options.includedTags,
62866
+ includeTagDefaults: options.includeTagDefaults,
62406
62867
  nodeBinaryPath: resolvedNodeBinaryPath ?? void 0,
62407
62868
  runDeadCode: options.deadCode,
62408
62869
  isCi: options.isCi,
@@ -62591,7 +63052,7 @@ const finalizeAndRender = (input) => gen(function* () {
62591
63052
  securityScanFailed
62592
63053
  });
62593
63054
  const hasSkippedChecks = skippedChecks.length > 0;
62594
- const noScoreMessage = buildNoScoreMessage(options.noScore);
63055
+ const noScoreMessage = buildNoScoreMessage(options.noScore, options.scoreDisabledMessage);
62595
63056
  const buildResult = () => ({
62596
63057
  diagnostics: [...diagnostics],
62597
63058
  score,
@@ -64696,21 +65157,25 @@ const resolveParallelFlag = (parallel) => parallel === false ? 1 : void 0;
64696
65157
  */
64697
65158
  const resolveCliInspectOptions = (flags, userConfig) => {
64698
65159
  const wantsWarningGate = pickBlockingLevel(flags, userConfig) === "warning";
65160
+ const isDesignScan = flags.design === true;
64699
65161
  return {
64700
65162
  lint: flags.lint,
64701
- deadCode: flags.deadCode,
64702
- supplyChain: flags.supplyChain,
65163
+ deadCode: isDesignScan ? false : flags.deadCode,
65164
+ supplyChain: isDesignScan ? false : flags.supplyChain,
64703
65165
  verbose: flags.verbose,
64704
65166
  outputDirectory: flags.outputDir,
64705
65167
  respectInlineDisables: flags.respectInlineDisables === false ? false : void 0,
64706
65168
  warnings: wantsWarningGate ? true : flags.warnings,
64707
65169
  scoreOnly: flags.score === true,
64708
- noScore: flags.score === false || flags.telemetry === false ? true : void 0,
65170
+ noScore: isDesignScan || flags.score === false || flags.telemetry === false ? true : void 0,
64709
65171
  isCi: isCiEnvironment(),
64710
65172
  silent: Boolean(flags.json),
64711
65173
  concurrency: resolveParallelFlag(flags.parallel),
64712
65174
  maxDurationMs: resolveMaxDurationFlag(flags.maxDuration),
64713
- categoryFilters: resolveCliCategories(flags.category)
65175
+ categoryFilters: resolveCliCategories(flags.category),
65176
+ includedTags: isDesignScan ? new Set(["design"]) : void 0,
65177
+ includeTagDefaults: isDesignScan ? true : void 0,
65178
+ scoreDisabledMessage: isDesignScan ? "Design scans do not affect the React health score." : void 0
64714
65179
  };
64715
65180
  };
64716
65181
  //#endregion
@@ -65128,7 +65593,7 @@ const maybeMigrateLegacyConfig = async (requestedDirectory, { isQuiet, isStaged
65128
65593
  if (!(!isQuiet && !isStaged && process.stdout.isTTY === true && !isCiOrCodingAgentEnvironment())) return;
65129
65594
  await runProjectMigrations(requestedDirectory);
65130
65595
  };
65131
- const inspectAction = async (directory, flags) => {
65596
+ const inspectAction = async (directory, flags, invocationCommand = "inspect") => {
65132
65597
  const isScoreOnly = Boolean(flags.score);
65133
65598
  const isJsonMode = Boolean(flags.json);
65134
65599
  const isQuiet = isScoreOnly || isJsonMode;
@@ -65142,7 +65607,7 @@ const inspectAction = async (directory, flags) => {
65142
65607
  });
65143
65608
  if (flags.jsonOut) recordCount(METRIC.jsonOutUsed, 1);
65144
65609
  }
65145
- recordCount(METRIC.cliInvoked, 1, { command: "inspect" });
65610
+ recordCount(METRIC.cliInvoked, 1, { command: invocationCommand });
65146
65611
  try {
65147
65612
  validateModeFlags(flags);
65148
65613
  if (flags.staged) setJsonReportMode("staged");
@@ -65454,6 +65919,13 @@ const inspectAction = async (directory, flags) => {
65454
65919
  }
65455
65920
  };
65456
65921
  //#endregion
65922
+ //#region src/cli/commands/design.ts
65923
+ const designAction = async (directory, flags) => inspectAction(directory, {
65924
+ ...flags,
65925
+ design: true,
65926
+ lint: flags.lint ?? true
65927
+ }, "design");
65928
+ //#endregion
65457
65929
  //#region src/cli/commands/install.ts
65458
65930
  const installAction = async (options, command) => {
65459
65931
  recordCount(METRIC.cliInvoked, 1, { command: "install" });
@@ -66290,6 +66762,7 @@ const INSTALL_FLAG_SPEC = {
66290
66762
  shortOptionsWithRequiredValues: new Set(["-c"])
66291
66763
  };
66292
66764
  const COMMAND_FLAG_SPECS = new Map([
66765
+ ["design", ROOT_FLAG_SPEC],
66293
66766
  ["install", INSTALL_FLAG_SPEC],
66294
66767
  ["setup", INSTALL_FLAG_SPEC],
66295
66768
  ["version", {
@@ -66446,6 +66919,7 @@ ${formatExampleLines([
66446
66919
  ["react-doctor --scope changed --base main", "scan only new issues vs. main"],
66447
66920
  ["react-doctor --project modules/a,modules/b", "score each module separately (names or paths)"],
66448
66921
  ["react-doctor --staged", "scan staged files (pre-commit hook)"],
66922
+ ["react-doctor design", "run the focused UI design audit"],
66449
66923
  ["react-doctor --category Security", "show only one diagnostic category"],
66450
66924
  ["react-doctor --blocking warning", "fail CI on warnings too (default: error)"],
66451
66925
  ["react-doctor --json > report.json", "write a machine-readable report"],
@@ -66479,6 +66953,20 @@ ${highlighter.dim("Managing CI:")}
66479
66953
  ${highlighter.dim("Learn more:")}
66480
66954
  ${highlighter.info(CANONICAL_GITHUB_URL)}
66481
66955
  `;
66956
+ const renderDesignHelpEpilog = () => `
66957
+ ${highlighter.dim("Examples:")}
66958
+ ${formatExampleLines([
66959
+ ["react-doctor design", "audit UI design in the current project"],
66960
+ ["react-doctor design ./apps/web", "audit one application"],
66961
+ ["react-doctor design --verbose", "show every design finding"],
66962
+ ["react-doctor design --json", "write a design-only JSON report"]
66963
+ ])}
66964
+
66965
+ ${highlighter.dim("Scope:")}
66966
+ Runs only rules tagged ${highlighter.info("design")}, including focused rules that stay opt-in during a general health scan.
66967
+ Dead-code, supply-chain, external lint-config, custom-plugin, and health-score passes are skipped.
66968
+ Standard scan flags such as ${highlighter.info("--scope")}, ${highlighter.info("--project")}, ${highlighter.info("--verbose")}, and ${highlighter.info("--json")} still work.
66969
+ `;
66482
66970
  const renderCiHelpEpilog = () => `
66483
66971
  ${highlighter.dim("Examples:")}
66484
66972
  ${formatExampleLines([
@@ -66500,6 +66988,7 @@ ${highlighter.dim("Learn more:")}
66500
66988
  const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
66501
66989
  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);
66502
66990
  program.action(inspectAction);
66991
+ program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
66503
66992
  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));
66504
66993
  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);
66505
66994
  const providerOption = ["--provider <name>", "ci provider: github-actions or gitlab-ci (auto-detected by default)"];
@@ -66548,4 +67037,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
66548
67037
  export {};
66549
67038
 
66550
67039
  //# sourceMappingURL=cli.js.map
66551
- //# debugId=81bdc95e-12f2-565f-a05c-7b8a60a98f81
67040
+ //# debugId=87efffda-8fc4-5b52-80e1-7ec503c85206