react-doctor 0.5.8-dev.e2393c4 → 0.5.8-dev.f028d8b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d3452281-e44f-57c8-9072-be20ba262596")}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]="7fde8867-60e0-5cd4-a9c7-b137ba38f519")}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";
@@ -37681,11 +37681,22 @@ for (const [legacyRuleKey, nativeRuleKey] of Object.entries(LEGACY_RULE_KEY_TO_N
37681
37681
  NATIVE_RULE_KEY_TO_LEGACY_RULE_KEYS.set(nativeRuleKey, aliases);
37682
37682
  }
37683
37683
  const getLegacyRuleKeysForNative = (ruleKey) => NATIVE_RULE_KEY_TO_LEGACY_RULE_KEYS.get(ruleKey) ?? [];
37684
+ const REACT_DOCTOR_RULE_KEY_PREFIX = "react-doctor/";
37684
37685
  const canonicalizeRuleKey = (ruleKey) => {
37685
37686
  const nativeRuleKey = LEGACY_RULE_KEY_TO_NATIVE_RULE_KEY[ruleKey];
37686
37687
  return typeof nativeRuleKey === "string" ? nativeRuleKey : ruleKey;
37687
37688
  };
37688
37689
  const isReactDoctorShortIdOf = (bareRuleKey, qualifiedRuleKey) => !bareRuleKey.includes("/") && qualifiedRuleKey === `react-doctor/${bareRuleKey}`;
37690
+ /**
37691
+ * Canonicalizes a rule key as users write it in config: a legacy alias
37692
+ * (`react/jsx-key`) maps to its native key, and a bare short id (`no-eval`)
37693
+ * qualifies as `react-doctor/<id>` — mirroring `isSameRuleKey`'s matching —
37694
+ * so telemetry groups every spelling of one rule under one key.
37695
+ */
37696
+ const canonicalizeUserRuleKey = (ruleKey) => {
37697
+ const nativeRuleKey = canonicalizeRuleKey(ruleKey);
37698
+ return nativeRuleKey.includes("/") ? nativeRuleKey : `${REACT_DOCTOR_RULE_KEY_PREFIX}${nativeRuleKey}`;
37699
+ };
37689
37700
  const isSameRuleKey = (candidateRuleKey, targetRuleKey) => {
37690
37701
  const canonicalCandidate = canonicalizeRuleKey(candidateRuleKey);
37691
37702
  const canonicalTarget = canonicalizeRuleKey(targetRuleKey);
@@ -38228,6 +38239,21 @@ const buildDiagnosticPipeline = (input) => {
38228
38239
  const fileLinesCache = /* @__PURE__ */ new Map();
38229
38240
  const fileContextCache = /* @__PURE__ */ new Map();
38230
38241
  const libraryFileCache = /* @__PURE__ */ new Map();
38242
+ const suppressions = /* @__PURE__ */ new Map();
38243
+ const suppress = (diagnostic, source) => {
38244
+ const { ruleKey } = getDiagnosticRuleIdentity(diagnostic);
38245
+ const suppressionKey = `${ruleKey}\u0000${source}`;
38246
+ const existing = suppressions.get(suppressionKey);
38247
+ suppressions.set(suppressionKey, existing ? {
38248
+ ...existing,
38249
+ count: existing.count + 1
38250
+ } : {
38251
+ rule: ruleKey,
38252
+ source,
38253
+ count: 1
38254
+ });
38255
+ return null;
38256
+ };
38231
38257
  const isLibraryFile = (filePath) => {
38232
38258
  let cached = libraryFileCache.get(filePath);
38233
38259
  if (cached === void 0) {
@@ -38282,51 +38308,54 @@ const buildDiagnosticPipeline = (input) => {
38282
38308
  const identifierMatch = JSX_NO_UNDEF_IDENTIFIER_PATTERN.exec(diagnostic.message);
38283
38309
  return identifierMatch !== null && runtimeGlobalNames.has(identifierMatch[1]);
38284
38310
  };
38285
- return { apply: (diagnostic) => {
38286
- if (shouldAutoSuppress(diagnostic)) return null;
38287
- let current = diagnostic;
38288
- let explicitSeverityOverride;
38289
- let explicitRuleOverride;
38290
- if (severityControls) {
38291
- const { ruleKey, category } = getDiagnosticRuleIdentity(current);
38292
- explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey }, severityControls);
38293
- explicitSeverityOverride = resolveRuleSeverityOverride({
38294
- ruleKey,
38295
- category
38296
- }, severityControls);
38297
- if (explicitSeverityOverride === "off") return null;
38298
- if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
38299
- }
38300
- if (explicitRuleOverride === void 0) {
38301
- if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
38302
- }
38303
- if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
38304
- if (userConfig) {
38305
- if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return null;
38306
- if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
38307
- if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return null;
38308
- if (isRnRawTextSuppressedByConfig(current)) return null;
38309
- if (isJsxNoUndefSuppressedByConfig(current)) return null;
38310
- }
38311
- if (respectInlineDisables && current.line > 0) {
38312
- const lines = getFileLines(current.filePath);
38313
- if (lines) {
38314
- const ruleIdentifier = `${current.plugin}/${current.rule}`;
38315
- const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
38316
- if (evaluation.isSuppressed) return null;
38317
- if (evaluation.nearMissHint) current = {
38318
- ...current,
38319
- suppressionHint: evaluation.nearMissHint
38320
- };
38311
+ return {
38312
+ apply: (diagnostic) => {
38313
+ if (shouldAutoSuppress(diagnostic)) return null;
38314
+ let current = diagnostic;
38315
+ let explicitSeverityOverride;
38316
+ let explicitRuleOverride;
38317
+ if (severityControls) {
38318
+ const { ruleKey, category } = getDiagnosticRuleIdentity(current);
38319
+ explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey }, severityControls);
38320
+ explicitSeverityOverride = resolveRuleSeverityOverride({
38321
+ ruleKey,
38322
+ category
38323
+ }, severityControls);
38324
+ if (explicitSeverityOverride === "off") return suppress(current, "config");
38325
+ if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
38326
+ }
38327
+ if (explicitRuleOverride === void 0) {
38328
+ if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
38329
+ }
38330
+ if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
38331
+ if (userConfig) {
38332
+ if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return suppress(current, "config");
38333
+ if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
38334
+ if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return suppress(current, "override");
38335
+ if (isRnRawTextSuppressedByConfig(current)) return null;
38336
+ if (isJsxNoUndefSuppressedByConfig(current)) return null;
38337
+ }
38338
+ if (respectInlineDisables && current.line > 0) {
38339
+ const lines = getFileLines(current.filePath);
38340
+ if (lines) {
38341
+ const ruleIdentifier = `${current.plugin}/${current.rule}`;
38342
+ const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
38343
+ if (evaluation.isSuppressed) return suppress(current, "inline");
38344
+ if (evaluation.nearMissHint) current = {
38345
+ ...current,
38346
+ suppressionHint: evaluation.nearMissHint
38347
+ };
38348
+ }
38321
38349
  }
38322
- }
38323
- const fileContext = getFileContext(current.filePath);
38324
- if (fileContext !== "production") current = {
38325
- ...current,
38326
- fileContext
38327
- };
38328
- return current;
38329
- } };
38350
+ const fileContext = getFileContext(current.filePath);
38351
+ if (fileContext !== "production") current = {
38352
+ ...current,
38353
+ fileContext
38354
+ };
38355
+ return current;
38356
+ },
38357
+ summarizeSuppressions: () => [...suppressions.values()]
38358
+ };
38330
38359
  };
38331
38360
  const OxlintUnavailableKind = Literals(["binary-not-found", "native-binding-missing"]);
38332
38361
  var OxlintUnavailable = class extends TaggedErrorClass()("OxlintUnavailable", {
@@ -44256,7 +44285,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
44256
44285
  scanConcurrency,
44257
44286
  supplyChainOverlapTimedOut: supplyChainResult.timedOut,
44258
44287
  lintCacheHitFileCount,
44259
- lintCacheTotalFileCount
44288
+ lintCacheTotalFileCount,
44289
+ suppressedRuleCounts: transform.summarizeSuppressions()
44260
44290
  };
44261
44291
  }).pipe(withSpan("runInspect", { attributes: {
44262
44292
  "inspect.directory": input.directory,
@@ -45059,6 +45089,8 @@ const METRIC = {
45059
45089
  scanCheckSkipped: "scan.check_skipped",
45060
45090
  baselineDegraded: "baseline.degraded",
45061
45091
  ruleFired: "rule.fired",
45092
+ ruleDisabled: "rule.disabled",
45093
+ ruleSuppressed: "rule.suppressed",
45062
45094
  lintFailed: "lint.failed",
45063
45095
  deadCodeFailed: "deadcode.failed",
45064
45096
  scoreUnavailable: "score.unavailable",
@@ -45124,7 +45156,7 @@ const makeNoopConsole = () => ({
45124
45156
  });
45125
45157
  //#endregion
45126
45158
  //#region src/cli/utils/version.ts
45127
- const VERSION = "0.5.8-dev.e2393c4";
45159
+ const VERSION = "0.5.8-dev.f028d8b";
45128
45160
  //#endregion
45129
45161
  //#region src/cli/utils/json-mode.ts
45130
45162
  let context = null;
@@ -45493,13 +45525,13 @@ const isDevVersion = (version) => version === "0.0.0" || version.includes("-");
45493
45525
  * uploads source-map artifacts under, so stack frames symbolicate. Honors the
45494
45526
  * standard `SENTRY_RELEASE` override.
45495
45527
  */
45496
- const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.5.8-dev.e2393c4`;
45528
+ const resolveSentryRelease = () => process.env.SENTRY_RELEASE || `react-doctor@0.5.8-dev.f028d8b`;
45497
45529
  /**
45498
45530
  * Deployment environment shown in Sentry's environment filter. Defaults to
45499
45531
  * `production` for tagged releases and `development` for dev/unbuilt versions,
45500
45532
  * overridable via the standard `SENTRY_ENVIRONMENT` env var.
45501
45533
  */
45502
- const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.5.8-dev.e2393c4") ? "development" : "production");
45534
+ const resolveSentryEnvironment = () => process.env.SENTRY_ENVIRONMENT || (isDevVersion("0.5.8-dev.f028d8b") ? "development" : "production");
45503
45535
  /**
45504
45536
  * Performance-tracing sample rate in `[0, 1]`. Reads `SENTRY_TRACES_SAMPLE_RATE`
45505
45537
  * (set to `0` to disable tracing) and falls back to
@@ -57442,6 +57474,29 @@ const summarizeRuleFirings = (diagnostics) => {
57442
57474
  return [...firings.values()];
57443
57475
  };
57444
57476
  /**
57477
+ * Enumerates the rules a config turns off entirely — `rules: { x: "off" }`
57478
+ * entries and the `ignore.rules` list — with keys canonicalized so every
57479
+ * spelling of one rule (legacy alias, bare short id) groups under one
57480
+ * `rule` attribute in Sentry. Deliberately scan-independent: an `"off"`
57481
+ * lint rule is removed from the generated oxlint config and never fires,
57482
+ * so the per-diagnostic `rule.suppressed` counter can't see it.
57483
+ */
57484
+ const summarizeDisabledRules = (userConfig) => {
57485
+ const disabledRules = /* @__PURE__ */ new Map();
57486
+ const record = (configuredRuleKey, source) => {
57487
+ const rule = canonicalizeUserRuleKey(configuredRuleKey);
57488
+ disabledRules.set(`${rule}\u0000${source}`, {
57489
+ rule,
57490
+ source
57491
+ });
57492
+ };
57493
+ for (const [ruleKey, severity] of Object.entries(userConfig?.rules ?? {})) if (severity === "off") record(ruleKey, "rules");
57494
+ if (Array.isArray(userConfig?.ignore?.rules)) {
57495
+ for (const ruleKey of userConfig.ignore.rules) if (typeof ruleKey === "string") record(ruleKey, "ignore");
57496
+ }
57497
+ return [...disabledRules.values()];
57498
+ };
57499
+ /**
57445
57500
  * Emits the per-scan engineering + product counters/distributions for one
57446
57501
  * `inspect()` run (fires once per project in a workspace scan). Every emission
57447
57502
  * is a no-op unless Sentry is live, and the shared run/project attributes ride
@@ -57480,6 +57535,14 @@ const recordScanMetrics = (input) => {
57480
57535
  category: firing.category,
57481
57536
  severity: firing.severity
57482
57537
  });
57538
+ for (const disabled of summarizeDisabledRules(input.userConfig)) recordCount(METRIC.ruleDisabled, 1, {
57539
+ rule: disabled.rule,
57540
+ source: disabled.source
57541
+ });
57542
+ for (const suppression of input.suppressedRuleCounts) recordCount(METRIC.ruleSuppressed, suppression.count, {
57543
+ rule: suppression.rule,
57544
+ source: suppression.source
57545
+ });
57483
57546
  if (result.diagnostics.length === 0 && !hasSkippedChecks) recordCount(METRIC.scanClean, 1, { mode: input.mode });
57484
57547
  if (result.score) recordDistribution(METRIC.scanScore, result.score.score, { attributes: { mode: input.mode } });
57485
57548
  else if (!input.noScore && !input.didLintFail) recordCount(METRIC.scoreUnavailable, 1, { mode: input.mode });
@@ -57625,6 +57688,19 @@ const buildOutcomeAttributes = (input) => {
57625
57688
  for (const count of findingsPerFixGroup.values()) fixGroupedFindings += count;
57626
57689
  const categoryRollup = {};
57627
57690
  for (const [category, count] of countByCategory) categoryRollup[`category.${toCategoryKey(category)}`] = count;
57691
+ const suppressionRollup = {};
57692
+ if (input.suppressedRuleCounts) {
57693
+ const countBySource = {
57694
+ config: 0,
57695
+ override: 0,
57696
+ inline: 0
57697
+ };
57698
+ for (const suppression of input.suppressedRuleCounts) countBySource[suppression.source] += suppression.count;
57699
+ suppressionRollup.suppressed = countBySource.config + countBySource.override + countBySource.inline;
57700
+ suppressionRollup.suppressedConfig = countBySource.config;
57701
+ suppressionRollup.suppressedOverride = countBySource.override;
57702
+ suppressionRollup.suppressedInline = countBySource.inline;
57703
+ }
57628
57704
  const attributes = {
57629
57705
  ...withNamespace("outcome", {
57630
57706
  status: outcome,
@@ -57645,7 +57721,8 @@ const buildOutcomeAttributes = (input) => {
57645
57721
  topRule,
57646
57722
  fixGroups: findingsPerFixGroup.size,
57647
57723
  fixGroupedFindings,
57648
- ...categoryRollup
57724
+ ...categoryRollup,
57725
+ ...suppressionRollup
57649
57726
  }),
57650
57727
  ...withNamespace("score", {
57651
57728
  value: result.score ? result.score.score : null,
@@ -58998,12 +59075,12 @@ const resolveCacheFilePath = (projectDirectory) => {
58998
59075
  const readPersistedCache = (cacheFilePath) => {
58999
59076
  try {
59000
59077
  const parsed = JSON.parse(fs.readFileSync(cacheFilePath, "utf8"));
59001
- if (!isRecord(parsed) || parsed.version !== 2) return {
59002
- version: 2,
59078
+ if (!isRecord(parsed) || parsed.version !== 3) return {
59079
+ version: 3,
59003
59080
  entries: []
59004
59081
  };
59005
59082
  if (!Array.isArray(parsed.entries)) return {
59006
- version: 2,
59083
+ version: 3,
59007
59084
  entries: []
59008
59085
  };
59009
59086
  const entries = [];
@@ -59013,12 +59090,12 @@ const readPersistedCache = (cacheFilePath) => {
59013
59090
  entries.push(entry);
59014
59091
  }
59015
59092
  return {
59016
- version: 2,
59093
+ version: 3,
59017
59094
  entries
59018
59095
  };
59019
59096
  } catch {
59020
59097
  return {
59021
- version: 2,
59098
+ version: 3,
59022
59099
  entries: []
59023
59100
  };
59024
59101
  }
@@ -59071,7 +59148,7 @@ const buildScanResultCacheKey = (input) => {
59071
59148
  if (headSha === null) return null;
59072
59149
  if (stringifyStableJson(input.userConfig) === null) return null;
59073
59150
  const cacheKeyJson = stringifyStableJson({
59074
- schemaVersion: 2,
59151
+ schemaVersion: 3,
59075
59152
  projectIdentity: resolveProjectIdentity(input.projectDirectory),
59076
59153
  headSha,
59077
59154
  reactDoctorVersion: input.version,
@@ -59109,7 +59186,7 @@ const createScanResultCache = (projectDirectory) => {
59109
59186
  for (const entry of persistedCache.entries) entries.set(entry.key, entry);
59110
59187
  const persist = () => {
59111
59188
  writePersistedCache(cacheFilePath, {
59112
- version: 2,
59189
+ version: 3,
59113
59190
  entries: [...entries.values()].sort((firstEntry, secondEntry) => secondEntry.createdAtMs - firstEntry.createdAtMs).slice(0, 20)
59114
59191
  });
59115
59192
  };
@@ -59443,7 +59520,8 @@ const runInspectWithRuntime = async (directory, options, userConfig, hasConfigOv
59443
59520
  scanConcurrency: output.scanConcurrency,
59444
59521
  baselineDelta,
59445
59522
  lintFailureReasonKind: lintBindingMissing ? "native-binding-missing" : output.lintFailureReasonKind,
59446
- supplyChainOverlapTimedOut: output.supplyChainOverlapTimedOut
59523
+ supplyChainOverlapTimedOut: output.supplyChainOverlapTimedOut,
59524
+ suppressedRuleCounts: output.suppressedRuleCounts
59447
59525
  };
59448
59526
  if (cacheKey !== null && scanResultCache !== null && shouldStoreScanPayload(payload)) scanResultCache.store(cacheKey, payload);
59449
59527
  const result = await renderAndRecordScan({
@@ -59506,7 +59584,9 @@ const renderAndRecordScan = async (input) => {
59506
59584
  noScore: input.options.noScore,
59507
59585
  didLintFail: input.payload.didLintFail,
59508
59586
  lintFailureReasonKind: input.payload.lintFailureReasonKind,
59509
- didDeadCodeFail: input.payload.didDeadCodeFail
59587
+ didDeadCodeFail: input.payload.didDeadCodeFail,
59588
+ userConfig: input.userConfig,
59589
+ suppressedRuleCounts: input.payload.suppressedRuleCounts
59510
59590
  });
59511
59591
  recordRunEvent(input.rootSentrySpan, {
59512
59592
  ...buildRunEventConfig(input.options, input.userConfig, input.hasCustomConfig, resolvedWorkerCount),
@@ -59519,7 +59599,8 @@ const renderAndRecordScan = async (input) => {
59519
59599
  lintDroppedFileCount: countDroppedLintFiles(input.payload.lintPartialFailures),
59520
59600
  didDeadCodeFail: input.payload.didDeadCodeFail,
59521
59601
  supplyChainOverlapTimedOut: input.payload.supplyChainOverlapTimedOut,
59522
- deadCodeOverlapped: input.payload.deadCodeOverlapped
59602
+ deadCodeOverlapped: input.payload.deadCodeOverlapped,
59603
+ suppressedRuleCounts: input.payload.suppressedRuleCounts
59523
59604
  });
59524
59605
  return result;
59525
59606
  };
@@ -63303,4 +63384,4 @@ Promise.resolve().then(() => assertNoRemovedFlags(process.argv)).then(() => prog
63303
63384
  export {};
63304
63385
 
63305
63386
  //# sourceMappingURL=cli.js.map
63306
- //# debugId=d3452281-e44f-57c8-9072-be20ba262596
63387
+ //# debugId=7fde8867-60e0-5cd4-a9c7-b137ba38f519
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1e049c6a-27f7-5c62-8be8-57ce0b987f6f")}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]="3fb133b5-fc1f-519f-8f76-6f1d3bb556ce")}catch(e){}}();
3
3
  import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
4
4
  import { createRequire } from "node:module";
5
5
  import * as NFS from "node:fs";
@@ -35040,6 +35040,21 @@ const buildDiagnosticPipeline = (input) => {
35040
35040
  const fileLinesCache = /* @__PURE__ */ new Map();
35041
35041
  const fileContextCache = /* @__PURE__ */ new Map();
35042
35042
  const libraryFileCache = /* @__PURE__ */ new Map();
35043
+ const suppressions = /* @__PURE__ */ new Map();
35044
+ const suppress = (diagnostic, source) => {
35045
+ const { ruleKey } = getDiagnosticRuleIdentity(diagnostic);
35046
+ const suppressionKey = `${ruleKey}\u0000${source}`;
35047
+ const existing = suppressions.get(suppressionKey);
35048
+ suppressions.set(suppressionKey, existing ? {
35049
+ ...existing,
35050
+ count: existing.count + 1
35051
+ } : {
35052
+ rule: ruleKey,
35053
+ source,
35054
+ count: 1
35055
+ });
35056
+ return null;
35057
+ };
35043
35058
  const isLibraryFile = (filePath) => {
35044
35059
  let cached = libraryFileCache.get(filePath);
35045
35060
  if (cached === void 0) {
@@ -35094,51 +35109,54 @@ const buildDiagnosticPipeline = (input) => {
35094
35109
  const identifierMatch = JSX_NO_UNDEF_IDENTIFIER_PATTERN.exec(diagnostic.message);
35095
35110
  return identifierMatch !== null && runtimeGlobalNames.has(identifierMatch[1]);
35096
35111
  };
35097
- return { apply: (diagnostic) => {
35098
- if (shouldAutoSuppress(diagnostic)) return null;
35099
- let current = diagnostic;
35100
- let explicitSeverityOverride;
35101
- let explicitRuleOverride;
35102
- if (severityControls) {
35103
- const { ruleKey, category } = getDiagnosticRuleIdentity(current);
35104
- explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey }, severityControls);
35105
- explicitSeverityOverride = resolveRuleSeverityOverride({
35106
- ruleKey,
35107
- category
35108
- }, severityControls);
35109
- if (explicitSeverityOverride === "off") return null;
35110
- if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
35111
- }
35112
- if (explicitRuleOverride === void 0) {
35113
- if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
35114
- }
35115
- if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
35116
- if (userConfig) {
35117
- if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return null;
35118
- if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
35119
- if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return null;
35120
- if (isRnRawTextSuppressedByConfig(current)) return null;
35121
- if (isJsxNoUndefSuppressedByConfig(current)) return null;
35122
- }
35123
- if (respectInlineDisables && current.line > 0) {
35124
- const lines = getFileLines(current.filePath);
35125
- if (lines) {
35126
- const ruleIdentifier = `${current.plugin}/${current.rule}`;
35127
- const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
35128
- if (evaluation.isSuppressed) return null;
35129
- if (evaluation.nearMissHint) current = {
35130
- ...current,
35131
- suppressionHint: evaluation.nearMissHint
35132
- };
35112
+ return {
35113
+ apply: (diagnostic) => {
35114
+ if (shouldAutoSuppress(diagnostic)) return null;
35115
+ let current = diagnostic;
35116
+ let explicitSeverityOverride;
35117
+ let explicitRuleOverride;
35118
+ if (severityControls) {
35119
+ const { ruleKey, category } = getDiagnosticRuleIdentity(current);
35120
+ explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey }, severityControls);
35121
+ explicitSeverityOverride = resolveRuleSeverityOverride({
35122
+ ruleKey,
35123
+ category
35124
+ }, severityControls);
35125
+ if (explicitSeverityOverride === "off") return suppress(current, "config");
35126
+ if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
35133
35127
  }
35134
- }
35135
- const fileContext = getFileContext(current.filePath);
35136
- if (fileContext !== "production") current = {
35137
- ...current,
35138
- fileContext
35139
- };
35140
- return current;
35141
- } };
35128
+ if (explicitRuleOverride === void 0) {
35129
+ if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
35130
+ }
35131
+ if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
35132
+ if (userConfig) {
35133
+ if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return suppress(current, "config");
35134
+ if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
35135
+ if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return suppress(current, "override");
35136
+ if (isRnRawTextSuppressedByConfig(current)) return null;
35137
+ if (isJsxNoUndefSuppressedByConfig(current)) return null;
35138
+ }
35139
+ if (respectInlineDisables && current.line > 0) {
35140
+ const lines = getFileLines(current.filePath);
35141
+ if (lines) {
35142
+ const ruleIdentifier = `${current.plugin}/${current.rule}`;
35143
+ const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
35144
+ if (evaluation.isSuppressed) return suppress(current, "inline");
35145
+ if (evaluation.nearMissHint) current = {
35146
+ ...current,
35147
+ suppressionHint: evaluation.nearMissHint
35148
+ };
35149
+ }
35150
+ }
35151
+ const fileContext = getFileContext(current.filePath);
35152
+ if (fileContext !== "production") current = {
35153
+ ...current,
35154
+ fileContext
35155
+ };
35156
+ return current;
35157
+ },
35158
+ summarizeSuppressions: () => [...suppressions.values()]
35159
+ };
35142
35160
  };
35143
35161
  const OxlintUnavailableKind = Literals(["binary-not-found", "native-binding-missing"]);
35144
35162
  var OxlintUnavailable = class extends TaggedErrorClass()("OxlintUnavailable", {
@@ -41024,7 +41042,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41024
41042
  scanConcurrency,
41025
41043
  supplyChainOverlapTimedOut: supplyChainResult.timedOut,
41026
41044
  lintCacheHitFileCount,
41027
- lintCacheTotalFileCount
41045
+ lintCacheTotalFileCount,
41046
+ suppressedRuleCounts: transform.summarizeSuppressions()
41028
41047
  };
41029
41048
  }).pipe(withSpan("runInspect", { attributes: {
41030
41049
  "inspect.directory": input.directory,
@@ -41663,4 +41682,4 @@ const toJsonReport = (result, options) => buildJsonReport({
41663
41682
  export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
41664
41683
 
41665
41684
  //# sourceMappingURL=index.js.map
41666
- //# debugId=1e049c6a-27f7-5c62-8be8-57ce0b987f6f
41685
+ //# debugId=3fb133b5-fc1f-519f-8f76-6f1d3bb556ce
package/dist/lsp.js CHANGED
@@ -35095,6 +35095,21 @@ const buildDiagnosticPipeline = (input) => {
35095
35095
  const fileLinesCache = /* @__PURE__ */ new Map();
35096
35096
  const fileContextCache = /* @__PURE__ */ new Map();
35097
35097
  const libraryFileCache = /* @__PURE__ */ new Map();
35098
+ const suppressions = /* @__PURE__ */ new Map();
35099
+ const suppress = (diagnostic, source) => {
35100
+ const { ruleKey } = getDiagnosticRuleIdentity(diagnostic);
35101
+ const suppressionKey = `${ruleKey}\u0000${source}`;
35102
+ const existing = suppressions.get(suppressionKey);
35103
+ suppressions.set(suppressionKey, existing ? {
35104
+ ...existing,
35105
+ count: existing.count + 1
35106
+ } : {
35107
+ rule: ruleKey,
35108
+ source,
35109
+ count: 1
35110
+ });
35111
+ return null;
35112
+ };
35098
35113
  const isLibraryFile = (filePath) => {
35099
35114
  let cached = libraryFileCache.get(filePath);
35100
35115
  if (cached === void 0) {
@@ -35149,51 +35164,54 @@ const buildDiagnosticPipeline = (input) => {
35149
35164
  const identifierMatch = JSX_NO_UNDEF_IDENTIFIER_PATTERN.exec(diagnostic.message);
35150
35165
  return identifierMatch !== null && runtimeGlobalNames.has(identifierMatch[1]);
35151
35166
  };
35152
- return { apply: (diagnostic) => {
35153
- if (shouldAutoSuppress(diagnostic)) return null;
35154
- let current = diagnostic;
35155
- let explicitSeverityOverride;
35156
- let explicitRuleOverride;
35157
- if (severityControls) {
35158
- const { ruleKey, category } = getDiagnosticRuleIdentity(current);
35159
- explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey }, severityControls);
35160
- explicitSeverityOverride = resolveRuleSeverityOverride({
35161
- ruleKey,
35162
- category
35163
- }, severityControls);
35164
- if (explicitSeverityOverride === "off") return null;
35165
- if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
35166
- }
35167
- if (explicitRuleOverride === void 0) {
35168
- if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
35169
- }
35170
- if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
35171
- if (userConfig) {
35172
- if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return null;
35173
- if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
35174
- if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return null;
35175
- if (isRnRawTextSuppressedByConfig(current)) return null;
35176
- if (isJsxNoUndefSuppressedByConfig(current)) return null;
35177
- }
35178
- if (respectInlineDisables && current.line > 0) {
35179
- const lines = getFileLines(current.filePath);
35180
- if (lines) {
35181
- const ruleIdentifier = `${current.plugin}/${current.rule}`;
35182
- const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
35183
- if (evaluation.isSuppressed) return null;
35184
- if (evaluation.nearMissHint) current = {
35185
- ...current,
35186
- suppressionHint: evaluation.nearMissHint
35187
- };
35167
+ return {
35168
+ apply: (diagnostic) => {
35169
+ if (shouldAutoSuppress(diagnostic)) return null;
35170
+ let current = diagnostic;
35171
+ let explicitSeverityOverride;
35172
+ let explicitRuleOverride;
35173
+ if (severityControls) {
35174
+ const { ruleKey, category } = getDiagnosticRuleIdentity(current);
35175
+ explicitRuleOverride = resolveRuleSeverityOverride({ ruleKey }, severityControls);
35176
+ explicitSeverityOverride = resolveRuleSeverityOverride({
35177
+ ruleKey,
35178
+ category
35179
+ }, severityControls);
35180
+ if (explicitSeverityOverride === "off") return suppress(current, "config");
35181
+ if (explicitSeverityOverride !== void 0) current = restampSeverity(current, explicitSeverityOverride);
35188
35182
  }
35189
- }
35190
- const fileContext = getFileContext(current.filePath);
35191
- if (fileContext !== "production") current = {
35192
- ...current,
35193
- fileContext
35194
- };
35195
- return current;
35196
- } };
35183
+ if (explicitRuleOverride === void 0) {
35184
+ if (isAppOnlyRule(`${current.plugin}/${current.rule}`) && isLibraryFile(current.filePath)) return null;
35185
+ }
35186
+ if (!showWarnings && current.severity === "warning" && explicitSeverityOverride !== "warn") return null;
35187
+ if (userConfig) {
35188
+ if (isRuleIgnored(`${current.plugin}/${current.rule}`)) return suppress(current, "config");
35189
+ if (isFileIgnoredByPatterns(current.filePath, rootDirectory, ignoredFilePatterns)) return null;
35190
+ if (isDiagnosticIgnoredByOverrides(current, rootDirectory, compiledOverrides)) return suppress(current, "override");
35191
+ if (isRnRawTextSuppressedByConfig(current)) return null;
35192
+ if (isJsxNoUndefSuppressedByConfig(current)) return null;
35193
+ }
35194
+ if (respectInlineDisables && current.line > 0) {
35195
+ const lines = getFileLines(current.filePath);
35196
+ if (lines) {
35197
+ const ruleIdentifier = `${current.plugin}/${current.rule}`;
35198
+ const evaluation = evaluateSuppression(lines, current.line - 1, ruleIdentifier);
35199
+ if (evaluation.isSuppressed) return suppress(current, "inline");
35200
+ if (evaluation.nearMissHint) current = {
35201
+ ...current,
35202
+ suppressionHint: evaluation.nearMissHint
35203
+ };
35204
+ }
35205
+ }
35206
+ const fileContext = getFileContext(current.filePath);
35207
+ if (fileContext !== "production") current = {
35208
+ ...current,
35209
+ fileContext
35210
+ };
35211
+ return current;
35212
+ },
35213
+ summarizeSuppressions: () => [...suppressions.values()]
35214
+ };
35197
35215
  };
35198
35216
  const OxlintUnavailableKind = Literals(["binary-not-found", "native-binding-missing"]);
35199
35217
  var OxlintUnavailable = class extends TaggedErrorClass()("OxlintUnavailable", {
@@ -41009,7 +41027,8 @@ const runInspect = (input, hooks = {}) => gen(function* () {
41009
41027
  scanConcurrency,
41010
41028
  supplyChainOverlapTimedOut: supplyChainResult.timedOut,
41011
41029
  lintCacheHitFileCount,
41012
- lintCacheTotalFileCount
41030
+ lintCacheTotalFileCount,
41031
+ suppressedRuleCounts: transform.summarizeSuppressions()
41013
41032
  };
41014
41033
  }).pipe(withSpan("runInspect", { attributes: {
41015
41034
  "inspect.directory": input.directory,
@@ -43047,6 +43066,8 @@ const METRIC = {
43047
43066
  scanCheckSkipped: "scan.check_skipped",
43048
43067
  baselineDegraded: "baseline.degraded",
43049
43068
  ruleFired: "rule.fired",
43069
+ ruleDisabled: "rule.disabled",
43070
+ ruleSuppressed: "rule.suppressed",
43050
43071
  lintFailed: "lint.failed",
43051
43072
  deadCodeFailed: "deadcode.failed",
43052
43073
  scoreUnavailable: "score.unavailable",
@@ -43386,5 +43407,5 @@ const startLanguageServer = () => {
43386
43407
  };
43387
43408
  //#endregion
43388
43409
  export { startLanguageServer };
43389
- !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]="5b21d2c0-25a8-52b7-ae5f-f4cc20771996")}catch(e){}}();
43390
- //# debugId=5b21d2c0-25a8-52b7-ae5f-f4cc20771996
43410
+ !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]="1822e36c-fbae-57bf-bdb9-98afebb9a03b")}catch(e){}}();
43411
+ //# debugId=1822e36c-fbae-57bf-bdb9-98afebb9a03b
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-doctor",
3
- "version": "0.5.8-dev.e2393c4",
3
+ "version": "0.5.8-dev.f028d8b",
4
4
  "description": "Your agent writes bad React. This catches it",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -65,8 +65,8 @@
65
65
  "vscode-languageserver-textdocument": "^1.0.12",
66
66
  "vscode-uri": "^3.1.0",
67
67
  "yaml": "^2.9.0",
68
- "deslop-js": "0.5.8",
69
- "oxlint-plugin-react-doctor": "0.5.8-dev.e2393c4"
68
+ "oxlint-plugin-react-doctor": "0.5.8-dev.f028d8b",
69
+ "deslop-js": "0.5.8"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/babel__code-frame": "^7.27.0",
@@ -74,8 +74,8 @@
74
74
  "@xterm/headless": "^6.0.0",
75
75
  "commander": "^14.0.3",
76
76
  "ora": "^9.4.0",
77
- "@react-doctor/api": "0.5.8",
78
77
  "@react-doctor/core": "0.5.8",
78
+ "@react-doctor/api": "0.5.8",
79
79
  "@react-doctor/language-server": "0.5.8"
80
80
  },
81
81
  "engines": {