@angular-eslint/eslint-plugin-template 17.0.0-alpha.0 → 17.0.1-alpha.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.
@@ -23,35 +23,90 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
23
23
  create(context) {
24
24
  const parserServices = (0, utils_1.getTemplateParserServices)(context);
25
25
  return {
26
- Element$1({ children, name, startSourceSpan, endSourceSpan, }) {
27
- // Ignore native elements.
28
- if ((0, get_dom_elements_1.getDomElements)().has(name)) {
29
- return;
26
+ 'Element$1, Template, Content'(node) {
27
+ if (isContentNode(node)) {
28
+ processContentNode(node);
30
29
  }
31
- const noContent = !children.length ||
32
- children.every((node) => {
33
- const text = node.value;
34
- // If the node has no value, or only whitespace,
35
- // we can consider it empty.
36
- return (typeof text === 'string' && text.replace(/\n/g, '').trim() === '');
37
- });
38
- const noCloseTag = !endSourceSpan ||
39
- (startSourceSpan.start.offset === endSourceSpan.start.offset &&
40
- startSourceSpan.end.offset === endSourceSpan.end.offset);
41
- if (!noContent || noCloseTag) {
42
- return;
30
+ else {
31
+ // Ignore native elements.
32
+ if ('name' in node && (0, get_dom_elements_1.getDomElements)().has(node.name)) {
33
+ return;
34
+ }
35
+ processElementOrTemplateNode(node);
43
36
  }
44
- // HTML tags always have more than two characters
37
+ },
38
+ };
39
+ function processElementOrTemplateNode(node) {
40
+ const { children, startSourceSpan, endSourceSpan } = node;
41
+ const noContent = !children.length ||
42
+ children.every((node) => {
43
+ const text = node.value;
44
+ // If the node has no value, or only whitespace,
45
+ // we can consider it empty.
46
+ return (typeof text === 'string' && text.replace(/\n/g, '').trim() === '');
47
+ });
48
+ const noCloseTag = !endSourceSpan ||
49
+ (startSourceSpan.start.offset === endSourceSpan.start.offset &&
50
+ startSourceSpan.end.offset === endSourceSpan.end.offset);
51
+ if (!noContent || noCloseTag) {
52
+ return;
53
+ }
54
+ // HTML tags always have more than two characters
55
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
56
+ const openingTagLastChar = startSourceSpan.toString().at(-2);
57
+ const closingTagPrefix = getClosingTagPrefix(openingTagLastChar);
58
+ context.report({
59
+ loc: parserServices.convertNodeSourceSpanToLoc(endSourceSpan),
60
+ messageId: exports.MESSAGE_ID,
61
+ fix: (fixer) => fixer.replaceTextRange([startSourceSpan.end.offset - 1, endSourceSpan.end.offset], closingTagPrefix + '/>'),
62
+ });
63
+ }
64
+ function processContentNode(node) {
65
+ var _a, _b;
66
+ const { sourceSpan } = node;
67
+ const ngContentCloseTag = '</ng-content>';
68
+ if (sourceSpan.toString().includes(ngContentCloseTag)) {
69
+ // content nodes can only contain whitespaces
70
+ const content = (_b = (_a = sourceSpan
71
+ .toString()
72
+ .match(/>(\s*)</m)) === null || _a === void 0 ? void 0 : _a.at(1)) !== null && _b !== void 0 ? _b : '';
73
+ const openingTagLastChar =
74
+ // This is more than the minimum length of a ng-content element
45
75
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
46
- const openingTagLastChar = startSourceSpan.toString().at(-2);
47
- const hasOwnWhitespace = openingTagLastChar.trim() === '';
48
- const closingTagPrefix = hasOwnWhitespace ? '' : ' ';
76
+ sourceSpan
77
+ .toString()
78
+ .at(-2 - ngContentCloseTag.length - content.length);
79
+ const closingTagPrefix = getClosingTagPrefix(openingTagLastChar);
49
80
  context.report({
50
- loc: parserServices.convertNodeSourceSpanToLoc(endSourceSpan),
81
+ // content nodes don't have information about startSourceSpan and endSourceSpan,
82
+ // so we need to calculate it by our own
83
+ loc: {
84
+ start: {
85
+ line: sourceSpan.end.line + 1,
86
+ column: sourceSpan.end.col - ngContentCloseTag.length,
87
+ },
88
+ end: {
89
+ line: sourceSpan.end.line + 1,
90
+ column: sourceSpan.end.col,
91
+ },
92
+ },
51
93
  messageId: exports.MESSAGE_ID,
52
- fix: (fixer) => fixer.replaceTextRange([startSourceSpan.end.offset - 1, endSourceSpan.end.offset], closingTagPrefix + '/>'),
94
+ fix: (fixer) => fixer.replaceTextRange([
95
+ sourceSpan.end.offset -
96
+ ngContentCloseTag.length -
97
+ content.length -
98
+ 1,
99
+ sourceSpan.end.offset,
100
+ ], closingTagPrefix + '/>'),
53
101
  });
54
- },
55
- };
102
+ }
103
+ }
56
104
  },
57
105
  });
106
+ function isContentNode(node) {
107
+ return 'name' in node && node.name === 'ng-content';
108
+ }
109
+ function getClosingTagPrefix(openingTagLastChar) {
110
+ const hasOwnWhitespace = openingTagLastChar.trim() === '';
111
+ return hasOwnWhitespace ? '' : ' ';
112
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-eslint/eslint-plugin-template",
3
- "version": "17.0.0-alpha.0",
3
+ "version": "17.0.1-alpha.0+4eddce1",
4
4
  "description": "ESLint plugin for Angular Templates",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -17,19 +17,19 @@
17
17
  "LICENSE"
18
18
  ],
19
19
  "dependencies": {
20
- "@angular-eslint/bundled-angular-compiler": "17.0.0-alpha.0",
21
- "@angular-eslint/utils": "17.0.0-alpha.0",
20
+ "@angular-eslint/bundled-angular-compiler": "17.0.1-alpha.0+4eddce1",
21
+ "@angular-eslint/utils": "17.0.1-alpha.0+4eddce1",
22
22
  "@typescript-eslint/type-utils": "6.10.0",
23
23
  "@typescript-eslint/utils": "6.10.0",
24
24
  "aria-query": "5.3.0",
25
- "axobject-query": "3.2.1"
25
+ "axobject-query": "4.0.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@types/aria-query": "5.0.3"
28
+ "@types/aria-query": "5.0.4"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "eslint": "^7.20.0 || ^8.0.0",
32
32
  "typescript": "*"
33
33
  },
34
- "gitHead": "e0478be1ae5b9010ad1d74eac4d06511250bf13f"
34
+ "gitHead": "4eddce1ede6e3baccb297dcbb5b980af95126f64"
35
35
  }