react-doctor 0.7.7-dev.fbc804e → 0.7.8-dev.4829841

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.
Files changed (4) hide show
  1. package/dist/cli.js +451 -78
  2. package/dist/index.js +436 -75
  3. package/dist/lsp.js +437 -76
  4. package/package.json +6 -6
package/dist/lsp.js CHANGED
@@ -6,6 +6,8 @@ import os from "node:os";
6
6
  import * as Path from "node:path";
7
7
  import path from "node:path";
8
8
  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";
9
+ import * as Crypto from "node:crypto";
10
+ import crypto, { createHash } from "node:crypto";
9
11
  import * as NodeChildProcess from "node:child_process";
10
12
  import { execFileSync, spawn, spawnSync } from "node:child_process";
11
13
  import ts from "typescript";
@@ -13,8 +15,6 @@ import { parseJSON5 } from "confbox";
13
15
  import * as NodeUrl from "node:url";
14
16
  import { fileURLToPath } from "node:url";
15
17
  import { createJiti } from "jiti";
16
- import * as Crypto from "node:crypto";
17
- import crypto, { createHash } from "node:crypto";
18
18
  import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
19
19
  import { gzipSync } from "node:zlib";
20
20
  import { CodeActionKind, CodeActionTriggerKind, DidChangeWatchedFilesNotification, DocumentDiagnosticReportKind, FileChangeType, TextDocumentSyncKind, TextDocuments, createConnection } from "vscode-languageserver/node.js";
@@ -19365,12 +19365,13 @@ var JsonReportDiagnosticV3 = class extends Class("JsonReportDiagnosticV3")({
19365
19365
  fixGroupId: optional(String$1)
19366
19366
  }) {};
19367
19367
  /**
19368
- * Deterministic identity string for a diagnostic. Same diagnostic
19369
- * across two scans yields the same identity; lets baselines,
19370
- * suppression files, content-hash caches, and IDE "ignore this"
19371
- * actions all key off one shared shape.
19368
+ * Deterministic identity string for a retained diagnostic occurrence.
19369
+ * Severity and message distinguish content variants at one normalized site.
19372
19370
  */
19373
- const buildDiagnosticIdentity = (input) => `${input.filePath}::${input.line}:${input.column}::${input.plugin}/${input.rule}`;
19371
+ const buildDiagnosticIdentity = (input) => {
19372
+ const occurrenceDigest = createHash("sha256").update(JSON.stringify([input.severity, input.message])).digest("hex");
19373
+ return `${input.filePath}::${input.line}:${input.column}::${input.plugin}/${input.rule}::${occurrenceDigest}`;
19374
+ };
19374
19375
  const JsonReportMode = Literals([
19375
19376
  "full",
19376
19377
  "diff",
@@ -33091,7 +33092,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
33091
33092
  const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
33092
33093
  const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
33093
33094
  const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
33094
- const CORE_PACKAGE_VERSION = "0.7.7";
33095
+ const CORE_PACKAGE_VERSION = "0.7.8";
33095
33096
  const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
33096
33097
  const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
33097
33098
  const SUPPLY_CHAIN_PLUGIN = "socket";
@@ -37160,18 +37161,45 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
37160
37161
  }
37161
37162
  return diagnostics;
37162
37163
  };
37163
- const REDUCED_MOTION_GREP_PATTERN = "prefers-reduced-motion|useReducedMotion|MotionConfig|reducedMotion";
37164
- const REDUCED_MOTION_PATTERN = new RegExp(REDUCED_MOTION_GREP_PATTERN);
37165
- const REDUCED_MOTION_FILE_EXTENSIONS = new Set([
37164
+ const getTypescriptScriptKind = (fileName) => {
37165
+ if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
37166
+ if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
37167
+ if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
37168
+ return ts.ScriptKind.JS;
37169
+ };
37170
+ const unwrapTypescriptExpression = (expression) => {
37171
+ let currentExpression = expression;
37172
+ while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
37173
+ return currentExpression;
37174
+ };
37175
+ const EMPTY_MOTION_EXPRESSION_EVIDENCE = {
37176
+ isAnimationFunction: false,
37177
+ isMotionComponent: false,
37178
+ isMotionComponentFactory: false,
37179
+ isMotionComponentNamespace: false,
37180
+ isMotionConfig: false,
37181
+ isMotionNamespace: false,
37182
+ isReducedMotionHook: false
37183
+ };
37184
+ const MOTION_COMPONENT_FACTORY_EXPORT_NAMES = new Set(["m", "motion"]);
37185
+ const MOTION_COMPONENT_NAMESPACE_EXPORT_NAMES = new Set(["Reorder"]);
37186
+ const MOTION_COMPONENT_NAMESPACE_MEMBER_NAMES = new Set(["Item"]);
37187
+ const MOTION_ANIMATION_FUNCTION_EXPORT_NAMES = new Set(["animate"]);
37188
+ const REDUCED_MOTION_HOOK_EXPORT_NAME = "useReducedMotion";
37189
+ const MOTION_CONFIG_EXPORT_NAME = "MotionConfig";
37190
+ const REDUCED_MOTION_PROP_NAME = "reducedMotion";
37191
+ const REDUCED_MOTION_CONFIG_VALUES = new Set(["always", "user"]);
37192
+ const SCRIPT_MODULE_EXTENSIONS = [
37166
37193
  ".ts",
37167
37194
  ".tsx",
37168
37195
  ".js",
37169
- ".jsx",
37170
- ".css",
37171
- ".scss"
37172
- ]);
37173
- const REDUCED_MOTION_FILE_GLOBS = [...REDUCED_MOTION_FILE_EXTENSIONS].map((extension) => `*${extension}`);
37174
- const GIT_GREP_NO_MATCH_STATUS = 1;
37196
+ ".jsx"
37197
+ ];
37198
+ const SCRIPT_FILE_EXTENSIONS = new Set(SCRIPT_MODULE_EXTENSIONS);
37199
+ const STYLE_FILE_EXTENSIONS = new Set([".css", ".scss"]);
37200
+ const MOTION_SOURCE_PREFILTER = /framer-motion|["']motion(?:\/[A-Za-z0-9_./-]+)?["']|MotionConfig|useReducedMotion/;
37201
+ const REDUCED_MOTION_MEDIA_QUERY_PATTERN = /@media\s+([^{}]*\(\s*prefers-reduced-motion\s*:\s*reduce\s*\)[^{}]*)\{/gi;
37202
+ const CSS_DECLARATION_PATTERN = /(?:^|[;{])\s*[-_A-Za-z][-_A-Za-z0-9]*\s*:/;
37175
37203
  const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
37176
37204
  filePath: "package.json",
37177
37205
  plugin: "react-doctor",
@@ -37183,52 +37211,406 @@ const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
37183
37211
  column: 0,
37184
37212
  category: "Accessibility"
37185
37213
  };
37186
- const hasReducedMotionHandlingViaFilesystem = (rootDirectory) => {
37214
+ const isMotionModuleSource = (moduleSource) => {
37215
+ for (const packageName of MOTION_LIBRARY_PACKAGES) if (moduleSource === packageName || moduleSource.startsWith(`${packageName}/`)) return true;
37216
+ return false;
37217
+ };
37218
+ const classifyMotionExport = (exportName) => ({
37219
+ isAnimationFunction: MOTION_ANIMATION_FUNCTION_EXPORT_NAMES.has(exportName),
37220
+ isMotionComponent: false,
37221
+ isMotionComponentFactory: MOTION_COMPONENT_FACTORY_EXPORT_NAMES.has(exportName),
37222
+ isMotionComponentNamespace: MOTION_COMPONENT_NAMESPACE_EXPORT_NAMES.has(exportName),
37223
+ isMotionConfig: exportName === MOTION_CONFIG_EXPORT_NAME,
37224
+ isMotionNamespace: false,
37225
+ isReducedMotionHook: exportName === REDUCED_MOTION_HOOK_EXPORT_NAME
37226
+ });
37227
+ const getImportModuleSource = (node) => {
37228
+ let currentNode = node;
37229
+ while (currentNode) {
37230
+ if (ts.isImportDeclaration(currentNode) && ts.isStringLiteral(currentNode.moduleSpecifier)) return currentNode.moduleSpecifier.text;
37231
+ currentNode = currentNode.parent;
37232
+ }
37233
+ return null;
37234
+ };
37235
+ const getImportedBindingEvidence = (declaration, typeChecker, program, visitedSymbols) => {
37236
+ const moduleSource = getImportModuleSource(declaration);
37237
+ if (!moduleSource) return null;
37238
+ if (isMotionModuleSource(moduleSource) && ts.isNamespaceImport(declaration)) return {
37239
+ ...EMPTY_MOTION_EXPRESSION_EVIDENCE,
37240
+ isMotionNamespace: true
37241
+ };
37242
+ if (isMotionModuleSource(moduleSource) && ts.isImportSpecifier(declaration)) {
37243
+ if (declaration.isTypeOnly) return null;
37244
+ return classifyMotionExport(declaration.propertyName?.text ?? declaration.name.text);
37245
+ }
37246
+ if (isMotionModuleSource(moduleSource) && ts.isImportClause(declaration)) {
37247
+ if (declaration.isTypeOnly) return null;
37248
+ return EMPTY_MOTION_EXPRESSION_EVIDENCE;
37249
+ }
37250
+ if (ts.isImportSpecifier(declaration) && !declaration.isTypeOnly || ts.isImportClause(declaration) && !declaration.isTypeOnly && declaration.name) {
37251
+ const importedName = ts.isImportSpecifier(declaration) ? declaration.propertyName?.text ?? declaration.name.text : "default";
37252
+ const moduleSourceFile = getLocalModuleSourceFile(moduleSource, declaration.getSourceFile().fileName, program);
37253
+ if (!moduleSourceFile) return null;
37254
+ return resolveModuleExportEvidence(moduleSourceFile, importedName, typeChecker, program, visitedSymbols);
37255
+ }
37256
+ return null;
37257
+ };
37258
+ const getLocalModuleSourceFile = (moduleSource, importingFileName, program) => {
37259
+ if (!moduleSource.startsWith(".")) return null;
37260
+ const moduleBasePath = Path.resolve(Path.dirname(importingFileName), moduleSource);
37261
+ const moduleBaseExtension = Path.extname(moduleBasePath);
37262
+ const typescriptModuleBasePath = moduleBaseExtension === ".js" || moduleBaseExtension === ".jsx" ? moduleBasePath.slice(0, -moduleBaseExtension.length) : null;
37263
+ const candidates = [
37264
+ moduleBasePath,
37265
+ ...typescriptModuleBasePath ? [
37266
+ `${typescriptModuleBasePath}.ts`,
37267
+ `${typescriptModuleBasePath}.tsx`,
37268
+ Path.join(typescriptModuleBasePath, "index.ts"),
37269
+ Path.join(typescriptModuleBasePath, "index.tsx")
37270
+ ] : [],
37271
+ ...SCRIPT_MODULE_EXTENSIONS.map((extension) => `${moduleBasePath}${extension}`),
37272
+ ...SCRIPT_MODULE_EXTENSIONS.map((extension) => Path.join(moduleBasePath, `index${extension}`))
37273
+ ];
37274
+ for (const candidate of candidates) {
37275
+ const sourceFile = program.getSourceFile(candidate);
37276
+ if (sourceFile) return sourceFile;
37277
+ }
37278
+ return null;
37279
+ };
37280
+ const resolveModuleExportEvidence = (sourceFile, exportName, typeChecker, program, visitedSymbols) => {
37281
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
37282
+ if (moduleSymbol && visitedSymbols.has(moduleSymbol)) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
37283
+ const nextVisitedSymbols = new Set(visitedSymbols);
37284
+ if (moduleSymbol) nextVisitedSymbols.add(moduleSymbol);
37285
+ for (const statement of sourceFile.statements) {
37286
+ if (exportName === "default" && ts.isExportAssignment(statement) && !statement.isExportEquals) {
37287
+ const evidence = resolveMotionExpressionEvidence(statement.expression, typeChecker, program, nextVisitedSymbols);
37288
+ if (hasMotionExpressionEvidence(evidence)) return evidence;
37289
+ continue;
37290
+ }
37291
+ if (!ts.isExportDeclaration(statement) || !statement.moduleSpecifier) continue;
37292
+ if (statement.isTypeOnly) continue;
37293
+ if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
37294
+ const moduleSource = statement.moduleSpecifier.text;
37295
+ if (!statement.exportClause) {
37296
+ if (isMotionModuleSource(moduleSource)) {
37297
+ const evidence = classifyMotionExport(exportName);
37298
+ if (hasMotionExpressionEvidence(evidence)) return evidence;
37299
+ continue;
37300
+ }
37301
+ const moduleSourceFile = getLocalModuleSourceFile(moduleSource, sourceFile.fileName, program);
37302
+ if (moduleSourceFile) {
37303
+ const evidence = resolveModuleExportEvidence(moduleSourceFile, exportName, typeChecker, program, nextVisitedSymbols);
37304
+ if (hasMotionExpressionEvidence(evidence)) return evidence;
37305
+ }
37306
+ continue;
37307
+ }
37308
+ if (!ts.isNamedExports(statement.exportClause)) continue;
37309
+ for (const exportSpecifier of statement.exportClause.elements) {
37310
+ if (exportSpecifier.name.text !== exportName || exportSpecifier.isTypeOnly) continue;
37311
+ const sourceExportName = exportSpecifier.propertyName?.text ?? exportSpecifier.name.text;
37312
+ if (isMotionModuleSource(moduleSource)) return classifyMotionExport(sourceExportName);
37313
+ const moduleSourceFile = getLocalModuleSourceFile(moduleSource, sourceFile.fileName, program);
37314
+ if (!moduleSourceFile) continue;
37315
+ return resolveModuleExportEvidence(moduleSourceFile, sourceExportName, typeChecker, program, nextVisitedSymbols);
37316
+ }
37317
+ }
37318
+ if (!moduleSymbol) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
37319
+ const exportedSymbol = typeChecker.getExportsOfModule(moduleSymbol).find((candidateSymbol) => candidateSymbol.name === exportName);
37320
+ if (!exportedSymbol || nextVisitedSymbols.has(exportedSymbol)) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
37321
+ nextVisitedSymbols.add(exportedSymbol);
37322
+ let resolvedEvidence = EMPTY_MOTION_EXPRESSION_EVIDENCE;
37323
+ for (const declaration of exportedSymbol.declarations ?? []) {
37324
+ if (ts.isExportSpecifier(declaration)) {
37325
+ const targetSymbol = typeChecker.getExportSpecifierLocalTargetSymbol(declaration);
37326
+ for (const targetDeclaration of targetSymbol?.declarations ?? []) {
37327
+ const importedEvidence = getImportedBindingEvidence(targetDeclaration, typeChecker, program, nextVisitedSymbols);
37328
+ if (importedEvidence) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, importedEvidence);
37329
+ if (ts.isVariableDeclaration(targetDeclaration) && targetDeclaration.initializer) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, resolveMotionExpressionEvidence(targetDeclaration.initializer, typeChecker, program, nextVisitedSymbols));
37330
+ }
37331
+ }
37332
+ if (ts.isVariableDeclaration(declaration) && declaration.initializer) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, resolveMotionExpressionEvidence(declaration.initializer, typeChecker, program, nextVisitedSymbols));
37333
+ }
37334
+ return resolvedEvidence;
37335
+ };
37336
+ const mergeMotionExpressionEvidence = (leftEvidence, rightEvidence) => ({
37337
+ isAnimationFunction: leftEvidence.isAnimationFunction || rightEvidence.isAnimationFunction,
37338
+ isMotionComponent: leftEvidence.isMotionComponent || rightEvidence.isMotionComponent,
37339
+ isMotionComponentFactory: leftEvidence.isMotionComponentFactory || rightEvidence.isMotionComponentFactory,
37340
+ isMotionComponentNamespace: leftEvidence.isMotionComponentNamespace || rightEvidence.isMotionComponentNamespace,
37341
+ isMotionConfig: leftEvidence.isMotionConfig || rightEvidence.isMotionConfig,
37342
+ isMotionNamespace: leftEvidence.isMotionNamespace || rightEvidence.isMotionNamespace,
37343
+ isReducedMotionHook: leftEvidence.isReducedMotionHook || rightEvidence.isReducedMotionHook
37344
+ });
37345
+ const hasMotionExpressionEvidence = (evidence) => evidence.isAnimationFunction || evidence.isMotionComponent || evidence.isMotionComponentFactory || evidence.isMotionComponentNamespace || evidence.isMotionConfig || evidence.isMotionNamespace || evidence.isReducedMotionHook;
37346
+ const classifyMotionMember = (receiverEvidence, memberName) => {
37347
+ if (receiverEvidence.isMotionNamespace) return classifyMotionExport(memberName);
37348
+ if (receiverEvidence.isMotionComponentFactory) return {
37349
+ ...EMPTY_MOTION_EXPRESSION_EVIDENCE,
37350
+ isMotionComponent: true
37351
+ };
37352
+ if (receiverEvidence.isMotionComponentNamespace && MOTION_COMPONENT_NAMESPACE_MEMBER_NAMES.has(memberName)) return {
37353
+ ...EMPTY_MOTION_EXPRESSION_EVIDENCE,
37354
+ isMotionComponent: true
37355
+ };
37356
+ return EMPTY_MOTION_EXPRESSION_EVIDENCE;
37357
+ };
37358
+ const resolveMotionExpressionEvidence = (expression, typeChecker, program, visitedSymbols = /* @__PURE__ */ new Set()) => {
37359
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
37360
+ if (ts.isIdentifier(unwrappedExpression)) {
37361
+ const symbol = typeChecker.getSymbolAtLocation(unwrappedExpression);
37362
+ if (!symbol || visitedSymbols.has(symbol)) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
37363
+ const nextVisitedSymbols = new Set(visitedSymbols);
37364
+ nextVisitedSymbols.add(symbol);
37365
+ let resolvedEvidence = EMPTY_MOTION_EXPRESSION_EVIDENCE;
37366
+ for (const declaration of symbol.declarations ?? []) {
37367
+ const importedEvidence = getImportedBindingEvidence(declaration, typeChecker, program, nextVisitedSymbols);
37368
+ if (importedEvidence) {
37369
+ resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, importedEvidence);
37370
+ continue;
37371
+ }
37372
+ if (ts.isVariableDeclaration(declaration) && declaration.initializer) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, resolveMotionExpressionEvidence(declaration.initializer, typeChecker, program, nextVisitedSymbols));
37373
+ if (ts.isBindingElement(declaration) && ts.isObjectBindingPattern(declaration.parent) && ts.isVariableDeclaration(declaration.parent.parent) && declaration.parent.parent.initializer) {
37374
+ const propertyName = declaration.propertyName ?? declaration.name;
37375
+ if (ts.isIdentifier(propertyName) || ts.isStringLiteral(propertyName)) {
37376
+ const receiverEvidence = resolveMotionExpressionEvidence(declaration.parent.parent.initializer, typeChecker, program, nextVisitedSymbols);
37377
+ resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, classifyMotionMember(receiverEvidence, propertyName.text));
37378
+ }
37379
+ }
37380
+ }
37381
+ return resolvedEvidence;
37382
+ }
37383
+ if (ts.isPropertyAccessExpression(unwrappedExpression)) return classifyMotionMember(resolveMotionExpressionEvidence(unwrappedExpression.expression, typeChecker, program, visitedSymbols), unwrappedExpression.name.text);
37384
+ if (ts.isElementAccessExpression(unwrappedExpression) && unwrappedExpression.argumentExpression && (ts.isStringLiteral(unwrappedExpression.argumentExpression) || ts.isNoSubstitutionTemplateLiteral(unwrappedExpression.argumentExpression))) return classifyMotionMember(resolveMotionExpressionEvidence(unwrappedExpression.expression, typeChecker, program, visitedSymbols), unwrappedExpression.argumentExpression.text);
37385
+ if (ts.isCallExpression(unwrappedExpression)) {
37386
+ if (ts.isIdentifier(unwrappedExpression.expression) && unwrappedExpression.expression.text === "require" && !typeChecker.getSymbolAtLocation(unwrappedExpression.expression) && unwrappedExpression.arguments.length === 1 && ts.isStringLiteral(unwrappedExpression.arguments[0]) && isMotionModuleSource(unwrappedExpression.arguments[0].text)) return {
37387
+ ...EMPTY_MOTION_EXPRESSION_EVIDENCE,
37388
+ isMotionNamespace: true
37389
+ };
37390
+ if (ts.isPropertyAccessExpression(unwrappedExpression.expression) && unwrappedExpression.expression.name.text === "bind") {
37391
+ const boundReceiverEvidence = resolveMotionExpressionEvidence(unwrappedExpression.expression.expression, typeChecker, program, visitedSymbols);
37392
+ if (boundReceiverEvidence.isAnimationFunction) return boundReceiverEvidence;
37393
+ }
37394
+ const calleeEvidence = resolveMotionExpressionEvidence(unwrappedExpression.expression, typeChecker, program, visitedSymbols);
37395
+ if (calleeEvidence.isMotionComponentFactory) return {
37396
+ ...EMPTY_MOTION_EXPRESSION_EVIDENCE,
37397
+ isMotionComponent: true
37398
+ };
37399
+ return calleeEvidence;
37400
+ }
37401
+ return EMPTY_MOTION_EXPRESSION_EVIDENCE;
37402
+ };
37403
+ const getStaticStringExpressionValue = (expression, typeChecker, visitedSymbols = /* @__PURE__ */ new Set()) => {
37404
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
37405
+ if (ts.isStringLiteral(unwrappedExpression) || ts.isNoSubstitutionTemplateLiteral(unwrappedExpression)) return unwrappedExpression.text;
37406
+ if (!ts.isIdentifier(unwrappedExpression)) return null;
37407
+ const symbol = typeChecker.getSymbolAtLocation(unwrappedExpression);
37408
+ if (!symbol || visitedSymbols.has(symbol)) return null;
37409
+ const nextVisitedSymbols = new Set(visitedSymbols);
37410
+ nextVisitedSymbols.add(symbol);
37411
+ for (const declaration of symbol.declarations ?? []) {
37412
+ if (!ts.isVariableDeclaration(declaration) || !declaration.initializer) continue;
37413
+ if (!ts.isVariableDeclarationList(declaration.parent)) continue;
37414
+ if (!(declaration.parent.flags & ts.NodeFlags.Const)) continue;
37415
+ const value = getStaticStringExpressionValue(declaration.initializer, typeChecker, nextVisitedSymbols);
37416
+ if (value !== null) return value;
37417
+ }
37418
+ return null;
37419
+ };
37420
+ const getStaticJsxAttributeValue = (attribute, typeChecker) => {
37421
+ if (!attribute.initializer) return null;
37422
+ if (ts.isStringLiteral(attribute.initializer)) return attribute.initializer.text;
37423
+ if (!ts.isJsxExpression(attribute.initializer) || !attribute.initializer.expression) return null;
37424
+ return getStaticStringExpressionValue(attribute.initializer.expression, typeChecker);
37425
+ };
37426
+ const isExpressionValueConsumed = (expression) => {
37427
+ let currentExpression = expression;
37428
+ while (ts.isParenthesizedExpression(currentExpression.parent) || ts.isAsExpression(currentExpression.parent) || ts.isSatisfiesExpression(currentExpression.parent) || ts.isNonNullExpression(currentExpression.parent) || ts.isTypeAssertionExpression(currentExpression.parent)) currentExpression = currentExpression.parent;
37429
+ return !ts.isExpressionStatement(currentExpression.parent) && !ts.isVoidExpression(currentExpression.parent);
37430
+ };
37431
+ const jsxElementHasReducedMotionConfiguration = (attributes, typeChecker) => attributes.properties.some((attribute) => ts.isJsxAttribute(attribute) && ts.isIdentifier(attribute.name) && attribute.name.text === REDUCED_MOTION_PROP_NAME && REDUCED_MOTION_CONFIG_VALUES.has(getStaticJsxAttributeValue(attribute, typeChecker) ?? ""));
37432
+ const collectScriptMotionEvidence = (sourceFile, typeChecker, program) => {
37433
+ const evidence = {
37434
+ hasMotionUse: false,
37435
+ hasReducedMotionHandling: false
37436
+ };
37437
+ const visitNode = (node) => {
37438
+ if (ts.isCallExpression(node)) {
37439
+ const calleeEvidence = resolveMotionExpressionEvidence(node.expression, typeChecker, program);
37440
+ const isAnimationFunctionCallViaCallOrApply = (ts.isPropertyAccessExpression(node.expression) && (node.expression.name.text === "call" || node.expression.name.text === "apply") || ts.isElementAccessExpression(node.expression) && node.expression.argumentExpression && (ts.isStringLiteral(node.expression.argumentExpression) || ts.isNoSubstitutionTemplateLiteral(node.expression.argumentExpression)) && (node.expression.argumentExpression.text === "call" || node.expression.argumentExpression.text === "apply")) && resolveMotionExpressionEvidence(node.expression.expression, typeChecker, program).isAnimationFunction;
37441
+ if (calleeEvidence.isAnimationFunction || isAnimationFunctionCallViaCallOrApply) evidence.hasMotionUse = true;
37442
+ if (calleeEvidence.isReducedMotionHook && isExpressionValueConsumed(node)) evidence.hasReducedMotionHandling = true;
37443
+ }
37444
+ if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
37445
+ const tagEvidence = ts.isJsxNamespacedName(node.tagName) ? EMPTY_MOTION_EXPRESSION_EVIDENCE : resolveMotionExpressionEvidence(node.tagName, typeChecker, program);
37446
+ if (tagEvidence.isMotionComponent || tagEvidence.isMotionComponentFactory) evidence.hasMotionUse = true;
37447
+ if (tagEvidence.isMotionConfig && jsxElementHasReducedMotionConfiguration(node.attributes, typeChecker)) evidence.hasReducedMotionHandling = true;
37448
+ }
37449
+ ts.forEachChild(node, visitNode);
37450
+ };
37451
+ visitNode(sourceFile);
37452
+ return evidence;
37453
+ };
37454
+ const analyzeReducedMotionSources = (sources) => {
37455
+ if (!sources.some(({ sourceText }) => MOTION_SOURCE_PREFILTER.test(sourceText))) return {
37456
+ hasMotionUse: false,
37457
+ hasReducedMotionHandling: false
37458
+ };
37459
+ const compilerOptions = {
37460
+ allowJs: true,
37461
+ checkJs: false,
37462
+ jsx: ts.JsxEmit.Preserve,
37463
+ module: ts.ModuleKind.ESNext,
37464
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
37465
+ noEmit: true,
37466
+ noLib: true,
37467
+ noResolve: true,
37468
+ skipLibCheck: true,
37469
+ target: ts.ScriptTarget.Latest
37470
+ };
37471
+ const sourceTextByFileName = new Map(sources.map(({ fileName: sourceFileName, sourceText: content }) => [Path.resolve(sourceFileName), content]));
37472
+ const compilerHost = ts.createCompilerHost(compilerOptions);
37473
+ const getDefaultSourceFile = compilerHost.getSourceFile.bind(compilerHost);
37474
+ compilerHost.getSourceFile = (requestedFileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => sourceTextByFileName.has(Path.resolve(requestedFileName)) ? ts.createSourceFile(Path.resolve(requestedFileName), sourceTextByFileName.get(Path.resolve(requestedFileName)) ?? "", languageVersionOrOptions, true, getTypescriptScriptKind(requestedFileName)) : getDefaultSourceFile(requestedFileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile);
37475
+ const program = ts.createProgram([...sourceTextByFileName.keys()], compilerOptions, compilerHost);
37476
+ const typeChecker = program.getTypeChecker();
37477
+ const evidence = {
37478
+ hasMotionUse: false,
37479
+ hasReducedMotionHandling: false
37480
+ };
37481
+ for (const sourceFileName of sourceTextByFileName.keys()) {
37482
+ const sourceFile = program.getSourceFile(sourceFileName);
37483
+ if (!sourceFile) continue;
37484
+ const fileEvidence = collectScriptMotionEvidence(sourceFile, typeChecker, program);
37485
+ evidence.hasMotionUse ||= fileEvidence.hasMotionUse;
37486
+ evidence.hasReducedMotionHandling ||= fileEvidence.hasReducedMotionHandling;
37487
+ }
37488
+ return evidence;
37489
+ };
37490
+ const removeCssCommentsAndStrings = (content) => {
37491
+ let sanitizedContent = "";
37492
+ let quote = null;
37493
+ let isInsideComment = false;
37494
+ let isInsideLineComment = false;
37495
+ for (let characterIndex = 0; characterIndex < content.length; characterIndex += 1) {
37496
+ const character = content[characterIndex];
37497
+ const nextCharacter = content[characterIndex + 1];
37498
+ if (isInsideLineComment) {
37499
+ sanitizedContent += character === "\n" ? "\n" : " ";
37500
+ if (character === "\n") isInsideLineComment = false;
37501
+ continue;
37502
+ }
37503
+ if (isInsideComment) {
37504
+ if (character === "*" && nextCharacter === "/") {
37505
+ sanitizedContent += " ";
37506
+ characterIndex += 1;
37507
+ isInsideComment = false;
37508
+ } else sanitizedContent += character === "\n" ? "\n" : " ";
37509
+ continue;
37510
+ }
37511
+ if (quote) {
37512
+ if (character === "\\") {
37513
+ sanitizedContent += " ";
37514
+ characterIndex += 1;
37515
+ continue;
37516
+ }
37517
+ if (character === quote) quote = null;
37518
+ sanitizedContent += character === "\n" ? "\n" : " ";
37519
+ continue;
37520
+ }
37521
+ if (character === "/" && nextCharacter === "*") {
37522
+ sanitizedContent += " ";
37523
+ characterIndex += 1;
37524
+ isInsideComment = true;
37525
+ continue;
37526
+ }
37527
+ if (character === "/" && nextCharacter === "/") {
37528
+ sanitizedContent += " ";
37529
+ characterIndex += 1;
37530
+ isInsideLineComment = true;
37531
+ continue;
37532
+ }
37533
+ if (character === "\"" || character === "'") {
37534
+ sanitizedContent += " ";
37535
+ quote = character;
37536
+ continue;
37537
+ }
37538
+ sanitizedContent += character;
37539
+ }
37540
+ return sanitizedContent;
37541
+ };
37542
+ const findMatchingClosingBrace = (content, openingBraceIndex) => {
37543
+ let depth = 0;
37544
+ for (let characterIndex = openingBraceIndex; characterIndex < content.length; characterIndex += 1) {
37545
+ if (content[characterIndex] === "{") depth += 1;
37546
+ if (content[characterIndex] !== "}") continue;
37547
+ depth -= 1;
37548
+ if (depth === 0) return characterIndex;
37549
+ }
37550
+ return -1;
37551
+ };
37552
+ const hasReducedMotionMediaQuery = (content) => {
37553
+ const sanitizedContent = removeCssCommentsAndStrings(content);
37554
+ REDUCED_MOTION_MEDIA_QUERY_PATTERN.lastIndex = 0;
37555
+ for (const match of sanitizedContent.matchAll(REDUCED_MOTION_MEDIA_QUERY_PATTERN)) {
37556
+ const mediaPrelude = match[1];
37557
+ if (/\bnot\b/i.test(mediaPrelude)) continue;
37558
+ const openingBraceIndex = (match.index ?? 0) + match[0].lastIndexOf("{");
37559
+ const closingBraceIndex = findMatchingClosingBrace(sanitizedContent, openingBraceIndex);
37560
+ if (closingBraceIndex === -1) continue;
37561
+ const body = sanitizedContent.slice(openingBraceIndex + 1, closingBraceIndex);
37562
+ if (CSS_DECLARATION_PATTERN.test(body)) return true;
37563
+ }
37564
+ return false;
37565
+ };
37566
+ const collectProjectMotionEvidence = (rootDirectory) => {
37567
+ const scriptSources = [];
37568
+ let hasReducedMotionHandling = false;
37187
37569
  for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
37188
- if (!REDUCED_MOTION_FILE_EXTENSIONS.has(Path.extname(name))) continue;
37570
+ const extension = Path.extname(name);
37571
+ if (!SCRIPT_FILE_EXTENSIONS.has(extension) && !STYLE_FILE_EXTENSIONS.has(extension)) continue;
37189
37572
  let content;
37190
37573
  try {
37191
37574
  content = NFS.readFileSync(absolutePath, "utf-8");
37192
37575
  } catch {
37193
37576
  continue;
37194
37577
  }
37195
- if (REDUCED_MOTION_PATTERN.test(content)) return true;
37578
+ if (STYLE_FILE_EXTENSIONS.has(extension)) {
37579
+ if (hasReducedMotionMediaQuery(content)) hasReducedMotionHandling = true;
37580
+ continue;
37581
+ }
37582
+ scriptSources.push({
37583
+ fileName: absolutePath,
37584
+ sourceText: content
37585
+ });
37196
37586
  }
37197
- return false;
37587
+ if (scriptSources.length === 0) return {
37588
+ hasMotionUse: false,
37589
+ hasReducedMotionHandling
37590
+ };
37591
+ const scriptEvidence = analyzeReducedMotionSources(scriptSources);
37592
+ const hasMotionUse = scriptEvidence.hasMotionUse;
37593
+ hasReducedMotionHandling ||= scriptEvidence.hasReducedMotionHandling;
37594
+ return {
37595
+ hasMotionUse,
37596
+ hasReducedMotionHandling
37597
+ };
37198
37598
  };
37199
37599
  const checkReducedMotion = (rootDirectory) => {
37200
37600
  const packageJsonPath = Path.join(rootDirectory, "package.json");
37201
37601
  if (!isFile(packageJsonPath)) return [];
37202
- let hasMotionLibrary = false;
37203
37602
  try {
37204
37603
  const packageJson = readPackageJson(packageJsonPath);
37205
37604
  const allDependencies = {
37206
37605
  ...packageJson.dependencies,
37207
37606
  ...packageJson.devDependencies
37208
37607
  };
37209
- hasMotionLibrary = Object.keys(allDependencies).some((packageName) => MOTION_LIBRARY_PACKAGES.has(packageName));
37608
+ if (!Object.keys(allDependencies).some((packageName) => MOTION_LIBRARY_PACKAGES.has(packageName))) return [];
37210
37609
  } catch {
37211
37610
  return [];
37212
37611
  }
37213
- if (!hasMotionLibrary) return [];
37214
- const result = spawnSync("git", [
37215
- "grep",
37216
- "--untracked",
37217
- "-lE",
37218
- REDUCED_MOTION_GREP_PATTERN,
37219
- "--",
37220
- ...REDUCED_MOTION_FILE_GLOBS
37221
- ], {
37222
- cwd: rootDirectory,
37223
- encoding: "utf-8",
37224
- stdio: [
37225
- "ignore",
37226
- "pipe",
37227
- "pipe"
37228
- ]
37229
- });
37230
- if (!(!result.error && (result.status === 0 || result.status === GIT_GREP_NO_MATCH_STATUS))) return hasReducedMotionHandlingViaFilesystem(rootDirectory) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
37231
- return result.status === 0 && result.stdout.split("\n").some((filePath) => filePath.length > 0 && !hasIgnoredPathSegment(filePath)) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
37612
+ const evidence = collectProjectMotionEvidence(rootDirectory);
37613
+ return evidence.hasMotionUse && !evidence.hasReducedMotionHandling ? [MISSING_REDUCED_MOTION_DIAGNOSTIC] : [];
37232
37614
  };
37233
37615
  const buildSecurityScanDiagnostic = (finding, entry, relativePath) => ({
37234
37616
  filePath: relativePath,
@@ -39831,23 +40213,12 @@ const REACT_USE_BINDING_RESOLUTION = {
39831
40213
  isReactUseBinding: true,
39832
40214
  isReactNamespaceBinding: false
39833
40215
  };
39834
- const getScriptKind$2 = (filename) => {
39835
- if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
39836
- if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
39837
- if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
39838
- return ts.ScriptKind.JS;
39839
- };
39840
40216
  const getUtf16Offset$1 = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
39841
- const unwrapExpression = (expression) => {
39842
- let currentExpression = expression;
39843
- while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
39844
- return currentExpression;
39845
- };
39846
40217
  const getStaticPropertyName = (node) => {
39847
40218
  if (!node) return null;
39848
40219
  if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node)) return node.text;
39849
40220
  if (ts.isComputedPropertyName(node)) {
39850
- const expression = unwrapExpression(node.expression);
40221
+ const expression = unwrapTypescriptExpression(node.expression);
39851
40222
  if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) return expression.text;
39852
40223
  }
39853
40224
  return null;
@@ -39876,7 +40247,7 @@ const isReactUseObjectBindingElement = (bindingElement) => {
39876
40247
  return getStaticPropertyName(bindingElement.propertyName) === USE_IDENTIFIER;
39877
40248
  };
39878
40249
  const isReactRequireCall = (expression) => {
39879
- const unwrappedExpression = unwrapExpression(expression);
40250
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
39880
40251
  return ts.isCallExpression(unwrappedExpression) && ts.isIdentifier(unwrappedExpression.expression) && unwrappedExpression.expression.text === REQUIRE_IDENTIFIER && unwrappedExpression.arguments.length === 1 && ts.isStringLiteral(unwrappedExpression.arguments[0]) && unwrappedExpression.arguments[0].text === REACT_MODULE_SOURCE;
39881
40252
  };
39882
40253
  const getModuleSource = (node) => {
@@ -39978,7 +40349,7 @@ const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
39978
40349
  return false;
39979
40350
  };
39980
40351
  const isReactNamespaceExpression = (expression, reactImportBindings, sourceFile, visitedDeclarations) => {
39981
- const unwrappedExpression = unwrapExpression(expression);
40352
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
39982
40353
  if (isReactRequireCall(unwrappedExpression)) return true;
39983
40354
  if (!ts.isIdentifier(unwrappedExpression)) return false;
39984
40355
  if (reactImportBindings.namespaceNames.has(unwrappedExpression.text) && !isIdentifierShadowedByLocalBinding(unwrappedExpression, sourceFile)) return true;
@@ -39986,7 +40357,7 @@ const isReactNamespaceExpression = (expression, reactImportBindings, sourceFile,
39986
40357
  };
39987
40358
  const isReactUseExpression = (expression, reactImportBindings, sourceFile, visitedDeclarations) => {
39988
40359
  if (!expression) return false;
39989
- const unwrappedExpression = unwrapExpression(expression);
40360
+ const unwrappedExpression = unwrapTypescriptExpression(expression);
39990
40361
  if (ts.isIdentifier(unwrappedExpression)) {
39991
40362
  if (reactImportBindings.useImportNames.has(unwrappedExpression.text) && !isIdentifierShadowedByLocalBinding(unwrappedExpression, sourceFile)) return true;
39992
40363
  if (unwrappedExpression.text === USE_IDENTIFIER) return false;
@@ -40086,7 +40457,7 @@ const findUseCallIdentifier = (sourceFile, useOffset) => {
40086
40457
  return matchedIdentifier;
40087
40458
  };
40088
40459
  const resolveUseCallBinding = (sourceText, filename, utf8Offset) => {
40089
- const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getScriptKind$2(filename));
40460
+ const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getTypescriptScriptKind(filename));
40090
40461
  const useIdentifier = findUseCallIdentifier(sourceFile, getUtf16Offset$1(sourceText, utf8Offset));
40091
40462
  if (!useIdentifier) return null;
40092
40463
  return resolveIdentifierBinding(useIdentifier, collectReactImportBindings(sourceFile), sourceFile);
@@ -40122,12 +40493,6 @@ const WORKLET_ACCEPTING_CALLEES = new Set([
40122
40493
  "executeOnUIRuntimeSync"
40123
40494
  ]);
40124
40495
  const GESTURE_ROOT_IDENTIFIER = "Gesture";
40125
- const getScriptKind$1 = (filename) => {
40126
- if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
40127
- if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
40128
- if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
40129
- return ts.ScriptKind.JS;
40130
- };
40131
40496
  const getUtf16Offset = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
40132
40497
  const hasWorkletDirective = (node) => {
40133
40498
  if (!ts.isFunctionDeclaration(node) && !ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isMethodDeclaration(node)) return false;
@@ -40199,17 +40564,11 @@ const shouldSuppressCompilerFindingInWorklet = (diagnostic, project, rootDirecto
40199
40564
  } catch {
40200
40565
  return false;
40201
40566
  }
40202
- return isOffsetInsideWorklet(ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getScriptKind$1(absolutePath)), getUtf16Offset(sourceText, primaryLabel.span.offset));
40567
+ return isOffsetInsideWorklet(ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getTypescriptScriptKind(absolutePath)), getUtf16Offset(sourceText, primaryLabel.span.offset));
40203
40568
  };
40204
40569
  const MANUAL_MEMOIZATION_PLUGIN = "react-doctor";
40205
40570
  const MANUAL_MEMOIZATION_RULE = "react-compiler-no-manual-memoization";
40206
40571
  const REACT_COMPILER_PLUGIN = "react-hooks-js";
40207
- const getScriptKind = (filename) => {
40208
- if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
40209
- if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
40210
- if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
40211
- return ts.ScriptKind.JS;
40212
- };
40213
40572
  const isManualMemoizationDiagnostic = (diagnostic) => diagnostic.plugin === MANUAL_MEMOIZATION_PLUGIN && diagnostic.rule === MANUAL_MEMOIZATION_RULE;
40214
40573
  const nodeLineRange = (sourceFile, node) => ({
40215
40574
  startLine: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1,
@@ -40271,7 +40630,7 @@ const suppressMemoizationInBailedOutFunctions = (diagnostics, rootDirectory) =>
40271
40630
  try {
40272
40631
  const buffer = NFS.readFileSync(absolutePath);
40273
40632
  parsed = {
40274
- sourceFile: ts.createSourceFile(absolutePath, buffer.toString("utf8"), ts.ScriptTarget.Latest, true, getScriptKind(absolutePath)),
40633
+ sourceFile: ts.createSourceFile(absolutePath, buffer.toString("utf8"), ts.ScriptTarget.Latest, true, getTypescriptScriptKind(absolutePath)),
40275
40634
  buffer
40276
40635
  };
40277
40636
  } catch {
@@ -42870,7 +43229,7 @@ const computeConfigFingerprint = (projectDirectory, version) => {
42870
43229
  /** Display name used in client-facing messages and progress titles. */
42871
43230
  const SERVER_DISPLAY_NAME = "React Doctor";
42872
43231
  /** Server version reported in `serverInfo`; injected at build, `dev` from source. */
42873
- const SERVER_VERSION = "0.7.7";
43232
+ const SERVER_VERSION = "0.7.8";
42874
43233
  /** `Diagnostic.source` shown next to every published diagnostic. */
42875
43234
  const DIAGNOSTIC_SOURCE = "react-doctor";
42876
43235
  /**
@@ -43073,7 +43432,9 @@ const toLspDiagnostic = (input) => {
43073
43432
  line: diagnostic.line,
43074
43433
  column: diagnostic.column,
43075
43434
  plugin: diagnostic.plugin,
43076
- rule: diagnostic.rule
43435
+ rule: diagnostic.rule,
43436
+ severity: diagnostic.severity,
43437
+ message: diagnostic.message
43077
43438
  }),
43078
43439
  plugin: diagnostic.plugin,
43079
43440
  rule: diagnostic.rule,
@@ -44915,5 +45276,5 @@ const startLanguageServer = () => {
44915
45276
  };
44916
45277
  //#endregion
44917
45278
  export { startLanguageServer };
44918
- !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]="64a3133a-c62e-5131-9413-879f051371ef")}catch(e){}}();
44919
- //# debugId=64a3133a-c62e-5131-9413-879f051371ef
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]="6f5aad14-63ee-530d-a972-9d9330e3a155")}catch(e){}}();
45280
+ //# debugId=6f5aad14-63ee-530d-a972-9d9330e3a155