@yoo-digital/eslint-plugin-angular 2.0.8 → 3.0.2
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/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# YOO ESLint plugin Angular
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Aim
|
|
4
4
|
|
|
5
|
-
Here should live all custom Angular lint rules that eslint does not already provide.
|
|
5
|
+
Here should live all ***custom Angular lint rules*** that eslint does not already provide.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Use
|
|
8
8
|
|
|
9
9
|
Wrong code is yellow/red underlined in VScode, it can also be raised running : `npm run lint`, autofixing them with : `npm run lint:fix`
|
|
10
10
|
|
|
@@ -15,6 +15,7 @@ TypeScript rule that enforces `booleanAttribute` transform on boolean inputs
|
|
|
15
15
|
### Setting
|
|
16
16
|
```json
|
|
17
17
|
{
|
|
18
|
+
"files": ["**/*.ts"],
|
|
18
19
|
"rules": {
|
|
19
20
|
"@yoo-digital/eslint-plugin-angular/boolean-attribute-shorthand": "error"
|
|
20
21
|
}
|
|
@@ -47,6 +48,7 @@ HTML rule that enforces shorthand syntax for `[attr]="true"` bindings
|
|
|
47
48
|
### Setting
|
|
48
49
|
```json
|
|
49
50
|
{
|
|
51
|
+
"files": ["**/*.html"],
|
|
50
52
|
"rules": {
|
|
51
53
|
"@yoo-digital/eslint-plugin-angular/boolean-attribute-shorthand": "error"
|
|
52
54
|
}
|
|
@@ -56,7 +58,7 @@ HTML rule that enforces shorthand syntax for `[attr]="true"` bindings
|
|
|
56
58
|
#### True value
|
|
57
59
|
```html
|
|
58
60
|
<mealComponent [isVegan]="true" />
|
|
59
|
-
<!-- Lint issue
|
|
61
|
+
<!-- Lint issue, must become : -->
|
|
60
62
|
<mealComponent isVegan />
|
|
61
63
|
```
|
|
62
64
|
|
|
@@ -66,7 +68,7 @@ HTML rule that enforces shorthand syntax for `[attr]="true"` bindings
|
|
|
66
68
|
<!-- No lint issue, to be able to address false value for a default true input -->
|
|
67
69
|
```
|
|
68
70
|
|
|
69
|
-
###
|
|
71
|
+
### Right usage
|
|
70
72
|
#### Default true
|
|
71
73
|
|
|
72
74
|
If boolean input is by default **true**
|
|
@@ -29,6 +29,7 @@ exports.preferBooleanAttributeShorthandRule = {
|
|
|
29
29
|
docs: {
|
|
30
30
|
description: 'Prefer boolean input attribute shorthand when binding to true (e.g., use "disabled" instead of [disabled]="true").',
|
|
31
31
|
},
|
|
32
|
+
fixable: 'code',
|
|
32
33
|
schema: [],
|
|
33
34
|
messages: {
|
|
34
35
|
preferTrue: 'Use attribute shorthand "{{attr}}" instead of [{{attr}}]="true".',
|
|
@@ -50,10 +51,13 @@ exports.preferBooleanAttributeShorthandRule = {
|
|
|
50
51
|
if (ast.value === true) {
|
|
51
52
|
const attrName = node.name;
|
|
52
53
|
const loc = parserServices.convertNodeSourceSpanToLoc(node.sourceSpan);
|
|
54
|
+
const start = node.sourceSpan.start.offset;
|
|
55
|
+
const end = node.sourceSpan.end.offset;
|
|
53
56
|
context.report({
|
|
54
57
|
loc,
|
|
55
58
|
messageId: 'preferTrue',
|
|
56
59
|
data: { attr: attrName },
|
|
60
|
+
fix: (fixer) => fixer.replaceTextRange([start, end], attrName),
|
|
57
61
|
});
|
|
58
62
|
}
|
|
59
63
|
// [attr]="false" is explicitly ignored - no warning
|
|
@@ -19,6 +19,7 @@ exports.requireBooleanAttributeTransformRule = {
|
|
|
19
19
|
docs: {
|
|
20
20
|
description: 'Require booleanAttribute transform on boolean @Input() properties and input() signals.',
|
|
21
21
|
},
|
|
22
|
+
fixable: 'code',
|
|
22
23
|
schema: [],
|
|
23
24
|
messages: {
|
|
24
25
|
requireTransformDecorator: 'Boolean @Input() "{{name}}" must use transform: booleanAttribute',
|
|
@@ -27,6 +28,7 @@ exports.requireBooleanAttributeTransformRule = {
|
|
|
27
28
|
},
|
|
28
29
|
defaultOptions: [],
|
|
29
30
|
create(context) {
|
|
31
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
30
32
|
return {
|
|
31
33
|
// Handle both @Input() decorator syntax and input() signal syntax
|
|
32
34
|
PropertyDefinition(node) {
|
|
@@ -62,6 +64,35 @@ exports.requireBooleanAttributeTransformRule = {
|
|
|
62
64
|
node: node.key,
|
|
63
65
|
messageId: 'requireTransformDecorator',
|
|
64
66
|
data: { name: propertyName },
|
|
67
|
+
fix(fixer) {
|
|
68
|
+
const decoratorNode = inputDecorator?.expression;
|
|
69
|
+
if (!decoratorNode || decoratorNode.type !== 'CallExpression') {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const decoratorStart = decoratorNode.range[0];
|
|
73
|
+
const decoratorEnd = decoratorNode.range[1];
|
|
74
|
+
// Generate the fixed decorator
|
|
75
|
+
let newDecorator;
|
|
76
|
+
if (decoratorNode.arguments.length === 0) {
|
|
77
|
+
// @Input() → @Input({ transform: booleanAttribute })
|
|
78
|
+
newDecorator = '@Input({ transform: booleanAttribute })';
|
|
79
|
+
}
|
|
80
|
+
else if (decoratorNode.arguments[0].type === 'ObjectExpression') {
|
|
81
|
+
// @Input({ ... }) → @Input({ ..., transform: booleanAttribute })
|
|
82
|
+
const objExpr = decoratorNode.arguments[0];
|
|
83
|
+
const objText = sourceCode.getText(objExpr);
|
|
84
|
+
const closingBrace = objText.lastIndexOf('}');
|
|
85
|
+
const existingProps = objText.substring(1, closingBrace).trim();
|
|
86
|
+
const separator = existingProps ? ', ' : '';
|
|
87
|
+
newDecorator = `@Input({ ${existingProps}${separator}transform: booleanAttribute })`;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// @Input('alias') → @Input({ alias: 'alias', transform: booleanAttribute })
|
|
91
|
+
const aliasArg = sourceCode.getText(decoratorNode.arguments[0]);
|
|
92
|
+
newDecorator = `@Input({ alias: ${aliasArg}, transform: booleanAttribute })`;
|
|
93
|
+
}
|
|
94
|
+
return fixer.replaceTextRange([decoratorStart, decoratorEnd], newDecorator);
|
|
95
|
+
},
|
|
65
96
|
});
|
|
66
97
|
return;
|
|
67
98
|
}
|
|
@@ -109,6 +140,15 @@ exports.requireBooleanAttributeTransformRule = {
|
|
|
109
140
|
node: node.key,
|
|
110
141
|
messageId: 'requireTransformSignal',
|
|
111
142
|
data: { name: propertyName },
|
|
143
|
+
fix(fixer) {
|
|
144
|
+
const callStart = callExpr.range[0];
|
|
145
|
+
const callEnd = callExpr.range[1];
|
|
146
|
+
// Get the default value argument
|
|
147
|
+
const defaultValue = callExpr.arguments[0] ? sourceCode.getText(callExpr.arguments[0]) : 'false';
|
|
148
|
+
// Build the new call expression
|
|
149
|
+
const newCall = `input<boolean, BooleanInput>(${defaultValue}, {\\n transform: booleanAttribute,\\n })`;
|
|
150
|
+
return fixer.replaceTextRange([callStart, callEnd], newCall);
|
|
151
|
+
},
|
|
112
152
|
});
|
|
113
153
|
},
|
|
114
154
|
// Handle input() signal syntax (standalone variable declarations - rare)
|
package/package.json
CHANGED