From 286a5cca037c004c7e4c64c63ff027b3b7f2a281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maria=20Jos=C3=A9=20Solano?= Date: Mon, 23 Jan 2023 15:56:49 -0800 Subject: [PATCH 1/6] Add directive fix type --- server/src/eslint.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/eslint.ts b/server/src/eslint.ts index 9a7ddddd..e68addf8 100644 --- a/server/src/eslint.ts +++ b/server/src/eslint.ts @@ -1071,7 +1071,7 @@ export namespace ESLint { } } - const validFixTypes = new Set(['problem', 'suggestion', 'layout']); + const validFixTypes = new Set(['problem', 'suggestion', 'layout', 'directive']); export async function validate(document: TextDocument, settings: TextDocumentSettings & { library: ESLintModule }): Promise { const newOptions: CLIOptions = Object.assign(Object.create(null), settings.options); let fixTypes: Set | undefined = undefined; From 692fed64668c8f245175fc5d2502c8ba561c27d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maria=20Jos=C3=A9=20Solano?= Date: Mon, 23 Jan 2023 16:28:44 -0800 Subject: [PATCH 2/6] Handle unused directive problems --- server/src/eslint.ts | 27 +++++++++++++++++++++++++++ server/src/eslintServer.ts | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/server/src/eslint.ts b/server/src/eslint.ts index e68addf8..e64dfe4e 100644 --- a/server/src/eslint.ts +++ b/server/src/eslint.ts @@ -126,6 +126,8 @@ export namespace RuleMetaData { const handled: Set = new Set(); const ruleId2Meta: Map = new Map(); + export const unusedDisableDirectiveId = 'unused-disable-directive'; + export function capture(eslint: ESLintClass, reports: ESLintDocumentReport[]): void { let rulesMetaData: Record | undefined; if (eslint.isCLIEngine) { @@ -133,9 +135,11 @@ export namespace RuleMetaData { if (toHandle.length === 0) { return; } + addUnusedDisableDirectivesMeta(toHandle); rulesMetaData = typeof eslint.getRulesMetaForResults === 'function' ? eslint.getRulesMetaForResults(toHandle) : undefined; toHandle.forEach(report => handled.add(report.filePath)); } else { + addUnusedDisableDirectivesMeta(reports); rulesMetaData = typeof eslint.getRulesMetaForResults === 'function' ? eslint.getRulesMetaForResults(reports) : undefined; } if (rulesMetaData === undefined) { @@ -167,6 +171,25 @@ export namespace RuleMetaData { export function hasRuleId(ruleId: string): boolean { return ruleId2Meta.has(ruleId); } + + export function isUnusedDisableDirectiveProblem(problem: ESLintProblem): boolean { + return problem.ruleId === null && problem.message.startsWith('Unused eslint-disable directive'); + } + + function addUnusedDisableDirectivesMeta(reports: ESLintDocumentReport[]): void { + for (const report of reports) { + for (const message of report.messages) { + if (isUnusedDisableDirectiveProblem(message)) { + ruleId2Meta.set(unusedDisableDirectiveId, { + docs: { + url: 'https://eslint.org/docs/latest/use/configure/rules#report-unused-eslint-disable-comments' + }, + type: 'directive' + }); + } + } + } + } } export type ParserOptions = { @@ -1111,6 +1134,10 @@ export namespace ESLint { CodeActions.record(document, diagnostic, problem); } } else { + if (RuleMetaData.isUnusedDisableDirectiveProblem(problem)) { + problem.ruleId = RuleMetaData.unusedDisableDirectiveId; + } + CodeActions.record(document, diagnostic, problem); } } diff --git a/server/src/eslintServer.ts b/server/src/eslintServer.ts index d7577427..257d35a7 100644 --- a/server/src/eslintServer.ts +++ b/server/src/eslintServer.ts @@ -845,7 +845,7 @@ messageQueue.registerRequest(CodeActionRequest.type, async (params) => { }); } - if (settings.codeAction.disableRuleComment.enable) { + if (settings.codeAction.disableRuleComment.enable && ruleId !== RuleMetaData.unusedDisableDirectiveId) { let workspaceChange = new WorkspaceChange(); if (settings.codeAction.disableRuleComment.location === 'sameLine') { workspaceChange.getTextEditChange({ uri, version: documentVersion }).add(createDisableSameLineTextEdit(textDocument, editInfo)); From bf3633bfdea60c8a6329f3c5c47604c479915516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maria=20Jos=C3=A9=20Solano?= Date: Mon, 23 Jan 2023 16:33:25 -0800 Subject: [PATCH 3/6] Avoid double sets --- server/src/eslint.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/src/eslint.ts b/server/src/eslint.ts index e64dfe4e..4cc0274e 100644 --- a/server/src/eslint.ts +++ b/server/src/eslint.ts @@ -177,6 +177,10 @@ export namespace RuleMetaData { } function addUnusedDisableDirectivesMeta(reports: ESLintDocumentReport[]): void { + if (hasRuleId(unusedDisableDirectiveId)) { + return; + } + for (const report of reports) { for (const message of report.messages) { if (isUnusedDisableDirectiveProblem(message)) { @@ -186,6 +190,8 @@ export namespace RuleMetaData { }, type: 'directive' }); + + return; } } } From 8c93b6d0e6966744d767939779f6f33e1ed99a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maria=20Jos=C3=A9=20Solano?= Date: Mon, 23 Jan 2023 16:36:24 -0800 Subject: [PATCH 4/6] Add explanation --- server/src/eslint.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/eslint.ts b/server/src/eslint.ts index 4cc0274e..ff155774 100644 --- a/server/src/eslint.ts +++ b/server/src/eslint.ts @@ -126,6 +126,9 @@ export namespace RuleMetaData { const handled: Set = new Set(); const ruleId2Meta: Map = new Map(); + // For unused eslint-disable comments, ESLint does not include a rule ID + // nor any other metadata (although they do provide a fix). In order to + // provide code actions for these, we create a fake rule ID and metadata. export const unusedDisableDirectiveId = 'unused-disable-directive'; export function capture(eslint: ESLintClass, reports: ESLintDocumentReport[]): void { From fdf9c7d64b61b4e251a3397e7af62b0b059e0cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maria=20Jos=C3=A9=20Solano?= Date: Mon, 23 Jan 2023 18:13:05 -0800 Subject: [PATCH 5/6] Simplify metadata --- server/src/eslint.ts | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/server/src/eslint.ts b/server/src/eslint.ts index ff155774..e28369f9 100644 --- a/server/src/eslint.ts +++ b/server/src/eslint.ts @@ -138,11 +138,9 @@ export namespace RuleMetaData { if (toHandle.length === 0) { return; } - addUnusedDisableDirectivesMeta(toHandle); rulesMetaData = typeof eslint.getRulesMetaForResults === 'function' ? eslint.getRulesMetaForResults(toHandle) : undefined; toHandle.forEach(report => handled.add(report.filePath)); } else { - addUnusedDisableDirectivesMeta(reports); rulesMetaData = typeof eslint.getRulesMetaForResults === 'function' ? eslint.getRulesMetaForResults(reports) : undefined; } if (rulesMetaData === undefined) { @@ -164,41 +162,28 @@ export namespace RuleMetaData { } export function getUrl(ruleId: string): string | undefined { + if (ruleId === unusedDisableDirectiveId) { + return 'https://eslint.org/docs/latest/use/configure/rules#report-unused-eslint-disable-comments'; + } + return ruleId2Meta.get(ruleId)?.docs?.url; } export function getType(ruleId: string): string | undefined { + if (ruleId === unusedDisableDirectiveId) { + return 'directive'; + } + return ruleId2Meta.get(ruleId)?.type; } export function hasRuleId(ruleId: string): boolean { - return ruleId2Meta.has(ruleId); + return ruleId === unusedDisableDirectiveId || ruleId2Meta.has(ruleId); } export function isUnusedDisableDirectiveProblem(problem: ESLintProblem): boolean { return problem.ruleId === null && problem.message.startsWith('Unused eslint-disable directive'); } - - function addUnusedDisableDirectivesMeta(reports: ESLintDocumentReport[]): void { - if (hasRuleId(unusedDisableDirectiveId)) { - return; - } - - for (const report of reports) { - for (const message of report.messages) { - if (isUnusedDisableDirectiveProblem(message)) { - ruleId2Meta.set(unusedDisableDirectiveId, { - docs: { - url: 'https://eslint.org/docs/latest/use/configure/rules#report-unused-eslint-disable-comments' - }, - type: 'directive' - }); - - return; - } - } - } - } } export type ParserOptions = { From a5b6034d769245b6b7883e5b4144cdbeb939c45d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maria=20Jos=C3=A9=20Solano?= Date: Tue, 24 Jan 2023 16:24:45 -0800 Subject: [PATCH 6/6] Replace ifs by map entry --- server/src/eslint.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/server/src/eslint.ts b/server/src/eslint.ts index e28369f9..0f59f3fe 100644 --- a/server/src/eslint.ts +++ b/server/src/eslint.ts @@ -123,13 +123,19 @@ export type RuleMetaData = { }; export namespace RuleMetaData { - const handled: Set = new Set(); - const ruleId2Meta: Map = new Map(); - // For unused eslint-disable comments, ESLint does not include a rule ID // nor any other metadata (although they do provide a fix). In order to // provide code actions for these, we create a fake rule ID and metadata. export const unusedDisableDirectiveId = 'unused-disable-directive'; + const unusedDisableDirectiveMeta: RuleMetaData = { + docs: { + url: 'https://eslint.org/docs/latest/use/configure/rules#report-unused-eslint-disable-comments' + }, + type: 'directive' + }; + + const handled: Set = new Set(); + const ruleId2Meta: Map = new Map([[unusedDisableDirectiveId, unusedDisableDirectiveMeta]]); export function capture(eslint: ESLintClass, reports: ESLintDocumentReport[]): void { let rulesMetaData: Record | undefined; @@ -159,26 +165,19 @@ export namespace RuleMetaData { export function clear(): void { handled.clear(); ruleId2Meta.clear(); + ruleId2Meta.set(unusedDisableDirectiveId, unusedDisableDirectiveMeta); } export function getUrl(ruleId: string): string | undefined { - if (ruleId === unusedDisableDirectiveId) { - return 'https://eslint.org/docs/latest/use/configure/rules#report-unused-eslint-disable-comments'; - } - return ruleId2Meta.get(ruleId)?.docs?.url; } export function getType(ruleId: string): string | undefined { - if (ruleId === unusedDisableDirectiveId) { - return 'directive'; - } - return ruleId2Meta.get(ruleId)?.type; } export function hasRuleId(ruleId: string): boolean { - return ruleId === unusedDisableDirectiveId || ruleId2Meta.has(ruleId); + return ruleId2Meta.has(ruleId); } export function isUnusedDisableDirectiveProblem(problem: ESLintProblem): boolean {