Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions $shared/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ export type ConfigurationSettings = {
codeActionOnSave: CodeActionsOnSaveSettings;
format: boolean;
quiet: boolean;
bulkSuppression: {
enable: boolean;
suppressionsLocation?: string;
severity?: 'error' | 'warn' | 'info' | 'hint';
};
onIgnoredFiles: ESLintSeverity;
options: ESLintOptions | undefined;
rulesCustomizations: RuleCustomization[];
Expand Down
1 change: 1 addition & 0 deletions client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,7 @@ export namespace ESLintClient {
},
format: false,
quiet: config.get<boolean>('quiet', false),
bulkSuppression: config.get<ConfigurationSettings['bulkSuppression']>('bulkSuppression', { enable: false }),
onIgnoredFiles: ESLintSeverity.from(config.get<string>('onIgnoredFiles', ESLintSeverity.off)),
options: config.get<ESLintOptions>('options', {}),
rulesCustomizations: getRuleCustomizations(config, resource),
Expand Down
23 changes: 23 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,29 @@
"default": false,
"description": "Turns on quiet mode, which ignores warnings and info diagnostics."
},
"eslint.bulkSuppression": {
"type": "object",
"scope": "resource",
"description": "Controls whether bulk-suppressed violations (from eslint-suppressions.json) are shown as hint diagnostics.",
"properties": {
"enable": {
"type": "boolean",
"default": false,
"description": "Show bulk-suppressed violations as hint (grey) diagnostics."
},
"suppressionsLocation": {
"type": "string",
"description": "Path to the suppressions file relative to the workspace. Defaults to eslint-suppressions.json."
},
"severity": {
"type": "string",
"enum": ["error", "warn", "info", "hint"],
"default": "info",
"description": "Diagnostic severity for bulk-suppressed violations. Defaults to 'info' (blue underline)."
}
},
"default": { "enable": false, "severity": "info" }
},
"eslint.onIgnoredFiles": {
"scope": "resource",
"type": "string",
Expand Down
40 changes: 39 additions & 1 deletion server/src/eslint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,16 @@ type ESLintProblem = {
suggestions?: ESLintSuggestionResult[];
};

type SuppressedESLintProblem = ESLintProblem & {
suppressions: Array<{ kind: string; justification: string }>;
};

type ESLintDocumentReport = {
filePath: string;
errorCount: number;
warningCount: number;
messages: ESLintProblem[];
suppressedMessages?: SuppressedESLintProblem[];
output?: string;
};

Expand Down Expand Up @@ -115,6 +120,8 @@ export type ESLintClassOptions = {
fix?: boolean;
overrideConfig?: ConfigData;
overrideConfigFile?: string | null;
applySuppressions?: boolean;
suppressionsLocation?: string;
};

export type RuleMetaData = {
Expand Down Expand Up @@ -1195,6 +1202,15 @@ export namespace ESLint {
}
}

function bulkSeverity(severity?: 'error' | 'warn' | 'info' | 'hint'): DiagnosticSeverity {
switch (severity) {
case 'error': return DiagnosticSeverity.Error;
case 'warn': return DiagnosticSeverity.Warning;
case 'hint': return DiagnosticSeverity.Hint;
default: return DiagnosticSeverity.Information;
}
}

const validFixTypes = new Set<string>(['problem', 'suggestion', 'layout', 'directive']);
export async function validate(document: TextDocument, settings: TextDocumentSettings & { library: ESLintModule }): Promise<Diagnostic[]> {
const newOptions: CLIOptions = Object.assign(Object.create(null), settings.options);
Expand All @@ -1215,6 +1231,15 @@ export namespace ESLint {
const uri = document.uri;
const file = getFilePath(document, settings);

const suppressionOptions: ESLintClassOptions = settings.bulkSuppression?.enable
? {
applySuppressions: true,
...(settings.bulkSuppression.suppressionsLocation
? { suppressionsLocation: settings.bulkSuppression.suppressionsLocation }
: {}),
}
: {};

return withClass(async (eslintClass) => {
CodeActions.remove(uri);
const reportResults: ESLintDocumentReport[] = await eslintClass.lintText(content, { filePath: file, warnIgnored: settings.onIgnoredFiles !== ESLintSeverity.off });
Expand Down Expand Up @@ -1244,9 +1269,22 @@ export namespace ESLint {
}
});
}
// Bulk-suppressed diagnostics intentionally bypass `quiet` mode: they are opt-in
// and already represent a deliberate visibility decision by the user.
if (settings.bulkSuppression?.enable && docReport.suppressedMessages && Array.isArray(docReport.suppressedMessages)) {
for (const problem of docReport.suppressedMessages) {
if (problem && problem.suppressions?.some(s => s.kind === 'file')) {
const [diagnostic, override] = Diagnostics.create(settings, problem, document);
if (override !== RuleSeverity.off) {
diagnostic.severity = bulkSeverity(settings.bulkSuppression.severity);
diagnostics.push(diagnostic);
}
}
}
}
}
return diagnostics;
}, settings);
}, settings, suppressionOptions);
}

function trace(message: string, verbose?: string): void {
Expand Down