react-doctor 0.7.9-dev.9aa98b9 → 0.7.9-dev.a16e452

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]="a51e06c5-66da-5c06-be51-50358579743c")}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]="5c4df375-a5c4-57d2-9076-4e54cbb8f3bd")}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";
@@ -36532,11 +36532,8 @@ const frameworkMergeRank = (framework) => {
36532
36532
  if (framework === "unknown") return 3;
36533
36533
  return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
36534
36534
  };
36535
- const REACT_COMPILER_PACKAGES = new Set([
36536
- "babel-plugin-react-compiler",
36537
- "react-compiler-runtime",
36538
- "eslint-plugin-react-compiler"
36539
- ]);
36535
+ const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
36536
+ const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
36540
36537
  const NEXT_CONFIG_FILENAMES = [
36541
36538
  "next.config.js",
36542
36539
  "next.config.mjs",
@@ -36566,16 +36563,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
36566
36563
  "app.config.js",
36567
36564
  "app.config.ts"
36568
36565
  ];
36569
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|["']react-compiler["']/;
36566
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
36570
36567
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
36571
36568
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
36572
- const hasCompilerPackage = (packageJson) => {
36569
+ const hasCompilerPackage = (packageJson, compilerPackages) => {
36573
36570
  const allDependencies = {
36574
36571
  ...packageJson.peerDependencies,
36575
36572
  ...packageJson.dependencies,
36576
36573
  ...packageJson.devDependencies
36577
36574
  };
36578
- return Object.keys(allDependencies).some((packageName) => REACT_COMPILER_PACKAGES.has(packageName));
36575
+ return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
36576
+ };
36577
+ const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
36578
+ if (isProjectBoundary(directory)) return false;
36579
+ let ancestorDirectory = Path.dirname(directory);
36580
+ while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
36581
+ const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
36582
+ if (isFile(ancestorPackagePath)) {
36583
+ if (hasCompilerPackage(readPackageJson$1(ancestorPackagePath), compilerPackages)) return true;
36584
+ }
36585
+ if (isProjectBoundary(ancestorDirectory)) return false;
36586
+ ancestorDirectory = Path.dirname(ancestorDirectory);
36587
+ }
36588
+ return false;
36579
36589
  };
36580
36590
  const hasCompilerInConfigFile = (filePath) => {
36581
36591
  if (!isFile(filePath)) return false;
@@ -36584,23 +36594,14 @@ const hasCompilerInConfigFile = (filePath) => {
36584
36594
  };
36585
36595
  const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
36586
36596
  const detectReactCompiler = (directory, packageJson) => {
36587
- if (hasCompilerPackage(packageJson)) return true;
36597
+ if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
36588
36598
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
36589
36599
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
36590
36600
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
36591
36601
  if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
36592
- if (isProjectBoundary(directory)) return false;
36593
- let ancestorDirectory = Path.dirname(directory);
36594
- while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
36595
- const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
36596
- if (isFile(ancestorPackagePath)) {
36597
- if (hasCompilerPackage(readPackageJson$1(ancestorPackagePath))) return true;
36598
- }
36599
- if (isProjectBoundary(ancestorDirectory)) return false;
36600
- ancestorDirectory = Path.dirname(ancestorDirectory);
36601
- }
36602
- return false;
36602
+ return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
36603
36603
  };
36604
+ const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
36604
36605
  const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
36605
36606
  const filePath = Path.join(directory, filename);
36606
36607
  return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
@@ -37564,6 +37565,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
37564
37565
  framework: "unknown",
37565
37566
  hasTypeScript: hasOwnTsConfig,
37566
37567
  hasReactCompiler: false,
37568
+ hasReactCompilerLintPlugin: false,
37567
37569
  hasTanStackQuery: false,
37568
37570
  hasSsrDependency: false,
37569
37571
  preactVersion: null,
@@ -37684,6 +37686,7 @@ const discoverProject = (directory) => {
37684
37686
  framework,
37685
37687
  hasTypeScript,
37686
37688
  hasReactCompiler: detectReactCompiler(directory, packageJson),
37689
+ hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
37687
37690
  hasTanStackQuery: hasTanStackQuery(packageJson),
37688
37691
  hasSsrDependency: workspaceFacts.hasSsrDependency,
37689
37692
  preactVersion,
@@ -42963,7 +42966,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
42963
42966
  return enabled;
42964
42967
  };
42965
42968
  const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
42966
- const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
42969
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
42967
42970
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
42968
42971
  const jsPlugins = [];
42969
42972
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -43926,6 +43929,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
43926
43929
  const TRAILING_PERIOD_PATTERN = /\.$/;
43927
43930
  const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
43928
43931
  const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
43932
+ const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
43933
+ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
43929
43934
  const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
43930
43935
  const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
43931
43936
  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`.";
@@ -43969,6 +43974,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
43969
43974
  const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
43970
43975
  const resolveDiagnosticTitle = (plugin, rule) => {
43971
43976
  if (plugin !== "react-hooks-js") return getRuleTitle(rule);
43977
+ if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
43972
43978
  return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
43973
43979
  };
43974
43980
  const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
@@ -43987,6 +43993,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
43987
43993
  };
43988
43994
  const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
43989
43995
  const reasonDetail = reasonDetailLines.join("\n").trim();
43996
+ if (rule === "error-boundaries") return {
43997
+ message: REACT_ERROR_BOUNDARY_MESSAGE,
43998
+ help: reasonDetail || help
43999
+ };
43990
44000
  return {
43991
44001
  message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
43992
44002
  help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
@@ -44008,7 +44018,10 @@ const parseRuleCode = (code) => {
44008
44018
  rule: match[2]
44009
44019
  };
44010
44020
  };
44011
- const resolveDiagnosticCategory = (plugin, rule) => getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
44021
+ const resolveDiagnosticCategory = (plugin, rule) => {
44022
+ if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
44023
+ return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
44024
+ };
44012
44025
  const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
44013
44026
  /**
44014
44027
  * Maps oxlint's non-primary labels (`labels[1..]`) into related source
@@ -44821,7 +44834,7 @@ const runOxlint = async (options) => {
44821
44834
  };
44822
44835
  }
44823
44836
  };
44824
- if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
44837
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
44825
44838
  const rulesetHash = computeRulesetHash({
44826
44839
  config: buildConfig({
44827
44840
  extendsPaths: [],
@@ -45263,6 +45276,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
45263
45276
  });
45264
45277
  }));
45265
45278
  };
45279
+ const HOME_DIRECTORY = os.homedir();
45280
+ const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
45281
+ const scrubSensitivePaths = (text) => {
45282
+ let scrubbed = text;
45283
+ if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
45284
+ for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
45285
+ return scrubbed;
45286
+ };
45266
45287
  const ScoreApiResponseSchema = Struct({
45267
45288
  score: Number$1,
45268
45289
  label: String$1,
@@ -45277,7 +45298,10 @@ const ScoreApiResponseSchema = Struct({
45277
45298
  })))
45278
45299
  });
45279
45300
  const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
45280
- const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
45301
+ const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
45302
+ ...rest,
45303
+ filePath: redactSensitiveText(scrubSensitivePaths(filePath))
45304
+ }));
45281
45305
  const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
45282
45306
  const describeFailure = (error) => {
45283
45307
  if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
@@ -45290,7 +45314,7 @@ const calculateScore = async (diagnostics, options = {}) => {
45290
45314
  const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
45291
45315
  try {
45292
45316
  const compressedBody = gzipSync(JSON.stringify({
45293
- diagnostics: stripLocalFileFields(diagnostics),
45317
+ diagnostics: sanitizeScoreDiagnostics(diagnostics),
45294
45318
  ...options.metadata?.repo ? { repo: options.metadata.repo } : {},
45295
45319
  ...options.metadata?.sha ? { sha: options.metadata.sha } : {},
45296
45320
  ...options.metadata?.framework ? { framework: options.metadata.framework } : {},
@@ -47135,7 +47159,7 @@ const makeNoopConsole = () => ({
47135
47159
  });
47136
47160
  //#endregion
47137
47161
  //#region src/cli/utils/version.ts
47138
- const VERSION = "0.7.9-dev.9aa98b9";
47162
+ const VERSION = "0.7.9-dev.a16e452";
47139
47163
  //#endregion
47140
47164
  //#region src/cli/utils/json-mode.ts
47141
47165
  let context = null;
@@ -47221,23 +47245,6 @@ const getRunId = () => {
47221
47245
  return cachedRunId;
47222
47246
  };
47223
47247
  //#endregion
47224
- //#region src/cli/utils/scrub-sensitive-text.ts
47225
- const HOME_DIRECTORY = os.homedir();
47226
- const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
47227
- /**
47228
- * Replaces the user's home directory (and generic `/Users|/home|C:\Users\<name>`
47229
- * roots) with `~` so absolute paths can't be tied back to an individual. Keeps
47230
- * the path's relative structure intact, which stays useful for debugging while
47231
- * dropping the personally-identifying prefix. Idempotent — re-running on an
47232
- * already-scrubbed `~/...` path is a no-op.
47233
- */
47234
- const scrubSensitivePaths = (text) => {
47235
- let scrubbed = text;
47236
- if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
47237
- for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
47238
- return scrubbed;
47239
- };
47240
- //#endregion
47241
47248
  //#region src/cli/utils/build-run-context.ts
47242
47249
  const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
47243
47250
  const detectInvokedVia = () => {
@@ -47504,13 +47511,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47504
47511
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47505
47512
  * standard `SENTRY_RELEASE` override.
47506
47513
  */
47507
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.9aa98b9`;
47514
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.a16e452`;
47508
47515
  /**
47509
47516
  * Deployment environment shown in Sentry's environment filter. Defaults to
47510
47517
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47511
47518
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47512
47519
  */
47513
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.9aa98b9") ? "development" : "production");
47520
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.a16e452") ? "development" : "production");
47514
47521
  /**
47515
47522
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47516
47523
  * (set to `0` to disable tracing) and falls back to
@@ -65788,4 +65795,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
65788
65795
  export {};
65789
65796
 
65790
65797
  //# sourceMappingURL=cli.js.map
65791
- //# debugId=a51e06c5-66da-5c06-be51-50358579743c
65798
+ //# debugId=5c4df375-a5c4-57d2-9076-4e54cbb8f3bd
package/dist/index.d.ts CHANGED
@@ -9540,6 +9540,7 @@ interface ProjectInfo {
9540
9540
  framework: Framework;
9541
9541
  hasTypeScript: boolean;
9542
9542
  hasReactCompiler: boolean;
9543
+ hasReactCompilerLintPlugin?: boolean;
9543
9544
  hasTanStackQuery: boolean;
9544
9545
  /**
9545
9546
  * `true` when the project or a workspace declares a Vite-based SSR runtime
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]="b173f528-892d-5c34-b63a-37cb26d03f0f")}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]="526cf949-6544-5cb8-bf6d-3f4d854b6678")}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";
@@ -33336,11 +33336,8 @@ const frameworkMergeRank = (framework) => {
33336
33336
  if (framework === "unknown") return 3;
33337
33337
  return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
33338
33338
  };
33339
- const REACT_COMPILER_PACKAGES = new Set([
33340
- "babel-plugin-react-compiler",
33341
- "react-compiler-runtime",
33342
- "eslint-plugin-react-compiler"
33343
- ]);
33339
+ const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
33340
+ const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
33344
33341
  const NEXT_CONFIG_FILENAMES = [
33345
33342
  "next.config.js",
33346
33343
  "next.config.mjs",
@@ -33370,16 +33367,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
33370
33367
  "app.config.js",
33371
33368
  "app.config.ts"
33372
33369
  ];
33373
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|["']react-compiler["']/;
33370
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
33374
33371
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
33375
33372
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
33376
- const hasCompilerPackage = (packageJson) => {
33373
+ const hasCompilerPackage = (packageJson, compilerPackages) => {
33377
33374
  const allDependencies = {
33378
33375
  ...packageJson.peerDependencies,
33379
33376
  ...packageJson.dependencies,
33380
33377
  ...packageJson.devDependencies
33381
33378
  };
33382
- return Object.keys(allDependencies).some((packageName) => REACT_COMPILER_PACKAGES.has(packageName));
33379
+ return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
33380
+ };
33381
+ const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
33382
+ if (isProjectBoundary(directory)) return false;
33383
+ let ancestorDirectory = Path.dirname(directory);
33384
+ while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
33385
+ const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
33386
+ if (isFile(ancestorPackagePath)) {
33387
+ if (hasCompilerPackage(readPackageJson(ancestorPackagePath), compilerPackages)) return true;
33388
+ }
33389
+ if (isProjectBoundary(ancestorDirectory)) return false;
33390
+ ancestorDirectory = Path.dirname(ancestorDirectory);
33391
+ }
33392
+ return false;
33383
33393
  };
33384
33394
  const hasCompilerInConfigFile = (filePath) => {
33385
33395
  if (!isFile(filePath)) return false;
@@ -33388,23 +33398,14 @@ const hasCompilerInConfigFile = (filePath) => {
33388
33398
  };
33389
33399
  const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
33390
33400
  const detectReactCompiler = (directory, packageJson) => {
33391
- if (hasCompilerPackage(packageJson)) return true;
33401
+ if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
33392
33402
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
33393
33403
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
33394
33404
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
33395
33405
  if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
33396
- if (isProjectBoundary(directory)) return false;
33397
- let ancestorDirectory = Path.dirname(directory);
33398
- while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
33399
- const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
33400
- if (isFile(ancestorPackagePath)) {
33401
- if (hasCompilerPackage(readPackageJson(ancestorPackagePath))) return true;
33402
- }
33403
- if (isProjectBoundary(ancestorDirectory)) return false;
33404
- ancestorDirectory = Path.dirname(ancestorDirectory);
33405
- }
33406
- return false;
33406
+ return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
33407
33407
  };
33408
+ const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
33408
33409
  const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
33409
33410
  const filePath = Path.join(directory, filename);
33410
33411
  return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
@@ -34371,6 +34372,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
34371
34372
  framework: "unknown",
34372
34373
  hasTypeScript: hasOwnTsConfig,
34373
34374
  hasReactCompiler: false,
34375
+ hasReactCompilerLintPlugin: false,
34374
34376
  hasTanStackQuery: false,
34375
34377
  hasSsrDependency: false,
34376
34378
  preactVersion: null,
@@ -34491,6 +34493,7 @@ const discoverProject = (directory) => {
34491
34493
  framework,
34492
34494
  hasTypeScript,
34493
34495
  hasReactCompiler: detectReactCompiler(directory, packageJson),
34496
+ hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
34494
34497
  hasTanStackQuery: hasTanStackQuery(packageJson),
34495
34498
  hasSsrDependency: workspaceFacts.hasSsrDependency,
34496
34499
  preactVersion,
@@ -39719,7 +39722,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
39719
39722
  return enabled;
39720
39723
  };
39721
39724
  const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
39722
- const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
39725
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
39723
39726
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
39724
39727
  const jsPlugins = [];
39725
39728
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -40682,6 +40685,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
40682
40685
  const TRAILING_PERIOD_PATTERN = /\.$/;
40683
40686
  const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
40684
40687
  const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
40688
+ const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
40689
+ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
40685
40690
  const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
40686
40691
  const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
40687
40692
  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`.";
@@ -40725,6 +40730,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
40725
40730
  const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
40726
40731
  const resolveDiagnosticTitle = (plugin, rule) => {
40727
40732
  if (plugin !== "react-hooks-js") return getRuleTitle(rule);
40733
+ if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
40728
40734
  return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
40729
40735
  };
40730
40736
  const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
@@ -40743,6 +40749,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
40743
40749
  };
40744
40750
  const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
40745
40751
  const reasonDetail = reasonDetailLines.join("\n").trim();
40752
+ if (rule === "error-boundaries") return {
40753
+ message: REACT_ERROR_BOUNDARY_MESSAGE,
40754
+ help: reasonDetail || help
40755
+ };
40746
40756
  return {
40747
40757
  message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
40748
40758
  help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
@@ -40764,7 +40774,10 @@ const parseRuleCode = (code) => {
40764
40774
  rule: match[2]
40765
40775
  };
40766
40776
  };
40767
- const resolveDiagnosticCategory = (plugin, rule) => getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
40777
+ const resolveDiagnosticCategory = (plugin, rule) => {
40778
+ if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
40779
+ return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
40780
+ };
40768
40781
  const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
40769
40782
  /**
40770
40783
  * Maps oxlint's non-primary labels (`labels[1..]`) into related source
@@ -41577,7 +41590,7 @@ const runOxlint = async (options) => {
41577
41590
  };
41578
41591
  }
41579
41592
  };
41580
- if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
41593
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
41581
41594
  const rulesetHash = computeRulesetHash({
41582
41595
  config: buildConfig({
41583
41596
  extendsPaths: [],
@@ -42019,6 +42032,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
42019
42032
  });
42020
42033
  }));
42021
42034
  };
42035
+ const HOME_DIRECTORY = os.homedir();
42036
+ const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
42037
+ const scrubSensitivePaths = (text) => {
42038
+ let scrubbed = text;
42039
+ if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
42040
+ for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
42041
+ return scrubbed;
42042
+ };
42022
42043
  const ScoreApiResponseSchema = Struct({
42023
42044
  score: Number$1,
42024
42045
  label: String$1,
@@ -42033,7 +42054,10 @@ const ScoreApiResponseSchema = Struct({
42033
42054
  })))
42034
42055
  });
42035
42056
  const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
42036
- const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
42057
+ const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
42058
+ ...rest,
42059
+ filePath: redactSensitiveText(scrubSensitivePaths(filePath))
42060
+ }));
42037
42061
  const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
42038
42062
  const describeFailure = (error) => {
42039
42063
  if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
@@ -42046,7 +42070,7 @@ const calculateScore = async (diagnostics, options = {}) => {
42046
42070
  const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
42047
42071
  try {
42048
42072
  const compressedBody = gzipSync(JSON.stringify({
42049
- diagnostics: stripLocalFileFields(diagnostics),
42073
+ diagnostics: sanitizeScoreDiagnostics(diagnostics),
42050
42074
  ...options.metadata?.repo ? { repo: options.metadata.repo } : {},
42051
42075
  ...options.metadata?.sha ? { sha: options.metadata.sha } : {},
42052
42076
  ...options.metadata?.framework ? { framework: options.metadata.framework } : {},
@@ -43639,4 +43663,4 @@ const toJsonReport = (result, options) => buildJsonReport({
43639
43663
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
43640
43664
 
43641
43665
  //# sourceMappingURL=index.js.map
43642
- //# debugId=b173f528-892d-5c34-b63a-37cb26d03f0f
43666
+ //# debugId=526cf949-6544-5cb8-bf6d-3f4d854b6678
package/dist/lsp.js CHANGED
@@ -33388,11 +33388,8 @@ const frameworkMergeRank = (framework) => {
33388
33388
  if (framework === "unknown") return 3;
33389
33389
  return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
33390
33390
  };
33391
- const REACT_COMPILER_PACKAGES = new Set([
33392
- "babel-plugin-react-compiler",
33393
- "react-compiler-runtime",
33394
- "eslint-plugin-react-compiler"
33395
- ]);
33391
+ const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
33392
+ const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
33396
33393
  const NEXT_CONFIG_FILENAMES = [
33397
33394
  "next.config.js",
33398
33395
  "next.config.mjs",
@@ -33422,16 +33419,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
33422
33419
  "app.config.js",
33423
33420
  "app.config.ts"
33424
33421
  ];
33425
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|["']react-compiler["']/;
33422
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
33426
33423
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
33427
33424
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
33428
- const hasCompilerPackage = (packageJson) => {
33425
+ const hasCompilerPackage = (packageJson, compilerPackages) => {
33429
33426
  const allDependencies = {
33430
33427
  ...packageJson.peerDependencies,
33431
33428
  ...packageJson.dependencies,
33432
33429
  ...packageJson.devDependencies
33433
33430
  };
33434
- return Object.keys(allDependencies).some((packageName) => REACT_COMPILER_PACKAGES.has(packageName));
33431
+ return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
33432
+ };
33433
+ const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
33434
+ if (isProjectBoundary(directory)) return false;
33435
+ let ancestorDirectory = Path.dirname(directory);
33436
+ while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
33437
+ const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
33438
+ if (isFile(ancestorPackagePath)) {
33439
+ if (hasCompilerPackage(readPackageJson(ancestorPackagePath), compilerPackages)) return true;
33440
+ }
33441
+ if (isProjectBoundary(ancestorDirectory)) return false;
33442
+ ancestorDirectory = Path.dirname(ancestorDirectory);
33443
+ }
33444
+ return false;
33435
33445
  };
33436
33446
  const hasCompilerInConfigFile = (filePath) => {
33437
33447
  if (!isFile(filePath)) return false;
@@ -33440,23 +33450,14 @@ const hasCompilerInConfigFile = (filePath) => {
33440
33450
  };
33441
33451
  const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
33442
33452
  const detectReactCompiler = (directory, packageJson) => {
33443
- if (hasCompilerPackage(packageJson)) return true;
33453
+ if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
33444
33454
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
33445
33455
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
33446
33456
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
33447
33457
  if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;
33448
- if (isProjectBoundary(directory)) return false;
33449
- let ancestorDirectory = Path.dirname(directory);
33450
- while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
33451
- const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
33452
- if (isFile(ancestorPackagePath)) {
33453
- if (hasCompilerPackage(readPackageJson(ancestorPackagePath))) return true;
33454
- }
33455
- if (isProjectBoundary(ancestorDirectory)) return false;
33456
- ancestorDirectory = Path.dirname(ancestorDirectory);
33457
- }
33458
- return false;
33458
+ return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
33459
33459
  };
33460
+ const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
33460
33461
  const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
33461
33462
  const filePath = Path.join(directory, filename);
33462
33463
  return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
@@ -34423,6 +34424,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
34423
34424
  framework: "unknown",
34424
34425
  hasTypeScript: hasOwnTsConfig,
34425
34426
  hasReactCompiler: false,
34427
+ hasReactCompilerLintPlugin: false,
34426
34428
  hasTanStackQuery: false,
34427
34429
  hasSsrDependency: false,
34428
34430
  preactVersion: null,
@@ -34543,6 +34545,7 @@ const discoverProject = (directory) => {
34543
34545
  framework,
34544
34546
  hasTypeScript,
34545
34547
  hasReactCompiler: detectReactCompiler(directory, packageJson),
34548
+ hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
34546
34549
  hasTanStackQuery: hasTanStackQuery(packageJson),
34547
34550
  hasSsrDependency: workspaceFacts.hasSsrDependency,
34548
34551
  preactVersion,
@@ -39697,7 +39700,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
39697
39700
  return enabled;
39698
39701
  };
39699
39702
  const createOxlintConfig = ({ pluginPath, project, customRulesOnly = false, extendsPaths = [], ignoredTags = /* @__PURE__ */ new Set(), serverAuthFunctionNames, severityControls, userPlugins = [], disableReactHooksJsPlugin = false, ruleSelection, sidecarRuleIdFilter }) => {
39700
- const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler, customRulesOnly);
39703
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
39701
39704
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
39702
39705
  const jsPlugins = [];
39703
39706
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -40660,6 +40663,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
40660
40663
  const TRAILING_PERIOD_PATTERN = /\.$/;
40661
40664
  const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
40662
40665
  const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
40666
+ const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
40667
+ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
40663
40668
  const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
40664
40669
  const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
40665
40670
  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`.";
@@ -40703,6 +40708,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
40703
40708
  const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
40704
40709
  const resolveDiagnosticTitle = (plugin, rule) => {
40705
40710
  if (plugin !== "react-hooks-js") return getRuleTitle(rule);
40711
+ if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
40706
40712
  return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
40707
40713
  };
40708
40714
  const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
@@ -40721,6 +40727,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
40721
40727
  };
40722
40728
  const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
40723
40729
  const reasonDetail = reasonDetailLines.join("\n").trim();
40730
+ if (rule === "error-boundaries") return {
40731
+ message: REACT_ERROR_BOUNDARY_MESSAGE,
40732
+ help: reasonDetail || help
40733
+ };
40724
40734
  return {
40725
40735
  message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
40726
40736
  help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
@@ -40742,7 +40752,10 @@ const parseRuleCode = (code) => {
40742
40752
  rule: match[2]
40743
40753
  };
40744
40754
  };
40745
- const resolveDiagnosticCategory = (plugin, rule) => getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
40755
+ const resolveDiagnosticCategory = (plugin, rule) => {
40756
+ if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
40757
+ return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
40758
+ };
40746
40759
  const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
40747
40760
  /**
40748
40761
  * Maps oxlint's non-primary labels (`labels[1..]`) into related source
@@ -41555,7 +41568,7 @@ const runOxlint = async (options) => {
41555
41568
  };
41556
41569
  }
41557
41570
  };
41558
- if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
41571
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
41559
41572
  const rulesetHash = computeRulesetHash({
41560
41573
  config: buildConfig({
41561
41574
  extendsPaths: [],
@@ -41997,6 +42010,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
41997
42010
  });
41998
42011
  }));
41999
42012
  };
42013
+ const HOME_DIRECTORY = os.homedir();
42014
+ const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
42015
+ const scrubSensitivePaths = (text) => {
42016
+ let scrubbed = text;
42017
+ if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
42018
+ for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
42019
+ return scrubbed;
42020
+ };
42000
42021
  const ScoreApiResponseSchema = Struct({
42001
42022
  score: Number$1,
42002
42023
  label: String$1,
@@ -42011,7 +42032,10 @@ const ScoreApiResponseSchema = Struct({
42011
42032
  })))
42012
42033
  });
42013
42034
  const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
42014
- const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
42035
+ const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
42036
+ ...rest,
42037
+ filePath: redactSensitiveText(scrubSensitivePaths(filePath))
42038
+ }));
42015
42039
  const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
42016
42040
  const describeFailure = (error) => {
42017
42041
  if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
@@ -42024,7 +42048,7 @@ const calculateScore = async (diagnostics, options = {}) => {
42024
42048
  const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
42025
42049
  try {
42026
42050
  const compressedBody = gzipSync(JSON.stringify({
42027
- diagnostics: stripLocalFileFields(diagnostics),
42051
+ diagnostics: sanitizeScoreDiagnostics(diagnostics),
42028
42052
  ...options.metadata?.repo ? { repo: options.metadata.repo } : {},
42029
42053
  ...options.metadata?.sha ? { sha: options.metadata.sha } : {},
42030
42054
  ...options.metadata?.framework ? { framework: options.metadata.framework } : {},
@@ -44971,23 +44995,6 @@ const METRIC = {
44971
44995
  */
44972
44996
  const toCategoryKey = (category) => category.toLowerCase().replace(/[^a-z0-9]+/g, "_");
44973
44997
  //#endregion
44974
- //#region src/cli/utils/scrub-sensitive-text.ts
44975
- const HOME_DIRECTORY = os.homedir();
44976
- const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
44977
- /**
44978
- * Replaces the user's home directory (and generic `/Users|/home|C:\Users\<name>`
44979
- * roots) with `~` so absolute paths can't be tied back to an individual. Keeps
44980
- * the path's relative structure intact, which stays useful for debugging while
44981
- * dropping the personally-identifying prefix. Idempotent — re-running on an
44982
- * already-scrubbed `~/...` path is a no-op.
44983
- */
44984
- const scrubSensitivePaths = (text) => {
44985
- let scrubbed = text;
44986
- if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
44987
- for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
44988
- return scrubbed;
44989
- };
44990
- //#endregion
44991
44998
  //#region src/cli/utils/anonymize-text.ts
44992
44999
  /**
44993
45000
  * Free-text fields can carry both a home-directory path (the OS username) and a
@@ -45276,5 +45283,5 @@ const startLanguageServer = () => {
45276
45283
  };
45277
45284
  //#endregion
45278
45285
  export { startLanguageServer };
45279
- !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]="8227a9ff-6d2c-5cc4-99b6-7016d7554b99")}catch(e){}}();
45280
- //# debugId=8227a9ff-6d2c-5cc4-99b6-7016d7554b99
45286
+ !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]="3eb1e331-d4d9-517d-a23d-3170e3d3203f")}catch(e){}}();
45287
+ //# debugId=3eb1e331-d4d9-517d-a23d-3170e3d3203f
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.7.9-dev.9aa98b9",
3
+ "version": "0.7.9-dev.a16e452",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -66,7 +66,7 @@
66
66
  "vscode-uri": "^3.1.0",
67
67
  "yaml": "^2.9.0",
68
68
  "deslop-js": "0.7.9",
69
- "oxlint-plugin-react-doctor": "0.7.9-dev.9aa98b9"
69
+ "oxlint-plugin-react-doctor": "0.7.9-dev.a16e452"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/babel__code-frame": "^7.27.0",