react-doctor 0.5.6-dev.93b796d → 0.5.6-dev.a9d2713

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/lsp.js CHANGED
@@ -14,7 +14,7 @@ import * as NodeUrl from "node:url";
14
14
  import { fileURLToPath } from "node:url";
15
15
  import { createJiti } from "jiti";
16
16
  import * as Crypto from "node:crypto";
17
- import crypto from "node:crypto";
17
+ import crypto, { createHash } from "node:crypto";
18
18
  import { gzipSync } from "node:zlib";
19
19
  import { CodeActionKind, CodeActionTriggerKind, DidChangeWatchedFilesNotification, DocumentDiagnosticReportKind, FileChangeType, TextDocumentSyncKind, TextDocuments, createConnection } from "vscode-languageserver/node.js";
20
20
  import { TextDocument } from "vscode-languageserver-textdocument";
@@ -19286,7 +19286,8 @@ var Diagnostic = class extends Class("Diagnostic")({
19286
19286
  category: String$1,
19287
19287
  fileContext: optional(Literals(["test", "story"])),
19288
19288
  suppressionHint: optional(String$1),
19289
- relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation))
19289
+ relatedLocations: optional(ArraySchema(DiagnosticRelatedLocation)),
19290
+ fixGroupId: optional(String$1)
19290
19291
  }) {};
19291
19292
  /**
19292
19293
  * Deterministic identity string for a diagnostic. Same diagnostic
@@ -19335,6 +19336,7 @@ var JsonReportProjectEntry = class extends Class("JsonReportProjectEntry")({
19335
19336
  score: Unknown,
19336
19337
  skippedChecks: ArraySchema(String$1),
19337
19338
  skippedCheckReasons: optional(Record$1(String$1, String$1)),
19339
+ scannedFileCount: optional(Number$1),
19338
19340
  elapsedMilliseconds: Number$1
19339
19341
  }) {};
19340
19342
  /**
@@ -32761,6 +32763,7 @@ const isLargeMinifiedFile = (absolutePath) => {
32761
32763
  if (sizeBytes < 2e4) return false;
32762
32764
  return isMinifiedSource(absolutePath);
32763
32765
  };
32766
+ const isErrnoException = (error) => error instanceof Error && "code" in error;
32764
32767
  const IGNORABLE_READDIR_ERROR_CODES = new Set([
32765
32768
  "EACCES",
32766
32769
  "EPERM",
@@ -32770,11 +32773,7 @@ const IGNORABLE_READDIR_ERROR_CODES = new Set([
32770
32773
  "ELOOP",
32771
32774
  "ENAMETOOLONG"
32772
32775
  ]);
32773
- const isIgnorableReaddirError = (error) => {
32774
- if (typeof error !== "object" || error === null) return false;
32775
- const errorCode = error.code;
32776
- return typeof errorCode === "string" && IGNORABLE_READDIR_ERROR_CODES.has(errorCode);
32777
- };
32776
+ const isIgnorableReaddirError = (error) => isErrnoException(error) && typeof error.code === "string" && IGNORABLE_READDIR_ERROR_CODES.has(error.code);
32778
32777
  const readDirectoryEntries = (directoryPath) => {
32779
32778
  try {
32780
32779
  return NFS.readdirSync(directoryPath, { withFileTypes: true });
@@ -32824,7 +32823,7 @@ const readPackageJsonUncached = (packageJsonPath) => {
32824
32823
  return JSON.parse(NFS.readFileSync(packageJsonPath, "utf-8"));
32825
32824
  } catch (error) {
32826
32825
  if (error instanceof SyntaxError) return {};
32827
- if (error instanceof Error && "code" in error) {
32826
+ if (isErrnoException(error)) {
32828
32827
  const { code } = error;
32829
32828
  if (code === "EISDIR" || code === "EACCES" || code === "EPERM" || code === "ENOENT") return {};
32830
32829
  }
@@ -33549,17 +33548,13 @@ const isPackageJsonReactNativeAware = (packageJson) => {
33549
33548
  return false;
33550
33549
  };
33551
33550
  const hasReactNativeWorkspaceAnywhere = (rootDirectory, rootPackageJson) => someWorkspacePackageJson(rootDirectory, rootPackageJson, isPackageJsonReactNativeAware);
33552
- const getExpoDependencySpec = (packageJson) => {
33553
- const spec = packageJson.dependencies?.expo ?? packageJson.devDependencies?.expo ?? packageJson.peerDependencies?.expo ?? packageJson.optionalDependencies?.expo;
33551
+ const getDependencySpec = (packageJson, packageName) => {
33552
+ const spec = packageJson.dependencies?.[packageName] ?? packageJson.devDependencies?.[packageName] ?? packageJson.peerDependencies?.[packageName] ?? packageJson.optionalDependencies?.[packageName];
33554
33553
  return typeof spec === "string" ? spec : null;
33555
33554
  };
33556
- const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, getExpoDependencySpec);
33555
+ const findExpoVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "expo"));
33557
33556
  const SHOPIFY_FLASH_LIST_PACKAGE_NAME = "@shopify/flash-list";
33558
- const getShopifyFlashListDependencySpec = (packageJson) => {
33559
- const spec = packageJson.dependencies?.["@shopify/flash-list"] ?? packageJson.devDependencies?.["@shopify/flash-list"] ?? packageJson.peerDependencies?.["@shopify/flash-list"] ?? packageJson.optionalDependencies?.["@shopify/flash-list"];
33560
- return typeof spec === "string" ? spec : null;
33561
- };
33562
- const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, getShopifyFlashListDependencySpec);
33557
+ const findShopifyFlashListVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, SHOPIFY_FLASH_LIST_PACKAGE_NAME));
33563
33558
  const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson, packageName, version }) => {
33564
33559
  if (version === null || !isCatalogReference(version)) return version;
33565
33560
  const catalogName = extractCatalogName(version);
@@ -33571,11 +33566,7 @@ const resolveCatalogBackedDependencyVersion = ({ rootDirectory, rootPackageJson,
33571
33566
  if (!isFile(monorepoPackageJsonPath)) return version;
33572
33567
  return resolveCatalogVersion(readPackageJson(monorepoPackageJsonPath), packageName, monorepoRoot, catalogName) ?? version;
33573
33568
  };
33574
- const getNextjsDependencySpec = (packageJson) => {
33575
- const spec = packageJson.dependencies?.next ?? packageJson.devDependencies?.next ?? packageJson.peerDependencies?.next ?? packageJson.optionalDependencies?.next;
33576
- return typeof spec === "string" ? spec : null;
33577
- };
33578
- const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, getNextjsDependencySpec);
33569
+ const findNextjsVersion = (rootDirectory, rootPackageJson) => findInWorkspacePackageJsons(rootDirectory, rootPackageJson, (packageJson) => getDependencySpec(packageJson, "next"));
33579
33570
  const getPreactVersion = (packageJson) => {
33580
33571
  return {
33581
33572
  ...packageJson.peerDependencies,
@@ -33731,6 +33722,13 @@ const APP_ONLY_RULE_KEYS = new Set([
33731
33722
  ]);
33732
33723
  const COMPILER_CLEANUP_BUCKET = "compiler-cleanup";
33733
33724
  const COMPILER_CLEANUP_RULE_KEYS = new Set(["react-doctor/react-compiler-no-manual-memoization"]);
33725
+ const ROOT_CAUSE_GROUPABLE_RULE_KEYS = new Set([
33726
+ "react-doctor/no-derived-state",
33727
+ "react-doctor/no-derived-state-effect",
33728
+ "react-doctor/no-derived-useState",
33729
+ "react-doctor/no-adjust-state-on-prop-change",
33730
+ "react-doctor/no-reset-all-state-on-prop-change"
33731
+ ]);
33734
33732
  const MAX_GLOB_PATTERN_LENGTH_CHARS = 1024;
33735
33733
  const CONFIG_CACHE_TTL_MS = 300 * 1e3;
33736
33734
  const SOCKET_FREE_PURL_API_BASE = "https://firewall-api.socket.dev/purl";
@@ -34183,6 +34181,7 @@ const isTailwindAtLeast = (detected, required) => {
34183
34181
  if (detected.major !== required.major) return detected.major > required.major;
34184
34182
  return detected.minor >= required.minor;
34185
34183
  };
34184
+ const messageFromUnknown = (error) => error instanceof Error ? error.message : String(error);
34186
34185
  var InvalidGlobPatternError = class extends Error {
34187
34186
  pattern;
34188
34187
  reason;
@@ -34211,7 +34210,7 @@ const compileGlobPattern = (rawPattern) => {
34211
34210
  try {
34212
34211
  return import_picomatch.default.makeRe(normalizeGlobPattern(rawPattern), PICOMATCH_OPTIONS);
34213
34212
  } catch (caughtError) {
34214
- throw new InvalidGlobPatternError(rawPattern, caughtError instanceof Error ? caughtError.message : String(caughtError));
34213
+ throw new InvalidGlobPatternError(rawPattern, messageFromUnknown(caughtError));
34215
34214
  }
34216
34215
  };
34217
34216
  const compileGlobPatternsLenient = (patterns, onInvalid) => {
@@ -34307,115 +34306,6 @@ const buildRuleSeverityControls = (config) => {
34307
34306
  ...config.buckets !== void 0 ? { buckets: config.buckets } : {}
34308
34307
  };
34309
34308
  };
34310
- const JSX_OPENER_TAG_PATTERN = /<[A-Za-z][\w.]*/g;
34311
- const JSX_TAG_NAME_FOLLOW = /[A-Za-z]/;
34312
- const isOpenerMatchInsideLineComment = (line, openerCharIndex) => {
34313
- let stringDelimiter = null;
34314
- for (let charIndex = 0; charIndex < openerCharIndex; charIndex++) {
34315
- const character = line[charIndex];
34316
- if (stringDelimiter !== null) {
34317
- if (character === "\\") {
34318
- charIndex++;
34319
- continue;
34320
- }
34321
- if (character === stringDelimiter) stringDelimiter = null;
34322
- continue;
34323
- }
34324
- if (character === "\"" || character === "'" || character === "`") {
34325
- stringDelimiter = character;
34326
- continue;
34327
- }
34328
- if (character === "/" && line[charIndex + 1] === "/") return true;
34329
- }
34330
- return false;
34331
- };
34332
- const findOpenerTagOnLine = (line) => {
34333
- for (const match of line.matchAll(JSX_OPENER_TAG_PATTERN)) {
34334
- if (match.index === void 0) continue;
34335
- if (!isOpenerMatchInsideLineComment(line, match.index)) return { startCharIndex: match.index + match[0].length };
34336
- }
34337
- return null;
34338
- };
34339
- const findJsxOpenerSpan = (lines, openerLineIndex) => {
34340
- const openerLine = lines[openerLineIndex];
34341
- if (openerLine === void 0) return null;
34342
- const opener = findOpenerTagOnLine(openerLine);
34343
- if (!opener) return null;
34344
- const lookaheadLimit = Math.min(lines.length, openerLineIndex + 32);
34345
- let braceDepth = 0;
34346
- let innerAngleDepth = 0;
34347
- let stringDelimiter = null;
34348
- for (let lineIndex = openerLineIndex; lineIndex < lookaheadLimit; lineIndex++) {
34349
- const currentLine = lines[lineIndex];
34350
- const startCharForLine = lineIndex === openerLineIndex ? opener.startCharIndex : 0;
34351
- for (let charIndex = startCharForLine; charIndex < currentLine.length; charIndex++) {
34352
- const character = currentLine[charIndex];
34353
- if (stringDelimiter !== null) {
34354
- if (character === "\\") {
34355
- charIndex++;
34356
- continue;
34357
- }
34358
- if (character === stringDelimiter) stringDelimiter = null;
34359
- continue;
34360
- }
34361
- if (character === "\"" || character === "'" || character === "`") {
34362
- stringDelimiter = character;
34363
- continue;
34364
- }
34365
- if (character === "{") {
34366
- braceDepth++;
34367
- continue;
34368
- }
34369
- if (character === "}") {
34370
- braceDepth--;
34371
- continue;
34372
- }
34373
- if (braceDepth !== 0) continue;
34374
- if (character === "<") {
34375
- const followCharacter = currentLine[charIndex + 1];
34376
- if (followCharacter !== void 0 && JSX_TAG_NAME_FOLLOW.test(followCharacter)) innerAngleDepth++;
34377
- continue;
34378
- }
34379
- if (character !== ">") continue;
34380
- const previousCharacter = currentLine[charIndex - 1];
34381
- const nextCharacter = currentLine[charIndex + 1];
34382
- if (previousCharacter === "=" || nextCharacter === "=") continue;
34383
- if (innerAngleDepth > 0) {
34384
- innerAngleDepth--;
34385
- continue;
34386
- }
34387
- return lineIndex;
34388
- }
34389
- }
34390
- return null;
34391
- };
34392
- const findEnclosingMultilineJsxOpenerStart = (lines, diagnosticLineIndex) => {
34393
- for (let candidateIndex = diagnosticLineIndex - 1; candidateIndex >= 0 && diagnosticLineIndex - candidateIndex <= 32; candidateIndex--) {
34394
- const openerCloseIndex = findJsxOpenerSpan(lines, candidateIndex);
34395
- if (openerCloseIndex !== null && openerCloseIndex >= diagnosticLineIndex) return candidateIndex;
34396
- }
34397
- return null;
34398
- };
34399
- const DISABLE_NEXT_LINE_PATTERN = /(?:\/\/|\/\*)\s*react-doctor-disable-next-line\b(?:\s+([^\r\n]*?))?\s*(?:\*\/)?\s*\}?\s*$/;
34400
- const findStackedDisableCommentsAbove = (lines, anchorIndex) => {
34401
- const collected = [];
34402
- let isStillInChain = true;
34403
- for (let candidateIndex = anchorIndex - 1; candidateIndex >= 0 && anchorIndex - candidateIndex <= 10; candidateIndex--) {
34404
- const candidateLine = lines[candidateIndex];
34405
- if (candidateLine === void 0) break;
34406
- const match = candidateLine.match(DISABLE_NEXT_LINE_PATTERN);
34407
- if (match) {
34408
- collected.push({
34409
- commentLineIndex: candidateIndex,
34410
- ruleList: match[1],
34411
- isInChain: isStillInChain
34412
- });
34413
- continue;
34414
- }
34415
- isStillInChain = false;
34416
- }
34417
- return collected;
34418
- };
34419
34309
  const LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY = {
34420
34310
  "effect/no-adjust-state-on-prop-change": "react-doctor/no-adjust-state-on-prop-change",
34421
34311
  "effect/no-chain-state-updates": "react-doctor/no-chain-state-updates",
@@ -34540,7 +34430,13 @@ for (const [legacyRuleKey, nativeRuleKey] of Object.entries(LEGACY_RULE_KEY_TO_N
34540
34430
  }
34541
34431
  const getLegacyRuleKeysForNative = (ruleKey) => NATIVE_RULE_KEY_TO_LEGACY_RULE_KEYS.get(ruleKey) ?? [];
34542
34432
  const canonicalizeRuleKey = (ruleKey) => LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY[ruleKey] ?? ruleKey;
34543
- const isSameRuleKey = (candidateRuleKey, targetRuleKey) => canonicalizeRuleKey(candidateRuleKey) === canonicalizeRuleKey(targetRuleKey);
34433
+ const isReactDoctorShortIdOf = (bareRuleKey, qualifiedRuleKey) => !bareRuleKey.includes("/") && qualifiedRuleKey === `react-doctor/${bareRuleKey}`;
34434
+ const isSameRuleKey = (candidateRuleKey, targetRuleKey) => {
34435
+ const canonicalCandidate = canonicalizeRuleKey(candidateRuleKey);
34436
+ const canonicalTarget = canonicalizeRuleKey(targetRuleKey);
34437
+ if (canonicalCandidate === canonicalTarget) return true;
34438
+ return isReactDoctorShortIdOf(canonicalCandidate, canonicalTarget) || isReactDoctorShortIdOf(canonicalTarget, canonicalCandidate);
34439
+ };
34544
34440
  const getEquivalentRuleKeys = (ruleKey) => {
34545
34441
  const nativeRuleKey = canonicalizeRuleKey(ruleKey);
34546
34442
  return [nativeRuleKey, ...getLegacyRuleKeysForNative(nativeRuleKey)];
@@ -34550,12 +34446,182 @@ const stripDescriptionTail = (ruleList) => {
34550
34446
  if (!descriptionMatch || descriptionMatch.index === void 0) return ruleList;
34551
34447
  return ruleList.slice(0, descriptionMatch.index);
34552
34448
  };
34553
- const isRuleListedInComment = (ruleList, ruleId) => {
34449
+ const tokenizeRuleList = (ruleList) => {
34554
34450
  const trimmed = ruleList?.trim();
34555
- if (!trimmed) return true;
34451
+ if (!trimmed) return [];
34556
34452
  const ruleSection = stripDescriptionTail(trimmed).trim();
34557
- if (!ruleSection) return true;
34558
- return ruleSection.split(/[,\s]+/).some((token) => isSameRuleKey(token.trim(), ruleId));
34453
+ if (!ruleSection) return [];
34454
+ return ruleSection.split(/[,\s]+/).map((token) => token.trim()).filter(Boolean);
34455
+ };
34456
+ const FOREIGN_INLINE_DISABLE_PATTERN = /(?:\/\/|\/\*)[ \t]*(eslint|oxlint)-disable-(next-line|line)(?![\w-])([^\r\n]*)/;
34457
+ const FOREIGN_BLOCK_DISABLE_PATTERN = /\/\*[ \t]*(eslint|oxlint)-disable(?![\w-])([^*\r\n]*)/;
34458
+ const FOREIGN_BLOCK_ENABLE_PATTERN = /\/\*[ \t]*(?:eslint|oxlint)-enable(?![\w-])([^*\r\n]*)/;
34459
+ const buildHint = (tool, token, ruleId) => `oxlint matches plugin rules only by their full name, so \`${token}\` in your ${tool}-disable comment does not silence \`${ruleId}\` — change it to \`${ruleId}\`.`;
34460
+ const tokenMisnamesRule = (token, ruleId) => token !== ruleId && isSameRuleKey(token, ruleId);
34461
+ const detectInlineNearMiss = (lines, diagnosticLineIndex, ruleId) => {
34462
+ const candidates = [{
34463
+ line: lines[diagnosticLineIndex],
34464
+ requiredScope: "line"
34465
+ }, {
34466
+ line: lines[diagnosticLineIndex - 1],
34467
+ requiredScope: "next-line"
34468
+ }];
34469
+ for (const { line, requiredScope } of candidates) {
34470
+ const match = line?.match(FOREIGN_INLINE_DISABLE_PATTERN);
34471
+ if (!match) continue;
34472
+ const [, tool, scope, ruleList] = match;
34473
+ if (scope !== requiredScope) continue;
34474
+ const tokens = tokenizeRuleList(ruleList);
34475
+ if (tokens.includes(ruleId)) continue;
34476
+ for (const token of tokens) if (tokenMisnamesRule(token, ruleId)) return buildHint(tool, token, ruleId);
34477
+ }
34478
+ return null;
34479
+ };
34480
+ const detectBlockNearMiss = (lines, diagnosticLineIndex, ruleId) => {
34481
+ let openMisname = null;
34482
+ const lastLineIndex = Math.min(diagnosticLineIndex, lines.length - 1);
34483
+ for (let lineIndex = 0; lineIndex <= lastLineIndex; lineIndex++) {
34484
+ const line = lines[lineIndex];
34485
+ if (line === void 0 || !line.includes("-disable") && !line.includes("-enable")) continue;
34486
+ const disableMatch = line.match(FOREIGN_BLOCK_DISABLE_PATTERN);
34487
+ if (disableMatch) {
34488
+ const [, tool, ruleList] = disableMatch;
34489
+ const tokens = tokenizeRuleList(ruleList);
34490
+ if (tokens.includes(ruleId)) openMisname = null;
34491
+ else {
34492
+ const misnamed = tokens.find((token) => tokenMisnamesRule(token, ruleId));
34493
+ if (misnamed) openMisname = {
34494
+ tool,
34495
+ token: misnamed
34496
+ };
34497
+ }
34498
+ continue;
34499
+ }
34500
+ const enableMatch = line.match(FOREIGN_BLOCK_ENABLE_PATTERN);
34501
+ if (enableMatch) {
34502
+ const enabledRules = tokenizeRuleList(enableMatch[1]);
34503
+ if (enabledRules.length === 0 || enabledRules.some((rule) => isSameRuleKey(rule, ruleId))) openMisname = null;
34504
+ }
34505
+ }
34506
+ return openMisname ? buildHint(openMisname.tool, openMisname.token, ruleId) : null;
34507
+ };
34508
+ const detectForeignDisableNearMiss = (lines, diagnosticLineIndex, ruleId) => {
34509
+ if (!ruleId.startsWith("react-doctor/")) return null;
34510
+ return detectInlineNearMiss(lines, diagnosticLineIndex, ruleId) ?? detectBlockNearMiss(lines, diagnosticLineIndex, ruleId);
34511
+ };
34512
+ const JSX_OPENER_TAG_PATTERN = /<[A-Za-z][\w.]*/g;
34513
+ const JSX_TAG_NAME_FOLLOW = /[A-Za-z]/;
34514
+ const isOpenerMatchInsideLineComment = (line, openerCharIndex) => {
34515
+ let stringDelimiter = null;
34516
+ for (let charIndex = 0; charIndex < openerCharIndex; charIndex++) {
34517
+ const character = line[charIndex];
34518
+ if (stringDelimiter !== null) {
34519
+ if (character === "\\") {
34520
+ charIndex++;
34521
+ continue;
34522
+ }
34523
+ if (character === stringDelimiter) stringDelimiter = null;
34524
+ continue;
34525
+ }
34526
+ if (character === "\"" || character === "'" || character === "`") {
34527
+ stringDelimiter = character;
34528
+ continue;
34529
+ }
34530
+ if (character === "/" && line[charIndex + 1] === "/") return true;
34531
+ }
34532
+ return false;
34533
+ };
34534
+ const findOpenerTagOnLine = (line) => {
34535
+ for (const match of line.matchAll(JSX_OPENER_TAG_PATTERN)) {
34536
+ if (match.index === void 0) continue;
34537
+ if (!isOpenerMatchInsideLineComment(line, match.index)) return { startCharIndex: match.index + match[0].length };
34538
+ }
34539
+ return null;
34540
+ };
34541
+ const findJsxOpenerSpan = (lines, openerLineIndex) => {
34542
+ const openerLine = lines[openerLineIndex];
34543
+ if (openerLine === void 0) return null;
34544
+ const opener = findOpenerTagOnLine(openerLine);
34545
+ if (!opener) return null;
34546
+ const lookaheadLimit = Math.min(lines.length, openerLineIndex + 32);
34547
+ let braceDepth = 0;
34548
+ let innerAngleDepth = 0;
34549
+ let stringDelimiter = null;
34550
+ for (let lineIndex = openerLineIndex; lineIndex < lookaheadLimit; lineIndex++) {
34551
+ const currentLine = lines[lineIndex];
34552
+ const startCharForLine = lineIndex === openerLineIndex ? opener.startCharIndex : 0;
34553
+ for (let charIndex = startCharForLine; charIndex < currentLine.length; charIndex++) {
34554
+ const character = currentLine[charIndex];
34555
+ if (stringDelimiter !== null) {
34556
+ if (character === "\\") {
34557
+ charIndex++;
34558
+ continue;
34559
+ }
34560
+ if (character === stringDelimiter) stringDelimiter = null;
34561
+ continue;
34562
+ }
34563
+ if (character === "\"" || character === "'" || character === "`") {
34564
+ stringDelimiter = character;
34565
+ continue;
34566
+ }
34567
+ if (character === "{") {
34568
+ braceDepth++;
34569
+ continue;
34570
+ }
34571
+ if (character === "}") {
34572
+ braceDepth--;
34573
+ continue;
34574
+ }
34575
+ if (braceDepth !== 0) continue;
34576
+ if (character === "<") {
34577
+ const followCharacter = currentLine[charIndex + 1];
34578
+ if (followCharacter !== void 0 && JSX_TAG_NAME_FOLLOW.test(followCharacter)) innerAngleDepth++;
34579
+ continue;
34580
+ }
34581
+ if (character !== ">") continue;
34582
+ const previousCharacter = currentLine[charIndex - 1];
34583
+ const nextCharacter = currentLine[charIndex + 1];
34584
+ if (previousCharacter === "=" || nextCharacter === "=") continue;
34585
+ if (innerAngleDepth > 0) {
34586
+ innerAngleDepth--;
34587
+ continue;
34588
+ }
34589
+ return lineIndex;
34590
+ }
34591
+ }
34592
+ return null;
34593
+ };
34594
+ const findEnclosingMultilineJsxOpenerStart = (lines, diagnosticLineIndex) => {
34595
+ for (let candidateIndex = diagnosticLineIndex - 1; candidateIndex >= 0 && diagnosticLineIndex - candidateIndex <= 32; candidateIndex--) {
34596
+ const openerCloseIndex = findJsxOpenerSpan(lines, candidateIndex);
34597
+ if (openerCloseIndex !== null && openerCloseIndex >= diagnosticLineIndex) return candidateIndex;
34598
+ }
34599
+ return null;
34600
+ };
34601
+ const DISABLE_NEXT_LINE_PATTERN = /(?:\/\/|\/\*)\s*react-doctor-disable-next-line\b(?:\s+([^\r\n]*?))?\s*(?:\*\/)?\s*\}?\s*$/;
34602
+ const findStackedDisableCommentsAbove = (lines, anchorIndex) => {
34603
+ const collected = [];
34604
+ let isStillInChain = true;
34605
+ for (let candidateIndex = anchorIndex - 1; candidateIndex >= 0 && anchorIndex - candidateIndex <= 10; candidateIndex--) {
34606
+ const candidateLine = lines[candidateIndex];
34607
+ if (candidateLine === void 0) break;
34608
+ const match = candidateLine.match(DISABLE_NEXT_LINE_PATTERN);
34609
+ if (match) {
34610
+ collected.push({
34611
+ commentLineIndex: candidateIndex,
34612
+ ruleList: match[1],
34613
+ isInChain: isStillInChain
34614
+ });
34615
+ continue;
34616
+ }
34617
+ isStillInChain = false;
34618
+ }
34619
+ return collected;
34620
+ };
34621
+ const isRuleListedInComment = (ruleList, ruleId) => {
34622
+ const tokens = tokenizeRuleList(ruleList);
34623
+ if (tokens.length === 0) return true;
34624
+ return tokens.some((token) => isSameRuleKey(token, ruleId));
34559
34625
  };
34560
34626
  const DISABLE_LINE_PATTERN = /(?:\/\/|\/\*)\s*react-doctor-disable-line\b(?:\s+([^\r\n]*?))?\s*(?:\*\/)?\s*\}?\s*$/;
34561
34627
  const formatLineGap = (gapLineCount) => `${gapLineCount} line${gapLineCount === 1 ? "" : "s"}`;
@@ -34599,7 +34665,7 @@ const evaluateSuppression = (lines, diagnosticLineIndex, ruleId) => {
34599
34665
  };
34600
34666
  return {
34601
34667
  isSuppressed: false,
34602
- nearMissHint: classifyFromComments([directComments, openerComments], diagnosticLineIndex, ruleId)
34668
+ nearMissHint: classifyFromComments([directComments, openerComments], diagnosticLineIndex, ruleId) ?? detectForeignDisableNearMiss(lines, diagnosticLineIndex, ruleId)
34603
34669
  };
34604
34670
  };
34605
34671
  /**
@@ -35367,7 +35433,6 @@ const PACKAGE_JSON_FILENAME = "package.json";
35367
35433
  const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
35368
35434
  const LEGACY_CONFIG_FILENAME = "react-doctor.config.json";
35369
35435
  const jiti = createJiti(import.meta.url);
35370
- const formatError = (error) => error instanceof Error ? error.message : String(error);
35371
35436
  const importDefaultExport = async (jitiInstance, filePath) => {
35372
35437
  const imported = await jitiInstance.import(filePath);
35373
35438
  return imported?.default ?? imported;
@@ -35399,7 +35464,7 @@ const loadModuleConfig = async (filePath) => {
35399
35464
  try {
35400
35465
  return await importDefaultExport(aliasJiti, filePath);
35401
35466
  } catch (retryError) {
35402
- throw new Error(`${formatError(error)} (retry with ${SELF_PACKAGE_IMPORT_SPECIFIER} aliased to the running react-doctor package also failed: ${formatError(retryError)})`, { cause: retryError });
35467
+ throw new Error(`${messageFromUnknown(error)} (retry with ${SELF_PACKAGE_IMPORT_SPECIFIER} aliased to the running react-doctor package also failed: ${messageFromUnknown(retryError)})`, { cause: retryError });
35403
35468
  }
35404
35469
  }
35405
35470
  };
@@ -35448,7 +35513,7 @@ const loadLegacyConfig = (directory) => {
35448
35513
  }
35449
35514
  warn(`${LEGACY_CONFIG_FILENAME} must contain an object, ignoring.`);
35450
35515
  } catch (error) {
35451
- warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${formatError(error)}`);
35516
+ warn(`Failed to load ${LEGACY_CONFIG_FILENAME}: ${messageFromUnknown(error)}`);
35452
35517
  }
35453
35518
  return {
35454
35519
  status: "invalid",
@@ -35475,7 +35540,7 @@ const loadConfigFromDirectory = async (directory) => {
35475
35540
  warn(`${CONFIG_BASENAME}.${extension} must export an object, ignoring.`);
35476
35541
  sawBrokenConfigFile = true;
35477
35542
  } catch (error) {
35478
- warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${formatError(error)}`);
35543
+ warn(`Failed to load ${CONFIG_BASENAME}.${extension}: ${messageFromUnknown(error)}`);
35479
35544
  sawBrokenConfigFile = true;
35480
35545
  }
35481
35546
  }
@@ -35529,6 +35594,29 @@ const resolveConfigRootDir = (config, configSourceDirectory) => {
35529
35594
  }
35530
35595
  return resolvedRootDir;
35531
35596
  };
35597
+ const buildFixGroupId = (diagnostic) => createHash("sha1").update(JSON.stringify([
35598
+ diagnostic.filePath,
35599
+ `${diagnostic.plugin}/${diagnostic.rule}`,
35600
+ diagnostic.message
35601
+ ])).digest("hex").slice(0, 16);
35602
+ const isGroupableRule = (diagnostic) => ROOT_CAUSE_GROUPABLE_RULE_KEYS.has(`${diagnostic.plugin}/${diagnostic.rule}`);
35603
+ const assignFixGroups = (diagnostics) => {
35604
+ const siteCountByGroupId = /* @__PURE__ */ new Map();
35605
+ for (const diagnostic of diagnostics) {
35606
+ if (!isGroupableRule(diagnostic)) continue;
35607
+ const groupId = buildFixGroupId(diagnostic);
35608
+ siteCountByGroupId.set(groupId, (siteCountByGroupId.get(groupId) ?? 0) + 1);
35609
+ }
35610
+ return diagnostics.map((diagnostic) => {
35611
+ if (!isGroupableRule(diagnostic)) return diagnostic;
35612
+ const groupId = buildFixGroupId(diagnostic);
35613
+ if ((siteCountByGroupId.get(groupId) ?? 0) < 2) return diagnostic;
35614
+ return {
35615
+ ...diagnostic,
35616
+ fixGroupId: groupId
35617
+ };
35618
+ });
35619
+ };
35532
35620
  const getDirectDependencyNames = (packageJson) => new Set([...Object.keys(packageJson.dependencies ?? {}), ...Object.keys(packageJson.devDependencies ?? {})]);
35533
35621
  const buildExpoCheckContext = (rootDirectory, expoVersion) => {
35534
35622
  const packageJson = readPackageJson(Path.join(rootDirectory, "package.json"));
@@ -36655,7 +36743,7 @@ const readIgnoreFile = (filePath) => {
36655
36743
  try {
36656
36744
  content = NFS.readFileSync(filePath, "utf-8");
36657
36745
  } catch (error) {
36658
- const errnoCode = error?.code;
36746
+ const errnoCode = isErrnoException(error) ? error.code : void 0;
36659
36747
  if (errnoCode && errnoCode !== "ENOENT") runSync(warn$1(`Could not read ignore file ${filePath}: ${errnoCode}`));
36660
36748
  return [];
36661
36749
  }
@@ -37214,15 +37302,13 @@ var DeadCode = class DeadCode extends Service()("react-doctor/DeadCode") {
37214
37302
  })()) }));
37215
37303
  static layerOf = (diagnostics) => succeed$3(DeadCode, DeadCode.of({ run: () => fromIterable$1(diagnostics) }));
37216
37304
  };
37217
- const createNodeReadFileLinesSync = (rootDirectory) => {
37218
- return (filePath) => {
37219
- const absolutePath = Path.isAbsolute(filePath) ? filePath : Path.join(rootDirectory, filePath);
37220
- try {
37221
- return NFS.readFileSync(absolutePath, "utf-8").split("\n");
37222
- } catch {
37223
- return null;
37224
- }
37225
- };
37305
+ const createNodeReadFileLinesSync = (rootDirectory) => (filePath) => {
37306
+ const absolutePath = Path.isAbsolute(filePath) ? filePath : Path.join(rootDirectory, filePath);
37307
+ try {
37308
+ return NFS.readFileSync(absolutePath, "utf-8").split("\n");
37309
+ } catch {
37310
+ return null;
37311
+ }
37226
37312
  };
37227
37313
  var Files = class Files extends Service()("react-doctor/Files") {
37228
37314
  static layerNode = succeed$3(Files, Files.of({
@@ -37433,7 +37519,10 @@ var Git = class Git extends Service()("react-doctor/Git") {
37433
37519
  directory: input.directory,
37434
37520
  cause
37435
37521
  }) });
37436
- }));
37522
+ }), withSpan("git.exec", { attributes: {
37523
+ "git.command": input.command,
37524
+ "git.subcommand": input.args[0] ?? ""
37525
+ } }));
37437
37526
  const runGit = (directory, args) => runCommand({
37438
37527
  command: "git",
37439
37528
  args,
@@ -37461,7 +37550,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
37461
37550
  ]);
37462
37551
  if (candidates.status !== 0) return null;
37463
37552
  return trimOrNull(candidates.stdout.split("\n")[0] ?? "");
37464
- });
37553
+ }).pipe(withSpan("Git.defaultBranch"));
37465
37554
  const branchExists = (directory, branch) => runGit(directory, [
37466
37555
  "rev-parse",
37467
37556
  "--verify",
@@ -37508,7 +37597,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
37508
37597
  const result = resultOption.value;
37509
37598
  if (result.status !== 0) return null;
37510
37599
  return parseGithubViewerPermission(result.stdout);
37511
- }).pipe(catch_$1(() => succeed$2(null)));
37600
+ }).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.githubViewerPermission"));
37512
37601
  /**
37513
37602
  * Resolves a `--diff A..B` / `A...B` commit range into a changed-file
37514
37603
  * selection. Each endpoint is validated with `isSafeGitRevision`
@@ -37622,7 +37711,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
37622
37711
  changedFiles: splitNullSeparated(diff.stdout),
37623
37712
  isCurrentChanges: false
37624
37713
  };
37625
- }),
37714
+ }).pipe(withSpan("Git.diffSelection")),
37626
37715
  stagedFilePaths: (directory) => runGit(directory, [
37627
37716
  "diff",
37628
37717
  "--cached",
@@ -37664,7 +37753,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
37664
37753
  status: result.status,
37665
37754
  stdout: result.stdout
37666
37755
  };
37667
- }),
37756
+ }).pipe(withSpan("Git.grep")),
37668
37757
  changedLineRanges: ({ directory, baseRef, cached, files }) => gen(function* () {
37669
37758
  if (files.length === 0) return [];
37670
37759
  if (baseRef !== void 0 && !isSafeGitRevision(baseRef)) return null;
@@ -37680,7 +37769,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
37680
37769
  ]);
37681
37770
  if (result.status !== 0) return null;
37682
37771
  return parseChangedLineRanges(result.stdout);
37683
- })
37772
+ }).pipe(withSpan("Git.changedLineRanges"))
37684
37773
  });
37685
37774
  })).pipe(provide$2(layer$2.pipe(provide$2(mergeAll$1(layer$1, layer)))));
37686
37775
  /**
@@ -37895,7 +37984,7 @@ const neutralizeDisableDirectives = async (rootDirectory, includePaths) => {
37895
37984
  for (const [absolutePath, originalContent] of originalContents) try {
37896
37985
  NFS.writeFileSync(absolutePath, originalContent);
37897
37986
  } catch (error) {
37898
- process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${error instanceof Error ? error.message : String(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
37987
+ process.stderr.write(`[react-doctor] Failed to restore inline disable directives in ${absolutePath}: ${messageFromUnknown(error)}\n[react-doctor] Run: git checkout -- ${absolutePath}\n`);
37899
37988
  }
37900
37989
  };
37901
37990
  const onExit = () => restore();
@@ -38001,7 +38090,7 @@ const resolveUserPlugin = (spec, configSourceDirectory) => {
38001
38090
  try {
38002
38091
  resolvedSpecifier = isRelative ? Path.resolve(configSourceDirectory, spec) : candidateRequire.resolve(spec);
38003
38092
  } catch (error) {
38004
- warnConfigIssue(`config.plugins entry "${spec}" could not be resolved from ${configSourceDirectory}: ${error instanceof Error ? error.message : String(error)}`);
38093
+ warnConfigIssue(`config.plugins entry "${spec}" could not be resolved from ${configSourceDirectory}: ${messageFromUnknown(error)}`);
38005
38094
  return null;
38006
38095
  }
38007
38096
  const { name, ruleNames } = readPluginShape(resolvedSpecifier, (target) => candidateRequire(target));
@@ -38847,7 +38936,7 @@ const spawnOxlint = (args, rootDirectory, nodeBinaryPath, spawnTimeoutMs = OXLIN
38847
38936
  child.kill("SIGKILL");
38848
38937
  reject(new ReactDoctorError({ reason: new OxlintBatchExceeded({
38849
38938
  kind: "timeout",
38850
- detail: `${spawnTimeoutMs / 1e3}s budget exceeded`
38939
+ detail: `${spawnTimeoutMs / MILLISECONDS_PER_SECOND}s budget exceeded`
38851
38940
  }) }));
38852
38941
  }, spawnTimeoutMs);
38853
38942
  timeoutHandle.unref?.();
@@ -39969,17 +40058,17 @@ const runInspect = (input, hooks = {}) => gen(function* () {
39969
40058
  }))))))));
39970
40059
  const deadCodeFailureState = yield* get$2(deadCodeFailure);
39971
40060
  const scanElapsedMilliseconds = Date.now() - scanStartTime;
39972
- const scanElapsedSeconds = (scanElapsedMilliseconds / 1e3).toFixed(1);
40061
+ const scanElapsedSeconds = (scanElapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1);
39973
40062
  if (!lintFailureState.didFail) if (deadCodeFailureState.didFail) yield* scanProgress.fail(DEAD_CODE_FAIL_TEXT);
39974
40063
  else if (input.suppressScanSummary) yield* scanProgress.stop();
39975
40064
  else yield* scanProgress.succeed(`Scanned ${scannedFilesLabel} in ${scanElapsedSeconds}s${workerCountSuffix}`);
39976
40065
  yield* reporterService.finalize;
39977
- const finalDiagnostics = [
40066
+ const finalDiagnostics = assignFixGroups([
39978
40067
  ...envCollected,
39979
40068
  ...supplyChainCollected,
39980
40069
  ...lintCollected,
39981
40070
  ...deadCodeCollected
39982
- ];
40071
+ ]);
39983
40072
  const githubViewerPermission = yield* join(githubViewerPermissionFiber);
39984
40073
  const scoreMetadata = {
39985
40074
  ...repo !== null ? { repo } : {},
@@ -40183,7 +40272,7 @@ const materializeSourceTree = (input) => gen(function* () {
40183
40272
  static layerNode = effect(StagedFiles, gen(function* () {
40184
40273
  const git = yield* Git;
40185
40274
  return StagedFiles.of({
40186
- discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile))),
40275
+ discoverSourceFiles: (directory) => git.stagedFilePaths(directory).pipe(map$3((entries) => entries.filter(isLintableSourceFile)), withSpan("StagedFiles.discoverSourceFiles")),
40187
40276
  materialize: ({ directory, stagedFiles, tempDirectory }) => materializeSourceTree({
40188
40277
  directory,
40189
40278
  files: stagedFiles,
@@ -40193,7 +40282,7 @@ const materializeSourceTree = (input) => gen(function* () {
40193
40282
  tempDirectory: tree.tempDirectory,
40194
40283
  stagedFiles: tree.materializedFiles,
40195
40284
  cleanup: tree.cleanup
40196
- })))
40285
+ })), withSpan("StagedFiles.materialize"))
40197
40286
  });
40198
40287
  }));
40199
40288
  /**
@@ -40261,7 +40350,10 @@ const runEditorScan = async (input) => {
40261
40350
  isCi: false,
40262
40351
  resolveLocalGithubViewerPermission: false,
40263
40352
  skipJsxIncludeFilter: true
40264
- }).pipe(provide(layers), provide(layerOtlp)));
40353
+ }).pipe(withSpan("runEditorScan", { attributes: {
40354
+ "editor.lint": lint,
40355
+ "editor.runDeadCode": runDeadCode
40356
+ } }), provide(layers), provide(layerOtlp)));
40265
40357
  if (isSuccess(exit)) {
40266
40358
  const output = exit.value;
40267
40359
  return {
@@ -40291,7 +40383,7 @@ const runEditorScan = async (input) => {
40291
40383
  didDeadCodeFail: false,
40292
40384
  deadCodeFailureReason: null,
40293
40385
  lintPartialFailures: [],
40294
- error: error instanceof Error ? error.message : String(error)
40386
+ error: messageFromUnknown(error)
40295
40387
  };
40296
40388
  };
40297
40389
  /**
@@ -40573,7 +40665,6 @@ const toLspDiagnostic = (input) => {
40573
40665
  data
40574
40666
  };
40575
40667
  };
40576
- const toUri = (absoluteFilePath) => fsPathToUri(absoluteFilePath);
40577
40668
  /**
40578
40669
  * Owns the published-diagnostic state. Maps scan outcomes to LSP
40579
40670
  * diagnostics, publishes complete per-URI replacement sets (so the
@@ -40603,7 +40694,7 @@ var DiagnosticsManager = class {
40603
40694
  const isProtectedPath = (fsPath) => protectOpen && this.isOpen(fsPath);
40604
40695
  for (const [fsPath, coreDiagnostics] of outcome.byFile) {
40605
40696
  if (isProtectedPath(fsPath)) continue;
40606
- const uri = toUri(fsPath);
40697
+ const uri = fsPathToUri(fsPath);
40607
40698
  const text = this.textProvider(fsPath);
40608
40699
  const lspDiagnostics = coreDiagnostics.map((diagnostic) => toLspDiagnostic({
40609
40700
  diagnostic,
@@ -40625,7 +40716,7 @@ var DiagnosticsManager = class {
40625
40716
  for (const fsPath of outcome.requestedPaths) {
40626
40717
  if (isProtectedPath(fsPath)) continue;
40627
40718
  if (outcome.byFile.has(fsPath)) continue;
40628
- const uri = toUri(fsPath);
40719
+ const uri = fsPathToUri(fsPath);
40629
40720
  if (this.byUri.has(uri)) this.byUri.delete(uri);
40630
40721
  this.publish(uri, []);
40631
40722
  }
@@ -40650,7 +40741,7 @@ var DiagnosticsManager = class {
40650
40741
  const set = this.projectUris.get(project) ?? /* @__PURE__ */ new Set();
40651
40742
  for (const uri of liveUris) set.add(uri);
40652
40743
  for (const fsPath of outcome.requestedPaths) {
40653
- const uri = toUri(fsPath);
40744
+ const uri = fsPathToUri(fsPath);
40654
40745
  if (!liveUris.has(uri)) set.delete(uri);
40655
40746
  }
40656
40747
  this.projectUris.set(project, set);
@@ -40678,7 +40769,7 @@ var DiagnosticsManager = class {
40678
40769
  const tracked = this.projectUris.get(project);
40679
40770
  if (!tracked) return;
40680
40771
  const liveUris = /* @__PURE__ */ new Set();
40681
- for (const fsPath of liveFsPaths) liveUris.add(toUri(fsPath));
40772
+ for (const fsPath of liveFsPaths) liveUris.add(fsPathToUri(fsPath));
40682
40773
  for (const uri of [...tracked]) {
40683
40774
  if (liveUris.has(uri)) continue;
40684
40775
  this.byUri.delete(uri);
@@ -40975,7 +41066,7 @@ const createProjectGraph = (options) => {
40975
41066
  });
40976
41067
  }
40977
41068
  } catch (error) {
40978
- logger.warn(`Project discovery failed for ${root}: ${error instanceof Error ? error.message : String(error)}`);
41069
+ logger.warn(`Project discovery failed for ${root}: ${messageFromUnknown(error)}`);
40979
41070
  }
40980
41071
  return [...seen.values()].sort((first, second) => second.directory.length - first.directory.length);
40981
41072
  };
@@ -41042,7 +41133,7 @@ const createLintCache = (input) => {
41042
41133
  fs.writeFileSync(tempPath, JSON.stringify(payload));
41043
41134
  fs.renameSync(tempPath, cacheFilePath);
41044
41135
  } catch (error) {
41045
- logger.warn(`Failed to persist lint cache: ${error instanceof Error ? error.message : String(error)}`);
41136
+ logger.warn(`Failed to persist lint cache: ${messageFromUnknown(error)}`);
41046
41137
  }
41047
41138
  };
41048
41139
  return {
@@ -41350,7 +41441,7 @@ const createScheduler = (options) => {
41350
41441
  if (outcome && !token.isCancelled) options.onResult(outcome);
41351
41442
  }).catch((error) => {
41352
41443
  if (options.onError) options.onError(error, request);
41353
- else logger.error(`Scan failed: ${error instanceof Error ? error.message : String(error)}`);
41444
+ else logger.error(`Scan failed: ${messageFromUnknown(error)}`);
41354
41445
  }).finally(() => {
41355
41446
  running -= 1;
41356
41447
  if (isBackground) runningBackground -= 1;
@@ -41737,7 +41828,7 @@ const createServer = (connection, options = {}) => {
41737
41828
  maybeWarnLintUnavailable(outcome);
41738
41829
  if (outcome.request.priority === "background") scanTelemetry.accumulate(outcome);
41739
41830
  },
41740
- onError: (error, request) => logger.error(`Scan of ${request.projectDirectory} threw: ${error instanceof Error ? error.message : String(error)}`),
41831
+ onError: (error, request) => logger.error(`Scan of ${request.projectDirectory} threw: ${messageFromUnknown(error)}`),
41741
41832
  onIdleChange: (idle) => {
41742
41833
  setBusy(!idle);
41743
41834
  if (idle) scanTelemetry.finish();
@@ -42385,5 +42476,5 @@ const startLanguageServer = () => {
42385
42476
  };
42386
42477
  //#endregion
42387
42478
  export { startLanguageServer };
42388
- !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]="42683a4c-8da1-5155-bf9c-b9a69b9718e6")}catch(e){}}();
42389
- //# debugId=42683a4c-8da1-5155-bf9c-b9a69b9718e6
42479
+ !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]="6fbf847f-43b8-5c5c-ba97-c26c2e08e250")}catch(e){}}();
42480
+ //# debugId=6fbf847f-43b8-5c5c-ba97-c26c2e08e250