From 40bdb0b27b21de511f0ecd151cb8282a625ca6e1 Mon Sep 17 00:00:00 2001 From: Stefan Knutas Date: Sun, 28 Mar 2021 23:11:42 +0200 Subject: [PATCH] feat(eslint-plugin): [type-annotation-spacing] handle space between ? and : (#3138) * fix(eslint-plugin): [type-annotation-spacing] handle space after ? * fix: skip before flag and add test for interface * fix: add new message * fix: use isSpaceBetweenTokens to support older ESLint --- .../src/rules/type-annotation-spacing.ts | 24 ++++- .../rules/type-annotation-spacing.test.ts | 100 ++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/type-annotation-spacing.ts b/packages/eslint-plugin/src/rules/type-annotation-spacing.ts index 985e008c16d..0cf3e34b8b8 100644 --- a/packages/eslint-plugin/src/rules/type-annotation-spacing.ts +++ b/packages/eslint-plugin/src/rules/type-annotation-spacing.ts @@ -35,7 +35,8 @@ type MessageIds = | 'expectedSpaceAfter' | 'expectedSpaceBefore' | 'unexpectedSpaceAfter' - | 'unexpectedSpaceBefore'; + | 'unexpectedSpaceBefore' + | 'unexpectedSpaceBetween'; const definition = { type: 'object', @@ -122,6 +123,8 @@ export default util.createRule({ expectedSpaceBefore: "Expected a space before the '{{type}}'.", unexpectedSpaceAfter: "Unexpected space after the '{{type}}'.", unexpectedSpaceBefore: "Unexpected space before the '{{type}}'.", + unexpectedSpaceBetween: + "Unexpected space between the '{{previousToken}}' and the '{{type}}'.", }, schema: [ { @@ -177,6 +180,25 @@ export default util.createRule({ const { before, after } = getRules(ruleSet, typeAnnotation); if (type === ':' && previousToken.value === '?') { + if ( + sourceCode.isSpaceBetweenTokens(previousToken, punctuatorTokenStart) + ) { + context.report({ + node: punctuatorTokenStart, + messageId: 'unexpectedSpaceBetween', + data: { + type, + previousToken: previousToken.value, + }, + fix(fixer) { + return fixer.removeRange([ + previousToken.range[1], + punctuatorTokenStart.range[0], + ]); + }, + }); + } + // shift the start to the ? type = '?:'; punctuatorTokenStart = previousToken; diff --git a/packages/eslint-plugin/tests/rules/type-annotation-spacing.test.ts b/packages/eslint-plugin/tests/rules/type-annotation-spacing.test.ts index de714cff43f..19349a80889 100644 --- a/packages/eslint-plugin/tests/rules/type-annotation-spacing.test.ts +++ b/packages/eslint-plugin/tests/rules/type-annotation-spacing.test.ts @@ -4593,6 +4593,54 @@ type Bar = Record }, ], }, + { + code: 'function foo(a? : string) {}', + output: 'function foo(a?: string) {}', + errors: [ + { + messageId: 'unexpectedSpaceBetween', + data: { type: ':', previousToken: '?' }, + line: 1, + column: 17, + }, + ], + }, + { + code: 'function foo(a ? : string) {}', + output: 'function foo(a?: string) {}', + errors: [ + { + messageId: 'unexpectedSpaceBefore', + data: { type: '?:' }, + line: 1, + column: 16, + }, + { + messageId: 'unexpectedSpaceBetween', + data: { type: ':', previousToken: '?' }, + line: 1, + column: 18, + }, + ], + }, + { + code: 'function foo(a ? : string) {}', + output: 'function foo(a?: string) {}', + errors: [ + { + messageId: 'unexpectedSpaceBefore', + data: { type: '?:' }, + line: 1, + column: 16, + }, + { + messageId: 'unexpectedSpaceBetween', + data: { type: ':', previousToken: '?' }, + line: 1, + column: 19, + }, + ], + }, { code: ` class Foo { @@ -4635,6 +4683,32 @@ class Foo { }, { code: ` +class Foo { + constructor(message ? : string); +} + `, + output: ` +class Foo { + constructor(message?: string); +} + `, + errors: [ + { + messageId: 'unexpectedSpaceBefore', + data: { type: '?:' }, + line: 3, + column: 25, + }, + { + messageId: 'unexpectedSpaceBetween', + data: { type: ':', previousToken: '?' }, + line: 3, + column: 27, + }, + ], + }, + { + code: ` class Foo { greet(name ?: string) : string { return name; } } @@ -4681,6 +4755,32 @@ interface Foo { }, { code: ` +interface Foo { + name ? : string; +} + `, + output: ` +interface Foo { + name?: string; +} + `, + errors: [ + { + messageId: 'unexpectedSpaceBefore', + data: { type: '?:' }, + line: 3, + column: 10, + }, + { + messageId: 'unexpectedSpaceBetween', + data: { type: ':', previousToken: '?' }, + line: 3, + column: 12, + }, + ], + }, + { + code: ` interface Foo { greet(name ?: string) : string; }