react-doctor 0.7.9-dev.d8a20e0 → 0.7.9-dev.e5a5f73

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]="6f05eada-46fe-5b24-92d8-15fa92a38b00")}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";
@@ -36252,6 +36252,53 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
36252
36252
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
36253
36253
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
36254
36254
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
36255
+ const lastSourceMappingUrl = (fileContent) => {
36256
+ const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
36257
+ return lastReference ? lastReference[1] : null;
36258
+ };
36259
+ const mapTargetsSource = (mapContent, input) => {
36260
+ const parsedMap = JSON.parse(mapContent);
36261
+ if (typeof parsedMap !== "object" || parsedMap === null) return false;
36262
+ const { file, sources } = parsedMap;
36263
+ if (file !== input.expectedFile) return false;
36264
+ if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
36265
+ return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
36266
+ };
36267
+ const quartetProvesEmit = (stem, sourcePath, readFileText) => {
36268
+ try {
36269
+ const emitBaseName = Path.posix.basename(stem);
36270
+ const mapDirectory = Path.posix.dirname(stem);
36271
+ return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
36272
+ expectedFile: `${emitBaseName}.js`,
36273
+ mapDirectory,
36274
+ sourcePath
36275
+ }) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
36276
+ expectedFile: `${emitBaseName}.d.ts`,
36277
+ mapDirectory,
36278
+ sourcePath
36279
+ });
36280
+ } catch {
36281
+ return false;
36282
+ }
36283
+ };
36284
+ const collectTypeScriptEmitDuplicateJsPaths = (input) => {
36285
+ const untracked = new Set(input.untrackedPaths);
36286
+ const duplicateJsPaths = /* @__PURE__ */ new Set();
36287
+ for (const jsPath of untracked) {
36288
+ if (!jsPath.endsWith(".js")) continue;
36289
+ const stem = jsPath.slice(0, -3);
36290
+ if (![
36291
+ jsPath,
36292
+ `${stem}.js.map`,
36293
+ `${stem}.d.ts`,
36294
+ `${stem}.d.ts.map`
36295
+ ].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
36296
+ const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
36297
+ if (!sourcePath) continue;
36298
+ if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
36299
+ }
36300
+ return duplicateJsPaths;
36301
+ };
36255
36302
  const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
36256
36303
  const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
36257
36304
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
@@ -36319,20 +36366,29 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
36319
36366
  }
36320
36367
  return entries;
36321
36368
  };
36322
- const listSourceFilesViaGit = (rootDirectory) => {
36369
+ const gitLsFiles = (rootDirectory, flags) => {
36323
36370
  const result = spawnSync("git", [
36324
36371
  "ls-files",
36325
36372
  "-z",
36326
- "--cached",
36327
- "--others",
36328
- "--exclude-standard"
36373
+ ...flags
36329
36374
  ], {
36330
36375
  cwd: rootDirectory,
36331
36376
  encoding: "utf-8",
36332
36377
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
36333
36378
  });
36334
36379
  if (result.error || result.status !== 0) return null;
36335
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
36380
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
36381
+ };
36382
+ const listSourceFilesViaGit = (rootDirectory) => {
36383
+ const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
36384
+ const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
36385
+ if (trackedPaths === null || untrackedPaths === null) return null;
36386
+ const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
36387
+ trackedPaths: new Set(trackedPaths),
36388
+ untrackedPaths,
36389
+ readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
36390
+ });
36391
+ return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
36336
36392
  };
36337
36393
  const listSourceFilesViaFilesystem = (rootDirectory) => {
36338
36394
  const filePaths = [];
@@ -36532,11 +36588,8 @@ const frameworkMergeRank = (framework) => {
36532
36588
  if (framework === "unknown") return 3;
36533
36589
  return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
36534
36590
  };
36535
- const REACT_COMPILER_PACKAGES = new Set([
36536
- "babel-plugin-react-compiler",
36537
- "react-compiler-runtime",
36538
- "eslint-plugin-react-compiler"
36539
- ]);
36591
+ const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
36592
+ const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
36540
36593
  const NEXT_CONFIG_FILENAMES = [
36541
36594
  "next.config.js",
36542
36595
  "next.config.mjs",
@@ -36566,16 +36619,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
36566
36619
  "app.config.js",
36567
36620
  "app.config.ts"
36568
36621
  ];
36569
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|["']react-compiler["']/;
36622
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
36570
36623
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
36571
36624
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
36572
- const hasCompilerPackage = (packageJson) => {
36625
+ const hasCompilerPackage = (packageJson, compilerPackages) => {
36573
36626
  const allDependencies = {
36574
36627
  ...packageJson.peerDependencies,
36575
36628
  ...packageJson.dependencies,
36576
36629
  ...packageJson.devDependencies
36577
36630
  };
36578
- return Object.keys(allDependencies).some((packageName) => REACT_COMPILER_PACKAGES.has(packageName));
36631
+ return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
36632
+ };
36633
+ const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
36634
+ if (isProjectBoundary(directory)) return false;
36635
+ let ancestorDirectory = Path.dirname(directory);
36636
+ while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
36637
+ const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
36638
+ if (isFile(ancestorPackagePath)) {
36639
+ if (hasCompilerPackage(readPackageJson$1(ancestorPackagePath), compilerPackages)) return true;
36640
+ }
36641
+ if (isProjectBoundary(ancestorDirectory)) return false;
36642
+ ancestorDirectory = Path.dirname(ancestorDirectory);
36643
+ }
36644
+ return false;
36579
36645
  };
36580
36646
  const hasCompilerInConfigFile = (filePath) => {
36581
36647
  if (!isFile(filePath)) return false;
@@ -36584,23 +36650,14 @@ const hasCompilerInConfigFile = (filePath) => {
36584
36650
  };
36585
36651
  const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
36586
36652
  const detectReactCompiler = (directory, packageJson) => {
36587
- if (hasCompilerPackage(packageJson)) return true;
36653
+ if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
36588
36654
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
36589
36655
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
36590
36656
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
36591
36657
  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;
36658
+ return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
36603
36659
  };
36660
+ const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
36604
36661
  const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
36605
36662
  const filePath = Path.join(directory, filename);
36606
36663
  return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
@@ -37564,6 +37621,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
37564
37621
  framework: "unknown",
37565
37622
  hasTypeScript: hasOwnTsConfig,
37566
37623
  hasReactCompiler: false,
37624
+ hasReactCompilerLintPlugin: false,
37567
37625
  hasTanStackQuery: false,
37568
37626
  hasSsrDependency: false,
37569
37627
  preactVersion: null,
@@ -37684,6 +37742,7 @@ const discoverProject = (directory) => {
37684
37742
  framework,
37685
37743
  hasTypeScript,
37686
37744
  hasReactCompiler: detectReactCompiler(directory, packageJson),
37745
+ hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
37687
37746
  hasTanStackQuery: hasTanStackQuery(packageJson),
37688
37747
  hasSsrDependency: workspaceFacts.hasSsrDependency,
37689
37748
  preactVersion,
@@ -42963,7 +43022,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
42963
43022
  return enabled;
42964
43023
  };
42965
43024
  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);
43025
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
42967
43026
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
42968
43027
  const jsPlugins = [];
42969
43028
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -43926,6 +43985,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
43926
43985
  const TRAILING_PERIOD_PATTERN = /\.$/;
43927
43986
  const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
43928
43987
  const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
43988
+ const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
43989
+ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
43929
43990
  const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
43930
43991
  const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
43931
43992
  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 +44030,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
43969
44030
  const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
43970
44031
  const resolveDiagnosticTitle = (plugin, rule) => {
43971
44032
  if (plugin !== "react-hooks-js") return getRuleTitle(rule);
44033
+ if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
43972
44034
  return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
43973
44035
  };
43974
44036
  const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
@@ -43987,6 +44049,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
43987
44049
  };
43988
44050
  const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
43989
44051
  const reasonDetail = reasonDetailLines.join("\n").trim();
44052
+ if (rule === "error-boundaries") return {
44053
+ message: REACT_ERROR_BOUNDARY_MESSAGE,
44054
+ help: reasonDetail || help
44055
+ };
43990
44056
  return {
43991
44057
  message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
43992
44058
  help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
@@ -44008,7 +44074,10 @@ const parseRuleCode = (code) => {
44008
44074
  rule: match[2]
44009
44075
  };
44010
44076
  };
44011
- const resolveDiagnosticCategory = (plugin, rule) => getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
44077
+ const resolveDiagnosticCategory = (plugin, rule) => {
44078
+ if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
44079
+ return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
44080
+ };
44012
44081
  const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
44013
44082
  /**
44014
44083
  * Maps oxlint's non-primary labels (`labels[1..]`) into related source
@@ -44821,7 +44890,7 @@ const runOxlint = async (options) => {
44821
44890
  };
44822
44891
  }
44823
44892
  };
44824
- if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
44893
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
44825
44894
  const rulesetHash = computeRulesetHash({
44826
44895
  config: buildConfig({
44827
44896
  extendsPaths: [],
@@ -45263,6 +45332,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
45263
45332
  });
45264
45333
  }));
45265
45334
  };
45335
+ const HOME_DIRECTORY = os.homedir();
45336
+ const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
45337
+ const scrubSensitivePaths = (text) => {
45338
+ let scrubbed = text;
45339
+ if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
45340
+ for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
45341
+ return scrubbed;
45342
+ };
45266
45343
  const ScoreApiResponseSchema = Struct({
45267
45344
  score: Number$1,
45268
45345
  label: String$1,
@@ -45277,7 +45354,10 @@ const ScoreApiResponseSchema = Struct({
45277
45354
  })))
45278
45355
  });
45279
45356
  const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
45280
- const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
45357
+ const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
45358
+ ...rest,
45359
+ filePath: redactSensitiveText(scrubSensitivePaths(filePath))
45360
+ }));
45281
45361
  const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
45282
45362
  const describeFailure = (error) => {
45283
45363
  if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
@@ -45290,7 +45370,7 @@ const calculateScore = async (diagnostics, options = {}) => {
45290
45370
  const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
45291
45371
  try {
45292
45372
  const compressedBody = gzipSync(JSON.stringify({
45293
- diagnostics: stripLocalFileFields(diagnostics),
45373
+ diagnostics: sanitizeScoreDiagnostics(diagnostics),
45294
45374
  ...options.metadata?.repo ? { repo: options.metadata.repo } : {},
45295
45375
  ...options.metadata?.sha ? { sha: options.metadata.sha } : {},
45296
45376
  ...options.metadata?.framework ? { framework: options.metadata.framework } : {},
@@ -47135,7 +47215,7 @@ const makeNoopConsole = () => ({
47135
47215
  });
47136
47216
  //#endregion
47137
47217
  //#region src/cli/utils/version.ts
47138
- const VERSION = "0.7.9-dev.d8a20e0";
47218
+ const VERSION = "0.7.9-dev.e5a5f73";
47139
47219
  //#endregion
47140
47220
  //#region src/cli/utils/json-mode.ts
47141
47221
  let context = null;
@@ -47221,23 +47301,6 @@ const getRunId = () => {
47221
47301
  return cachedRunId;
47222
47302
  };
47223
47303
  //#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
47304
  //#region src/cli/utils/build-run-context.ts
47242
47305
  const ROOT_SUBCOMMANDS = new Set(["install", "setup"]);
47243
47306
  const detectInvokedVia = () => {
@@ -47504,13 +47567,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47504
47567
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47505
47568
  * standard `SENTRY_RELEASE` override.
47506
47569
  */
47507
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.d8a20e0`;
47570
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.9-dev.e5a5f73`;
47508
47571
  /**
47509
47572
  * Deployment environment shown in Sentry's environment filter. Defaults to
47510
47573
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47511
47574
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47512
47575
  */
47513
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.d8a20e0") ? "development" : "production");
47576
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.9-dev.e5a5f73") ? "development" : "production");
47514
47577
  /**
47515
47578
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47516
47579
  * (set to `0` to disable tracing) and falls back to
@@ -65788,4 +65851,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
65788
65851
  export {};
65789
65852
 
65790
65853
  //# sourceMappingURL=cli.js.map
65791
- //# debugId=a51e06c5-66da-5c06-be51-50358579743c
65854
+ //# debugId=6f05eada-46fe-5b24-92d8-15fa92a38b00
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]="28287c1c-b7b6-53b8-9e72-7d28d4f3ca45")}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";
@@ -33050,6 +33050,53 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
33050
33050
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
33051
33051
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
33052
33052
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
33053
+ const lastSourceMappingUrl = (fileContent) => {
33054
+ const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
33055
+ return lastReference ? lastReference[1] : null;
33056
+ };
33057
+ const mapTargetsSource = (mapContent, input) => {
33058
+ const parsedMap = JSON.parse(mapContent);
33059
+ if (typeof parsedMap !== "object" || parsedMap === null) return false;
33060
+ const { file, sources } = parsedMap;
33061
+ if (file !== input.expectedFile) return false;
33062
+ if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
33063
+ return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
33064
+ };
33065
+ const quartetProvesEmit = (stem, sourcePath, readFileText) => {
33066
+ try {
33067
+ const emitBaseName = Path.posix.basename(stem);
33068
+ const mapDirectory = Path.posix.dirname(stem);
33069
+ return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
33070
+ expectedFile: `${emitBaseName}.js`,
33071
+ mapDirectory,
33072
+ sourcePath
33073
+ }) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
33074
+ expectedFile: `${emitBaseName}.d.ts`,
33075
+ mapDirectory,
33076
+ sourcePath
33077
+ });
33078
+ } catch {
33079
+ return false;
33080
+ }
33081
+ };
33082
+ const collectTypeScriptEmitDuplicateJsPaths = (input) => {
33083
+ const untracked = new Set(input.untrackedPaths);
33084
+ const duplicateJsPaths = /* @__PURE__ */ new Set();
33085
+ for (const jsPath of untracked) {
33086
+ if (!jsPath.endsWith(".js")) continue;
33087
+ const stem = jsPath.slice(0, -3);
33088
+ if (![
33089
+ jsPath,
33090
+ `${stem}.js.map`,
33091
+ `${stem}.d.ts`,
33092
+ `${stem}.d.ts.map`
33093
+ ].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
33094
+ const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
33095
+ if (!sourcePath) continue;
33096
+ if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
33097
+ }
33098
+ return duplicateJsPaths;
33099
+ };
33053
33100
  const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
33054
33101
  const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
33055
33102
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
@@ -33120,20 +33167,29 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
33120
33167
  }
33121
33168
  return entries;
33122
33169
  };
33123
- const listSourceFilesViaGit = (rootDirectory) => {
33170
+ const gitLsFiles = (rootDirectory, flags) => {
33124
33171
  const result = spawnSync("git", [
33125
33172
  "ls-files",
33126
33173
  "-z",
33127
- "--cached",
33128
- "--others",
33129
- "--exclude-standard"
33174
+ ...flags
33130
33175
  ], {
33131
33176
  cwd: rootDirectory,
33132
33177
  encoding: "utf-8",
33133
33178
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
33134
33179
  });
33135
33180
  if (result.error || result.status !== 0) return null;
33136
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
33181
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
33182
+ };
33183
+ const listSourceFilesViaGit = (rootDirectory) => {
33184
+ const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
33185
+ const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
33186
+ if (trackedPaths === null || untrackedPaths === null) return null;
33187
+ const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
33188
+ trackedPaths: new Set(trackedPaths),
33189
+ untrackedPaths,
33190
+ readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
33191
+ });
33192
+ return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
33137
33193
  };
33138
33194
  const listSourceFilesViaFilesystem = (rootDirectory) => {
33139
33195
  const filePaths = [];
@@ -33336,11 +33392,8 @@ const frameworkMergeRank = (framework) => {
33336
33392
  if (framework === "unknown") return 3;
33337
33393
  return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
33338
33394
  };
33339
- const REACT_COMPILER_PACKAGES = new Set([
33340
- "babel-plugin-react-compiler",
33341
- "react-compiler-runtime",
33342
- "eslint-plugin-react-compiler"
33343
- ]);
33395
+ const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
33396
+ const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
33344
33397
  const NEXT_CONFIG_FILENAMES = [
33345
33398
  "next.config.js",
33346
33399
  "next.config.mjs",
@@ -33370,16 +33423,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
33370
33423
  "app.config.js",
33371
33424
  "app.config.ts"
33372
33425
  ];
33373
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|["']react-compiler["']/;
33426
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
33374
33427
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
33375
33428
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
33376
- const hasCompilerPackage = (packageJson) => {
33429
+ const hasCompilerPackage = (packageJson, compilerPackages) => {
33377
33430
  const allDependencies = {
33378
33431
  ...packageJson.peerDependencies,
33379
33432
  ...packageJson.dependencies,
33380
33433
  ...packageJson.devDependencies
33381
33434
  };
33382
- return Object.keys(allDependencies).some((packageName) => REACT_COMPILER_PACKAGES.has(packageName));
33435
+ return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
33436
+ };
33437
+ const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
33438
+ if (isProjectBoundary(directory)) return false;
33439
+ let ancestorDirectory = Path.dirname(directory);
33440
+ while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
33441
+ const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
33442
+ if (isFile(ancestorPackagePath)) {
33443
+ if (hasCompilerPackage(readPackageJson(ancestorPackagePath), compilerPackages)) return true;
33444
+ }
33445
+ if (isProjectBoundary(ancestorDirectory)) return false;
33446
+ ancestorDirectory = Path.dirname(ancestorDirectory);
33447
+ }
33448
+ return false;
33383
33449
  };
33384
33450
  const hasCompilerInConfigFile = (filePath) => {
33385
33451
  if (!isFile(filePath)) return false;
@@ -33388,23 +33454,14 @@ const hasCompilerInConfigFile = (filePath) => {
33388
33454
  };
33389
33455
  const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
33390
33456
  const detectReactCompiler = (directory, packageJson) => {
33391
- if (hasCompilerPackage(packageJson)) return true;
33457
+ if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
33392
33458
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
33393
33459
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
33394
33460
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
33395
33461
  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;
33462
+ return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
33407
33463
  };
33464
+ const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
33408
33465
  const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
33409
33466
  const filePath = Path.join(directory, filename);
33410
33467
  return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
@@ -34371,6 +34428,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
34371
34428
  framework: "unknown",
34372
34429
  hasTypeScript: hasOwnTsConfig,
34373
34430
  hasReactCompiler: false,
34431
+ hasReactCompilerLintPlugin: false,
34374
34432
  hasTanStackQuery: false,
34375
34433
  hasSsrDependency: false,
34376
34434
  preactVersion: null,
@@ -34491,6 +34549,7 @@ const discoverProject = (directory) => {
34491
34549
  framework,
34492
34550
  hasTypeScript,
34493
34551
  hasReactCompiler: detectReactCompiler(directory, packageJson),
34552
+ hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
34494
34553
  hasTanStackQuery: hasTanStackQuery(packageJson),
34495
34554
  hasSsrDependency: workspaceFacts.hasSsrDependency,
34496
34555
  preactVersion,
@@ -39719,7 +39778,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
39719
39778
  return enabled;
39720
39779
  };
39721
39780
  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);
39781
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
39723
39782
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
39724
39783
  const jsPlugins = [];
39725
39784
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -40682,6 +40741,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
40682
40741
  const TRAILING_PERIOD_PATTERN = /\.$/;
40683
40742
  const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
40684
40743
  const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
40744
+ const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
40745
+ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
40685
40746
  const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
40686
40747
  const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
40687
40748
  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 +40786,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
40725
40786
  const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
40726
40787
  const resolveDiagnosticTitle = (plugin, rule) => {
40727
40788
  if (plugin !== "react-hooks-js") return getRuleTitle(rule);
40789
+ if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
40728
40790
  return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
40729
40791
  };
40730
40792
  const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
@@ -40743,6 +40805,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
40743
40805
  };
40744
40806
  const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
40745
40807
  const reasonDetail = reasonDetailLines.join("\n").trim();
40808
+ if (rule === "error-boundaries") return {
40809
+ message: REACT_ERROR_BOUNDARY_MESSAGE,
40810
+ help: reasonDetail || help
40811
+ };
40746
40812
  return {
40747
40813
  message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
40748
40814
  help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
@@ -40764,7 +40830,10 @@ const parseRuleCode = (code) => {
40764
40830
  rule: match[2]
40765
40831
  };
40766
40832
  };
40767
- const resolveDiagnosticCategory = (plugin, rule) => getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
40833
+ const resolveDiagnosticCategory = (plugin, rule) => {
40834
+ if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
40835
+ return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
40836
+ };
40768
40837
  const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
40769
40838
  /**
40770
40839
  * Maps oxlint's non-primary labels (`labels[1..]`) into related source
@@ -41577,7 +41646,7 @@ const runOxlint = async (options) => {
41577
41646
  };
41578
41647
  }
41579
41648
  };
41580
- if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
41649
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
41581
41650
  const rulesetHash = computeRulesetHash({
41582
41651
  config: buildConfig({
41583
41652
  extendsPaths: [],
@@ -42019,6 +42088,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
42019
42088
  });
42020
42089
  }));
42021
42090
  };
42091
+ const HOME_DIRECTORY = os.homedir();
42092
+ const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
42093
+ const scrubSensitivePaths = (text) => {
42094
+ let scrubbed = text;
42095
+ if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
42096
+ for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
42097
+ return scrubbed;
42098
+ };
42022
42099
  const ScoreApiResponseSchema = Struct({
42023
42100
  score: Number$1,
42024
42101
  label: String$1,
@@ -42033,7 +42110,10 @@ const ScoreApiResponseSchema = Struct({
42033
42110
  })))
42034
42111
  });
42035
42112
  const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
42036
- const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
42113
+ const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
42114
+ ...rest,
42115
+ filePath: redactSensitiveText(scrubSensitivePaths(filePath))
42116
+ }));
42037
42117
  const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
42038
42118
  const describeFailure = (error) => {
42039
42119
  if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
@@ -42046,7 +42126,7 @@ const calculateScore = async (diagnostics, options = {}) => {
42046
42126
  const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
42047
42127
  try {
42048
42128
  const compressedBody = gzipSync(JSON.stringify({
42049
- diagnostics: stripLocalFileFields(diagnostics),
42129
+ diagnostics: sanitizeScoreDiagnostics(diagnostics),
42050
42130
  ...options.metadata?.repo ? { repo: options.metadata.repo } : {},
42051
42131
  ...options.metadata?.sha ? { sha: options.metadata.sha } : {},
42052
42132
  ...options.metadata?.framework ? { framework: options.metadata.framework } : {},
@@ -43639,4 +43719,4 @@ const toJsonReport = (result, options) => buildJsonReport({
43639
43719
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
43640
43720
 
43641
43721
  //# sourceMappingURL=index.js.map
43642
- //# debugId=b173f528-892d-5c34-b63a-37cb26d03f0f
43722
+ //# debugId=28287c1c-b7b6-53b8-9e72-7d28d4f3ca45
package/dist/lsp.js CHANGED
@@ -33102,6 +33102,53 @@ const SUPPLY_CHAIN_OVERLAP_TIMEOUT_MS = 9e4;
33102
33102
  const SUPPLY_CHAIN_CACHE_TTL_MS = 864e5;
33103
33103
  const SUPPLY_CHAIN_CACHE_SUBDIR = "supply-chain";
33104
33104
  const SUPPLY_CHAIN_IGNORED_PACKAGES = new Set(["next"]);
33105
+ const lastSourceMappingUrl = (fileContent) => {
33106
+ const lastReference = [...fileContent.matchAll(/\/\/# sourceMappingURL=(\S+)/g)].at(-1);
33107
+ return lastReference ? lastReference[1] : null;
33108
+ };
33109
+ const mapTargetsSource = (mapContent, input) => {
33110
+ const parsedMap = JSON.parse(mapContent);
33111
+ if (typeof parsedMap !== "object" || parsedMap === null) return false;
33112
+ const { file, sources } = parsedMap;
33113
+ if (file !== input.expectedFile) return false;
33114
+ if (!Array.isArray(sources) || sources.length !== 1 || typeof sources[0] !== "string") return false;
33115
+ return Path.posix.normalize(Path.posix.join(input.mapDirectory, sources[0])) === input.sourcePath;
33116
+ };
33117
+ const quartetProvesEmit = (stem, sourcePath, readFileText) => {
33118
+ try {
33119
+ const emitBaseName = Path.posix.basename(stem);
33120
+ const mapDirectory = Path.posix.dirname(stem);
33121
+ return lastSourceMappingUrl(readFileText(`${stem}.js`)) === `${emitBaseName}.js.map` && lastSourceMappingUrl(readFileText(`${stem}.d.ts`)) === `${emitBaseName}.d.ts.map` && mapTargetsSource(readFileText(`${stem}.js.map`), {
33122
+ expectedFile: `${emitBaseName}.js`,
33123
+ mapDirectory,
33124
+ sourcePath
33125
+ }) && mapTargetsSource(readFileText(`${stem}.d.ts.map`), {
33126
+ expectedFile: `${emitBaseName}.d.ts`,
33127
+ mapDirectory,
33128
+ sourcePath
33129
+ });
33130
+ } catch {
33131
+ return false;
33132
+ }
33133
+ };
33134
+ const collectTypeScriptEmitDuplicateJsPaths = (input) => {
33135
+ const untracked = new Set(input.untrackedPaths);
33136
+ const duplicateJsPaths = /* @__PURE__ */ new Set();
33137
+ for (const jsPath of untracked) {
33138
+ if (!jsPath.endsWith(".js")) continue;
33139
+ const stem = jsPath.slice(0, -3);
33140
+ if (![
33141
+ jsPath,
33142
+ `${stem}.js.map`,
33143
+ `${stem}.d.ts`,
33144
+ `${stem}.d.ts.map`
33145
+ ].every((emitPath) => untracked.has(emitPath) && !input.trackedPaths.has(emitPath))) continue;
33146
+ const sourcePath = [`${stem}.ts`, `${stem}.tsx`].find((candidatePath) => input.trackedPaths.has(candidatePath));
33147
+ if (!sourcePath) continue;
33148
+ if (quartetProvesEmit(stem, sourcePath, input.readFileText)) duplicateJsPaths.add(jsPath);
33149
+ }
33150
+ return duplicateJsPaths;
33151
+ };
33105
33152
  const isIgnoredDirectoryName = (directoryName) => IGNORED_DIRECTORIES.has(directoryName) || directoryName.startsWith(".") && !SCANNED_DOT_DIRECTORIES.has(directoryName);
33106
33153
  const hasIgnoredPathSegment = (relativePath) => relativePath.split(/[/\\]/).slice(0, -1).some((segment) => isIgnoredDirectoryName(segment));
33107
33154
  const isLintableSourceFile = (filePath) => SOURCE_FILE_PATTERN.test(filePath) && !GENERATED_BUNDLE_FILE_PATTERN.test(filePath) && !GENERATED_SOURCE_DIRECTORY_PATTERN.test(filePath);
@@ -33172,20 +33219,29 @@ const collectSizedSourceFiles = (rootDirectory, relativePaths) => {
33172
33219
  }
33173
33220
  return entries;
33174
33221
  };
33175
- const listSourceFilesViaGit = (rootDirectory) => {
33222
+ const gitLsFiles = (rootDirectory, flags) => {
33176
33223
  const result = spawnSync("git", [
33177
33224
  "ls-files",
33178
33225
  "-z",
33179
- "--cached",
33180
- "--others",
33181
- "--exclude-standard"
33226
+ ...flags
33182
33227
  ], {
33183
33228
  cwd: rootDirectory,
33184
33229
  encoding: "utf-8",
33185
33230
  maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES
33186
33231
  });
33187
33232
  if (result.error || result.status !== 0) return null;
33188
- return result.stdout.split("\0").filter((filePath) => filePath.length > 0 && isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath));
33233
+ return result.stdout.split("\0").filter((filePath) => filePath.length > 0);
33234
+ };
33235
+ const listSourceFilesViaGit = (rootDirectory) => {
33236
+ const trackedPaths = gitLsFiles(rootDirectory, ["--cached"]);
33237
+ const untrackedPaths = gitLsFiles(rootDirectory, ["--others", "--exclude-standard"]);
33238
+ if (trackedPaths === null || untrackedPaths === null) return null;
33239
+ const emitDuplicateJsPaths = collectTypeScriptEmitDuplicateJsPaths({
33240
+ trackedPaths: new Set(trackedPaths),
33241
+ untrackedPaths,
33242
+ readFileText: (relativePath) => NFS.readFileSync(Path.resolve(rootDirectory, relativePath), "utf-8")
33243
+ });
33244
+ return [...trackedPaths, ...untrackedPaths].filter((filePath) => isLintableSourceFile(filePath) && !hasIgnoredPathSegment(filePath) && !emitDuplicateJsPaths.has(filePath));
33189
33245
  };
33190
33246
  const listSourceFilesViaFilesystem = (rootDirectory) => {
33191
33247
  const filePaths = [];
@@ -33388,11 +33444,8 @@ const frameworkMergeRank = (framework) => {
33388
33444
  if (framework === "unknown") return 3;
33389
33445
  return MOBILE_FRAMEWORKS.has(framework) ? 2 : 1;
33390
33446
  };
33391
- const REACT_COMPILER_PACKAGES = new Set([
33392
- "babel-plugin-react-compiler",
33393
- "react-compiler-runtime",
33394
- "eslint-plugin-react-compiler"
33395
- ]);
33447
+ const REACT_COMPILER_TRANSFORM_PACKAGES = new Set(["babel-plugin-react-compiler", "react-compiler-runtime"]);
33448
+ const REACT_COMPILER_LINT_PACKAGES = new Set(["eslint-plugin-react-compiler"]);
33396
33449
  const NEXT_CONFIG_FILENAMES = [
33397
33450
  "next.config.js",
33398
33451
  "next.config.mjs",
@@ -33422,16 +33475,29 @@ const EXPO_APP_CONFIG_FILENAMES = [
33422
33475
  "app.config.js",
33423
33476
  "app.config.ts"
33424
33477
  ];
33425
- const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|["']react-compiler["']/;
33478
+ const REACT_COMPILER_PACKAGE_REFERENCE_PATTERN = /babel-plugin-react-compiler|react-compiler-runtime|["']react-compiler["']/;
33426
33479
  const REACT_COMPILER_ENABLED_FLAG_PATTERN = /["']?reactCompiler["']?\s*:\s*(?:true\b|\{)/;
33427
33480
  const STATIC_EXPORT_OUTPUT_PATTERN = /(?:^|[^.\w])["']?output["']?\s*:\s*["']export["']/m;
33428
- const hasCompilerPackage = (packageJson) => {
33481
+ const hasCompilerPackage = (packageJson, compilerPackages) => {
33429
33482
  const allDependencies = {
33430
33483
  ...packageJson.peerDependencies,
33431
33484
  ...packageJson.dependencies,
33432
33485
  ...packageJson.devDependencies
33433
33486
  };
33434
- return Object.keys(allDependencies).some((packageName) => REACT_COMPILER_PACKAGES.has(packageName));
33487
+ return Object.keys(allDependencies).some((packageName) => compilerPackages.has(packageName));
33488
+ };
33489
+ const hasCompilerPackageInAncestors = (directory, compilerPackages) => {
33490
+ if (isProjectBoundary(directory)) return false;
33491
+ let ancestorDirectory = Path.dirname(directory);
33492
+ while (ancestorDirectory !== Path.dirname(ancestorDirectory)) {
33493
+ const ancestorPackagePath = Path.join(ancestorDirectory, "package.json");
33494
+ if (isFile(ancestorPackagePath)) {
33495
+ if (hasCompilerPackage(readPackageJson(ancestorPackagePath), compilerPackages)) return true;
33496
+ }
33497
+ if (isProjectBoundary(ancestorDirectory)) return false;
33498
+ ancestorDirectory = Path.dirname(ancestorDirectory);
33499
+ }
33500
+ return false;
33435
33501
  };
33436
33502
  const hasCompilerInConfigFile = (filePath) => {
33437
33503
  if (!isFile(filePath)) return false;
@@ -33440,23 +33506,14 @@ const hasCompilerInConfigFile = (filePath) => {
33440
33506
  };
33441
33507
  const hasCompilerInConfigFiles = (directory, filenames) => filenames.some((filename) => hasCompilerInConfigFile(Path.join(directory, filename)));
33442
33508
  const detectReactCompiler = (directory, packageJson) => {
33443
- if (hasCompilerPackage(packageJson)) return true;
33509
+ if (hasCompilerPackage(packageJson, REACT_COMPILER_TRANSFORM_PACKAGES)) return true;
33444
33510
  if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;
33445
33511
  if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;
33446
33512
  if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;
33447
33513
  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;
33514
+ return hasCompilerPackageInAncestors(directory, REACT_COMPILER_TRANSFORM_PACKAGES);
33459
33515
  };
33516
+ const detectReactCompilerLintPlugin = (directory, packageJson) => hasCompilerPackage(packageJson, REACT_COMPILER_LINT_PACKAGES) || hasCompilerPackageInAncestors(directory, REACT_COMPILER_LINT_PACKAGES);
33460
33517
  const detectNextjsStaticExport = (directory) => NEXT_CONFIG_FILENAMES.some((filename) => {
33461
33518
  const filePath = Path.join(directory, filename);
33462
33519
  return isFile(filePath) && STATIC_EXPORT_OUTPUT_PATTERN.test(NFS.readFileSync(filePath, "utf-8"));
@@ -34423,6 +34480,7 @@ const discoverProjectWithoutPackageJson = (directory) => {
34423
34480
  framework: "unknown",
34424
34481
  hasTypeScript: hasOwnTsConfig,
34425
34482
  hasReactCompiler: false,
34483
+ hasReactCompilerLintPlugin: false,
34426
34484
  hasTanStackQuery: false,
34427
34485
  hasSsrDependency: false,
34428
34486
  preactVersion: null,
@@ -34543,6 +34601,7 @@ const discoverProject = (directory) => {
34543
34601
  framework,
34544
34602
  hasTypeScript,
34545
34603
  hasReactCompiler: detectReactCompiler(directory, packageJson),
34604
+ hasReactCompilerLintPlugin: detectReactCompilerLintPlugin(directory, packageJson),
34546
34605
  hasTanStackQuery: hasTanStackQuery(packageJson),
34547
34606
  hasSsrDependency: workspaceFacts.hasSsrDependency,
34548
34607
  preactVersion,
@@ -39697,7 +39756,7 @@ const buildUserPluginRules = (userPlugin, severityControls) => {
39697
39756
  return enabled;
39698
39757
  };
39699
39758
  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);
39759
+ const reactHooksJsPlugin = disableReactHooksJsPlugin || ruleSelection === "sidecar" ? null : resolveReactHooksJsPlugin(project.hasReactCompiler || project.hasReactCompilerLintPlugin === true, customRulesOnly);
39701
39760
  const reactCompilerRules = reactHooksJsPlugin ? applyRuleSeverityControls(filterRulesToAvailable(REACT_COMPILER_RULES, "react-hooks-js", reactHooksJsPlugin.availableRuleNames), severityControls) : {};
39702
39761
  const jsPlugins = [];
39703
39762
  if (reactHooksJsPlugin) jsPlugins.push(reactHooksJsPlugin.entry);
@@ -40660,6 +40719,8 @@ const LEADING_SEVERITY_LABEL_PATTERN = /^(?:Error|Warning):\s*/;
40660
40719
  const TRAILING_PERIOD_PATTERN = /\.$/;
40661
40720
  const REACT_COMPILER_TITLE = "React Compiler can't optimize this";
40662
40721
  const REACT_COMPILER_TODO_TITLE = "React Compiler doesn't support this syntax";
40722
+ const REACT_ERROR_BOUNDARY_TITLE = "JSX render errors need an Error Boundary";
40723
+ const REACT_ERROR_BOUNDARY_MESSAGE = "This try/catch cannot catch errors thrown while the JSX child renders. Use an Error Boundary instead.";
40663
40724
  const REACT_COMPILER_IMPACT = "This component misses React Compiler's automatic memoization & re-renders more than it should";
40664
40725
  const REACT_COMPILER_ACTION = "Rewrite the flagged code so the compiler can optimize it.";
40665
40726
  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 +40764,7 @@ const getRuleCategory = (ruleName) => reactDoctorPlugin.rules[ruleName]?.categor
40703
40764
  const getRuleTitle = (ruleName) => reactDoctorPlugin.rules[ruleName]?.title;
40704
40765
  const resolveDiagnosticTitle = (plugin, rule) => {
40705
40766
  if (plugin !== "react-hooks-js") return getRuleTitle(rule);
40767
+ if (rule === "error-boundaries") return REACT_ERROR_BOUNDARY_TITLE;
40706
40768
  return rule === "todo" ? REACT_COMPILER_TODO_TITLE : REACT_COMPILER_TITLE;
40707
40769
  };
40708
40770
  const cleanDiagnosticMessage = (message, help, plugin, rule, project) => {
@@ -40721,6 +40783,10 @@ const resolveCleanedDiagnostic = (message, help, plugin, rule, project) => {
40721
40783
  };
40722
40784
  const [reasonSummary = "", ...reasonDetailLines] = bailoutReason.split("\n");
40723
40785
  const reasonDetail = reasonDetailLines.join("\n").trim();
40786
+ if (rule === "error-boundaries") return {
40787
+ message: REACT_ERROR_BOUNDARY_MESSAGE,
40788
+ help: reasonDetail || help
40789
+ };
40724
40790
  return {
40725
40791
  message: buildReactCompilerMessage(reasonSummary.trim(), rule === "incompatible-library" ? REACT_COMPILER_INCOMPATIBLE_LIBRARY_ACTION : REACT_COMPILER_ACTION),
40726
40792
  help: appendReanimatedSharedValueHint(reasonDetail || help, rule, project)
@@ -40742,7 +40808,10 @@ const parseRuleCode = (code) => {
40742
40808
  rule: match[2]
40743
40809
  };
40744
40810
  };
40745
- const resolveDiagnosticCategory = (plugin, rule) => getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
40811
+ const resolveDiagnosticCategory = (plugin, rule) => {
40812
+ if (plugin === "react-hooks-js" && rule === "error-boundaries") return "Bugs";
40813
+ return getRuleCategory(rule) ?? lookupOwnString(PLUGIN_CATEGORY_MAP, plugin) ?? "Bugs";
40814
+ };
40746
40815
  const resolveMatchByOccurrence = (rule, category) => OCCURRENCE_MATCHED_CATEGORIES.has(category) || Boolean(reactDoctorPlugin.rules[rule]?.matchByOccurrence);
40747
40816
  /**
40748
40817
  * Maps oxlint's non-primary labels (`labels[1..]`) into related source
@@ -41555,7 +41624,7 @@ const runOxlint = async (options) => {
41555
41624
  };
41556
41625
  }
41557
41626
  };
41558
- if (perFileLintCacheEnabled && !project.hasReactCompiler && extendsPaths.length === 0 && userPlugins.length === 0) {
41627
+ if (perFileLintCacheEnabled && !project.hasReactCompiler && project.hasReactCompilerLintPlugin !== true && extendsPaths.length === 0 && userPlugins.length === 0) {
41559
41628
  const rulesetHash = computeRulesetHash({
41560
41629
  config: buildConfig({
41561
41630
  extendsPaths: [],
@@ -41997,6 +42066,14 @@ var Reporter = class Reporter extends Service()("react-doctor/Reporter") {
41997
42066
  });
41998
42067
  }));
41999
42068
  };
42069
+ const HOME_DIRECTORY = os.homedir();
42070
+ const USER_HOME_PATTERNS = [/[A-Za-z]:[\\/]Users[\\/][^\\/]+/gi, /(?:\/Users\/|\/home\/)[^/\\]+/gi];
42071
+ const scrubSensitivePaths = (text) => {
42072
+ let scrubbed = text;
42073
+ if (HOME_DIRECTORY.length > 1) scrubbed = scrubbed.split(HOME_DIRECTORY).join("~");
42074
+ for (const pattern of USER_HOME_PATTERNS) scrubbed = scrubbed.replace(pattern, "~");
42075
+ return scrubbed;
42076
+ };
42000
42077
  const ScoreApiResponseSchema = Struct({
42001
42078
  score: Number$1,
42002
42079
  label: String$1,
@@ -42011,7 +42088,10 @@ const ScoreApiResponseSchema = Struct({
42011
42088
  })))
42012
42089
  });
42013
42090
  const parseScoreResult = (value) => getOrNull(decodeUnknownOption(ScoreApiResponseSchema)(value));
42014
- const stripLocalFileFields = (diagnostics) => diagnostics.map(({ filePath: _filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => rest);
42091
+ const sanitizeScoreDiagnostics = (diagnostics) => diagnostics.map(({ filePath, fileContext: _fileContext, fixGroupId: _fixGroupId, ...rest }) => ({
42092
+ ...rest,
42093
+ filePath: redactSensitiveText(scrubSensitivePaths(filePath))
42094
+ }));
42015
42095
  const isAbortError = (error) => error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
42016
42096
  const describeFailure = (error) => {
42017
42097
  if (isAbortError(error)) return `timed out after ${FETCH_TIMEOUT_MS / 1e3}s`;
@@ -42024,7 +42104,7 @@ const calculateScore = async (diagnostics, options = {}) => {
42024
42104
  const requestUrl = options.isCi ? `${SCORE_API_URL}?ci=1` : SCORE_API_URL;
42025
42105
  try {
42026
42106
  const compressedBody = gzipSync(JSON.stringify({
42027
- diagnostics: stripLocalFileFields(diagnostics),
42107
+ diagnostics: sanitizeScoreDiagnostics(diagnostics),
42028
42108
  ...options.metadata?.repo ? { repo: options.metadata.repo } : {},
42029
42109
  ...options.metadata?.sha ? { sha: options.metadata.sha } : {},
42030
42110
  ...options.metadata?.framework ? { framework: options.metadata.framework } : {},
@@ -44971,23 +45051,6 @@ const METRIC = {
44971
45051
  */
44972
45052
  const toCategoryKey = (category) => category.toLowerCase().replace(/[^a-z0-9]+/g, "_");
44973
45053
  //#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
45054
  //#region src/cli/utils/anonymize-text.ts
44992
45055
  /**
44993
45056
  * Free-text fields can carry both a home-directory path (the OS username) and a
@@ -45276,5 +45339,5 @@ const startLanguageServer = () => {
45276
45339
  };
45277
45340
  //#endregion
45278
45341
  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
45342
+ !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]="6c89dec9-5fbe-5a2e-b1fe-6b3954e0e85b")}catch(e){}}();
45343
+ //# debugId=6c89dec9-5fbe-5a2e-b1fe-6b3954e0e85b
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.7.9-dev.d8a20e0",
3
+ "version": "0.7.9-dev.e5a5f73",
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.d8a20e0"
69
+ "oxlint-plugin-react-doctor": "0.7.9-dev.e5a5f73"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/babel__code-frame": "^7.27.0",