8000 fix(eslint-plugin): [sort-ngmodule-metadata-arrays] handle literal me… · angular-eslint/angular-eslint@f993069 · GitHub
[go: up one dir, main page]

Skip to content

Commit f993069

Browse files
authored
fix(eslint-plugin): [sort-ngmodule-metadata-arrays] handle literal metadata and computed properties (#667)
1 parent 3723c4c commit f993069

File tree

3 files changed

+285
-234
lines changed

3 files changed

+285
-234
lines changed

packages/eslint-plugin/docs/rules/sort-ngmodule-metadata-arrays.md

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
# `@angular-eslint/sort-ngmodule-metadata-arrays`
1515

16-
Enforces ASC alphabetical order for NgModule metadata arrays for easy visual scanning
16+
Ensures ASC alphabetical order for `NgModule` metadata arrays for easy visual scanning
1717

1818
- Type: suggestion
1919
- Category: Best Practices
@@ -37,20 +37,15 @@ The rule does not have any configuration options.
3737

3838
```ts
3939
@NgModule({
40-
imports: [
41-
aModule,
42-
bModule,
43-
DModule,
44-
~~~~~~~
45-
cModule,
46-
]
40+
imports: [aModule, bModule, DModule, cModule]
41+
~~~~~~~
4742
})
4843
class Test {}
4944
```
5045

5146
```ts
5247
@NgModule({
53-
declarations: [
48+
'declarations': [
5449
AComponent,
5550
cPipe,
5651
~~~~~
@@ -63,7 +58,7 @@ class Test {}
6358

6459
```ts
6560
@NgModule({
66-
exports: [
61+
['exports']: [
6762
AComponent,
6863
cPipe,
6964
~~~~~
@@ -76,7 +71,7 @@ class Test {}
7671

7772
```ts
7873
@NgModule({
79-
bootstrap: [
74+
[`bootstrap`]: [
8075
AppModule2,
8176
AppModule3,
8277
~~~~~~~~~~
@@ -123,28 +118,64 @@ class Test {}
123118

124119
✅ - Examples of **correct** code for this rule:
125120

121+
```ts
122+
class Test {}
123+
```
124+
125+
```ts
126+
@NgModule()
127+
class Test {}
128+
```
129+
130+
```ts
131+
@NgModule({})
132+
class Test {}
133+
```
134+
135+
```ts
136+
const options = {};
137+
@NgModule(options)
138+
class Test {}
139+
```
140+
141+
```ts
142+
@NgModule({
143+
bootstrap,
144+
declarations: declarations,
145+
providers: providers(),
146+
schemas: [],
147+
[imports]: [
148+
aModule,
149+
bModule,
150+
DModule,
151+
cModule,
152+
],
153+
})
154+
class Test {}
155+
```
156+
126157
```ts
127158
@NgModule({
128159
bootstrap: [
129160
AppModule1,
130161
AppModule2,
131162
AppModule3,
132163
],
133-
declarations: [
164+
'declarations': [
134165
AComponent,
135166
bDirective,
136167
cPipe,
137168
DComponent,
138169
VariableComponent,
139170
],
140-
imports: [
171+
['imports']: [
141172
_foo,
142173
AModule,
143174
bModule,
144175
cModule,
145176
DModule,
146177
],
147-
providers: [
178+
[`providers`]: [
148179
AProvider,
149180
{
150181
provide: 'myprovider',
@@ -157,3 +188,13 @@ class Test {}
157188
})
158189
class Test {}
159190
```
191+
192+
```ts
193+
@Component({
194+
providers: [
195+
DeclarationD,
196+
DeclarationA,
197+
]
198+
})
199+
class Test {}
200+
```

packages/eslint-plugin/src/rules/sort-ngmodule-metadata-arrays.ts

Lines changed: 26 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,55 @@
1-
import type { NgModule } from '@angular/compiler/src/core';
21
import type { TSESTree } from '@typescript-eslint/experimental-utils';
32
import { ASTUtils } from '@typescript-eslint/experimental-utils';
43
import { createESLintRule } from '../utils/create-eslint-rule';
5-
import { MODULE_CLASS_DECORATOR } from '../utils/selectors';
6-
import { getDecoratorPropertyValue, isArrayExpression } from '../utils/utils';
4+
import { metadataProperty, MODULE_CLASS_DECORATOR } from '../utils/selectors';
75

86
type Options = [];
9-
export const RULE_NAME = 'sort-ngmodule-metadata-arrays';
107
export type MessageIds = 'sortNgmoduleMetadataArrays';
11-
const validProperties: (keyof NgModule)[] = [
12-
'bootstrap',
13-
'declarations',
14-
'entryComponents',
15-
'exports',
16-
'imports',
17-
'providers',
18-
'schemas',
19-
];
8+
export const RULE_NAME = 'sort-ngmodule-metadata-arrays';
209

2110
export default createESLintRule<Options, MessageIds>({
2211
name: RULE_NAME,
2312
meta: {
2413
type: 'suggestion',
2514
docs: {
2615
description:
27-
'Enforces ASC alphabetical order for NgModule metadata arrays for easy visual scanning',
16+
'Ensures ASC alphabetical order for `NgModule` metadata arrays for easy visual scanning',
2817
category: 'Best Practices',
2918
recommended: false,
3019
},
3120
fixable: 'code',
3221
schema: [],
3322
messages: {
3423
sortNgmoduleMetadataArrays:
35-
'NgModule metadata arrays should be sorted in ASC alphabetical order',
24+
'`NgModule` metadata arrays should be sorted in ASC alphabetical order',
3625
},
3726
},
3827
defaultOptions: [],
3928
create(context) {
40-
return {
41-
[MODULE_CLASS_DECORATOR](node: TSESTree.Decorator) {
42-
validProperties.forEach((prop: keyof NgModule) => {
43-
const initializer = getDecoratorPropertyValue(node, prop);
44-
if (
45-
!initializer ||
46-
!isArrayExpression(initializer) ||
47-
initializer.elements.length < 2
48-
) {
49-
return;
50-
}
51-
const unorderedNodes = initializer.elements
52-
.filter(ASTUtils.isIdentifier)
53-
.map((current, index, list) => {
54-
return [current, list[index + 1]];
55-
})
56-
.find(([current, next]) => {
57-
return next && current.name.localeCompare(next.name) === 1;
58-
});
59-
if (!unorderedNodes) return;
29+
const metadataPropertyPattern =
30+
/^(bootstrap|declarations|entryComponents|exports|imports|providers|schemas)$/;
6031

61-
const [unorderedNode, nextNode] = unorderedNodes;
62-
context.report({
63-
messageId: 'sortNgmoduleMetadataArrays',
64-
node: unorderedNode,
65-
fix: (fixer) => {
66-
return [
67-
fixer.replaceText(unorderedNode, nextNode.name),
68-
fixer.replaceText(nextNode, unorderedNode.name),
69-
];
70-
},
32+
return {
33+
[`${MODULE_CLASS_DECORATOR} ${metadataProperty(
34+
metadataPropertyPattern,
35+
)} ArrayExpression`]({ elements }: TSESTree.ArrayExpression) {
36+
const unorderedNodes = elements
37+
.filter(ASTUtils.isIdentifier)
38+
.map((current, index, list) => [current, list[index + 1]])
39+
.find(([current, next]) => {
40+
return next && current.name.localeCompare(next.name) === 1;
7141
});
42+
43+
if (!unorderedNodes) return;
44+
45+
const [unorderedNode, nextNode] = unorderedNodes;
46+
context.report({
47+
node: unorderedNode,
48+
messageId: 'sortNgmoduleMetadataArrays',
49+
fix: (fixer) => [
50+
fixer.replaceText(unorderedNode, nextNode.name),
51+
fixer.replaceText(nextNode, unorderedNode.name),
52+
],
7253
});
7354
},
7455
};

0 commit comments

Comments
 (0)
0