@angular-eslint/eslint-plugin-template 16.0.4-alpha.7 → 16.0.4-alpha.9

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.
@@ -24,6 +24,7 @@
24
24
  "@angular-eslint/template/no-interpolation-in-attributes": "error",
25
25
  "@angular-eslint/template/no-negated-async": "error",
26
26
  "@angular-eslint/template/no-positive-tabindex": "error",
27
+ "@angular-eslint/template/prefer-self-closing-tags": "error",
27
28
  "@angular-eslint/template/role-has-required-aria": "error",
28
29
  "@angular-eslint/template/table-scope": "error",
29
30
  "@angular-eslint/template/use-track-by-function": "error",
package/dist/index.js CHANGED
@@ -52,6 +52,7 @@ const no_inline_styles_1 = __importStar(require("./rules/no-inline-styles"));
52
52
  const no_interpolation_in_attributes_1 = __importStar(require("./rules/no-interpolation-in-attributes"));
53
53
  const no_negated_async_1 = __importStar(require("./rules/no-negated-async"));
54
54
  const no_positive_tabindex_1 = __importStar(require("./rules/no-positive-tabindex"));
55
+ const prefer_self_closing_tags_1 = __importStar(require("./rules/prefer-self-closing-tags"));
55
56
  const role_has_required_aria_1 = __importStar(require("./rules/role-has-required-aria"));
56
57
  const table_scope_1 = __importStar(require("./rules/table-scope"));
57
58
  const use_track_by_function_1 = __importStar(require("./rules/use-track-by-function"));
@@ -87,6 +88,7 @@ module.exports = {
87
88
  [no_interpolation_in_attributes_1.RULE_NAME]: no_interpolation_in_attributes_1.default,
88
89
  [no_negated_async_1.RULE_NAME]: no_negated_async_1.default,
89
90
  [no_positive_tabindex_1.RULE_NAME]: no_positive_tabindex_1.default,
91
+ [prefer_self_closing_tags_1.RULE_NAME]: prefer_self_closing_tags_1.default,
90
92
  [role_has_required_aria_1.RULE_NAME]: role_has_required_aria_1.default,
91
93
  [table_scope_1.RULE_NAME]: table_scope_1.default,
92
94
  [use_track_by_function_1.RULE_NAME]: use_track_by_function_1.default,
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RULE_NAME = exports.MESSAGE_ID = void 0;
4
+ const utils_1 = require("@angular-eslint/utils");
5
+ const create_eslint_rule_1 = require("../utils/create-eslint-rule");
6
+ const get_dom_elements_1 = require("../utils/get-dom-elements");
7
+ exports.MESSAGE_ID = 'preferSelfClosingTags';
8
+ exports.RULE_NAME = 'prefer-self-closing-tags';
9
+ exports.default = (0, create_eslint_rule_1.createESLintRule)({
10
+ name: exports.RULE_NAME,
11
+ meta: {
12
+ type: 'layout',
13
+ docs: {
14
+ description: 'Ensures that self-closing tags are used for elements with a closing tag but no content.',
15
+ recommended: false,
16
+ },
17
+ fixable: 'code',
18
+ schema: [],
19
+ messages: {
20
+ [exports.MESSAGE_ID]: 'Use self-closing tags for elements with a closing tag but no content.',
21
+ },
22
+ },
23
+ defaultOptions: [],
24
+ create(context) {
25
+ const parserServices = (0, utils_1.getTemplateParserServices)(context);
26
+ return {
27
+ Element$1({ children, name, startSourceSpan, endSourceSpan, }) {
28
+ // Ignore native elements.
29
+ if ((0, get_dom_elements_1.getDomElements)().has(name)) {
30
+ return;
31
+ }
32
+ const noContent = !children.length ||
33
+ children.every((node) => {
34
+ const text = node.value;
35
+ // If the node has no value, or only whitespace,
36
+ // we can consider it empty.
37
+ return (typeof text === 'string' && text.replace(/\n/g, '').trim() === '');
38
+ });
39
+ const noCloseTag = !endSourceSpan ||
40
+ (startSourceSpan.start.offset === endSourceSpan.start.offset &&
41
+ startSourceSpan.end.offset === endSourceSpan.end.offset);
42
+ if (!noContent || noCloseTag) {
43
+ return;
44
+ }
45
+ context.report({
46
+ loc: parserServices.convertNodeSourceSpanToLoc(endSourceSpan),
47
+ messageId: exports.MESSAGE_ID,
48
+ fix: (fixer) => fixer.replaceTextRange([startSourceSpan.end.offset - 1, endSourceSpan.end.offset], ' />'),
49
+ });
50
+ },
51
+ };
52
+ },
53
+ });
@@ -98,6 +98,12 @@ function isNil(value) {
98
98
  function isString(value) {
99
99
  return typeof value == 'string';
100
100
  }
101
+ function isMixed(value) {
102
+ return isString(value) && value === 'mixed';
103
+ }
104
+ function isTristate(value) {
105
+ return isMixed(value) || isBooleanLike(value) || isNil(value);
106
+ }
101
107
  function isValidAriaPropertyValue({ allowundefined, type, values }, attributeValue) {
102
108
  if (allowundefined && isNil(attributeValue))
103
109
  return true;
@@ -105,7 +111,7 @@ function isValidAriaPropertyValue({ allowundefined, type, values }, attributeVal
105
111
  case 'boolean':
106
112
  return isBooleanLike(attributeValue);
107
113
  case 'tristate':
108
- return isBooleanLike(attributeValue) || isNil(attributeValue);
114
+ return isTristate(attributeValue);
109
115
  case 'id':
110
116
  case 'idlist':
111
117
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-eslint/eslint-plugin-template",
3
- "version": "16.0.4-alpha.7+580c842",
3
+ "version": "16.0.4-alpha.9+6d26c59",
4
4
  "description": "ESLint plugin for Angular Templates",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -17,8 +17,8 @@
17
17
  "LICENSE"
18
18
  ],
19
19
  "dependencies": {
20
- "@angular-eslint/bundled-angular-compiler": "16.0.4-alpha.7+580c842",
21
- "@angular-eslint/utils": "16.0.4-alpha.7+580c842",
20
+ "@angular-eslint/bundled-angular-compiler": "16.0.4-alpha.9+6d26c59",
21
+ "@angular-eslint/utils": "16.0.4-alpha.9+6d26c59",
22
22
  "@typescript-eslint/type-utils": "5.59.8",
23
23
  "@typescript-eslint/utils": "5.59.8",
24
24
  "aria-query": "5.1.3",
@@ -31,5 +31,5 @@
31
31
  "eslint": "^7.20.0 || ^8.0.0",
32
32
  "typescript": "*"
33
33
  },
34
- "gitHead": "580c8422835ec29eeeb3d196c934bf18e243dc09"
34
+ "gitHead": "6d26c590e4b15e0b28a6ff7467560537e2b9b92d"
35
35
  }