From ea6c303a9fa2696007b63d4c6621b0a3de8efe94 Mon Sep 17 00:00:00 2001 From: Alex Parloti Date: Sat, 13 Jan 2024 22:16:25 -0300 Subject: [PATCH] fix(eslint-plugin): member-ordering default configuration (#5452) --- .../docs/rules/member-ordering.md | 329 ++++++++++-------- .../src/rules/member-ordering.ts | 6 +- .../tests/rules/member-ordering.test.ts | 116 ++++++ 3 files changed, 309 insertions(+), 142 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/member-ordering.md b/packages/eslint-plugin/docs/rules/member-ordering.md index 711d590728c1..74fa2127b392 100644 --- a/packages/eslint-plugin/docs/rules/member-ordering.md +++ b/packages/eslint-plugin/docs/rules/member-ordering.md @@ -25,7 +25,7 @@ type OrderConfig = MemberType[] | SortedOrderConfig | 'never'; interface SortedOrderConfig { memberTypes?: MemberType[] | 'never'; optionalityOrder?: 'optional-first' | 'required-first'; - order: + order?: | 'alphabetically' | 'alphabetically-case-insensitive' | 'as-written' @@ -80,176 +80,178 @@ The default configuration looks as follows: ```jsonc { - "default": [ - // Index signature - "signature", - "call-signature", + "default": { + "memberTypes": [ + // Index signature + "signature", + "call-signature", - // Fields - "public-static-field", - "protected-static-field", - "private-static-field", - "#private-static-field", + // Fields + "public-static-field", + "protected-static-field", + "private-static-field", + "#private-static-field", - "public-decorated-field", - "protected-decorated-field", - "private-decorated-field", + "public-decorated-field", + "protected-decorated-field", + "private-decorated-field", - "public-instance-field", - "protected-instance-field", - "private-instance-field", - "#private-instance-field", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "#private-instance-field", - "public-abstract-field", - "protected-abstract-field", + "public-abstract-field", + "protected-abstract-field", - "public-field", - "protected-field", - "private-field", - "#private-field", + "public-field", + "protected-field", + "private-field", + "#private-field", - "static-field", - "instance-field", - "abstract-field", + "static-field", + "instance-field", + "abstract-field", - "decorated-field", + "decorated-field", - "field", + "field", - // Static initialization - "static-initialization", + // Static initialization + "static-initialization", - // Constructors - "public-constructor", - "protected-constructor", - "private-constructor", + // Constructors + "public-constructor", + "protected-constructor", + "private-constructor", - "constructor", + "constructor", - // Accessors - "public-static-accessor", - "protected-static-accessor", - "private-static-accessor", - "#private-static-accessor", + // Accessors + "public-static-accessor", + "protected-static-accessor", + "private-static-accessor", + "#private-static-accessor", - "public-decorated-accessor", - "protected-decorated-accessor", - "private-decorated-accessor", + "public-decorated-accessor", + "protected-decorated-accessor", + "private-decorated-accessor", - "public-instance-accessor", - "protected-instance-accessor", - "private-instance-accessor", - "#private-instance-accessor", + "public-instance-accessor", + "protected-instance-accessor", + "private-instance-accessor", + "#private-instance-accessor", - "public-abstract-accessor", - "protected-abstract-accessor", + "public-abstract-accessor", + "protected-abstract-accessor", - "public-accessor", - "protected-accessor", - "private-accessor", - "#private-accessor", + "public-accessor", + "protected-accessor", + "private-accessor", + "#private-accessor", - "static-accessor", - "instance-accessor", - "abstract-accessor", + "static-accessor", + "instance-accessor", + "abstract-accessor", - "decorated-accessor", + "decorated-accessor", - "accessor", + "accessor", - // Getters - "public-static-get", - "protected-static-get", - "private-static-get", - "#private-static-get", + // Getters + "public-static-get", + "protected-static-get", + "private-static-get", + "#private-static-get", - "public-decorated-get", - "protected-decorated-get", - "private-decorated-get", + "public-decorated-get", + "protected-decorated-get", + "private-decorated-get", - "public-instance-get", - "protected-instance-get", - "private-instance-get", - "#private-instance-get", + "public-instance-get", + "protected-instance-get", + "private-instance-get", + "#private-instance-get", - "public-abstract-get", - "protected-abstract-get", + "public-abstract-get", + "protected-abstract-get", - "public-get", - "protected-get", - "private-get", - "#private-get", + "public-get", + "protected-get", + "private-get", + "#private-get", - "static-get", - "instance-get", - "abstract-get", + "static-get", + "instance-get", + "abstract-get", - "decorated-get", + "decorated-get", - "get", + "get", - // Setters - "public-static-set", - "protected-static-set", - "private-static-set", - "#private-static-set", + // Setters + "public-static-set", + "protected-static-set", + "private-static-set", + "#private-static-set", - "public-decorated-set", - "protected-decorated-set", - "private-decorated-set", + "public-decorated-set", + "protected-decorated-set", + "private-decorated-set", - "public-instance-set", - "protected-instance-set", - "private-instance-set", - "#private-instance-set", + "public-instance-set", + "protected-instance-set", + "private-instance-set", + "#private-instance-set", - "public-abstract-set", - "protected-abstract-set", + "public-abstract-set", + "protected-abstract-set", - "public-set", - "protected-set", - "private-set", - "#private-set", + "public-set", + "protected-set", + "private-set", + "#private-set", - "static-set", - "instance-set", - "abstract-set", + "static-set", + "instance-set", + "abstract-set", - "decorated-set", + "decorated-set", - "set", + "set", - // Methods - "public-static-method", - "protected-static-method", - "private-static-method", - "#private-static-method", + // Methods + "public-static-method", + "protected-static-method", + "private-static-method", + "#private-static-method", - "public-decorated-method", - "protected-decorated-method", - "private-decorated-method", + "public-decorated-method", + "protected-decorated-method", + "private-decorated-method", - "public-instance-method", - "protected-instance-method", - "private-instance-method", - "#private-instance-method", + "public-instance-method", + "protected-instance-method", + "private-instance-method", + "#private-instance-method", - "public-abstract-method", - "protected-abstract-method", + "public-abstract-method", + "protected-abstract-method", - "public-method", - "protected-method", - "private-method", - "#private-method", + "public-method", + "protected-method", + "private-method", + "#private-method", - "static-method", - "instance-method", - "abstract-method", + "static-method", + "instance-method", + "abstract-method", - "decorated-method", + "decorated-method", - "method" - ] + "method" + ] + } } ``` @@ -792,7 +794,8 @@ type Foo = { #### Sorting Alphabetically Within Member Groups This config specifies that within each `memberTypes` group, members are in an alphabetic case-sensitive order. -You can copy and paste the default order from [Default Configuration](#default-configuration). +The default member order will be applied if `memberTypes` is not specified. +You can see the default order in [Default Configuration](#default-configuration). ```jsonc // .eslintrc.json @@ -802,9 +805,6 @@ You can copy and paste the default order from [Default Configuration](#default-c "error", { "default": { - "memberTypes": [ - /* */ - ], "order": "alphabetically" } } @@ -817,7 +817,7 @@ You can copy and paste the default order from [Default Configuration](#default-c ##### ❌ Incorrect -```ts option='{"default":{"memberTypes":["signature","call-signature","public-static-field","protected-static-field","private-static-field","#private-static-field","public-decorated-field","protected-decorated-field","private-decorated-field","public-instance-field","protected-instance-field","private-instance-field","#private-instance-field","public-abstract-field","protected-abstract-field","public-field","protected-field","private-field","#private-field","static-field","instance-field","abstract-field","decorated-field","field","static-initialization","public-constructor","protected-constructor","private-constructor","constructor","public-static-get","protected-static-get","private-static-get","#private-static-get","public-decorated-get","protected-decorated-get","private-decorated-get","public-instance-get","protected-instance-get","private-instance-get","#private-instance-get","public-abstract-get","protected-abstract-get","public-get","protected-get","private-get","#private-get","static-get","instance-get","abstract-get","decorated-get","get","public-static-set","protected-static-set","private-static-set","#private-static-set","public-decorated-set","protected-decorated-set","private-decorated-set","public-instance-set","protected-instance-set","private-instance-set","#private-instance-set","public-abstract-set","protected-abstract-set","public-set","protected-set","private-set","#private-set","static-set","instance-set","abstract-set","decorated-set","set","public-static-method","protected-static-method","private-static-method","#private-static-method","public-decorated-method","protected-decorated-method","private-decorated-method","public-instance-method","protected-instance-method","private-instance-method","#private-instance-method","public-abstract-method","protected-abstract-method","public-method","protected-method","private-method","#private-method","static-method","instance-method","abstract-method","decorated-method","method"],"order":"alphabetically"}}' +```ts option='{"default":{"order":"alphabetically"}}' interface Foo { a: x; B: x; @@ -831,7 +831,7 @@ interface Foo { ##### ✅ Correct -```ts option='{"default":{"memberTypes":["signature","call-signature","public-static-field","protected-static-field","private-static-field","#private-static-field","public-decorated-field","protected-decorated-field","private-decorated-field","public-instance-field","protected-instance-field","private-instance-field","#private-instance-field","public-abstract-field","protected-abstract-field","public-field","protected-field","private-field","#private-field","static-field","instance-field","abstract-field","decorated-field","field","static-initialization","public-constructor","protected-constructor","private-constructor","constructor","public-static-get","protected-static-get","private-static-get","#private-static-get","public-decorated-get","protected-decorated-get","private-decorated-get","public-instance-get","protected-instance-get","private-instance-get","#private-instance-get","public-abstract-get","protected-abstract-get","public-get","protected-get","private-get","#private-get","static-get","instance-get","abstract-get","decorated-get","get","public-static-set","protected-static-set","private-static-set","#private-static-set","public-decorated-set","protected-decorated-set","private-decorated-set","public-instance-set","protected-instance-set","private-instance-set","#private-instance-set","public-abstract-set","protected-abstract-set","public-set","protected-set","private-set","#private-set","static-set","instance-set","abstract-set","decorated-set","set","public-static-method","protected-static-method","private-static-method","#private-static-method","public-decorated-method","protected-decorated-method","private-decorated-method","public-instance-method","protected-instance-method","private-instance-method","#private-instance-method","public-abstract-method","protected-abstract-method","public-method","protected-method","private-method","#private-method","static-method","instance-method","abstract-method","decorated-method","method"],"order":"alphabetically"}}' +```ts option='{"default":{"order":"alphabetically"}}' interface Foo { B: x; a: x; @@ -843,10 +843,62 @@ interface Foo { } ``` +#### Sorting Alphabetically Within Custom Member Groups + +This config specifies that within each custom `memberTypes` group, members are in an alphabetic case-sensitive order. + +```jsonc +// .eslintrc.json +{ + "rules": { + "@typescript-eslint/member-ordering": [ + "error", + { + "default": { + "memberTypes": ["method", "field"], + "order": "alphabetically" + } + } + ] + } +} +``` + + + +##### ❌ Incorrect + +```ts option='{"default":{"memberTypes":["method","field"],"order":"alphabetically"}}' +interface Foo { + B(): void; + c(): void; + a(): void; + + a: x; + B: x; + c: x; +} +``` + +##### ✅ Correct + +```ts option='{"default":{"memberTypes":["method","field"],"order":"alphabetically"}}' +interface Foo { + B(): void; + a(): void; + c(): void; + + B: x; + a: x; + c: x; +} +``` + #### Sorting Alphabetically Case Insensitive Within Member Groups This config specifies that within each `memberTypes` group, members are in an alphabetic case-insensitive order. -You can copy and paste the default order from [Default Configuration](#default-configuration). +The default member order will be applied if `memberTypes` is not specified. +You can see the default order in [Default Configuration](#default-configuration). ```jsonc // .eslintrc.json @@ -856,9 +908,6 @@ You can copy and paste the default order from [Default Configuration](#default-c "error", { "default": { - "memberTypes": [ - /* */ - ], "order": "alphabetically-case-insensitive" } } @@ -871,7 +920,7 @@ You can copy and paste the default order from [Default Configuration](#default-c ##### ❌ Incorrect -```ts option='{"default":{"memberTypes":["signature","call-signature","public-static-field","protected-static-field","private-static-field","#private-static-field","public-decorated-field","protected-decorated-field","private-decorated-field","public-instance-field","protected-instance-field","private-instance-field","#private-instance-field","public-abstract-field","protected-abstract-field","public-field","protected-field","private-field","#private-field","static-field","instance-field","abstract-field","decorated-field","field","static-initialization","public-constructor","protected-constructor","private-constructor","constructor","public-static-get","protected-static-get","private-static-get","#private-static-get","public-decorated-get","protected-decorated-get","private-decorated-get","public-instance-get","protected-instance-get","private-instance-get","#private-instance-get","public-abstract-get","protected-abstract-get","public-get","protected-get","private-get","#private-get","static-get","instance-get","abstract-get","decorated-get","get","public-static-set","protected-static-set","private-static-set","#private-static-set","public-decorated-set","protected-decorated-set","private-decorated-set","public-instance-set","protected-instance-set","private-instance-set","#private-instance-set","public-abstract-set","protected-abstract-set","public-set","protected-set","private-set","#private-set","static-set","instance-set","abstract-set","decorated-set","set","public-static-method","protected-static-method","private-static-method","#private-static-method","public-decorated-method","protected-decorated-method","private-decorated-method","public-instance-method","protected-instance-method","private-instance-method","#private-instance-method","public-abstract-method","protected-abstract-method","public-method","protected-method","private-method","#private-method","static-method","instance-method","abstract-method","decorated-method","method"],"order":"alphabetically-case-insensitive"}}' +```ts option='{"default":{"order":"alphabetically-case-insensitive"}}' interface Foo { B: x; a: x; @@ -885,7 +934,7 @@ interface Foo { ##### ✅ Correct -```ts option='{"default":{"memberTypes":["signature","call-signature","public-static-field","protected-static-field","private-static-field","#private-static-field","public-decorated-field","protected-decorated-field","private-decorated-field","public-instance-field","protected-instance-field","private-instance-field","#private-instance-field","public-abstract-field","protected-abstract-field","public-field","protected-field","private-field","#private-field","static-field","instance-field","abstract-field","decorated-field","field","static-initialization","public-constructor","protected-constructor","private-constructor","constructor","public-static-get","protected-static-get","private-static-get","#private-static-get","public-decorated-get","protected-decorated-get","private-decorated-get","public-instance-get","protected-instance-get","private-instance-get","#private-instance-get","public-abstract-get","protected-abstract-get","public-get","protected-get","private-get","#private-get","static-get","instance-get","abstract-get","decorated-get","get","public-static-set","protected-static-set","private-static-set","#private-static-set","public-decorated-set","protected-decorated-set","private-decorated-set","public-instance-set","protected-instance-set","private-instance-set","#private-instance-set","public-abstract-set","protected-abstract-set","public-set","protected-set","private-set","#private-set","static-set","instance-set","abstract-set","decorated-set","set","public-static-method","protected-static-method","private-static-method","#private-static-method","public-decorated-method","protected-decorated-method","private-decorated-method","public-instance-method","protected-instance-method","private-instance-method","#private-instance-method","public-abstract-method","protected-abstract-method","public-method","protected-method","private-method","#private-method","static-method","instance-method","abstract-method","decorated-method","method"],"order":"alphabetically-case-insensitive"}}' +```ts option='{"default":{"order":"alphabetically-case-insensitive"}}' interface Foo { a: x; B: x; diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index c404823dfd80..34fed637e6c8 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -70,7 +70,7 @@ type Order = AlphabeticalOrder | 'as-written'; interface SortedOrderConfig { memberTypes?: MemberType[] | 'never'; optionalityOrder?: OptionalityOrder; - order: Order; + order?: Order; } type OrderConfig = MemberType[] | SortedOrderConfig | 'never'; @@ -739,7 +739,9 @@ export default createRule({ }, defaultOptions: [ { - default: defaultOrder, + default: { + memberTypes: defaultOrder, + }, }, ], create(context, [options]) { diff --git a/packages/eslint-plugin/tests/rules/member-ordering.test.ts b/packages/eslint-plugin/tests/rules/member-ordering.test.ts index 47019dfe5ab5..6ebcb82e3aaa 100644 --- a/packages/eslint-plugin/tests/rules/member-ordering.test.ts +++ b/packages/eslint-plugin/tests/rules/member-ordering.test.ts @@ -1649,6 +1649,31 @@ class Foo { }, ], }, + { + name: 'default member types with alphabetically-case-insensitive order', + code: ` +// no accessibility === public +class Foo { + [A: string]: any; + [a: string]: any; + static C: boolean; + static d: boolean; + b: any; + B: any; + get e(): string {} + get E(): string {} + private imPrivate() {} + private ImPrivate() {} +} + `, + options: [ + { + default: { + order: 'alphabetically-case-insensitive', + }, + }, + ], + }, { code: ` class Foo { @@ -2032,6 +2057,46 @@ class Foo { }, ], }, + { + name: 'default member types with alphabetically order', + code: ` +// no accessibility === public +class Foo { + [A: string]: any; + [B: string]: any; + [a: string]: any; + [b: string]: any; + static C: boolean; + static d: boolean; + get E(): string {} + get e(): string {} + private ImPrivate() {} + private imPrivate() {} +} + `, + options: [ + { + default: { + order: 'alphabetically', + }, + }, + ], + }, + { + name: 'alphabetically order without member types', + code: ` +// no accessibility === public +interface Foo { + A: string; + B: string; + [Z: string]: any; + c(); + new (); + r(); +} + `, + options: [{ default: { memberTypes: 'never', order: 'alphabetically' } }], + }, { code: ` class Foo { @@ -4802,6 +4867,57 @@ class Foo { }, ], }, + { + name: 'default member types with alphabetically order', + code: ` +// no accessibility === public +class Foo { + static C: boolean; + [B: string]: any; + private A() {} +} + `, + errors: [ + { + messageId: 'incorrectGroupOrder', + data: { + name: 'B', + rank: 'public static field', + }, + line: 5, + column: 3, + }, + ], + options: [ + { + default: { + order: 'alphabetically', + }, + }, + ], + }, + { + name: 'alphabetically order without member types', + code: ` +// no accessibility === public +class Foo { + static C: boolean; + [B: string]: any; +} + `, + errors: [ + { + messageId: 'incorrectOrder', + data: { + member: 'B', + beforeMember: 'C', + }, + line: 5, + column: 3, + }, + ], + options: [{ default: { memberTypes: 'never', order: 'alphabetically' } }], + }, { name: '#private and private member order', code: `