Skip to content
This repository was archived by the owner on Nov 16, 2023. It is now read-only.

Commit 3c2ba6a

Browse files
authored
Merge pull request #36 from reduckted/feature/22-always-show-disable-rule-fix
Always show disable rule fix
2 parents 04ced8d + 1be5cd1 commit 3c2ba6a

File tree

3 files changed

+49
-46
lines changed

3 files changed

+49
-46
lines changed

src/plugin.ts

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,20 @@ import { getNonOverlappingReplacements, filterProblemsForFile } from './runner/f
99

1010
const isTsLintLanguageServiceMarker = Symbol('__isTsLintLanguageServiceMarker__');
1111

12-
class FailureMap {
13-
private readonly _map = new Map<string, tslint.RuleFailure>();
12+
interface Problem {
13+
failure: tslint.RuleFailure;
14+
fixable: boolean;
15+
}
16+
17+
class ProblemMap {
18+
private readonly _map = new Map<string, Problem>();
1419

1520
public get(start: number, end: number) {
1621
return this._map.get(this.key(start, end));
1722
}
1823

19-
public set(start: number, end: number, failure: tslint.RuleFailure): void {
20-
this._map.set(this.key(start, end), failure);
24+
public set(start: number, end: number, problem: Problem): void {
25+
this._map.set(this.key(start, end), problem);
2126
}
2227

2328
public values() {
@@ -31,7 +36,7 @@ class FailureMap {
3136
}
3237

3338
export class TSLintPlugin {
34-
private readonly codeFixActions = new Map<string, FailureMap>();
39+
private readonly codeFixActions = new Map<string, ProblemMap>();
3540
private readonly configFileWatcher: ConfigFileWatcher;
3641
private readonly runner: TsLintRunner;
3742

@@ -182,12 +187,12 @@ export class TSLintPlugin {
182187
const documentFixes = this.codeFixActions.get(fileName);
183188
if (documentFixes) {
184189
const problem = documentFixes.get(start, end);
185-
if (problem) {
186-
const fix = problem.getFix();
190+
if (problem && problem.fixable) {
191+
const fix = problem.failure.getFix();
187192
if (fix) {
188-
fixes.push(this.getRuleFailureQuickFix(problem, fileName));
193+
fixes.push(this.getRuleFailureQuickFix(problem.failure, fileName));
189194

190-
const fixAll = this.getRuleFailureFixAllQuickFix(problem.getRuleName(), documentFixes, fileName);
195+
const fixAll = this.getRuleFailureFixAllQuickFix(problem.failure.getRuleName(), documentFixes, fileName);
191196
if (fixAll) {
192197
fixes.push(fixAll);
193198
}
@@ -197,50 +202,44 @@ export class TSLintPlugin {
197202
fixes.push(this.getFixAllAutoFixableQuickFix(documentFixes, fileName));
198203

199204
if (problem) {
200-
fixes.push(this.getDisableRuleQuickFix(problem, fileName, this.getProgram().getSourceFile(fileName)!));
205+
fixes.push(this.getDisableRuleQuickFix(problem.failure, fileName, this.getProgram().getSourceFile(fileName)!));
201206
}
202207
}
203208

204209
return fixes;
205210
}
206211

207-
private recordCodeAction(problem: tslint.RuleFailure, file: ts.SourceFile) {
208-
let fix: tslint.Fix | undefined;
209-
212+
private recordCodeAction(failure: tslint.RuleFailure, file: ts.SourceFile) {
210213
// tslint can return a fix with an empty replacements array, these fixes are ignored
211-
if (problem.getFix && problem.getFix() && !replacementsAreEmpty(problem.getFix())) { // tslint fixes are not available in tslint < 3.17
212-
fix = problem.getFix(); // createAutoFix(problem, document, problem.getFix());
213-
}
214-
215-
if (!fix) {
216-
return;
217-
}
214+
const fixable = !!(failure.getFix && failure.getFix() && !replacementsAreEmpty(failure.getFix()));
218215

219216
let documentAutoFixes = this.codeFixActions.get(file.fileName);
220217
if (!documentAutoFixes) {
221-
documentAutoFixes = new FailureMap();
218+
documentAutoFixes = new ProblemMap();
222219
this.codeFixActions.set(file.fileName, documentAutoFixes);
223220
}
224-
documentAutoFixes.set(problem.getStartPosition().getPosition(), problem.getEndPosition().getPosition(), problem);
221+
documentAutoFixes.set(failure.getStartPosition().getPosition(), failure.getEndPosition().getPosition(), { failure, fixable });
225222
}
226223

227-
private getRuleFailureQuickFix(problem: tslint.RuleFailure, fileName: string): ts_module.CodeFixAction {
224+
private getRuleFailureQuickFix(failure: tslint.RuleFailure, fileName: string): ts_module.CodeFixAction {
228225
return {
229-
description: `Fix: ${problem.getFailure()}`,
226+
description: `Fix: ${failure.getFailure()}`,
230227
fixName: '',
231-
changes: [problemToFileTextChange(problem, fileName)],
228+
changes: [failureToFileTextChange(failure, fileName)],
232229
};
233230
}
234231

235232
/**
236233
* Generate a code action that fixes all instances of ruleName.
237234
*/
238-
private getRuleFailureFixAllQuickFix(ruleName: string, problems: FailureMap, fileName: string): ts_module.CodeFixAction | undefined {
235+
private getRuleFailureFixAllQuickFix(ruleName: string, problems: ProblemMap, fileName: string): ts_module.CodeFixAction | undefined {
239236
const changes: ts_module.FileTextChanges[] = [];
240237

241238
for (const problem of problems.values()) {
242-
if (problem.getRuleName() === ruleName) {
243-
changes.push(problemToFileTextChange(problem, fileName));
239+
if (problem.fixable) {
240+
if (problem.failure.getRuleName() === ruleName) {
241+
changes.push(failureToFileTextChange(problem.failure, fileName));
242+
}
244243
}
245244
}
246245

@@ -256,22 +255,22 @@ export class TSLintPlugin {
256255
};
257256
}
258257

259-
private getDisableRuleQuickFix(problem: tslint.RuleFailure, fileName: string, file: ts_module.SourceFile): ts_module.CodeFixAction {
258+
private getDisableRuleQuickFix(failure: tslint.RuleFailure, fileName: string, file: ts_module.SourceFile): ts_module.CodeFixAction {
260259
return {
261-
description: `Disable rule '${problem.getRuleName()}'`,
260+
description: `Disable rule '${failure.getRuleName()}'`,
262261
fixName: '',
263262
changes: [{
264263
fileName,
265264
textChanges: [{
266-
newText: `// tslint:disable-next-line: ${problem.getRuleName()}\n`,
267-
span: { start: file.getLineStarts()[problem.getStartPosition().getLineAndCharacter().line], length: 0 },
265+
newText: `// tslint:disable-next-line: ${failure.getRuleName()}\n`,
266+
span: { start: file.getLineStarts()[failure.getStartPosition().getLineAndCharacter().line], length: 0 },
268267
}],
269268
}],
270269
};
271270
}
272271

273-
private getFixAllAutoFixableQuickFix(documentFixes: FailureMap, fileName: string): ts_module.CodeFixAction {
274-
const allReplacements = getNonOverlappingReplacements(Array.from(documentFixes.values()));
272+
private getFixAllAutoFixableQuickFix(documentFixes: ProblemMap, fileName: string): ts_module.CodeFixAction {
273+
const allReplacements = getNonOverlappingReplacements(Array.from(documentFixes.values()).filter(x => x.fixable).map(x => x.failure));
275274
return {
276275
description: `Fix all auto-fixable tslint failures`,
277276
fixName: '',
@@ -286,28 +285,28 @@ export class TSLintPlugin {
286285
return this.project.getLanguageService().getProgram()!;
287286
}
288287

289-
private makeDiagnostic(problem: tslint.RuleFailure, file: ts.SourceFile): ts.Diagnostic {
290-
const message = (problem.getRuleName() !== null)
291-
? `${problem.getFailure()} (${problem.getRuleName()})`
292-
: `${problem.getFailure()}`;
288+
private makeDiagnostic(failure: tslint.RuleFailure, file: ts.SourceFile): ts.Diagnostic {
289+
const message = (failure.getRuleName() !== null)
290+
? `${failure.getFailure()} (${failure.getRuleName()})`
291+
: `${failure.getFailure()}`;
293292

294-
const category = this.getDiagnosticCategory(problem);
293+
const category = this.getDiagnosticCategory(failure);
295294

296295
return {
297296
file,
298-
start: problem.getStartPosition().getPosition(),
299-
length: problem.getEndPosition().getPosition() - problem.getStartPosition().getPosition(),
297+
start: failure.getStartPosition().getPosition(),
298+
length: failure.getEndPosition().getPosition() - failure.getStartPosition().getPosition(),
300299
messageText: message,
301300
category,
302301
source: TSLINT_ERROR_SOURCE,
303302
code: TSLINT_ERROR_CODE,
304303
};
305304
}
306305

307-
private getDiagnosticCategory(problem: tslint.RuleFailure): ts.DiagnosticCategory {
306+
private getDiagnosticCategory(failure: tslint.RuleFailure): ts.DiagnosticCategory {
308307
if (this.configurationManager.config.alwaysShowRuleFailuresAsWarnings === true) {
309308
return this.ts.DiagnosticCategory.Warning;
310-
} else if (problem.getRuleSeverity && problem.getRuleSeverity() === 'error') {
309+
} else if (failure.getRuleSeverity && failure.getRuleSeverity() === 'error') {
311310
// tslint5 supports to assign severities to rules
312311
return this.ts.DiagnosticCategory.Error;
313312
}
@@ -339,8 +338,8 @@ function convertReplacementToTextChange(repl: tslint.Replacement): ts_module.Tex
339338
};
340339
}
341340

342-
function problemToFileTextChange(problem: tslint.RuleFailure, fileName: string): ts_module.FileTextChanges {
343-
const fix = problem.getFix();
341+
function failureToFileTextChange(failure: tslint.RuleFailure, fileName: string): ts_module.FileTextChanges {
342+
const fix = failure.getFix();
344343
const replacements: tslint.Replacement[] = getReplacements(fix);
345344

346345
return {

test-workspace/.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"typescript.tsdk": "node_modules/typescript/lib"
2+
"typescript.tsdk": "node_modules/typescript/lib",
3+
"tslint.enable": false
34
}

test-workspace/examples/eval.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// There is no TSLint fix for the "no-eval" rule,
2+
// but the "disable rule" fix is still available.
3+
let x = eval("1 + 1");

0 commit comments

Comments
 (0)