Skip to content

Commit

Permalink
feat: use dynamic group generation in sort-classes
Browse files Browse the repository at this point in the history
  • Loading branch information
hugop95 authored Aug 14, 2024
1 parent c30c8ee commit baa701d
Show file tree
Hide file tree
Showing 8 changed files with 1,618 additions and 174 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ dist/
# Editor
.vscode/
.vim/
.idea/

# Astro
.astro/
Expand Down
229 changes: 149 additions & 80 deletions docs/content/rules/sort-classes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -215,146 +215,215 @@ Allows you to use comments to separate the class members into logical groups. Th

Allows you to specify a list of class member groups for sorting. Groups help organize class members into categories, prioritizing them during sorting. Multiple groups can be combined to achieve the desired sorting order.

There are a lot of predefined groups.

Predefined Groups:

- `'index-signature'` — Index signatures, which define the types of keys and values in an object.
- `'protected-decorated-accessor-property'` — Protected accessor properties with decorators.
- `'private-decorated-accessor-property'` — Private accessor properties with decorators.
- `'decorated-accessor-property'` — Accessor properties with decorators.
- `'protected-decorated-property'` — Protected properties with decorators.
- `'private-decorated-property'` — Private properties with decorators.
- `'decorated-property'` — Properties with decorators.
- `'protected-property'` — Protected properties.
- `'private-property'` — Private properties.
- `'static-property'` — Static properties.
- `'property'` — Regular properties.
- `'constructor'` — Constructor method.
- `'protected-method'` — Protected methods.
- `'private-method'` — Private methods.
- `'static-protected-method'` — Static protected methods.
- `'static-private-method'` — Static private methods.
- `'static-method'` — Static methods.
- `'decorated-method'` — Methods with decorators.
- `'decorated-get-method'` — Getter methods with decorators.
- `'decorated-set-method'` — Setter methods with decorators.
- `'get-method'` — Getter methods.
- `'set-method'` — Setter methods.
- `'method'` — Regular methods.
- `'unknown'` — Members that don’t fit into any other group.
Predefined groups are characterized by a single selector and potentially multiple modifiers. You may enter modifiers in any order, but the selector must always come at the end.

Example:
#### Constructors
- Selector: `constructor`.
- Modifiers: `protected`, `private`, `public`.
- Example: `protected-constructor`, `private-constructor`, `public-constructor` or `constructor`.

#### Methods and accessors
- Method selectors: `get-method`, `set-method`, `method`.
- Accessors selector: `accessor-property`.
- Modifiers: `static`, `abstract`, `decorated`, `override`, `protected`, `private`, `public`.
- Example: `private-static-accessor-property`, `protected-abstract-override-method` or `static-get-method`.

The `abstract` modifier is incompatible with the `static`, `private` and `decorated` modifiers.
`constructor`, `get-method` and `set-method` elements will also be matched as `method`.

#### Properties
- Selector: `property`.
- Modifiers: `static`, `declare`, `abstract`, `decorated`, `override`, `readonly`, `protected`, `private`, `public`.
- Example: `readonly-decorated-property`.

The `abstract` modifier is incompatible with the `static`, `private` and `decorated` modifiers.
The `declare` modifier is incompatible with the `override` and `decorated` modifiers.

#### Index-signatures
- Selector: `index-signature`.
- Modifiers: `static`, `readonly`.
- Example: `static-readonly-index-signature`.

#### Static-blocks
- Selector: `static-block`.
- Modifiers: No modifier available.
- Example: `static-block`.

#### Important notes

##### Scope of the `private` modifier
The `private` modifier will currently match any of the following:
- Elements with the `private` keyword.
- Elements with their name starting with `#`.

##### Scope of the `public` modifier
Elements that are not `protected` nor `private` will be matched with the `public` modifier, even if the keyword is not present.


##### The `unknown` group
Members that don’t fit into any group entered by the user will be placed in the `unknown` group.

##### Behavior when multiple groups match an element

The lists of selectors and modifiers above are both sorted by importance, from most to least important.
In case of multiple groups matching an element, the following rules will be applied:

1. Selector priority: `constructor`, `get-method` and `set-method` groups will always take precedence over `method` groups.
2. If the selector is the same, the group with the most modifiers matching will be selected.
3. If modifiers quantity is the same, order will be chosen based on modifier importance as listed above.

Example 1:
```ts
abstract class Class {

protected abstract get field();

}
```

`field` can be matched by the following groups, from most to least important:
- `abstract-protected-get-method` or `protected-abstract-get-method`.
- `abstract-get-method`.
- `protected-get-method`.
- `get-method`.
- `abstract-protected-method` or `protected-abstract-method`.
- `abstract-method`.
- `protected-method`.
- `method`.
- `unknown`.

Example 2: (The most important group is written in the comments)

```ts
class Example {
abstract class Example extends BaseExample {

// 'index-signature'
[key: string]: any;

// 'protected-decorated-accessor-property'
@SomeDecorator
protected get accessor() {
return this._value;
}
// 'public-static-property'
static instance: Example;

// 'private-decorated-accessor-property'
@SomeDecorator
private get accessor() {
return this._value;
}
// 'declare-protected-static-readonly-property'
declare protected static readonly value: string;

// 'decorated-accessor-property'
// 'protected-abstract-override-readonly-decorated-property'
@SomeDecorator
get accessor() {
return this._value;
}
protected abstract override readonly _value: number;

// 'protected-decorated-property'
@SomeDecorator
protected _value: number;
// 'protected-property'
protected name: string;

// 'private-decorated-property'
@SomeDecorator
private _value: number;

// 'decorated-property'
@SomeDecorator
public value: number;

// 'protected-property'
protected name: string;

// 'private-property'
private name: string;

// 'static-property'
static instance: Example;

// 'property'
// 'public-property'
public description: string;

// 'constructor'
// 'public-decorated-property'
@SomeDecorator
public value: number;

// 'public-constructor'
constructor(value: number) {
this._value = value;
}

// 'protected-method'
protected calculate() {
return this._value * 2;
}

// 'private-method'
private calculate() {
return this._value * 2;
// 'public-static-method'
static getInstance() {
return this.instance;
}

// 'static-protected-method'
// 'protected-static-method'
protected static initialize() {
this.instance = new Example(0);
}

// 'static-private-method'
// 'private-static-method'
private static initialize() {
this.instance = new Example(0);
}

// 'static-method'
static getInstance() {
return this.instance;
// 'protected-method'
protected calculate() {
return this._value * 2;
}

// 'private-method'
private calculate() {
return this._value * 2;
}

// 'decorated-method'
// 'public-decorated-method'
@SomeDecorator
public decoratedMethod() {
return this._value;
}

// 'decorated-get-method'
// 'public-method'
public display() {
console.log(this._value);
}

// 'public-decorated-get-method'
@SomeDecorator
get decoratedValue() {
return this._value;
}

// 'decorated-set-method'
// 'public-decorated-set-method'
@SomeDecorator
set decoratedValue(value: number) {
this._value = value;
}

// 'get-method'
// 'protected-decorated-get-method'
@SomeDecorator
protected get value() {
return this._value;
}

// 'private-decorated-get-method'
@SomeDecorator
private get value() {
return this._value;
}

// 'public-decorated-get-method'
@SomeDecorator
get value() {
return this._value;
}

// 'public-get-method'
get value() {
return this._value;
}

// 'set-method'
// 'public-set-method'
set value(value: number) {
this._value = value;
}

// 'method'
public display() {
console.log(this._value);
// 'protected-decorated-accessor-property'
@SomeDecorator
protected accessor _value: number;

// 'private-decorated-accessor-property'
@SomeDecorator
private accessor _value: number;

// 'static-block'
static {
console.log("I am a static block");
}

// 'public-decorated-accessor-property'
@SomeDecorator
public accessor value: number;
}
```

Expand Down
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ module.exports = [
rules: {
'perfectionist/sort-objects': 'off',
},
files: ['**/test/*', '**/rules/*'],
files: ['**/test/**', '**/rules/**'],
},
]
Loading

0 comments on commit baa701d

Please sign in to comment.