@utoo/lint 0.2.7 → 0.2.8

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/README.md CHANGED
@@ -67,6 +67,24 @@ when a rule or a particular code shape cannot be fixed safely. The current
67
67
  [rule status](https://github.com/fireairforce/utoo-lint/blob/main/docs/rule-status.md)
68
68
  lists autofix coverage by rule.
69
69
 
70
+ ## Suppression comments
71
+
72
+ Suppress a rule for the next line of code with `utlint-ignore`:
73
+
74
+ ```js
75
+ // utlint-ignore no-debugger: generated breakpoint
76
+ debugger;
77
+ ```
78
+
79
+ Omit the rule ID to suppress all lint rules for the next line of code. Use
80
+ `utlint-ignore-all` before any code for a file-level suppression, or matching
81
+ `utlint-ignore-start` and `utlint-ignore-end` comments for a range. Line and
82
+ block comments are supported. Parse errors remain visible, and fixes from
83
+ suppressed diagnostics are not applied.
84
+
85
+ Native reports expose suppressed items in `suppressedDiagnostics`; the ESLint
86
+ compatibility API exposes them in `suppressedMessages`.
87
+
70
88
  ## Configuration
71
89
 
72
90
  `utoo-lint` supports two canonical project config formats:
package/index.cjs CHANGED
@@ -514,7 +514,7 @@ class UtooLint {
514
514
  const results = reportToESLintResults(report, {
515
515
  source: code,
516
516
  filePath,
517
- includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0,
517
+ includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0 || (report.suppressedDiagnostics?.length ?? 0) > 0,
518
518
  ruleSeverityForFile: (filePath) => ruleSeverityMapForOptions(nativeOptions, filePath)
519
519
  });
520
520
  if (report.files !== 0) {
@@ -641,7 +641,7 @@ class CLIEngine {
641
641
  const results = maybeFilterQuietResults(reportToESLintResults(report, {
642
642
  source: code,
643
643
  filePath: normalizeESLintFilePath(filePath, mergedOptions.cwd),
644
- includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0,
644
+ includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0 || (report.suppressedDiagnostics?.length ?? 0) > 0,
645
645
  ruleSeverityForFile: (filePath) => ruleSeverityMapForOptions(mergedOptions, filePath)
646
646
  }), mergedOptions);
647
647
  return resultsToCLIEngineReport(results);
@@ -842,6 +842,7 @@ function publicCliReport(report) {
842
842
  files: report.files ?? 0,
843
843
  filePaths: report.filePaths ?? [],
844
844
  diagnostics: report.diagnostics ?? [],
845
+ suppressedDiagnostics: report.suppressedDiagnostics ?? [],
845
846
  outputs: report.outputs ?? []
846
847
  };
847
848
  }
@@ -1140,7 +1141,7 @@ function lintFiles(paths, options = {}) {
1140
1141
  const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
1141
1142
  const lintPaths = filteredLintPaths(targets, options);
1142
1143
  if (lintPaths.length === 0) {
1143
- return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
1144
+ return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
1144
1145
  }
1145
1146
 
1146
1147
  const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
@@ -1205,8 +1206,10 @@ function finalizeLintReport(report, ignoredDiagnostics, options) {
1205
1206
  if (!options.deferDiagnosticConfigFiltering) {
1206
1207
  report.filePaths = normalizeReportFilePaths(report.filePaths, options);
1207
1208
  report.diagnostics = normalizeDiagnosticFilePaths(report.diagnostics, options);
1209
+ report.suppressedDiagnostics = normalizeDiagnosticFilePaths(report.suppressedDiagnostics, options);
1208
1210
  report.outputs = normalizeReportOutputs(report.outputs, options);
1209
1211
  report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
1212
+ report.suppressedDiagnostics = normalizeReportDiagnostics(report.suppressedDiagnostics, options);
1210
1213
  report.exitCode = exitCodeForDiagnostics(report.diagnostics);
1211
1214
  }
1212
1215
  return report;
@@ -1303,6 +1306,7 @@ function mergeNativeReports(reports) {
1303
1306
  files: reports.reduce((count, item) => count + (item.files ?? 0), 0),
1304
1307
  filePaths: reports.flatMap((item) => item.filePaths ?? []),
1305
1308
  diagnostics: reports.flatMap((item) => item.diagnostics ?? []),
1309
+ suppressedDiagnostics: reports.flatMap((item) => item.suppressedDiagnostics ?? []),
1306
1310
  outputs: reports.flatMap((item) => item.outputs ?? []),
1307
1311
  exitCode: reports.some((item) => item.exitCode) ? 1 : 0
1308
1312
  };
@@ -1335,6 +1339,7 @@ function lintText(code, options = {}) {
1335
1339
  files: 0,
1336
1340
  filePaths: [],
1337
1341
  diagnostics,
1342
+ suppressedDiagnostics: [],
1338
1343
  exitCode: exitCodeForDiagnostics(diagnostics)
1339
1344
  };
1340
1345
  }
@@ -1356,7 +1361,12 @@ function lintText(code, options = {}) {
1356
1361
  ...diagnostic,
1357
1362
  filePath: requestedPath
1358
1363
  }));
1364
+ report.suppressedDiagnostics = (report.suppressedDiagnostics ?? []).map((diagnostic) => ({
1365
+ ...diagnostic,
1366
+ filePath: requestedPath
1367
+ }));
1359
1368
  report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
1369
+ report.suppressedDiagnostics = normalizeReportDiagnostics(report.suppressedDiagnostics, options);
1360
1370
  report.exitCode = exitCodeForDiagnostics(report.diagnostics);
1361
1371
  return report;
1362
1372
  } finally {
@@ -1888,7 +1898,10 @@ class Linter {
1888
1898
  config: calculatedConfig({ cwd: verifyOptions.cwd, noConfig: true, overrideConfig: config }, normalizedFilePath)
1889
1899
  });
1890
1900
  const customRuleFilter = applyDisableDirectives(customRuleMessages, sourceCode);
1891
- this.suppressedMessages = customRuleFilter.suppressedMessages;
1901
+ this.suppressedMessages = [
1902
+ ...(report.suppressedDiagnostics ?? []).map((diagnostic) => suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities)),
1903
+ ...customRuleFilter.suppressedMessages
1904
+ ];
1892
1905
  this.times = { passes: [] };
1893
1906
  this.fixPassCount = 0;
1894
1907
  return [
@@ -2197,14 +2210,18 @@ function applyDisableDirectives(messages, sourceCode) {
2197
2210
  const directives = sourceCode.getDisableDirectives()
2198
2211
  .filter((directive) => directive.node?.loc?.start?.line)
2199
2212
  .sort((left, right) => left.node.loc.start.line - right.node.loc.start.line);
2200
- if (directives.length === 0) {
2213
+ const utlintDirectives = sourceCode.getAllComments()
2214
+ .map((comment) => utlintDirectiveFromComment(comment, sourceCode))
2215
+ .filter(Boolean)
2216
+ .sort((left, right) => left.node.range[0] - right.node.range[0]);
2217
+ if (directives.length === 0 && utlintDirectives.length === 0) {
2201
2218
  return { messages, suppressedMessages: [] };
2202
2219
  }
2203
2220
 
2204
2221
  const kept = [];
2205
2222
  const suppressed = [];
2206
2223
  for (const message of messages) {
2207
- const directive = disableDirectiveForMessage(message, directives);
2224
+ const directive = utlintDirectiveForMessage(message, utlintDirectives) ?? disableDirectiveForMessage(message, directives);
2208
2225
  if (directive) {
2209
2226
  suppressed.push({
2210
2227
  ...message,
@@ -2220,6 +2237,68 @@ function applyDisableDirectives(messages, sourceCode) {
2220
2237
  return { messages: kept, suppressedMessages: suppressed };
2221
2238
  }
2222
2239
 
2240
+ function utlintDirectiveFromComment(comment, sourceCode) {
2241
+ const match = String(comment?.value ?? "").trim().match(/^(utlint-ignore(?:-all|-start|-end)?)\b\s*(.*)$/u);
2242
+ if (!match) {
2243
+ return null;
2244
+ }
2245
+
2246
+ const [, type, tail] = match;
2247
+ const colon = tail.indexOf(":");
2248
+ const rawRuleId = (colon === -1 ? tail : tail.slice(0, colon)).trim();
2249
+ const justification = colon === -1 ? "" : tail.slice(colon + 1).trim();
2250
+ const nextToken = sourceCode.getAllTokens().find((token) => token.range?.[0] >= comment.range?.[1]);
2251
+ return {
2252
+ type,
2253
+ node: comment,
2254
+ ruleId: rawRuleId || null,
2255
+ justification,
2256
+ nextCodeLine: nextToken?.loc?.start?.line ?? null,
2257
+ topLevel: sourceCode.getAllTokens().every((token) => token.range?.[0] >= comment.range?.[0])
2258
+ };
2259
+ }
2260
+
2261
+ function utlintDirectiveForMessage(message, directives) {
2262
+ let allRulesRangeDepth = 0;
2263
+ let namedRuleRangeDepth = 0;
2264
+ let allRulesRangeDirective = null;
2265
+ let namedRuleRangeDirective = null;
2266
+
2267
+ for (const directive of directives) {
2268
+ if (directive.node.loc.start.line > message.line) {
2269
+ break;
2270
+ }
2271
+ if (directive.type === "utlint-ignore-start") {
2272
+ if (directive.ruleId == null) {
2273
+ allRulesRangeDirective ??= directive;
2274
+ allRulesRangeDepth += 1;
2275
+ } else if (directive.ruleId === message.ruleId) {
2276
+ namedRuleRangeDirective ??= directive;
2277
+ namedRuleRangeDepth += 1;
2278
+ }
2279
+ continue;
2280
+ }
2281
+ if (directive.type === "utlint-ignore-end") {
2282
+ if (directive.ruleId == null && allRulesRangeDepth > 0) {
2283
+ allRulesRangeDepth -= 1;
2284
+ if (allRulesRangeDepth === 0) allRulesRangeDirective = null;
2285
+ } else if (directive.ruleId === message.ruleId && namedRuleRangeDepth > 0) {
2286
+ namedRuleRangeDepth -= 1;
2287
+ if (namedRuleRangeDepth === 0) namedRuleRangeDirective = null;
2288
+ }
2289
+ continue;
2290
+ }
2291
+ if (directive.type === "utlint-ignore-all" && directive.topLevel && disableDirectiveMatchesRule(directive, message.ruleId)) {
2292
+ return directive;
2293
+ }
2294
+ if (directive.type === "utlint-ignore" && directive.nextCodeLine === message.line && disableDirectiveMatchesRule(directive, message.ruleId)) {
2295
+ return directive;
2296
+ }
2297
+ }
2298
+
2299
+ return namedRuleRangeDirective ?? allRulesRangeDirective;
2300
+ }
2301
+
2223
2302
  function disableDirectiveForMessage(message, directives) {
2224
2303
  const active = {
2225
2304
  all: null,
@@ -3695,6 +3774,18 @@ function reportToESLintResults(report, textOptions = {}) {
3695
3774
  byFile.get(filePath).messages.push(diagnosticToESLintMessage(diagnostic, ruleSeverities));
3696
3775
  }
3697
3776
 
3777
+ for (const diagnostic of report.suppressedDiagnostics ?? []) {
3778
+ const filePath = textOptions.filePath ?? normalizeESLintFilePath(diagnostic.filePath, textOptions.cwd);
3779
+ if (!byFile.has(filePath)) {
3780
+ byFile.set(filePath, emptyESLintResult(filePath, textOptions.source));
3781
+ }
3782
+ const ruleSeverities = textOptions.ruleSeverityForFile?.(filePath) ?? textOptions.ruleSeverities;
3783
+ if (diagnostic.ruleId && ruleSeverities?.get(diagnostic.ruleId) === 0) {
3784
+ continue;
3785
+ }
3786
+ byFile.get(filePath).suppressedMessages.push(suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities));
3787
+ }
3788
+
3698
3789
  for (const fixed of report.outputs ?? []) {
3699
3790
  const filePath = textOptions.filePath ?? normalizeESLintFilePath(fixed.filePath, textOptions.cwd);
3700
3791
  if (!byFile.has(filePath)) {
@@ -4398,6 +4489,16 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
4398
4489
  return message;
4399
4490
  }
4400
4491
 
4492
+ function suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities) {
4493
+ return {
4494
+ ...diagnosticToESLintMessage(diagnostic, ruleSeverities),
4495
+ suppressions: [{
4496
+ kind: diagnostic.suppression?.kind ?? "directive",
4497
+ justification: diagnostic.suppression?.justification ?? ""
4498
+ }]
4499
+ };
4500
+ }
4501
+
4401
4502
  function finalizeESLintResult(result) {
4402
4503
  result.errorCount = 0;
4403
4504
  result.warningCount = 0;
package/index.d.ts CHANGED
@@ -9,10 +9,17 @@ export interface LintMessage {
9
9
  nodeType?: string | null;
10
10
  fix?: LintFix | LintFix[];
11
11
  suggestions?: LintSuggestion[];
12
+ suppressions?: LintSuppression[];
12
13
  }
13
14
 
14
- export interface LintDiagnostic extends Omit<LintMessage, "severity"> {
15
+ export interface LintSuppression {
16
+ kind: "directive";
17
+ justification: string;
18
+ }
19
+
20
+ export interface LintDiagnostic extends Omit<LintMessage, "severity" | "suppressions"> {
15
21
  severity: "warning" | "error";
22
+ suppression?: LintSuppression;
16
23
  }
17
24
 
18
25
  export interface LintFix {
@@ -42,6 +49,7 @@ export interface LintReport {
42
49
  files: number;
43
50
  filePaths: string[];
44
51
  diagnostics: LintDiagnostic[];
52
+ suppressedDiagnostics: LintDiagnostic[];
45
53
  outputs?: Array<{ filePath: string; output: string }>;
46
54
  exitCode: number;
47
55
  stderr?: string;
package/index.js CHANGED
@@ -517,7 +517,7 @@ export class UtooLint {
517
517
  const results = reportToESLintResults(report, {
518
518
  source: code,
519
519
  filePath,
520
- includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0,
520
+ includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0 || (report.suppressedDiagnostics?.length ?? 0) > 0,
521
521
  ruleSeverityForFile: (filePath) => ruleSeverityMapForOptions(nativeOptions, filePath)
522
522
  });
523
523
  if (report.files !== 0) {
@@ -635,7 +635,10 @@ export class Linter {
635
635
  config: calculatedConfig({ cwd: verifyOptions.cwd, noConfig: true, overrideConfig: config }, normalizedFilePath)
636
636
  });
637
637
  const customRuleFilter = applyDisableDirectives(customRuleMessages, sourceCode);
638
- this.suppressedMessages = customRuleFilter.suppressedMessages;
638
+ this.suppressedMessages = [
639
+ ...(report.suppressedDiagnostics ?? []).map((diagnostic) => suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities)),
640
+ ...customRuleFilter.suppressedMessages
641
+ ];
639
642
  this.times = { passes: [] };
640
643
  this.fixPassCount = 0;
641
644
  return [
@@ -944,14 +947,18 @@ function applyDisableDirectives(messages, sourceCode) {
944
947
  const directives = sourceCode.getDisableDirectives()
945
948
  .filter((directive) => directive.node?.loc?.start?.line)
946
949
  .sort((left, right) => left.node.loc.start.line - right.node.loc.start.line);
947
- if (directives.length === 0) {
950
+ const utlintDirectives = sourceCode.getAllComments()
951
+ .map((comment) => utlintDirectiveFromComment(comment, sourceCode))
952
+ .filter(Boolean)
953
+ .sort((left, right) => left.node.range[0] - right.node.range[0]);
954
+ if (directives.length === 0 && utlintDirectives.length === 0) {
948
955
  return { messages, suppressedMessages: [] };
949
956
  }
950
957
 
951
958
  const kept = [];
952
959
  const suppressed = [];
953
960
  for (const message of messages) {
954
- const directive = disableDirectiveForMessage(message, directives);
961
+ const directive = utlintDirectiveForMessage(message, utlintDirectives) ?? disableDirectiveForMessage(message, directives);
955
962
  if (directive) {
956
963
  suppressed.push({
957
964
  ...message,
@@ -967,6 +974,68 @@ function applyDisableDirectives(messages, sourceCode) {
967
974
  return { messages: kept, suppressedMessages: suppressed };
968
975
  }
969
976
 
977
+ function utlintDirectiveFromComment(comment, sourceCode) {
978
+ const match = String(comment?.value ?? "").trim().match(/^(utlint-ignore(?:-all|-start|-end)?)\b\s*(.*)$/u);
979
+ if (!match) {
980
+ return null;
981
+ }
982
+
983
+ const [, type, tail] = match;
984
+ const colon = tail.indexOf(":");
985
+ const rawRuleId = (colon === -1 ? tail : tail.slice(0, colon)).trim();
986
+ const justification = colon === -1 ? "" : tail.slice(colon + 1).trim();
987
+ const nextToken = sourceCode.getAllTokens().find((token) => token.range?.[0] >= comment.range?.[1]);
988
+ return {
989
+ type,
990
+ node: comment,
991
+ ruleId: rawRuleId || null,
992
+ justification,
993
+ nextCodeLine: nextToken?.loc?.start?.line ?? null,
994
+ topLevel: sourceCode.getAllTokens().every((token) => token.range?.[0] >= comment.range?.[0])
995
+ };
996
+ }
997
+
998
+ function utlintDirectiveForMessage(message, directives) {
999
+ let allRulesRangeDepth = 0;
1000
+ let namedRuleRangeDepth = 0;
1001
+ let allRulesRangeDirective = null;
1002
+ let namedRuleRangeDirective = null;
1003
+
1004
+ for (const directive of directives) {
1005
+ if (directive.node.loc.start.line > message.line) {
1006
+ break;
1007
+ }
1008
+ if (directive.type === "utlint-ignore-start") {
1009
+ if (directive.ruleId == null) {
1010
+ allRulesRangeDirective ??= directive;
1011
+ allRulesRangeDepth += 1;
1012
+ } else if (directive.ruleId === message.ruleId) {
1013
+ namedRuleRangeDirective ??= directive;
1014
+ namedRuleRangeDepth += 1;
1015
+ }
1016
+ continue;
1017
+ }
1018
+ if (directive.type === "utlint-ignore-end") {
1019
+ if (directive.ruleId == null && allRulesRangeDepth > 0) {
1020
+ allRulesRangeDepth -= 1;
1021
+ if (allRulesRangeDepth === 0) allRulesRangeDirective = null;
1022
+ } else if (directive.ruleId === message.ruleId && namedRuleRangeDepth > 0) {
1023
+ namedRuleRangeDepth -= 1;
1024
+ if (namedRuleRangeDepth === 0) namedRuleRangeDirective = null;
1025
+ }
1026
+ continue;
1027
+ }
1028
+ if (directive.type === "utlint-ignore-all" && directive.topLevel && disableDirectiveMatchesRule(directive, message.ruleId)) {
1029
+ return directive;
1030
+ }
1031
+ if (directive.type === "utlint-ignore" && directive.nextCodeLine === message.line && disableDirectiveMatchesRule(directive, message.ruleId)) {
1032
+ return directive;
1033
+ }
1034
+ }
1035
+
1036
+ return namedRuleRangeDirective ?? allRulesRangeDirective;
1037
+ }
1038
+
970
1039
  function disableDirectiveForMessage(message, directives) {
971
1040
  const active = {
972
1041
  all: null,
@@ -2477,7 +2546,7 @@ export class CLIEngine {
2477
2546
  const results = maybeFilterQuietResults(reportToESLintResults(report, {
2478
2547
  source: code,
2479
2548
  filePath: normalizeESLintFilePath(filePath, mergedOptions.cwd),
2480
- includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0,
2549
+ includeEmptyTextResult: report.files !== 0 || (report.diagnostics?.length ?? 0) > 0 || (report.suppressedDiagnostics?.length ?? 0) > 0,
2481
2550
  ruleSeverityForFile: (filePath) => ruleSeverityMapForOptions(mergedOptions, filePath)
2482
2551
  }), mergedOptions);
2483
2552
  return resultsToCLIEngineReport(results);
@@ -2678,6 +2747,7 @@ function publicCliReport(report) {
2678
2747
  files: report.files ?? 0,
2679
2748
  filePaths: report.filePaths ?? [],
2680
2749
  diagnostics: report.diagnostics ?? [],
2750
+ suppressedDiagnostics: report.suppressedDiagnostics ?? [],
2681
2751
  outputs: report.outputs ?? []
2682
2752
  };
2683
2753
  }
@@ -2976,7 +3046,7 @@ export function lintFiles(paths, options = {}) {
2976
3046
  const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
2977
3047
  const lintPaths = filteredLintPaths(targets, options);
2978
3048
  if (lintPaths.length === 0) {
2979
- return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
3049
+ return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
2980
3050
  }
2981
3051
 
2982
3052
  const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
@@ -3041,8 +3111,10 @@ function finalizeLintReport(report, ignoredDiagnostics, options) {
3041
3111
  if (!options.deferDiagnosticConfigFiltering) {
3042
3112
  report.filePaths = normalizeReportFilePaths(report.filePaths, options);
3043
3113
  report.diagnostics = normalizeDiagnosticFilePaths(report.diagnostics, options);
3114
+ report.suppressedDiagnostics = normalizeDiagnosticFilePaths(report.suppressedDiagnostics, options);
3044
3115
  report.outputs = normalizeReportOutputs(report.outputs, options);
3045
3116
  report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
3117
+ report.suppressedDiagnostics = normalizeReportDiagnostics(report.suppressedDiagnostics, options);
3046
3118
  report.exitCode = exitCodeForDiagnostics(report.diagnostics);
3047
3119
  }
3048
3120
  return report;
@@ -3139,6 +3211,7 @@ function mergeNativeReports(reports) {
3139
3211
  files: reports.reduce((count, item) => count + (item.files ?? 0), 0),
3140
3212
  filePaths: reports.flatMap((item) => item.filePaths ?? []),
3141
3213
  diagnostics: reports.flatMap((item) => item.diagnostics ?? []),
3214
+ suppressedDiagnostics: reports.flatMap((item) => item.suppressedDiagnostics ?? []),
3142
3215
  outputs: reports.flatMap((item) => item.outputs ?? []),
3143
3216
  exitCode: reports.some((item) => item.exitCode) ? 1 : 0
3144
3217
  };
@@ -3171,6 +3244,7 @@ export function lintText(code, options = {}) {
3171
3244
  files: 0,
3172
3245
  filePaths: [],
3173
3246
  diagnostics,
3247
+ suppressedDiagnostics: [],
3174
3248
  exitCode: exitCodeForDiagnostics(diagnostics)
3175
3249
  };
3176
3250
  }
@@ -3192,7 +3266,12 @@ export function lintText(code, options = {}) {
3192
3266
  ...diagnostic,
3193
3267
  filePath: requestedPath
3194
3268
  }));
3269
+ report.suppressedDiagnostics = (report.suppressedDiagnostics ?? []).map((diagnostic) => ({
3270
+ ...diagnostic,
3271
+ filePath: requestedPath
3272
+ }));
3195
3273
  report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
3274
+ report.suppressedDiagnostics = normalizeReportDiagnostics(report.suppressedDiagnostics, options);
3196
3275
  report.exitCode = exitCodeForDiagnostics(report.diagnostics);
3197
3276
  return report;
3198
3277
  } finally {
@@ -3698,6 +3777,18 @@ function reportToESLintResults(report, textOptions = {}) {
3698
3777
  byFile.get(filePath).messages.push(diagnosticToESLintMessage(diagnostic, ruleSeverities));
3699
3778
  }
3700
3779
 
3780
+ for (const diagnostic of report.suppressedDiagnostics ?? []) {
3781
+ const filePath = textOptions.filePath ?? normalizeESLintFilePath(diagnostic.filePath, textOptions.cwd);
3782
+ if (!byFile.has(filePath)) {
3783
+ byFile.set(filePath, emptyESLintResult(filePath, textOptions.source));
3784
+ }
3785
+ const ruleSeverities = textOptions.ruleSeverityForFile?.(filePath) ?? textOptions.ruleSeverities;
3786
+ if (diagnostic.ruleId && ruleSeverities?.get(diagnostic.ruleId) === 0) {
3787
+ continue;
3788
+ }
3789
+ byFile.get(filePath).suppressedMessages.push(suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities));
3790
+ }
3791
+
3701
3792
  for (const fixed of report.outputs ?? []) {
3702
3793
  const filePath = textOptions.filePath ?? normalizeESLintFilePath(fixed.filePath, textOptions.cwd);
3703
3794
  if (!byFile.has(filePath)) {
@@ -4401,6 +4492,16 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
4401
4492
  return message;
4402
4493
  }
4403
4494
 
4495
+ function suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities) {
4496
+ return {
4497
+ ...diagnosticToESLintMessage(diagnostic, ruleSeverities),
4498
+ suppressions: [{
4499
+ kind: diagnostic.suppression?.kind ?? "directive",
4500
+ justification: diagnostic.suppression?.justification ?? ""
4501
+ }]
4502
+ };
4503
+ }
4504
+
4404
4505
  function finalizeESLintResult(result) {
4405
4506
  result.errorCount = 0;
4406
4507
  result.warningCount = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utoo/lint",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Experimental JavaScript and TypeScript linter powered by Yuku",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -76,11 +76,11 @@
76
76
  "use-at-your-own-risk.js"
77
77
  ],
78
78
  "optionalDependencies": {
79
- "@utoo/lint-darwin-arm64": "0.2.7",
80
- "@utoo/lint-darwin-x64": "0.2.7",
81
- "@utoo/lint-linux-arm64": "0.2.7",
82
- "@utoo/lint-linux-x64": "0.2.7",
83
- "@utoo/lint-win32-x64": "0.2.7"
79
+ "@utoo/lint-darwin-arm64": "0.2.8",
80
+ "@utoo/lint-darwin-x64": "0.2.8",
81
+ "@utoo/lint-linux-arm64": "0.2.8",
82
+ "@utoo/lint-linux-x64": "0.2.8",
83
+ "@utoo/lint-win32-x64": "0.2.8"
84
84
  },
85
85
  "dependencies": {
86
86
  "jiti": "2.7.0"