react-doctor 0.8.0-dev.eb2d687 → 0.8.1-dev.0b0b5ac

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/index.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]="4a473a3e-0567-5c2a-8eea-947cdfc7b9ee")}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]="4ef51735-a42d-5161-b990-86e4fa9e4d19")}catch(e){}}();
3
3
  import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
@@ -33040,7 +33040,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
33040
33040
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
33041
33041
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
33042
33042
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
33043
- const CORE_PACKAGE_VERSION = "0.8.0";
33043
+ const CORE_PACKAGE_VERSION = "0.8.1";
33044
33044
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
33045
33045
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
33046
33046
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -33375,10 +33375,10 @@ const FALLBACK_TSCONFIG_FILENAMES = ["tsconfig.app.json", "tsconfig.build.json"]
33375
33375
  const FRAMEWORK_PACKAGES = {
33376
33376
  next: "nextjs",
33377
33377
  "@tanstack/react-start": "tanstack-start",
33378
- vite: "vite",
33379
- "react-scripts": "cra",
33380
33378
  "@remix-run/react": "remix",
33381
33379
  gatsby: "gatsby",
33380
+ vite: "vite",
33381
+ "react-scripts": "cra",
33382
33382
  expo: "expo",
33383
33383
  "react-native": "react-native"
33384
33384
  };
@@ -33402,11 +33402,17 @@ const NEXT_CONFIG_FILENAMES = [
33402
33402
  ];
33403
33403
  const BABEL_CONFIG_FILENAMES = [
33404
33404
  ".babelrc",
33405
+ ".babelrc.js",
33405
33406
  ".babelrc.json",
33407
+ ".babelrc.cjs",
33408
+ ".babelrc.mjs",
33409
+ ".babelrc.cts",
33406
33410
  "babel.config.js",
33407
33411
  "babel.config.json",
33408
33412
  "babel.config.cjs",
33409
- "babel.config.mjs"
33413
+ "babel.config.mjs",
33414
+ "babel.config.ts",
33415
+ "babel.config.cts"
33410
33416
  ];
33411
33417
  const VITE_CONFIG_FILENAMES = [
33412
33418
  "vite.config.js",
@@ -33418,12 +33424,28 @@ const VITE_CONFIG_FILENAMES = [
33418
33424
  "vitest.config.ts",
33419
33425
  "vitest.config.js"
33420
33426
  ];
33427
+ const RSBUILD_CONFIG_FILENAMES = [
33428
+ "rsbuild.config.ts",
33429
+ "rsbuild.config.js",
33430
+ "rsbuild.config.mts",
33431
+ "rsbuild.config.mjs",
33432
+ "rsbuild.config.cts",
33433
+ "rsbuild.config.cjs"
33434
+ ];
33435
+ const RSPACK_CONFIG_FILENAMES = [
33436
+ "rspack.config.ts",
33437
+ "rspack.config.js",
33438
+ "rspack.config.mts",
33439
+ "rspack.config.mjs",
33440
+ "rspack.config.cts",
33441
+ "rspack.config.cjs"
33442
+ ];
33421
33443
  const EXPO_APP_CONFIG_FILENAMES = [
33422
33444
  "app.json",
33423
33445
  "app.config.js",
33424
33446
  "app.config.ts"
33425
33447
  ];
33426
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
33448
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|reactCompilerPreset\s*\(|["']react-compiler["']/;
33427
33449
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
33428
33450
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
33429
33451
  const hasCompilerPackage = (packageJson, compilerPackages) => {
@@ -33458,6 +33480,8 @@ const detectReactCompiler = (directory, packageJson) => {
33458
33480
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
33459
33481
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
33460
33482
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
33483
+ if (hasCompilerInConfigFiles(directory, RSBUILD_CONFIG_FILENAMES)) return true;
33484
+ if (hasCompilerInConfigFiles(directory, RSPACK_CONFIG_FILENAMES)) return true;
33461
33485
  if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
33462
33486
  return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
33463
33487
  };
@@ -33905,19 +33929,6 @@ const getPreactVersion = (packageJson) => {
33905
33929
  ...packageJson.devDependencies
33906
33930
  }.preact ?? null;
33907
33931
  };
33908
- const TANSTACK_QUERY_PACKAGES = new Set([
33909
- "@tanstack/react-query",
33910
- "@tanstack/query-core",
33911
- "react-query"
33912
- ]);
33913
- const hasTanStackQuery = (packageJson) => {
33914
- const allDependencies = {
33915
- ...packageJson.peerDependencies,
33916
- ...packageJson.dependencies,
33917
- ...packageJson.devDependencies
33918
- };
33919
- return Object.keys(allDependencies).some((packageName) => TANSTACK_QUERY_PACKAGES.has(packageName));
33920
- };
33921
33932
  const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
33922
33933
  if (version === null || !isCatalogReference(version)) return version;
33923
33934
  const catalogName = extractCatalogName(version);
@@ -34120,7 +34131,60 @@ const listWorkspacePackages = (rootDirectory) => {
34120
34131
  }
34121
34132
  return packages;
34122
34133
  };
34134
+ const getPreferredDependencyVersion = ({ packageJson, packageNames }) => {
34135
+ const allDependencies = {
34136
+ ...packageJson.devDependencies,
34137
+ ...packageJson.peerDependencies,
34138
+ ...packageJson.dependencies
34139
+ };
34140
+ for (const packageName of packageNames) {
34141
+ const version = allDependencies[packageName];
34142
+ if (version !== void 0) return version;
34143
+ }
34144
+ return null;
34145
+ };
34146
+ const TANSTACK_REACT_QUERY_PACKAGES = ["@tanstack/react-query", "react-query"];
34147
+ const getTanStackQueryVersion = (packageJson) => {
34148
+ return getPreferredDependencyVersion({
34149
+ packageJson,
34150
+ packageNames: TANSTACK_REACT_QUERY_PACKAGES
34151
+ });
34152
+ };
34153
+ const STYLED_COMPONENTS_PACKAGES = ["styled-components"];
34154
+ const getStyledComponentsVersion = (packageJson) => {
34155
+ return getPreferredDependencyVersion({
34156
+ packageJson,
34157
+ packageNames: STYLED_COMPONENTS_PACKAGES
34158
+ });
34159
+ };
34160
+ const I18N_PACKAGES = [
34161
+ "i18next",
34162
+ "react-i18next",
34163
+ "next-i18next",
34164
+ "react-intl",
34165
+ "next-intl",
34166
+ "use-intl",
34167
+ "@formatjs/intl",
34168
+ "@lingui/core",
34169
+ "@lingui/react",
34170
+ "typesafe-i18n",
34171
+ "@tolgee/react",
34172
+ "react-intl-universal"
34173
+ ];
34174
+ const hasI18nDependency = (packageJson) => {
34175
+ const allDependencies = {
34176
+ ...packageJson.peerDependencies,
34177
+ ...packageJson.dependencies,
34178
+ ...packageJson.devDependencies,
34179
+ ...packageJson.optionalDependencies
34180
+ };
34181
+ return I18N_PACKAGES.some((packageName) => allDependencies[packageName] !== void 0);
34182
+ };
34123
34183
  const REANIMATED_DEPENDENCY_NAME = "react-native-reanimated";
34184
+ const MOBX_REACT_PACKAGE_NAME = "mobx-react";
34185
+ const MOBX_REACT_LITE_PACKAGE_NAME = "mobx-react-lite";
34186
+ const MOBX_STATE_TREE_PACKAGE_NAME = "mobx-state-tree";
34187
+ const MOBX_REACT_OBSERVER_PACKAGE_NAME = "mobx-react-observer";
34124
34188
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
34125
34189
  const resolveWorkspaceDependencyVersion = ({ concreteVersion, packageName, rootDirectory, rootPackageJson, sections, workspaceDirectory, workspacePackageJson }) => {
34126
34190
  const dependencyDeclaration = getDependencyDeclaration({
@@ -34139,7 +34203,26 @@ const shouldReplaceReactVersion = (currentVersion, nextVersion) => {
34139
34203
  if (nextMajor === null) return false;
34140
34204
  return nextMajor < currentMajor;
34141
34205
  };
34142
- const evaluateManifestFacts = (facts, packageJson, directory) => {
34206
+ const shouldReplaceSupportedDependencyFact = (currentFact, nextFact, latestSupportedMajor) => {
34207
+ if (currentFact.version === null) return true;
34208
+ if (nextFact.version === null) return false;
34209
+ const currentMajor = getLowestDependencyMajor(currentFact.version);
34210
+ const nextMajor = getLowestDependencyMajor(nextFact.version);
34211
+ if (currentMajor === null) return false;
34212
+ if (nextMajor === null) return true;
34213
+ if (currentMajor > latestSupportedMajor) return false;
34214
+ if (nextMajor > latestSupportedMajor) return true;
34215
+ return nextMajor < currentMajor;
34216
+ };
34217
+ const shouldReplaceStyledComponentsVersion = (currentVersion, nextVersion) => {
34218
+ if (!currentVersion) return true;
34219
+ const currentMajor = getLowestDependencyMajor(currentVersion);
34220
+ const nextMajor = getLowestDependencyMajor(nextVersion);
34221
+ if (currentMajor === null) return nextMajor !== null && nextMajor < 6;
34222
+ if (nextMajor === null) return currentMajor >= 6;
34223
+ return nextMajor < currentMajor;
34224
+ };
34225
+ const evaluateManifestFacts = (facts, packageJson, directory, rootDirectory, rootPackageJson) => {
34143
34226
  if (facts.expo.version === null) {
34144
34227
  const spec = getDependencySpec(packageJson, "expo");
34145
34228
  if (spec !== null) facts.expo = {
@@ -34161,13 +34244,74 @@ const evaluateManifestFacts = (facts, packageJson, directory) => {
34161
34244
  sourceDirectory: directory
34162
34245
  };
34163
34246
  }
34247
+ const mobxSpec = getDependencySpec(packageJson, "mobx");
34248
+ if (mobxSpec !== null) {
34249
+ const nextMobxFact = {
34250
+ version: resolveCatalogBackedDependencyVersion({
34251
+ rootDirectory: directory,
34252
+ rootPackageJson: packageJson,
34253
+ packageName: "mobx",
34254
+ version: mobxSpec
34255
+ }),
34256
+ sourceDirectory: directory
34257
+ };
34258
+ if (shouldReplaceSupportedDependencyFact(facts.mobx, nextMobxFact, 6)) facts.mobx = nextMobxFact;
34259
+ }
34260
+ facts.hasMobxReact = facts.hasMobxReact || getDependencySpec(packageJson, MOBX_REACT_PACKAGE_NAME) !== null;
34261
+ facts.hasMobxReactLite = facts.hasMobxReactLite || getDependencySpec(packageJson, MOBX_REACT_LITE_PACKAGE_NAME) !== null;
34262
+ facts.hasMobxStateTree = facts.hasMobxStateTree || getDependencySpec(packageJson, MOBX_STATE_TREE_PACKAGE_NAME) !== null;
34263
+ facts.hasMobxReactObserver = facts.hasMobxReactObserver || getDependencySpec(packageJson, MOBX_REACT_OBSERVER_PACKAGE_NAME) !== null;
34264
+ const zustandSpec = getDependencySpec(packageJson, "zustand");
34265
+ if (zustandSpec !== null) {
34266
+ const nextZustandFact = {
34267
+ version: resolveCatalogBackedDependencyVersion({
34268
+ rootDirectory: directory,
34269
+ rootPackageJson: packageJson,
34270
+ packageName: "zustand",
34271
+ version: zustandSpec
34272
+ }),
34273
+ sourceDirectory: directory
34274
+ };
34275
+ if (shouldReplaceSupportedDependencyFact(facts.zustand, nextZustandFact, 5)) facts.zustand = nextZustandFact;
34276
+ }
34164
34277
  if (facts.reanimatedVersion === null) {
34165
34278
  const spec = getDependencySpec(packageJson, REANIMATED_DEPENDENCY_NAME);
34166
34279
  if (spec !== null) facts.reanimatedVersion = spec;
34167
34280
  }
34281
+ if (facts.valtioVersion === null) {
34282
+ const spec = getDependencySpec(packageJson, "valtio");
34283
+ if (spec !== null) facts.valtioVersion = spec;
34284
+ }
34285
+ facts.tanstackQueryVersion ??= getTanStackQueryVersion(packageJson);
34286
+ const styledComponentsVersion = resolveCatalogBackedDependencyVersion({
34287
+ rootDirectory: directory,
34288
+ rootPackageJson: packageJson,
34289
+ packageName: "styled-components",
34290
+ version: getStyledComponentsVersion(packageJson)
34291
+ });
34292
+ if (styledComponentsVersion && shouldReplaceStyledComponentsVersion(facts.styledComponentsVersion, styledComponentsVersion)) facts.styledComponentsVersion = styledComponentsVersion;
34293
+ facts.hasI18nLibrary = facts.hasI18nLibrary || hasI18nDependency(packageJson);
34168
34294
  facts.hasReactNativeAwarePackage = facts.hasReactNativeAwarePackage || isPackageJsonReactNativeAware(packageJson);
34169
34295
  facts.hasReanimatedAwarePackage = facts.hasReanimatedAwarePackage || isPackageJsonReanimatedAware(packageJson);
34170
34296
  facts.hasSsrDependency = facts.hasSsrDependency || isPackageJsonSsrAware(packageJson);
34297
+ const remotionSpec = getDependencySpec(packageJson, "remotion");
34298
+ if (remotionSpec !== null) {
34299
+ facts.hasRemotionDependency = true;
34300
+ const resolvedRemotionVersion = resolveCatalogBackedDependencyVersion({
34301
+ rootDirectory,
34302
+ rootPackageJson,
34303
+ packageName: "remotion",
34304
+ version: remotionSpec
34305
+ });
34306
+ const remotionMajorVersion = resolvedRemotionVersion === null ? null : getLowestDependencyMajor(resolvedRemotionVersion);
34307
+ if (remotionMajorVersion === null) {
34308
+ facts.hasUnknownRemotionVersion = true;
34309
+ facts.remotionVersion = null;
34310
+ } else if (!facts.hasUnknownRemotionVersion) {
34311
+ const currentRemotionMajorVersion = facts.remotionVersion === null ? null : getLowestDependencyMajor(facts.remotionVersion);
34312
+ if (currentRemotionMajorVersion === null || remotionMajorVersion < currentRemotionMajorVersion) facts.remotionVersion = resolvedRemotionVersion;
34313
+ }
34314
+ }
34171
34315
  };
34172
34316
  const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGroup }) => {
34173
34317
  const facts = {
@@ -34187,12 +34331,31 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
34187
34331
  version: null,
34188
34332
  sourceDirectory: null
34189
34333
  },
34334
+ valtioVersion: null,
34335
+ mobx: {
34336
+ version: null,
34337
+ sourceDirectory: null
34338
+ },
34339
+ hasMobxReact: false,
34340
+ hasMobxReactLite: false,
34341
+ hasMobxStateTree: false,
34342
+ hasMobxReactObserver: false,
34343
+ zustand: {
34344
+ version: null,
34345
+ sourceDirectory: null
34346
+ },
34347
+ tanstackQueryVersion: null,
34348
+ styledComponentsVersion: null,
34349
+ hasI18nLibrary: false,
34190
34350
  hasReactNativeAwarePackage: false,
34191
34351
  hasReanimatedAwarePackage: false,
34192
34352
  hasSsrDependency: false,
34353
+ hasRemotionDependency: false,
34354
+ hasUnknownRemotionVersion: false,
34355
+ remotionVersion: null,
34193
34356
  reanimatedVersion: null
34194
34357
  };
34195
- evaluateManifestFacts(facts, rootPackageJson, rootDirectory);
34358
+ evaluateManifestFacts(facts, rootPackageJson, rootDirectory, rootDirectory, rootPackageJson);
34196
34359
  let isReactGroupSettled = !collectReactGroup;
34197
34360
  const visitedDirectories = /* @__PURE__ */ new Set();
34198
34361
  for (const pattern of getWorkspacePatterns(rootDirectory, rootPackageJson)) {
@@ -34201,7 +34364,7 @@ const collectWorkspaceFacts = (rootDirectory, rootPackageJson, { collectReactGro
34201
34364
  if (visitedDirectories.has(workspaceDirectory)) continue;
34202
34365
  visitedDirectories.add(workspaceDirectory);
34203
34366
  const workspacePackageJson = readPackageJson(Path.join(workspaceDirectory, "package.json"));
34204
- evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory);
34367
+ evaluateManifestFacts(facts, workspacePackageJson, workspaceDirectory, rootDirectory, rootPackageJson);
34205
34368
  const info = extractDependencyInfo(workspacePackageJson);
34206
34369
  if (info.framework !== "unknown" && frameworkMergeRank(info.framework) < frameworkMergeRank(facts.framework)) facts.framework = info.framework;
34207
34370
  if (isReactGroupSettled) continue;
@@ -34425,11 +34588,27 @@ const discoverProjectWithoutPackageJson = (directory) => {
34425
34588
  tailwindVersion: null,
34426
34589
  zodVersion: null,
34427
34590
  zodMajorVersion: null,
34591
+ mobxVersion: null,
34592
+ mobxMajorVersion: null,
34593
+ hasMobxReact: false,
34594
+ hasMobxReactLite: false,
34595
+ hasMobxStateTree: false,
34596
+ hasMobxReactObserver: false,
34597
+ zustandVersion: null,
34598
+ zustandMajorVersion: null,
34428
34599
  framework: "unknown",
34429
34600
  hasTypeScript: hasOwnTsConfig,
34430
34601
  hasReactCompiler: false,
34431
34602
  hasReactCompilerLintPlugin: false,
34432
34603
  hasTanStackQuery: false,
34604
+ valtioVersion: null,
34605
+ valtioMajorVersion: null,
34606
+ hasRemotion: false,
34607
+ remotionVersion: null,
34608
+ remotionMajorVersion: null,
34609
+ hasI18nLibrary: false,
34610
+ tanstackQueryVersion: null,
34611
+ styledComponentsVersion: null,
34433
34612
  hasSsrDependency: false,
34434
34613
  preactVersion: null,
34435
34614
  preactMajorVersion: null,
@@ -34528,6 +34707,12 @@ const discoverProject = (directory) => {
34528
34707
  packageName: SHOPIFY_FLASH_LIST_PACKAGE_NAME,
34529
34708
  version: workspaceFacts.shopifyFlashList.version
34530
34709
  }) : null;
34710
+ const zustandVersion = resolveCatalogBackedDependencyVersion({
34711
+ rootDirectory: directory,
34712
+ rootPackageJson: packageJson,
34713
+ packageName: "zustand",
34714
+ version: workspaceFacts.zustand.version
34715
+ });
34531
34716
  const hasReanimated = hasReactNativeWorkspace && workspaceFacts.hasReanimatedAwarePackage;
34532
34717
  const reanimatedVersion = hasReanimated ? workspaceFacts.reanimatedVersion : null;
34533
34718
  const nextjsVersion = framework === "nextjs" ? resolveCatalogBackedDependencyVersion({
@@ -34536,7 +34721,21 @@ const discoverProject = (directory) => {
34536
34721
  packageName: "next",
34537
34722
  version: workspaceFacts.next.version
34538
34723
  }) : null;
34724
+ const valtioVersion = resolveCatalogBackedDependencyVersion({
34725
+ rootDirectory: directory,
34726
+ rootPackageJson: packageJson,
34727
+ packageName: "valtio",
34728
+ version: workspaceFacts.valtioVersion
34729
+ });
34730
+ const mobxVersion = resolveCatalogBackedDependencyVersion({
34731
+ rootDirectory: directory,
34732
+ rootPackageJson: packageJson,
34733
+ packageName: "mobx",
34734
+ version: workspaceFacts.mobx.version
34735
+ });
34539
34736
  const preactVersion = getPreactVersion(packageJson);
34737
+ const remotionVersion = workspaceFacts.remotionVersion;
34738
+ const tanstackQueryVersion = getTanStackQueryVersion(packageJson) ?? workspaceFacts.tanstackQueryVersion;
34540
34739
  const isPreES2023Target = hasTypeScript && detectPreES2023Target(directory);
34541
34740
  const projectInfo = {
34542
34741
  rootDirectory: directory,
@@ -34546,11 +34745,27 @@ const discoverProject = (directory) => {
34546
34745
  tailwindVersion,
34547
34746
  zodVersion,
34548
34747
  zodMajorVersion: zodVersion === null ? null : getLowestDependencyMajor(zodVersion),
34748
+ mobxVersion,
34749
+ mobxMajorVersion: mobxVersion === null ? null : getLowestDependencyMajor(mobxVersion),
34750
+ hasMobxReact: workspaceFacts.hasMobxReact,
34751
+ hasMobxReactLite: workspaceFacts.hasMobxReactLite,
34752
+ hasMobxStateTree: workspaceFacts.hasMobxStateTree,
34753
+ hasMobxReactObserver: workspaceFacts.hasMobxReactObserver,
34754
+ zustandVersion,
34755
+ zustandMajorVersion: zustandVersion === null ? null : getLowestDependencyMajor(zustandVersion),
34549
34756
  framework,
34550
34757
  hasTypeScript,
34551
34758
  hasReactCompiler: detectReactCompiler(directory, packageJson),
34552
34759
  hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
34553
- hasTanStackQuery: hasTanStackQuery(packageJson),
34760
+ hasTanStackQuery: tanstackQueryVersion !== null,
34761
+ hasI18nLibrary: workspaceFacts.hasI18nLibrary,
34762
+ tanstackQueryVersion,
34763
+ styledComponentsVersion: workspaceFacts.styledComponentsVersion,
34764
+ valtioVersion,
34765
+ valtioMajorVersion: valtioVersion === null ? null : getLowestDependencyMajor(valtioVersion),
34766
+ hasRemotion: workspaceFacts.hasRemotionDependency,
34767
+ remotionVersion,
34768
+ remotionMajorVersion: remotionVersion === null ? null : getLowestDependencyMajor(remotionVersion),
34554
34769
  hasSsrDependency: workspaceFacts.hasSsrDependency,
34555
34770
  preactVersion,
34556
34771
  preactMajorVersion: parseReactMajor(preactVersion),
@@ -34784,7 +34999,6 @@ const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
34784
34999
  "react/jsx-no-new-function-as-prop": "react-doctor/jsx-no-new-function-as-prop",
34785
35000
  "react/jsx-no-new-object-as-prop": "react-doctor/jsx-no-new-object-as-prop",
34786
35001
  "react/jsx-no-script-url": "react-doctor/jsx-no-script-url",
34787
- "react/jsx-no-target-blank": "react-doctor/jsx-no-target-blank",
34788
35002
  "react/jsx-no-undef": "react-doctor/jsx-no-undef",
34789
35003
  "react/jsx-no-useless-fragment": "react-doctor/jsx-no-useless-fragment",
34790
35004
  "react/jsx-pascal-case": "react-doctor/jsx-pascal-case",
@@ -37071,9 +37285,25 @@ const BABEL_CONFIG_FILE_NAMES = [
37071
37285
  ".babelrc.json"
37072
37286
  ];
37073
37287
  const LEGACY_PRESET_SPEC = "module:metro-react-native-babel-preset";
37288
+ const LEGACY_PRESET_PACKAGE = "metro-react-native-babel-preset";
37289
+ const REACT_NATIVE_PACKAGE = "react-native";
37290
+ const PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION = "0.73.0";
37291
+ const LEGACY_PRESET_REFERENCE = new RegExp(`['"]${LEGACY_PRESET_SPEC}['"]`);
37074
37292
  const MODERN_PRESET_REFERENCE = new RegExp(`['"]module:@react-native/babel-preset['"]`);
37075
37293
  const ENABLE_BABEL_RUNTIME_VERSION = /enableBabelRuntime["']?\s*:\s*['"]/;
37294
+ const isReactNativeVersionAtLeastPresetRename = (rootDirectory, packageJson) => {
37295
+ const installedReactNativeManifestPath = Path.join(rootDirectory, "node_modules", REACT_NATIVE_PACKAGE, "package.json");
37296
+ const reactNativeVersionSpec = (isFile(installedReactNativeManifestPath) ? readPackageJson(installedReactNativeManifestPath).version : void 0) ?? getDependencySpec(packageJson, REACT_NATIVE_PACKAGE);
37297
+ if (reactNativeVersionSpec === null || reactNativeVersionSpec === void 0) return false;
37298
+ const normalizedVersionRange = import_semver.validRange(reactNativeVersionSpec);
37299
+ if (normalizedVersionRange === null) return false;
37300
+ const minimumVersion = import_semver.minVersion(normalizedVersionRange);
37301
+ return minimumVersion !== null && import_semver.gte(minimumVersion, PRESET_RENAME_MINIMUM_REACT_NATIVE_VERSION);
37302
+ };
37303
+ const canResolveLegacyPreset = (rootDirectory, packageJson) => getDependencySpec(packageJson, LEGACY_PRESET_PACKAGE) !== null || isFile(Path.join(rootDirectory, "node_modules", LEGACY_PRESET_PACKAGE, "package.json"));
37076
37304
  const checkReactNativeMetroBabelPreset = (rootDirectory) => {
37305
+ const packageJson = readPackageJson(Path.join(rootDirectory, "package.json"));
37306
+ const shouldReportLegacyPreset = isReactNativeVersionAtLeastPresetRename(rootDirectory, packageJson) && !canResolveLegacyPreset(rootDirectory, packageJson);
37077
37307
  for (const fileName of BABEL_CONFIG_FILE_NAMES) {
37078
37308
  const filePath = Path.join(rootDirectory, fileName);
37079
37309
  if (!isFile(filePath)) continue;
@@ -37083,7 +37313,7 @@ const checkReactNativeMetroBabelPreset = (rootDirectory) => {
37083
37313
  } catch {
37084
37314
  continue;
37085
37315
  }
37086
- if (contents.includes(LEGACY_PRESET_SPEC)) return [buildReactNativeDiagnostic({
37316
+ if (shouldReportLegacyPreset && LEGACY_PRESET_REFERENCE.test(contents)) return [buildReactNativeDiagnostic({
37087
37317
  filePath: fileName,
37088
37318
  rule: "rn-no-metro-babel-preset",
37089
37319
  severity: "error",
@@ -37106,12 +37336,6 @@ const checkReactNativeProject = (rootDirectory, project) => {
37106
37336
  return [...checkReactNativeMetroBabelPreset(rootDirectory), ...checkReactNativeLibraryDependencies(rootDirectory)];
37107
37337
  };
37108
37338
  const RULE_KEY = "no-vulnerable-react-server-components";
37109
- const DEPENDENCY_SECTIONS = [
37110
- "dependencies",
37111
- "devDependencies",
37112
- "peerDependencies",
37113
- "optionalDependencies"
37114
- ];
37115
37339
  const REACT_RSC_ADVISORIES_BY_MINOR = {
37116
37340
  "19.0": {
37117
37341
  rceFixedVersion: "19.0.1",
@@ -37158,20 +37382,13 @@ const enumerateWorkspaceDirectories = (workspaceRoot) => {
37158
37382
  for (const pattern of patterns) for (const directory of resolveWorkspaceDirectories(workspaceRoot, pattern)) directories.add(directory);
37159
37383
  return [...directories];
37160
37384
  };
37161
- const readDeclaredSpec = (packageJson, packageName) => {
37162
- for (const section of DEPENDENCY_SECTIONS) {
37163
- const spec = packageJson[section]?.[packageName];
37164
- if (typeof spec === "string") return spec;
37165
- }
37166
- return null;
37167
- };
37168
37385
  const resolveVersionInDirectory = (directory, packageName, declaredSpecOverride) => {
37169
37386
  const manifestPath = Path.join(directory, "node_modules", packageName, "package.json");
37170
37387
  if (isFile(manifestPath)) {
37171
37388
  const installedVersion = import_semver.valid(readPackageJson(manifestPath).version ?? null);
37172
37389
  if (installedVersion !== null) return installedVersion;
37173
37390
  }
37174
- const candidateSpecs = [readDeclaredSpec(readPackageJson(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
37391
+ const candidateSpecs = [getDependencySpec(readPackageJson(Path.join(directory, "package.json")), packageName), declaredSpecOverride];
37175
37392
  for (const spec of candidateSpecs) {
37176
37393
  const pinnedVersion = spec === null ? null : import_semver.valid(spec);
37177
37394
  if (pinnedVersion !== null) return pinnedVersion;
@@ -37839,21 +38056,50 @@ const buildCapabilities = (project) => {
37839
38056
  if (CLIENT_ONLY_FRAMEWORKS.has(project.framework)) capabilities.add("client-only");
37840
38057
  if (project.isStaticExport) capabilities.add("nextjs:static-export");
37841
38058
  if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 15) capabilities.add("nextjs:15");
38059
+ if (project.nextjsMajorVersion !== null && project.nextjsMajorVersion >= 16) capabilities.add("nextjs:16");
37842
38060
  addMajorLadder(capabilities, "react", project.reactMajorVersion, 17, 30);
37843
38061
  if (project.reactMajorVersion !== null && project.reactMajorVersion >= 19 && isMajorMinorAtLeast(parseReactMajorMinor(project.reactVersion), {
37844
38062
  major: 19,
37845
38063
  minor: 2
37846
38064
  })) capabilities.add("react:19.2");
37847
- if (project.tailwindVersion !== null) capabilities.add("tailwind");
37848
- if (project.tailwindVersion !== null && isMajorMinorAtLeast(parseTailwindMajorMinor(project.tailwindVersion), {
37849
- major: 3,
37850
- minor: 4
37851
- })) capabilities.add("tailwind:3.4");
38065
+ if (project.tailwindVersion !== null) {
38066
+ capabilities.add("tailwind");
38067
+ const tailwindVersion = parseTailwindMajorMinor(project.tailwindVersion);
38068
+ if (isMajorMinorAtLeast(tailwindVersion, {
38069
+ major: 3,
38070
+ minor: 4
38071
+ })) capabilities.add("tailwind:3.4");
38072
+ if (tailwindVersion !== null && isMajorMinorAtLeast(tailwindVersion, {
38073
+ major: 4,
38074
+ minor: 0
38075
+ })) capabilities.add("tailwind:4");
38076
+ }
37852
38077
  if (project.zodVersion !== null) capabilities.add("zod");
37853
38078
  if (project.zodMajorVersion !== null && project.zodMajorVersion >= 4) capabilities.add("zod:4");
38079
+ if (project.mobxVersion !== void 0 && project.mobxVersion !== null || project.hasMobxReact === true || project.hasMobxReactLite === true || project.hasMobxStateTree === true || project.hasMobxReactObserver === true) capabilities.add("mobx");
38080
+ if (project.hasMobxReact === true) capabilities.add("mobx-react");
38081
+ if (project.hasMobxReactLite === true) capabilities.add("mobx-react-lite");
38082
+ if (project.hasMobxReact === true || project.hasMobxReactLite === true) capabilities.add("mobx-react-binding");
38083
+ if (project.hasMobxStateTree === true) capabilities.add("mobx-state-tree");
38084
+ if (project.hasMobxReactObserver === true) capabilities.add("mobx-react-observer");
38085
+ if (project.mobxMajorVersion !== void 0 && project.mobxMajorVersion !== null && project.mobxMajorVersion >= 4 && project.mobxMajorVersion <= 6) addMajorLadder(capabilities, "mobx", project.mobxMajorVersion, 4, 6);
38086
+ if (project.zustandVersion !== void 0 && project.zustandVersion !== null) capabilities.add("zustand");
38087
+ if (project.zustandMajorVersion !== void 0 && project.zustandMajorVersion !== null && project.zustandMajorVersion >= 1 && project.zustandMajorVersion <= 5) addMajorLadder(capabilities, "zustand", project.zustandMajorVersion, 1, 5);
37854
38088
  if (project.isPreES2023Target) capabilities.add("pre-es2023");
37855
38089
  if (project.hasReactCompiler) capabilities.add("react-compiler");
37856
- if (project.hasTanStackQuery) capabilities.add("tanstack-query");
38090
+ if (Boolean(project.hasTanStackQuery) || Boolean(project.tanstackQueryVersion)) capabilities.add("tanstack-query");
38091
+ if (project.styledComponentsVersion) {
38092
+ capabilities.add("styled-components");
38093
+ const styledComponentsMajor = getLowestDependencyMajor(project.styledComponentsVersion);
38094
+ if (styledComponentsMajor !== null && styledComponentsMajor >= 6) capabilities.add("styled-components:6");
38095
+ }
38096
+ if (project.hasI18nLibrary) capabilities.add("i18n");
38097
+ if (project.valtioVersion !== null) capabilities.add("valtio");
38098
+ addMajorLadder(capabilities, "valtio", project.valtioMajorVersion, 1, 10);
38099
+ if (project.hasRemotion) {
38100
+ capabilities.add("remotion");
38101
+ addMajorLadder(capabilities, "remotion", project.remotionMajorVersion ?? null, 4, 30);
38102
+ }
37857
38103
  if (project.hasTypeScript) capabilities.add("typescript");
37858
38104
  if (project.preactVersion !== null) capabilities.add("preact");
37859
38105
  addMajorLadder(capabilities, "preact", project.preactMajorVersion, 10, 20);
@@ -37868,7 +38114,7 @@ const getCapabilities = (project) => {
37868
38114
  capabilitiesByProject.set(project, capabilities);
37869
38115
  return capabilities;
37870
38116
  };
37871
- const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen) => {
38117
+ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhen, includedTags) => {
37872
38118
  if (requires) {
37873
38119
  for (const capability of requires) if (!capabilities.has(capability)) return false;
37874
38120
  }
@@ -37879,20 +38125,29 @@ const shouldEnableRule = (requires, tags, capabilities, ignoredTags, disabledWhe
37879
38125
  if (tags) {
37880
38126
  for (const tag of tags) if (ignoredTags.has(tag)) return false;
37881
38127
  }
38128
+ if (includedTags && includedTags.size > 0) {
38129
+ if (!tags?.some((tag) => includedTags.has(tag))) return false;
38130
+ }
37882
38131
  return true;
37883
38132
  };
38133
+ const shouldEnableRuleByDefaultStatus = (options) => options.defaultEnabled !== false || options.hasExplicitOverride === true || options.includeTagDefaults && options.hasIncludedTags;
37884
38134
  const yieldToEventLoop = () => new Promise((resolve) => {
37885
38135
  setImmediate(resolve);
37886
38136
  });
37887
38137
  const createSecurityScanSession = (rootDirectory, options) => {
37888
38138
  const capabilities = options.project ? getCapabilities(options.project) : /* @__PURE__ */ new Set();
37889
38139
  const ignoredTags = options.ignoredTags ?? /* @__PURE__ */ new Set();
38140
+ const includedTags = options.includedTags ?? /* @__PURE__ */ new Set();
37890
38141
  const enabledScanRules = REACT_DOCTOR_RULES.flatMap((entry) => {
37891
38142
  const rule = entry.rule;
37892
38143
  const scan = rule.scan;
37893
38144
  if (typeof scan !== "function") return [];
37894
- if (rule.defaultEnabled === false) return [];
37895
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) return [];
38145
+ if (!shouldEnableRuleByDefaultStatus({
38146
+ defaultEnabled: rule.defaultEnabled,
38147
+ includeTagDefaults: options.includeTagDefaults === true,
38148
+ hasIncludedTags: includedTags.size > 0
38149
+ })) return [];
38150
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) return [];
37896
38151
  return [{
37897
38152
  entry,
37898
38153
  scan,
@@ -39090,6 +39345,35 @@ const parseGithubViewerPermission = (stdout) => {
39090
39345
  return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
39091
39346
  };
39092
39347
  const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
39348
+ const parseBaselineDiffPlan = (value) => {
39349
+ const entries = splitNullSeparated(value);
39350
+ const baseFiles = /* @__PURE__ */ new Set();
39351
+ const headFiles = /* @__PURE__ */ new Set();
39352
+ for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 2) {
39353
+ const status = entries[entryIndex];
39354
+ const filePath = entries[entryIndex + 1];
39355
+ if (status === void 0 || filePath === void 0 || status.length !== 1) return null;
39356
+ if (status === "A") {
39357
+ headFiles.add(filePath);
39358
+ continue;
39359
+ }
39360
+ if (status === "D") {
39361
+ baseFiles.add(filePath);
39362
+ continue;
39363
+ }
39364
+ if (status === "M" || status === "T") {
39365
+ baseFiles.add(filePath);
39366
+ headFiles.add(filePath);
39367
+ continue;
39368
+ }
39369
+ return null;
39370
+ }
39371
+ return {
39372
+ baseFiles: [...baseFiles],
39373
+ headFiles: [...headFiles],
39374
+ untrackedFiles: []
39375
+ };
39376
+ };
39093
39377
  const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
39094
39378
  /**
39095
39379
  * `Git` wraps every `git`-via-subprocess call react-doctor makes
@@ -39292,6 +39576,45 @@ var Git = class Git extends Service()("react-doctor/Git") {
39292
39576
  githubViewerPermission,
39293
39577
  branchExists,
39294
39578
  mergeBase,
39579
+ baselineDiffPlan: (input) => {
39580
+ if (!isSafeGitRevision(input.ref)) return succeed$2(null);
39581
+ return gen(function* () {
39582
+ const unmerged = yield* runGit(input.directory, [
39583
+ "diff",
39584
+ "--no-ext-diff",
39585
+ "-z",
39586
+ "--name-only",
39587
+ "--diff-filter=U",
39588
+ "--relative"
39589
+ ]);
39590
+ if (unmerged.status !== 0 || unmerged.stdout.length > 0) return null;
39591
+ const result = yield* runGit(input.directory, [
39592
+ "diff",
39593
+ "--no-ext-diff",
39594
+ "--no-textconv",
39595
+ "--no-renames",
39596
+ "-z",
39597
+ "--name-status",
39598
+ "--relative",
39599
+ input.ref
39600
+ ]);
39601
+ if (result.status !== 0) return null;
39602
+ const plan = parseBaselineDiffPlan(result.stdout);
39603
+ if (plan === null) return null;
39604
+ const untracked = yield* runGit(input.directory, [
39605
+ "ls-files",
39606
+ "--others",
39607
+ "--exclude-standard",
39608
+ "-z"
39609
+ ]);
39610
+ if (untracked.status !== 0) return null;
39611
+ return {
39612
+ baseFiles: plan.baseFiles,
39613
+ headFiles: plan.headFiles,
39614
+ untrackedFiles: splitNullSeparated(untracked.stdout)
39615
+ };
39616
+ }).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.baselineDiffPlan"));
39617
+ },
39295
39618
  diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
39296
39619
  if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
39297
39620
  if (explicitBaseBranch !== void 0) {
@@ -39441,6 +39764,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
39441
39764
  githubViewerPermission: () => succeed$2(snapshot.githubViewerPermission ?? null),
39442
39765
  branchExists: (_directory, branch) => succeed$2(snapshot.branchExists?.get(branch) ?? false),
39443
39766
  mergeBase: ({ ref }) => succeed$2(snapshot.mergeBase?.get(ref) ?? null),
39767
+ baselineDiffPlan: () => succeed$2(snapshot.baselineDiffPlan ?? null),
39444
39768
  diffSelection: () => succeed$2(snapshot.diffSelection ?? null),
39445
39769
  stagedFilePaths: () => succeed$2(snapshot.stagedFiles ?? []),
39446
39770
  showStagedContent: (_directory, relativePath) => succeed$2(snapshot.stagedContent?.get(relativePath) ?? null),
@@ -39809,8 +40133,9 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
39809
40133
  }
39810
40134
  return enabled;
39811
40135
  };
39812
- const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
39813
- const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
40136
+ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), includedTags = /* @__PURE__ */ new Set(), includeTagDefaults = false, serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
40137
+ const hasIncludedTags = includedTags.size > 0;
40138
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" || hasIncludedTags ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
39814
40139
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
39815
40140
  const jsPlugins = [];
39816
40141
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -39825,9 +40150,14 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
39825
40150
  if (rule.scan !== void 0) continue;
39826
40151
  if (customRulesOnly && registryEntry.originallyExternal) continue;
39827
40152
  if (rule.framework !== "global" && !rule.requires) continue;
39828
- if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen)) continue;
40153
+ if (!shouldEnableRule(rule.requires, rule.tags, capabilities, ignoredTags, rule.disabledWhen, includedTags)) continue;
39829
40154
  const explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey: registryEntry.key }, severityControls);
39830
- if (rule.defaultEnabled === false && explicitRuleOverride === void 0) continue;
40155
+ if (!shouldEnableRuleByDefaultStatus({
40156
+ defaultEnabled: rule.defaultEnabled,
40157
+ includeTagDefaults,
40158
+ hasIncludedTags,
40159
+ hasExplicitOverride: explicitRuleOverride !== void 0
40160
+ })) continue;
39831
40161
  const severity = resolveRuleSeverityOverride({
39832
40162
  ruleKey: registryEntry.key,
39833
40163
  category: rule.category
@@ -39836,7 +40166,7 @@ const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, exte
39836
40166
  enabledReactDoctorRules[registryEntry.key] = severity;
39837
40167
  }
39838
40168
  const userPluginRules = {};
39839
- if (ruleSelection !== "sidecar") for (const userPlugin of userPlugins) {
40169
+ if (ruleSelection !== "sidecar" && !hasIncludedTags) for (const userPlugin of userPlugins) {
39840
40170
  Object.assign(userPluginRules, buildUserPluginRules(userPlugin, severityControls));
39841
40171
  jsPlugins.push(userPlugin.entry);
39842
40172
  }
@@ -40053,6 +40383,19 @@ const createSidecarLintCache = (cacheDirectory, rulesetHash) => {
40053
40383
  }
40054
40384
  };
40055
40385
  };
40386
+ const fingerprintCacheByFilePath = /* @__PURE__ */ new Map();
40387
+ const fingerprintFileContents = (filePath, fingerprintLength) => {
40388
+ const fileStats = NFS.statSync(filePath, { bigint: true });
40389
+ const cachedFingerprint = fingerprintCacheByFilePath.get(filePath);
40390
+ if (cachedFingerprint?.modifiedTimeNanoseconds === fileStats.mtimeNs && cachedFingerprint.sizeBytes === fileStats.size) return cachedFingerprint.fingerprint;
40391
+ const fingerprint = crypto.createHash("sha256").update(NFS.readFileSync(filePath)).digest("hex").slice(0, fingerprintLength);
40392
+ fingerprintCacheByFilePath.set(filePath, {
40393
+ fingerprint,
40394
+ modifiedTimeNanoseconds: fileStats.mtimeNs,
40395
+ sizeBytes: fileStats.size
40396
+ });
40397
+ return fingerprint;
40398
+ };
40056
40399
  const bundledRequire = createRequire(import.meta.url);
40057
40400
  const childNodeVersionByBinaryPath = /* @__PURE__ */ new Map();
40058
40401
  const resolveChildNodeVersion = (nodeBinaryPath) => {
@@ -40076,6 +40419,13 @@ const TOOLCHAIN_PACKAGE_SPECIFIERS = [
40076
40419
  "oxlint-plugin-react-doctor/package.json",
40077
40420
  "eslint-plugin-react-hooks/package.json"
40078
40421
  ];
40422
+ const resolvePluginFingerprint = () => {
40423
+ try {
40424
+ return fingerprintFileContents(bundledRequire.resolve("oxlint-plugin-react-doctor"), 16);
40425
+ } catch {
40426
+ return "unresolved";
40427
+ }
40428
+ };
40079
40429
  const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
40080
40430
  const versions = [`node=${resolveChildNodeVersion(nodeBinaryPath)}`];
40081
40431
  for (const specifier of TOOLCHAIN_PACKAGE_SPECIFIERS) try {
@@ -40085,6 +40435,7 @@ const resolveOxlintToolchainVersions = (nodeBinaryPath = process.execPath) => {
40085
40435
  } catch {
40086
40436
  versions.push(`${specifier}=missing`);
40087
40437
  }
40438
+ versions.push(`oxlint-plugin-react-doctor#fingerprint=${resolvePluginFingerprint()}`);
40088
40439
  return versions;
40089
40440
  };
40090
40441
  const esmRequire = createRequire(import.meta.url);
@@ -40778,12 +41129,17 @@ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown
40778
41129
  const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
40779
41130
  const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
40780
41131
  const REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION = "It's how the library works, not a bug in your code. Memoize values you pass from it into other memoized components, or suppress it with `// react-doctor-disable-next-line react-hooks-js/incompatible-library`.";
41132
+ const SET_STATE_IN_EFFECT_ACTION = "Prefer deriving or initializing the value before render. If the effect must read a browser API after mount, treat this as advisory or suppress it with `// react-doctor-disable-next-line react-hooks-js/set-state-in-effect`.";
40781
41133
  const REACT_COMPILER_GENERIC_MESSAGE = `${REACT_COMPILER_IMPACT}. ${REACT_COMPILER_ACTION}`;
40782
41134
  const buildReactCompilerMessage = (reasonSummary, action = REACT_COMPILER_ACTION) => {
40783
41135
  const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
40784
41136
  if (!normalizedSummary) return `${REACT_COMPILER_IMPACT}. ${action}`;
40785
41137
  return `${REACT_COMPILER_IMPACT}: ${normalizedSummary}. ${action}`;
40786
41138
  };
41139
+ const buildSetStateInEffectMessage = (reasonSummary) => {
41140
+ const normalizedSummary = reasonSummary.replace(TRAILING_PERIOD_PATTERN, "");
41141
+ return `This synchronous effect update causes an extra render${normalizedSummary ? `: ${normalizedSummary}` : ""}. ${SET_STATE_IN_EFFECT_ACTION}`;
41142
+ };
40787
41143
  const PLUGIN_CATEGORY_MAP = {
40788
41144
  react: "Bugs",
40789
41145
  "react-hooks": "Bugs",
@@ -40841,6 +41197,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
40841
41197
  message: REACT_ERROR_BOUNDARY_MESSAGE,
40842
41198
  help: reasonDetail || help
40843
41199
  };
41200
+ if (rule === "set-state-in-effect") return {
41201
+ message: buildSetStateInEffectMessage(reasonSummary.trim()),
41202
+ help: reasonDetail || help
41203
+ };
40844
41204
  return {
40845
41205
  message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
40846
41206
  help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
@@ -41551,7 +41911,7 @@ const reactHooksJsPluginDropNote = (error) => {
41551
41911
  * 6. always restore disable directives + clean up the temp dir
41552
41912
  */
41553
41913
  const runOxlint = async (options) => {
41554
- 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;
41914
+ 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;
41555
41915
  const serverAuthFunctionNames = Array.isArray(userConfig?.serverAuthFunctionNames) ? userConfig.serverAuthFunctionNames.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0;
41556
41916
  const severityControls = buildRuleSeverityControls(userConfig);
41557
41917
  validateRuleRegistration();
@@ -41565,13 +41925,15 @@ const runOxlint = async (options) => {
41565
41925
  }
41566
41926
  const pluginPath = resolvePluginPath();
41567
41927
  const extendsPaths = (adoptExistingLintConfig && !customRulesOnly ? detectUserLintConfigPaths(rootDirectory) : []).filter(canOxlintExtendConfig);
41568
- const userPlugins = resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
41928
+ const userPlugins = includedTags.size > 0 ? [] : resolveUserPlugins(userConfig?.plugins, configSourceDirectory);
41569
41929
  const buildConfig = (overrides) => createOxlintConfig({
41570
41930
  pluginPath,
41571
41931
  project,
41572
41932
  customRulesOnly,
41573
41933
  extendsPaths: overrides.extendsPaths,
41574
41934
  ignoredTags,
41935
+ includedTags,
41936
+ includeTagDefaults,
41575
41937
  serverAuthFunctionNames,
41576
41938
  severityControls,
41577
41939
  userPlugins,
@@ -41960,6 +42322,8 @@ var Linter = class Linter extends Service()("react-doctor/Linter") {
41960
42322
  respectInlineDisables: input.respectInlineDisables,
41961
42323
  adoptExistingLintConfig: input.adoptExistingLintConfig,
41962
42324
  ignoredTags: input.ignoredTags,
42325
+ includedTags: input.includedTags,
42326
+ includeTagDefaults: input.includeTagDefaults,
41963
42327
  userConfig: input.userConfig ?? null,
41964
42328
  configSourceDirectory: input.configSourceDirectory,
41965
42329
  onPartialFailure: (reason) => {
@@ -42808,7 +43172,9 @@ const runInspect = (input, hooks = {}) => gen(function* () {
42808
43172
  const securityScanFailedRef = yield* make$13(false);
42809
43173
  const securityScanFiber = yield* forkChild(runCollect(applyPerElementPipeline(isDiffMode ? empty$4 : unwrap(tryPromise(() => checkSecurityScanCooperative(scanDirectory, {
42810
43174
  project,
42811
- ignoredTags: input.ignoredTags
43175
+ ignoredTags: input.ignoredTags,
43176
+ includedTags: input.includedTags,
43177
+ includeTagDefaults: input.includeTagDefaults
42812
43178
  })).pipe(map$3((diagnostics) => fromIterable$1(diagnostics)), catch_$1(() => set(securityScanFailedRef, true).pipe(as(empty$4))))))).pipe(withSpan("SecurityScan.run")));
42813
43179
  const shouldRunSupplyChain = !isDiffMode || (input.supplyChainManifestChanged ?? false);
42814
43180
  const supplyChainOverlapTimeout = yield* SupplyChainOverlapTimeoutMs;
@@ -42899,6 +43265,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
42899
43265
  respectInlineDisables: input.respectInlineDisables,
42900
43266
  adoptExistingLintConfig: input.adoptExistingLintConfig,
42901
43267
  ignoredTags: input.ignoredTags,
43268
+ includedTags: input.includedTags,
43269
+ includeTagDefaults: input.includeTagDefaults,
42902
43270
  userConfig: resolvedConfig.config ?? void 0,
42903
43271
  configSourceDirectory: resolvedConfig.configSourceDirectory ?? void 0,
42904
43272
  onFileProgress: (scannedFileCount, totalFileCount) => {
@@ -43166,12 +43534,19 @@ const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
43166
43534
  */
43167
43535
  const materializeSourceTree = (input) => gen(function* () {
43168
43536
  const materializedFiles = [];
43537
+ const unmaterializedFiles = [];
43169
43538
  const resolvedTempDirectory = path.resolve(input.tempDirectory);
43170
43539
  for (const relativePath of input.files) {
43171
43540
  const content = yield* input.readContent(relativePath).pipe(orElseSucceed(() => null));
43172
- if (content === null) continue;
43541
+ if (content === null) {
43542
+ unmaterializedFiles.push(relativePath);
43543
+ continue;
43544
+ }
43173
43545
  const candidateTargetPath = path.resolve(resolvedTempDirectory, relativePath);
43174
- if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory)) continue;
43546
+ if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory)) {
43547
+ unmaterializedFiles.push(relativePath);
43548
+ continue;
43549
+ }
43175
43550
  yield* sync(() => {
43176
43551
  fs.mkdirSync(path.dirname(candidateTargetPath), { recursive: true });
43177
43552
  fs.writeFileSync(candidateTargetPath, content);
@@ -43188,6 +43563,7 @@ const materializeSourceTree = (input) => gen(function* () {
43188
43563
  return {
43189
43564
  tempDirectory: input.tempDirectory,
43190
43565
  materializedFiles,
43566
+ unmaterializedFiles,
43191
43567
  cleanup: () => {
43192
43568
  try {
43193
43569
  fs.rmSync(input.tempDirectory, {
@@ -43751,4 +44127,4 @@ const toJsonReport = (result, options) => buildJsonReport({
43751
44127
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
43752
44128
 
43753
44129
  //# sourceMappingURL=index.js.map
43754
- //# debugId=4a473a3e-0567-5c2a-8eea-947cdfc7b9ee
44130
+ //# debugId=4ef51735-a42d-5161-b990-86e4fa9e4d19