react-doctor 0.7.7-dev.e632f8a → 0.7.7-dev.ec144d9

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 +77 -450
  2. package/dist/index.js +74 -435
  3. package/dist/lsp.js +74 -435
  4. package/package.json +4 -4
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]="81733cc9-f550-5459-9418-8ab3751a3ea3")}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]="50d648e9-77ea-5f0f-87a2-6d2a2461613e")}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";
@@ -9,8 +9,6 @@ import * as NFS from "node:fs";
9
9
  import fs, { mkdtempSync, rmSync } from "node:fs";
10
10
  import process$1 from "node:process";
11
11
  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";
12
- import * as Crypto from "node:crypto";
13
- import crypto, { createHash, randomUUID } from "node:crypto";
14
12
  import ts from "typescript";
15
13
  import * as OS from "node:os";
16
14
  import os, { tmpdir } from "node:os";
@@ -18,6 +16,8 @@ import { parseJSON5 } from "confbox";
18
16
  import * as NodeUrl from "node:url";
19
17
  import { fileURLToPath, pathToFileURL } from "node:url";
20
18
  import { createJiti } from "jiti";
19
+ import * as Crypto from "node:crypto";
20
+ import crypto, { createHash, randomUUID } from "node:crypto";
21
21
  import { ANALYZED_MANIFEST_FILENAMES, DEFAULT_EXTENSIONS } from "deslop-js/analyzed-inputs";
22
22
  import { gzipSync } from "node:zlib";
23
23
  import * as Sentry from "@sentry/node";
@@ -22437,13 +22437,12 @@ var JsonReportDiagnosticV3 = class extends Class("JsonReportDiagnosticV3")({
22437
22437
  fixGroupId: optional(String$1)
22438
22438
  }) {};
22439
22439
  /**
22440
- * Deterministic identity string for a retained diagnostic occurrence.
22441
- * Severity and message distinguish content variants at one normalized site.
22440
+ * Deterministic identity string for a diagnostic. Same diagnostic
22441
+ * across two scans yields the same identity; lets baselines,
22442
+ * suppression files, content-hash caches, and IDE "ignore this"
22443
+ * actions all key off one shared shape.
22442
22444
  */
22443
- const buildDiagnosticIdentity = (input) => {
22444
- const occurrenceDigest = createHash("sha256").update(JSON.stringify([input.severity, input.message])).digest("hex");
22445
- return `${input.filePath}::${input.line}:${input.column}::${input.plugin}/${input.rule}::${occurrenceDigest}`;
22446
- };
22445
+ const buildDiagnosticIdentity = (input) => `${input.filePath}::${input.line}:${input.column}::${input.plugin}/${input.rule}`;
22447
22446
  const JsonReportMode = Literals([
22448
22447
  "full",
22449
22448
  "diff",
@@ -40411,45 +40410,18 @@ const checkReactServerComponentsAdvisory = (scanDirectory, project) => {
40411
40410
  }
40412
40411
  return diagnostics;
40413
40412
  };
40414
- const getTypescriptScriptKind = (fileName) => {
40415
- if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
40416
- if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
40417
- if (fileName.endsWith(".ts")) return ts.ScriptKind.TS;
40418
- return ts.ScriptKind.JS;
40419
- };
40420
- const unwrapTypescriptExpression = (expression) => {
40421
- let currentExpression = expression;
40422
- while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
40423
- return currentExpression;
40424
- };
40425
- const EMPTY_MOTION_EXPRESSION_EVIDENCE = {
40426
- isAnimationFunction: false,
40427
- isMotionComponent: false,
40428
- isMotionComponentFactory: false,
40429
- isMotionComponentNamespace: false,
40430
- isMotionConfig: false,
40431
- isMotionNamespace: false,
40432
- isReducedMotionHook: false
40433
- };
40434
- const MOTION_COMPONENT_FACTORY_EXPORT_NAMES = new Set(["m", "motion"]);
40435
- const MOTION_COMPONENT_NAMESPACE_EXPORT_NAMES = new Set(["Reorder"]);
40436
- const MOTION_COMPONENT_NAMESPACE_MEMBER_NAMES = new Set(["Item"]);
40437
- const MOTION_ANIMATION_FUNCTION_EXPORT_NAMES = new Set(["animate"]);
40438
- const REDUCED_MOTION_HOOK_EXPORT_NAME = "useReducedMotion";
40439
- const MOTION_CONFIG_EXPORT_NAME = "MotionConfig";
40440
- const REDUCED_MOTION_PROP_NAME = "reducedMotion";
40441
- const REDUCED_MOTION_CONFIG_VALUES = new Set(["always", "user"]);
40442
- const SCRIPT_MODULE_EXTENSIONS = [
40413
+ const REDUCED_MOTION_GREP_PATTERN = "prefers-reduced-motion|useReducedMotion|MotionConfig|reducedMotion";
40414
+ const REDUCED_MOTION_PATTERN = new RegExp(REDUCED_MOTION_GREP_PATTERN);
40415
+ const REDUCED_MOTION_FILE_EXTENSIONS = new Set([
40443
40416
  ".ts",
40444
40417
  ".tsx",
40445
40418
  ".js",
40446
- ".jsx"
40447
- ];
40448
- const SCRIPT_FILE_EXTENSIONS = new Set(SCRIPT_MODULE_EXTENSIONS);
40449
- const STYLE_FILE_EXTENSIONS = new Set([".css", ".scss"]);
40450
- const MOTION_SOURCE_PREFILTER = /framer-motion|["']motion(?:\/[A-Za-z0-9_./-]+)?["']|MotionConfig|useReducedMotion/;
40451
- const REDUCED_MOTION_MEDIA_QUERY_PATTERN = /@media\s+([^{}]*\(\s*prefers-reduced-motion\s*:\s*reduce\s*\)[^{}]*)\{/gi;
40452
- const CSS_DECLARATION_PATTERN = /(?:^|[;{])\s*[-_A-Za-z][-_A-Za-z0-9]*\s*:/;
40419
+ ".jsx",
40420
+ ".css",
40421
+ ".scss"
40422
+ ]);
40423
+ const REDUCED_MOTION_FILE_GLOBS = [...REDUCED_MOTION_FILE_EXTENSIONS].map((extension) => `*${extension}`);
40424
+ const GIT_GREP_NO_MATCH_STATUS = 1;
40453
40425
  const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
40454
40426
  filePath: "package.json",
40455
40427
  plugin: "react-doctor",
@@ -40461,406 +40433,52 @@ const MISSING_REDUCED_MOTION_DIAGNOSTIC = {
40461
40433
  column: 0,
40462
40434
  category: "Accessibility"
40463
40435
  };
40464
- const isMotionModuleSource = (moduleSource) => {
40465
- for (const packageName of MOTION_LIBRARY_PACKAGES) if (moduleSource === packageName || moduleSource.startsWith(`${packageName}/`)) return true;
40466
- return false;
40467
- };
40468
- const classifyMotionExport = (exportName) => ({
40469
- isAnimationFunction: MOTION_ANIMATION_FUNCTION_EXPORT_NAMES.has(exportName),
40470
- isMotionComponent: false,
40471
- isMotionComponentFactory: MOTION_COMPONENT_FACTORY_EXPORT_NAMES.has(exportName),
40472
- isMotionComponentNamespace: MOTION_COMPONENT_NAMESPACE_EXPORT_NAMES.has(exportName),
40473
- isMotionConfig: exportName === MOTION_CONFIG_EXPORT_NAME,
40474
- isMotionNamespace: false,
40475
- isReducedMotionHook: exportName === REDUCED_MOTION_HOOK_EXPORT_NAME
40476
- });
40477
- const getImportModuleSource = (node) => {
40478
- let currentNode = node;
40479
- while (currentNode) {
40480
- if (ts.isImportDeclaration(currentNode) && ts.isStringLiteral(currentNode.moduleSpecifier)) return currentNode.moduleSpecifier.text;
40481
- currentNode = currentNode.parent;
40482
- }
40483
- return null;
40484
- };
40485
- const getImportedBindingEvidence = (declaration, typeChecker, program, visitedSymbols) => {
40486
- const moduleSource = getImportModuleSource(declaration);
40487
- if (!moduleSource) return null;
40488
- if (isMotionModuleSource(moduleSource) && ts.isNamespaceImport(declaration)) return {
40489
- ...EMPTY_MOTION_EXPRESSION_EVIDENCE,
40490
- isMotionNamespace: true
40491
- };
40492
- if (isMotionModuleSource(moduleSource) && ts.isImportSpecifier(declaration)) {
40493
- if (declaration.isTypeOnly) return null;
40494
- return classifyMotionExport(declaration.propertyName?.text ?? declaration.name.text);
40495
- }
40496
- if (isMotionModuleSource(moduleSource) && ts.isImportClause(declaration)) {
40497
- if (declaration.isTypeOnly) return null;
40498
- return EMPTY_MOTION_EXPRESSION_EVIDENCE;
40499
- }
40500
- if (ts.isImportSpecifier(declaration) && !declaration.isTypeOnly || ts.isImportClause(declaration) && !declaration.isTypeOnly && declaration.name) {
40501
- const importedName = ts.isImportSpecifier(declaration) ? declaration.propertyName?.text ?? declaration.name.text : "default";
40502
- const moduleSourceFile = getLocalModuleSourceFile(moduleSource, declaration.getSourceFile().fileName, program);
40503
- if (!moduleSourceFile) return null;
40504
- return resolveModuleExportEvidence(moduleSourceFile, importedName, typeChecker, program, visitedSymbols);
40505
- }
40506
- return null;
40507
- };
40508
- const getLocalModuleSourceFile = (moduleSource, importingFileName, program) => {
40509
- if (!moduleSource.startsWith(".")) return null;
40510
- const moduleBasePath = Path.resolve(Path.dirname(importingFileName), moduleSource);
40511
- const moduleBaseExtension = Path.extname(moduleBasePath);
40512
- const typescriptModuleBasePath = moduleBaseExtension === ".js" || moduleBaseExtension === ".jsx" ? moduleBasePath.slice(0, -moduleBaseExtension.length) : null;
40513
- const candidates = [
40514
- moduleBasePath,
40515
- ...typescriptModuleBasePath ? [
40516
- `${typescriptModuleBasePath}.ts`,
40517
- `${typescriptModuleBasePath}.tsx`,
40518
- Path.join(typescriptModuleBasePath, "index.ts"),
40519
- Path.join(typescriptModuleBasePath, "index.tsx")
40520
- ] : [],
40521
- ...SCRIPT_MODULE_EXTENSIONS.map((extension) => `${moduleBasePath}${extension}`),
40522
- ...SCRIPT_MODULE_EXTENSIONS.map((extension) => Path.join(moduleBasePath, `index${extension}`))
40523
- ];
40524
- for (const candidate of candidates) {
40525
- const sourceFile = program.getSourceFile(candidate);
40526
- if (sourceFile) return sourceFile;
40527
- }
40528
- return null;
40529
- };
40530
- const resolveModuleExportEvidence = (sourceFile, exportName, typeChecker, program, visitedSymbols) => {
40531
- const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
40532
- if (moduleSymbol && visitedSymbols.has(moduleSymbol)) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
40533
- const nextVisitedSymbols = new Set(visitedSymbols);
40534
- if (moduleSymbol) nextVisitedSymbols.add(moduleSymbol);
40535
- for (const statement of sourceFile.statements) {
40536
- if (exportName === "default" && ts.isExportAssignment(statement) && !statement.isExportEquals) {
40537
- const evidence = resolveMotionExpressionEvidence(statement.expression, typeChecker, program, nextVisitedSymbols);
40538
- if (hasMotionExpressionEvidence(evidence)) return evidence;
40539
- continue;
40540
- }
40541
- if (!ts.isExportDeclaration(statement) || !statement.moduleSpecifier) continue;
40542
- if (statement.isTypeOnly) continue;
40543
- if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
40544
- const moduleSource = statement.moduleSpecifier.text;
40545
- if (!statement.exportClause) {
40546
- if (isMotionModuleSource(moduleSource)) {
40547
- const evidence = classifyMotionExport(exportName);
40548
- if (hasMotionExpressionEvidence(evidence)) return evidence;
40549
- continue;
40550
- }
40551
- const moduleSourceFile = getLocalModuleSourceFile(moduleSource, sourceFile.fileName, program);
40552
- if (moduleSourceFile) {
40553
- const evidence = resolveModuleExportEvidence(moduleSourceFile, exportName, typeChecker, program, nextVisitedSymbols);
40554
- if (hasMotionExpressionEvidence(evidence)) return evidence;
40555
- }
40556
- continue;
40557
- }
40558
- if (!ts.isNamedExports(statement.exportClause)) continue;
40559
- for (const exportSpecifier of statement.exportClause.elements) {
40560
- if (exportSpecifier.name.text !== exportName || exportSpecifier.isTypeOnly) continue;
40561
- const sourceExportName = exportSpecifier.propertyName?.text ?? exportSpecifier.name.text;
40562
- if (isMotionModuleSource(moduleSource)) return classifyMotionExport(sourceExportName);
40563
- const moduleSourceFile = getLocalModuleSourceFile(moduleSource, sourceFile.fileName, program);
40564
- if (!moduleSourceFile) continue;
40565
- return resolveModuleExportEvidence(moduleSourceFile, sourceExportName, typeChecker, program, nextVisitedSymbols);
40566
- }
40567
- }
40568
- if (!moduleSymbol) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
40569
- const exportedSymbol = typeChecker.getExportsOfModule(moduleSymbol).find((candidateSymbol) => candidateSymbol.name === exportName);
40570
- if (!exportedSymbol || nextVisitedSymbols.has(exportedSymbol)) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
40571
- nextVisitedSymbols.add(exportedSymbol);
40572
- let resolvedEvidence = EMPTY_MOTION_EXPRESSION_EVIDENCE;
40573
- for (const declaration of exportedSymbol.declarations ?? []) {
40574
- if (ts.isExportSpecifier(declaration)) {
40575
- const targetSymbol = typeChecker.getExportSpecifierLocalTargetSymbol(declaration);
40576
- for (const targetDeclaration of targetSymbol?.declarations ?? []) {
40577
- const importedEvidence = getImportedBindingEvidence(targetDeclaration, typeChecker, program, nextVisitedSymbols);
40578
- if (importedEvidence) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, importedEvidence);
40579
- if (ts.isVariableDeclaration(targetDeclaration) && targetDeclaration.initializer) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, resolveMotionExpressionEvidence(targetDeclaration.initializer, typeChecker, program, nextVisitedSymbols));
40580
- }
40581
- }
40582
- if (ts.isVariableDeclaration(declaration) && declaration.initializer) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, resolveMotionExpressionEvidence(declaration.initializer, typeChecker, program, nextVisitedSymbols));
40583
- }
40584
- return resolvedEvidence;
40585
- };
40586
- const mergeMotionExpressionEvidence = (leftEvidence, rightEvidence) => ({
40587
- isAnimationFunction: leftEvidence.isAnimationFunction || rightEvidence.isAnimationFunction,
40588
- isMotionComponent: leftEvidence.isMotionComponent || rightEvidence.isMotionComponent,
40589
- isMotionComponentFactory: leftEvidence.isMotionComponentFactory || rightEvidence.isMotionComponentFactory,
40590
- isMotionComponentNamespace: leftEvidence.isMotionComponentNamespace || rightEvidence.isMotionComponentNamespace,
40591
- isMotionConfig: leftEvidence.isMotionConfig || rightEvidence.isMotionConfig,
40592
- isMotionNamespace: leftEvidence.isMotionNamespace || rightEvidence.isMotionNamespace,
40593
- isReducedMotionHook: leftEvidence.isReducedMotionHook || rightEvidence.isReducedMotionHook
40594
- });
40595
- const hasMotionExpressionEvidence = (evidence) => evidence.isAnimationFunction || evidence.isMotionComponent || evidence.isMotionComponentFactory || evidence.isMotionComponentNamespace || evidence.isMotionConfig || evidence.isMotionNamespace || evidence.isReducedMotionHook;
40596
- const classifyMotionMember = (receiverEvidence, memberName) => {
40597
- if (receiverEvidence.isMotionNamespace) return classifyMotionExport(memberName);
40598
- if (receiverEvidence.isMotionComponentFactory) return {
40599
- ...EMPTY_MOTION_EXPRESSION_EVIDENCE,
40600
- isMotionComponent: true
40601
- };
40602
- if (receiverEvidence.isMotionComponentNamespace && MOTION_COMPONENT_NAMESPACE_MEMBER_NAMES.has(memberName)) return {
40603
- ...EMPTY_MOTION_EXPRESSION_EVIDENCE,
40604
- isMotionComponent: true
40605
- };
40606
- return EMPTY_MOTION_EXPRESSION_EVIDENCE;
40607
- };
40608
- const resolveMotionExpressionEvidence = (expression, typeChecker, program, visitedSymbols = /* @__PURE__ */ new Set()) => {
40609
- const unwrappedExpression = unwrapTypescriptExpression(expression);
40610
- if (ts.isIdentifier(unwrappedExpression)) {
40611
- const symbol = typeChecker.getSymbolAtLocation(unwrappedExpression);
40612
- if (!symbol || visitedSymbols.has(symbol)) return EMPTY_MOTION_EXPRESSION_EVIDENCE;
40613
- const nextVisitedSymbols = new Set(visitedSymbols);
40614
- nextVisitedSymbols.add(symbol);
40615
- let resolvedEvidence = EMPTY_MOTION_EXPRESSION_EVIDENCE;
40616
- for (const declaration of symbol.declarations ?? []) {
40617
- const importedEvidence = getImportedBindingEvidence(declaration, typeChecker, program, nextVisitedSymbols);
40618
- if (importedEvidence) {
40619
- resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, importedEvidence);
40620
- continue;
40621
- }
40622
- if (ts.isVariableDeclaration(declaration) && declaration.initializer) resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, resolveMotionExpressionEvidence(declaration.initializer, typeChecker, program, nextVisitedSymbols));
40623
- if (ts.isBindingElement(declaration) && ts.isObjectBindingPattern(declaration.parent) && ts.isVariableDeclaration(declaration.parent.parent) && declaration.parent.parent.initializer) {
40624
- const propertyName = declaration.propertyName ?? declaration.name;
40625
- if (ts.isIdentifier(propertyName) || ts.isStringLiteral(propertyName)) {
40626
- const receiverEvidence = resolveMotionExpressionEvidence(declaration.parent.parent.initializer, typeChecker, program, nextVisitedSymbols);
40627
- resolvedEvidence = mergeMotionExpressionEvidence(resolvedEvidence, classifyMotionMember(receiverEvidence, propertyName.text));
40628
- }
40629
- }
40630
- }
40631
- return resolvedEvidence;
40632
- }
40633
- if (ts.isPropertyAccessExpression(unwrappedExpression)) return classifyMotionMember(resolveMotionExpressionEvidence(unwrappedExpression.expression, typeChecker, program, visitedSymbols), unwrappedExpression.name.text);
40634
- 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);
40635
- if (ts.isCallExpression(unwrappedExpression)) {
40636
- 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 {
40637
- ...EMPTY_MOTION_EXPRESSION_EVIDENCE,
40638
- isMotionNamespace: true
40639
- };
40640
- if (ts.isPropertyAccessExpression(unwrappedExpression.expression) && unwrappedExpression.expression.name.text === "bind") {
40641
- const boundReceiverEvidence = resolveMotionExpressionEvidence(unwrappedExpression.expression.expression, typeChecker, program, visitedSymbols);
40642
- if (boundReceiverEvidence.isAnimationFunction) return boundReceiverEvidence;
40643
- }
40644
- const calleeEvidence = resolveMotionExpressionEvidence(unwrappedExpression.expression, typeChecker, program, visitedSymbols);
40645
- if (calleeEvidence.isMotionComponentFactory) return {
40646
- ...EMPTY_MOTION_EXPRESSION_EVIDENCE,
40647
- isMotionComponent: true
40648
- };
40649
- return calleeEvidence;
40650
- }
40651
- return EMPTY_MOTION_EXPRESSION_EVIDENCE;
40652
- };
40653
- const getStaticStringExpressionValue = (expression, typeChecker, visitedSymbols = /* @__PURE__ */ new Set()) => {
40654
- const unwrappedExpression = unwrapTypescriptExpression(expression);
40655
- if (ts.isStringLiteral(unwrappedExpression) || ts.isNoSubstitutionTemplateLiteral(unwrappedExpression)) return unwrappedExpression.text;
40656
- if (!ts.isIdentifier(unwrappedExpression)) return null;
40657
- const symbol = typeChecker.getSymbolAtLocation(unwrappedExpression);
40658
- if (!symbol || visitedSymbols.has(symbol)) return null;
40659
- const nextVisitedSymbols = new Set(visitedSymbols);
40660
- nextVisitedSymbols.add(symbol);
40661
- for (const declaration of symbol.declarations ?? []) {
40662
- if (!ts.isVariableDeclaration(declaration) || !declaration.initializer) continue;
40663
- if (!ts.isVariableDeclarationList(declaration.parent)) continue;
40664
- if (!(declaration.parent.flags & ts.NodeFlags.Const)) continue;
40665
- const value = getStaticStringExpressionValue(declaration.initializer, typeChecker, nextVisitedSymbols);
40666
- if (value !== null) return value;
40667
- }
40668
- return null;
40669
- };
40670
- const getStaticJsxAttributeValue = (attribute, typeChecker) => {
40671
- if (!attribute.initializer) return null;
40672
- if (ts.isStringLiteral(attribute.initializer)) return attribute.initializer.text;
40673
- if (!ts.isJsxExpression(attribute.initializer) || !attribute.initializer.expression) return null;
40674
- return getStaticStringExpressionValue(attribute.initializer.expression, typeChecker);
40675
- };
40676
- const isExpressionValueConsumed = (expression) => {
40677
- let currentExpression = expression;
40678
- while (ts.isParenthesizedExpression(currentExpression.parent) || ts.isAsExpression(currentExpression.parent) || ts.isSatisfiesExpression(currentExpression.parent) || ts.isNonNullExpression(currentExpression.parent) || ts.isTypeAssertionExpression(currentExpression.parent)) currentExpression = currentExpression.parent;
40679
- return !ts.isExpressionStatement(currentExpression.parent) && !ts.isVoidExpression(currentExpression.parent);
40680
- };
40681
- 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) ?? ""));
40682
- const collectScriptMotionEvidence = (sourceFile, typeChecker, program) => {
40683
- const evidence = {
40684
- hasMotionUse: false,
40685
- hasReducedMotionHandling: false
40686
- };
40687
- const visitNode = (node) => {
40688
- if (ts.isCallExpression(node)) {
40689
- const calleeEvidence = resolveMotionExpressionEvidence(node.expression, typeChecker, program);
40690
- 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;
40691
- if (calleeEvidence.isAnimationFunction || isAnimationFunctionCallViaCallOrApply) evidence.hasMotionUse = true;
40692
- if (calleeEvidence.isReducedMotionHook && isExpressionValueConsumed(node)) evidence.hasReducedMotionHandling = true;
40693
- }
40694
- if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
40695
- const tagEvidence = ts.isJsxNamespacedName(node.tagName) ? EMPTY_MOTION_EXPRESSION_EVIDENCE : resolveMotionExpressionEvidence(node.tagName, typeChecker, program);
40696
- if (tagEvidence.isMotionComponent || tagEvidence.isMotionComponentFactory) evidence.hasMotionUse = true;
40697
- if (tagEvidence.isMotionConfig && jsxElementHasReducedMotionConfiguration(node.attributes, typeChecker)) evidence.hasReducedMotionHandling = true;
40698
- }
40699
- ts.forEachChild(node, visitNode);
40700
- };
40701
- visitNode(sourceFile);
40702
- return evidence;
40703
- };
40704
- const analyzeReducedMotionSources = (sources) => {
40705
- if (!sources.some(({ sourceText }) => MOTION_SOURCE_PREFILTER.test(sourceText))) return {
40706
- hasMotionUse: false,
40707
- hasReducedMotionHandling: false
40708
- };
40709
- const compilerOptions = {
40710
- allowJs: true,
40711
- checkJs: false,
40712
- jsx: ts.JsxEmit.Preserve,
40713
- module: ts.ModuleKind.ESNext,
40714
- moduleResolution: ts.ModuleResolutionKind.Bundler,
40715
- noEmit: true,
40716
- noLib: true,
40717
- noResolve: true,
40718
- skipLibCheck: true,
40719
- target: ts.ScriptTarget.Latest
40720
- };
40721
- const sourceTextByFileName = new Map(sources.map(({ fileName: sourceFileName, sourceText: content }) => [Path.resolve(sourceFileName), content]));
40722
- const compilerHost = ts.createCompilerHost(compilerOptions);
40723
- const getDefaultSourceFile = compilerHost.getSourceFile.bind(compilerHost);
40724
- 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);
40725
- const program = ts.createProgram([...sourceTextByFileName.keys()], compilerOptions, compilerHost);
40726
- const typeChecker = program.getTypeChecker();
40727
- const evidence = {
40728
- hasMotionUse: false,
40729
- hasReducedMotionHandling: false
40730
- };
40731
- for (const sourceFileName of sourceTextByFileName.keys()) {
40732
- const sourceFile = program.getSourceFile(sourceFileName);
40733
- if (!sourceFile) continue;
40734
- const fileEvidence = collectScriptMotionEvidence(sourceFile, typeChecker, program);
40735
- evidence.hasMotionUse ||= fileEvidence.hasMotionUse;
40736
- evidence.hasReducedMotionHandling ||= fileEvidence.hasReducedMotionHandling;
40737
- }
40738
- return evidence;
40739
- };
40740
- const removeCssCommentsAndStrings = (content) => {
40741
- let sanitizedContent = "";
40742
- let quote = null;
40743
- let isInsideComment = false;
40744
- let isInsideLineComment = false;
40745
- for (let characterIndex = 0; characterIndex < content.length; characterIndex += 1) {
40746
- const character = content[characterIndex];
40747
- const nextCharacter = content[characterIndex + 1];
40748
- if (isInsideLineComment) {
40749
- sanitizedContent += character === "\n" ? "\n" : " ";
40750
- if (character === "\n") isInsideLineComment = false;
40751
- continue;
40752
- }
40753
- if (isInsideComment) {
40754
- if (character === "*" && nextCharacter === "/") {
40755
- sanitizedContent += " ";
40756
- characterIndex += 1;
40757
- isInsideComment = false;
40758
- } else sanitizedContent += character === "\n" ? "\n" : " ";
40759
- continue;
40760
- }
40761
- if (quote) {
40762
- if (character === "\\") {
40763
- sanitizedContent += " ";
40764
- characterIndex += 1;
40765
- continue;
40766
- }
40767
- if (character === quote) quote = null;
40768
- sanitizedContent += character === "\n" ? "\n" : " ";
40769
- continue;
40770
- }
40771
- if (character === "/" && nextCharacter === "*") {
40772
- sanitizedContent += " ";
40773
- characterIndex += 1;
40774
- isInsideComment = true;
40775
- continue;
40776
- }
40777
- if (character === "/" && nextCharacter === "/") {
40778
- sanitizedContent += " ";
40779
- characterIndex += 1;
40780
- isInsideLineComment = true;
40781
- continue;
40782
- }
40783
- if (character === "\"" || character === "'") {
40784
- sanitizedContent += " ";
40785
- quote = character;
40786
- continue;
40787
- }
40788
- sanitizedContent += character;
40789
- }
40790
- return sanitizedContent;
40791
- };
40792
- const findMatchingClosingBrace = (content, openingBraceIndex) => {
40793
- let depth = 0;
40794
- for (let characterIndex = openingBraceIndex; characterIndex < content.length; characterIndex += 1) {
40795
- if (content[characterIndex] === "{") depth += 1;
40796
- if (content[characterIndex] !== "}") continue;
40797
- depth -= 1;
40798
- if (depth === 0) return characterIndex;
40799
- }
40800
- return -1;
40801
- };
40802
- const hasReducedMotionMediaQuery = (content) => {
40803
- const sanitizedContent = removeCssCommentsAndStrings(content);
40804
- REDUCED_MOTION_MEDIA_QUERY_PATTERN.lastIndex = 0;
40805
- for (const match of sanitizedContent.matchAll(REDUCED_MOTION_MEDIA_QUERY_PATTERN)) {
40806
- const mediaPrelude = match[1];
40807
- if (/\bnot\b/i.test(mediaPrelude)) continue;
40808
- const openingBraceIndex = (match.index ?? 0) + match[0].lastIndexOf("{");
40809
- const closingBraceIndex = findMatchingClosingBrace(sanitizedContent, openingBraceIndex);
40810
- if (closingBraceIndex === -1) continue;
40811
- const body = sanitizedContent.slice(openingBraceIndex + 1, closingBraceIndex);
40812
- if (CSS_DECLARATION_PATTERN.test(body)) return true;
40813
- }
40814
- return false;
40815
- };
40816
- const collectProjectMotionEvidence = (rootDirectory) => {
40817
- const scriptSources = [];
40818
- let hasReducedMotionHandling = false;
40436
+ const hasReducedMotionHandlingViaFilesystem = (rootDirectory) => {
40819
40437
  for (const { absolutePath, name } of walkSourceTreeFiles(rootDirectory)) {
40820
- const extension = Path.extname(name);
40821
- if (!SCRIPT_FILE_EXTENSIONS.has(extension) && !STYLE_FILE_EXTENSIONS.has(extension)) continue;
40438
+ if (!REDUCED_MOTION_FILE_EXTENSIONS.has(Path.extname(name))) continue;
40822
40439
  let content;
40823
40440
  try {
40824
40441
  content = NFS.readFileSync(absolutePath, "utf-8");
40825
40442
  } catch {
40826
40443
  continue;
40827
40444
  }
40828
- if (STYLE_FILE_EXTENSIONS.has(extension)) {
40829
- if (hasReducedMotionMediaQuery(content)) hasReducedMotionHandling = true;
40830
- continue;
40831
- }
40832
- scriptSources.push({
40833
- fileName: absolutePath,
40834
- sourceText: content
40835
- });
40445
+ if (REDUCED_MOTION_PATTERN.test(content)) return true;
40836
40446
  }
40837
- if (scriptSources.length === 0) return {
40838
- hasMotionUse: false,
40839
- hasReducedMotionHandling
40840
- };
40841
- const scriptEvidence = analyzeReducedMotionSources(scriptSources);
40842
- const hasMotionUse = scriptEvidence.hasMotionUse;
40843
- hasReducedMotionHandling ||= scriptEvidence.hasReducedMotionHandling;
40844
- return {
40845
- hasMotionUse,
40846
- hasReducedMotionHandling
40847
- };
40447
+ return false;
40848
40448
  };
40849
40449
  const checkReducedMotion = (rootDirectory) => {
40850
40450
  const packageJsonPath = Path.join(rootDirectory, "package.json");
40851
40451
  if (!isFile(packageJsonPath)) return [];
40452
+ let hasMotionLibrary = false;
40852
40453
  try {
40853
40454
  const packageJson = readPackageJson$1(packageJsonPath);
40854
40455
  const allDependencies = {
40855
40456
  ...packageJson.dependencies,
40856
40457
  ...packageJson.devDependencies
40857
40458
  };
40858
- if (!Object.keys(allDependencies).some((packageName) => MOTION_LIBRARY_PACKAGES.has(packageName))) return [];
40459
+ hasMotionLibrary = Object.keys(allDependencies).some((packageName) => MOTION_LIBRARY_PACKAGES.has(packageName));
40859
40460
  } catch {
40860
40461
  return [];
40861
40462
  }
40862
- const evidence = collectProjectMotionEvidence(rootDirectory);
40863
- return evidence.hasMotionUse && !evidence.hasReducedMotionHandling ? [MISSING_REDUCED_MOTION_DIAGNOSTIC] : [];
40463
+ if (!hasMotionLibrary) return [];
40464
+ const result = spawnSync("git", [
40465
+ "grep",
40466
+ "--untracked",
40467
+ "-lE",
40468
+ REDUCED_MOTION_GREP_PATTERN,
40469
+ "--",
40470
+ ...REDUCED_MOTION_FILE_GLOBS
40471
+ ], {
40472
+ cwd: rootDirectory,
40473
+ encoding: "utf-8",
40474
+ stdio: [
40475
+ "ignore",
40476
+ "pipe",
40477
+ "pipe"
40478
+ ]
40479
+ });
40480
+ if (!(!result.error && (result.status === 0 || result.status === GIT_GREP_NO_MATCH_STATUS))) return hasReducedMotionHandlingViaFilesystem(rootDirectory) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
40481
+ return result.status === 0 && result.stdout.split("\n").some((filePath) => filePath.length > 0 && !hasIgnoredPathSegment(filePath)) ? [] : [MISSING_REDUCED_MOTION_DIAGNOSTIC];
40864
40482
  };
40865
40483
  const buildSecurityScanDiagnostic = (finding, entry, relativePath) => ({
40866
40484
  filePath: relativePath,
@@ -43479,12 +43097,23 @@ const REACT_USE_BINDING_RESOLUTION = {
43479
43097
  isReactUseBinding: true,
43480
43098
  isReactNamespaceBinding: false
43481
43099
  };
43100
+ const getScriptKind$2 = (filename) => {
43101
+ if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
43102
+ if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
43103
+ if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
43104
+ return ts.ScriptKind.JS;
43105
+ };
43482
43106
  const getUtf16Offset$1 = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
43107
+ const unwrapExpression = (expression) => {
43108
+ let currentExpression = expression;
43109
+ while (ts.isParenthesizedExpression(currentExpression) || ts.isAsExpression(currentExpression) || ts.isSatisfiesExpression(currentExpression) || ts.isNonNullExpression(currentExpression) || ts.isTypeAssertionExpression(currentExpression)) currentExpression = currentExpression.expression;
43110
+ return currentExpression;
43111
+ };
43483
43112
  const getStaticPropertyName = (node) => {
43484
43113
  if (!node) return null;
43485
43114
  if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node)) return node.text;
43486
43115
  if (ts.isComputedPropertyName(node)) {
43487
- const expression = unwrapTypescriptExpression(node.expression);
43116
+ const expression = unwrapExpression(node.expression);
43488
43117
  if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) return expression.text;
43489
43118
  }
43490
43119
  return null;
@@ -43513,7 +43142,7 @@ const isReactUseObjectBindingElement = (bindingElement) => {
43513
43142
  return getStaticPropertyName(bindingElement.propertyName) === USE_IDENTIFIER;
43514
43143
  };
43515
43144
  const isReactRequireCall = (expression) => {
43516
- const unwrappedExpression = unwrapTypescriptExpression(expression);
43145
+ const unwrappedExpression = unwrapExpression(expression);
43517
43146
  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;
43518
43147
  };
43519
43148
  const getModuleSource = (node) => {
@@ -43615,7 +43244,7 @@ const isIdentifierShadowedByLocalBinding = (identifier, sourceFile) => {
43615
43244
  return false;
43616
43245
  };
43617
43246
  const isReactNamespaceExpression = (expression, reactImportBindings, sourceFile, visitedDeclarations) => {
43618
- const unwrappedExpression = unwrapTypescriptExpression(expression);
43247
+ const unwrappedExpression = unwrapExpression(expression);
43619
43248
  if (isReactRequireCall(unwrappedExpression)) return true;
43620
43249
  if (!ts.isIdentifier(unwrappedExpression)) return false;
43621
43250
  if (reactImportBindings.namespaceNames.has(unwrappedExpression.text) && !isIdentifierShadowedByLocalBinding(unwrappedExpression, sourceFile)) return true;
@@ -43623,7 +43252,7 @@ const isReactNamespaceExpression = (expression, reactImportBindings, sourceFile,
43623
43252
  };
43624
43253
  const isReactUseExpression = (expression, reactImportBindings, sourceFile, visitedDeclarations) => {
43625
43254
  if (!expression) return false;
43626
- const unwrappedExpression = unwrapTypescriptExpression(expression);
43255
+ const unwrappedExpression = unwrapExpression(expression);
43627
43256
  if (ts.isIdentifier(unwrappedExpression)) {
43628
43257
  if (reactImportBindings.useImportNames.has(unwrappedExpression.text) && !isIdentifierShadowedByLocalBinding(unwrappedExpression, sourceFile)) return true;
43629
43258
  if (unwrappedExpression.text === USE_IDENTIFIER) return false;
@@ -43723,7 +43352,7 @@ const findUseCallIdentifier = (sourceFile, useOffset) => {
43723
43352
  return matchedIdentifier;
43724
43353
  };
43725
43354
  const resolveUseCallBinding = (sourceText, filename, utf8Offset) => {
43726
- const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getTypescriptScriptKind(filename));
43355
+ const sourceFile = ts.createSourceFile(filename, sourceText, ts.ScriptTarget.Latest, true, getScriptKind$2(filename));
43727
43356
  const useIdentifier = findUseCallIdentifier(sourceFile, getUtf16Offset$1(sourceText, utf8Offset));
43728
43357
  if (!useIdentifier) return null;
43729
43358
  return resolveIdentifierBinding(useIdentifier, collectReactImportBindings(sourceFile), sourceFile);
@@ -43759,6 +43388,12 @@ const WORKLET_ACCEPTING_CALLEES = new Set([
43759
43388
  "executeOnUIRuntimeSync"
43760
43389
  ]);
43761
43390
  const GESTURE_ROOT_IDENTIFIER = "Gesture";
43391
+ const getScriptKind$1 = (filename) => {
43392
+ if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
43393
+ if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
43394
+ if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
43395
+ return ts.ScriptKind.JS;
43396
+ };
43762
43397
  const getUtf16Offset = (sourceText, utf8Offset) => Buffer.from(sourceText).subarray(0, utf8Offset).toString("utf8").length;
43763
43398
  const hasWorkletDirective = (node) => {
43764
43399
  if (!ts.isFunctionDeclaration(node) && !ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isMethodDeclaration(node)) return false;
@@ -43830,11 +43465,17 @@ const shouldSuppressCompilerFindingInWorklet = (diagnostic, project, rootDirecto
43830
43465
  } catch {
43831
43466
  return false;
43832
43467
  }
43833
- return isOffsetInsideWorklet(ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getTypescriptScriptKind(absolutePath)), getUtf16Offset(sourceText, primaryLabel.span.offset));
43468
+ return isOffsetInsideWorklet(ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, getScriptKind$1(absolutePath)), getUtf16Offset(sourceText, primaryLabel.span.offset));
43834
43469
  };
43835
43470
  const MANUAL_MEMOIZATION_PLUGIN = "react-doctor";
43836
43471
  const MANUAL_MEMOIZATION_RULE = "react-compiler-no-manual-memoization";
43837
43472
  const REACT_COMPILER_PLUGIN = "react-hooks-js";
43473
+ const getScriptKind = (filename) => {
43474
+ if (filename.endsWith(".tsx")) return ts.ScriptKind.TSX;
43475
+ if (filename.endsWith(".jsx")) return ts.ScriptKind.JSX;
43476
+ if (filename.endsWith(".ts")) return ts.ScriptKind.TS;
43477
+ return ts.ScriptKind.JS;
43478
+ };
43838
43479
  const isManualMemoizationDiagnostic = (diagnostic) => diagnostic.plugin === MANUAL_MEMOIZATION_PLUGIN && diagnostic.rule === MANUAL_MEMOIZATION_RULE;
43839
43480
  const nodeLineRange = (sourceFile, node) => ({
43840
43481
  startLine: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1,
@@ -43896,7 +43537,7 @@ const suppressMemoizationInBailedOutFunctions = (diagnostics, rootDirectory) =>
43896
43537
  try {
43897
43538
  const buffer = NFS.readFileSync(absolutePath);
43898
43539
  parsed = {
43899
- sourceFile: ts.createSourceFile(absolutePath, buffer.toString("utf8"), ts.ScriptTarget.Latest, true, getTypescriptScriptKind(absolutePath)),
43540
+ sourceFile: ts.createSourceFile(absolutePath, buffer.toString("utf8"), ts.ScriptTarget.Latest, true, getScriptKind(absolutePath)),
43900
43541
  buffer
43901
43542
  };
43902
43543
  } catch {
@@ -46511,9 +46152,7 @@ const toJsonReportDiagnostic = (diagnostic, projectRoot, reportRoot) => {
46511
46152
  line: diagnostic.line,
46512
46153
  column: diagnostic.column,
46513
46154
  plugin: diagnostic.plugin,
46514
- rule: diagnostic.rule,
46515
- severity: diagnostic.severity,
46516
- message: diagnostic.message
46155
+ rule: diagnostic.rule
46517
46156
  }),
46518
46157
  normalizedFilePath,
46519
46158
  category: ruleIdentity.category,
@@ -47135,7 +46774,7 @@ const makeNoopConsole = () => ({
47135
46774
  });
47136
46775
  //#endregion
47137
46776
  //#region src/cli/utils/version.ts
47138
- const VERSION = "0.7.7-dev.e632f8a";
46777
+ const VERSION = "0.7.7-dev.ec144d9";
47139
46778
  //#endregion
47140
46779
  //#region src/cli/utils/json-mode.ts
47141
46780
  let context = null;
@@ -47504,13 +47143,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
47504
47143
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
47505
47144
  * standard `SENTRY_RELEASE` override.
47506
47145
  */
47507
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.7-dev.e632f8a`;
47146
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.7.7-dev.ec144d9`;
47508
47147
  /**
47509
47148
  * Deployment environment shown in Sentry's environment filter. Defaults to
47510
47149
  * `production` for tagged releases and `development` for dev/unbuilt versions,
47511
47150
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
47512
47151
  */
47513
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.7-dev.e632f8a") ? "development" : "production");
47152
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.7.7-dev.ec144d9") ? "development" : "production");
47514
47153
  /**
47515
47154
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
47516
47155
  * (set to `0` to disable tracing) and falls back to
@@ -60027,25 +59666,14 @@ const buildOutcomeAttributes = (input) => {
60027
59666
  const largestRuleBucket = buildRuleBlastRadii(result.diagnostics)[0] ?? null;
60028
59667
  let diagnosticsInTestFiles = 0;
60029
59668
  let diagnosticsInStoryFiles = 0;
60030
- const diagnosticSiteCounts = /* @__PURE__ */ new Map();
60031
59669
  const findingsPerFixGroup = /* @__PURE__ */ new Map();
60032
59670
  for (const diagnostic of result.diagnostics) {
60033
59671
  if (diagnostic.fileContext === "test") diagnosticsInTestFiles += 1;
60034
59672
  if (diagnostic.fileContext === "story") diagnosticsInStoryFiles += 1;
60035
- const diagnosticSite = JSON.stringify([
60036
- diagnostic.filePath,
60037
- diagnostic.line,
60038
- diagnostic.column,
60039
- diagnostic.plugin,
60040
- diagnostic.rule
60041
- ]);
60042
- diagnosticSiteCounts.set(diagnosticSite, (diagnosticSiteCounts.get(diagnosticSite) ?? 0) + 1);
60043
59673
  if (diagnostic.fixGroupId) findingsPerFixGroup.set(diagnostic.fixGroupId, (findingsPerFixGroup.get(diagnostic.fixGroupId) ?? 0) + 1);
60044
59674
  }
60045
59675
  let fixGroupedFindings = 0;
60046
59676
  for (const count of findingsPerFixGroup.values()) fixGroupedFindings += count;
60047
- let sameSiteOccurrences = 0;
60048
- for (const count of diagnosticSiteCounts.values()) sameSiteOccurrences += Math.max(0, count - 1);
60049
59677
  const categoryRollup = {};
60050
59678
  for (const [category, count] of countByCategory) categoryRollup[`category.${toCategoryKey(category)}`] = count;
60051
59679
  const suppressionRollup = {};
@@ -60082,7 +59710,6 @@ const buildOutcomeAttributes = (input) => {
60082
59710
  inStoryFiles: diagnosticsInStoryFiles,
60083
59711
  distinctRules: countByRule.size,
60084
59712
  topRule,
60085
- sameSiteOccurrences,
60086
59713
  fixGroups: findingsPerFixGroup.size,
60087
59714
  fixGroupedFindings,
60088
59715
  ...categoryRollup,
@@ -65788,4 +65415,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
65788
65415
  export {};
65789
65416
 
65790
65417
  //# sourceMappingURL=cli.js.map
65791
- //# debugId=81733cc9-f550-5459-9418-8ab3751a3ea3
65418
+ //# debugId=50d648e9-77ea-5f0f-87a2-6d2a2461613e