Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat(eslint-plugin): [member-ordering] add option to sort case insens…
…itive (#3896)

* feat(eslint-plugin): member ordering - case insensitive order option

* feat(eslint-plugin): member ordering - add lower/upper ordering invalid test cases

* feat(eslint-plugin): member ordering - remove default value for param as it is not used

* feat(eslint-plugin): member ordering - fix jsdoc typo

* feat(eslint-plugin): member ordering - change 'alphabetically-ci' to 'alphabetically-case-insensitive'

* feat(eslint-plugin): member ordering - reduce tests to simply test ordering
  • Loading branch information
VincentRoth committed Nov 17, 2021
1 parent 5a4ce6a commit e3533d5
Show file tree
Hide file tree
Showing 5 changed files with 3,376 additions and 2,629 deletions.
81 changes: 74 additions & 7 deletions packages/eslint-plugin/docs/rules/member-ordering.md
Expand Up @@ -26,10 +26,10 @@ These options allow to specify how to group the members and sort their groups.
type TypeOptions<T> =
| {
memberTypes: Array<T> | 'never',
order?: 'alphabetically' | 'as-written',
order?: 'alphabetically' | 'alphabetically-case-insensitive' | 'as-written',
}
| {
order: 'alphabetically',
order: 'alphabetically' | 'alphabetically-case-insensitive' | 'as-written',
};

{
Expand Down Expand Up @@ -956,21 +956,21 @@ It is possible to sort all members within a group alphabetically.

#### Configuration: `{ "default": { "memberTypes": <Default Order>, "order": "alphabetically" } }`

This will apply the default order (see above) and enforce an alphabetic order within each group.
This will apply the default order (see above) and enforce an alphabetic case-sensitive order within each group.

##### Incorrect examples

```ts
interface Foo {
B: x;
a: x;
b: x;
c: x;

new (): Bar;
(): Baz;

B(): void;
a(): void;
b(): void;
c(): void;

// Wrong group order, should be placed before all field definitions
Expand All @@ -982,16 +982,16 @@ interface Foo {
interface Foo {
[a: string]: number;

B: x;
a: x;
b: x;
c: x;

new (): Bar;
(): Baz;

// Wrong alphabetic order within group
c(): void;
b(): void;
B(): void;
a(): void;
}
```
Expand All @@ -1017,6 +1017,73 @@ interface Foo {

Note: Wrong alphabetic order `b(): void` should come after `a: b`.

### Sorting alphabetically case-insensitive within member groups

It is possible to sort all members within a group alphabetically with case insensitivity.

#### Configuration: `{ "default": { "memberTypes": <Default Order>, "order": "alphabetically-case-insensitive" } }`

This will apply the default order (see above) and enforce an alphabetic case-insensitive order within each group.

##### Incorrect examples

```ts
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;
}
```

```ts
interface Foo {
[a: string]: number;

a: x;
B: x;
c: x;

new (): Bar;
(): Baz;

// Wrong alphabetic order within group
C(): void;
b(): void;
a(): void;
}
```

### Sorting alphabetically case-insensitive while ignoring member groups

It is also possible to sort all members with case insensitivity and ignore the member groups completely.

#### Configuration: `{ "default": { "memberTypes": "never", "order": "alphabetically-case-insensitive" } }`

##### Incorrect example

```ts
interface Foo {
B(): void;
a: number;

[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)
}
```

Note: Wrong alphabetic order `B(): void` should come after `a: number`.

## 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.
Expand Down
38 changes: 29 additions & 9 deletions packages/eslint-plugin/src/rules/member-ordering.ts
Expand Up @@ -8,9 +8,14 @@ import * as util from '../util';

export type MessageIds = 'incorrectGroupOrder' | 'incorrectOrder';

type Order =
| 'alphabetically'
| 'alphabetically-case-insensitive'
| 'as-written';

interface SortedOrderConfig {
memberTypes?: string[] | 'never';
order: 'alphabetically' | 'as-written';
order: Order;
}

type OrderConfig = string[] | SortedOrderConfig | 'never';
Expand Down Expand Up @@ -46,7 +51,7 @@ const objectConfig = (memberTypes: string[]): JSONSchema.JSONSchema4 => ({
},
order: {
type: 'string',
enum: ['alphabetically', 'as-written'],
enum: ['alphabetically', 'alphabetically-case-insensitive', 'as-written'],
},
},
additionalProperties: false,
Expand Down Expand Up @@ -539,10 +544,14 @@ export default util.createRule<Options, MessageIds>({
* Checks if the members are alphabetically sorted.
*
* @param members Members to be validated.
* @param caseSensitive indicates if the alpha ordering is case sensitive or not.
*
* @return True if all members are correctly sorted.
*/
function checkAlphaSort(members: Member[]): boolean {
function checkAlphaSort(
members: Member[],
caseSensitive: boolean,
): boolean {
let previousName = '';
let isCorrectlySorted = true;

Expand All @@ -552,7 +561,11 @@ export default util.createRule<Options, MessageIds>({

// Note: Not all members have names
if (name) {
if (name < previousName) {
if (
caseSensitive
? name < previousName
: name.toLowerCase() < previousName.toLowerCase()
) {
context.report({
node: member,
messageId: 'incorrectOrder',
Expand Down Expand Up @@ -589,7 +602,7 @@ export default util.createRule<Options, MessageIds>({
}

// Standardize config
let order = null;
let order: Order | null = null;
let memberTypes;

if (Array.isArray(orderConfig)) {
Expand All @@ -599,6 +612,10 @@ export default util.createRule<Options, MessageIds>({
memberTypes = orderConfig.memberTypes;
}

const hasAlphaSort = order?.startsWith('alphabetically');
const alphaSortIsCaseSensitive =
order !== 'alphabetically-case-insensitive';

// Check order
if (Array.isArray(memberTypes)) {
const grouped = checkGroupSort(members, memberTypes, supportsModifiers);
Expand All @@ -607,11 +624,14 @@ export default util.createRule<Options, MessageIds>({
return;
}

if (order === 'alphabetically') {
grouped.some(groupMember => !checkAlphaSort(groupMember));
if (hasAlphaSort) {
grouped.some(
groupMember =>
!checkAlphaSort(groupMember, alphaSortIsCaseSensitive),
);
}
} else if (order === 'alphabetically') {
checkAlphaSort(members);
} else if (hasAlphaSort) {
checkAlphaSort(members, alphaSortIsCaseSensitive);
}
}

Expand Down

0 comments on commit e3533d5

Please sign in to comment.