From f4cbc9054f163d95824378dc1a8e0a027817a547 Mon Sep 17 00:00:00 2001 From: Milos Lajtman Date: Wed, 8 Apr 2020 22:23:06 +0200 Subject: [PATCH 1/5] feat(eslint-plugin): [member-ordering] add decorators support --- .../docs/rules/member-ordering.md | 58 +++- .../src/rules/member-ordering.ts | 127 +++++--- .../tests/rules/member-ordering.test.ts | 280 +++++++++++++++++- 3 files changed, 410 insertions(+), 55 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/member-ordering.md b/packages/eslint-plugin/docs/rules/member-ordering.md index cccf2bbbe0a..cfaffa7c1c0 100644 --- a/packages/eslint-plugin/docs/rules/member-ordering.md +++ b/packages/eslint-plugin/docs/rules/member-ordering.md @@ -62,6 +62,9 @@ There are multiple ways to specify the member types. The most explicit and granu 'public-static-field', 'protected-static-field', 'private-static-field', + 'public-decorated-field', + 'protected-decorated-field', + 'private-decorated-field', 'public-instance-field', 'protected-instance-field', 'private-instance-field', @@ -78,6 +81,9 @@ There are multiple ways to specify the member types. The most explicit and granu 'public-static-method', 'protected-static-method', 'private-static-method', + 'public-decorated-method', + 'protected-decorated-method', + 'private-decorated-method', 'public-instance-method', 'protected-instance-method', 'private-instance-method', @@ -99,17 +105,45 @@ It is also possible to group member types by their accessibility (`static`, `ins // No accessibility for index signature. See above. // Fields - 'public-field', // = ['public-static-field', 'public-instance-field']) - 'protected-field', // = ['protected-static-field', 'protected-instance-field']) - 'private-field', // = ['private-static-field', 'private-instance-field']) + 'public-field', // = ['public-static-field', 'public-instance-field'] + 'protected-field', // = ['protected-static-field', 'protected-instance-field'] + 'private-field', // = ['private-static-field', 'private-instance-field'] // Constructors // Only the accessibility of constructors is configurable. See below. // Methods - 'public-method', // = ['public-static-method', 'public-instance-method']) - 'protected-method', // = ['protected-static-method', 'protected-instance-method']) - 'private-method', // = ['private-static-method', 'private-instance-method']) + 'public-method', // = ['public-static-method', 'public-instance-method'] + 'protected-method', // = ['protected-static-method', 'protected-instance-method'] + 'private-method', // = ['private-static-method', 'private-instance-method'] +] +``` + +### Member group types (with accessibility and a decorator) + +It is also possible to group methods or fields with a decorator separately, optionally specifying +their accessibility. + +```json5 +[ + // Index signature + // No decorators for index signature. + + // Fields + 'public-decorated-field', + 'protected-decorated-field', + 'private-decorated-field', + + 'decorated-field', // = ['public-decorated-field', 'protected-decorated-field', private-decorated-field] + + // Constructors + // There are no decorators for constructors. + + 'public-decorated-method', + 'protected-decorated-method', + 'private-decorated-method', + + 'decorated-method', // = ['public-decorated-method', 'protected-decorated-method', 'private-decorated-method'] ] ``` @@ -174,6 +208,10 @@ The default configuration looks as follows: 'protected-static-field', 'private-static-field', + 'public-decorated-field', + 'protected-decorated-field', + 'private-decorated-field', + 'public-instance-field', 'protected-instance-field', 'private-instance-field', @@ -190,6 +228,8 @@ The default configuration looks as follows: 'instance-field', 'abstract-field', + 'decorated-field', + 'field', // Constructors @@ -204,6 +244,10 @@ The default configuration looks as follows: 'protected-static-method', 'private-static-method', + 'public-decorated-method', + 'protected-decorated-method', + 'private-decorated-method', + 'public-instance-method', 'protected-instance-method', 'private-instance-method', @@ -220,6 +264,8 @@ The default configuration looks as follows: 'instance-method', 'abstract-method', + 'decorated-method', + 'method', ], } diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index 14ddcc236a9..25d85958d06 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -60,6 +60,10 @@ export const defaultOrder = [ 'protected-static-field', 'private-static-field', + 'public-decorated-field', + 'protected-decorated-field', + 'private-decorated-field', + 'public-instance-field', 'protected-instance-field', 'private-instance-field', @@ -76,6 +80,8 @@ export const defaultOrder = [ 'instance-field', 'abstract-field', + 'decorated-field', + 'field', // Constructors @@ -90,6 +96,10 @@ export const defaultOrder = [ 'protected-static-method', 'private-static-method', + 'public-decorated-method', + 'protected-decorated-method', + 'private-decorated-method', + 'public-instance-method', 'protected-instance-method', 'private-instance-method', @@ -106,6 +116,8 @@ export const defaultOrder = [ 'instance-method', 'abstract-method', + 'decorated-method', + 'method', ]; @@ -119,6 +131,18 @@ const allMemberTypes = ['signature', 'field', 'method', 'constructor'].reduce< all.push(`${accessibility}-${type}`); // e.g. `public-field` } + // Only class instance fields and methods can have decorators attached to them + if (type === 'field' || type === 'method') { + const decoratedMemberType = `${accessibility}-decorated-${type}`; + const decoratedMemberTypeNoAccessibility = `decorated-${type}`; + if (!all.includes(decoratedMemberType)) { + all.push(decoratedMemberType); + } + if (!all.includes(decoratedMemberTypeNoAccessibility)) { + all.push(decoratedMemberTypeNoAccessibility); + } + } + if (type !== 'constructor' && type !== 'signature') { // There is no `static-constructor` or `instance-constructor` or `abstract-constructor` ['static', 'instance', 'abstract'].forEach(scope => { @@ -150,6 +174,9 @@ function getNodeType(node: Member): string | null { case AST_NODE_TYPES.TSAbstractMethodDefinition: case AST_NODE_TYPES.MethodDefinition: return node.kind; + // return node.decorators && node.decorators.length > 0 + // ? `decorated-${node.kind}` + // : node.kind; case AST_NODE_TYPES.TSMethodSignature: return 'method'; case AST_NODE_TYPES.TSConstructSignatureDeclaration: @@ -159,6 +186,10 @@ function getNodeType(node: Member): string | null { return node.value && functionExpressions.includes(node.value.type) ? 'method' : 'field'; + // ? 'method' + // : node.decorators && node.decorators.length > 0 + // ? 'decorated-field' + // : 'field'; case AST_NODE_TYPES.TSPropertySignature: return 'field'; case AST_NODE_TYPES.TSIndexSignature: @@ -258,6 +289,12 @@ function getRank( const memberGroups = []; if (supportsModifiers) { + const decorated = 'decorators' in node && node.decorators!.length > 0; + if (decorated && (type === 'field' || type === 'method')) { + memberGroups.push(`${accessibility}-decorated-${type}`); + memberGroups.push(`decorated-${type}`); + } + if (type !== 'constructor') { // Constructors have no scope memberGroups.push(`${accessibility}-${scope}-${type}`); @@ -396,27 +433,29 @@ export default util.createRule({ const name = getMemberName(member, context.getSourceCode()); const rankLastMember = previousRanks[previousRanks.length - 1]; - if (rank !== -1) { - // Works for 1st item because x < undefined === false for any x (typeof string) - if (rank < rankLastMember) { - context.report({ - node: member, - messageId: 'incorrectGroupOrder', - data: { - name, - rank: getLowestRank(previousRanks, rank, groupOrder), - }, - }); + if (rank === -1) { + return; + } - isCorrectlySorted = false; - } else if (rank === rankLastMember) { - // Same member group --> Push to existing member group array - memberGroups[memberGroups.length - 1].push(member); - } else { - // New member group --> Create new member group array - previousRanks.push(rank); - memberGroups.push([member]); - } + // Works for 1st item because x < undefined === false for any x (typeof string) + if (rank < rankLastMember) { + context.report({ + node: member, + messageId: 'incorrectGroupOrder', + data: { + name, + rank: getLowestRank(previousRanks, rank, groupOrder), + }, + }); + + isCorrectlySorted = false; + } else if (rank === rankLastMember) { + // Same member group --> Push to existing member group array + memberGroups[memberGroups.length - 1].push(member); + } else { + // New member group --> Create new member group array + previousRanks.push(rank); + memberGroups.push([member]); } }); @@ -472,36 +511,34 @@ export default util.createRule({ orderConfig: OrderConfig, supportsModifiers: boolean, ): void { - if (orderConfig !== 'never') { - // Standardize config - let order = null; - let memberTypes; + if (orderConfig === 'never') { + return; + } - if (Array.isArray(orderConfig)) { - memberTypes = orderConfig; - } else { - order = orderConfig.order; - memberTypes = orderConfig.memberTypes; - } + // Standardize config + let order = null; + let memberTypes; - // Check order - if (Array.isArray(memberTypes)) { - const grouped = checkGroupSort( - members, - memberTypes, - supportsModifiers, - ); + if (Array.isArray(orderConfig)) { + memberTypes = orderConfig; + } else { + order = orderConfig.order; + memberTypes = orderConfig.memberTypes; + } - if (grouped === null) { - return; - } + // Check order + if (Array.isArray(memberTypes)) { + const grouped = checkGroupSort(members, memberTypes, supportsModifiers); - if (order === 'alphabetically') { - grouped.some(groupMember => !checkAlphaSort(groupMember)); - } - } else if (order === 'alphabetically') { - checkAlphaSort(members); + if (grouped === null) { + return; + } + + if (order === 'alphabetically') { + grouped.some(groupMember => !checkAlphaSort(groupMember)); } + } else if (order === 'alphabetically') { + checkAlphaSort(members); } } diff --git a/packages/eslint-plugin/tests/rules/member-ordering.test.ts b/packages/eslint-plugin/tests/rules/member-ordering.test.ts index c64c57c4591..5134d591ffa 100644 --- a/packages/eslint-plugin/tests/rules/member-ordering.test.ts +++ b/packages/eslint-plugin/tests/rules/member-ordering.test.ts @@ -1317,6 +1317,101 @@ abstract class Foo { `, options: [{ classes: ['signature', 'field', 'constructor', 'method'] }], }, + { + code: ` +class Foo { + @Dec() B: string; + @Dec() A: string; + constructor() {} + D: string; + C: string; + E(): void; + F(): void; +} `, + options: [{ default: ['decorated-field', 'field'] }], + }, + { + code: ` +class Foo { + A: string; + B: string; + @Dec() private C: string; + private D: string; +} `, + options: [ + { + default: ['public-field', 'private-decorated-field', 'private-field'], + }, + ], + }, + { + code: ` +class Foo { + constructor() {} + @Dec() public A(): void; + @Dec() private B: string; + private C(): void; + private D: string; +} `, + options: [ + { + default: [ + 'decorated-method', + 'private-decorated-field', + 'private-method', + ], + }, + ], + }, + { + code: ` +class Foo { + @Dec() private A(): void; + @Dec() private B: string; + constructor() {} + private C(): void; + private D: string; +} `, + options: [ + { + default: [ + 'private-decorated-method', + 'private-decorated-field', + 'constructor', + 'private-field', + ], + }, + ], + }, + { + code: ` +class Foo { + public A: string; + @Dec() private B: string; +} `, + options: [ + { + default: ['private-decorated-field', 'public-instance-field'], + classes: ['public-instance-field', 'private-decorated-field'], + }, + ], + }, + // class + ignore decorator + { + code: ` +class Foo { + public A(): string; + @Dec() public B(): string; + public C(): string; + + d: string; +} `, + options: [ + { + default: ['public-method', 'field'], + }, + ], + }, ], invalid: [ { @@ -3614,6 +3709,96 @@ abstract class Foo { }, ], }, + { + code: ` +// no accessibility === public +class Foo { + B: string; + @Dec() A: string = ""; + C: string = ""; + constructor() {} + D() {} + E() {} +} `, + options: [{ default: ['decorated-field', 'field'] }], + errors: [ + { + messageId: 'incorrectGroupOrder', + data: { + name: 'A', + rank: 'field', + }, + line: 5, + column: 5, + }, + ], + }, + { + code: ` +class Foo { + A() {} + + @Decorator() + B() {} +} `, + options: [{ default: ['decorated-method', 'method'] }], + errors: [ + { + messageId: 'incorrectGroupOrder', + data: { + name: 'B', + rank: 'method', + }, + line: 5, // Symbol starts at the line with decorator + column: 5, + }, + ], + }, + { + code: ` +class Foo { + @Decorator() C() {} + A() {} +} `, + options: [{ default: ['public-method', 'decorated-method'] }], + errors: [ + { + messageId: 'incorrectGroupOrder', + data: { + name: 'A', + rank: 'decorated method', + }, + line: 4, + column: 5, + }, + ], + }, + { + code: ` +class Foo { + A(): void; + B(): void; + private C() {} + constructor() {} + @Dec() private D() {} +} `, + options: [ + { + classes: ['public-method', 'decorated-method', 'private-method'], + }, + ], + errors: [ + { + messageId: 'incorrectGroupOrder', + data: { + name: 'D', + rank: 'private method', + }, + line: 7, + column: 5, + }, + ], + }, ], }; @@ -3702,9 +3887,11 @@ class Foo { protected static b : string = ""; private static c : string = ""; constructor() {} - public d : string = ""; - protected e : string = ""; - private f : string = ""; + @Dec() d: string; + public e : string = ""; + @Dec() f : string = ""; + protected g : string = ""; + private h : string = ""; } `, options: [{ default: { memberTypes: 'never', order: 'alphabetically' } }], @@ -3765,6 +3952,18 @@ const foo = class Foo { const foo = class Foo { public static a1 : string; public static aa : string; +} + `, + options: [{ default: { memberTypes: 'never', order: 'alphabetically' } }], + }, + + // default option + class + decorators + { + code: ` +class Foo { + public static a : string; + @Dec() static b : string; + public static c : string; } `, options: [{ default: { memberTypes: 'never', order: 'alphabetically' } }], @@ -4064,10 +4263,11 @@ type Foo = { class Foo { public static a : string; protected static b : string = ""; - private static c : string = ""; + @Dec() private static c : string = ""; constructor() {} public d : string = ""; protected e : string = ""; + @Dec() private f : string = ""; } `, @@ -5019,6 +5219,29 @@ class Foo { protected e: string = ""; private f: string = ""; + constructor() {} +} + `, + options: [ + { default: { memberTypes: defaultOrder, order: 'alphabetically' } }, + ], + }, + // default option + class + decorators + default order + alphabetically + { + code: ` +class Foo { + public static a: string; + protected static b: string = ""; + private static c: string = ""; + + @Dec() public d: string; + @Dec() protected e: string; + @Dec() private f: string; + + public g: string = ""; + protected h: string = ""; + private i: string = ""; + constructor() {} } `, @@ -5217,6 +5440,55 @@ const foo = class Foo { }, ], }, + // default option + class + decorators + custom order + wrong order within group and wrong group order + alphabetically + { + code: ` +class Foo { + @Dec() a1: string; + @Dec() + a3: string; + @Dec() + a2: string; + + constructor() {} + + b1: string; + b2: string; + + public c(): void; + @Dec() d(): void +} + `, + options: [ + { + default: { + memberTypes: [ + 'decorated-field', + 'field', + 'constructor', + 'decorated-method', + ], + order: 'alphabetically', + }, + }, + ], + errors: [ + { + messageId: 'incorrectGroupOrder', + data: { + name: 'b1', + rank: 'constructor', + }, + }, + { + messageId: 'incorrectGroupOrder', + data: { + name: 'b2', + rank: 'constructor', + }, + }, + ], + }, ], }; From f02221128c97551a1ddf56441d3d65f06ea89222 Mon Sep 17 00:00:00 2001 From: Milos Lajtman Date: Wed, 8 Apr 2020 22:51:29 +0200 Subject: [PATCH 2/5] refactor: remove commented-out code --- packages/eslint-plugin/src/rules/member-ordering.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index 25d85958d06..411823c8de7 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -174,9 +174,6 @@ function getNodeType(node: Member): string | null { case AST_NODE_TYPES.TSAbstractMethodDefinition: case AST_NODE_TYPES.MethodDefinition: return node.kind; - // return node.decorators && node.decorators.length > 0 - // ? `decorated-${node.kind}` - // : node.kind; case AST_NODE_TYPES.TSMethodSignature: return 'method'; case AST_NODE_TYPES.TSConstructSignatureDeclaration: @@ -186,10 +183,6 @@ function getNodeType(node: Member): string | null { return node.value && functionExpressions.includes(node.value.type) ? 'method' : 'field'; - // ? 'method' - // : node.decorators && node.decorators.length > 0 - // ? 'decorated-field' - // : 'field'; case AST_NODE_TYPES.TSPropertySignature: return 'field'; case AST_NODE_TYPES.TSIndexSignature: From b8c0dceeafed09ba3f9459727af12be15b19d9bd Mon Sep 17 00:00:00 2001 From: Milos Lajtman Date: Mon, 27 Apr 2020 19:44:33 +0200 Subject: [PATCH 3/5] refactor: fix prettier issues --- .../docs/rules/member-ordering.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/member-ordering.md b/packages/eslint-plugin/docs/rules/member-ordering.md index 6174c37825e..eda1c573c8e 100644 --- a/packages/eslint-plugin/docs/rules/member-ordering.md +++ b/packages/eslint-plugin/docs/rules/member-ordering.md @@ -25,11 +25,11 @@ These options allow to specify how to group the members and sort their groups. ```ts type TypeOptions = | { - memberTypes: Array | "never", - order?: "alphabetically" | "as-written", + memberTypes: Array | 'never', + order?: 'alphabetically' | 'as-written', } | { - order: "alphabetically", + order: 'alphabetically', }; { @@ -38,8 +38,8 @@ type TypeOptions = classes?: TypeOptions, classExpressions?: TypeOptions, - interfaces?: TypeOptions<"signature" | "field" | "method" | "constructor">, - typeLiterals?: TypeOptions<"signature" | "field" | "method" | "constructor">, + interfaces?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>, + typeLiterals?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>, } ``` @@ -124,7 +124,7 @@ It is also possible to group member types by their accessibility (`static`, `ins It is also possible to group methods or fields with a decorator separately, optionally specifying their accessibility. -```json5 +```jsonc [ // Index signature // No decorators for index signature. @@ -143,7 +143,7 @@ their accessibility. "protected-decorated-method", "private-decorated-method", - "decorated-method", // = ["public-decorated-method", "protected-decorated-method", "private-decorated-method"] + "decorated-method" // = ["public-decorated-method", "protected-decorated-method", "private-decorated-method"] ] ``` @@ -266,8 +266,8 @@ The default configuration looks as follows: "decorated-method", - "method", - ], + "method" + ] } ``` From ae951041b829a78a05764cb7ca4c513f3144b04b Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Mon, 27 Apr 2020 11:29:27 -0700 Subject: [PATCH 4/5] Update member-ordering.md --- .../docs/rules/member-ordering.md | 150 ------------------ 1 file changed, 150 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/member-ordering.md b/packages/eslint-plugin/docs/rules/member-ordering.md index eda1c573c8e..03eb6bb6513 100644 --- a/packages/eslint-plugin/docs/rules/member-ordering.md +++ b/packages/eslint-plugin/docs/rules/member-ordering.md @@ -31,13 +31,10 @@ type TypeOptions = | { order: 'alphabetically', }; - { default?: TypeOptions, - classes?: TypeOptions, classExpressions?: TypeOptions, - interfaces?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>, typeLiterals?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>, } @@ -57,7 +54,6 @@ There are multiple ways to specify the member types. The most explicit and granu [ // Index signature "signature", - // Fields "public-static-field", "protected-static-field", @@ -71,12 +67,10 @@ There are multiple ways to specify the member types. The most explicit and granu "public-abstract-field", "protected-abstract-field", "private-abstract-field", - // Constructors "public-constructor", "protected-constructor", "private-constructor", - // Methods "public-static-method", "protected-static-method", @@ -103,15 +97,12 @@ It is also possible to group member types by their accessibility (`static`, `ins [ // Index signature // No accessibility for index signature. See above. - // Fields "public-field", // = ["public-static-field", "public-instance-field"] "protected-field", // = ["protected-static-field", "protected-instance-field"] "private-field", // = ["private-static-field", "private-instance-field"] - // Constructors // Only the accessibility of constructors is configurable. See below. - // Methods "public-method", // = ["public-static-method", "public-instance-method"] "protected-method", // = ["protected-static-method", "protected-instance-method"] @@ -128,21 +119,16 @@ their accessibility. [ // Index signature // No decorators for index signature. - // Fields "public-decorated-field", "protected-decorated-field", "private-decorated-field", - "decorated-field", // = ["public-decorated-field", "protected-decorated-field", "private-decorated-field"] - // Constructors // There are no decorators for constructors. - "public-decorated-method", "protected-decorated-method", "private-decorated-method", - "decorated-method" // = ["public-decorated-method", "protected-decorated-method", "private-decorated-method"] ] ``` @@ -155,15 +141,12 @@ Another option is to group the member types by their scope (`public`, `protected [ // Index signature // No scope for index signature. See above. - // Fields "static-field", // = ["public-static-field", "protected-static-field", "private-static-field"] "instance-field", // = ["public-instance-field", "protected-instance-field", "private-instance-field"] "abstract-field", // = ["public-abstract-field", "protected-abstract-field", "private-abstract-field"] - // Constructors "constructor", // = ["public-constructor", "protected-constructor", "private-constructor"] - // Methods "static-method", // = ["public-static-method", "protected-static-method", "private-static-method"] "instance-method", // = ["public-instance-method", "protected-instance-method", "private-instance-method"] @@ -179,14 +162,11 @@ The third grouping option is to ignore both scope and accessibility. [ // Index signature // No grouping for index signature. See above. - // Fields "field", // = ["public-static-field", "protected-static-field", "private-static-field", "public-instance-field", "protected-instance-field", "private-instance-field", // "public-abstract-field", "protected-abstract-field", private-abstract-field"] - // Constructors // Only the accessibility of constructors is configurable. See above. - // Methods "method" // = ["public-static-method", "protected-static-method", "private-static-method", "public-instance-method", "protected-instance-method", "private-instance-method", // "public-abstract-method", "protected-abstract-method", "private-abstract-method"] @@ -202,70 +182,52 @@ The default configuration looks as follows: "default": [ // Index signature "signature", - // Fields "public-static-field", "protected-static-field", "private-static-field", - "public-decorated-field", "protected-decorated-field", "private-decorated-field", - "public-instance-field", "protected-instance-field", "private-instance-field", - "public-abstract-field", "protected-abstract-field", "private-abstract-field", - "public-field", "protected-field", "private-field", - "static-field", "instance-field", "abstract-field", - "decorated-field", - "field", - // Constructors "public-constructor", "protected-constructor", "private-constructor", - "constructor", - // Methods "public-static-method", "protected-static-method", "private-static-method", - "public-decorated-method", "protected-decorated-method", "private-decorated-method", - "public-instance-method", "protected-instance-method", "private-instance-method", - "public-abstract-method", "protected-abstract-method", "private-abstract-method", - "public-method", "protected-method", "private-method", - "static-method", "instance-method", "abstract-method", - "decorated-method", - "method" ] } @@ -288,11 +250,8 @@ Note: The `default` options are overwritten in these examples. ```ts interface Foo { B: string; // -> field - new (); // -> constructor - A(): void; // -> method - [Z: string]: any; // -> signature } ``` @@ -302,11 +261,8 @@ Note: Wrong order. ```ts type Foo = { B: string; // -> field - // no constructor - A(): void; // -> method - // no signature }; ``` @@ -318,12 +274,9 @@ class Foo { private C: string; // -> field public D: string; // -> field protected static E: string; // -> field - constructor() {} // -> constructor - public static A(): void {} // -> method public B(): void {} // -> method - [Z: string]: any; // -> signature } ``` @@ -334,14 +287,10 @@ Note: Accessibility or scope are ignored with this configuration. const Foo = class { private C: string; // -> field public D: string; // -> field - constructor() {} // -> constructor - public static A(): void {} // -> method public B(): void {} // -> method - [Z: string]: any; // -> signature - protected static E: string; // -> field }; ``` @@ -353,11 +302,8 @@ Note: Not all members have to be grouped to find rule violations. ```ts interface Foo { [Z: string]: any; // -> signature - A(): void; // -> method - new (); // -> constructor - B: string; // -> field } ``` @@ -365,11 +311,8 @@ interface Foo { ```ts type Foo = { // no signature - A(): void; // -> method - // no constructor - B: string; // -> field }; ``` @@ -377,12 +320,9 @@ type Foo = { ```ts class Foo { [Z: string]: any; // -> signature - public static A(): void {} // -> method public B(): void {} // -> method - constructor() {} // -> constructor - private C: string; // -> field public D: string; // -> field protected static E: string; // -> field @@ -392,12 +332,9 @@ class Foo { ```ts const Foo = class { [Z: string]: any; // -> signature - public static A(): void {} // -> method public B(): void {} // -> method - constructor() {} // -> constructor - private C: string; // -> field public D: string; // -> field protected static E: string; // -> field @@ -413,17 +350,11 @@ Note: This configuration does not apply to interfaces/type literals as accessibi ```ts class Foo { private C: string; // (irrelevant) - public D: string; // (irrelevant) - public static E: string; // -> public static field - constructor() {} // (irrelevant) - public static A(): void {} // (irrelevant) - [Z: string]: any; // (irrelevant) - public B(): void {} // -> public instance method } ``` @@ -433,17 +364,11 @@ Note: Public instance methods should come first before public static fields. Eve ```ts const Foo = class { private C: string; // (irrelevant) - [Z: string]: any; // (irrelevant) - public static E: string; // -> public static field - public D: string; // (irrelevant) - constructor() {} // (irrelevant) - public static A(): void {} // (irrelevant) - public B(): void {} // -> public instance method }; ``` @@ -455,17 +380,11 @@ Note: Public instance methods should come first before public static fields. Eve ```ts class Foo { public B(): void {} // -> public instance method - private C: string; // (irrelevant) - public D: string; // (irrelevant) - public static E: string; // -> public static field - constructor() {} // (irrelevant) - public static A(): void {} // (irrelevant) - [Z: string]: any; // (irrelevant) } ``` @@ -473,17 +392,11 @@ class Foo { ```ts const Foo = class { public B(): void {} // -> public instance method - private C: string; // (irrelevant) - [Z: string]: any; // (irrelevant) - public D: string; // (irrelevant) - constructor() {} // (irrelevant) - public static A(): void {} // (irrelevant) - public static E: string; // -> public static field }; ``` @@ -497,13 +410,10 @@ Note: This configuration does not apply to interfaces/type literals as accessibi ```ts class Foo { private E: string; // -> instance field - private static B: string; // -> static field protected static C: string; // -> static field private static D: string; // -> static field - public static A: string; // -> public static field - [Z: string]: any; // (irrelevant) } ``` @@ -513,18 +423,12 @@ Note: Public static fields should come first, followed by static fields and inst ```ts const foo = class { public T(): void {} // (irrelevant) - private static B: string; // -> static field - constructor() {} // (irrelevant) - private E: string; // -> instance field - protected static C: string; // -> static field private static D: string; // -> static field - [Z: string]: any; // (irrelevant) - public static A: string; // -> public static field }; ``` @@ -536,11 +440,9 @@ Note: Public static fields should come first, followed by static fields and inst ```ts class Foo { public static A: string; // -> public static field - private static B: string; // -> static field protected static C: string; // -> static field private static D: string; // -> static field - private E: string; // -> instance field } ``` @@ -548,17 +450,12 @@ class Foo { ```ts const foo = class { [Z: string]: any; // -> signature - public static A: string; // -> public static field - constructor() {} // -> constructor - private static B: string; // -> static field protected static C: string; // -> static field private static D: string; // -> static field - private E: string; // -> instance field - public T(): void {} // -> method }; ``` @@ -578,9 +475,7 @@ class Foo { private C: string; // -> field public D: string; // -> field protected static E: string; // -> field - constructor() {} // -> constructor - public static A(): void {} // -> method public B(): void {} // -> method } @@ -592,9 +487,7 @@ class Foo { class Foo { public static A(): void {} // -> method public B(): void {} // -> method - constructor() {} // -> constructor - private C: string; // -> field public D: string; // -> field protected static E: string; // -> field @@ -608,15 +501,10 @@ class Foo { ```ts class Foo { private C: string; // (irrelevant) - public D: string; // (irrelevant) - public static E: string; // -> public static field - constructor() {} // (irrelevant) - public static A(): void {} // (irrelevant) - public B(): void {} // -> public instance method } ``` @@ -626,15 +514,10 @@ class Foo { ```ts class Foo { private C: string; // (irrelevant) - public D: string; // (irrelevant) - public B(): void {} // -> public instance method - constructor() {} // (irrelevant) - public static A(): void {} // (irrelevant) - public static E: string; // -> public static field } ``` @@ -654,9 +537,7 @@ const foo = class { private C: string; // -> field public D: string; // -> field protected static E: string; // -> field - constructor() {} // -> constructor - public static A(): void {} // -> method public B(): void {} // -> method }; @@ -668,9 +549,7 @@ const foo = class { const foo = class { public static A(): void {} // -> method public B(): void {} // -> method - constructor() {} // -> constructor - private C: string; // -> field public D: string; // -> field protected static E: string; // -> field @@ -684,15 +563,10 @@ const foo = class { ```ts const foo = class { private C: string; // (irrelevant) - public D: string; // (irrelevant) - public static E: string; // -> public static field - constructor() {} // (irrelevant) - public static A(): void {} // (irrelevant) - public B(): void {} // -> public instance method }; ``` @@ -702,15 +576,10 @@ const foo = class { ```ts const foo = class { private C: string; // (irrelevant) - public D: string; // (irrelevant) - public B(): void {} // -> public instance method - public static E: string; // -> public static field - constructor() {} // (irrelevant) - public static A(): void {} // (irrelevant) }; ``` @@ -730,11 +599,8 @@ Note: The configuration for `interfaces` does not apply to type literals (use `t ```ts interface Foo { B: string; // -> field - new (); // -> constructor - A(): void; // -> method - [Z: string]: any; // -> signature } ``` @@ -744,11 +610,8 @@ interface Foo { ```ts interface Foo { [Z: string]: any; // -> signature - A(): void; // -> method - new (); // -> constructor - B: string; // -> field } ``` @@ -768,11 +631,8 @@ Note: The configuration for `typeLiterals` does not apply to interfaces (use `in ```ts type Foo = { B: string; // -> field - A(): void; // -> method - new (); // -> constructor - [Z: string]: any; // -> signature }; ``` @@ -782,11 +642,8 @@ type Foo = { ```ts type Foo = { [Z: string]: any; // -> signature - A(): void; // -> method - new (); // -> constructor - B: string; // -> field }; ``` @@ -806,14 +663,11 @@ interface Foo { a: x; b: x; c: x; - new (): Bar; (): Baz; - a(): void; b(): void; c(): void; - // Wrong group order, should be placed before all field definitions [a: string]: number; } @@ -822,14 +676,11 @@ interface Foo { ```ts interface Foo { [a: string]: number; - a: x; b: x; c: x; - new (): Bar; (): Baz; - // Wrong alphabetic order within group c(): void; b(): void; @@ -849,7 +700,6 @@ It is also possible to sort all members and ignore the member groups completely. interface Foo { b(): void; a: b; - [a: string]: number; // Order doesn't matter (no sortable identifier) new (): Bar; // Order doesn't matter (no sortable identifier) (): Baz; // Order doesn't matter (no sortable identifier) From 5a353fb77fce6d748a8c7b1af6ffb4543c085a52 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Mon, 27 Apr 2020 11:30:51 -0700 Subject: [PATCH 5/5] Update member-ordering.md --- .../docs/rules/member-ordering.md | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/packages/eslint-plugin/docs/rules/member-ordering.md b/packages/eslint-plugin/docs/rules/member-ordering.md index 03eb6bb6513..eda1c573c8e 100644 --- a/packages/eslint-plugin/docs/rules/member-ordering.md +++ b/packages/eslint-plugin/docs/rules/member-ordering.md @@ -31,10 +31,13 @@ type TypeOptions = | { order: 'alphabetically', }; + { default?: TypeOptions, + classes?: TypeOptions, classExpressions?: TypeOptions, + interfaces?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>, typeLiterals?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>, } @@ -54,6 +57,7 @@ There are multiple ways to specify the member types. The most explicit and granu [ // Index signature "signature", + // Fields "public-static-field", "protected-static-field", @@ -67,10 +71,12 @@ There are multiple ways to specify the member types. The most explicit and granu "public-abstract-field", "protected-abstract-field", "private-abstract-field", + // Constructors "public-constructor", "protected-constructor", "private-constructor", + // Methods "public-static-method", "protected-static-method", @@ -97,12 +103,15 @@ It is also possible to group member types by their accessibility (`static`, `ins [ // Index signature // No accessibility for index signature. See above. + // Fields "public-field", // = ["public-static-field", "public-instance-field"] "protected-field", // = ["protected-static-field", "protected-instance-field"] "private-field", // = ["private-static-field", "private-instance-field"] + // Constructors // Only the accessibility of constructors is configurable. See below. + // Methods "public-method", // = ["public-static-method", "public-instance-method"] "protected-method", // = ["protected-static-method", "protected-instance-method"] @@ -119,16 +128,21 @@ their accessibility. [ // Index signature // No decorators for index signature. + // Fields "public-decorated-field", "protected-decorated-field", "private-decorated-field", + "decorated-field", // = ["public-decorated-field", "protected-decorated-field", "private-decorated-field"] + // Constructors // There are no decorators for constructors. + "public-decorated-method", "protected-decorated-method", "private-decorated-method", + "decorated-method" // = ["public-decorated-method", "protected-decorated-method", "private-decorated-method"] ] ``` @@ -141,12 +155,15 @@ Another option is to group the member types by their scope (`public`, `protected [ // Index signature // No scope for index signature. See above. + // Fields "static-field", // = ["public-static-field", "protected-static-field", "private-static-field"] "instance-field", // = ["public-instance-field", "protected-instance-field", "private-instance-field"] "abstract-field", // = ["public-abstract-field", "protected-abstract-field", "private-abstract-field"] + // Constructors "constructor", // = ["public-constructor", "protected-constructor", "private-constructor"] + // Methods "static-method", // = ["public-static-method", "protected-static-method", "private-static-method"] "instance-method", // = ["public-instance-method", "protected-instance-method", "private-instance-method"] @@ -162,11 +179,14 @@ The third grouping option is to ignore both scope and accessibility. [ // Index signature // No grouping for index signature. See above. + // Fields "field", // = ["public-static-field", "protected-static-field", "private-static-field", "public-instance-field", "protected-instance-field", "private-instance-field", // "public-abstract-field", "protected-abstract-field", private-abstract-field"] + // Constructors // Only the accessibility of constructors is configurable. See above. + // Methods "method" // = ["public-static-method", "protected-static-method", "private-static-method", "public-instance-method", "protected-instance-method", "private-instance-method", // "public-abstract-method", "protected-abstract-method", "private-abstract-method"] @@ -182,52 +202,70 @@ The default configuration looks as follows: "default": [ // Index signature "signature", + // Fields "public-static-field", "protected-static-field", "private-static-field", + "public-decorated-field", "protected-decorated-field", "private-decorated-field", + "public-instance-field", "protected-instance-field", "private-instance-field", + "public-abstract-field", "protected-abstract-field", "private-abstract-field", + "public-field", "protected-field", "private-field", + "static-field", "instance-field", "abstract-field", + "decorated-field", + "field", + // Constructors "public-constructor", "protected-constructor", "private-constructor", + "constructor", + // Methods "public-static-method", "protected-static-method", "private-static-method", + "public-decorated-method", "protected-decorated-method", "private-decorated-method", + "public-instance-method", "protected-instance-method", "private-instance-method", + "public-abstract-method", "protected-abstract-method", "private-abstract-method", + "public-method", "protected-method", "private-method", + "static-method", "instance-method", "abstract-method", + "decorated-method", + "method" ] } @@ -250,8 +288,11 @@ Note: The `default` options are overwritten in these examples. ```ts interface Foo { B: string; // -> field + new (); // -> constructor + A(): void; // -> method + [Z: string]: any; // -> signature } ``` @@ -261,8 +302,11 @@ Note: Wrong order. ```ts type Foo = { B: string; // -> field + // no constructor + A(): void; // -> method + // no signature }; ``` @@ -274,9 +318,12 @@ class Foo { private C: string; // -> field public D: string; // -> field protected static E: string; // -> field + constructor() {} // -> constructor + public static A(): void {} // -> method public B(): void {} // -> method + [Z: string]: any; // -> signature } ``` @@ -287,10 +334,14 @@ Note: Accessibility or scope are ignored with this configuration. const Foo = class { private C: string; // -> field public D: string; // -> field + constructor() {} // -> constructor + public static A(): void {} // -> method public B(): void {} // -> method + [Z: string]: any; // -> signature + protected static E: string; // -> field }; ``` @@ -302,8 +353,11 @@ Note: Not all members have to be grouped to find rule violations. ```ts interface Foo { [Z: string]: any; // -> signature + A(): void; // -> method + new (); // -> constructor + B: string; // -> field } ``` @@ -311,8 +365,11 @@ interface Foo { ```ts type Foo = { // no signature + A(): void; // -> method + // no constructor + B: string; // -> field }; ``` @@ -320,9 +377,12 @@ type Foo = { ```ts class Foo { [Z: string]: any; // -> signature + public static A(): void {} // -> method public B(): void {} // -> method + constructor() {} // -> constructor + private C: string; // -> field public D: string; // -> field protected static E: string; // -> field @@ -332,9 +392,12 @@ class Foo { ```ts const Foo = class { [Z: string]: any; // -> signature + public static A(): void {} // -> method public B(): void {} // -> method + constructor() {} // -> constructor + private C: string; // -> field public D: string; // -> field protected static E: string; // -> field @@ -350,11 +413,17 @@ Note: This configuration does not apply to interfaces/type literals as accessibi ```ts class Foo { private C: string; // (irrelevant) + public D: string; // (irrelevant) + public static E: string; // -> public static field + constructor() {} // (irrelevant) + public static A(): void {} // (irrelevant) + [Z: string]: any; // (irrelevant) + public B(): void {} // -> public instance method } ``` @@ -364,11 +433,17 @@ Note: Public instance methods should come first before public static fields. Eve ```ts const Foo = class { private C: string; // (irrelevant) + [Z: string]: any; // (irrelevant) + public static E: string; // -> public static field + public D: string; // (irrelevant) + constructor() {} // (irrelevant) + public static A(): void {} // (irrelevant) + public B(): void {} // -> public instance method }; ``` @@ -380,11 +455,17 @@ Note: Public instance methods should come first before public static fields. Eve ```ts class Foo { public B(): void {} // -> public instance method + private C: string; // (irrelevant) + public D: string; // (irrelevant) + public static E: string; // -> public static field + constructor() {} // (irrelevant) + public static A(): void {} // (irrelevant) + [Z: string]: any; // (irrelevant) } ``` @@ -392,11 +473,17 @@ class Foo { ```ts const Foo = class { public B(): void {} // -> public instance method + private C: string; // (irrelevant) + [Z: string]: any; // (irrelevant) + public D: string; // (irrelevant) + constructor() {} // (irrelevant) + public static A(): void {} // (irrelevant) + public static E: string; // -> public static field }; ``` @@ -410,10 +497,13 @@ Note: This configuration does not apply to interfaces/type literals as accessibi ```ts class Foo { private E: string; // -> instance field + private static B: string; // -> static field protected static C: string; // -> static field private static D: string; // -> static field + public static A: string; // -> public static field + [Z: string]: any; // (irrelevant) } ``` @@ -423,12 +513,18 @@ Note: Public static fields should come first, followed by static fields and inst ```ts const foo = class { public T(): void {} // (irrelevant) + private static B: string; // -> static field + constructor() {} // (irrelevant) + private E: string; // -> instance field + protected static C: string; // -> static field private static D: string; // -> static field + [Z: string]: any; // (irrelevant) + public static A: string; // -> public static field }; ``` @@ -440,9 +536,11 @@ Note: Public static fields should come first, followed by static fields and inst ```ts class Foo { public static A: string; // -> public static field + private static B: string; // -> static field protected static C: string; // -> static field private static D: string; // -> static field + private E: string; // -> instance field } ``` @@ -450,12 +548,17 @@ class Foo { ```ts const foo = class { [Z: string]: any; // -> signature + public static A: string; // -> public static field + constructor() {} // -> constructor + private static B: string; // -> static field protected static C: string; // -> static field private static D: string; // -> static field + private E: string; // -> instance field + public T(): void {} // -> method }; ``` @@ -475,7 +578,9 @@ class Foo { private C: string; // -> field public D: string; // -> field protected static E: string; // -> field + constructor() {} // -> constructor + public static A(): void {} // -> method public B(): void {} // -> method } @@ -487,7 +592,9 @@ class Foo { class Foo { public static A(): void {} // -> method public B(): void {} // -> method + constructor() {} // -> constructor + private C: string; // -> field public D: string; // -> field protected static E: string; // -> field @@ -501,10 +608,15 @@ class Foo { ```ts class Foo { private C: string; // (irrelevant) + public D: string; // (irrelevant) + public static E: string; // -> public static field + constructor() {} // (irrelevant) + public static A(): void {} // (irrelevant) + public B(): void {} // -> public instance method } ``` @@ -514,10 +626,15 @@ class Foo { ```ts class Foo { private C: string; // (irrelevant) + public D: string; // (irrelevant) + public B(): void {} // -> public instance method + constructor() {} // (irrelevant) + public static A(): void {} // (irrelevant) + public static E: string; // -> public static field } ``` @@ -537,7 +654,9 @@ const foo = class { private C: string; // -> field public D: string; // -> field protected static E: string; // -> field + constructor() {} // -> constructor + public static A(): void {} // -> method public B(): void {} // -> method }; @@ -549,7 +668,9 @@ const foo = class { const foo = class { public static A(): void {} // -> method public B(): void {} // -> method + constructor() {} // -> constructor + private C: string; // -> field public D: string; // -> field protected static E: string; // -> field @@ -563,10 +684,15 @@ const foo = class { ```ts const foo = class { private C: string; // (irrelevant) + public D: string; // (irrelevant) + public static E: string; // -> public static field + constructor() {} // (irrelevant) + public static A(): void {} // (irrelevant) + public B(): void {} // -> public instance method }; ``` @@ -576,10 +702,15 @@ const foo = class { ```ts const foo = class { private C: string; // (irrelevant) + public D: string; // (irrelevant) + public B(): void {} // -> public instance method + public static E: string; // -> public static field + constructor() {} // (irrelevant) + public static A(): void {} // (irrelevant) }; ``` @@ -599,8 +730,11 @@ Note: The configuration for `interfaces` does not apply to type literals (use `t ```ts interface Foo { B: string; // -> field + new (); // -> constructor + A(): void; // -> method + [Z: string]: any; // -> signature } ``` @@ -610,8 +744,11 @@ interface Foo { ```ts interface Foo { [Z: string]: any; // -> signature + A(): void; // -> method + new (); // -> constructor + B: string; // -> field } ``` @@ -631,8 +768,11 @@ Note: The configuration for `typeLiterals` does not apply to interfaces (use `in ```ts type Foo = { B: string; // -> field + A(): void; // -> method + new (); // -> constructor + [Z: string]: any; // -> signature }; ``` @@ -642,8 +782,11 @@ type Foo = { ```ts type Foo = { [Z: string]: any; // -> signature + A(): void; // -> method + new (); // -> constructor + B: string; // -> field }; ``` @@ -663,11 +806,14 @@ interface Foo { a: x; b: x; c: x; + new (): Bar; (): Baz; + a(): void; b(): void; c(): void; + // Wrong group order, should be placed before all field definitions [a: string]: number; } @@ -676,11 +822,14 @@ interface Foo { ```ts interface Foo { [a: string]: number; + a: x; b: x; c: x; + new (): Bar; (): Baz; + // Wrong alphabetic order within group c(): void; b(): void; @@ -700,6 +849,7 @@ It is also possible to sort all members and ignore the member groups completely. interface Foo { b(): void; a: b; + [a: string]: number; // Order doesn't matter (no sortable identifier) new (): Bar; // Order doesn't matter (no sortable identifier) (): Baz; // Order doesn't matter (no sortable identifier)