@angular-eslint/eslint-plugin-template 17.0.2-alpha.0 → 17.0.2-alpha.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
@@ -57,7 +57,7 @@
57
57
  | [`no-distracting-elements`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-distracting-elements.md) | [Accessibility] Enforces that no distracting elements are used | | :wrench: | | :accessibility: |
58
58
  | [`no-inline-styles`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-inline-styles.md) | Disallows the use of inline styles in HTML templates | | | | |
59
59
  | [`no-interpolation-in-attributes`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-interpolation-in-attributes.md) | Ensures that property-binding is used instead of interpolation in attributes. | | | | |
60
- | [`no-negated-async`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-negated-async.md) | Ensures that async pipe results are not negated | :white_check_mark: | | :bulb: | |
60
+ | [`no-negated-async`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-negated-async.md) | Ensures that async pipe results, as well as values used with the async pipe, are not negated | :white_check_mark: | | :bulb: | |
61
61
  | [`no-positive-tabindex`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/no-positive-tabindex.md) | Ensures that the `tabindex` attribute is not positive | | | :bulb: | |
62
62
  | [`prefer-ngsrc`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/prefer-ngsrc.md) | Ensures ngSrc is used instead of src for img elements | | | | |
63
63
  | [`role-has-required-aria`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin-template/docs/rules/role-has-required-aria.md) | [Accessibility] Ensures elements with ARIA roles have all required properties for that role. | | | :bulb: | :accessibility: |
@@ -152,10 +152,14 @@ function byOrder(order, alphabetical) {
152
152
  var _a, _b, _c, _d;
153
153
  const orderComparison = getOrderIndex(one, order) - getOrderIndex(other, order);
154
154
  if (alphabetical && orderComparison === 0) {
155
- return ((_b = (_a = one.keySpan) === null || _a === void 0 ? void 0 : _a.details) !== null && _b !== void 0 ? _b : one.name) >
156
- ((_d = (_c = other.keySpan) === null || _c === void 0 ? void 0 : _c.details) !== null && _d !== void 0 ? _d : other.name)
157
- ? 1
158
- : -1;
155
+ const oneName = (_b = (_a = one.keySpan) === null || _a === void 0 ? void 0 : _a.details) !== null && _b !== void 0 ? _b : one.name;
156
+ const oneNormalised = oneName.replace(/^i18n-/, '');
157
+ const otherName = (_d = (_c = other.keySpan) === null || _c === void 0 ? void 0 : _c.details) !== null && _d !== void 0 ? _d : other.name;
158
+ const otherNormalised = otherName.replace(/^i18n-/, '');
159
+ if (oneNormalised === otherNormalised) {
160
+ return /^i18n-/.test(oneName) ? 1 : -1;
161
+ }
162
+ return oneNormalised > otherNormalised ? 1 : -1;
159
163
  }
160
164
  return orderComparison;
161
165
  };
@@ -185,6 +189,7 @@ function isImplicitTemplate(node) {
185
189
  return isTmplAstTemplate(node) && node.tagName !== 'ng-template';
186
190
  }
187
191
  function extractTemplateAttrs(node) {
192
+ var _a, _b, _c, _d, _e, _f;
188
193
  if (isTmplAstTemplate(node)) {
189
194
  return node.templateAttrs.map(toStructuralDirectiveOrderType).concat(node.variables.map((x) => {
190
195
  return Object.assign(Object.assign({}, toAttributeBindingOrderType(x)), {
@@ -202,17 +207,25 @@ function extractTemplateAttrs(node) {
202
207
  * will parsed as two attributes (`ngFor` and `ngForOf`)
203
208
  */
204
209
  const attrs = node.parent.templateAttrs.map(toStructuralDirectiveOrderType);
205
- // Pick up on any subsequent `let` bindings, e.g. `index as i`
206
- let sourceEnd = attrs[attrs.length - 1].sourceSpan.end;
207
- node.parent.variables.forEach((v) => {
208
- if (v.sourceSpan.start.offset <= sourceEnd.offset &&
209
- sourceEnd.offset < v.sourceSpan.end.offset) {
210
- sourceEnd = v.sourceSpan.end;
210
+ let keyEnd = (_a = attrs[0].keySpan) === null || _a === void 0 ? void 0 : _a.end;
211
+ if (((_b = keyEnd === null || keyEnd === void 0 ? void 0 : keyEnd.getContext(0, 0)) === null || _b === void 0 ? void 0 : _b.after) === '=') {
212
+ keyEnd = keyEnd.moveBy(1);
213
+ const apos = (_c = keyEnd.getContext(0, 0)) === null || _c === void 0 ? void 0 : _c.after;
214
+ if (apos === "'" || apos === '"') {
215
+ do {
216
+ keyEnd = keyEnd.moveBy(1);
217
+ } while (((_d = keyEnd.getContext(0, 0)) === null || _d === void 0 ? void 0 : _d.after) !== apos);
218
+ }
219
+ else {
220
+ while (!/[\s>]/.test((_f = (_e = keyEnd.getContext(0, 0)) === null || _e === void 0 ? void 0 : _e.after) !== null && _f !== void 0 ? _f : '')) {
221
+ keyEnd = keyEnd.moveBy(1);
222
+ }
211
223
  }
212
- });
213
- return [
214
- Object.assign(Object.assign({}, attrs[0]), { sourceSpan: new bundled_angular_compiler_1.ParseSourceSpan(attrs[0].sourceSpan.start, sourceEnd) }),
215
- ];
224
+ return [
225
+ Object.assign(Object.assign({}, attrs[0]), { sourceSpan: new bundled_angular_compiler_1.ParseSourceSpan(attrs[0].sourceSpan.start, keyEnd) }),
226
+ ];
227
+ }
228
+ return [attrs[0]];
216
229
  }
217
230
  function normalizeInputsOutputs(inputs, outputs) {
218
231
  const extractedInputs = inputs
@@ -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
  exports.RULE_NAME = 'no-negated-async';
@@ -9,16 +10,18 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
9
10
  meta: {
10
11
  type: 'suggestion',
11
12
  docs: {
12
- description: 'Ensures that async pipe results are not negated',
13
+ description: 'Ensures that async pipe results, as well as values used with the async pipe, are not negated',
13
14
  recommended: 'recommended',
14
15
  },
15
16
  hasSuggestions: true,
16
17
  schema: [],
17
18
  messages: {
18
19
  noNegatedAsync: 'Async pipe results should not be negated. Use `(observable | async) === false`, `(observable | async) === null`, or `(observable | async) === undefined` to check its value instead',
20
+ noNegatedValueForAsync: 'Values used with the async pipe should not be negated.',
19
21
  suggestFalseComparison: 'Compare with `false`',
20
22
  suggestNullComparison: 'Compare with `null`',
21
23
  suggestUndefinedComparison: 'Compare with `undefined`',
24
+ suggestUsingNonNegatedValue: 'Use non-negated value',
22
25
  },
23
26
  },
24
27
  defaultOptions: [],
@@ -26,6 +29,25 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
26
29
  (0, utils_1.ensureTemplateParser)(context);
27
30
  const sourceCode = context.getSourceCode();
28
31
  return {
32
+ 'BindingPipe[name="async"]'(bindingPipe) {
33
+ if (bindingPipe.exp instanceof bundled_angular_compiler_1.PrefixNot) {
34
+ const sourceSpanStart = bindingPipe.sourceSpan.start;
35
+ const sourceSpanEnd = bindingPipe.sourceSpan.end;
36
+ context.report({
37
+ messageId: 'noNegatedValueForAsync',
38
+ loc: {
39
+ start: sourceCode.getLocFromIndex(sourceSpanStart),
40
+ end: sourceCode.getLocFromIndex(sourceSpanEnd),
41
+ },
42
+ suggest: [
43
+ {
44
+ messageId: 'suggestUsingNonNegatedValue',
45
+ fix: (fixer) => fixer.removeRange([sourceSpanStart, sourceSpanStart + 1]),
46
+ },
47
+ ],
48
+ });
49
+ }
50
+ },
29
51
  ':not(PrefixNot) > PrefixNot > BindingPipe[name="async"]'({ parent: { sourceSpan: { end, start }, }, }) {
30
52
  context.report({
31
53
  messageId: 'noNegatedAsync',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-eslint/eslint-plugin-template",
3
- "version": "17.0.2-alpha.0",
3
+ "version": "17.0.2-alpha.2",
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": "17.0.2-alpha.0",
21
- "@angular-eslint/utils": "17.0.2-alpha.0",
20
+ "@angular-eslint/bundled-angular-compiler": "17.0.2-alpha.2",
21
+ "@angular-eslint/utils": "17.0.2-alpha.2",
22
22
  "@typescript-eslint/type-utils": "6.10.0",
23
23
  "@typescript-eslint/utils": "6.10.0",
24
24
  "aria-query": "5.3.0",