@yoo-digital/eslint-plugin-angular 0.1.9 → 1.1.0
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,6 +1,113 @@
|
|
|
1
1
|
# eslint-plugin-angular
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Custom lint purpose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Here should live all custom Angular lint rules that eslint does not already provide.
|
|
6
6
|
|
|
7
|
+
## Linting
|
|
8
|
+
|
|
9
|
+
Wrong code is yellow underlined in VScode, it can also be raises running : `npm run lint`
|
|
10
|
+
|
|
11
|
+
## Rule 1 : boolean input conversion (prefer-boolean-attribute-shorthand)
|
|
12
|
+
|
|
13
|
+
`booleanAttribute @angular/core`
|
|
14
|
+
|
|
15
|
+
`BooleanInput @angular/cdk/coercion`
|
|
16
|
+
|
|
17
|
+
### ⚠️ Important Limitations
|
|
18
|
+
|
|
19
|
+
**Current Implementation:** This rule enforces shorthand syntax (`<x a />` instead of `<x [a]="true" />`) but **cannot automatically verify**:
|
|
20
|
+
- Whether an input has `transform: booleanAttribute`
|
|
21
|
+
- What the default value of an input is
|
|
22
|
+
|
|
23
|
+
This is a technical limitation of Angular ESLint - template rules cannot access the component's TypeScript code.
|
|
24
|
+
|
|
25
|
+
### Recommended Usage
|
|
26
|
+
|
|
27
|
+
This rule works best when:
|
|
28
|
+
1. **All boolean inputs** in your project use `booleanAttribute` transform
|
|
29
|
+
2. **Most boolean inputs** have `default = false` or no default
|
|
30
|
+
3. You treat this as a **style guide enforcer** rather than a safety checker
|
|
31
|
+
|
|
32
|
+
### Configuration
|
|
33
|
+
|
|
34
|
+
By default, the rule only flags `[attr]="true"` bindings (safe default):
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"rules": {
|
|
39
|
+
"@yoo-digital/eslint-plugin-angular/prefer-boolean-attribute-shorthand": "error"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
To also enforce removal of `[attr]="false"` bindings:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"rules": {
|
|
49
|
+
"@yoo-digital/eslint-plugin-angular/prefer-boolean-attribute-shorthand": [
|
|
50
|
+
"error",
|
|
51
|
+
{ "allowFalseLiteral": false }
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Examples
|
|
58
|
+
|
|
59
|
+
#### ✅ Recommended Pattern (Default false or no default)
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// Component
|
|
63
|
+
@Input({ transform: booleanAttribute }) disabled: boolean = false;
|
|
64
|
+
// OR
|
|
65
|
+
disabled = input<boolean, BooleanInput>(false, { transform: booleanAttribute });
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Template:**
|
|
69
|
+
- ❌ `<button [disabled]="true">` → Should be `<button disabled>`
|
|
70
|
+
- ✅ `<button disabled>` (shorthand for true)
|
|
71
|
+
- ✅ `<button>` (omit for false)
|
|
72
|
+
- ✅ `<button [disabled]="isLoading">` (expressions are allowed)
|
|
73
|
+
|
|
74
|
+
#### ⚠️ Special Case: Default true (Disable rule if needed)
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// Component
|
|
78
|
+
@Input({ transform: booleanAttribute }) enabled: boolean = true;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Template:**
|
|
82
|
+
```html
|
|
83
|
+
<!-- eslint-disable-next-line @yoo-digital/eslint-plugin-angular/prefer-boolean-attribute-shorthand -->
|
|
84
|
+
<button [enabled]="false">Explicitly disabled</button>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
When default is `true`, you may need explicit `[attr]="true"` or `[attr]="false"` bindings.
|
|
88
|
+
|
|
89
|
+
#### ❌ Without booleanAttribute (Won't work!)
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// Component - Missing transform!
|
|
93
|
+
@Input() checked: boolean = false;
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Template:**
|
|
97
|
+
- ❌ `<input checked>` → Will pass `""` (empty string), NOT boolean!
|
|
98
|
+
- ✅ `<input [checked]="true">` (must use property binding)
|
|
99
|
+
|
|
100
|
+
### Decorator Syntax
|
|
101
|
+
|
|
102
|
+
`@Input({ transform: booleanAttribute }) myInput: boolean = false;`
|
|
103
|
+
|
|
104
|
+
### Signal Input Syntax
|
|
105
|
+
|
|
106
|
+
`myInput = input<boolean, BooleanInput>(false, { transform: booleanAttribute });`
|
|
107
|
+
|
|
108
|
+
### Summary
|
|
109
|
+
|
|
110
|
+
- **Rule enforces**: `[attr]="true"` → `attr` shorthand
|
|
111
|
+
- **Rule assumes**: Inputs have `booleanAttribute` and `default ≠ true`
|
|
112
|
+
- **Manual override**: Use eslint-disable comments for special cases
|
|
113
|
+
- **Best practice**: Ensure all boolean inputs use `booleanAttribute`
|
|
@@ -4,5 +4,34 @@ interface Options {
|
|
|
4
4
|
}
|
|
5
5
|
type MessageIds = 'preferTrue' | 'preferFalse' | 'suggestTrue' | 'suggestRemove';
|
|
6
6
|
export declare const RULE_NAME = "prefer-boolean-attribute-shorthand";
|
|
7
|
+
/**
|
|
8
|
+
* IMPORTANT LIMITATIONS:
|
|
9
|
+
*
|
|
10
|
+
* Angular ESLint template rules cannot directly access the TypeScript component class
|
|
11
|
+
* to check for booleanAttribute transforms or default values. This would require:
|
|
12
|
+
* 1. Access to the TypeScript program (not available in template parser services)
|
|
13
|
+
* 2. Cross-file analysis (template -> component.ts)
|
|
14
|
+
* 3. Complex AST traversal and decorator/signal input analysis
|
|
15
|
+
*
|
|
16
|
+
* The current implementation enforces shorthand syntax for [attr]="true" bindings
|
|
17
|
+
* but cannot verify:
|
|
18
|
+
* - Whether the input has `transform: booleanAttribute`
|
|
19
|
+
* - What the default value of the input is
|
|
20
|
+
*
|
|
21
|
+
* RECOMMENDATIONS FOR USERS:
|
|
22
|
+
* 1. Only use this rule in projects where ALL boolean inputs have booleanAttribute
|
|
23
|
+
* 2. If an input has default=true, manually disable the rule for that binding
|
|
24
|
+
* 3. Consider the rule as a style guide enforcer, not a safety checker
|
|
25
|
+
*
|
|
26
|
+
* FUTURE ENHANCEMENTS:
|
|
27
|
+
* To implement the full feature set requested would require creating a SEPARATE
|
|
28
|
+
* TypeScript ESLint rule that:
|
|
29
|
+
* - Runs on .ts component files (not templates)
|
|
30
|
+
* - Analyzes @Component decorators to find template references
|
|
31
|
+
* - Parses templates and cross-references with component inputs
|
|
32
|
+
* - Reports errors in both .ts and template files
|
|
33
|
+
*
|
|
34
|
+
* This would be a significantly more complex multi-file analysis rule.
|
|
35
|
+
*/
|
|
7
36
|
export declare const preferBooleanAttributeShorthandRule: TSESLint.RuleModule<MessageIds, Options[]>;
|
|
8
37
|
export {};
|
|
@@ -3,11 +3,40 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.preferBooleanAttributeShorthandRule = exports.RULE_NAME = void 0;
|
|
4
4
|
const utils_1 = require("@angular-eslint/utils");
|
|
5
5
|
exports.RULE_NAME = 'prefer-boolean-attribute-shorthand';
|
|
6
|
+
/**
|
|
7
|
+
* IMPORTANT LIMITATIONS:
|
|
8
|
+
*
|
|
9
|
+
* Angular ESLint template rules cannot directly access the TypeScript component class
|
|
10
|
+
* to check for booleanAttribute transforms or default values. This would require:
|
|
11
|
+
* 1. Access to the TypeScript program (not available in template parser services)
|
|
12
|
+
* 2. Cross-file analysis (template -> component.ts)
|
|
13
|
+
* 3. Complex AST traversal and decorator/signal input analysis
|
|
14
|
+
*
|
|
15
|
+
* The current implementation enforces shorthand syntax for [attr]="true" bindings
|
|
16
|
+
* but cannot verify:
|
|
17
|
+
* - Whether the input has `transform: booleanAttribute`
|
|
18
|
+
* - What the default value of the input is
|
|
19
|
+
*
|
|
20
|
+
* RECOMMENDATIONS FOR USERS:
|
|
21
|
+
* 1. Only use this rule in projects where ALL boolean inputs have booleanAttribute
|
|
22
|
+
* 2. If an input has default=true, manually disable the rule for that binding
|
|
23
|
+
* 3. Consider the rule as a style guide enforcer, not a safety checker
|
|
24
|
+
*
|
|
25
|
+
* FUTURE ENHANCEMENTS:
|
|
26
|
+
* To implement the full feature set requested would require creating a SEPARATE
|
|
27
|
+
* TypeScript ESLint rule that:
|
|
28
|
+
* - Runs on .ts component files (not templates)
|
|
29
|
+
* - Analyzes @Component decorators to find template references
|
|
30
|
+
* - Parses templates and cross-references with component inputs
|
|
31
|
+
* - Reports errors in both .ts and template files
|
|
32
|
+
*
|
|
33
|
+
* This would be a significantly more complex multi-file analysis rule.
|
|
34
|
+
*/
|
|
6
35
|
exports.preferBooleanAttributeShorthandRule = {
|
|
7
36
|
meta: {
|
|
8
37
|
type: 'suggestion',
|
|
9
38
|
docs: {
|
|
10
|
-
description: 'Prefer boolean input attribute shorthand instead of binding to literal true/false.',
|
|
39
|
+
description: 'Prefer boolean input attribute shorthand instead of binding to literal true/false. NOTE: This rule assumes inputs have booleanAttribute transform and does not have default=true.',
|
|
11
40
|
},
|
|
12
41
|
hasSuggestions: true,
|
|
13
42
|
schema: [
|
|
@@ -20,22 +49,22 @@ exports.preferBooleanAttributeShorthandRule = {
|
|
|
20
49
|
},
|
|
21
50
|
],
|
|
22
51
|
messages: {
|
|
23
|
-
preferTrue: 'Use attribute shorthand "{{attr}}" instead of [{{attr}}]="true".',
|
|
24
|
-
preferFalse: 'Avoid binding [{{attr}}]="false"; remove the binding
|
|
52
|
+
preferTrue: 'Use attribute shorthand "{{attr}}" instead of [{{attr}}]="true". WARNING: Only works if input has booleanAttribute transform.',
|
|
53
|
+
preferFalse: 'Avoid binding [{{attr}}]="false"; remove the binding if default is false.',
|
|
25
54
|
suggestTrue: 'Replace with attribute shorthand {{attr}}',
|
|
26
55
|
suggestRemove: 'Remove the false binding',
|
|
27
56
|
},
|
|
28
57
|
},
|
|
29
58
|
defaultOptions: [
|
|
30
59
|
{
|
|
31
|
-
allowFalseLiteral:
|
|
60
|
+
allowFalseLiteral: true, // Changed default to true for safety
|
|
32
61
|
},
|
|
33
62
|
],
|
|
34
63
|
create(context) {
|
|
35
64
|
// Robust to missing options: default to [{}] if undefined
|
|
36
65
|
const optionsArr = context.options ?? [{}];
|
|
37
66
|
const options = optionsArr[0] ?? {};
|
|
38
|
-
const allowFalseLiteral = options.allowFalseLiteral ??
|
|
67
|
+
const allowFalseLiteral = options.allowFalseLiteral ?? true; // Default to true for safety
|
|
39
68
|
const parserServices = (0, utils_1.getTemplateParserServices)(context);
|
|
40
69
|
return {
|
|
41
70
|
BoundAttribute(node) {
|
|
@@ -49,6 +78,8 @@ exports.preferBooleanAttributeShorthandRule = {
|
|
|
49
78
|
const start = node.sourceSpan.start.offset;
|
|
50
79
|
const end = node.sourceSpan.end.offset;
|
|
51
80
|
if (ast.value === true) {
|
|
81
|
+
// Enforce shorthand for true bindings
|
|
82
|
+
// NOTE: This assumes the input has booleanAttribute and default != true
|
|
52
83
|
context.report({
|
|
53
84
|
loc,
|
|
54
85
|
messageId: 'preferTrue',
|
|
@@ -63,6 +94,7 @@ exports.preferBooleanAttributeShorthandRule = {
|
|
|
63
94
|
});
|
|
64
95
|
}
|
|
65
96
|
else if (ast.value === false && !allowFalseLiteral) {
|
|
97
|
+
// Only flag false bindings if explicitly configured
|
|
66
98
|
context.report({
|
|
67
99
|
loc,
|
|
68
100
|
messageId: 'preferFalse',
|
package/package.json
CHANGED