From 31362de490466e0d434d4648a0374ae216edd542 Mon Sep 17 00:00:00 2001 From: weirdpattern Date: Thu, 2 Feb 2017 00:17:18 -0600 Subject: [PATCH 1/3] New: Add rule member-ordering Update documentation, include compatibility to TSLint --- README.md | 1 + docs/rules/member-ordering.md | 584 +++++++ lib/rules/member-ordering.js | 333 ++++ tests/lib/rules/member-ordering.js | 2569 ++++++++++++++++++++++++++++ 4 files changed, 3487 insertions(+) create mode 100644 docs/rules/member-ordering.md create mode 100644 lib/rules/member-ordering.js create mode 100644 tests/lib/rules/member-ordering.js diff --git a/README.md b/README.md index e9b96ea..e37f5d3 100644 --- a/README.md +++ b/README.md @@ -58,3 +58,4 @@ Then configure the rules you want to use under the rules section. * `typescript/no-namespace` - disallows the use of custom TypeScript modules and namespaces. * `typescript/prefer-namespace-keyword` - enforces the use of the keyword `namespace` over `module` to declare custom TypeScript modules. * `typescript/no-type-literal` - disallows the use of type aliases. +* `typescript/member-ordering` - enforces a standard member declaration order. diff --git a/docs/rules/member-ordering.md b/docs/rules/member-ordering.md new file mode 100644 index 0000000..741e211 --- /dev/null +++ b/docs/rules/member-ordering.md @@ -0,0 +1,584 @@ +# Enforces a standard member declaration order. + +A consistent ordering of fields, methods and constructors can make interfaces, type literals, classes and class +expressions easier to read, navigate and edit. + +## Rule Details + +This rule aims to standardise the way interfaces, type literals, classes and class expressions are structured. + +## Options + +This rule, in its default state, does not require any argument, in which case the following order is enforced: +- `public-static-field` +- `protected-static-field` +- `private-static-field` +- `public-instance-field` +- `protected-instance-field` +- `private-instance-field` +- `public-field` (disregard of the scope) +- `protected-field` (disregard of the scope) +- `private-field` (disregard of the scope) +- `static-field` (disregard of the accessibility) +- `instance-field` (disregard of the accessibility) +- `field` (disregard of the scope and/or accessibility) +- `constructor` (disregard of the scope and/or accessibility) +- `public-static-method` +- `protected-static-method` +- `private-static-method` +- `public-instance-method` +- `protected-instance-method` +- `private-instance-method` +- `public-method` (disregard of the scope) +- `protected-method` (disregard of the scope) +- `private-method` (disregard of the scope) +- `static-method` (disregard of the accessibility) +- `instance-method` (disregard of the accessibility) +- `method` (disregard of the scope and/or accessibility) + +The rule can also take one or more of the following options: +- `default`, use this to change the default order (used when no specific configuration has been provided). +- `classes`, use this to change the order in classes. +- `classExpressions`, use this to change the order in class expressions. +- `interfaces`, use this to change the order in interfaces. +- `typeLiterals`, use this to change the order in type literals. + +### default +Disable using `never` or use one of the following values to specify an order: +- Fields: +`public-static-field` +`protected-static-field` +`private-static-field` +`public-instance-field` +`protected-instance-field` +`private-instance-field` +`public-field` (= public-*-field) +`protected-field` (= protected-*-field) +`private-field` (= private-*-field) +`static-field` (= *-static-field) +`instance-field` (= *-instance-field) +`field` (= all) + +- Constructors: +`public-constructor` +`protected-constructor` +`private-constructor` +`constructor` (= *-constructor) + +- Methods: +`public-static-method` +`protected-static-method` +`private-static-method` +`public-instance-method` +`protected-instance-method` +`private-instance-method` +`public-method` (= public-*-method) +`protected-method` (= protected-*-method) +`private-method` (= private-*-method) +`static-method` (= *-static-method) +`instance-method` (= *-instance-method) +`method` (= all) + +Examples of **incorrect** code for the `{ "default": [...] }` option: +```ts +// { "default": ["method", "constructor", "field"] } + +interface Foo { + // -> field + B: string; + + // -> constructor + new(); + + // -> method + A() : void; +} + +type Foo = { + // -> field + B: string; + + // no constructor + + // -> method + A() : void; +} + +class Foo { + // -> * field + private C: string + public D: string + protected static E: string + + // -> constructor + constructor() {} + + // -> * method + public static A(): void {} + public B(): void {} +} + +const Foo = class { + // -> * field + private C: string + public D: string + + // -> constructor + constructor() {} + + // -> * method + public static A(): void {} + public B(): void {} + + // * field + protected static E: string +} + +// { "default": ["public-instance-method", "public-static-field"] } + +// does not apply for interfaces/type literals (accessibility and scope are not part of interfaces/type literals) + +class Foo { + // private instance field + private C: string + + // public instance field + public D: string + + // -> public static field + public static E: string + + // constructor + constructor() {} + + // public static method + public static A(): void {} + + // -> public instance method + public B(): void {} +} + +const Foo = class { + // private instance field + private C: string + + // -> public static field + public static E: string + + // public instance field + public D: string + + // constructor + constructor() {} + + // public static method + public static A(): void {} + + // -> public instance method + public B(): void {} +} +``` + +Examples of **correct** code for the `{ "default": [...] }` option: +```ts +// { "default": ["method", "constructor", "field"] } + +interface Foo { + // -> method + A() : void; + + // -> constructor + new(); + + // -> field + B: string; +} + +type Foo = { + // -> method + A() : void; + + // -> field + B: string; +} + +class Foo { + // -> * method + public static A(): void {} + public B(): void {} + + // -> constructor + constructor() {} + + // -> * field + private C: string + public D: string + protected static E: string +} + +const Foo = class { + // -> * method + public static A(): void {} + public B(): void {} + + // -> constructor + constructor() {} + + // -> * field + private C: string + public D: string + protected static E: string +} + +// { "default": ["public-instance-method", "public-static-field"] } + +// does not apply for interfaces/type literals (accessibility and scope are not part of interfaces/type literals) + +class Foo { + // -> public instance method + public B(): void {} + + // private instance field + private C: string + + // public instance field + public D: string + + // -> public static field + public static E: string + + // constructor + constructor() {} + + // public static method + public static A(): void {} +} + +const Foo = class { + // -> public instance method + public B(): void {} + + // private instance field + private C: string + + // public instance field + public D: string + + // constructor + constructor() {} + + // public static method + public static A(): void {} + + // -> protected static field + protected static: string +} + +// { "default": ["public-static-field", "static-field", "instance-field"] } + +// does not apply for interfaces/type literals (accessibility and scope are not part of interfaces/type literals) + +class Foo { + // -> public static field + public static A: string; + + // -> * static field + private static B: string; + protected statis C:string; + private static D: string; + + // -> * instance field + private E: string; +} + +const foo = class { + // * method + public T(): void {} + + // -> public static field + public static A: string; + + // constructor + constructor(){} + + // -> * static field + private static B: string; + protected statis C:string; + private static D: string; + + // -> * instance field + private E: string; +} +``` + +### classes +Disable using `never` or use one of the valid values (see default) to specify an order. + +Examples of **incorrect** code for the `{ "classes": [...] }` option: +```ts +// { "classes": ["method", "constructor", "field"] } + +// does not apply for interfaces/type literals/class expressions. + +class Foo { + // -> field + private C: string + public D: string + protected static E: string + + // -> constructor + constructor() {} + + // -> method + public static A(): void {} + public B(): void {} +} + +// { "classes": ["public-instance-method", "public-static-field"] } + +// does not apply for interfaces/type literals/class expressions. + +class Foo { + // private instance field + private C: string + + // public instance field + public D: string + + // -> public static field + public static E: string + + // constructor + constructor() {} + + // public static method + public static A(): void {} + + // -> public instance method + public B(): void {} +} +``` + +Examples of **correct** code for `{ "classes": [...] }` option: +```ts +// { "classes": ["method", "constructor", "field"] } + +// does not apply for interfaces/type literals/class expressions. + +class Foo { + // -> * method + public static A(): void {} + public B(): void {} + + // -> constructor + constructor() {} + + // -> * field + private C: string + public D: string + protected static E: string +} + +// { "classes": ["public-instance-method", "public-static-field"] } + +// does not apply for interfaces/type literals/class expressions. + +class Foo { + // private instance field + private C: string + + // public instance field + public D: string + + // -> public static field + public static E: string + + // constructor + constructor() {} + + // public static method + public static A(): void {} + + // -> public instance method + public B(): void {} +} +``` + +### classExpressions +Disable using `never` or use one of the valid values (see default) to specify an order. + +Examples of **incorrect** code for the `{ "classExpressions": [...] }` option: +```ts +// { "classExpressions": ["method", "constructor", "field"] } + +// does not apply for interfaces/type literals/class expressions. + +const foo = class { + // -> field + private C: string + public D: string + protected static E: string + + // -> constructor + constructor() {} + + // -> method + public static A(): void {} + public B(): void {} +} + +// { "classExpressions": ["public-instance-method", "public-static-field"] } + +// does not apply for interfaces/type literals/class expressions. + +const foo = class { + // private instance field + private C: string + + // public instance field + public D: string + + // -> public static field + public static E: string + + // constructor + constructor() {} + + // public static method + public static A(): void {} + + // -> public instance method + public B(): void {} +} +``` + +Examples of **correct** code for `{ "classExpressions": [...] }` option: +```ts +// { "classExpressions": ["method", "constructor", "field"] } + +// does not apply for interfaces/type literals/class expressions. + +const foo = class { + // -> * method + public static A(): void {} + public B(): void {} + + // -> constructor + constructor() {} + + // -> * field + private C: string + public D: string + protected static E: string +} + +// { "classExpressions": ["public-instance-method", "public-static-field"] } + +// does not apply for interfaces/type literals/class expressions. + +const foo = class { + // private instance field + private C: string + + // public instance field + public D: string + + // -> public static field + public static E: string + + // constructor + constructor() {} + + // public static method + public static A(): void {} + + // -> public instance method + public B(): void {} +} +``` + +### interfaces +Disable using `never` or use one of the following values to specify an order: +`field` +`constructor` +`method` + +Examples of **incorrect** code for the `{ "interfaces": [...] }` option: +```ts +// { "interfaces": ["method", "constructor", "field"] } + +// does not apply for classes/class expressions/type literals + +interface Foo { + // -> field + B: string; + + // -> constructor + new(); + + // -> method + A() : void; +} +``` + +Examples of **correct** code for the `{ "interfaces": [...] }` option: +```ts +// { "interfaces": ["method", "constructor", "field"] } + +// does not apply for classes/class expressions/type literals + +interface Foo { + // -> method + A() : void; + + // -> constructor + new(); + + // -> field + B: string; +} +``` + +### typeLiterals +Disable using `never` or use one of the valid values (see interfaces) to specify an order. + +Examples of **incorrect** code for the `{ "typeLiterals": [...] }` option: +```ts +// { "typeLiterals": ["method", "constructor", "field"] } + +// does not apply for classes/class expressions/interfaces + +type Foo = { + // -> field + B: string; + + // -> method + A() : void; +} +``` + +Examples of **correct** code for the `{ "typeLiterals": [...] }` option: +```ts +// { "typeLiterals": ["method", "constructor", "field"] } + +// does not apply for classes/class expressions/interfaces + +type Foo = { + // -> method + A() : void; + + // -> constructor + new(); + + // -> field + B: string; +} +``` + +## When Not To Use It + +If you don't care about the general structure of your classes and interfaces, then you will not need this rule. + +## Compatibility + +* TSLint: [member-ordering](https://palantir.github.io/tslint/rules/member-ordering/) \ No newline at end of file diff --git a/lib/rules/member-ordering.js b/lib/rules/member-ordering.js new file mode 100644 index 0000000..3554bf4 --- /dev/null +++ b/lib/rules/member-ordering.js @@ -0,0 +1,333 @@ +/** + * @fileoverview Enforces a standard member declaration order. + * @author Patricio Trevino + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +var schemaOptions = ["field", "method", "constructor"].reduce(function(options, type) { + options.push(type); + + ["public", "protected", "private"].forEach(function(accessibility) { + options.push(accessibility + "-" + type); + if (type !== "constructor") { + ["static", "instance"].forEach(function(scope) { + if (options.indexOf(scope + "-" + type) === -1) { + options.push(scope + "-" + type); + } + options.push(accessibility + "-" + scope + "-" + type); + }); + } + }); + + return options; +}, []); + +module.exports = { + meta: { + docs: { + description: "Enforces a standard member declaration order.", + category: "TypeScript" + }, + schema: [ + { + type: "object", + properties: { + default: { + oneOf: [ + { + enum: ["never"] + }, + { + type: "array", + items: { + enum: schemaOptions + } + } + ] + }, + classes: { + oneOf: [ + { + enum: ["never"] + }, + { + type: "array", + items: { + enum: schemaOptions + } + } + ] + }, + classExpressions: { + oneOf: [ + { + enum: ["never"] + }, + { + type: "array", + items: { + enum: schemaOptions + } + } + ] + }, + interfaces: { + oneOf: [ + { + enum: ["never"] + }, + { + type: "array", + items: { + enum: ["field", "method", "constructor"] + } + } + ] + }, + typeLiterals: { + oneOf: [ + { + enum: ["never"] + }, + { + type: "array", + items: { + enum: ["field", "method", "constructor"] + } + } + ] + } + }, + additionalProperties: false + } + ] + }, + + create: function(context) { + + var options = context.options[0] || {}; + + var defaultOrder = [ + "public-static-field", + "protected-static-field", + "private-static-field", + + "public-instance-field", + "protected-instance-field", + "private-instance-field", + + "public-field", + "protected-field", + "private-field", + + "static-field", + "instance-field", + + "field", + + "constructor", + + "public-static-method", + "protected-static-method", + "private-static-method", + + "public-instance-method", + "protected-instance-method", + "private-instance-method", + + "public-method", + "protected-method", + "private-method", + + "static-method", + "instance-method", + + "method" + ]; + + //---------------------------------------------------------------------- + // Helpers + //---------------------------------------------------------------------- + + /** + * Gets the node type. + * @param {ASTNode} node the node to be evaluated. + * @returns {string|null} the type of the node. + * @private + */ + function getNodeType(node) { + switch (node.type) { + case "MethodDefinition": + return node.kind; + case "TSMethodSignature": + return "method"; + case "TSConstructSignature": + return "constructor"; + case "ClassProperty": + case "TSPropertySignature": + return "field"; + default: + return null; + } + } + + /** + * Gets the member name based on the member type. + * @param {ASTNode} node the node to be evaluated. + * @returns {string|null} the name of the member. + * @private + */ + function getMemberName(node) { + switch (node.type) { + case "ClassProperty": + case "MethodDefinition": + return node.kind === "constructor" + ? "constructor" + : node.key.name; + case "TSPropertySignature": + case "TSMethodSignature": + return node.name.name; + case "TSConstructSignature": + return "new"; + default: + return null; + } + } + + /** + * Gets the calculated rank using the provided method definition. + * The algorithm is as follows: + * - Get the rank based on the accessibility-scope-type name, e.g. public-instance-field + * - If there is no order for accessibility-scope-type, then strip out the accessibility. + * - If there is no order for scope-type, then strip out the scope. + * - If there is no order for type, then return -1 + * @param {Array} names the valid names to be validated. + * @param {Array} order the current order to be validated. + * @returns {number} the rank of the method definition in the given order. + * @private + */ + function getRankOrder(names, order) { + var rank = -1; + var stack = names.slice(); + + while (stack.length > 0 && rank === -1) { + rank = order.indexOf(stack.shift()); + } + + return rank; + } + + /** + * Gets the rank of the node given the order. + * @param {ASTNode} node the node to be evaluated. + * @param {Array} order the current order to be validated. + * @param {boolean} supportsModifiers a flag indicating whether the type supports modifiers or not. + * @returns {number} the rank of the node. + * @private + */ + function getRank(node, order, supportsModifiers) { + var type = getNodeType(node); + var scope = node.static ? "static" : "instance"; + var accessibility = node.accessibility || "public"; + + var names = []; + + if (supportsModifiers) { + if (type !== "constructor") { + names.push(accessibility + "-" + scope + "-" + type); + names.push(scope + "-" + type); + } + names.push(accessibility + "-" + type); + } + + names.push(type); + + return getRankOrder(names, order); + } + + /** + * Gets the lowest possible rank higher than target. + * e.g. given the following order: + * ... + * public-static-method + * protected-static-method + * private-static-method + * public-instance-method + * protected-instance-method + * private-instance-method + * ... + * and considering that a public-instance-method has already been declared, so ranks contains + * public-instance-method, then the lowest possible rank for public-static-method is + * public-instance-method. + * @param {Array} ranks the existing ranks in the object. + * @param {number} target the target rank. + * @param {Array} order the current order to be validated. + * @returns {string} the name of the lowest possible rank without dashes (-). + * @private + */ + function getLowestRank(ranks, target, order) { + var lowest = ranks[ranks.length - 1]; + + ranks.forEach(function(rank) { + if (rank > target) { + lowest = Math.min(lowest, rank); + } + }); + + return order[lowest].replace(/-/g, " "); + } + + /** + * Validates each member rank. + * @param {Array} members the members to be validated. + * @param {(Array|string)} order the current order to be validated. + * @param {boolean} supportsModifiers a flag indicating whether the type supports modifiers or not. + * @returns {void} + * @private + */ + function validateMembers(members, order, supportsModifiers) { + if (members && order !== "never") { + var previousRanks = []; + members.forEach(function(member) { + var rank = getRank(member, order, supportsModifiers); + if (rank !== -1) { + if (rank < previousRanks[previousRanks.length - 1]) { + context.report({ + node: member, + message: "Member {{name}} should be declared before all {{rank}} definitions.", + data: { + name: getMemberName(member), + rank: getLowestRank(previousRanks, rank, order) + } + }); + } else { + previousRanks.push(rank); + } + } + }); + } + } + + //---------------------------------------------------------------------- + // Public + //---------------------------------------------------------------------- + return { + ClassDeclaration: function(node) { + validateMembers(node.body.body, options.classes || options.default || defaultOrder, true); + }, + ClassExpression: function(node) { + validateMembers(node.body.body, options.classExpressions || options.default || defaultOrder, true); + }, + TSInterfaceDeclaration: function(node) { + validateMembers(node.members, options.interfaces || options.default || defaultOrder, false); + }, + TSTypeLiteral: function(node) { + validateMembers(node.members, options.typeLiterals || options.default || defaultOrder, false); + } + }; + } +}; diff --git a/tests/lib/rules/member-ordering.js b/tests/lib/rules/member-ordering.js new file mode 100644 index 0000000..6d86558 --- /dev/null +++ b/tests/lib/rules/member-ordering.js @@ -0,0 +1,2569 @@ +/** + * @fileoverview Enforces a standard member declaration order. + * @author Patricio Trevino + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var rule = require("../../../lib/rules/member-ordering"), + RuleTester = require("eslint").RuleTester; + + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +var ruleTester = new RuleTester(); +ruleTester.run("member-ordering", rule, { + valid: [ + { + code: ` +// no accessibility === public +interface Foo { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + new(); + G(); + H(); + I(); + J(); + K(); + L(); +} + `, + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +interface Foo { + A: string; + J(); + K(); + D: string; + E: string; + F: string; + new(); + G(); + H(); + B: string; + C: string; + I(); + L(); +} + `, + options: [{ default: "never" }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +interface Foo { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + new(); + G(); + H(); + I(); + J(); + K(); + L(); +} + `, + options: [{ default: ["field", "constructor", "method"] }], + parser: "typescript-eslint-parser" + }, + + { + code: ` +// no accessibility === public +interface Foo { + A: string; + J(); + K(); + D: string; + E: string; + F: string; + new(); + G(); + B: string; + C: string; + H(); + I(); + L(); +} + `, + options: [{ interfaces: "never" }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +interface Foo { + G(); + H(); + I(); + J(); + K(); + L(); + new(); + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; +} + `, + options: [{ interfaces: ["method", "constructor", "field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +interface Foo { + G(); + H(); + I(); + J(); + K(); + L(); + new(); + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; +} + `, + options: [ + { + default: ["field", "constructor", "method"], + interfaces: ["method", "constructor", "field"] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +interface Foo { + G(); + H(); + I(); + new(); + D: string; + E: string; + F: string; + J(); + K(); + L(); + A: string; + B: string; + C: string; +} + `, + options: [{ default: ["private-instance-method", "public-constructor", "protected-static-field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +interface Foo { + G(); + H(); + I(); + J(); + K(); + L(); + D: string; + E: string; + F: string; + new(); + A: string; + B: string; + C: string; +} + `, + options: [{ default: ["method", "public-constructor", "protected-static-field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +type Foo = { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + new(); + G(); + H(); + I(); + J(); + K(); + L(); +} + `, + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +type Foo = { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); +} + `, + options: [{ default: "never" }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +type Foo = { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); +} + `, + options: [{ default: ["field", "constructor", "method"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +type Foo = { + new(); + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); +} + `, + options: [{ default: ["field", "method"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +type Foo = { + G(); + H(); + K(); + L(); + A: string; + B: string; + I(); + J(); + C: string; + D: string; + E: string; + F: string; +} + `, + options: [{ typeLiterals: "never" }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +type Foo = { + G(); + H(); + I(); + J(); + K(); + L(); + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; +} + `, + options: [{ typeLiterals: ["method", "field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +type Foo = { + G(); + H(); + I(); + J(); + K(); + L(); + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; +} + `, + options: [{ typeLiterals: ["method", "constructor", "field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +type Foo = { + G(); + H(); + I(); + J(); + K(); + L(); + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; +} + `, + options: [ + { + default: ["field", "constructor", "method"], + typeLiterals: ["method", "constructor", "field"] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +// no accessibility === public +type Foo = { + D: string; + E: string; + F: string; + A: string; + B: string; + C: string; + G(); + H(); + I(); + J(); + K(); + L(); +} + `, + options: [ + { + default: ["public-instance-method", "public-constructor", "protected-static-field"], + typeLiterals: ["field", "method"] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} +} + `, + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} +} + `, + options: [{ default: "never" }], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} +} + `, + options: [{ default: ["field", "constructor", "method"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + constructor() {} + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} +} + `, + options: [{ default: ["field", "method"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public static G() {} + protected K() {} + private L() {} + private static I() {} + public J() {} + public D: string = ""; + protected static H() {} + public static A: string; + protected static B: string = ""; + constructor() {} + private static C: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + options: [{ classes: "never" }], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} +} + `, + options: [{ classes: ["method", "field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} + constructor() {} + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + options: [{ classes: ["method", "constructor", "field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} + constructor() {} + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + options: [ + { + default: ["field", "constructor", "method"], + classes: ["method", "constructor", "field"] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public J() {} + public static G() {} + protected static H() {} + private static I() {} + protected K() {} + private L() {} + constructor() {} + public D: string = ""; + public static A: string; + private static C: string = ""; + private F: string = ""; + protected static B: string = ""; + protected E: string = ""; +} + `, + options: [ + { + classes: ["public-method", "constructor", "public-field", "private-field", "protected-field"] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public static G() {} + private static I() {} + protected static H() {} + public J() {} + private L() {} + protected K() {} + constructor() {} + public D: string = ""; + public static A: string; + protected static B: string = ""; + protected E: string = ""; + private static C: string = ""; + private F: string = ""; +} + `, + options: [ + { + classes: [ + "public-static-method", + "static-method", + "public-instance-method", + "instance-method", + "constructor", + "public-field", + "protected-field", + "private-field"] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public J() {} + public static G() {} + public D: string = ""; + public static A: string = ""; + constructor() {} + protected K() {} + private L() {} + protected static H() {} + private static I() {} + protected static B: string = ""; + private static C: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + parser: "typescript-eslint-parser", + options: [{ default: ["public-method", "public-field", "constructor", "method", "field"] }] + }, + { + code: ` +class Foo { + public J() {} + public static G() {} + protected static H() {} + private static I() {} + protected K() {} + private L() {} + constructor() {} + public static A: string; + private F: string = ""; + protected static B: string = ""; + public D: string = ""; + private static C: string = ""; + protected E: string = ""; +} + `, + options: [ + { + classes: [ + "public-method", + "protected-static-method", + "private-static-method", + "protected-instance-method", + "private-instance-method", + "constructor", + "field" + ] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + private L() {} + private static I() {} + protected static H() {} + protected static B: string = ""; + public static G() {} + public J() {} + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; + public D: string = ""; + constructor() {} + +} + `, + options: [{ classes: ["private-instance-method", "protected-static-field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + private L() {} + private static I() {} + protected static H() {} + public static G() {} + public J() {} + protected static B: string = ""; + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; + public D: string = ""; + constructor() {} + +} + `, + options: [{ default: ["public-instance-method", "protected-static-field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + private L() {} + private static I() {} + protected static H() {} + public static G() {} + public J() {} + protected static B: string = ""; + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; + public D: string = ""; + constructor() {} + +} + `, + options: [{ classes: ["public-instance-method", "protected-static-field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public D: string = ""; + private L() {} + private static I() {} + protected static H() {} + public static G() {} + public J() {} + private constructor() {} + protected static B: string = ""; + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; +} + `, + options: [ + { + default: ["public-instance-method", "public-constructor", "protected-static-field"], + classes: ["public-instance-field", "private-constructor", "protected-instance-method"] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +class Foo { + public constructor() {} + public D: string = ""; + private L() {} + private static I() {} + protected static H() {} + public static G() {} + public J() {} + protected static B: string = ""; + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; +} + `, + options: [ + { + default: ["public-instance-method", "public-constructor", "protected-static-field"], + classes: ["public-instance-field", "private-constructor", "protected-instance-method"] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} +} + `, + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + constructor() {} + public static A: string; + protected static B: string = ""; + private static I() {} + public J() {} + private F: string = ""; + public static G() {} + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + protected static H() {} + protected K() {} + private L() {} +} + `, + options: [{ default: "never" }], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} +} + `, + options: [{ default: ["field", "constructor", "method"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + constructor() {} + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} +} + `, + options: [{ default: ["field", "method"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + private L() {} + protected static H() {} + constructor() {} + private static I() {} + public J() {} + private static C: string = ""; + public D: string = ""; + protected K() {} + public static G() {} + public static A: string; + protected static B: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + options: [{ classExpressions: "never" }], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} +} + `, + options: [{ classExpressions: ["method", "field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} + constructor() {} + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + options: [{ classExpressions: ["method", "constructor", "field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} + constructor() {} + public static A: string; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + options: [ + { + default: ["field", "constructor", "method"], + classExpressions: ["method", "constructor", "field"] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + private L() {} + private static I() {} + protected static H() {} + protected static B: string = ""; + public static G() {} + public J() {} + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; + public D: string = ""; + constructor() {} + +} + `, + options: [{ classExpressions: ["private-instance-method", "protected-static-field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + private L() {} + private static I() {} + protected static H() {} + public static G() {} + public J() {} + protected static B: string = ""; + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; + public D: string = ""; + constructor() {} + +} + `, + options: [{ default: ["public-instance-method", "protected-static-field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + private L() {} + private static I() {} + protected static H() {} + public static G() {} + public J() {} + protected static B: string = ""; + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; + public D: string = ""; + constructor() {} + +} + `, + options: [{ classExpressions: ["public-instance-method", "protected-static-field"] }], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + public D: string = ""; + private L() {} + private static I() {} + protected static H() {} + public static G() {} + public J() {} + private constructor() {} + protected static B: string = ""; + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; +} + `, + options: [ + { + default: ["public-instance-method", "public-constructor", "protected-static-field"], + classes: ["public-instance-method", "protected-constructor", "protected-static-method"], + classExpressions: ["public-instance-field", "private-constructor", "protected-instance-method"] + } + ], + parser: "typescript-eslint-parser" + }, + { + code: ` +const foo = class Foo { + public constructor() {} + public D: string = ""; + private L() {} + private static I() {} + protected static H() {} + public static G() {} + public J() {} + protected static B: string = ""; + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; +} + `, + options: [ + { + default: ["public-instance-method", "public-constructor", "protected-static-field"], + classes: ["public-instance-method", "protected-constructor", "protected-static-method"], + classExpressions: ["public-instance-field", "private-constructor", "protected-instance-method"] + } + ], + parser: "typescript-eslint-parser" + }, + ], + invalid: [ + { + code: ` +// no accessibility === public +interface Foo { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); + new(); +} + `, + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member new should be declared before all method definitions.", + line: 16, + column: 5 + } + ] + }, + { + code: ` +// no accessibility === public +interface Foo { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); + new(); +} + `, + parser: "typescript-eslint-parser", + options: [{ default: ["method", "constructor", "field"] }], + errors: [ + { + message: "Member G should be declared before all field definitions.", + line: 10, + column: 5 + }, + { + message: "Member H should be declared before all field definitions.", + line: 11, + column: 5 + }, + { + message: "Member I should be declared before all field definitions.", + line: 12, + column: 5 + }, + { + message: "Member J should be declared before all field definitions.", + line: 13, + column: 5 + }, + { + message: "Member K should be declared before all field definitions.", + line: 14, + column: 5 + }, + { + message: "Member L should be declared before all field definitions.", + line: 15, + column: 5 + }, + { + message: "Member new should be declared before all field definitions.", + line: 16, + column: 5 + } + ] + }, + { + code: ` +// no accessibility === public +interface Foo { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); + new(); +} + `, + parser: "typescript-eslint-parser", + options: [{ interfaces: ["method", "constructor", "field"] }], + errors: [ + { + message: "Member G should be declared before all field definitions.", + line: 10, + column: 5 + }, + { + message: "Member H should be declared before all field definitions.", + line: 11, + column: 5 + }, + { + message: "Member I should be declared before all field definitions.", + line: 12, + column: 5 + }, + { + message: "Member J should be declared before all field definitions.", + line: 13, + column: 5 + }, + { + message: "Member K should be declared before all field definitions.", + line: 14, + column: 5 + }, + { + message: "Member L should be declared before all field definitions.", + line: 15, + column: 5 + }, + { + message: "Member new should be declared before all field definitions.", + line: 16, + column: 5 + } + ] + }, + { + code: ` +// no accessibility === public +interface Foo { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); + new(); +} + `, + parser: "typescript-eslint-parser", + options: [ + { + default: ["field", "method", "constructor"], + interfaces: ["method", "constructor", "field"] + } + ], + errors: [ + { + message: "Member G should be declared before all field definitions.", + line: 10, + column: 5 + }, + { + message: "Member H should be declared before all field definitions.", + line: 11, + column: 5 + }, + { + message: "Member I should be declared before all field definitions.", + line: 12, + column: 5 + }, + { + message: "Member J should be declared before all field definitions.", + line: 13, + column: 5 + }, + { + message: "Member K should be declared before all field definitions.", + line: 14, + column: 5 + }, + { + message: "Member L should be declared before all field definitions.", + line: 15, + column: 5 + }, + { + message: "Member new should be declared before all field definitions.", + line: 16, + column: 5 + } + ] + }, + { + code: ` +// no accessibility === public +interface Foo { + new(); + A: string; + G(); + B: string; + H(); + C: string; + I(); + D: string; + J(); + E: string; + K(); + F: string; + L(); +} + `, + parser: "typescript-eslint-parser", + options: [ + { + interfaces: ["constructor", "field", "method"] + } + ], + errors: [ + { + message: "Member B should be declared before all method definitions.", + line: 7, + column: 5 + }, + { + message: "Member C should be declared before all method definitions.", + line: 9, + column: 5 + }, + { + message: "Member D should be declared before all method definitions.", + line: 11, + column: 5 + }, + { + message: "Member E should be declared before all method definitions.", + line: 13, + column: 5 + }, + { + message: "Member F should be declared before all method definitions.", + line: 15, + column: 5 + } + ] + }, + { + code: ` +// no accessibility === public +type Foo = { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); + new(); +} + `, + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member new should be declared before all method definitions.", + line: 16, + column: 5 + } + ] + }, + { + code: ` +// no accessibility === public +type Foo = { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); + new(); +} + `, + parser: "typescript-eslint-parser", + options: [{ default: ["method", "constructor", "field"] }], + errors: [ + { + message: "Member G should be declared before all field definitions.", + line: 10, + column: 5 + }, + { + message: "Member H should be declared before all field definitions.", + line: 11, + column: 5 + }, + { + message: "Member I should be declared before all field definitions.", + line: 12, + column: 5 + }, + { + message: "Member J should be declared before all field definitions.", + line: 13, + column: 5 + }, + { + message: "Member K should be declared before all field definitions.", + line: 14, + column: 5 + }, + { + message: "Member L should be declared before all field definitions.", + line: 15, + column: 5 + }, + { + message: "Member new should be declared before all field definitions.", + line: 16, + column: 5 + } + ] + }, + { + code: ` +// no accessibility === public +type Foo = { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); + new(); +} + `, + parser: "typescript-eslint-parser", + options: [{ typeLiterals: ["method", "constructor", "field"] }], + errors: [ + { + message: "Member G should be declared before all field definitions.", + line: 10, + column: 5 + }, + { + message: "Member H should be declared before all field definitions.", + line: 11, + column: 5 + }, + { + message: "Member I should be declared before all field definitions.", + line: 12, + column: 5 + }, + { + message: "Member J should be declared before all field definitions.", + line: 13, + column: 5 + }, + { + message: "Member K should be declared before all field definitions.", + line: 14, + column: 5 + }, + { + message: "Member L should be declared before all field definitions.", + line: 15, + column: 5 + }, + { + message: "Member new should be declared before all field definitions.", + line: 16, + column: 5 + } + ] + }, + { + code: ` +// no accessibility === public +type Foo = { + A: string; + B: string; + C: string; + D: string; + E: string; + F: string; + G(); + H(); + I(); + J(); + K(); + L(); + new(); +} + `, + parser: "typescript-eslint-parser", + options: [ + { + default: ["field", "method", "constructor"], + typeLiterals: ["method", "constructor", "field"] + } + ], + errors: [ + { + message: "Member G should be declared before all field definitions.", + line: 10, + column: 5 + }, + { + message: "Member H should be declared before all field definitions.", + line: 11, + column: 5 + }, + { + message: "Member I should be declared before all field definitions.", + line: 12, + column: 5 + }, + { + message: "Member J should be declared before all field definitions.", + line: 13, + column: 5 + }, + { + message: "Member K should be declared before all field definitions.", + line: 14, + column: 5 + }, + { + message: "Member L should be declared before all field definitions.", + line: 15, + column: 5 + }, + { + message: "Member new should be declared before all field definitions.", + line: 16, + column: 5 + } + ] + }, + { + code: ` +// no accessibility === public +type Foo = { + new(); + A: string; + G(); + B: string; + H(); + C: string; + I(); + D: string; + J(); + E: string; + K(); + F: string; + L(); +} + `, + parser: "typescript-eslint-parser", + options: [ + { + typeLiterals: ["constructor", "field", "method"] + } + ], + errors: [ + { + message: "Member B should be declared before all method definitions.", + line: 7, + column: 5 + }, + { + message: "Member C should be declared before all method definitions.", + line: 9, + column: 5 + }, + { + message: "Member D should be declared before all method definitions.", + line: 11, + column: 5 + }, + { + message: "Member E should be declared before all method definitions.", + line: 13, + column: 5 + }, + { + message: "Member F should be declared before all method definitions.", + line: 15, + column: 5 + } + ] + }, + { + code: ` +class Foo { + public static A: string = ""; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} + public J() {} + protected K() {} + private L() {} + public static G() {} + protected static H() {} + private static I() {} +} + `, + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member G should be declared before all public instance method definitions.", + line: 13, + column: 5 + }, + { + message: "Member H should be declared before all public instance method definitions.", + line: 14, + column: 5 + }, + { + message: "Member I should be declared before all public instance method definitions.", + line: 15, + column: 5 + } + ] + }, + { + code: ` +class Foo { + constructor() {} + public static A: string = ""; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + public J() {} + protected K() {} + private L() {} + public static G() {} + protected static H() {} + private static I() {} +} + `, + parser: "typescript-eslint-parser", + options: [{ default: ["field", "constructor", "method"] }], + errors: [ + { + message: "Member A should be declared before all constructor definitions.", + line: 4, + column: 5 + }, + { + message: "Member B should be declared before all constructor definitions.", + line: 5, + column: 5 + }, + { + message: "Member C should be declared before all constructor definitions.", + line: 6, + column: 5 + }, + { + message: "Member D should be declared before all constructor definitions.", + line: 7, + column: 5 + }, + { + message: "Member E should be declared before all constructor definitions.", + line: 8, + column: 5 + }, + { + message: "Member F should be declared before all constructor definitions.", + line: 9, + column: 5 + } + ] + }, + { + code: ` +class Foo { + constructor() {} + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + public static G() {} + public static A: string; + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} +} + `, + options: [{ default: ["field", "method"] }], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member A should be declared before all method definitions.", + line: 10, + column: 5 + } + ] + }, + { + code: ` +class Foo { + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} + public static A: string; + public static G() {} + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} +} + `, + options: [{ default: ["method", "field"] }], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member G should be declared before all field definitions.", + line: 9, + column: 5 + } + ] + }, + { + code: ` +class Foo { + public static G() {} + protected static H() {} + protected static B: string = ""; + private static I() {} + public J() {} + protected K() {} + private L() {} + public static A: string; + constructor() {} + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + options: [{ classes: ["method", "constructor", "field"] }], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member I should be declared before all field definitions.", + line: 6, + column: 5 + }, + { + message: "Member J should be declared before all field definitions.", + line: 7, + column: 5 + }, + { + message: "Member K should be declared before all field definitions.", + line: 8, + column: 5 + }, + { + message: "Member L should be declared before all field definitions.", + line: 9, + column: 5 + }, + { + message: "Member constructor should be declared before all field definitions.", + line: 11, + column: 5 + } + ] + }, + { + code: ` +class Foo { + public static A: string; + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} + constructor() {} + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + options: [ + { + default: ["field", "constructor", "method"], + classes: ["method", "constructor", "field"] + } + ], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member G should be declared before all field definitions.", + line: 4, + column: 5 + }, + { + message: "Member H should be declared before all field definitions.", + line: 5, + column: 5 + }, + { + message: "Member I should be declared before all field definitions.", + line: 6, + column: 5 + }, + { + message: "Member J should be declared before all field definitions.", + line: 7, + column: 5 + }, + { + message: "Member K should be declared before all field definitions.", + line: 8, + column: 5 + }, + { + message: "Member L should be declared before all field definitions.", + line: 9, + column: 5 + }, + { + message: "Member constructor should be declared before all field definitions.", + line: 10, + column: 5 + } + ] + }, + { + code: ` +class Foo { + private L() {} + public J() {} + public static G() {} + protected static H() {} + private static I() {} + protected K() {} + constructor() {} + public D: string = ""; + private static C: string = ""; + public static A: string; + private static C: string = ""; + protected static B: string = ""; + private F: string = ""; + protected static B: string = ""; + protected E: string = ""; +} + `, + options: [ + { + classes: ["public-method", "constructor", "public-field", "private-field", "protected-field"] + } + ], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member A should be declared before all private field definitions.", + line: 12, + column: 5 + }, + { + message: "Member F should be declared before all protected field definitions.", + line: 15, + column: 5 + } + ] + }, + { + code: ` +class Foo { + public static G() {} + private static I() {} + public J() {} + protected static H() {} + private L() {} + protected K() {} + public D: string = ""; + constructor() {} + public static A: string; + protected static B: string = ""; + protected E: string = ""; + private static C: string = ""; + private F: string = ""; +} + `, + options: [ + { + classes: [ + "public-static-method", + "static-method", + "public-instance-method", + "instance-method", + "constructor", + "public-field", + "protected-field", + "private-field"] + } + ], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member H should be declared before all public instance method definitions.", + line: 6, + column: 5 + }, + { + message: "Member constructor should be declared before all public field definitions.", + line: 10, + column: 5 + } + ] + }, + { + code: ` +class Foo { + public J() {} + public static G() {} + public D: string = ""; + public static A: string = ""; + private L() {} + constructor() {} + protected K() {} + protected static H() {} + private static I() {} + protected static B: string = ""; + private static C: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + parser: "typescript-eslint-parser", + options: [{ default: ["public-method", "public-field", "constructor", "method", "field"] }], + errors: [ + { + message: "Member constructor should be declared before all method definitions.", + line: 8, + column: 5 + } + ] + }, + { + code: ` +class Foo { + public J() {} + private static I() {} + public static G() {} + protected static H() {} + protected K() {} + private L() {} + constructor() {} + public static A: string; + private F: string = ""; + protected static B: string = ""; + public D: string = ""; + private static C: string = ""; + protected E: string = ""; +} + `, + options: [ + { + classes: [ + "public-method", + "protected-static-method", + "private-static-method", + "protected-instance-method", + "private-instance-method", + "constructor", + "field" + ] + } + ], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member G should be declared before all private static method definitions.", + line: 5, + column: 5 + }, + { + message: "Member H should be declared before all private static method definitions.", + line: 6, + column: 5 + } + ] + }, + { + code: ` +class Foo { + private static I() {} + protected static H() {} + protected static B: string = ""; + public static G() {} + public J() {} + protected K() {} + private static C: string = ""; + private L() {} + private F: string = ""; + protected E: string = ""; + public static A: string; + public D: string = ""; + constructor() {} +} + `, + options: [{ classes: ["private-instance-method", "protected-static-field"] }], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member L should be declared before all protected static field definitions.", + line: 10, + column: 5 + } + ] + }, + { + code: ` +class Foo { + private L() {} + private static I() {} + protected static H() {} + public static G() {} + protected static B: string = ""; + public J() {} + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; + public D: string = ""; + constructor() {} + +} + `, + options: [{ default: ["public-instance-method", "protected-static-field"] }], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member J should be declared before all protected static field definitions.", + line: 8, + column: 5 + } + ] + }, + { + code: ` +const foo = class Foo { + public static A: string = ""; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} + public J() {} + protected K() {} + private L() {} + public static G() {} + protected static H() {} + private static I() {} +} + `, + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member G should be declared before all public instance method definitions.", + line: 13, + column: 5 + }, + { + message: "Member H should be declared before all public instance method definitions.", + line: 14, + column: 5 + }, + { + message: "Member I should be declared before all public instance method definitions.", + line: 15, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + constructor() {} + public static A: string = ""; + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + public J() {} + protected K() {} + private L() {} + public static G() {} + protected static H() {} + private static I() {} +} + `, + parser: "typescript-eslint-parser", + options: [{ default: ["field", "constructor", "method"] }], + errors: [ + { + message: "Member A should be declared before all constructor definitions.", + line: 4, + column: 5 + }, + { + message: "Member B should be declared before all constructor definitions.", + line: 5, + column: 5 + }, + { + message: "Member C should be declared before all constructor definitions.", + line: 6, + column: 5 + }, + { + message: "Member D should be declared before all constructor definitions.", + line: 7, + column: 5 + }, + { + message: "Member E should be declared before all constructor definitions.", + line: 8, + column: 5 + }, + { + message: "Member F should be declared before all constructor definitions.", + line: 9, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + constructor() {} + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + public static G() {} + public static A: string; + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} +} + `, + options: [{ default: ["field", "method"] }], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member A should be declared before all method definitions.", + line: 10, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} + public static A: string; + public static G() {} + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; + constructor() {} +} + `, + options: [{ default: ["method", "field"] }], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member G should be declared before all field definitions.", + line: 9, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + public static G() {} + protected static H() {} + protected static B: string = ""; + private static I() {} + public J() {} + protected K() {} + private L() {} + public static A: string; + constructor() {} + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + options: [{ classExpressions: ["method", "constructor", "field"] }], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member I should be declared before all field definitions.", + line: 6, + column: 5 + }, + { + message: "Member J should be declared before all field definitions.", + line: 7, + column: 5 + }, + { + message: "Member K should be declared before all field definitions.", + line: 8, + column: 5 + }, + { + message: "Member L should be declared before all field definitions.", + line: 9, + column: 5 + }, + { + message: "Member constructor should be declared before all field definitions.", + line: 11, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + public static A: string; + public static G() {} + protected static H() {} + private static I() {} + public J() {} + protected K() {} + private L() {} + constructor() {} + protected static B: string = ""; + private static C: string = ""; + public D: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + options: [ + { + default: ["field", "constructor", "method"], + classExpressions: ["method", "constructor", "field"] + } + ], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member G should be declared before all field definitions.", + line: 4, + column: 5 + }, + { + message: "Member H should be declared before all field definitions.", + line: 5, + column: 5 + }, + { + message: "Member I should be declared before all field definitions.", + line: 6, + column: 5 + }, + { + message: "Member J should be declared before all field definitions.", + line: 7, + column: 5 + }, + { + message: "Member K should be declared before all field definitions.", + line: 8, + column: 5 + }, + { + message: "Member L should be declared before all field definitions.", + line: 9, + column: 5 + }, + { + message: "Member constructor should be declared before all field definitions.", + line: 10, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + private L() {} + public J() {} + public static G() {} + protected static H() {} + private static I() {} + protected K() {} + constructor() {} + public D: string = ""; + private static C: string = ""; + public static A: string; + private static C: string = ""; + protected static B: string = ""; + private F: string = ""; + protected static B: string = ""; + protected E: string = ""; +} + `, + options: [ + { + classExpressions: ["public-method", "constructor", "public-field", "private-field", "protected-field"] + } + ], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member A should be declared before all private field definitions.", + line: 12, + column: 5 + }, + { + message: "Member F should be declared before all protected field definitions.", + line: 15, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + public static G() {} + private static I() {} + public J() {} + protected static H() {} + private L() {} + protected K() {} + public D: string = ""; + constructor() {} + public static A: string; + protected static B: string = ""; + protected E: string = ""; + private static C: string = ""; + private F: string = ""; +} + `, + options: [ + { + classExpressions: [ + "public-static-method", + "static-method", + "public-instance-method", + "instance-method", + "constructor", + "public-field", + "protected-field", + "private-field"] + } + ], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member H should be declared before all public instance method definitions.", + line: 6, + column: 5 + }, + { + message: "Member constructor should be declared before all public field definitions.", + line: 10, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + public J() {} + public static G() {} + public D: string = ""; + public static A: string = ""; + private L() {} + constructor() {} + protected K() {} + protected static H() {} + private static I() {} + protected static B: string = ""; + private static C: string = ""; + protected E: string = ""; + private F: string = ""; +} + `, + parser: "typescript-eslint-parser", + options: [{ default: ["public-method", "public-field", "constructor", "method", "field"] }], + errors: [ + { + message: "Member constructor should be declared before all method definitions.", + line: 8, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + public J() {} + private static I() {} + public static G() {} + protected static H() {} + protected K() {} + private L() {} + constructor() {} + public static A: string; + private F: string = ""; + protected static B: string = ""; + public D: string = ""; + private static C: string = ""; + protected E: string = ""; +} + `, + options: [ + { + classExpressions: [ + "public-method", + "protected-static-method", + "private-static-method", + "protected-instance-method", + "private-instance-method", + "constructor", + "field" + ] + } + ], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member G should be declared before all private static method definitions.", + line: 5, + column: 5 + }, + { + message: "Member H should be declared before all private static method definitions.", + line: 6, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + private static I() {} + protected static H() {} + protected static B: string = ""; + public static G() {} + public J() {} + protected K() {} + private static C: string = ""; + private L() {} + private F: string = ""; + protected E: string = ""; + public static A: string; + public D: string = ""; + constructor() {} + +} + `, + options: [{ classExpressions: ["private-instance-method", "protected-static-field"] }], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member L should be declared before all protected static field definitions.", + line: 10, + column: 5 + } + ] + }, + { + code: ` +const foo = class { + private L() {} + private static I() {} + protected static H() {} + public static G() {} + protected static B: string = ""; + public J() {} + protected K() {} + private static C: string = ""; + private F: string = ""; + protected E: string = ""; + public static A: string; + public D: string = ""; + constructor() {} + +} + `, + options: [{ default: ["public-instance-method", "protected-static-field"] }], + parser: "typescript-eslint-parser", + errors: [ + { + message: "Member J should be declared before all protected static field definitions.", + line: 8, + column: 5 + } + ] + } + ] +}); From f270fdfda6952902abcb355294d25614aaa7c554 Mon Sep 17 00:00:00 2001 From: weirdpattern Date: Thu, 3 Aug 2017 21:47:34 -0500 Subject: [PATCH 2/3] Fix code based on lint suggestions and support newer typescript version --- lib/rules/member-ordering.js | 66 +++++++++++++++--------------- tests/lib/rules/member-ordering.js | 7 ++-- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/lib/rules/member-ordering.js b/lib/rules/member-ordering.js index 3554bf4..1bacfd8 100644 --- a/lib/rules/member-ordering.js +++ b/lib/rules/member-ordering.js @@ -8,17 +8,17 @@ // Rule Definition //------------------------------------------------------------------------------ -var schemaOptions = ["field", "method", "constructor"].reduce(function(options, type) { +const schemaOptions = ["field", "method", "constructor"].reduce((options, type) => { options.push(type); - ["public", "protected", "private"].forEach(function(accessibility) { - options.push(accessibility + "-" + type); + ["public", "protected", "private"].forEach(accessibility => { + options.push(`${accessibility}-${type}`); if (type !== "constructor") { - ["static", "instance"].forEach(function(scope) { - if (options.indexOf(scope + "-" + type) === -1) { - options.push(scope + "-" + type); + ["static", "instance"].forEach(scope => { + if (options.indexOf(`${scope}-${type}`) === -1) { + options.push(`${scope}-${type}`); } - options.push(accessibility + "-" + scope + "-" + type); + options.push(`${accessibility}-${scope}-${type}`); }); } }); @@ -107,11 +107,11 @@ module.exports = { ] }, - create: function(context) { + create(context) { - var options = context.options[0] || {}; + const options = context.options[0] || {}; - var defaultOrder = [ + const defaultOrder = [ "public-static-field", "protected-static-field", "private-static-field", @@ -186,11 +186,11 @@ module.exports = { case "ClassProperty": case "MethodDefinition": return node.kind === "constructor" - ? "constructor" - : node.key.name; + ? "constructor" + : node.key.name; case "TSPropertySignature": case "TSMethodSignature": - return node.name.name; + return node.key.name; case "TSConstructSignature": return "new"; default: @@ -211,8 +211,8 @@ module.exports = { * @private */ function getRankOrder(names, order) { - var rank = -1; - var stack = names.slice(); + let rank = -1; + const stack = names.slice(); while (stack.length > 0 && rank === -1) { rank = order.indexOf(stack.shift()); @@ -230,18 +230,18 @@ module.exports = { * @private */ function getRank(node, order, supportsModifiers) { - var type = getNodeType(node); - var scope = node.static ? "static" : "instance"; - var accessibility = node.accessibility || "public"; + const type = getNodeType(node); + const scope = node.static ? "static" : "instance"; + const accessibility = node.accessibility || "public"; - var names = []; + const names = []; if (supportsModifiers) { if (type !== "constructor") { - names.push(accessibility + "-" + scope + "-" + type); - names.push(scope + "-" + type); + names.push(`${accessibility}-${scope}-${type}`); + names.push(`${scope}-${type}`); } - names.push(accessibility + "-" + type); + names.push(`${accessibility}-${type}`); } names.push(type); @@ -270,9 +270,9 @@ module.exports = { * @private */ function getLowestRank(ranks, target, order) { - var lowest = ranks[ranks.length - 1]; + let lowest = ranks[ranks.length - 1]; - ranks.forEach(function(rank) { + ranks.forEach(rank => { if (rank > target) { lowest = Math.min(lowest, rank); } @@ -291,9 +291,11 @@ module.exports = { */ function validateMembers(members, order, supportsModifiers) { if (members && order !== "never") { - var previousRanks = []; - members.forEach(function(member) { - var rank = getRank(member, order, supportsModifiers); + const previousRanks = []; + + members.forEach(member => { + const rank = getRank(member, order, supportsModifiers); + if (rank !== -1) { if (rank < previousRanks[previousRanks.length - 1]) { context.report({ @@ -316,16 +318,16 @@ module.exports = { // Public //---------------------------------------------------------------------- return { - ClassDeclaration: function(node) { + ClassDeclaration(node) { validateMembers(node.body.body, options.classes || options.default || defaultOrder, true); }, - ClassExpression: function(node) { + ClassExpression(node) { validateMembers(node.body.body, options.classExpressions || options.default || defaultOrder, true); }, - TSInterfaceDeclaration: function(node) { - validateMembers(node.members, options.interfaces || options.default || defaultOrder, false); + TSInterfaceDeclaration(node) { + validateMembers(node.body.body, options.interfaces || options.default || defaultOrder, false); }, - TSTypeLiteral: function(node) { + TSTypeLiteral(node) { validateMembers(node.members, options.typeLiterals || options.default || defaultOrder, false); } }; diff --git a/tests/lib/rules/member-ordering.js b/tests/lib/rules/member-ordering.js index 6d86558..5c09e4e 100644 --- a/tests/lib/rules/member-ordering.js +++ b/tests/lib/rules/member-ordering.js @@ -8,7 +8,7 @@ // Requirements //------------------------------------------------------------------------------ -var rule = require("../../../lib/rules/member-ordering"), +const rule = require("../../../lib/rules/member-ordering"), RuleTester = require("eslint").RuleTester; @@ -16,7 +16,8 @@ var rule = require("../../../lib/rules/member-ordering"), // Tests //------------------------------------------------------------------------------ -var ruleTester = new RuleTester(); +const ruleTester = new RuleTester(); + ruleTester.run("member-ordering", rule, { valid: [ { @@ -1093,7 +1094,7 @@ const foo = class Foo { } ], parser: "typescript-eslint-parser" - }, + } ], invalid: [ { From 1d621ed4fe4af05faebf1eabd1441d624f0bd1c7 Mon Sep 17 00:00:00 2001 From: weirdpattern Date: Sat, 5 Aug 2017 11:32:19 -0500 Subject: [PATCH 3/3] Update documentation --- docs/rules/member-ordering.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/rules/member-ordering.md b/docs/rules/member-ordering.md index 741e211..296ed58 100644 --- a/docs/rules/member-ordering.md +++ b/docs/rules/member-ordering.md @@ -16,25 +16,25 @@ This rule, in its default state, does not require any argument, in which case th - `public-instance-field` - `protected-instance-field` - `private-instance-field` -- `public-field` (disregard of the scope) -- `protected-field` (disregard of the scope) -- `private-field` (disregard of the scope) -- `static-field` (disregard of the accessibility) -- `instance-field` (disregard of the accessibility) -- `field` (disregard of the scope and/or accessibility) -- `constructor` (disregard of the scope and/or accessibility) +- `public-field` (ignores scope) +- `protected-field` (ignores scope) +- `private-field` (ignores scope) +- `static-field` (ignores accessibility) +- `instance-field` (ignores accessibility) +- `field` (ignores scope and/or accessibility) +- `constructor` (ignores scope and/or accessibility) - `public-static-method` - `protected-static-method` - `private-static-method` - `public-instance-method` - `protected-instance-method` - `private-instance-method` -- `public-method` (disregard of the scope) -- `protected-method` (disregard of the scope) -- `private-method` (disregard of the scope) -- `static-method` (disregard of the accessibility) -- `instance-method` (disregard of the accessibility) -- `method` (disregard of the scope and/or accessibility) +- `public-method` (ignores scope) +- `protected-method` (ignores scope) +- `private-method` (ignores scope) +- `static-method` (ignores accessibility) +- `instance-method` (ignores accessibility) +- `method` (ignores scope and/or accessibility) The rule can also take one or more of the following options: - `default`, use this to change the default order (used when no specific configuration has been provided).