@yoo-digital/eslint-plugin-angular 2.0.9 → 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
@@ -15,7 +15,7 @@ TypeScript rule that enforces `booleanAttribute` transform on boolean inputs
15
15
  ### Setting
16
16
  ```json
17
17
  {
18
- "files": ['**/*.ts'],
18
+ "files": ["**/*.ts"],
19
19
  "rules": {
20
20
  "@yoo-digital/eslint-plugin-angular/boolean-attribute-shorthand": "error"
21
21
  }
@@ -48,7 +48,7 @@ HTML rule that enforces shorthand syntax for `[attr]="true"` bindings
48
48
  ### Setting
49
49
  ```json
50
50
  {
51
- "files": ['**/*.html'],
51
+ "files": ["**/*.html"],
52
52
  "rules": {
53
53
  "@yoo-digital/eslint-plugin-angular/boolean-attribute-shorthand": "error"
54
54
  }
@@ -58,7 +58,7 @@ HTML rule that enforces shorthand syntax for `[attr]="true"` bindings
58
58
  #### True value
59
59
  ```html
60
60
  <mealComponent [isVegan]="true" />
61
- <!-- Lint issue enforcing to be : -->
61
+ <!-- Lint issue, must become : -->
62
62
  <mealComponent isVegan />
63
63
  ```
64
64
 
@@ -68,7 +68,7 @@ HTML rule that enforces shorthand syntax for `[attr]="true"` bindings
68
68
  <!-- No lint issue, to be able to address false value for a default true input -->
69
69
  ```
70
70
 
71
- ### Default value
71
+ ### Right usage
72
72
  #### Default true
73
73
 
74
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoo-digital/eslint-plugin-angular",
3
- "version": "2.0.9",
3
+ "version": "3.0.2",
4
4
  "description": "Yoo Digital custom Angular ESLint plugin for enforcing boolean attribute best practices.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",