From e51048cc6d0d13ecb10016c89e31f7a15aa5827b Mon Sep 17 00:00:00 2001 From: Alexander T Date: Fri, 20 Dec 2019 02:23:08 +0200 Subject: [PATCH] fix(eslint-plugin): [quotes] ignore backticks for Enum members (#1355) * fix(eslint-plugin): [quotes] ignore backticks for Enum members * feat(eslint-plugin): [quotes] handle more TypeScript node types Co-authored-by: Brad Zacher --- packages/eslint-plugin/src/rules/quotes.ts | 36 +- .../eslint-plugin/tests/rules/quotes.test.ts | 486 ++++++++++++++++++ 2 files changed, 514 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin/src/rules/quotes.ts b/packages/eslint-plugin/src/rules/quotes.ts index 25a9d3b4c9e..6a8e91814c1 100644 --- a/packages/eslint-plugin/src/rules/quotes.ts +++ b/packages/eslint-plugin/src/rules/quotes.ts @@ -1,4 +1,7 @@ -import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'; +import { + AST_NODE_TYPES, + TSESTree, +} from '@typescript-eslint/experimental-utils'; import baseRule from 'eslint/lib/rules/quotes'; import * as util from '../util'; @@ -29,15 +32,32 @@ export default util.createRule({ create(context, [option]) { const rules = baseRule.create(context); + function isAllowedAsNonBacktick(node: TSESTree.Literal): boolean { + const parent = node.parent; + + switch (parent?.type) { + case AST_NODE_TYPES.TSAbstractMethodDefinition: + case AST_NODE_TYPES.TSMethodSignature: + case AST_NODE_TYPES.TSPropertySignature: + case AST_NODE_TYPES.TSModuleDeclaration: + case AST_NODE_TYPES.TSLiteralType: + return true; + + case AST_NODE_TYPES.TSEnumMember: + return node === parent.id; + + case AST_NODE_TYPES.TSAbstractClassProperty: + case AST_NODE_TYPES.ClassProperty: + return node === parent.key; + + default: + return false; + } + } + return { Literal(node): void { - const parent = node.parent; - if ( - option === 'backtick' && - (parent?.type === AST_NODE_TYPES.TSModuleDeclaration || - parent?.type === AST_NODE_TYPES.TSLiteralType || - parent?.type === AST_NODE_TYPES.TSPropertySignature) - ) { + if (option === 'backtick' && isAllowedAsNonBacktick(node)) { return; } diff --git a/packages/eslint-plugin/tests/rules/quotes.test.ts b/packages/eslint-plugin/tests/rules/quotes.test.ts index feb312deb99..c6bf01f3e77 100644 --- a/packages/eslint-plugin/tests/rules/quotes.test.ts +++ b/packages/eslint-plugin/tests/rules/quotes.test.ts @@ -353,6 +353,146 @@ interface Foo { b: string; 'a-b': boolean; 'a-b-c': boolean; +} + `, + options: ['backtick'], + }, + + // TSEnumMember + { + code: ` +enum Foo { + A = 1, + "A-B" = 2 +} + `, + }, + { + code: ` +enum Foo { + A = 1, + 'A-B' = 2 +} + `, + options: ['single'], + }, + { + code: ` +enum Foo { + A = \`A\`, + 'A-B' = \`A-B\` +} + `, + options: ['backtick'], + }, + + // TSMethodSignature + { + code: ` +interface Foo { + a(): void; + "a-b"(): void; +} + `, + }, + { + code: ` +interface Foo { + a(): void; + 'a-b'(): void; +} + `, + options: ['single'], + }, + { + code: ` +interface Foo { + a(): void; + 'a-b'(): void; +} + `, + options: ['backtick'], + }, + + // ClassProperty + { + code: ` +class Foo { + public a = ""; + public "a-b" = ""; +} + `, + }, + { + code: ` +class Foo { + public a = ''; + public 'a-b' = ''; +} + `, + options: ['single'], + }, + { + code: ` +class Foo { + public a = \`\`; + public 'a-b' = \`\`; +} + `, + options: ['backtick'], + }, + + // TSAbstractClassProperty + { + code: ` +abstract class Foo { + public abstract a = ""; + public abstract "a-b" = ""; +} + `, + }, + { + code: ` +abstract class Foo { + public abstract a = ''; + public abstract 'a-b' = ''; +} + `, + options: ['single'], + }, + { + code: ` +abstract class Foo { + public abstract a = \`\`; + public abstract 'a-b' = \`\`; +} + `, + options: ['backtick'], + }, + + // TSAbstractMethodDefinition + { + code: ` +abstract class Foo { + public abstract a(): void; + public abstract "a-b"(): void; +} + `, + }, + { + code: ` +abstract class Foo { + public abstract a(): void; + public abstract 'a-b'(): void; +} + `, + options: ['single'], + }, + { + code: ` +abstract class Foo { + public abstract a(): void; + public abstract 'a-b'(): void; } `, options: ['backtick'], @@ -684,5 +824,351 @@ interface Foo { ], options: ['single'], }, + + // Enums + { + code: ` +enum Foo { + A = 1, + 'A-B' = 2 +} + `, + output: ` +enum Foo { + A = 1, + "A-B" = 2 +} + `, + errors: [ + { + ...useDoubleQuote, + line: 4, + column: 3, + }, + ], + }, + { + code: ` +enum Foo { + A = 1, + "A-B" = 2 +} + `, + output: ` +enum Foo { + A = 1, + 'A-B' = 2 +} + `, + errors: [ + { + ...useSingleQuote, + line: 4, + column: 3, + }, + ], + options: ['single'], + }, + { + code: ` +enum Foo { + A = 'A', + 'A-B' = 'A-B' +} + `, + output: ` +enum Foo { + A = \`A\`, + 'A-B' = \`A-B\` +} + `, + errors: [ + { + ...useBacktick, + line: 3, + column: 7, + }, + { + ...useBacktick, + line: 4, + column: 11, + }, + ], + options: ['backtick'], + }, + + // TSMethodSignature + { + code: ` +interface Foo { + a(): void; + 'a-b'(): void; +} + `, + output: ` +interface Foo { + a(): void; + "a-b"(): void; +} + `, + errors: [ + { + ...useDoubleQuote, + line: 4, + column: 3, + }, + ], + }, + { + code: ` +interface Foo { + a(): void; + "a-b"(): void; +} + `, + output: ` +interface Foo { + a(): void; + 'a-b'(): void; +} + `, + errors: [ + { + ...useSingleQuote, + line: 4, + column: 3, + }, + ], + options: ['single'], + }, + + // ClassProperty + { + code: ` +class Foo { + public a = ''; + public 'a-b' = ''; +} + `, + output: ` +class Foo { + public a = ""; + public "a-b" = ""; +} + `, + errors: [ + { + ...useDoubleQuote, + line: 3, + column: 14, + }, + { + ...useDoubleQuote, + line: 4, + column: 10, + }, + { + ...useDoubleQuote, + line: 4, + column: 18, + }, + ], + }, + { + code: ` +class Foo { + public a = ""; + public "a-b" = ""; +} + `, + output: ` +class Foo { + public a = ''; + public 'a-b' = ''; +} + `, + errors: [ + { + ...useSingleQuote, + line: 3, + column: 14, + }, + { + ...useSingleQuote, + line: 4, + column: 10, + }, + { + ...useSingleQuote, + line: 4, + column: 18, + }, + ], + options: ['single'], + }, + { + code: ` +class Foo { + public a = ""; + public "a-b" = ""; +} + `, + output: ` +class Foo { + public a = \`\`; + public "a-b" = \`\`; +} + `, + errors: [ + { + ...useBacktick, + line: 3, + column: 14, + }, + { + ...useBacktick, + line: 4, + column: 18, + }, + ], + options: ['backtick'], + }, + + // TSAbstractClassProperty + { + code: ` +abstract class Foo { + public abstract a = ''; + public abstract 'a-b' = ''; +} + `, + output: ` +abstract class Foo { + public abstract a = ""; + public abstract "a-b" = ""; +} + `, + errors: [ + { + ...useDoubleQuote, + line: 3, + column: 23, + }, + { + ...useDoubleQuote, + line: 4, + column: 19, + }, + { + ...useDoubleQuote, + line: 4, + column: 27, + }, + ], + }, + { + code: ` +abstract class Foo { + public abstract a = ""; + public abstract "a-b" = ""; +} + `, + output: ` +abstract class Foo { + public abstract a = ''; + public abstract 'a-b' = ''; +} + `, + errors: [ + { + ...useSingleQuote, + line: 3, + column: 23, + }, + { + ...useSingleQuote, + line: 4, + column: 19, + }, + { + ...useSingleQuote, + line: 4, + column: 27, + }, + ], + options: ['single'], + }, + { + code: ` +abstract class Foo { + public abstract a = ""; + public abstract "a-b" = ""; +} + `, + output: ` +abstract class Foo { + public abstract a = \`\`; + public abstract "a-b" = \`\`; +} + `, + errors: [ + { + ...useBacktick, + line: 3, + column: 23, + }, + { + ...useBacktick, + line: 4, + column: 27, + }, + ], + options: ['backtick'], + }, + + // TSAbstractMethodDefinition + { + code: ` +abstract class Foo { + public abstract a(): void; + public abstract 'a-b'(): void; +} + `, + output: ` +abstract class Foo { + public abstract a(): void; + public abstract "a-b"(): void; +} + `, + errors: [ + { + ...useDoubleQuote, + line: 4, + column: 19, + }, + ], + }, + { + code: ` +abstract class Foo { + public abstract a(): void; + public abstract "a-b"(): void; +} + `, + output: ` +abstract class Foo { + public abstract a(): void; + public abstract 'a-b'(): void; +} + `, + errors: [ + { + ...useSingleQuote, + line: 4, + column: 19, + }, + ], + options: ['single'], + }, ], });