From c91debda968d30a072a6885739dee52cf097b916 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 23 Aug 2020 03:23:04 +0900 Subject: [PATCH 1/6] feat(eslint-plugin): add extension rule `comma-dangle` --- packages/eslint-plugin/README.md | 1 + .../eslint-plugin/docs/rules/comma-dangle.md | 34 +++ packages/eslint-plugin/src/configs/all.ts | 1 + .../eslint-plugin/src/rules/comma-dangle.ts | 179 ++++++++++++++ packages/eslint-plugin/src/rules/index.ts | 2 + .../tests/rules/comma-dangle.test.ts | 223 ++++++++++++++++++ .../eslint-plugin/typings/eslint-rules.d.ts | 33 +++ 7 files changed, 473 insertions(+) create mode 100644 packages/eslint-plugin/docs/rules/comma-dangle.md create mode 100644 packages/eslint-plugin/src/rules/comma-dangle.ts create mode 100644 packages/eslint-plugin/tests/rules/comma-dangle.test.ts diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index cb8a5546142..9e87ad58536 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -212,6 +212,7 @@ In these cases, we create what we call an extension rule; a rule within our plug | [`@typescript-eslint/return-await`](./docs/rules/return-await.md) | Enforces consistent returning of awaited values | | :wrench: | :thought_balloon: | | [`@typescript-eslint/semi`](./docs/rules/semi.md) | Require or disallow semicolons instead of ASI | | :wrench: | | | [`@typescript-eslint/space-before-function-paren`](./docs/rules/space-before-function-paren.md) | Enforces consistent spacing before function parenthesis | | :wrench: | | +| [`@typescript-eslint/comma-dangle`](./docs/rules/comma-dangle.md) | Require or disallow trailing comma | | :wrench: | | diff --git a/packages/eslint-plugin/docs/rules/comma-dangle.md b/packages/eslint-plugin/docs/rules/comma-dangle.md new file mode 100644 index 00000000000..961fe59ee3c --- /dev/null +++ b/packages/eslint-plugin/docs/rules/comma-dangle.md @@ -0,0 +1,34 @@ +# Require or disallow trailing comma (`comma-dangle`) + +## Rule Details + +This rule extends the base [`eslint/comma-dangle`](https://eslint.org/docs/rules/comma-dangle) rule. +It adds support for TypeScript syntax. + +See the [ESLint documentation](https://eslint.org/docs/rules/comma-dangle) for more details on the `comma-dangle` rule. + +## Rule Changes + +```cjson +{ + // note you must disable the base rule as it can report incorrect errors + "comma-dange": "off", + "@typescript-eslint/comma-dange": ["error"] +} +``` + +In addition to the options supported by the `comma-dange` rule in ESLint core, the rule adds the following options: + +## Options + +This rule has a string option and an object option. + +- Object option: + + - `"enums"` is for trailing comma in enum. (e.g. `enum Foo = {Bar,}`) + - `"generics"` is for trailing comma in generic. (e.g. `function foo() {}`) + - `"tuples"` is for trailing comma in tuple. (e.g. `type Foo = [string,]`) + +- [See the other options allowed](https://github.com/eslint/eslint/blob/master/docs/rules/comma-dange.md#options) + +Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/comma-dange.md) diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index 8361bde29b2..5ea68ad2b0c 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -132,5 +132,6 @@ export = { '@typescript-eslint/typedef': 'error', '@typescript-eslint/unbound-method': 'error', '@typescript-eslint/unified-signatures': 'error', + '@typescript-eslint/comma-dangle': 'error', }, }; diff --git a/packages/eslint-plugin/src/rules/comma-dangle.ts b/packages/eslint-plugin/src/rules/comma-dangle.ts new file mode 100644 index 00000000000..a498f7aa0c6 --- /dev/null +++ b/packages/eslint-plugin/src/rules/comma-dangle.ts @@ -0,0 +1,179 @@ +import * as util from '../util'; +import baseRule from 'eslint/lib/rules/comma-dangle'; +import { + TSESTree, + AST_NODE_TYPES, +} from '@typescript-eslint/experimental-utils'; + +export type Options = util.InferOptionsTypeFromRule; +export type MessageIds = util.InferMessageIdsTypeFromRule; + +type Option = Options[0]; +type NormalizedOptions = Required< + Pick, 'enums' | 'generics' | 'tuples'> +>; + +const OPTION_VALUE_SCHEME = [ + 'always-multiline', + 'always', + 'never', + 'only-multiline', +]; + +const DEFAULT_OPTION_VALUE = 'never'; + +function normalizeOptions(options: Option): NormalizedOptions { + if (typeof options === 'string') { + return { + enums: options, + generics: options, + tuples: options, + }; + } + return { + enums: options.enums ?? DEFAULT_OPTION_VALUE, + generics: options.generics ?? DEFAULT_OPTION_VALUE, + tuples: options.tuples ?? DEFAULT_OPTION_VALUE, + }; +} + +export default util.createRule({ + name: 'comman-dangle', + meta: { + type: 'layout', + docs: { + description: 'Require or disallow trailing comma', + category: 'Stylistic Issues', + recommended: false, + extendsBaseRule: true, + }, + schema: { + definitions: { + value: { + enum: OPTION_VALUE_SCHEME, + }, + valueWithIgnore: { + enum: [...OPTION_VALUE_SCHEME, 'ignore'], + }, + }, + type: 'array', + items: [ + { + oneOf: [ + { + $ref: '#/definitions/value', + }, + { + type: 'object', + properties: { + arrays: { $ref: '#/definitions/valueWithIgnore' }, + objects: { $ref: '#/definitions/valueWithIgnore' }, + imports: { $ref: '#/definitions/valueWithIgnore' }, + exports: { $ref: '#/definitions/valueWithIgnore' }, + functions: { $ref: '#/definitions/valueWithIgnore' }, + enums: { $ref: '#/definitions/valueWithIgnore' }, + generics: { $ref: '#/definitions/valueWithIgnore' }, + tuples: { $ref: '#/definitions/valueWithIgnore' }, + }, + additionalProperties: false, + }, + ], + }, + ], + }, + fixable: 'code', + messages: baseRule.meta.messages, + }, + defaultOptions: ['never'], + create(context, [options]) { + const rules = baseRule.create(context); + const sourceCode = context.getSourceCode(); + const normalizedOptions = normalizeOptions(options); + + const predicate = { + always: forceComma, + 'always-multiline': forceCommaIfMultiline, + 'only-multiline': allowCommaIfMultiline, + never: forbidComma, + ignore: (): void => {}, + }; + + function last(nodes: TSESTree.Node[]): TSESTree.Node | null { + return nodes[nodes.length - 1] ?? null; + } + + function getLastItem(node: TSESTree.Node): TSESTree.Node | null { + switch (node.type) { + case AST_NODE_TYPES.TSEnumDeclaration: + return last(node.members); + case AST_NODE_TYPES.TSTypeParameterDeclaration: + return last(node.params); + case AST_NODE_TYPES.TSTupleType: + return last(node.elementTypes); + default: + return null; + } + } + + function getTrailingToken(node: TSESTree.Node): TSESTree.Token | null { + const last = getLastItem(node); + const trailing = last && sourceCode.getTokenAfter(last); + return trailing; + } + + function isMultiline(node: TSESTree.Node): boolean { + const last = getLastItem(node); + const lastToken = sourceCode.getLastToken(node); + return last?.loc.end.line !== lastToken?.loc.end.line; + } + + function forbidComma(node: TSESTree.Node): void { + const last = getLastItem(node); + const trailing = getTrailingToken(node); + if (last && trailing && util.isCommaToken(trailing)) { + context.report({ + node, + messageId: 'unexpected', + fix(fixer) { + return fixer.remove(trailing); + }, + }); + } + } + + function forceComma(node: TSESTree.Node): void { + const last = getLastItem(node); + const trailing = getTrailingToken(node); + if (last && trailing && !util.isCommaToken(trailing)) { + context.report({ + node, + messageId: 'missing', + fix(fixer) { + return fixer.insertTextAfter(last, ','); + }, + }); + } + } + + function allowCommaIfMultiline(node: TSESTree.Node): void { + if (!isMultiline(node)) { + forbidComma(node); + } + } + + function forceCommaIfMultiline(node: TSESTree.Node): void { + if (isMultiline(node)) { + forceComma(node); + } else { + forbidComma(node); + } + } + + return { + ...rules, + TSEnumDeclaration: predicate[normalizedOptions.enums], + TSTypeParameterDeclaration: predicate[normalizedOptions.generics], + TSTupleType: predicate[normalizedOptions.tuples], + }; + }, +}); diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 85d0642fc79..9165e4f1c50 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -99,6 +99,7 @@ import typeAnnotationSpacing from './type-annotation-spacing'; import typedef from './typedef'; import unboundMethod from './unbound-method'; import unifiedSignatures from './unified-signatures'; +import commaDangle from './comma-dangle'; export default { 'adjacent-overload-signatures': adjacentOverloadSignatures, @@ -202,4 +203,5 @@ export default { 'unified-signatures': unifiedSignatures, 'lines-between-class-members': linesBetweenClassMembers, 'no-loss-of-precision': noLossOfPrecision, + 'comma-dangle': commaDangle, }; diff --git a/packages/eslint-plugin/tests/rules/comma-dangle.test.ts b/packages/eslint-plugin/tests/rules/comma-dangle.test.ts new file mode 100644 index 00000000000..2299dcc2fe3 --- /dev/null +++ b/packages/eslint-plugin/tests/rules/comma-dangle.test.ts @@ -0,0 +1,223 @@ +/* eslint-disable eslint-comments/no-use */ +// this rule tests the new lines, which prettier will want to fix and break the tests +/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ +/* eslint-enable eslint-comments/no-use */ +import rule from '../../src/rules/comma-dangle'; +import { RuleTester } from '../RuleTester'; + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', +}); + +ruleTester.run('comma-dangle', rule, { + valid: [ + // default + { code: 'enum Foo {Bar}' }, + { code: 'function Foo() {}' }, + + // never + { code: 'enum Foo {Bar}', options: ['never'] }, + { code: 'enum Foo {Bar\n}', options: ['never'] }, + { code: 'enum Foo {Bar\n}', options: [{ enums: 'never' }] }, + { code: 'function Foo() {}', options: ['never'] }, + { code: 'function Foo() {}', options: ['never'] }, + { code: 'function Foo() {}', options: [{ generics: 'never' }] }, + { code: 'type Foo = [string]', options: ['never'] }, + { code: 'type Foo = [string]', options: [{ tuples: 'never' }] }, + + // always + { code: 'enum Foo {Bar,}', options: ['always'] }, + { code: 'enum Foo {Bar,\n}', options: ['always'] }, + { code: 'enum Foo {Bar,\n}', options: [{ enums: 'always' }] }, + { code: 'function Foo() {}', options: ['always'] }, + { code: 'function Foo() {}', options: ['always'] }, + { code: 'function Foo() {}', options: [{ generics: 'always' }] }, + { code: 'type Foo = [string,]', options: ['always'] }, + { code: 'type Foo = [string,\n]', options: [{ tuples: 'always' }] }, + + // always-multiline + { code: 'enum Foo {Bar,\n}', options: ['always-multiline'] }, + { code: 'enum Foo {Bar,\n}', options: [{ enums: 'always-multiline' }] }, + { code: 'function Foo() {}', options: ['always-multiline'] }, + { + code: 'function Foo() {}', + options: [{ generics: 'always-multiline' }], + }, + { code: 'type Foo = [string,\n]', options: ['always-multiline'] }, + { + code: 'type Foo = [string,\n]', + options: [{ tuples: 'always-multiline' }], + }, + + // only-multiline + { code: 'enum Foo {Bar}', options: ['only-multiline'] }, + { code: 'enum Foo {Bar\n}', options: ['only-multiline'] }, + { code: 'enum Foo {Bar,\n}', options: ['only-multiline'] }, + { code: 'enum Foo {Bar,\n}', options: [{ enums: 'only-multiline' }] }, + { code: 'function Foo() {}', options: ['only-multiline'] }, + { code: 'function Foo() {}', options: ['only-multiline'] }, + { code: 'function Foo() {}', options: ['only-multiline'] }, + { + code: 'function Foo() {}', + options: [{ generics: 'only-multiline' }], + }, + { + code: 'function Foo() {}', + options: [{ generics: 'only-multiline' }], + }, + { code: 'type Foo = [string\n]', options: [{ tuples: 'only-multiline' }] }, + { code: 'type Foo = [string,\n]', options: [{ tuples: 'only-multiline' }] }, + + // each options + { + code: ` +const Obj = { a: 1 }; +enum Foo {Bar} +function Baz() {} +type Qux = [string, +] + `, + options: [ + { + enums: 'never', + generics: 'always', + tuples: 'always-multiline', + }, + ], + }, + ], + invalid: [ + // default + { + code: 'enum Foo {Bar,}', + output: 'enum Foo {Bar}', + errors: [{ messageId: 'unexpected' }], + }, + { + code: 'function Foo() {}', + output: 'function Foo() {}', + errors: [{ messageId: 'unexpected' }], + }, + { + code: 'type Foo = [string,]', + output: 'type Foo = [string]', + errors: [{ messageId: 'unexpected' }], + }, + + // never + { + code: 'enum Foo {Bar,}', + output: 'enum Foo {Bar}', + options: ['never'], + errors: [{ messageId: 'unexpected' }], + }, + { + code: 'enum Foo {Bar,\n}', + output: 'enum Foo {Bar\n}', + options: ['never'], + errors: [{ messageId: 'unexpected' }], + }, + { + code: 'function Foo() {}', + output: 'function Foo() {}', + options: ['never'], + errors: [{ messageId: 'unexpected' }], + }, + { + code: 'function Foo() {}', + output: 'function Foo() {}', + options: ['never'], + errors: [{ messageId: 'unexpected' }], + }, + { + code: 'type Foo = [string,]', + output: 'type Foo = [string]', + options: ['never'], + errors: [{ messageId: 'unexpected' }], + }, + { + code: 'type Foo = [string,\n]', + output: 'type Foo = [string\n]', + options: ['never'], + errors: [{ messageId: 'unexpected' }], + }, + + // always + { + code: 'enum Foo {Bar}', + output: 'enum Foo {Bar,}', + options: ['always'], + errors: [{ messageId: 'missing' }], + }, + { + code: 'enum Foo {Bar\n}', + output: 'enum Foo {Bar,\n}', + options: ['always'], + errors: [{ messageId: 'missing' }], + }, + { + code: 'function Foo() {}', + output: 'function Foo() {}', + options: ['always'], + errors: [{ messageId: 'missing' }], + }, + { + code: 'function Foo() {}', + output: 'function Foo() {}', + options: ['always'], + errors: [{ messageId: 'missing' }], + }, + { + code: 'type Foo = [string]', + output: 'type Foo = [string,]', + options: ['always'], + errors: [{ messageId: 'missing' }], + }, + { + code: 'type Foo = [string\n]', + output: 'type Foo = [string,\n]', + options: ['always'], + errors: [{ messageId: 'missing' }], + }, + + // always-multiline + { + code: 'enum Foo {Bar\n}', + output: 'enum Foo {Bar,\n}', + options: ['always-multiline'], + errors: [{ messageId: 'missing' }], + }, + { + code: 'function Foo() {}', + output: 'function Foo() {}', + options: ['always-multiline'], + errors: [{ messageId: 'missing' }], + }, + { + code: 'type Foo = [string\n]', + output: 'type Foo = [string,\n]', + options: ['always-multiline'], + errors: [{ messageId: 'missing' }], + }, + + // only-multiline + { + code: 'enum Foo {Bar,}', + output: 'enum Foo {Bar}', + options: ['only-multiline'], + errors: [{ messageId: 'unexpected' }], + }, + { + code: 'function Foo() {}', + output: 'function Foo() {}', + options: ['only-multiline'], + errors: [{ messageId: 'unexpected' }], + }, + { + code: 'type Foo = [string,]', + output: 'type Foo = [string]', + options: ['only-multiline'], + errors: [{ messageId: 'unexpected' }], + }, + ], +}); diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index add5af1c1bb..60f10944fc1 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -715,3 +715,36 @@ declare module 'eslint/lib/rules/no-loss-of-precision' { >; export = rule; } + +declare module 'eslint/lib/rules/comma-dangle' { + import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; + + type StringOptions = + | 'always-multiline' + | 'always' + | 'never' + | 'only-multiline'; + type Selectors = + | 'arrays' + | 'objects' + | 'imports' + | 'exports' + | 'functions' + | 'enums' + | 'generics' + | 'tuples'; + type ObjectOptions = Partial>; + + const rule: TSESLint.RuleModule< + 'unexpected' | 'missing', + [StringOptions | ObjectOptions], + { + TSEnumDeclaration(node: TSESTree.TSEnumDeclaration): void; + TSTypeParameterDeclaration( + node: TSESTree.TSTypeParameterDeclaration, + ): void; + TSTupleType(node: TSESTree.TSTupleType): void; + } + >; + export = rule; +} From 204ddf2e143a126e438677809218929d03b4c07b Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 23 Aug 2020 13:58:16 +0900 Subject: [PATCH 2/6] add test case --- .../eslint-plugin/tests/rules/comma-dangle.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/comma-dangle.test.ts b/packages/eslint-plugin/tests/rules/comma-dangle.test.ts index 2299dcc2fe3..3a4d9ad8dae 100644 --- a/packages/eslint-plugin/tests/rules/comma-dangle.test.ts +++ b/packages/eslint-plugin/tests/rules/comma-dangle.test.ts @@ -12,8 +12,12 @@ const ruleTester = new RuleTester({ ruleTester.run('comma-dangle', rule, { valid: [ // default + { code: 'enum Foo {}' }, + { code: 'enum Foo {\n}' }, { code: 'enum Foo {Bar}' }, { code: 'function Foo() {}' }, + { code: 'type Foo = []' }, + { code: 'type Foo = [\n]' }, // never { code: 'enum Foo {Bar}', options: ['never'] }, @@ -87,6 +91,13 @@ type Qux = [string, }, ], invalid: [ + // base rule + { + code: 'const Foo = {bar: 1,}', + output: 'const Foo = {bar: 1}', + errors: [{ messageId: 'unexpected' }], + }, + // default { code: 'enum Foo {Bar,}', From bdc06380a04ede5e75c441da8816ab2d0c9e57bb Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 23 Aug 2020 14:15:43 +0900 Subject: [PATCH 3/6] fix doc check --- packages/eslint-plugin/README.md | 2 +- packages/eslint-plugin/src/rules/comma-dangle.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 9e87ad58536..d3279613b3b 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -187,6 +187,7 @@ In these cases, we create what we call an extension rule; a rule within our plug | Name | Description | :heavy_check_mark: | :wrench: | :thought_balloon: | | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------ | -------- | ----------------- | | [`@typescript-eslint/brace-style`](./docs/rules/brace-style.md) | Enforce consistent brace style for blocks | | :wrench: | | +| [`@typescript-eslint/comma-dangle`](./docs/rules/comma-dangle.md) | Require or disallow trailing comma | | :wrench: | | | [`@typescript-eslint/comma-spacing`](./docs/rules/comma-spacing.md) | Enforces consistent spacing before and after commas | | :wrench: | | | [`@typescript-eslint/default-param-last`](./docs/rules/default-param-last.md) | Enforce default parameters to be last | | | | | [`@typescript-eslint/dot-notation`](./docs/rules/dot-notation.md) | enforce dot notation whenever possible | | :wrench: | :thought_balloon: | @@ -212,7 +213,6 @@ In these cases, we create what we call an extension rule; a rule within our plug | [`@typescript-eslint/return-await`](./docs/rules/return-await.md) | Enforces consistent returning of awaited values | | :wrench: | :thought_balloon: | | [`@typescript-eslint/semi`](./docs/rules/semi.md) | Require or disallow semicolons instead of ASI | | :wrench: | | | [`@typescript-eslint/space-before-function-paren`](./docs/rules/space-before-function-paren.md) | Enforces consistent spacing before function parenthesis | | :wrench: | | -| [`@typescript-eslint/comma-dangle`](./docs/rules/comma-dangle.md) | Require or disallow trailing comma | | :wrench: | | diff --git a/packages/eslint-plugin/src/rules/comma-dangle.ts b/packages/eslint-plugin/src/rules/comma-dangle.ts index a498f7aa0c6..e0e06a6711d 100644 --- a/packages/eslint-plugin/src/rules/comma-dangle.ts +++ b/packages/eslint-plugin/src/rules/comma-dangle.ts @@ -38,7 +38,7 @@ function normalizeOptions(options: Option): NormalizedOptions { } export default util.createRule({ - name: 'comman-dangle', + name: 'comma-dangle', meta: { type: 'layout', docs: { From ef929b3792af8d3958abe2fac23404c04cc065d1 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 23 Aug 2020 14:19:07 +0900 Subject: [PATCH 4/6] off base rule --- packages/eslint-plugin/src/configs/all.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index 5ea68ad2b0c..30439653b0c 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -132,6 +132,7 @@ export = { '@typescript-eslint/typedef': 'error', '@typescript-eslint/unbound-method': 'error', '@typescript-eslint/unified-signatures': 'error', + 'comma-dangle': 'off', '@typescript-eslint/comma-dangle': 'error', }, }; From b3b15888334ec3179be5435715ade4b1177e1bef Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 23 Aug 2020 14:32:39 +0900 Subject: [PATCH 5/6] add tc --- .../tests/rules/comma-dangle.test.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/comma-dangle.test.ts b/packages/eslint-plugin/tests/rules/comma-dangle.test.ts index 3a4d9ad8dae..1e94e982971 100644 --- a/packages/eslint-plugin/tests/rules/comma-dangle.test.ts +++ b/packages/eslint-plugin/tests/rules/comma-dangle.test.ts @@ -40,13 +40,16 @@ ruleTester.run('comma-dangle', rule, { { code: 'type Foo = [string,\n]', options: [{ tuples: 'always' }] }, // always-multiline + { code: 'enum Foo {Bar}', options: ['always-multiline'] }, { code: 'enum Foo {Bar,\n}', options: ['always-multiline'] }, { code: 'enum Foo {Bar,\n}', options: [{ enums: 'always-multiline' }] }, + { code: 'function Foo() {}', options: ['always-multiline'] }, { code: 'function Foo() {}', options: ['always-multiline'] }, { code: 'function Foo() {}', options: [{ generics: 'always-multiline' }], }, + { code: 'type Foo = [string]', options: ['always-multiline'] }, { code: 'type Foo = [string,\n]', options: ['always-multiline'] }, { code: 'type Foo = [string,\n]', @@ -192,18 +195,36 @@ type Qux = [string, }, // always-multiline + { + code: 'enum Foo {Bar,}', + output: 'enum Foo {Bar}', + options: ['always-multiline'], + errors: [{ messageId: 'unexpected' }], + }, { code: 'enum Foo {Bar\n}', output: 'enum Foo {Bar,\n}', options: ['always-multiline'], errors: [{ messageId: 'missing' }], }, + { + code: 'function Foo() {}', + output: 'function Foo() {}', + options: ['always-multiline'], + errors: [{ messageId: 'unexpected' }], + }, { code: 'function Foo() {}', output: 'function Foo() {}', options: ['always-multiline'], errors: [{ messageId: 'missing' }], }, + { + code: 'type Foo = [string,]', + output: 'type Foo = [string]', + options: ['always-multiline'], + errors: [{ messageId: 'unexpected' }], + }, { code: 'type Foo = [string\n]', output: 'type Foo = [string,\n]', From 085789a20fc2968d213f444dd58aa207cf9eabe0 Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Mon, 24 Aug 2020 11:34:40 +0900 Subject: [PATCH 6/6] Update packages/eslint-plugin/docs/rules/comma-dangle.md Co-authored-by: Brad Zacher --- packages/eslint-plugin/docs/rules/comma-dangle.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/comma-dangle.md b/packages/eslint-plugin/docs/rules/comma-dangle.md index 961fe59ee3c..bfb40d338bc 100644 --- a/packages/eslint-plugin/docs/rules/comma-dangle.md +++ b/packages/eslint-plugin/docs/rules/comma-dangle.md @@ -12,12 +12,12 @@ See the [ESLint documentation](https://eslint.org/docs/rules/comma-dangle) for m ```cjson { // note you must disable the base rule as it can report incorrect errors - "comma-dange": "off", - "@typescript-eslint/comma-dange": ["error"] + "comma-dangle": "off", + "@typescript-eslint/comma-dangle": ["error"] } ``` -In addition to the options supported by the `comma-dange` rule in ESLint core, the rule adds the following options: +In addition to the options supported by the `comma-dangle` rule in ESLint core, the rule adds the following options: ## Options @@ -29,6 +29,6 @@ This rule has a string option and an object option. - `"generics"` is for trailing comma in generic. (e.g. `function foo() {}`) - `"tuples"` is for trailing comma in tuple. (e.g. `type Foo = [string,]`) -- [See the other options allowed](https://github.com/eslint/eslint/blob/master/docs/rules/comma-dange.md#options) +- [See the other options allowed](https://github.com/eslint/eslint/blob/master/docs/rules/comma-dangle.md#options) -Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/comma-dange.md) +Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/comma-dangle.md)