react-doctor 0.8.1-dev.5774353 → 0.8.1-dev.5b468f8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="83a484ab-e975-5390-830a-f2f723c71935")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="4d155139-533f-5635-af83-9ee012355893")}catch(e){}}();
3
3
  import { createRequire } from "node:module";
4
4
  import * as NodeChildProcess from "node:child_process";
5
5
  import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
@@ -36022,44 +36022,6 @@ var AmbiguousProjectError = class extends Error {
36022
36022
  }
36023
36023
  };
36024
36024
  const isProjectDiscoveryError = (value) => value instanceof ProjectNotFoundError || value instanceof NoReactDependencyError || value instanceof PackageJsonNotFoundError || value instanceof NotADirectoryError || value instanceof AmbiguousProjectError;
36025
- const isErrnoException = (error) => error instanceof Error && "code" in error;
36026
- const IGNORABLE_READDIR_ERROR_CODES = new Set([
36027
- "EACCES",
36028
- "EPERM",
36029
- "ENOENT",
36030
- "ENOTDIR",
36031
- "EINVAL",
36032
- "ELOOP",
36033
- "ENAMETOOLONG"
36034
- ]);
36035
- const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
36036
- const readDirectoryEntries = (directoryPath) => {
36037
- try {
36038
- return NFS.readdirSync(directoryPath, { withFileTypes: true });
36039
- } catch (error) {
36040
- if (isIgnorableReaddirError(error)) return [];
36041
- throw error;
36042
- }
36043
- };
36044
- const isFile = (filePath) => {
36045
- try {
36046
- return NFS.statSync(filePath).isFile();
36047
- } catch {
36048
- return false;
36049
- }
36050
- };
36051
- const isDirectory = (directoryPath) => {
36052
- try {
36053
- return NFS.statSync(directoryPath).isDirectory();
36054
- } catch {
36055
- return false;
36056
- }
36057
- };
36058
- const isPlainObject = (value) => {
36059
- if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
36060
- const prototype = Object.getPrototypeOf(value);
36061
- return prototype === null || prototype === Object.prototype;
36062
- };
36063
36025
  const SOURCE_FILE_PATTERN = /\.(tsx?|jsx?|mts|mjs)$/;
36064
36026
  const GENERATED_BUNDLE_FILE_PATTERN = /\.(iife|umd|global|min)\.m?js$/i;
36065
36027
  const GENERATED_SOURCE_DIRECTORY_PATTERN = /(?:^|\/)__generated__\//;
@@ -36252,6 +36214,44 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
36252
36214
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
36253
36215
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
36254
36216
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
36217
+ const isErrnoException = (error) => error instanceof Error && "code" in error;
36218
+ const IGNORABLE_READDIR_ERROR_CODES = new Set([
36219
+ "EACCES",
36220
+ "EPERM",
36221
+ "ENOENT",
36222
+ "ENOTDIR",
36223
+ "EINVAL",
36224
+ "ELOOP",
36225
+ "ENAMETOOLONG"
36226
+ ]);
36227
+ const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
36228
+ const readDirectoryEntries = (directoryPath) => {
36229
+ try {
36230
+ return NFS.readdirSync(directoryPath, { withFileTypes: true });
36231
+ } catch (error) {
36232
+ if (isIgnorableReaddirError(error)) return [];
36233
+ throw error;
36234
+ }
36235
+ };
36236
+ const isFile = (filePath) => {
36237
+ try {
36238
+ return NFS.statSync(filePath).isFile();
36239
+ } catch {
36240
+ return false;
36241
+ }
36242
+ };
36243
+ const isDirectory = (directoryPath) => {
36244
+ try {
36245
+ return NFS.statSync(directoryPath).isDirectory();
36246
+ } catch {
36247
+ return false;
36248
+ }
36249
+ };
36250
+ const isPlainObject = (value) => {
36251
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
36252
+ const prototype = Object.getPrototypeOf(value);
36253
+ return prototype === null || prototype === Object.prototype;
36254
+ };
36255
36255
  const lastSourceMappingUrl = (fileContent) => {
36256
36256
  const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
36257
36257
  return lastReference ? lastReference[1] : null;
@@ -36571,10 +36571,10 @@ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"]
36571
36571
  const FRAMEWORK_PACKAGES = {
36572
36572
  next: "nextjs",
36573
36573
  "@tanstack/react-start": "tanstack-start",
36574
- vite: "vite",
36575
- "react-scripts": "cra",
36576
36574
  "@remix-run/react": "remix",
36577
36575
  gatsby: "gatsby",
36576
+ vite: "vite",
36577
+ "react-scripts": "cra",
36578
36578
  expo: "expo",
36579
36579
  "react-native": "react-native"
36580
36580
  };
@@ -36598,11 +36598,17 @@ const NEXT_CONFIG_FILENAMES = [
36598
36598
  ];
36599
36599
  const BABEL_CONFIG_FILENAMES = [
36600
36600
  ".babelrc",
36601
+ ".babelrc.js",
36601
36602
  ".babelrc.json",
36603
+ ".babelrc.cjs",
36604
+ ".babelrc.mjs",
36605
+ ".babelrc.cts",
36602
36606
  "babel.config.js",
36603
36607
  "babel.config.json",
36604
36608
  "babel.config.cjs",
36605
- "babel.config.mjs"
36609
+ "babel.config.mjs",
36610
+ "babel.config.ts",
36611
+ "babel.config.cts"
36606
36612
  ];
36607
36613
  const VITE_CONFIG_FILENAMES = [
36608
36614
  "vite.config.js",
@@ -36614,12 +36620,28 @@ const VITE_CONFIG_FILENAMES = [
36614
36620
  "vitest.config.ts",
36615
36621
  "vitest.config.js"
36616
36622
  ];
36623
+ const RSBUILD_CONFIG_FILENAMES = [
36624
+ "rsbuild.config.ts",
36625
+ "rsbuild.config.js",
36626
+ "rsbuild.config.mts",
36627
+ "rsbuild.config.mjs",
36628
+ "rsbuild.config.cts",
36629
+ "rsbuild.config.cjs"
36630
+ ];
36631
+ const RSPACK_CONFIG_FILENAMES = [
36632
+ "rspack.config.ts",
36633
+ "rspack.config.js",
36634
+ "rspack.config.mts",
36635
+ "rspack.config.mjs",
36636
+ "rspack.config.cts",
36637
+ "rspack.config.cjs"
36638
+ ];
36617
36639
  const EXPO_APP_CONFIG_FILENAMES = [
36618
36640
  "app.json",
36619
36641
  "app.config.js",
36620
36642
  "app.config.ts"
36621
36643
  ];
36622
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
36644
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|reactCompilerPreset\s*\(|["']react-compiler["']/;
36623
36645
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
36624
36646
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
36625
36647
  const hasCompilerPackage = (packageJson, compilerPackages) => {
@@ -36654,6 +36676,8 @@ const detectReactCompiler = (directory, packageJson) => {
36654
36676
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
36655
36677
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
36656
36678
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
36679
+ if (hasCompilerInConfigFiles(directory, RSBUILD_CONFIG_FILENAMES)) return true;
36680
+ if (hasCompilerInConfigFiles(directory, RSPACK_CONFIG_FILENAMES)) return true;
36657
36681
  if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
36658
36682
  return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
36659
36683
  };
@@ -36662,7 +36686,7 @@ const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((file
36662
36686
  const filePath = Path.join(directory, filename);
36663
36687
  return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
36664
36688
  });
36665
- const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:file|git|github|https?|link|patch|portal|workspace|npm):/i;
36689
+ const UNRESOLVABLE_PROTOCOL_VERSION = /^(?:catalog|file|git|github|https?|link|patch|portal|workspace|npm):/i;
36666
36690
  const DIST_TAG_VERSION = /^[a-z][a-z0-9._-]*$/i;
36667
36691
  const WILDCARD_VERSION = /^[*xX](?:\.[*xX])*$/;
36668
36692
  const NPM_ALIAS_VERSION = /^npm:(?:@[^/]+\/[^@]+|[^@]+)@(.+)$/i;
@@ -36795,6 +36819,16 @@ const getLowestDependencyMajor = (version) => {
36795
36819
  }
36796
36820
  return lowestMajor;
36797
36821
  };
36822
+ const getDependencyMajorWithinSupportedRange = (version, latestSupportedMajor) => {
36823
+ const normalizedVersion = normalizeDependencyVersion(version);
36824
+ if (normalizedVersion === null) return null;
36825
+ const validRange = import_semver.validRange(normalizedVersion);
36826
+ if (validRange === null) return null;
36827
+ const minimumVersion = import_semver.minVersion(validRange);
36828
+ if (minimumVersion === null || minimumVersion.major > latestSupportedMajor) return null;
36829
+ if (import_semver.intersects(validRange, `>=${latestSupportedMajor + 1}.0.0`)) return null;
36830
+ return minimumVersion.major;
36831
+ };
36798
36832
  const isConcreteDependencyVersion = (version) => {
36799
36833
  const normalizedVersion = normalizeDependencyVersion(version);
36800
36834
  return normalizedVersion !== null && /\d/.test(normalizedVersion);
@@ -36838,9 +36872,18 @@ const parseReactMajorMinor = (reactVersion) => {
36838
36872
  };
36839
36873
  };
36840
36874
  const parseLowerBoundVersion = (versionSpec) => import_semver.validRange(versionSpec) !== null ? import_semver.minVersion(versionSpec) : import_semver.coerce(versionSpec);
36841
- const parseTailwindMajorMinor = (tailwindVersion) => {
36842
- if (typeof tailwindVersion !== "string") return null;
36843
- const trimmed = tailwindVersion.trim();
36875
+ const parseThreeRelease = (threeVersion) => {
36876
+ if (typeof threeVersion !== "string") return null;
36877
+ const normalizedVersion = normalizeDependencyVersion(threeVersion);
36878
+ if (normalizedVersion === null) return null;
36879
+ const lowerBound = parseLowerBoundVersion(normalizedVersion);
36880
+ if (lowerBound === null) return null;
36881
+ if (lowerBound.major > 0) return Number.MAX_SAFE_INTEGER;
36882
+ return lowerBound.minor > 0 ? lowerBound.minor : null;
36883
+ };
36884
+ const parseDependencyMajorMinor = (dependencyVersion) => {
36885
+ if (typeof dependencyVersion !== "string") return null;
36886
+ const trimmed = dependencyVersion.trim();
36844
36887
  if (trimmed.length === 0) return null;
36845
36888
  const lowerBound = parseLowerBoundVersion(trimmed);
36846
36889
  if (lowerBound === null || lowerBound.major <= 0) return null;
@@ -36849,6 +36892,7 @@ const parseTailwindMajorMinor = (tailwindVersion) => {
36849
36892
  minor: lowerBound.minor
36850
36893
  };
36851
36894
  };
36895
+ const parseTailwindMajorMinor = (tailwindVersion) => parseDependencyMajorMinor(tailwindVersion);
36852
36896
  const hasUpperBoundOnlyPeerRange = (range) => {
36853
36897
  if (typeof range !== "string") return false;
36854
36898
  const normalizedRange = normalizeDependencyVersion(range);
@@ -36870,7 +36914,7 @@ const resolveEffectiveReactMajor = (reactVersion, packageJson) => {
36870
36914
  if (peerFloor === null) return hasUpperBoundOnlyPeerRange(peerReactRange) ? null : installedReactMajor;
36871
36915
  return installedReactMajor !== null ? Math.min(installedReactMajor, peerFloor) : peerFloor;
36872
36916
  };
36873
- const isCatalogReference = (version) => version.startsWith("catalog:");
36917
+ const isCatalogReference = (version) => typeof version === "string" && version.startsWith("catalog:");
36874
36918
  const extractCatalogName = (version) => {
36875
36919
  if (!isCatalogReference(version)) return null;
36876
36920
  const name = version.slice(8).trim();
@@ -37020,6 +37064,12 @@ const TAILWIND_ZOD_SECTIONS = [
37020
37064
  "devDependencies",
37021
37065
  "peerDependencies"
37022
37066
  ];
37067
+ const DEPENDENCY_SPEC_SECTIONS = [
37068
+ "dependencies",
37069
+ "devDependencies",
37070
+ "peerDependencies",
37071
+ "optionalDependencies"
37072
+ ];
37023
37073
  const EMPTY_DEPENDENCY_INFO = {
37024
37074
  reactVersion: null,
37025
37075
  tailwindVersion: null,
@@ -37029,7 +37079,7 @@ const EMPTY_DEPENDENCY_INFO = {
37029
37079
  const pickConcreteVersion = (packageJson, packageName, sections) => {
37030
37080
  for (const section of sections) {
37031
37081
  const version = packageJson[section]?.[packageName];
37032
- if (version === void 0) continue;
37082
+ if (typeof version !== "string") continue;
37033
37083
  if (isCatalogReference(version)) return null;
37034
37084
  if (isConcreteDependencyVersion(version)) return version;
37035
37085
  }
@@ -37061,13 +37111,16 @@ const extractDependencyInfo = (packageJson) => {
37061
37111
  };
37062
37112
  };
37063
37113
  const getDependencySpec = (packageJson, packageName) => {
37064
- const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
37065
- return typeof spec === "string" ? spec : null;
37114
+ for (const section of DEPENDENCY_SPEC_SECTIONS) {
37115
+ const spec = packageJson[section]?.[packageName];
37116
+ if (typeof spec === "string") return spec;
37117
+ }
37118
+ return null;
37066
37119
  };
37067
37120
  const getDependencyDeclaration = ({ packageJson, packageName, sections }) => {
37068
37121
  for (const section of sections) {
37069
37122
  const version = packageJson[section]?.[packageName];
37070
- if (version === void 0) continue;
37123
+ if (typeof version !== "string") continue;
37071
37124
  return {
37072
37125
  catalogReference: extractCatalogName(version) ?? null,
37073
37126
  hasDeclaration: true,
@@ -37101,24 +37154,15 @@ const getPreactVersion = (packageJson) => {
37101
37154
  ...packageJson.devDependencies
37102
37155
  }.preact ?? null;
37103
37156
  };
37104
- const TANSTACK_QUERY_PACKAGES = new Set([
37105
- "@tanstack/react-query",
37106
- "@tanstack/query-core",
37107
- "react-query"
37108
- ]);
37109
- const hasTanStackQuery = (packageJson) => {
37110
- const allDependencies = {
37111
- ...packageJson.peerDependencies,
37112
- ...packageJson.dependencies,
37113
- ...packageJson.devDependencies
37114
- };
37115
- return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
37116
- };
37117
- const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
37157
+ const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, sourceDirectory = rootDirectory, sourcePackageJson = rootPackageJson, version }) => {
37118
37158
  if (version === null || !isCatalogReference(version)) return version;
37119
37159
  const catalogName = extractCatalogName(version);
37120
- const resolvedLocalVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
37121
- if (resolvedLocalVersion) return resolvedLocalVersion;
37160
+ const resolvedSourceVersion = resolveCatalogVersion(sourcePackageJson, packageName, sourceDirectory, catalogName);
37161
+ if (resolvedSourceVersion) return resolvedSourceVersion;
37162
+ if (sourceDirectory !== rootDirectory || sourcePackageJson !== rootPackageJson) {
37163
+ const resolvedRootVersion = resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, catalogName);
37164
+ if (resolvedRootVersion) return resolvedRootVersion;
37165
+ }
37122
37166
  const monorepoRoot = findMonorepoRoot(rootDirectory);
37123
37167
  if (!monorepoRoot) return version;
37124
37168
  const monorepoPackageJsonPath = Path.join(monorepoRoot, "package.json");
@@ -37316,7 +37360,75 @@ const listWorkspacePackages = (rootDirectory) => {
37316
37360
  }
37317
37361
  return packages;
37318
37362
  };
37363
+ const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
37364
+ const allDependencies = {
37365
+ ...packageJson.devDependencies,
37366
+ ...packageJson.peerDependencies,
37367
+ ...packageJson.dependencies
37368
+ };
37369
+ for (const packageName of packageNames) {
37370
+ const version = allDependencies[packageName];
37371
+ if (version !== void 0) return version;
37372
+ }
37373
+ return null;
37374
+ };
37375
+ const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
37376
+ const getTanStackQueryVersion = (packageJson) => {
37377
+ return getPreferredDependencyVersion({
37378
+ packageJson,
37379
+ packageNames: TANSTACK_REACT_QUERY_PACKAGES
37380
+ });
37381
+ };
37382
+ const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
37383
+ const getStyledComponentsVersion = (packageJson) => {
37384
+ return getPreferredDependencyVersion({
37385
+ packageJson,
37386
+ packageNames: STYLED_COMPONENTS_PACKAGES
37387
+ });
37388
+ };
37389
+ const I18N_PACKAGES = [
37390
+ "i18next",
37391
+ "react-i18next",
37392
+ "next-i18next",
37393
+ "react-intl",
37394
+ "next-intl",
37395
+ "use-intl",
37396
+ "@formatjs/intl",
37397
+ "@lingui/core",
37398
+ "@lingui/react",
37399
+ "typesafe-i18n",
37400
+ "@tolgee/react",
37401
+ "react-intl-universal"
37402
+ ];
37403
+ const hasI18nDependency = (packageJson) => {
37404
+ const allDependencies = {
37405
+ ...packageJson.peerDependencies,
37406
+ ...packageJson.dependencies,
37407
+ ...packageJson.devDependencies,
37408
+ ...packageJson.optionalDependencies
37409
+ };
37410
+ return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
37411
+ };
37319
37412
  const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
37413
+ const MOBX_REACT_PACKAGE_NAME = "mobx-react";
37414
+ const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
37415
+ const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
37416
+ const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
37417
+ const REACT_THREE_FIBER_DEPENDENCY_NAMES = ["@react-three/fiber", "react-three-fiber"];
37418
+ const REACT_THREE_FIBER_SECTIONS = [
37419
+ "dependencies",
37420
+ "peerDependencies",
37421
+ "optionalDependencies",
37422
+ "devDependencies"
37423
+ ];
37424
+ const THREE_DEPENDENCY_SECTIONS = [
37425
+ "dependencies",
37426
+ "peerDependencies",
37427
+ "optionalDependencies",
37428
+ "devDependencies"
37429
+ ];
37430
+ const REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES = [...REACT_THREE_FIBER_DEPENDENCY_NAMES, "@react-three/drei"];
37431
+ const THREE_DEPENDENCY_NAMES = [...REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES, "three"];
37320
37432
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
37321
37433
  const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
37322
37434
  const dependencyDeclaration = getDependencyDeclaration({
@@ -37327,7 +37439,7 @@ const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootD
37327
37439
  if (!dependencyDeclaration.hasDeclaration) return null;
37328
37440
  return concreteVersion ?? resolveCatalogVersion(workspacePackageJson, packageName, workspaceDirectory, dependencyDeclaration.catalogReference) ?? resolveCatalogVersion(rootPackageJson, packageName, rootDirectory, dependencyDeclaration.catalogReference);
37329
37441
  };
37330
- const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
37442
+ const shouldReplaceWithLowerMajor = (currentVersion, nextVersion) => {
37331
37443
  if (!currentVersion) return true;
37332
37444
  const currentMajor = parseReactMajor(currentVersion);
37333
37445
  const nextMajor = parseReactMajor(nextVersion);
@@ -37335,7 +37447,62 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
37335
37447
  if (nextMajor === null) return false;
37336
37448
  return nextMajor < currentMajor;
37337
37449
  };
37338
- const evaluateManifestFacts = (facts, packageJson, directory) => {
37450
+ const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSupportedMajor) => {
37451
+ if (currentFact.version === null) return true;
37452
+ if (nextFact.version === null) return false;
37453
+ const currentMajor = getLowestDependencyMajor(currentFact.version);
37454
+ const nextMajor = getLowestDependencyMajor(nextFact.version);
37455
+ if (currentMajor === null) return false;
37456
+ if (nextMajor === null) return true;
37457
+ if (currentMajor > latestSupportedMajor) return false;
37458
+ if (nextMajor > latestSupportedMajor) return true;
37459
+ return nextMajor < currentMajor;
37460
+ };
37461
+ const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
37462
+ if (!currentVersion) return true;
37463
+ const currentMajor = getLowestDependencyMajor(currentVersion);
37464
+ const nextMajor = getLowestDependencyMajor(nextVersion);
37465
+ if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
37466
+ if (nextMajor === null) return currentMajor >= 6;
37467
+ return nextMajor < currentMajor;
37468
+ };
37469
+ const selectOldestDependencyVersion = (currentVersion, nextVersion) => {
37470
+ if (currentVersion === null || nextVersion === null) return null;
37471
+ const current = parseDependencyMajorMinor(currentVersion);
37472
+ const next = parseDependencyMajorMinor(nextVersion);
37473
+ if (current === null) return currentVersion;
37474
+ if (next === null) return nextVersion;
37475
+ if (next.major !== current.major) return next.major < current.major ? nextVersion : currentVersion;
37476
+ return next.minor < current.minor ? nextVersion : currentVersion;
37477
+ };
37478
+ const shouldReplaceMobxFact = (currentFact, nextFact) => {
37479
+ if (currentFact.sourceDirectory === null) return true;
37480
+ if (currentFact.version === null) return false;
37481
+ if (nextFact.version === null) return true;
37482
+ const currentMajor = getDependencyMajorWithinSupportedRange(currentFact.version, 6);
37483
+ const nextMajor = getDependencyMajorWithinSupportedRange(nextFact.version, 6);
37484
+ if (currentMajor === null) return false;
37485
+ if (nextMajor === null) return true;
37486
+ return selectOldestDependencyVersion(currentFact.version, nextFact.version) === nextFact.version;
37487
+ };
37488
+ const collectBindingVersion = (facts, packageJson, directory, packageName) => {
37489
+ const version = getDependencySpec(packageJson, packageName);
37490
+ if (version === null) return;
37491
+ const resolvedVersion = resolveCatalogBackedDependencyVersion({
37492
+ rootDirectory: directory,
37493
+ rootPackageJson: packageJson,
37494
+ packageName,
37495
+ version
37496
+ });
37497
+ if (packageName === MOBX_REACT_PACKAGE_NAME) {
37498
+ facts.mobxReactVersion = facts.hasMobxReact ? selectOldestDependencyVersion(facts.mobxReactVersion, resolvedVersion) : resolvedVersion;
37499
+ facts.hasMobxReact = true;
37500
+ return;
37501
+ }
37502
+ facts.mobxReactLiteVersion = facts.hasMobxReactLite ? selectOldestDependencyVersion(facts.mobxReactLiteVersion, resolvedVersion) : resolvedVersion;
37503
+ facts.hasMobxReactLite = true;
37504
+ };
37505
+ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
37339
37506
  if (facts.expo.version === null) {
37340
37507
  const spec = getDependencySpec(packageJson, "expo");
37341
37508
  if (spec !== null) facts.expo = {
@@ -37357,6 +37524,36 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
37357
37524
  sourceDirectory: directory
37358
37525
  };
37359
37526
  }
37527
+ const mobxSpec = getDependencySpec(packageJson, "mobx");
37528
+ if (mobxSpec !== null) {
37529
+ const nextMobxFact = {
37530
+ version: resolveCatalogBackedDependencyVersion({
37531
+ rootDirectory: directory,
37532
+ rootPackageJson: packageJson,
37533
+ packageName: "mobx",
37534
+ version: mobxSpec
37535
+ }),
37536
+ sourceDirectory: directory
37537
+ };
37538
+ if (shouldReplaceMobxFact(facts.mobx, nextMobxFact)) facts.mobx = nextMobxFact;
37539
+ }
37540
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_PACKAGE_NAME);
37541
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_LITE_PACKAGE_NAME);
37542
+ facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
37543
+ facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
37544
+ const zustandSpec = getDependencySpec(packageJson, "zustand");
37545
+ if (zustandSpec !== null) {
37546
+ const nextZustandFact = {
37547
+ version: resolveCatalogBackedDependencyVersion({
37548
+ rootDirectory: directory,
37549
+ rootPackageJson: packageJson,
37550
+ packageName: "zustand",
37551
+ version: zustandSpec
37552
+ }),
37553
+ sourceDirectory: directory
37554
+ };
37555
+ if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
37556
+ }
37360
37557
  if (facts.reanimatedVersion === null) {
37361
37558
  const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
37362
37559
  if (spec !== null) facts.reanimatedVersion = spec;
@@ -37365,9 +37562,75 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
37365
37562
  const spec = getDependencySpec(packageJson, "valtio");
37366
37563
  if (spec !== null) facts.valtioVersion = spec;
37367
37564
  }
37565
+ facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
37566
+ const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
37567
+ rootDirectory: directory,
37568
+ rootPackageJson: packageJson,
37569
+ packageName: "styled-components",
37570
+ version: getStyledComponentsVersion(packageJson)
37571
+ });
37572
+ if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
37573
+ facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
37574
+ for (const packageName of REACT_THREE_FIBER_DEPENDENCY_NAMES) {
37575
+ const version = resolveCatalogBackedDependencyVersion({
37576
+ rootDirectory,
37577
+ rootPackageJson,
37578
+ sourceDirectory: directory,
37579
+ sourcePackageJson: packageJson,
37580
+ packageName,
37581
+ version: getDependencyDeclaration({
37582
+ packageName,
37583
+ packageJson,
37584
+ sections: REACT_THREE_FIBER_SECTIONS
37585
+ }).version
37586
+ });
37587
+ if (version === null) continue;
37588
+ if (shouldReplaceWithLowerMajor(facts.reactThreeFiber.version, version)) facts.reactThreeFiber = {
37589
+ packageName,
37590
+ version,
37591
+ sourceDirectory: directory
37592
+ };
37593
+ }
37594
+ const threeVersion = resolveCatalogBackedDependencyVersion({
37595
+ rootDirectory,
37596
+ rootPackageJson,
37597
+ sourceDirectory: directory,
37598
+ sourcePackageJson: packageJson,
37599
+ packageName: "three",
37600
+ version: getDependencyDeclaration({
37601
+ packageName: "three",
37602
+ packageJson,
37603
+ sections: THREE_DEPENDENCY_SECTIONS
37604
+ }).version
37605
+ });
37606
+ if (threeVersion !== null) {
37607
+ const currentRelease = parseThreeRelease(facts.threeVersion);
37608
+ const nextRelease = parseThreeRelease(threeVersion);
37609
+ if (facts.threeVersion === null || nextRelease !== null && (currentRelease === null || nextRelease < currentRelease)) facts.threeVersion = threeVersion;
37610
+ }
37368
37611
  facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
37369
37612
  facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
37370
37613
  facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
37614
+ const remotionSpec = getDependencySpec(packageJson, "remotion");
37615
+ if (remotionSpec !== null) {
37616
+ facts.hasRemotionDependency = true;
37617
+ const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
37618
+ rootDirectory,
37619
+ rootPackageJson,
37620
+ packageName: "remotion",
37621
+ version: remotionSpec
37622
+ });
37623
+ const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
37624
+ if (remotionMajorVersion === null) {
37625
+ facts.hasUnknownRemotionVersion = true;
37626
+ facts.remotionVersion = null;
37627
+ } else if (!facts.hasUnknownRemotionVersion) {
37628
+ const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
37629
+ if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
37630
+ }
37631
+ }
37632
+ facts.hasThree = facts.hasThree || THREE_DEPENDENCY_NAMES.some((dependencyName) => getDependencySpec(packageJson, dependencyName) !== null);
37633
+ facts.hasReactThreeFiber = facts.hasReactThreeFiber || REACT_THREE_FIBER_ECOSYSTEM_DEPENDENCY_NAMES.some((dependencyName) => getDependencySpec(packageJson, dependencyName) !== null);
37371
37634
  };
37372
37635
  const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
37373
37636
  const facts = {
@@ -37388,12 +37651,40 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37388
37651
  sourceDirectory: null
37389
37652
  },
37390
37653
  valtioVersion: null,
37654
+ mobx: {
37655
+ version: null,
37656
+ sourceDirectory: null
37657
+ },
37658
+ hasMobxReact: false,
37659
+ mobxReactVersion: null,
37660
+ hasMobxReactLite: false,
37661
+ mobxReactLiteVersion: null,
37662
+ hasMobxStateTree: false,
37663
+ hasMobxReactObserver: false,
37664
+ zustand: {
37665
+ version: null,
37666
+ sourceDirectory: null
37667
+ },
37668
+ tanstackQueryVersion: null,
37669
+ styledComponentsVersion: null,
37670
+ hasI18nLibrary: false,
37391
37671
  hasReactNativeAwarePackage: false,
37392
37672
  hasReanimatedAwarePackage: false,
37393
37673
  hasSsrDependency: false,
37674
+ hasRemotionDependency: false,
37675
+ hasUnknownRemotionVersion: false,
37676
+ remotionVersion: null,
37677
+ hasThree: false,
37678
+ threeVersion: null,
37679
+ hasReactThreeFiber: false,
37680
+ reactThreeFiber: {
37681
+ packageName: null,
37682
+ version: null,
37683
+ sourceDirectory: null
37684
+ },
37394
37685
  reanimatedVersion: null
37395
37686
  };
37396
- evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
37687
+ evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
37397
37688
  let isReactGroupSettled = !collectReactGroup;
37398
37689
  const visitedDirectories = /* @__PURE__ */ new Set();
37399
37690
  for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
@@ -37402,7 +37693,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37402
37693
  if (visitedDirectories.has(workspaceDirectory)) continue;
37403
37694
  visitedDirectories.add(workspaceDirectory);
37404
37695
  const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
37405
- evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
37696
+ evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory, rootDirectory, rootPackageJson);
37406
37697
  const info = extractDependencyInfo(workspacePackageJson);
37407
37698
  if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
37408
37699
  if (isReactGroupSettled) continue;
@@ -37433,7 +37724,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37433
37724
  workspaceDirectory,
37434
37725
  workspacePackageJson
37435
37726
  });
37436
- if (reactVersion && shouldReplaceReactVersion(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
37727
+ if (reactVersion && shouldReplaceWithLowerMajor(facts.reactVersion, reactVersion)) facts.reactVersion = reactVersion;
37437
37728
  if (tailwindVersion && !facts.tailwindVersion) facts.tailwindVersion = tailwindVersion;
37438
37729
  if (zodVersion && !facts.zodVersion) facts.zodVersion = zodVersion;
37439
37730
  const settledReactMajor = parseReactMajor(facts.reactVersion);
@@ -37623,6 +37914,16 @@ const discoverProjectWithoutPackageJson = (directory) => {
37623
37914
  tailwindVersion: null,
37624
37915
  zodVersion: null,
37625
37916
  zodMajorVersion: null,
37917
+ mobxVersion: null,
37918
+ mobxMajorVersion: null,
37919
+ hasMobxReact: false,
37920
+ mobxReactVersion: null,
37921
+ hasMobxReactLite: false,
37922
+ mobxReactLiteVersion: null,
37923
+ hasMobxStateTree: false,
37924
+ hasMobxReactObserver: false,
37925
+ zustandVersion: null,
37926
+ zustandMajorVersion: null,
37626
37927
  framework: "unknown",
37627
37928
  hasTypeScript: hasOwnTsConfig,
37628
37929
  hasReactCompiler: false,
@@ -37630,6 +37931,18 @@ const discoverProjectWithoutPackageJson = (directory) => {
37630
37931
  hasTanStackQuery: false,
37631
37932
  valtioVersion: null,
37632
37933
  valtioMajorVersion: null,
37934
+ hasRemotion: false,
37935
+ remotionVersion: null,
37936
+ remotionMajorVersion: null,
37937
+ hasI18nLibrary: false,
37938
+ tanstackQueryVersion: null,
37939
+ styledComponentsVersion: null,
37940
+ hasThree: false,
37941
+ threeVersion: null,
37942
+ threeRelease: null,
37943
+ hasReactThreeFiber: false,
37944
+ reactThreeFiberVersion: null,
37945
+ reactThreeFiberMajorVersion: null,
37633
37946
  hasSsrDependency: false,
37634
37947
  preactVersion: null,
37635
37948
  preactMajorVersion: null,
@@ -37728,6 +38041,12 @@ const discoverProject = (directory) => {
37728
38041
  packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
37729
38042
  version: workspaceFacts.shopifyFlashList.version
37730
38043
  }) : null;
38044
+ const zustandVersion = resolveCatalogBackedDependencyVersion({
38045
+ rootDirectory: directory,
38046
+ rootPackageJson: packageJson,
38047
+ packageName: "zustand",
38048
+ version: workspaceFacts.zustand.version
38049
+ });
37731
38050
  const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
37732
38051
  const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
37733
38052
  const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
@@ -37742,7 +38061,27 @@ const discoverProject = (directory) => {
37742
38061
  packageName: "valtio",
37743
38062
  version: workspaceFacts.valtioVersion
37744
38063
  });
38064
+ const mobxVersion = resolveCatalogBackedDependencyVersion({
38065
+ rootDirectory: directory,
38066
+ rootPackageJson: packageJson,
38067
+ packageName: "mobx",
38068
+ version: workspaceFacts.mobx.version
38069
+ });
37745
38070
  const preactVersion = getPreactVersion(packageJson);
38071
+ const remotionVersion = workspaceFacts.remotionVersion;
38072
+ const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
38073
+ const reactThreeFiberVersion = workspaceFacts.reactThreeFiber.packageName ? resolveCatalogBackedDependencyVersion({
38074
+ rootDirectory: directory,
38075
+ rootPackageJson: packageJson,
38076
+ packageName: workspaceFacts.reactThreeFiber.packageName,
38077
+ version: workspaceFacts.reactThreeFiber.version
38078
+ }) : null;
38079
+ const threeVersion = resolveCatalogBackedDependencyVersion({
38080
+ rootDirectory: directory,
38081
+ rootPackageJson: packageJson,
38082
+ packageName: "three",
38083
+ version: workspaceFacts.threeVersion
38084
+ });
37746
38085
  const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
37747
38086
  const projectInfo = {
37748
38087
  rootDirectory: directory,
@@ -37752,13 +38091,35 @@ const discoverProject = (directory) => {
37752
38091
  tailwindVersion,
37753
38092
  zodVersion,
37754
38093
  zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
38094
+ mobxVersion,
38095
+ mobxMajorVersion: mobxVersion === null ? null : getDependencyMajorWithinSupportedRange(mobxVersion, 6),
38096
+ hasMobxReact: workspaceFacts.hasMobxReact,
38097
+ mobxReactVersion: workspaceFacts.mobxReactVersion,
38098
+ hasMobxReactLite: workspaceFacts.hasMobxReactLite,
38099
+ mobxReactLiteVersion: workspaceFacts.mobxReactLiteVersion,
38100
+ hasMobxStateTree: workspaceFacts.hasMobxStateTree,
38101
+ hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
38102
+ zustandVersion,
38103
+ zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
37755
38104
  framework,
37756
38105
  hasTypeScript,
37757
38106
  hasReactCompiler: detectReactCompiler(directory, packageJson),
37758
38107
  hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
37759
- hasTanStackQuery: hasTanStackQuery(packageJson),
38108
+ hasTanStackQuery: tanstackQueryVersion !== null,
38109
+ hasI18nLibrary: workspaceFacts.hasI18nLibrary,
38110
+ tanstackQueryVersion,
38111
+ styledComponentsVersion: workspaceFacts.styledComponentsVersion,
37760
38112
  valtioVersion,
37761
38113
  valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
38114
+ hasRemotion: workspaceFacts.hasRemotionDependency,
38115
+ remotionVersion,
38116
+ remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
38117
+ hasThree: workspaceFacts.hasThree,
38118
+ threeVersion,
38119
+ threeRelease: parseThreeRelease(threeVersion),
38120
+ hasReactThreeFiber: workspaceFacts.hasReactThreeFiber,
38121
+ reactThreeFiberVersion,
38122
+ reactThreeFiberMajorVersion: reactThreeFiberVersion === null ? null : getLowestDependencyMajor(reactThreeFiberVersion),
37762
38123
  hasSsrDependency: workspaceFacts.hasSsrDependency,
37763
38124
  preactVersion,
37764
38125
  preactMajorVersion: parseReactMajor(preactVersion),
@@ -41068,10 +41429,10 @@ const SSR_FRAMEWORKS = new Set([
41068
41429
  "gatsby",
41069
41430
  "tanstack-start"
41070
41431
  ]);
41071
- const addMajorLadder = (capabilities, name, major, earliest, latest) => {
41072
- if (major === null) return;
41073
- const cappedMajor = Math.min(major, latest);
41074
- for (let candidate = earliest; candidate <= cappedMajor; candidate += 1) capabilities.add(`${name}:${candidate}`);
41432
+ const addVersionCapabilityLadder = (capabilities, name, detectedVersion, earliest, latest) => {
41433
+ if (detectedVersion === null) return;
41434
+ const cappedVersion = Math.min(detectedVersion, latest);
41435
+ for (let candidate = earliest; candidate <= cappedVersion; candidate += 1) capabilities.add(`${name}:${candidate}`);
41075
41436
  };
41076
41437
  const buildCapabilities = (project) => {
41077
41438
  const capabilities = /* @__PURE__ */ new Set();
@@ -41084,26 +41445,77 @@ const buildCapabilities = (project) => {
41084
41445
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
41085
41446
  if (project.isStaticExport) capabilities.add("nextjs:static-export");
41086
41447
  if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
41087
- addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
41448
+ if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
41449
+ addVersionCapabilityLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
41088
41450
  if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
41089
41451
  major: 19,
41090
41452
  minor: 2
41091
41453
  })) capabilities.add("react:19.2");
41092
- if (project.tailwindVersion !== null) capabilities.add("tailwind");
41093
- if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
41094
- major: 3,
41095
- minor: 4
41096
- })) capabilities.add("tailwind:3.4");
41454
+ if (project.tailwindVersion !== null) {
41455
+ capabilities.add("tailwind");
41456
+ const tailwindVersion = parseTailwindMajorMinor(project.tailwindVersion);
41457
+ if (isMajorMinorAtLeast(tailwindVersion, {
41458
+ major: 3,
41459
+ minor: 4
41460
+ })) capabilities.add("tailwind:3.4");
41461
+ if (tailwindVersion !== null && isMajorMinorAtLeast(tailwindVersion, {
41462
+ major: 4,
41463
+ minor: 0
41464
+ })) capabilities.add("tailwind:4");
41465
+ }
41097
41466
  if (project.zodVersion !== null) capabilities.add("zod");
41098
41467
  if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
41468
+ if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
41469
+ if (project.hasMobxReact === true) capabilities.add("mobx-react");
41470
+ if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
41471
+ if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
41472
+ const mobxReactVersion = parseDependencyMajorMinor(project.mobxReactVersion);
41473
+ const mobxReactLiteVersion = parseDependencyMajorMinor(project.mobxReactLiteVersion);
41474
+ const hasMobxReactObserverMemoGuard = mobxReactVersion !== null && isMajorMinorAtLeast(mobxReactVersion, {
41475
+ major: 7,
41476
+ minor: 3
41477
+ });
41478
+ const hasMobxReactLiteObserverMemoGuard = mobxReactLiteVersion !== null && isMajorMinorAtLeast(mobxReactLiteVersion, {
41479
+ major: 3,
41480
+ minor: 3
41481
+ });
41482
+ if (hasMobxReactObserverMemoGuard) capabilities.add("mobx-react-observer-memo-guard");
41483
+ if (hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-lite-observer-memo-guard");
41484
+ if (hasMobxReactObserverMemoGuard || hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-binding-observer-memo-guard");
41485
+ if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
41486
+ if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
41487
+ if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addVersionCapabilityLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
41488
+ const mobxVersion = parseDependencyMajorMinor(project.mobxVersion);
41489
+ if (project.mobxMajorVersion === 6 && mobxVersion !== null && isMajorMinorAtLeast(mobxVersion, {
41490
+ major: 6,
41491
+ minor: 10
41492
+ })) capabilities.add("mobx:6.10");
41493
+ if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
41494
+ if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addVersionCapabilityLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
41099
41495
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
41100
41496
  if (project.hasReactCompiler) capabilities.add("react-compiler");
41101
- if (project.hasTanStackQuery) capabilities.add("tanstack-query");
41497
+ if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
41498
+ if (project.styledComponentsVersion) {
41499
+ capabilities.add("styled-components");
41500
+ const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
41501
+ if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
41502
+ }
41503
+ if (project.hasI18nLibrary) capabilities.add("i18n");
41102
41504
  if (project.valtioVersion !== null) capabilities.add("valtio");
41103
- addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
41505
+ addVersionCapabilityLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
41506
+ if (project.hasRemotion) {
41507
+ capabilities.add("remotion");
41508
+ addVersionCapabilityLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
41509
+ }
41510
+ if (project.hasThree || project.hasReactThreeFiber) capabilities.add("three");
41511
+ addVersionCapabilityLadder(capabilities, "three", project.threeRelease ?? null, 145, 250);
41512
+ if (project.hasReactThreeFiber) {
41513
+ capabilities.add("r3f");
41514
+ addVersionCapabilityLadder(capabilities, "r3f", project.reactThreeFiberMajorVersion ?? null, 3, 10);
41515
+ }
41104
41516
  if (project.hasTypeScript) capabilities.add("typescript");
41105
41517
  if (project.preactVersion !== null) capabilities.add("preact");
41106
- addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
41518
+ addVersionCapabilityLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
41107
41519
  if (project.preactVersion !== null && project.reactVersion === null) capabilities.add("pure-preact");
41108
41520
  return capabilities;
41109
41521
  };
@@ -41115,7 +41527,7 @@ const getCapabilities = (project) => {
41115
41527
  capabilitiesByProject.set(project, capabilities);
41116
41528
  return capabilities;
41117
41529
  };
41118
- const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
41530
+ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen, includedTags) => {
41119
41531
  if (requires) {
41120
41532
  for (const capability of requires) if (!capabilities.has(capability)) return false;
41121
41533
  }
@@ -41126,20 +41538,29 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
41126
41538
  if (tags) {
41127
41539
  for (const tag of tags) if (ignoredTags.has(tag)) return false;
41128
41540
  }
41541
+ if (includedTags && includedTags.size > 0) {
41542
+ if (!tags?.some((tag) => includedTags.has(tag))) return false;
41543
+ }
41129
41544
  return true;
41130
41545
  };
41546
+ const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
41131
41547
  const yieldToEventLoop = () => new Promise((resolve) => {
41132
41548
  setImmediate(resolve);
41133
41549
  });
41134
41550
  const createSecurityScanSession = (rootDirectory, options) => {
41135
41551
  const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
41136
41552
  const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
41553
+ const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
41137
41554
  const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
41138
41555
  const rule = entry.rule;
41139
41556
  const scan = rule.scan;
41140
41557
  if (typeof scan !== "function") return [];
41141
- if (rule.defaultEnabled === false) return [];
41142
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
41558
+ if (!shouldEnableRuleByDefaultStatus({
41559
+ defaultEnabled: rule.defaultEnabled,
41560
+ includeTagDefaults: options.includeTagDefaults === true,
41561
+ hasIncludedTags: includedTags.size > 0
41562
+ })) return [];
41563
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) return [];
41143
41564
  return [{
41144
41565
  entry,
41145
41566
  scan,
@@ -43141,8 +43562,9 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
43141
43562
  }
43142
43563
  return enabled;
43143
43564
  };
43144
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
43145
- const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
43565
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
43566
+ const hasIncludedTags = includedTags.size > 0;
43567
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
43146
43568
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
43147
43569
  const jsPlugins = [];
43148
43570
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -43157,9 +43579,14 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
43157
43579
  if (rule.scan !== void 0) continue;
43158
43580
  if (customRulesOnly && registryEntry.originallyExternal) continue;
43159
43581
  if (rule.framework !== "global" && !rule.requires) continue;
43160
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
43582
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
43161
43583
  const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
43162
- if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
43584
+ if (!shouldEnableRuleByDefaultStatus({
43585
+ defaultEnabled: rule.defaultEnabled,
43586
+ includeTagDefaults,
43587
+ hasIncludedTags,
43588
+ hasExplicitOverride: explicitRuleOverride !== void 0
43589
+ })) continue;
43163
43590
  const severity = resolveRuleSeverityOverride({
43164
43591
  ruleKey: registryEntry.key,
43165
43592
  category: rule.category
@@ -43168,7 +43595,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
43168
43595
  enabledReactDoctorRules[registryEntry.key] = severity;
43169
43596
  }
43170
43597
  const userPluginRules = {};
43171
- if (ruleSelection !== "sidecar") for (const userPlugin of userPlugins) {
43598
+ if (ruleSelection !== "sidecar" && !hasIncludedTags) for (const userPlugin of userPlugins) {
43172
43599
  Object.assign(userPluginRules, buildUserPluginRules(userPlugin, severityControls));
43173
43600
  jsPlugins.push(userPlugin.entry);
43174
43601
  }
@@ -43385,6 +43812,19 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
43385
43812
  }
43386
43813
  };
43387
43814
  };
43815
+ const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
43816
+ const fingerprintFileContents = (filePath, fingerprintLength) => {
43817
+ const fileStats = NFS.statSync(filePath, { bigint: true });
43818
+ const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
43819
+ if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
43820
+ const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
43821
+ fingerprintCacheByFilePath.set(filePath, {
43822
+ fingerprint,
43823
+ modifiedTimeNanoseconds: fileStats.mtimeNs,
43824
+ sizeBytes: fileStats.size
43825
+ });
43826
+ return fingerprint;
43827
+ };
43388
43828
  const bundledRequire$3 = createRequire(import.meta.url);
43389
43829
  const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
43390
43830
  const resolveChildNodeVersion = (nodeBinaryPath) => {
@@ -43408,6 +43848,13 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS$1 = [
43408
43848
  "oxlint-plugin-react-doctor/package.json",
43409
43849
  "eslint-plugin-react-hooks/package.json"
43410
43850
  ];
43851
+ const resolvePluginFingerprint = () => {
43852
+ try {
43853
+ return fingerprintFileContents(bundledRequire$3.resolve("oxlint-plugin-react-doctor"), 16);
43854
+ } catch {
43855
+ return "unresolved";
43856
+ }
43857
+ };
43411
43858
  const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43412
43859
  const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
43413
43860
  for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS$1) try {
@@ -43417,6 +43864,7 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43417
43864
  } catch {
43418
43865
  versions.push(`${specifier}=missing`);
43419
43866
  }
43867
+ versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
43420
43868
  return versions;
43421
43869
  };
43422
43870
  const esmRequire = createRequire(import.meta.url);
@@ -44892,7 +45340,7 @@ const reactHooksJsPluginDropNote = (error) => {
44892
45340
  * 6. always restore disable directives + clean up the temp dir
44893
45341
  */
44894
45342
  const runOxlint = async (options) => {
44895
- const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
45343
+ const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
44896
45344
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
44897
45345
  const severityControls = buildRuleSeverityControls(userConfig);
44898
45346
  validateRuleRegistration();
@@ -44906,13 +45354,15 @@ const runOxlint = async (options) => {
44906
45354
  }
44907
45355
  const pluginPath = resolvePluginPath();
44908
45356
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
44909
- const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
45357
+ const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
44910
45358
  const buildConfig = (overrides) => createOxlintConfig({
44911
45359
  pluginPath,
44912
45360
  project,
44913
45361
  customRulesOnly,
44914
45362
  extendsPaths: overrides.extendsPaths,
44915
45363
  ignoredTags,
45364
+ includedTags,
45365
+ includeTagDefaults,
44916
45366
  serverAuthFunctionNames,
44917
45367
  severityControls,
44918
45368
  userPlugins,
@@ -45301,6 +45751,8 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
45301
45751
  respectInlineDisables: input.respectInlineDisables,
45302
45752
  adoptExistingLintConfig: input.adoptExistingLintConfig,
45303
45753
  ignoredTags: input.ignoredTags,
45754
+ includedTags: input.includedTags,
45755
+ includeTagDefaults: input.includeTagDefaults,
45304
45756
  userConfig: input.userConfig ?? null,
45305
45757
  configSourceDirectory: input.configSourceDirectory,
45306
45758
  onPartialFailure: (reason) => {
@@ -46149,7 +46601,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
46149
46601
  const securityScanFailedRef = yield* make$13(false);
46150
46602
  const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
46151
46603
  project,
46152
- ignoredTags: input.ignoredTags
46604
+ ignoredTags: input.ignoredTags,
46605
+ includedTags: input.includedTags,
46606
+ includeTagDefaults: input.includeTagDefaults
46153
46607
  })).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
46154
46608
  const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
46155
46609
  const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
@@ -46240,6 +46694,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
46240
46694
  respectInlineDisables: input.respectInlineDisables,
46241
46695
  adoptExistingLintConfig: input.adoptExistingLintConfig,
46242
46696
  ignoredTags: input.ignoredTags,
46697
+ includedTags: input.includedTags,
46698
+ includeTagDefaults: input.includeTagDefaults,
46243
46699
  userConfig: resolvedConfig.config ?? void 0,
46244
46700
  configSourceDirectory: resolvedConfig.configSourceDirectory ?? void 0,
46245
46701
  onFileProgress: (scannedFileCount, totalFileCount) => {
@@ -47384,7 +47840,7 @@ const makeNoopConsole = () => ({
47384
47840
  });
47385
47841
  //#endregion
47386
47842
  //#region src/cli/utils/version.ts
47387
- const VERSION = "0.8.1-dev.5774353";
47843
+ const VERSION = "0.8.1-dev.5b468f8";
47388
47844
  //#endregion
47389
47845
  //#region src/cli/utils/json-mode.ts
47390
47846
  let context = null;
@@ -47471,7 +47927,11 @@ const getRunId = () => {
47471
47927
  };
47472
47928
  //#endregion
47473
47929
  //#region src/cli/utils/build-run-context.ts
47474
- const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
47930
+ const ROOT_SUBCOMMANDS = new Set([
47931
+ "design",
47932
+ "install",
47933
+ "setup"
47934
+ ]);
47475
47935
  const detectInvokedVia = () => {
47476
47936
  const userAgent = process.env.npm_config_user_agent;
47477
47937
  if (!userAgent) return "unknown";
@@ -47555,7 +48015,9 @@ const buildSentryProjectContext = (projectInfo) => ({
47555
48015
  reactMajorVersion: projectInfo.reactMajorVersion,
47556
48016
  hasTypeScript: projectInfo.hasTypeScript,
47557
48017
  hasReactCompiler: projectInfo.hasReactCompiler,
47558
- hasTanStackQuery: projectInfo.hasTanStackQuery,
48018
+ tanstackQueryVersion: projectInfo.tanstackQueryVersion,
48019
+ mobxVersion: projectInfo.mobxVersion,
48020
+ styledComponentsVersion: projectInfo.styledComponentsVersion,
47559
48021
  tailwindVersion: projectInfo.tailwindVersion,
47560
48022
  zodVersion: projectInfo.zodVersion,
47561
48023
  preactVersion: projectInfo.preactVersion,
@@ -47736,13 +48198,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47736
48198
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47737
48199
  * standard `SENTRY_RELEASE` override.
47738
48200
  */
47739
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.5774353`;
48201
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.5b468f8`;
47740
48202
  /**
47741
48203
  * Deployment environment shown in Sentry's environment filter. Defaults to
47742
48204
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47743
48205
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47744
48206
  */
47745
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.5774353") ? "development" : "production");
48207
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.5b468f8") ? "development" : "production");
47746
48208
  /**
47747
48209
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47748
48210
  * (set to `0` to disable tracing) and falls back to
@@ -60068,6 +60530,8 @@ const buildScanResultCacheKey = (input) => {
60068
60530
  warnings: input.options.warnings,
60069
60531
  adoptExistingLintConfig: input.options.adoptExistingLintConfig,
60070
60532
  ignoredTags: [...input.options.ignoredTags].sort(),
60533
+ includedTags: [...input.options.includedTags].sort(),
60534
+ includeTagDefaults: input.options.includeTagDefaults,
60071
60535
  concurrency: input.options.concurrency,
60072
60536
  lintBatchOrdering: resolveLintBatchOrdering(),
60073
60537
  baselineRef: input.options.baseline?.ref,
@@ -60894,8 +61358,8 @@ const createDiagnosticEvidenceReader = (rootDirectory, options = {}) => {
60894
61358
  //#endregion
60895
61359
  //#region src/cli/utils/build-no-score-message.ts
60896
61360
  const ENTERPRISE_CONTACT_HINT = `Want something custom to your company? Contact us at ${ENTERPRISE_CONTACT_URL}.`;
60897
- const buildNoScoreMessage = (isScoreDisabled) => {
60898
- return `${isScoreDisabled ? "Score disabled by --no-score." : "Score unavailable (could not reach the score API)."} ${ENTERPRISE_CONTACT_HINT}`;
61361
+ const buildNoScoreMessage = (isScoreDisabled, disabledMessage) => {
61362
+ return `${isScoreDisabled ? disabledMessage ?? "Score disabled by --no-score." : "Score unavailable (could not reach the score API)."} ${ENTERPRISE_CONTACT_HINT}`;
60899
61363
  };
60900
61364
  //#endregion
60901
61365
  //#region src/cli/utils/render-agent-guidance.ts
@@ -62020,40 +62484,47 @@ const buildChangedLineMatcher = (directory, changedLineRanges) => {
62020
62484
  return diagnosticIntersectsLineRanges(diagnostic, ranges);
62021
62485
  };
62022
62486
  };
62023
- const buildIgnoredTags = (userConfig) => {
62487
+ const buildIgnoredTags = (userConfig, includedTags) => {
62024
62488
  const tags = /* @__PURE__ */ new Set();
62025
62489
  if (userConfig?.ignore?.tags) for (const tag of userConfig.ignore.tags) tags.add(tag);
62490
+ for (const tag of includedTags) tags.delete(tag);
62026
62491
  return tags;
62027
62492
  };
62028
- const mergeInspectOptions = (inputOptions, userConfig) => ({
62029
- lint: inputOptions.lint ?? userConfig?.lint ?? true,
62030
- deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
62031
- supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
62032
- verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
62033
- outputDirectory: inputOptions.outputDirectory || null,
62034
- scoreOnly: inputOptions.scoreOnly ?? false,
62035
- noScore: inputOptions.noScore ?? userConfig?.noScore ?? false,
62036
- isCi: inputOptions.isCi ?? false,
62037
- isCiOrCodingAgentEnvironment: isCiOrCodingAgentEnvironment(),
62038
- isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
62039
- silent: inputOptions.silent ?? false,
62040
- includePaths: inputOptions.includePaths ?? [],
62041
- customRulesOnly: userConfig?.customRulesOnly ?? false,
62042
- share: userConfig?.share ?? true,
62043
- respectInlineDisables: inputOptions.respectInlineDisables ?? userConfig?.respectInlineDisables ?? true,
62044
- warnings: inputOptions.warnings ?? userConfig?.warnings ?? true,
62045
- categoryFilters: new Set(resolveCliCategories(inputOptions.categoryFilters) ?? []),
62046
- adoptExistingLintConfig: userConfig?.adoptExistingLintConfig ?? true,
62047
- ignoredTags: buildIgnoredTags(userConfig),
62048
- outputSurface: inputOptions.outputSurface ?? "cli",
62049
- suppressRendering: inputOptions.suppressRendering ?? false,
62050
- concurrentScan: inputOptions.concurrentScan ?? false,
62051
- concurrency: inputOptions.concurrency,
62052
- maxDurationMs: inputOptions.maxDurationMs ?? null,
62053
- baseline: inputOptions.baseline ?? null,
62054
- changedLineRanges: inputOptions.changedLineRanges ?? null,
62055
- supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
62056
- });
62493
+ const mergeInspectOptions = (inputOptions, userConfig) => {
62494
+ const includedTags = inputOptions.includedTags ?? /* @__PURE__ */ new Set();
62495
+ return {
62496
+ lint: inputOptions.lint ?? userConfig?.lint ?? true,
62497
+ deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
62498
+ supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
62499
+ verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
62500
+ outputDirectory: inputOptions.outputDirectory || null,
62501
+ scoreOnly: inputOptions.scoreOnly ?? false,
62502
+ noScore: inputOptions.noScore ?? userConfig?.noScore ?? false,
62503
+ isCi: inputOptions.isCi ?? false,
62504
+ isCiOrCodingAgentEnvironment: isCiOrCodingAgentEnvironment(),
62505
+ isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
62506
+ silent: inputOptions.silent ?? false,
62507
+ includePaths: inputOptions.includePaths ?? [],
62508
+ customRulesOnly: includedTags.size > 0 ? false : userConfig?.customRulesOnly ?? false,
62509
+ share: userConfig?.share ?? true,
62510
+ respectInlineDisables: inputOptions.respectInlineDisables ?? userConfig?.respectInlineDisables ?? true,
62511
+ warnings: inputOptions.warnings ?? userConfig?.warnings ?? true,
62512
+ categoryFilters: new Set(resolveCliCategories(inputOptions.categoryFilters) ?? []),
62513
+ adoptExistingLintConfig: includedTags.size > 0 ? false : userConfig?.adoptExistingLintConfig ?? true,
62514
+ ignoredTags: buildIgnoredTags(userConfig, includedTags),
62515
+ includedTags,
62516
+ includeTagDefaults: inputOptions.includeTagDefaults ?? false,
62517
+ scoreDisabledMessage: inputOptions.scoreDisabledMessage,
62518
+ outputSurface: inputOptions.outputSurface ?? "cli",
62519
+ suppressRendering: inputOptions.suppressRendering ?? false,
62520
+ concurrentScan: inputOptions.concurrentScan ?? false,
62521
+ concurrency: inputOptions.concurrency,
62522
+ maxDurationMs: inputOptions.maxDurationMs ?? null,
62523
+ baseline: inputOptions.baseline ?? null,
62524
+ changedLineRanges: inputOptions.changedLineRanges ?? null,
62525
+ supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
62526
+ };
62527
+ };
62057
62528
  const deriveScope = (options) => {
62058
62529
  if (options.baseline) return "changed";
62059
62530
  if (options.changedLineRanges !== null) return "lines";
@@ -62184,6 +62655,8 @@ const runBaselineComparison = async (params) => {
62184
62655
  warnings: params.options.warnings,
62185
62656
  adoptExistingLintConfig: params.options.adoptExistingLintConfig,
62186
62657
  ignoredTags: params.options.ignoredTags,
62658
+ includedTags: params.options.includedTags,
62659
+ includeTagDefaults: params.options.includeTagDefaults,
62187
62660
  nodeBinaryPath: params.resolvedNodeBinaryPath ?? void 0,
62188
62661
  runDeadCode: false,
62189
62662
  isCi: params.options.isCi,
@@ -62277,6 +62750,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
62277
62750
  warnings: options.warnings,
62278
62751
  adoptExistingLintConfig: options.adoptExistingLintConfig,
62279
62752
  ignoredTags: options.ignoredTags,
62753
+ includedTags: options.includedTags,
62754
+ includeTagDefaults: options.includeTagDefaults,
62280
62755
  nodeBinaryPath: resolvedNodeBinaryPath ?? void 0,
62281
62756
  runDeadCode: options.deadCode,
62282
62757
  isCi: options.isCi,
@@ -62465,7 +62940,7 @@ const finalizeAndRender = (input) => gen(function* () {
62465
62940
  securityScanFailed
62466
62941
  });
62467
62942
  const hasSkippedChecks = skippedChecks.length > 0;
62468
- const noScoreMessage = buildNoScoreMessage(options.noScore);
62943
+ const noScoreMessage = buildNoScoreMessage(options.noScore, options.scoreDisabledMessage);
62469
62944
  const buildResult = () => ({
62470
62945
  diagnostics: [...diagnostics],
62471
62946
  score,
@@ -64570,21 +65045,25 @@ const resolveParallelFlag = (parallel) => parallel === false ? 1 : void 0;
64570
65045
  */
64571
65046
  const resolveCliInspectOptions = (flags, userConfig) => {
64572
65047
  const wantsWarningGate = pickBlockingLevel(flags, userConfig) === "warning";
65048
+ const isDesignScan = flags.design === true;
64573
65049
  return {
64574
65050
  lint: flags.lint,
64575
- deadCode: flags.deadCode,
64576
- supplyChain: flags.supplyChain,
65051
+ deadCode: isDesignScan ? false : flags.deadCode,
65052
+ supplyChain: isDesignScan ? false : flags.supplyChain,
64577
65053
  verbose: flags.verbose,
64578
65054
  outputDirectory: flags.outputDir,
64579
65055
  respectInlineDisables: flags.respectInlineDisables === false ? false : void 0,
64580
65056
  warnings: wantsWarningGate ? true : flags.warnings,
64581
65057
  scoreOnly: flags.score === true,
64582
- noScore: flags.score === false || flags.telemetry === false ? true : void 0,
65058
+ noScore: isDesignScan || flags.score === false || flags.telemetry === false ? true : void 0,
64583
65059
  isCi: isCiEnvironment(),
64584
65060
  silent: Boolean(flags.json),
64585
65061
  concurrency: resolveParallelFlag(flags.parallel),
64586
65062
  maxDurationMs: resolveMaxDurationFlag(flags.maxDuration),
64587
- categoryFilters: resolveCliCategories(flags.category)
65063
+ categoryFilters: resolveCliCategories(flags.category),
65064
+ includedTags: isDesignScan ? new Set(["design"]) : void 0,
65065
+ includeTagDefaults: isDesignScan ? true : void 0,
65066
+ scoreDisabledMessage: isDesignScan ? "Design scans do not affect the React health score." : void 0
64588
65067
  };
64589
65068
  };
64590
65069
  //#endregion
@@ -65002,7 +65481,7 @@ const maybeMigrateLegacyConfig = async (requestedDirectory, { isQuiet, isStaged
65002
65481
  if (!(!isQuiet && !isStaged && process.stdout.isTTY === true && !isCiOrCodingAgentEnvironment())) return;
65003
65482
  await runProjectMigrations(requestedDirectory);
65004
65483
  };
65005
- const inspectAction = async (directory, flags) => {
65484
+ const inspectAction = async (directory, flags, invocationCommand = "inspect") => {
65006
65485
  const isScoreOnly = Boolean(flags.score);
65007
65486
  const isJsonMode = Boolean(flags.json);
65008
65487
  const isQuiet = isScoreOnly || isJsonMode;
@@ -65016,7 +65495,7 @@ const inspectAction = async (directory, flags) => {
65016
65495
  });
65017
65496
  if (flags.jsonOut) recordCount(METRIC.jsonOutUsed, 1);
65018
65497
  }
65019
- recordCount(METRIC.cliInvoked, 1, { command: "inspect" });
65498
+ recordCount(METRIC.cliInvoked, 1, { command: invocationCommand });
65020
65499
  try {
65021
65500
  validateModeFlags(flags);
65022
65501
  if (flags.staged) setJsonReportMode("staged");
@@ -65328,6 +65807,13 @@ const inspectAction = async (directory, flags) => {
65328
65807
  }
65329
65808
  };
65330
65809
  //#endregion
65810
+ //#region src/cli/commands/design.ts
65811
+ const designAction = async (directory, flags) => inspectAction(directory, {
65812
+ ...flags,
65813
+ design: true,
65814
+ lint: flags.lint ?? true
65815
+ }, "design");
65816
+ //#endregion
65331
65817
  //#region src/cli/commands/install.ts
65332
65818
  const installAction = async (options, command) => {
65333
65819
  recordCount(METRIC.cliInvoked, 1, { command: "install" });
@@ -66164,6 +66650,7 @@ const INSTALL_FLAG_SPEC = {
66164
66650
  shortOptionsWithRequiredValues: new Set(["-c"])
66165
66651
  };
66166
66652
  const COMMAND_FLAG_SPECS = new Map([
66653
+ ["design", ROOT_FLAG_SPEC],
66167
66654
  ["install", INSTALL_FLAG_SPEC],
66168
66655
  ["setup", INSTALL_FLAG_SPEC],
66169
66656
  ["version", {
@@ -66320,6 +66807,7 @@ ${formatExampleLines([
66320
66807
  ["react-doctor --scope changed --base main", "scan only new issues vs. main"],
66321
66808
  ["react-doctor --project modules/a,modules/b", "score each module separately (names or paths)"],
66322
66809
  ["react-doctor --staged", "scan staged files (pre-commit hook)"],
66810
+ ["react-doctor design", "run the focused UI design audit"],
66323
66811
  ["react-doctor --category Security", "show only one diagnostic category"],
66324
66812
  ["react-doctor --blocking warning", "fail CI on warnings too (default: error)"],
66325
66813
  ["react-doctor --json > report.json", "write a machine-readable report"],
@@ -66353,6 +66841,20 @@ ${highlighter.dim("Managing CI:")}
66353
66841
  ${highlighter.dim("Learn more:")}
66354
66842
  ${highlighter.info(CANONICAL_GITHUB_URL)}
66355
66843
  `;
66844
+ const renderDesignHelpEpilog = () => `
66845
+ ${highlighter.dim("Examples:")}
66846
+ ${formatExampleLines([
66847
+ ["react-doctor design", "audit UI design in the current project"],
66848
+ ["react-doctor design ./apps/web", "audit one application"],
66849
+ ["react-doctor design --verbose", "show every design finding"],
66850
+ ["react-doctor design --json", "write a design-only JSON report"]
66851
+ ])}
66852
+
66853
+ ${highlighter.dim("Scope:")}
66854
+ Runs only rules tagged ${highlighter.info("design")}, including focused rules that stay opt-in during a general health scan.
66855
+ Dead-code, supply-chain, external lint-config, custom-plugin, and health-score passes are skipped.
66856
+ Standard scan flags such as ${highlighter.info("--scope")}, ${highlighter.info("--project")}, ${highlighter.info("--verbose")}, and ${highlighter.info("--json")} still work.
66857
+ `;
66356
66858
  const renderCiHelpEpilog = () => `
66357
66859
  ${highlighter.dim("Examples:")}
66358
66860
  ${formatExampleLines([
@@ -66374,6 +66876,7 @@ ${highlighter.dim("Learn more:")}
66374
66876
  const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
66375
66877
  const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").option("--include-untracked", "with --scope files/changed/lines, also scan ordinary untracked files (respects .gitignore)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
66376
66878
  program.action(inspectAction);
66879
+ program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
66377
66880
  program.command("why <location>").description("Explain why a rule fired (or why a suppression didn't apply) at a file:line").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple)").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").action((location, options) => whyAction(location, options));
66378
66881
  program.command("install").alias("setup").description("Install the react-doctor skill into your coding agents and optional git hook").option("-y, --yes", "skip prompts, install for all detected agents").option("--dry-run", "show what would be installed without writing files").option("--agent-hooks", "install native non-blocking agent hooks for Claude Code and Cursor").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderInstallHelpEpilog).action(installAction);
66379
66882
  const providerOption = ["--provider <name>", "ci provider: github-actions or gitlab-ci (auto-detected by default)"];
@@ -66422,4 +66925,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
66422
66925
  export {};
66423
66926
 
66424
66927
  //# sourceMappingURL=cli.js.map
66425
- //# debugId=83a484ab-e975-5390-830a-f2f723c71935
66928
+ //# debugId=4d155139-533f-5635-af83-9ee012355893