react-doctor 0.8.1-dev.a667b45 → 0.8.1-dev.af33723

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="24153a3f-aef9-53fd-8dff-9b016a9613fb")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d92b0964-cd34-5965-a1bf-ce1d06faf742")}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
  };
@@ -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,9 @@ 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 parseDependencyMajorMinor = (dependencyVersion) => {
36876
+ if (typeof dependencyVersion !== "string") return null;
36877
+ const trimmed = dependencyVersion.trim();
36844
36878
  if (trimmed.length === 0) return null;
36845
36879
  const lowerBound = parseLowerBoundVersion(trimmed);
36846
36880
  if (lowerBound === null || lowerBound.major <= 0) return null;
@@ -36849,6 +36883,7 @@ const parseTailwindMajorMinor = (tailwindVersion) => {
36849
36883
  minor: lowerBound.minor
36850
36884
  };
36851
36885
  };
36886
+ const parseTailwindMajorMinor = (tailwindVersion) => parseDependencyMajorMinor(tailwindVersion);
36852
36887
  const hasUpperBoundOnlyPeerRange = (range) => {
36853
36888
  if (typeof range !== "string") return false;
36854
36889
  const normalizedRange = normalizeDependencyVersion(range);
@@ -37101,19 +37136,6 @@ const getPreactVersion = (packageJson) => {
37101
37136
  ...packageJson.devDependencies
37102
37137
  }.preact ?? null;
37103
37138
  };
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
37139
  const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
37118
37140
  if (version === null || !isCatalogReference(version)) return version;
37119
37141
  const catalogName = extractCatalogName(version);
@@ -37316,7 +37338,60 @@ const listWorkspacePackages = (rootDirectory) => {
37316
37338
  }
37317
37339
  return packages;
37318
37340
  };
37341
+ const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
37342
+ const allDependencies = {
37343
+ ...packageJson.devDependencies,
37344
+ ...packageJson.peerDependencies,
37345
+ ...packageJson.dependencies
37346
+ };
37347
+ for (const packageName of packageNames) {
37348
+ const version = allDependencies[packageName];
37349
+ if (version !== void 0) return version;
37350
+ }
37351
+ return null;
37352
+ };
37353
+ const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
37354
+ const getTanStackQueryVersion = (packageJson) => {
37355
+ return getPreferredDependencyVersion({
37356
+ packageJson,
37357
+ packageNames: TANSTACK_REACT_QUERY_PACKAGES
37358
+ });
37359
+ };
37360
+ const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
37361
+ const getStyledComponentsVersion = (packageJson) => {
37362
+ return getPreferredDependencyVersion({
37363
+ packageJson,
37364
+ packageNames: STYLED_COMPONENTS_PACKAGES
37365
+ });
37366
+ };
37367
+ const I18N_PACKAGES = [
37368
+ "i18next",
37369
+ "react-i18next",
37370
+ "next-i18next",
37371
+ "react-intl",
37372
+ "next-intl",
37373
+ "use-intl",
37374
+ "@formatjs/intl",
37375
+ "@lingui/core",
37376
+ "@lingui/react",
37377
+ "typesafe-i18n",
37378
+ "@tolgee/react",
37379
+ "react-intl-universal"
37380
+ ];
37381
+ const hasI18nDependency = (packageJson) => {
37382
+ const allDependencies = {
37383
+ ...packageJson.peerDependencies,
37384
+ ...packageJson.dependencies,
37385
+ ...packageJson.devDependencies,
37386
+ ...packageJson.optionalDependencies
37387
+ };
37388
+ return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
37389
+ };
37319
37390
  const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
37391
+ const MOBX_REACT_PACKAGE_NAME = "mobx-react";
37392
+ const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
37393
+ const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
37394
+ const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
37320
37395
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
37321
37396
  const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
37322
37397
  const dependencyDeclaration = getDependencyDeclaration({
@@ -37335,7 +37410,62 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
37335
37410
  if (nextMajor === null) return false;
37336
37411
  return nextMajor < currentMajor;
37337
37412
  };
37338
- const evaluateManifestFacts = (facts, packageJson, directory) => {
37413
+ const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSupportedMajor) => {
37414
+ if (currentFact.version === null) return true;
37415
+ if (nextFact.version === null) return false;
37416
+ const currentMajor = getLowestDependencyMajor(currentFact.version);
37417
+ const nextMajor = getLowestDependencyMajor(nextFact.version);
37418
+ if (currentMajor === null) return false;
37419
+ if (nextMajor === null) return true;
37420
+ if (currentMajor > latestSupportedMajor) return false;
37421
+ if (nextMajor > latestSupportedMajor) return true;
37422
+ return nextMajor < currentMajor;
37423
+ };
37424
+ const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
37425
+ if (!currentVersion) return true;
37426
+ const currentMajor = getLowestDependencyMajor(currentVersion);
37427
+ const nextMajor = getLowestDependencyMajor(nextVersion);
37428
+ if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
37429
+ if (nextMajor === null) return currentMajor >= 6;
37430
+ return nextMajor < currentMajor;
37431
+ };
37432
+ const selectOldestDependencyVersion = (currentVersion, nextVersion) => {
37433
+ if (currentVersion === null || nextVersion === null) return null;
37434
+ const current = parseDependencyMajorMinor(currentVersion);
37435
+ const next = parseDependencyMajorMinor(nextVersion);
37436
+ if (current === null) return currentVersion;
37437
+ if (next === null) return nextVersion;
37438
+ if (next.major !== current.major) return next.major < current.major ? nextVersion : currentVersion;
37439
+ return next.minor < current.minor ? nextVersion : currentVersion;
37440
+ };
37441
+ const shouldReplaceMobxFact = (currentFact, nextFact) => {
37442
+ if (currentFact.sourceDirectory === null) return true;
37443
+ if (currentFact.version === null) return false;
37444
+ if (nextFact.version === null) return true;
37445
+ const currentMajor = getDependencyMajorWithinSupportedRange(currentFact.version, 6);
37446
+ const nextMajor = getDependencyMajorWithinSupportedRange(nextFact.version, 6);
37447
+ if (currentMajor === null) return false;
37448
+ if (nextMajor === null) return true;
37449
+ return selectOldestDependencyVersion(currentFact.version, nextFact.version) === nextFact.version;
37450
+ };
37451
+ const collectBindingVersion = (facts, packageJson, directory, packageName) => {
37452
+ const version = getDependencySpec(packageJson, packageName);
37453
+ if (version === null) return;
37454
+ const resolvedVersion = resolveCatalogBackedDependencyVersion({
37455
+ rootDirectory: directory,
37456
+ rootPackageJson: packageJson,
37457
+ packageName,
37458
+ version
37459
+ });
37460
+ if (packageName === MOBX_REACT_PACKAGE_NAME) {
37461
+ facts.mobxReactVersion = facts.hasMobxReact ? selectOldestDependencyVersion(facts.mobxReactVersion, resolvedVersion) : resolvedVersion;
37462
+ facts.hasMobxReact = true;
37463
+ return;
37464
+ }
37465
+ facts.mobxReactLiteVersion = facts.hasMobxReactLite ? selectOldestDependencyVersion(facts.mobxReactLiteVersion, resolvedVersion) : resolvedVersion;
37466
+ facts.hasMobxReactLite = true;
37467
+ };
37468
+ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
37339
37469
  if (facts.expo.version === null) {
37340
37470
  const spec = getDependencySpec(packageJson, "expo");
37341
37471
  if (spec !== null) facts.expo = {
@@ -37357,13 +37487,74 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
37357
37487
  sourceDirectory: directory
37358
37488
  };
37359
37489
  }
37490
+ const mobxSpec = getDependencySpec(packageJson, "mobx");
37491
+ if (mobxSpec !== null) {
37492
+ const nextMobxFact = {
37493
+ version: resolveCatalogBackedDependencyVersion({
37494
+ rootDirectory: directory,
37495
+ rootPackageJson: packageJson,
37496
+ packageName: "mobx",
37497
+ version: mobxSpec
37498
+ }),
37499
+ sourceDirectory: directory
37500
+ };
37501
+ if (shouldReplaceMobxFact(facts.mobx, nextMobxFact)) facts.mobx = nextMobxFact;
37502
+ }
37503
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_PACKAGE_NAME);
37504
+ collectBindingVersion(facts, packageJson, directory, MOBX_REACT_LITE_PACKAGE_NAME);
37505
+ facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
37506
+ facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
37507
+ const zustandSpec = getDependencySpec(packageJson, "zustand");
37508
+ if (zustandSpec !== null) {
37509
+ const nextZustandFact = {
37510
+ version: resolveCatalogBackedDependencyVersion({
37511
+ rootDirectory: directory,
37512
+ rootPackageJson: packageJson,
37513
+ packageName: "zustand",
37514
+ version: zustandSpec
37515
+ }),
37516
+ sourceDirectory: directory
37517
+ };
37518
+ if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
37519
+ }
37360
37520
  if (facts.reanimatedVersion === null) {
37361
37521
  const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
37362
37522
  if (spec !== null) facts.reanimatedVersion = spec;
37363
37523
  }
37524
+ if (facts.valtioVersion === null) {
37525
+ const spec = getDependencySpec(packageJson, "valtio");
37526
+ if (spec !== null) facts.valtioVersion = spec;
37527
+ }
37528
+ facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
37529
+ const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
37530
+ rootDirectory: directory,
37531
+ rootPackageJson: packageJson,
37532
+ packageName: "styled-components",
37533
+ version: getStyledComponentsVersion(packageJson)
37534
+ });
37535
+ if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
37536
+ facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
37364
37537
  facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
37365
37538
  facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
37366
37539
  facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
37540
+ const remotionSpec = getDependencySpec(packageJson, "remotion");
37541
+ if (remotionSpec !== null) {
37542
+ facts.hasRemotionDependency = true;
37543
+ const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
37544
+ rootDirectory,
37545
+ rootPackageJson,
37546
+ packageName: "remotion",
37547
+ version: remotionSpec
37548
+ });
37549
+ const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
37550
+ if (remotionMajorVersion === null) {
37551
+ facts.hasUnknownRemotionVersion = true;
37552
+ facts.remotionVersion = null;
37553
+ } else if (!facts.hasUnknownRemotionVersion) {
37554
+ const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
37555
+ if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
37556
+ }
37557
+ }
37367
37558
  };
37368
37559
  const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
37369
37560
  const facts = {
@@ -37383,12 +37574,33 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37383
37574
  version: null,
37384
37575
  sourceDirectory: null
37385
37576
  },
37577
+ valtioVersion: null,
37578
+ mobx: {
37579
+ version: null,
37580
+ sourceDirectory: null
37581
+ },
37582
+ hasMobxReact: false,
37583
+ mobxReactVersion: null,
37584
+ hasMobxReactLite: false,
37585
+ mobxReactLiteVersion: null,
37586
+ hasMobxStateTree: false,
37587
+ hasMobxReactObserver: false,
37588
+ zustand: {
37589
+ version: null,
37590
+ sourceDirectory: null
37591
+ },
37592
+ tanstackQueryVersion: null,
37593
+ styledComponentsVersion: null,
37594
+ hasI18nLibrary: false,
37386
37595
  hasReactNativeAwarePackage: false,
37387
37596
  hasReanimatedAwarePackage: false,
37388
37597
  hasSsrDependency: false,
37598
+ hasRemotionDependency: false,
37599
+ hasUnknownRemotionVersion: false,
37600
+ remotionVersion: null,
37389
37601
  reanimatedVersion: null
37390
37602
  };
37391
- evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
37603
+ evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
37392
37604
  let isReactGroupSettled = !collectReactGroup;
37393
37605
  const visitedDirectories = /* @__PURE__ */ new Set();
37394
37606
  for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
@@ -37397,7 +37609,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
37397
37609
  if (visitedDirectories.has(workspaceDirectory)) continue;
37398
37610
  visitedDirectories.add(workspaceDirectory);
37399
37611
  const workspacePackageJson = readPackageJson$1(Path.join(workspaceDirectory, "package.json"));
37400
- evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
37612
+ evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory, rootDirectory, rootPackageJson);
37401
37613
  const info = extractDependencyInfo(workspacePackageJson);
37402
37614
  if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
37403
37615
  if (isReactGroupSettled) continue;
@@ -37618,11 +37830,29 @@ const discoverProjectWithoutPackageJson = (directory) => {
37618
37830
  tailwindVersion: null,
37619
37831
  zodVersion: null,
37620
37832
  zodMajorVersion: null,
37833
+ mobxVersion: null,
37834
+ mobxMajorVersion: null,
37835
+ hasMobxReact: false,
37836
+ mobxReactVersion: null,
37837
+ hasMobxReactLite: false,
37838
+ mobxReactLiteVersion: null,
37839
+ hasMobxStateTree: false,
37840
+ hasMobxReactObserver: false,
37841
+ zustandVersion: null,
37842
+ zustandMajorVersion: null,
37621
37843
  framework: "unknown",
37622
37844
  hasTypeScript: hasOwnTsConfig,
37623
37845
  hasReactCompiler: false,
37624
37846
  hasReactCompilerLintPlugin: false,
37625
37847
  hasTanStackQuery: false,
37848
+ valtioVersion: null,
37849
+ valtioMajorVersion: null,
37850
+ hasRemotion: false,
37851
+ remotionVersion: null,
37852
+ remotionMajorVersion: null,
37853
+ hasI18nLibrary: false,
37854
+ tanstackQueryVersion: null,
37855
+ styledComponentsVersion: null,
37626
37856
  hasSsrDependency: false,
37627
37857
  preactVersion: null,
37628
37858
  preactMajorVersion: null,
@@ -37721,6 +37951,12 @@ const discoverProject = (directory) => {
37721
37951
  packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
37722
37952
  version: workspaceFacts.shopifyFlashList.version
37723
37953
  }) : null;
37954
+ const zustandVersion = resolveCatalogBackedDependencyVersion({
37955
+ rootDirectory: directory,
37956
+ rootPackageJson: packageJson,
37957
+ packageName: "zustand",
37958
+ version: workspaceFacts.zustand.version
37959
+ });
37724
37960
  const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
37725
37961
  const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
37726
37962
  const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
@@ -37729,7 +37965,21 @@ const discoverProject = (directory) => {
37729
37965
  packageName: "next",
37730
37966
  version: workspaceFacts.next.version
37731
37967
  }) : null;
37968
+ const valtioVersion = resolveCatalogBackedDependencyVersion({
37969
+ rootDirectory: directory,
37970
+ rootPackageJson: packageJson,
37971
+ packageName: "valtio",
37972
+ version: workspaceFacts.valtioVersion
37973
+ });
37974
+ const mobxVersion = resolveCatalogBackedDependencyVersion({
37975
+ rootDirectory: directory,
37976
+ rootPackageJson: packageJson,
37977
+ packageName: "mobx",
37978
+ version: workspaceFacts.mobx.version
37979
+ });
37732
37980
  const preactVersion = getPreactVersion(packageJson);
37981
+ const remotionVersion = workspaceFacts.remotionVersion;
37982
+ const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
37733
37983
  const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
37734
37984
  const projectInfo = {
37735
37985
  rootDirectory: directory,
@@ -37739,11 +37989,29 @@ const discoverProject = (directory) => {
37739
37989
  tailwindVersion,
37740
37990
  zodVersion,
37741
37991
  zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
37992
+ mobxVersion,
37993
+ mobxMajorVersion: mobxVersion === null ? null : getDependencyMajorWithinSupportedRange(mobxVersion, 6),
37994
+ hasMobxReact: workspaceFacts.hasMobxReact,
37995
+ mobxReactVersion: workspaceFacts.mobxReactVersion,
37996
+ hasMobxReactLite: workspaceFacts.hasMobxReactLite,
37997
+ mobxReactLiteVersion: workspaceFacts.mobxReactLiteVersion,
37998
+ hasMobxStateTree: workspaceFacts.hasMobxStateTree,
37999
+ hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
38000
+ zustandVersion,
38001
+ zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
37742
38002
  framework,
37743
38003
  hasTypeScript,
37744
38004
  hasReactCompiler: detectReactCompiler(directory, packageJson),
37745
38005
  hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
37746
- hasTanStackQuery: hasTanStackQuery(packageJson),
38006
+ hasTanStackQuery: tanstackQueryVersion !== null,
38007
+ hasI18nLibrary: workspaceFacts.hasI18nLibrary,
38008
+ tanstackQueryVersion,
38009
+ styledComponentsVersion: workspaceFacts.styledComponentsVersion,
38010
+ valtioVersion,
38011
+ valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
38012
+ hasRemotion: workspaceFacts.hasRemotionDependency,
38013
+ remotionVersion,
38014
+ remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
37747
38015
  hasSsrDependency: workspaceFacts.hasSsrDependency,
37748
38016
  preactVersion,
37749
38017
  preactMajorVersion: parseReactMajor(preactVersion),
@@ -37977,7 +38245,6 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
37977
38245
  "react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
37978
38246
  "react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
37979
38247
  "react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
37980
- "react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
37981
38248
  "react/jsx-no-undef": "react-doctor/jsx-no-undef",
37982
38249
  "react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
37983
38250
  "react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
@@ -40299,9 +40566,25 @@ const BABEL_CONFIG_FILE_NAMES = [
40299
40566
  ".babelrc.json"
40300
40567
  ];
40301
40568
  const LEGACY_PRESET_SPEC = "module:metro-react-native-babel-preset";
40569
+ const LEGACY_PRESET_PACKAGE = "metro-react-native-babel-preset";
40570
+ const REACT_NATIVE_PACKAGE = "react-native";
40571
+ const PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION = "0.73.0";
40572
+ const LEGACY_PRESET_REFERENCE = new RegExp(`['"]${LEGACY_PRESET_SPEC}['"]`);
40302
40573
  const MODERN_PRESET_REFERENCE = new RegExp(`['"]module:@react-native/babel-preset['"]`);
40303
40574
  const ENABLE_BABEL_RUNTIME_VERSION = /enableBabelRuntime["']?\s*:\s*['"]/;
40575
+ const isReactNativeVersionAtLeastPresetRename = (rootDirectory, packageJson) => {
40576
+ const installedReactNativeManifestPath = Path.join(rootDirectory, "node_modules", REACT_NATIVE_PACKAGE, "package.json");
40577
+ const reactNativeVersionSpec = (isFile(installedReactNativeManifestPath) ? readPackageJson$1(installedReactNativeManifestPath).version : void 0) ?? getDependencySpec(packageJson, REACT_NATIVE_PACKAGE);
40578
+ if (reactNativeVersionSpec === null || reactNativeVersionSpec === void 0) return false;
40579
+ const normalizedVersionRange = import_semver.validRange(reactNativeVersionSpec);
40580
+ if (normalizedVersionRange === null) return false;
40581
+ const minimumVersion = import_semver.minVersion(normalizedVersionRange);
40582
+ return minimumVersion !== null && import_semver.gte(minimumVersion, PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION);
40583
+ };
40584
+ const canResolveLegacyPreset = (rootDirectory, packageJson) => getDependencySpec(packageJson, LEGACY_PRESET_PACKAGE) !== null || isFile(Path.join(rootDirectory, "node_modules", LEGACY_PRESET_PACKAGE, "package.json"));
40304
40585
  const checkReactNativeMetroBabelPreset = (rootDirectory) => {
40586
+ const packageJson = readPackageJson$1(Path.join(rootDirectory, "package.json"));
40587
+ const shouldReportLegacyPreset = isReactNativeVersionAtLeastPresetRename(rootDirectory, packageJson) && !canResolveLegacyPreset(rootDirectory, packageJson);
40305
40588
  for (const fileName of BABEL_CONFIG_FILE_NAMES) {
40306
40589
  const filePath = Path.join(rootDirectory, fileName);
40307
40590
  if (!isFile(filePath)) continue;
@@ -40311,7 +40594,7 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
40311
40594
  } catch {
40312
40595
  continue;
40313
40596
  }
40314
- if (contents.includes(LEGACY_PRESET_SPEC)) return [buildReactNativeDiagnostic({
40597
+ if (shouldReportLegacyPreset && LEGACY_PRESET_REFERENCE.test(contents)) return [buildReactNativeDiagnostic({
40315
40598
  filePath: fileName,
40316
40599
  rule: "rn-no-metro-babel-preset",
40317
40600
  severity: "error",
@@ -40334,12 +40617,6 @@ const checkReactNativeProject = (rootDirectory, project) => {
40334
40617
  return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
40335
40618
  };
40336
40619
  const RULE_KEY = "no-vulnerable-react-server-components";
40337
- const DEPENDENCY_SECTIONS = [
40338
- "dependencies",
40339
- "devDependencies",
40340
- "peerDependencies",
40341
- "optionalDependencies"
40342
- ];
40343
40620
  const REACT_RSC_ADVISORIES_BY_MINOR = {
40344
40621
  "19.0": {
40345
40622
  rceFixedVersion: "19.0.1",
@@ -40386,20 +40663,13 @@ const enumerateWorkspaceDirectories = (workspaceRoot) => {
40386
40663
  for (const pattern of patterns) for (const directory of resolveWorkspaceDirectories(workspaceRoot, pattern)) directories.add(directory);
40387
40664
  return [...directories];
40388
40665
  };
40389
- const readDeclaredSpec = (packageJson, packageName) => {
40390
- for (const section of DEPENDENCY_SECTIONS) {
40391
- const spec = packageJson[section]?.[packageName];
40392
- if (typeof spec === "string") return spec;
40393
- }
40394
- return null;
40395
- };
40396
40666
  const resolveVersionInDirectory = (directory, packageName, declaredSpecOverride) => {
40397
40667
  const manifestPath = Path.join(directory, "node_modules", packageName, "package.json");
40398
40668
  if (isFile(manifestPath)) {
40399
40669
  const installedVersion = import_semver.valid(readPackageJson$1(manifestPath).version ?? null);
40400
40670
  if (installedVersion !== null) return installedVersion;
40401
40671
  }
40402
- const candidateSpecs = [readDeclaredSpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
40672
+ const candidateSpecs = [getDependencySpec(readPackageJson$1(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
40403
40673
  for (const spec of candidateSpecs) {
40404
40674
  const pinnedVersion = spec === null ? null : import_semver.valid(spec);
40405
40675
  if (pinnedVersion !== null) return pinnedVersion;
@@ -41067,21 +41337,68 @@ const buildCapabilities = (project) => {
41067
41337
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
41068
41338
  if (project.isStaticExport) capabilities.add("nextjs:static-export");
41069
41339
  if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
41340
+ if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
41070
41341
  addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
41071
41342
  if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
41072
41343
  major: 19,
41073
41344
  minor: 2
41074
41345
  })) capabilities.add("react:19.2");
41075
- if (project.tailwindVersion !== null) capabilities.add("tailwind");
41076
- if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
41077
- major: 3,
41078
- minor: 4
41079
- })) capabilities.add("tailwind:3.4");
41346
+ if (project.tailwindVersion !== null) {
41347
+ capabilities.add("tailwind");
41348
+ const tailwindVersion = parseTailwindMajorMinor(project.tailwindVersion);
41349
+ if (isMajorMinorAtLeast(tailwindVersion, {
41350
+ major: 3,
41351
+ minor: 4
41352
+ })) capabilities.add("tailwind:3.4");
41353
+ if (tailwindVersion !== null && isMajorMinorAtLeast(tailwindVersion, {
41354
+ major: 4,
41355
+ minor: 0
41356
+ })) capabilities.add("tailwind:4");
41357
+ }
41080
41358
  if (project.zodVersion !== null) capabilities.add("zod");
41081
41359
  if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
41360
+ if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
41361
+ if (project.hasMobxReact === true) capabilities.add("mobx-react");
41362
+ if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
41363
+ if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
41364
+ const mobxReactVersion = parseDependencyMajorMinor(project.mobxReactVersion);
41365
+ const mobxReactLiteVersion = parseDependencyMajorMinor(project.mobxReactLiteVersion);
41366
+ const hasMobxReactObserverMemoGuard = mobxReactVersion !== null && isMajorMinorAtLeast(mobxReactVersion, {
41367
+ major: 7,
41368
+ minor: 3
41369
+ });
41370
+ const hasMobxReactLiteObserverMemoGuard = mobxReactLiteVersion !== null && isMajorMinorAtLeast(mobxReactLiteVersion, {
41371
+ major: 3,
41372
+ minor: 3
41373
+ });
41374
+ if (hasMobxReactObserverMemoGuard) capabilities.add("mobx-react-observer-memo-guard");
41375
+ if (hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-lite-observer-memo-guard");
41376
+ if (hasMobxReactObserverMemoGuard || hasMobxReactLiteObserverMemoGuard) capabilities.add("mobx-react-binding-observer-memo-guard");
41377
+ if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
41378
+ if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
41379
+ if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addMajorLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
41380
+ const mobxVersion = parseDependencyMajorMinor(project.mobxVersion);
41381
+ if (project.mobxMajorVersion === 6 && mobxVersion !== null && isMajorMinorAtLeast(mobxVersion, {
41382
+ major: 6,
41383
+ minor: 10
41384
+ })) capabilities.add("mobx:6.10");
41385
+ if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
41386
+ if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addMajorLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
41082
41387
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
41083
41388
  if (project.hasReactCompiler) capabilities.add("react-compiler");
41084
- if (project.hasTanStackQuery) capabilities.add("tanstack-query");
41389
+ if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
41390
+ if (project.styledComponentsVersion) {
41391
+ capabilities.add("styled-components");
41392
+ const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
41393
+ if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
41394
+ }
41395
+ if (project.hasI18nLibrary) capabilities.add("i18n");
41396
+ if (project.valtioVersion !== null) capabilities.add("valtio");
41397
+ addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
41398
+ if (project.hasRemotion) {
41399
+ capabilities.add("remotion");
41400
+ addMajorLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
41401
+ }
41085
41402
  if (project.hasTypeScript) capabilities.add("typescript");
41086
41403
  if (project.preactVersion !== null) capabilities.add("preact");
41087
41404
  addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
@@ -41096,7 +41413,7 @@ const getCapabilities = (project) => {
41096
41413
  capabilitiesByProject.set(project, capabilities);
41097
41414
  return capabilities;
41098
41415
  };
41099
- const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
41416
+ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen, includedTags) => {
41100
41417
  if (requires) {
41101
41418
  for (const capability of requires) if (!capabilities.has(capability)) return false;
41102
41419
  }
@@ -41107,20 +41424,29 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
41107
41424
  if (tags) {
41108
41425
  for (const tag of tags) if (ignoredTags.has(tag)) return false;
41109
41426
  }
41427
+ if (includedTags && includedTags.size > 0) {
41428
+ if (!tags?.some((tag) => includedTags.has(tag))) return false;
41429
+ }
41110
41430
  return true;
41111
41431
  };
41432
+ const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
41112
41433
  const yieldToEventLoop = () => new Promise((resolve) => {
41113
41434
  setImmediate(resolve);
41114
41435
  });
41115
41436
  const createSecurityScanSession = (rootDirectory, options) => {
41116
41437
  const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
41117
41438
  const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
41439
+ const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
41118
41440
  const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
41119
41441
  const rule = entry.rule;
41120
41442
  const scan = rule.scan;
41121
41443
  if (typeof scan !== "function") return [];
41122
- if (rule.defaultEnabled === false) return [];
41123
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
41444
+ if (!shouldEnableRuleByDefaultStatus({
41445
+ defaultEnabled: rule.defaultEnabled,
41446
+ includeTagDefaults: options.includeTagDefaults === true,
41447
+ hasIncludedTags: includedTags.size > 0
41448
+ })) return [];
41449
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) return [];
41124
41450
  return [{
41125
41451
  entry,
41126
41452
  scan,
@@ -43122,8 +43448,9 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
43122
43448
  }
43123
43449
  return enabled;
43124
43450
  };
43125
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
43126
- const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
43451
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
43452
+ const hasIncludedTags = includedTags.size > 0;
43453
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
43127
43454
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
43128
43455
  const jsPlugins = [];
43129
43456
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -43138,9 +43465,14 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
43138
43465
  if (rule.scan !== void 0) continue;
43139
43466
  if (customRulesOnly && registryEntry.originallyExternal) continue;
43140
43467
  if (rule.framework !== "global" && !rule.requires) continue;
43141
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
43468
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
43142
43469
  const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
43143
- if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
43470
+ if (!shouldEnableRuleByDefaultStatus({
43471
+ defaultEnabled: rule.defaultEnabled,
43472
+ includeTagDefaults,
43473
+ hasIncludedTags,
43474
+ hasExplicitOverride: explicitRuleOverride !== void 0
43475
+ })) continue;
43144
43476
  const severity = resolveRuleSeverityOverride({
43145
43477
  ruleKey: registryEntry.key,
43146
43478
  category: rule.category
@@ -43149,7 +43481,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
43149
43481
  enabledReactDoctorRules[registryEntry.key] = severity;
43150
43482
  }
43151
43483
  const userPluginRules = {};
43152
- if (ruleSelection !== "sidecar") for (const userPlugin of userPlugins) {
43484
+ if (ruleSelection !== "sidecar" && !hasIncludedTags) for (const userPlugin of userPlugins) {
43153
43485
  Object.assign(userPluginRules, buildUserPluginRules(userPlugin, severityControls));
43154
43486
  jsPlugins.push(userPlugin.entry);
43155
43487
  }
@@ -43366,6 +43698,19 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
43366
43698
  }
43367
43699
  };
43368
43700
  };
43701
+ const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
43702
+ const fingerprintFileContents = (filePath, fingerprintLength) => {
43703
+ const fileStats = NFS.statSync(filePath, { bigint: true });
43704
+ const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
43705
+ if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
43706
+ const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
43707
+ fingerprintCacheByFilePath.set(filePath, {
43708
+ fingerprint,
43709
+ modifiedTimeNanoseconds: fileStats.mtimeNs,
43710
+ sizeBytes: fileStats.size
43711
+ });
43712
+ return fingerprint;
43713
+ };
43369
43714
  const bundledRequire$3 = createRequire(import.meta.url);
43370
43715
  const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
43371
43716
  const resolveChildNodeVersion = (nodeBinaryPath) => {
@@ -43389,6 +43734,13 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS$1 = [
43389
43734
  "oxlint-plugin-react-doctor/package.json",
43390
43735
  "eslint-plugin-react-hooks/package.json"
43391
43736
  ];
43737
+ const resolvePluginFingerprint = () => {
43738
+ try {
43739
+ return fingerprintFileContents(bundledRequire$3.resolve("oxlint-plugin-react-doctor"), 16);
43740
+ } catch {
43741
+ return "unresolved";
43742
+ }
43743
+ };
43392
43744
  const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43393
43745
  const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
43394
43746
  for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS$1) try {
@@ -43398,6 +43750,7 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
43398
43750
  } catch {
43399
43751
  versions.push(`${specifier}=missing`);
43400
43752
  }
43753
+ versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
43401
43754
  return versions;
43402
43755
  };
43403
43756
  const esmRequire = createRequire(import.meta.url);
@@ -44873,7 +45226,7 @@ const reactHooksJsPluginDropNote = (error) => {
44873
45226
  * 6. always restore disable directives + clean up the temp dir
44874
45227
  */
44875
45228
  const runOxlint = async (options) => {
44876
- const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
45229
+ const { rootDirectory, project, includePaths, nodeBinaryPath = process.execPath, customRulesOnly = false, respectInlineDisables = true, adoptExistingLintConfig = true, ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, userConfig, configSourceDirectory = rootDirectory, onPartialFailure, onFileCoverage, perFileLintCacheEnabled = false, sidecarLintCacheEnabled = false, onCacheStats, onSidecarStats, spawnTimeoutMs, outputMaxBytes, lintBatchOrdering = "cost" } = options;
44877
45230
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
44878
45231
  const severityControls = buildRuleSeverityControls(userConfig);
44879
45232
  validateRuleRegistration();
@@ -44887,13 +45240,15 @@ const runOxlint = async (options) => {
44887
45240
  }
44888
45241
  const pluginPath = resolvePluginPath();
44889
45242
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
44890
- const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
45243
+ const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
44891
45244
  const buildConfig = (overrides) => createOxlintConfig({
44892
45245
  pluginPath,
44893
45246
  project,
44894
45247
  customRulesOnly,
44895
45248
  extendsPaths: overrides.extendsPaths,
44896
45249
  ignoredTags,
45250
+ includedTags,
45251
+ includeTagDefaults,
44897
45252
  serverAuthFunctionNames,
44898
45253
  severityControls,
44899
45254
  userPlugins,
@@ -45282,6 +45637,8 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
45282
45637
  respectInlineDisables: input.respectInlineDisables,
45283
45638
  adoptExistingLintConfig: input.adoptExistingLintConfig,
45284
45639
  ignoredTags: input.ignoredTags,
45640
+ includedTags: input.includedTags,
45641
+ includeTagDefaults: input.includeTagDefaults,
45285
45642
  userConfig: input.userConfig ?? null,
45286
45643
  configSourceDirectory: input.configSourceDirectory,
45287
45644
  onPartialFailure: (reason) => {
@@ -46130,7 +46487,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
46130
46487
  const securityScanFailedRef = yield* make$13(false);
46131
46488
  const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
46132
46489
  project,
46133
- ignoredTags: input.ignoredTags
46490
+ ignoredTags: input.ignoredTags,
46491
+ includedTags: input.includedTags,
46492
+ includeTagDefaults: input.includeTagDefaults
46134
46493
  })).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
46135
46494
  const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
46136
46495
  const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
@@ -46221,6 +46580,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
46221
46580
  respectInlineDisables: input.respectInlineDisables,
46222
46581
  adoptExistingLintConfig: input.adoptExistingLintConfig,
46223
46582
  ignoredTags: input.ignoredTags,
46583
+ includedTags: input.includedTags,
46584
+ includeTagDefaults: input.includeTagDefaults,
46224
46585
  userConfig: resolvedConfig.config ?? void 0,
46225
46586
  configSourceDirectory: resolvedConfig.configSourceDirectory ?? void 0,
46226
46587
  onFileProgress: (scannedFileCount, totalFileCount) => {
@@ -47365,7 +47726,7 @@ const makeNoopConsole = () => ({
47365
47726
  });
47366
47727
  //#endregion
47367
47728
  //#region src/cli/utils/version.ts
47368
- const VERSION = "0.8.1-dev.a667b45";
47729
+ const VERSION = "0.8.1-dev.af33723";
47369
47730
  //#endregion
47370
47731
  //#region src/cli/utils/json-mode.ts
47371
47732
  let context = null;
@@ -47452,7 +47813,11 @@ const getRunId = () => {
47452
47813
  };
47453
47814
  //#endregion
47454
47815
  //#region src/cli/utils/build-run-context.ts
47455
- const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
47816
+ const ROOT_SUBCOMMANDS = new Set([
47817
+ "design",
47818
+ "install",
47819
+ "setup"
47820
+ ]);
47456
47821
  const detectInvokedVia = () => {
47457
47822
  const userAgent = process.env.npm_config_user_agent;
47458
47823
  if (!userAgent) return "unknown";
@@ -47536,7 +47901,9 @@ const buildSentryProjectContext = (projectInfo) => ({
47536
47901
  reactMajorVersion: projectInfo.reactMajorVersion,
47537
47902
  hasTypeScript: projectInfo.hasTypeScript,
47538
47903
  hasReactCompiler: projectInfo.hasReactCompiler,
47539
- hasTanStackQuery: projectInfo.hasTanStackQuery,
47904
+ tanstackQueryVersion: projectInfo.tanstackQueryVersion,
47905
+ mobxVersion: projectInfo.mobxVersion,
47906
+ styledComponentsVersion: projectInfo.styledComponentsVersion,
47540
47907
  tailwindVersion: projectInfo.tailwindVersion,
47541
47908
  zodVersion: projectInfo.zodVersion,
47542
47909
  preactVersion: projectInfo.preactVersion,
@@ -47717,13 +48084,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47717
48084
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47718
48085
  * standard `SENTRY_RELEASE` override.
47719
48086
  */
47720
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.a667b45`;
48087
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.8.1-dev.af33723`;
47721
48088
  /**
47722
48089
  * Deployment environment shown in Sentry's environment filter. Defaults to
47723
48090
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47724
48091
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47725
48092
  */
47726
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.a667b45") ? "development" : "production");
48093
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.8.1-dev.af33723") ? "development" : "production");
47727
48094
  /**
47728
48095
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47729
48096
  * (set to `0` to disable tracing) and falls back to
@@ -60049,6 +60416,8 @@ const buildScanResultCacheKey = (input) => {
60049
60416
  warnings: input.options.warnings,
60050
60417
  adoptExistingLintConfig: input.options.adoptExistingLintConfig,
60051
60418
  ignoredTags: [...input.options.ignoredTags].sort(),
60419
+ includedTags: [...input.options.includedTags].sort(),
60420
+ includeTagDefaults: input.options.includeTagDefaults,
60052
60421
  concurrency: input.options.concurrency,
60053
60422
  lintBatchOrdering: resolveLintBatchOrdering(),
60054
60423
  baselineRef: input.options.baseline?.ref,
@@ -60875,8 +61244,8 @@ const createDiagnosticEvidenceReader = (rootDirectory, options = {}) => {
60875
61244
  //#endregion
60876
61245
  //#region src/cli/utils/build-no-score-message.ts
60877
61246
  const ENTERPRISE_CONTACT_HINT = `Want something custom to your company? Contact us at ${ENTERPRISE_CONTACT_URL}.`;
60878
- const buildNoScoreMessage = (isScoreDisabled) => {
60879
- return `${isScoreDisabled ? "Score disabled by --no-score." : "Score unavailable (could not reach the score API)."} ${ENTERPRISE_CONTACT_HINT}`;
61247
+ const buildNoScoreMessage = (isScoreDisabled, disabledMessage) => {
61248
+ return `${isScoreDisabled ? disabledMessage ?? "Score disabled by --no-score." : "Score unavailable (could not reach the score API)."} ${ENTERPRISE_CONTACT_HINT}`;
60880
61249
  };
60881
61250
  //#endregion
60882
61251
  //#region src/cli/utils/render-agent-guidance.ts
@@ -62001,40 +62370,47 @@ const buildChangedLineMatcher = (directory, changedLineRanges) => {
62001
62370
  return diagnosticIntersectsLineRanges(diagnostic, ranges);
62002
62371
  };
62003
62372
  };
62004
- const buildIgnoredTags = (userConfig) => {
62373
+ const buildIgnoredTags = (userConfig, includedTags) => {
62005
62374
  const tags = /* @__PURE__ */ new Set();
62006
62375
  if (userConfig?.ignore?.tags) for (const tag of userConfig.ignore.tags) tags.add(tag);
62376
+ for (const tag of includedTags) tags.delete(tag);
62007
62377
  return tags;
62008
62378
  };
62009
- const mergeInspectOptions = (inputOptions, userConfig) => ({
62010
- lint: inputOptions.lint ?? userConfig?.lint ?? true,
62011
- deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
62012
- supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
62013
- verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
62014
- outputDirectory: inputOptions.outputDirectory || null,
62015
- scoreOnly: inputOptions.scoreOnly ?? false,
62016
- noScore: inputOptions.noScore ?? userConfig?.noScore ?? false,
62017
- isCi: inputOptions.isCi ?? false,
62018
- isCiOrCodingAgentEnvironment: isCiOrCodingAgentEnvironment(),
62019
- isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
62020
- silent: inputOptions.silent ?? false,
62021
- includePaths: inputOptions.includePaths ?? [],
62022
- customRulesOnly: userConfig?.customRulesOnly ?? false,
62023
- share: userConfig?.share ?? true,
62024
- respectInlineDisables: inputOptions.respectInlineDisables ?? userConfig?.respectInlineDisables ?? true,
62025
- warnings: inputOptions.warnings ?? userConfig?.warnings ?? true,
62026
- categoryFilters: new Set(resolveCliCategories(inputOptions.categoryFilters) ?? []),
62027
- adoptExistingLintConfig: userConfig?.adoptExistingLintConfig ?? true,
62028
- ignoredTags: buildIgnoredTags(userConfig),
62029
- outputSurface: inputOptions.outputSurface ?? "cli",
62030
- suppressRendering: inputOptions.suppressRendering ?? false,
62031
- concurrentScan: inputOptions.concurrentScan ?? false,
62032
- concurrency: inputOptions.concurrency,
62033
- maxDurationMs: inputOptions.maxDurationMs ?? null,
62034
- baseline: inputOptions.baseline ?? null,
62035
- changedLineRanges: inputOptions.changedLineRanges ?? null,
62036
- supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
62037
- });
62379
+ const mergeInspectOptions = (inputOptions, userConfig) => {
62380
+ const includedTags = inputOptions.includedTags ?? /* @__PURE__ */ new Set();
62381
+ return {
62382
+ lint: inputOptions.lint ?? userConfig?.lint ?? true,
62383
+ deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,
62384
+ supplyChain: inputOptions.supplyChain ?? userConfig?.supplyChain?.enabled ?? true,
62385
+ verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,
62386
+ outputDirectory: inputOptions.outputDirectory || null,
62387
+ scoreOnly: inputOptions.scoreOnly ?? false,
62388
+ noScore: inputOptions.noScore ?? userConfig?.noScore ?? false,
62389
+ isCi: inputOptions.isCi ?? false,
62390
+ isCiOrCodingAgentEnvironment: isCiOrCodingAgentEnvironment(),
62391
+ isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
62392
+ silent: inputOptions.silent ?? false,
62393
+ includePaths: inputOptions.includePaths ?? [],
62394
+ customRulesOnly: includedTags.size > 0 ? false : userConfig?.customRulesOnly ?? false,
62395
+ share: userConfig?.share ?? true,
62396
+ respectInlineDisables: inputOptions.respectInlineDisables ?? userConfig?.respectInlineDisables ?? true,
62397
+ warnings: inputOptions.warnings ?? userConfig?.warnings ?? true,
62398
+ categoryFilters: new Set(resolveCliCategories(inputOptions.categoryFilters) ?? []),
62399
+ adoptExistingLintConfig: includedTags.size > 0 ? false : userConfig?.adoptExistingLintConfig ?? true,
62400
+ ignoredTags: buildIgnoredTags(userConfig, includedTags),
62401
+ includedTags,
62402
+ includeTagDefaults: inputOptions.includeTagDefaults ?? false,
62403
+ scoreDisabledMessage: inputOptions.scoreDisabledMessage,
62404
+ outputSurface: inputOptions.outputSurface ?? "cli",
62405
+ suppressRendering: inputOptions.suppressRendering ?? false,
62406
+ concurrentScan: inputOptions.concurrentScan ?? false,
62407
+ concurrency: inputOptions.concurrency,
62408
+ maxDurationMs: inputOptions.maxDurationMs ?? null,
62409
+ baseline: inputOptions.baseline ?? null,
62410
+ changedLineRanges: inputOptions.changedLineRanges ?? null,
62411
+ supplyChainManifestChanged: inputOptions.supplyChainManifestChanged ?? false
62412
+ };
62413
+ };
62038
62414
  const deriveScope = (options) => {
62039
62415
  if (options.baseline) return "changed";
62040
62416
  if (options.changedLineRanges !== null) return "lines";
@@ -62165,6 +62541,8 @@ const runBaselineComparison = async (params) => {
62165
62541
  warnings: params.options.warnings,
62166
62542
  adoptExistingLintConfig: params.options.adoptExistingLintConfig,
62167
62543
  ignoredTags: params.options.ignoredTags,
62544
+ includedTags: params.options.includedTags,
62545
+ includeTagDefaults: params.options.includeTagDefaults,
62168
62546
  nodeBinaryPath: params.resolvedNodeBinaryPath ?? void 0,
62169
62547
  runDeadCode: false,
62170
62548
  isCi: params.options.isCi,
@@ -62258,6 +62636,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
62258
62636
  warnings: options.warnings,
62259
62637
  adoptExistingLintConfig: options.adoptExistingLintConfig,
62260
62638
  ignoredTags: options.ignoredTags,
62639
+ includedTags: options.includedTags,
62640
+ includeTagDefaults: options.includeTagDefaults,
62261
62641
  nodeBinaryPath: resolvedNodeBinaryPath ?? void 0,
62262
62642
  runDeadCode: options.deadCode,
62263
62643
  isCi: options.isCi,
@@ -62446,7 +62826,7 @@ const finalizeAndRender = (input) => gen(function* () {
62446
62826
  securityScanFailed
62447
62827
  });
62448
62828
  const hasSkippedChecks = skippedChecks.length > 0;
62449
- const noScoreMessage = buildNoScoreMessage(options.noScore);
62829
+ const noScoreMessage = buildNoScoreMessage(options.noScore, options.scoreDisabledMessage);
62450
62830
  const buildResult = () => ({
62451
62831
  diagnostics: [...diagnostics],
62452
62832
  score,
@@ -64551,21 +64931,25 @@ const resolveParallelFlag = (parallel) => parallel === false ? 1 : void 0;
64551
64931
  */
64552
64932
  const resolveCliInspectOptions = (flags, userConfig) => {
64553
64933
  const wantsWarningGate = pickBlockingLevel(flags, userConfig) === "warning";
64934
+ const isDesignScan = flags.design === true;
64554
64935
  return {
64555
64936
  lint: flags.lint,
64556
- deadCode: flags.deadCode,
64557
- supplyChain: flags.supplyChain,
64937
+ deadCode: isDesignScan ? false : flags.deadCode,
64938
+ supplyChain: isDesignScan ? false : flags.supplyChain,
64558
64939
  verbose: flags.verbose,
64559
64940
  outputDirectory: flags.outputDir,
64560
64941
  respectInlineDisables: flags.respectInlineDisables === false ? false : void 0,
64561
64942
  warnings: wantsWarningGate ? true : flags.warnings,
64562
64943
  scoreOnly: flags.score === true,
64563
- noScore: flags.score === false || flags.telemetry === false ? true : void 0,
64944
+ noScore: isDesignScan || flags.score === false || flags.telemetry === false ? true : void 0,
64564
64945
  isCi: isCiEnvironment(),
64565
64946
  silent: Boolean(flags.json),
64566
64947
  concurrency: resolveParallelFlag(flags.parallel),
64567
64948
  maxDurationMs: resolveMaxDurationFlag(flags.maxDuration),
64568
- categoryFilters: resolveCliCategories(flags.category)
64949
+ categoryFilters: resolveCliCategories(flags.category),
64950
+ includedTags: isDesignScan ? new Set(["design"]) : void 0,
64951
+ includeTagDefaults: isDesignScan ? true : void 0,
64952
+ scoreDisabledMessage: isDesignScan ? "Design scans do not affect the React health score." : void 0
64569
64953
  };
64570
64954
  };
64571
64955
  //#endregion
@@ -64983,7 +65367,7 @@ const maybeMigrateLegacyConfig = async (requestedDirectory, { isQuiet, isStaged
64983
65367
  if (!(!isQuiet && !isStaged && process.stdout.isTTY === true && !isCiOrCodingAgentEnvironment())) return;
64984
65368
  await runProjectMigrations(requestedDirectory);
64985
65369
  };
64986
- const inspectAction = async (directory, flags) => {
65370
+ const inspectAction = async (directory, flags, invocationCommand = "inspect") => {
64987
65371
  const isScoreOnly = Boolean(flags.score);
64988
65372
  const isJsonMode = Boolean(flags.json);
64989
65373
  const isQuiet = isScoreOnly || isJsonMode;
@@ -64997,7 +65381,7 @@ const inspectAction = async (directory, flags) => {
64997
65381
  });
64998
65382
  if (flags.jsonOut) recordCount(METRIC.jsonOutUsed, 1);
64999
65383
  }
65000
- recordCount(METRIC.cliInvoked, 1, { command: "inspect" });
65384
+ recordCount(METRIC.cliInvoked, 1, { command: invocationCommand });
65001
65385
  try {
65002
65386
  validateModeFlags(flags);
65003
65387
  if (flags.staged) setJsonReportMode("staged");
@@ -65309,6 +65693,13 @@ const inspectAction = async (directory, flags) => {
65309
65693
  }
65310
65694
  };
65311
65695
  //#endregion
65696
+ //#region src/cli/commands/design.ts
65697
+ const designAction = async (directory, flags) => inspectAction(directory, {
65698
+ ...flags,
65699
+ design: true,
65700
+ lint: flags.lint ?? true
65701
+ }, "design");
65702
+ //#endregion
65312
65703
  //#region src/cli/commands/install.ts
65313
65704
  const installAction = async (options, command) => {
65314
65705
  recordCount(METRIC.cliInvoked, 1, { command: "install" });
@@ -66145,6 +66536,7 @@ const INSTALL_FLAG_SPEC = {
66145
66536
  shortOptionsWithRequiredValues: new Set(["-c"])
66146
66537
  };
66147
66538
  const COMMAND_FLAG_SPECS = new Map([
66539
+ ["design", ROOT_FLAG_SPEC],
66148
66540
  ["install", INSTALL_FLAG_SPEC],
66149
66541
  ["setup", INSTALL_FLAG_SPEC],
66150
66542
  ["version", {
@@ -66301,6 +66693,7 @@ ${formatExampleLines([
66301
66693
  ["react-doctor --scope changed --base main", "scan only new issues vs. main"],
66302
66694
  ["react-doctor --project modules/a,modules/b", "score each module separately (names or paths)"],
66303
66695
  ["react-doctor --staged", "scan staged files (pre-commit hook)"],
66696
+ ["react-doctor design", "run the focused UI design audit"],
66304
66697
  ["react-doctor --category Security", "show only one diagnostic category"],
66305
66698
  ["react-doctor --blocking warning", "fail CI on warnings too (default: error)"],
66306
66699
  ["react-doctor --json > report.json", "write a machine-readable report"],
@@ -66334,6 +66727,20 @@ ${highlighter.dim("Managing CI:")}
66334
66727
  ${highlighter.dim("Learn more:")}
66335
66728
  ${highlighter.info(CANONICAL_GITHUB_URL)}
66336
66729
  `;
66730
+ const renderDesignHelpEpilog = () => `
66731
+ ${highlighter.dim("Examples:")}
66732
+ ${formatExampleLines([
66733
+ ["react-doctor design", "audit UI design in the current project"],
66734
+ ["react-doctor design ./apps/web", "audit one application"],
66735
+ ["react-doctor design --verbose", "show every design finding"],
66736
+ ["react-doctor design --json", "write a design-only JSON report"]
66737
+ ])}
66738
+
66739
+ ${highlighter.dim("Scope:")}
66740
+ Runs only rules tagged ${highlighter.info("design")}, including focused rules that stay opt-in during a general health scan.
66741
+ Dead-code, supply-chain, external lint-config, custom-plugin, and health-score passes are skipped.
66742
+ Standard scan flags such as ${highlighter.info("--scope")}, ${highlighter.info("--project")}, ${highlighter.info("--verbose")}, and ${highlighter.info("--json")} still work.
66743
+ `;
66337
66744
  const renderCiHelpEpilog = () => `
66338
66745
  ${highlighter.dim("Examples:")}
66339
66746
  ${formatExampleLines([
@@ -66355,6 +66762,7 @@ ${highlighter.dim("Learn more:")}
66355
66762
  const collectCategoryOption = (value, previousValues) => [...previousValues ?? [], value];
66356
66763
  const program = new Command().name("react-doctor").description("Diagnose React codebase health").version(VERSION, "-v, --version", "display the version number").argument("[directory]", "project directory to scan", ".").option("--lint", "enable linting").option("--no-lint", "skip linting").option("--dead-code", "enable dead-code analysis (default)").option("--no-dead-code", "skip dead-code analysis (unused files / exports / dependencies, circular imports)").option("--supply-chain", "enable the dependency supply-chain scan (default)").option("--no-supply-chain", "skip the dependency supply-chain scan (Socket.dev dependency health checks)").option("--verbose", "show every rule and per-file details (default shows top 3 rules)").option("--debug", "force a Sentry trace and print its id at the end (paste it into a bug report)").option("--output-dir <dir>", "directory for the full diagnostics dump (default: a temp folder)").option("--score", "output only the score").option("--json", "output a single structured JSON report (suppresses other output)").option("--json-compact", "with --json, emit compact JSON (no indentation)").option("--json-out <path>", "with --json, write the report to a file instead of stdout").option("-y, --yes", "skip prompts, scan all workspace projects").option("--no-parallel", "lint serially with one worker (default: parallel across CPU cores; set the worker count with REACT_DOCTOR_PARALLEL)").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple); overrides the `projects` config field").option("--scope <value>", "how much supported JS/TS source to scan/report: full (default), files, changed (only new issues vs base), or lines (issues whose source spans touch changed lines)").option("--base <ref>", "base git ref for files/changed/lines scope (auto-detected when omitted)").option("--include-untracked", "with --scope files/changed/lines, also scan ordinary untracked files (respects .gitignore)").addOption(new Option("--diff [base]", "[deprecated] alias for --scope changed (pass `false` to force a full scan)").hideHelp()).addOption(new Option("--changed-files-from <file>", "scan source files listed in a newline-delimited changed-files file").hideHelp()).option("--no-score", "skip the score API, the share URL, and crash reporting").addOption(new Option("--category <category>", "only show diagnostics in a category (repeatable; e.g. Security)").argParser(collectCategoryOption)).option("--no-telemetry", "alias for --no-score (skip the score API, share URL, and crash reporting)").option("--staged", "scan only staged (git index) files for pre-commit hooks").option("--max-duration <seconds>", "scan time budget for the whole run, shared across workspace projects: past it, remaining lint batches and dead-code are skipped and partial results are reported (skipped files are listed in the JSON report)").option("--blocking <level>", "severity that fails CI: error (default), warning, or none (advisory)").addOption(new Option("--fail-on <level>", "[deprecated] alias for --blocking <level>").hideHelp()).option("--no-respect-inline-disables", "audit mode: neutralize inline lint suppressions before scanning").option("--warnings", "show warning-severity diagnostics (default)").option("--no-warnings", "hide warning-severity diagnostics (errors only)").option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderRootHelpEpilog);
66357
66764
  program.action(inspectAction);
66765
+ program.command("design [directory]").description("Run only the focused UI design diagnostics").addHelpText("after", renderDesignHelpEpilog).action((directory, _options, command) => designAction(directory ?? ".", command.optsWithGlobals()));
66358
66766
  program.command("why <location>").description("Explain why a rule fired (or why a suppression didn't apply) at a file:line").option("--project <name>", "select projects: workspace names or directory paths (comma-separated for multiple)").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").action((location, options) => whyAction(location, options));
66359
66767
  program.command("install").alias("setup").description("Install the react-doctor skill into your coding agents and optional git hook").option("-y, --yes", "skip prompts, install for all detected agents").option("--dry-run", "show what would be installed without writing files").option("--agent-hooks", "install native non-blocking agent hooks for Claude Code and Cursor").option("-c, --cwd <cwd>", "working directory", process.cwd()).option("--color", "force colored output").option("--no-color", "disable colored output (also honors NO_COLOR)").addHelpText("after", renderInstallHelpEpilog).action(installAction);
66360
66768
  const providerOption = ["--provider <name>", "ci provider: github-actions or gitlab-ci (auto-detected by default)"];
@@ -66403,4 +66811,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
66403
66811
  export {};
66404
66812
 
66405
66813
  //# sourceMappingURL=cli.js.map
66406
- //# debugId=24153a3f-aef9-53fd-8dff-9b016a9613fb
66814
+ //# debugId=d92b0964-cd34-5965-a1bf-ce1d06faf742