@angular-eslint/eslint-plugin-template 22.3.1-alpha.2 → 22.3.1-alpha.4

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 +1 @@
1
- {"version":3,"file":"no-inline-styles.d.ts","sourceRoot":"","sources":["../../src/rules/no-inline-styles.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;QAChC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;KACrC;CACF,CAAC;AAKF,MAAM,MAAM,UAAU,GAAG,gBAAgB,CAAC;AAC1C,eAAO,MAAM,SAAS,qBAAqB,CAAC;;;;AAE5C,wBAqEG;AAwCH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
1
+ {"version":3,"file":"no-inline-styles.d.ts","sourceRoot":"","sources":["../../src/rules/no-inline-styles.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,OAAO,GAAG;IACpB;QACE,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;QAChC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;KACrC;CACF,CAAC;AAKF,MAAM,MAAM,UAAU,GAAG,gBAAgB,CAAC;AAC1C,eAAO,MAAM,SAAS,qBAAqB,CAAC;;;;AAM5C,wBA4EG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RULE_DOCS_EXTENSION = exports.RULE_NAME = void 0;
4
+ const bundled_angular_compiler_1 = require("@angular-eslint/bundled-angular-compiler");
4
5
  const utils_1 = require("@angular-eslint/utils");
5
6
  const create_eslint_rule_1 = require("../utils/create-eslint-rule");
6
7
  const DEFAULT_OPTIONS = {
@@ -40,22 +41,27 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
40
41
  const parserServices = (0, utils_1.getTemplateParserServices)(context);
41
42
  return {
42
43
  Element(node) {
43
- let isInvalid = false;
44
- if (!allowNgStyle && !allowBindToStyle) {
45
- isInvalid =
46
- isNodeHasStyleAttribute(node) ||
47
- isNodeHasNgStyleAttribute(node) ||
48
- isNodeHasBindingToStyleAttribute(node);
49
- }
50
- else {
51
- const ngStyle = allowNgStyle
52
- ? false
53
- : isNodeHasNgStyleAttribute(node);
54
- const bindToStyle = allowBindToStyle
55
- ? false
56
- : isNodeHasBindingToStyleAttribute(node);
57
- isInvalid = isNodeHasStyleAttribute(node) || ngStyle || bindToStyle;
58
- }
44
+ const hasDisallowedInput = node.inputs.some((input) => {
45
+ const { __originalType: originalType, type } = input;
46
+ switch (originalType ?? type) {
47
+ case bundled_angular_compiler_1.BindingType.Attribute:
48
+ return input.name === 'style';
49
+ case bundled_angular_compiler_1.BindingType.Style:
50
+ return !allowBindToStyle;
51
+ case bundled_angular_compiler_1.BindingType.Property:
52
+ if (input.name === 'style') {
53
+ return !allowBindToStyle;
54
+ }
55
+ if (input.name === 'ngStyle') {
56
+ return !allowNgStyle;
57
+ }
58
+ return false;
59
+ default:
60
+ return false;
61
+ }
62
+ });
63
+ const isInvalid = node.attributes.some(({ name }) => name === 'style') ||
64
+ hasDisallowedInput;
59
65
  if (isInvalid) {
60
66
  const loc = parserServices.convertElementSourceSpanToLoc(context, node);
61
67
  context.report({
@@ -70,37 +76,6 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
70
76
  };
71
77
  },
72
78
  });
73
- /**
74
- * Check that an element (for example `<img>`) has a `style` attribute or `attr.style` binding.
75
- */
76
- function isNodeHasStyleAttribute(node) {
77
- return (node.attributes.some(({ name }) => isStyle(name)) ||
78
- node.inputs.some(({ name }) => isStyle(name)));
79
- }
80
- /**
81
- * Check that an element (for example `<img>`) has a `ngStyle` attribute binding.
82
- */
83
- function isNodeHasNgStyleAttribute(node) {
84
- return node.inputs.some(({ name }) => isNgStyle(name));
85
- }
86
- /**
87
- * Check that an element (for example `<img>`) has a `[style.background-color]` attribute binding.
88
- */
89
- function isNodeHasBindingToStyleAttribute(node) {
90
- return node.inputs.some(({ keySpan }) => isStyleBound(keySpan));
91
- }
92
- /**
93
- * Check element is style
94
- */
95
- function isStyle(name) {
96
- return name === 'style';
97
- }
98
- function isNgStyle(name) {
99
- return name === 'ngStyle';
100
- }
101
- function isStyleBound(keySpan) {
102
- return keySpan?.details ? keySpan.details.includes('style.') : false;
103
- }
104
79
  exports.RULE_DOCS_EXTENSION = {
105
- rationale: 'Inline styles in templates (style attribute, ngStyle directive, or [style.property] bindings) make it difficult to maintain consistent styling across an application and can violate Content Security Policy (CSP) restrictions. Styles should be defined in component stylesheets or CSS classes where they can be managed centrally, reused, cached by browsers, and easily modified. Inline styles also mix presentation concerns with template structure, making templates harder to read. Using CSS classes with [class] or [ngClass] bindings provides the same dynamic styling capabilities while keeping styles organized and maintainable. This rule can be configured to allow ngStyle or style bindings if needed for specific use cases.',
80
+ rationale: 'Inline styles in templates (style attribute, ngStyle directive, [style] bindings, or [style.property] bindings) make it difficult to maintain consistent styling across an application and can violate Content Security Policy (CSP) restrictions. Styles should be defined in component stylesheets or CSS classes where they can be managed centrally, reused, cached by browsers, and easily modified. Inline styles also mix presentation concerns with template structure, making templates harder to read. Using CSS classes with [class] or [ngClass] bindings provides the same dynamic styling capabilities while keeping styles organized and maintainable. This rule can be configured to allow ngStyle or style bindings if needed for specific use cases.',
106
81
  };
@@ -1 +1 @@
1
- {"version":3,"file":"prefer-self-closing-tags.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-self-closing-tags.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,uBAAuB,CAAC;AACjD,eAAO,MAAM,SAAS,6BAA6B,CAAC;;;;AAEpD,wBA+JG;AAuCH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
1
+ {"version":3,"file":"prefer-self-closing-tags.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-self-closing-tags.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,uBAAuB,CAAC;AACjD,eAAO,MAAM,SAAS,6BAA6B,CAAC;;;;AAEpD,wBAiKG;AAoDH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
@@ -22,9 +22,11 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
22
22
  },
23
23
  create(context) {
24
24
  const parserServices = (0, utils_1.getTemplateParserServices)(context);
25
- // angular 18 doesn't support self closing tags in index.html
26
- if (/src[\\/]index\.html$/.test(context.physicalFilename)) {
27
- // If it is, return an empty object to skip this rule
25
+ // An index.html file is served to the browser as-is rather than being
26
+ // compiled as an Angular template, and browsers do not support
27
+ // self-closing tags for custom elements, so skip the rule for any
28
+ // file with that name regardless of where it lives.
29
+ if (/(^|[\\/])index\.html$/.test(context.physicalFilename)) {
28
30
  return {};
29
31
  }
30
32
  return {
@@ -34,7 +36,7 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
34
36
  }
35
37
  else {
36
38
  // Ignore native elements.
37
- if ('name' in node && (0, get_dom_elements_1.getDomElements)().has(node.name.toLowerCase())) {
39
+ if ('name' in node && isNativeElement(node.name)) {
38
40
  return;
39
41
  }
40
42
  processElementOrTemplateNode(node);
@@ -135,6 +137,16 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
135
137
  }
136
138
  },
137
139
  });
140
+ function isNativeElement(name) {
141
+ const lowerCaseName = name.toLowerCase();
142
+ // The Angular compiler namespaces the children of `<svg>` and `<math>`
143
+ // (e.g. `:svg:use` and `:math:mi`). These are foreign elements that are
144
+ // native to the browser, and self-closing some of them (such as `<title />`)
145
+ // produces a template that Angular cannot parse.
146
+ return (lowerCaseName.startsWith(':svg:') ||
147
+ lowerCaseName.startsWith(':math:') ||
148
+ (0, get_dom_elements_1.getDomElements)().has(lowerCaseName));
149
+ }
138
150
  function isContentNode(node) {
139
151
  return 'name' in node && node.name.toLowerCase() === 'ng-content';
140
152
  }
@@ -1 +1 @@
1
- {"version":3,"file":"literal-primitive.d.ts","sourceRoot":"","sources":["../../src/utils/literal-primitive.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EACH,gBAAgB,EACjB,MAAM,0CAA0C,CAAC;AAElD,MAAM,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEpC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,IAAI,gBAAgB,CAEtE;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,GAAG,GACR,IAAI,IAAI,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAE7D;AAED,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,KAAK,GACX,MAAM,CAIR"}
1
+ {"version":3,"file":"literal-primitive.d.ts","sourceRoot":"","sources":["../../src/utils/literal-primitive.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EACH,gBAAgB,EACjB,MAAM,0CAA0C,CAAC;AAElD,MAAM,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEpC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,IAAI,gBAAgB,CAStE;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,GAAG,GACR,IAAI,IAAI,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAE7D;AAED,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,KAAK,GACX,MAAM,CAIR"}
@@ -5,7 +5,12 @@ exports.isStringLiteralPrimitive = isStringLiteralPrimitive;
5
5
  exports.getLiteralPrimitiveStringValue = getLiteralPrimitiveStringValue;
6
6
  const bundled_angular_compiler_1 = require("@angular-eslint/bundled-angular-compiler");
7
7
  function isLiteralPrimitive(node) {
8
- return node instanceof bundled_angular_compiler_1.LiteralPrimitive;
8
+ // The template parser stamps `type` from `constructor.name`. `instanceof`
9
+ // fails when more than one copy of `@angular-eslint/bundled-angular-compiler`
10
+ // is installed (version mismatches, Yarn `hoistingLimits`, etc.).
11
+ return (!!node &&
12
+ (node.type === 'LiteralPrimitive' ||
13
+ node instanceof bundled_angular_compiler_1.LiteralPrimitive));
9
14
  }
10
15
  function isStringLiteralPrimitive(node) {
11
16
  return isLiteralPrimitive(node) && typeof node.value === 'string';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-eslint/eslint-plugin-template",
3
- "version": "22.3.1-alpha.2",
3
+ "version": "22.3.1-alpha.4",
4
4
  "description": "ESLint plugin for Angular Templates",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -19,17 +19,17 @@
19
19
  "LICENSE"
20
20
  ],
21
21
  "dependencies": {
22
- "@angular-eslint/bundled-angular-compiler": "22.3.1-alpha.2",
23
- "@angular-eslint/utils": "22.3.1-alpha.2",
22
+ "@angular-eslint/bundled-angular-compiler": "22.3.1-alpha.4",
23
+ "@angular-eslint/utils": "22.3.1-alpha.4",
24
24
  "aria-query": "5.3.2",
25
25
  "axobject-query": "4.1.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@angular-eslint/test-utils": "22.3.1-alpha.2",
28
+ "@angular-eslint/test-utils": "22.3.1-alpha.4",
29
29
  "@types/aria-query": "5.0.4"
30
30
  },
31
31
  "peerDependencies": {
32
- "@angular-eslint/template-parser": "22.3.1-alpha.2",
32
+ "@angular-eslint/template-parser": "22.3.1-alpha.4",
33
33
  "@typescript-eslint/types": "^8.0.0",
34
34
  "@typescript-eslint/utils": "^8.0.0",
35
35
  "eslint": "^9.0.0 || ^10.0.0",