eslint-config-angular-strict 2.3.82 → 2.3.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +4 -47
- package/naming-conventions.js +245 -0
- package/package.json +5 -5
package/index.js
CHANGED
|
@@ -9,6 +9,8 @@ import tsEslintParser from '@typescript-eslint/parser';
|
|
|
9
9
|
import tsEslintPlugin from '@typescript-eslint/eslint-plugin';
|
|
10
10
|
import unicornPlugin from 'eslint-plugin-unicorn';
|
|
11
11
|
|
|
12
|
+
import { namingConventionOverrides, noRestrictedSyntaxRule } from './naming-conventions.js';
|
|
13
|
+
|
|
12
14
|
export default [
|
|
13
15
|
{
|
|
14
16
|
ignores: ['dist/**', 'node_modules/**'],
|
|
@@ -47,12 +49,7 @@ export default [
|
|
|
47
49
|
'no-fallthrough': 'off',
|
|
48
50
|
'no-param-reassign': ['error', { props: false }],
|
|
49
51
|
'no-plusplus': 'off',
|
|
50
|
-
'no-restricted-syntax':
|
|
51
|
-
'error',
|
|
52
|
-
{ selector: 'TSEnumDeclaration:not(TSModuleBlock > TSEnumDeclaration)', message: 'Enums must live in enums.ts or *.enum.ts files' },
|
|
53
|
-
{ selector: 'TSInterfaceDeclaration:not(TSModuleBlock > TSInterfaceDeclaration)', message: 'Interfaces must live in *.interface.ts files' },
|
|
54
|
-
{ selector: 'TSTypeAliasDeclaration:not(TSModuleBlock > TSTypeAliasDeclaration)', message: 'Types must live in types.ts or *.type.ts files' },
|
|
55
|
-
],
|
|
52
|
+
'no-restricted-syntax': noRestrictedSyntaxRule,
|
|
56
53
|
'no-return-assign': 'off',
|
|
57
54
|
'no-underscore-dangle': ['error', { allowAfterThis: true }],
|
|
58
55
|
'radix': ['error', 'as-needed'],
|
|
@@ -301,45 +298,5 @@ export default [
|
|
|
301
298
|
},
|
|
302
299
|
},
|
|
303
300
|
|
|
304
|
-
|
|
305
|
-
{
|
|
306
|
-
files: ['**/*.interface.ts'],
|
|
307
|
-
rules: {
|
|
308
|
-
'no-restricted-syntax': [
|
|
309
|
-
'error',
|
|
310
|
-
{
|
|
311
|
-
selector: 'Program > :not(ImportDeclaration, TSInterfaceDeclaration, ExportNamedDeclaration:has(> TSInterfaceDeclaration))',
|
|
312
|
-
message: 'Only interfaces allowed in *.interface.ts',
|
|
313
|
-
},
|
|
314
|
-
],
|
|
315
|
-
},
|
|
316
|
-
},
|
|
317
|
-
|
|
318
|
-
// enums.ts / *.enum.ts: only enums allowed
|
|
319
|
-
{
|
|
320
|
-
files: ['**/enums.ts', '**/*.enum.ts'],
|
|
321
|
-
rules: {
|
|
322
|
-
'no-restricted-syntax': [
|
|
323
|
-
'error',
|
|
324
|
-
{
|
|
325
|
-
selector: 'Program > :not(ImportDeclaration, TSEnumDeclaration, ExportNamedDeclaration:has(> TSEnumDeclaration))',
|
|
326
|
-
message: 'Only enums allowed in enums.ts / *.enum.ts',
|
|
327
|
-
},
|
|
328
|
-
],
|
|
329
|
-
},
|
|
330
|
-
},
|
|
331
|
-
|
|
332
|
-
// types.ts / *.type.ts: only type aliases allowed
|
|
333
|
-
{
|
|
334
|
-
files: ['**/types.ts', '**/*.type.ts'],
|
|
335
|
-
rules: {
|
|
336
|
-
'no-restricted-syntax': [
|
|
337
|
-
'error',
|
|
338
|
-
{
|
|
339
|
-
selector: 'Program > :not(ImportDeclaration, TSTypeAliasDeclaration, ExportNamedDeclaration:has(> TSTypeAliasDeclaration))',
|
|
340
|
-
message: 'Only type aliases allowed in types.ts / *.type.ts',
|
|
341
|
-
},
|
|
342
|
-
],
|
|
343
|
-
},
|
|
344
|
-
},
|
|
301
|
+
...namingConventionOverrides,
|
|
345
302
|
];
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// Class suffix enforcement (regex matched against class name)
|
|
2
|
+
const classSuffixRestriction = (suffix, location) => ({
|
|
3
|
+
selector: `ClassDeclaration[id.name!=/${suffix}$/]`,
|
|
4
|
+
message: `Classes in ${location} must end with "${suffix}"`,
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
// Files containing only imports + export const should be named *.constant.ts
|
|
8
|
+
const constantsFileRestriction = {
|
|
9
|
+
selector:
|
|
10
|
+
'Program:has(ExportNamedDeclaration VariableDeclaration[kind="const"]):not(:has(:matches(ClassDeclaration, FunctionDeclaration, TSInterfaceDeclaration, TSEnumDeclaration, TSTypeAliasDeclaration)))',
|
|
11
|
+
message: 'Files containing only constants must be named constants/*.constant.ts',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Restrictions for interface/enum/type declarations (skipped inside `declare module` blocks)
|
|
15
|
+
const declarationFileRestrictions = [
|
|
16
|
+
{ selector: 'TSEnumDeclaration:not(TSModuleBlock > TSEnumDeclaration)', message: 'Enums must live in interfaces/enums.ts or interfaces/*.enum.ts files' },
|
|
17
|
+
{ selector: 'TSInterfaceDeclaration:not(TSModuleBlock > TSInterfaceDeclaration)', message: 'Interfaces must live in interfaces/*.interface.ts files' },
|
|
18
|
+
{
|
|
19
|
+
selector: 'TSTypeAliasDeclaration:not(TSModuleBlock > TSTypeAliasDeclaration)',
|
|
20
|
+
message: 'Types must live in interfaces/types.ts or interfaces/*.type.ts files',
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
// Restrictions for Angular class decorators (one decorator type per file)
|
|
25
|
+
const decoratorFileRestrictions = {
|
|
26
|
+
Component: {
|
|
27
|
+
selector: 'Decorator[expression.callee.name="Component"]',
|
|
28
|
+
message:
|
|
29
|
+
'@Component classes must live in app.ts / components/**/*.component.ts / components/drawers/*.drawer.ts / components/modals/*.modal.ts / pages/**/*.page.ts',
|
|
30
|
+
},
|
|
31
|
+
Directive: { selector: 'Decorator[expression.callee.name="Directive"]', message: '@Directive classes must live in directives/*.directive.ts' },
|
|
32
|
+
Injectable: { selector: 'Decorator[expression.callee.name="Injectable"]', message: '@Injectable classes must live in services/*.service.ts' },
|
|
33
|
+
Pipe: { selector: 'Decorator[expression.callee.name="Pipe"]', message: '@Pipe classes must live in pipes/*.pipe.ts' },
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Undecorated classes must live in helpers/*.helpers.ts
|
|
37
|
+
const helperFileRestriction = {
|
|
38
|
+
selector: 'ClassDeclaration:not(:has(Decorator))',
|
|
39
|
+
message: 'Undecorated classes must live in helpers/*.helpers.ts',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Global no-restricted-syntax rule (used in the main TypeScript files block)
|
|
43
|
+
export const noRestrictedSyntaxRule = [
|
|
44
|
+
'error',
|
|
45
|
+
constantsFileRestriction,
|
|
46
|
+
decoratorFileRestrictions.Component,
|
|
47
|
+
decoratorFileRestrictions.Directive,
|
|
48
|
+
decoratorFileRestrictions.Injectable,
|
|
49
|
+
decoratorFileRestrictions.Pipe,
|
|
50
|
+
helperFileRestriction,
|
|
51
|
+
...declarationFileRestrictions,
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
// Per-file overrides relaxing no-restricted-syntax to allow the relevant decorator/declaration
|
|
55
|
+
export const namingConventionOverrides = [
|
|
56
|
+
// app.ts / components/**/*.component.ts / components/drawers/*.drawer.ts / components/modals/*.modal.ts / pages/**/*.page.ts: @Component allowed
|
|
57
|
+
{
|
|
58
|
+
files: ['**/app.ts', '**/components/**/*.component.ts', '**/components/drawers/**/*.drawer.ts', '**/components/modals/**/*.modal.ts', '**/pages/**/*.page.ts'],
|
|
59
|
+
rules: {
|
|
60
|
+
'no-restricted-syntax': [
|
|
61
|
+
'error',
|
|
62
|
+
decoratorFileRestrictions.Directive,
|
|
63
|
+
decoratorFileRestrictions.Injectable,
|
|
64
|
+
decoratorFileRestrictions.Pipe,
|
|
65
|
+
helperFileRestriction,
|
|
66
|
+
...declarationFileRestrictions,
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
// directives/*.directive.ts: @Directive allowed
|
|
72
|
+
{
|
|
73
|
+
files: ['**/directives/**/*.directive.ts'],
|
|
74
|
+
rules: {
|
|
75
|
+
'no-restricted-syntax': [
|
|
76
|
+
'error',
|
|
77
|
+
decoratorFileRestrictions.Component,
|
|
78
|
+
decoratorFileRestrictions.Injectable,
|
|
79
|
+
decoratorFileRestrictions.Pipe,
|
|
80
|
+
helperFileRestriction,
|
|
81
|
+
...declarationFileRestrictions,
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
// pipes/*.pipe.ts: @Pipe allowed, class must end with "Pipe"
|
|
87
|
+
{
|
|
88
|
+
files: ['**/pipes/**/*.pipe.ts'],
|
|
89
|
+
rules: {
|
|
90
|
+
'no-restricted-syntax': [
|
|
91
|
+
'error',
|
|
92
|
+
classSuffixRestriction('Pipe', '*.pipe.ts'),
|
|
93
|
+
decoratorFileRestrictions.Component,
|
|
94
|
+
decoratorFileRestrictions.Directive,
|
|
95
|
+
decoratorFileRestrictions.Injectable,
|
|
96
|
+
helperFileRestriction,
|
|
97
|
+
...declarationFileRestrictions,
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
// services/*.service.ts: @Injectable allowed, class must end with "Service"
|
|
103
|
+
{
|
|
104
|
+
files: ['**/services/**/*.service.ts'],
|
|
105
|
+
rules: {
|
|
106
|
+
'no-restricted-syntax': [
|
|
107
|
+
'error',
|
|
108
|
+
classSuffixRestriction('Service', '*.service.ts'),
|
|
109
|
+
decoratorFileRestrictions.Component,
|
|
110
|
+
decoratorFileRestrictions.Directive,
|
|
111
|
+
decoratorFileRestrictions.Pipe,
|
|
112
|
+
helperFileRestriction,
|
|
113
|
+
...declarationFileRestrictions,
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// helpers/*.helpers.ts: undecorated classes allowed, class must end with "Helpers"
|
|
119
|
+
{
|
|
120
|
+
files: ['**/helpers/**/*.helpers.ts'],
|
|
121
|
+
rules: {
|
|
122
|
+
'no-restricted-syntax': [
|
|
123
|
+
'error',
|
|
124
|
+
classSuffixRestriction('Helpers', '*.helpers.ts'),
|
|
125
|
+
decoratorFileRestrictions.Component,
|
|
126
|
+
decoratorFileRestrictions.Directive,
|
|
127
|
+
decoratorFileRestrictions.Injectable,
|
|
128
|
+
decoratorFileRestrictions.Pipe,
|
|
129
|
+
...declarationFileRestrictions,
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
// interfaces/*.interface.ts: only interfaces allowed
|
|
135
|
+
{
|
|
136
|
+
files: ['**/interfaces/**/*.interface.ts'],
|
|
137
|
+
rules: {
|
|
138
|
+
'no-restricted-syntax': [
|
|
139
|
+
'error',
|
|
140
|
+
{
|
|
141
|
+
selector: 'Program > :not(ImportDeclaration, TSInterfaceDeclaration, ExportNamedDeclaration:has(> TSInterfaceDeclaration))',
|
|
142
|
+
message: 'Only interfaces allowed in interfaces/*.interface.ts',
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
// interfaces/enums.ts / interfaces/*.enum.ts: only enums allowed
|
|
149
|
+
{
|
|
150
|
+
files: ['**/interfaces/enums.ts', '**/interfaces/**/*.enum.ts'],
|
|
151
|
+
rules: {
|
|
152
|
+
'no-restricted-syntax': [
|
|
153
|
+
'error',
|
|
154
|
+
{
|
|
155
|
+
selector: 'Program > :not(ImportDeclaration, TSEnumDeclaration, ExportNamedDeclaration:has(> TSEnumDeclaration))',
|
|
156
|
+
message: 'Only enums allowed in interfaces/enums.ts / interfaces/*.enum.ts',
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
// interfaces/types.ts / interfaces/*.type.ts: only type aliases allowed
|
|
163
|
+
{
|
|
164
|
+
files: ['**/interfaces/types.ts', '**/interfaces/**/*.type.ts'],
|
|
165
|
+
rules: {
|
|
166
|
+
'no-restricted-syntax': [
|
|
167
|
+
'error',
|
|
168
|
+
{
|
|
169
|
+
selector: 'Program > :not(ImportDeclaration, TSTypeAliasDeclaration, ExportNamedDeclaration:has(> TSTypeAliasDeclaration))',
|
|
170
|
+
message: 'Only type aliases allowed in interfaces/types.ts / interfaces/*.type.ts',
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
// constants/*.constant.ts: only imports + export const allowed
|
|
177
|
+
{
|
|
178
|
+
files: ['**/constants/**/*.constant.ts'],
|
|
179
|
+
rules: {
|
|
180
|
+
'no-restricted-syntax': [
|
|
181
|
+
'error',
|
|
182
|
+
{
|
|
183
|
+
selector: 'Program > :not(ImportDeclaration, ExportNamedDeclaration:has(> VariableDeclaration[kind="const"]))',
|
|
184
|
+
message: 'Only imports and export const allowed in constants/*.constant.ts',
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
// guards/*.guard.ts: only imports + export const allowed (functional guards)
|
|
191
|
+
{
|
|
192
|
+
files: ['**/guards/**/*.guard.ts'],
|
|
193
|
+
rules: {
|
|
194
|
+
'no-restricted-syntax': [
|
|
195
|
+
'error',
|
|
196
|
+
{
|
|
197
|
+
selector: 'Program > :not(ImportDeclaration, ExportNamedDeclaration:has(> VariableDeclaration[kind="const"]))',
|
|
198
|
+
message: 'Only imports and export const allowed in guards/*.guard.ts',
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
// interceptors/*.interceptor.ts: only imports + export const allowed (functional interceptors)
|
|
205
|
+
{
|
|
206
|
+
files: ['**/interceptors/**/*.interceptor.ts'],
|
|
207
|
+
rules: {
|
|
208
|
+
'no-restricted-syntax': [
|
|
209
|
+
'error',
|
|
210
|
+
{
|
|
211
|
+
selector: 'Program > :not(ImportDeclaration, ExportNamedDeclaration:has(> VariableDeclaration[kind="const"]))',
|
|
212
|
+
message: 'Only imports and export const allowed in interceptors/*.interceptor.ts',
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
// resolvers/*.resolver.ts: only imports + export const allowed (functional resolvers)
|
|
219
|
+
{
|
|
220
|
+
files: ['**/resolvers/**/*.resolver.ts'],
|
|
221
|
+
rules: {
|
|
222
|
+
'no-restricted-syntax': [
|
|
223
|
+
'error',
|
|
224
|
+
{
|
|
225
|
+
selector: 'Program > :not(ImportDeclaration, ExportNamedDeclaration:has(> VariableDeclaration[kind="const"]))',
|
|
226
|
+
message: 'Only imports and export const allowed in resolvers/*.resolver.ts',
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
// *.routes.ts: only imports + export const allowed (route definitions, any folder)
|
|
233
|
+
{
|
|
234
|
+
files: ['**/*.routes.ts'],
|
|
235
|
+
rules: {
|
|
236
|
+
'no-restricted-syntax': [
|
|
237
|
+
'error',
|
|
238
|
+
{
|
|
239
|
+
selector: 'Program > :not(ImportDeclaration, ExportNamedDeclaration:has(> VariableDeclaration[kind="const"]))',
|
|
240
|
+
message: 'Only imports and export const allowed in *.routes.ts',
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-config-angular-strict",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.83",
|
|
4
4
|
"description": "Modern ESLint configuration with strict rules for Angular development.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"@angular-eslint/eslint-plugin-template": "21.3.1",
|
|
41
41
|
"@angular-eslint/template-parser": "21.3.1",
|
|
42
42
|
"@stylistic/eslint-plugin": "5.10.0",
|
|
43
|
-
"@typescript-eslint/eslint-plugin": "8.59.
|
|
44
|
-
"@typescript-eslint/parser": "8.59.
|
|
45
|
-
"@typescript-eslint/types": "8.59.
|
|
46
|
-
"@typescript-eslint/utils": "8.59.
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "8.59.3",
|
|
44
|
+
"@typescript-eslint/parser": "8.59.3",
|
|
45
|
+
"@typescript-eslint/types": "8.59.3",
|
|
46
|
+
"@typescript-eslint/utils": "8.59.3",
|
|
47
47
|
"eslint": "9.39.4",
|
|
48
48
|
"eslint-config-airbnb-extended": "3.1.0",
|
|
49
49
|
"eslint-plugin-import-x": "4.16.2",
|