eslint-config-angular-strict 22.1.6 → 22.1.8
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.
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
// Class suffix enforcement based on Angular decorator
|
|
2
|
-
const decoratorClassSuffixRestrictions = [
|
|
3
|
-
{
|
|
4
|
-
selector: 'ClassDeclaration:has(> Decorator[expression.callee.name="Injectable"]):not([id.name=/Service$/])',
|
|
5
|
-
message: '@Injectable classes must end with "Service"',
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
selector: 'ClassDeclaration:has(> Decorator[expression.callee.name="Pipe"]):not([id.name=/Pipe$/])',
|
|
9
|
-
message: '@Pipe classes must end with "Pipe"',
|
|
10
|
-
},
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
// Class suffix enforcement for files (used in helpers override since undecorated)
|
|
14
|
-
const helpersClassSuffixRestriction = {
|
|
15
|
-
selector: 'ClassDeclaration[id.name!=/Helpers$/]',
|
|
16
|
-
message: 'Classes in *.helpers.ts must end with "Helpers"',
|
|
17
|
-
};
|
|
18
|
-
|
|
19
1
|
// Files containing only imports + export const (literal values, not functions) should be named *.constant.ts
|
|
20
2
|
const constantsFileRestriction = {
|
|
21
3
|
selector:
|
|
@@ -33,6 +15,18 @@ const declarationFileRestrictions = [
|
|
|
33
15
|
},
|
|
34
16
|
];
|
|
35
17
|
|
|
18
|
+
// Class suffix enforcement based on Angular decorator (@Service is Angular 22's shorthand for @Injectable({ providedIn: 'root' }))
|
|
19
|
+
const decoratorClassSuffixRestrictions = [
|
|
20
|
+
{
|
|
21
|
+
selector: 'ClassDeclaration:has(> Decorator[expression.callee.name=/^(Injectable|Service)$/]):not([id.name=/Service$/])',
|
|
22
|
+
message: '@Injectable / @Service classes must end with "Service"',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
selector: 'ClassDeclaration:has(> Decorator[expression.callee.name="Pipe"]):not([id.name=/Pipe$/])',
|
|
26
|
+
message: '@Pipe classes must end with "Pipe"',
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
|
|
36
30
|
// Restrictions for Angular class decorators (one decorator type per file)
|
|
37
31
|
const decoratorFileRestrictions = {
|
|
38
32
|
Component: {
|
|
@@ -41,7 +35,10 @@ const decoratorFileRestrictions = {
|
|
|
41
35
|
'@Component classes must live in app.ts / components/**/*.component.ts / pages/**/*.component.ts / components/drawers/*.drawer.ts / components/modals/*.modal.ts / pages/**/*.page.ts',
|
|
42
36
|
},
|
|
43
37
|
Directive: { selector: 'Decorator[expression.callee.name="Directive"]', message: '@Directive classes must live in directives/*.directive.ts' },
|
|
44
|
-
Injectable: {
|
|
38
|
+
Injectable: {
|
|
39
|
+
selector: 'Decorator[expression.callee.name=/^(Injectable|Service)$/]',
|
|
40
|
+
message: '@Injectable / @Service classes must live in services/*.service.ts',
|
|
41
|
+
},
|
|
45
42
|
Pipe: { selector: 'Decorator[expression.callee.name="Pipe"]', message: '@Pipe classes must live in pipes/*.pipe.ts' },
|
|
46
43
|
};
|
|
47
44
|
|
|
@@ -51,6 +48,24 @@ const helperFileRestriction = {
|
|
|
51
48
|
message: 'Undecorated classes must live in helpers/*.helpers.ts',
|
|
52
49
|
};
|
|
53
50
|
|
|
51
|
+
// Class suffix enforcement for files (used in helpers override since undecorated)
|
|
52
|
+
const helpersClassSuffixRestriction = {
|
|
53
|
+
selector: 'ClassDeclaration[id.name!=/Helpers$/]',
|
|
54
|
+
message: 'Classes in *.helpers.ts must end with "Helpers"',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Everything in *.helpers.ts belongs to the class — no module-level constants, functions or state
|
|
58
|
+
const helpersFileRestrictions = [
|
|
59
|
+
{
|
|
60
|
+
selector: 'Program > :not(ImportDeclaration, ClassDeclaration, ExportNamedDeclaration:has(> ClassDeclaration))',
|
|
61
|
+
message: 'Only imports and the class allowed in *.helpers.ts — use static properties for constants and static methods for logic',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
selector: 'PropertyDefinition > :matches(ArrowFunctionExpression, FunctionExpression)',
|
|
65
|
+
message: 'Logic in *.helpers.ts must be declared as a static method, not a function property',
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
|
|
54
69
|
// Angular inputs must be public (they are part of the component's external API)
|
|
55
70
|
const inputVisibilityRestriction = {
|
|
56
71
|
selector: ':matches(PropertyDefinition[accessibility="protected"], PropertyDefinition[accessibility="private"]):has(CallExpression Identifier[name="input"])',
|
|
@@ -72,15 +87,15 @@ export const noRestrictedSyntaxRule = [
|
|
|
72
87
|
];
|
|
73
88
|
|
|
74
89
|
// Per-file overrides relaxing no-restricted-syntax to allow the relevant decorator/declaration
|
|
75
|
-
export const
|
|
76
|
-
// app.ts / components/**/*.component.ts / components/drawers/*.drawer.ts / components/modals/*.modal.ts / pages/**/*.page.ts: @Component allowed
|
|
90
|
+
export const noRestrictedSyntaxOverrides = [
|
|
91
|
+
// app.ts / components|pages/**/*.component.ts / components/drawers/*.drawer.ts / components/modals/*.modal.ts / pages/**/*.page.ts: @Component allowed
|
|
77
92
|
{
|
|
78
93
|
files: [
|
|
79
94
|
'**/app.ts',
|
|
80
95
|
'**/components/**/*.component.ts',
|
|
81
|
-
'**/pages/**/*.component.ts',
|
|
82
96
|
'**/components/drawers/**/*.drawer.ts',
|
|
83
97
|
'**/components/modals/**/*.modal.ts',
|
|
98
|
+
'**/pages/**/*.component.ts',
|
|
84
99
|
'**/pages/**/*.page.ts',
|
|
85
100
|
],
|
|
86
101
|
rules: {
|
|
@@ -146,19 +161,19 @@ export const namingConventionOverrides = [
|
|
|
146
161
|
},
|
|
147
162
|
},
|
|
148
163
|
|
|
149
|
-
// helpers/*.helpers.ts: undecorated classes allowed, class must end with "Helpers"
|
|
164
|
+
// helpers/*.helpers.ts: undecorated classes allowed, class must end with "Helpers", nothing else at module level
|
|
150
165
|
{
|
|
151
166
|
files: ['**/helpers/**/*.helpers.ts'],
|
|
152
167
|
rules: {
|
|
153
168
|
'no-restricted-syntax': [
|
|
154
169
|
'error',
|
|
155
170
|
helpersClassSuffixRestriction,
|
|
171
|
+
...helpersFileRestrictions,
|
|
156
172
|
decoratorFileRestrictions.Component,
|
|
157
173
|
decoratorFileRestrictions.Directive,
|
|
158
174
|
decoratorFileRestrictions.Injectable,
|
|
159
175
|
decoratorFileRestrictions.Pipe,
|
|
160
176
|
...decoratorClassSuffixRestrictions,
|
|
161
|
-
...declarationFileRestrictions,
|
|
162
177
|
],
|
|
163
178
|
},
|
|
164
179
|
},
|
package/index.js
CHANGED
|
@@ -9,7 +9,7 @@ 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 {
|
|
12
|
+
import { noRestrictedSyntaxOverrides, noRestrictedSyntaxRule } from './file-conventions.js';
|
|
13
13
|
|
|
14
14
|
// @angular-eslint v22 dropped the `configs` export — manually enable all rules instead
|
|
15
15
|
const enableAllRules = (plugin, prefix) => Object.fromEntries(Object.keys(plugin.rules).map(k => [`${prefix}/${k}`, 'error']));
|
|
@@ -325,5 +325,5 @@ export default [
|
|
|
325
325
|
},
|
|
326
326
|
},
|
|
327
327
|
|
|
328
|
-
...
|
|
328
|
+
...noRestrictedSyntaxOverrides,
|
|
329
329
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-config-angular-strict",
|
|
3
|
-
"version": "22.1.
|
|
3
|
+
"version": "22.1.08",
|
|
4
4
|
"description": "Modern ESLint configuration with strict rules for Angular development.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@typescript-eslint/parser": "8.65.0",
|
|
45
45
|
"@typescript-eslint/types": "8.65.0",
|
|
46
46
|
"@typescript-eslint/utils": "8.65.0",
|
|
47
|
-
"eslint": "10.
|
|
47
|
+
"eslint": "10.8.0",
|
|
48
48
|
"eslint-config-airbnb-extended": "3.1.1",
|
|
49
49
|
"eslint-plugin-import-x": "4.17.1",
|
|
50
50
|
"eslint-plugin-perfectionist": "5.10.0",
|