@typescript-eslint/eslint-plugin 8.50.2-alpha.12 → 8.50.2-alpha.13

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.
@@ -57,8 +57,7 @@ exports.default = (0, util_1.createRule)({
57
57
  }
58
58
  const [lhsName, rhs] = getLHSRHS();
59
59
  const lhs = lhsName.typeAnnotation?.typeAnnotation;
60
- if (!rhs ||
61
- rhs.type !== utils_1.AST_NODE_TYPES.NewExpression ||
60
+ if (rhs?.type !== utils_1.AST_NODE_TYPES.NewExpression ||
62
61
  rhs.callee.type !== utils_1.AST_NODE_TYPES.Identifier) {
63
62
  return;
64
63
  }
@@ -25,8 +25,7 @@ exports.default = (0, util_1.createRule)({
25
25
  if (node.computed) {
26
26
  return;
27
27
  }
28
- if (node.value &&
29
- node.value.type === utils_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression) {
28
+ if (node.value?.type === utils_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression) {
30
29
  return;
31
30
  }
32
31
  return coreListener(node);
@@ -530,8 +530,7 @@ exports.default = (0, util_1.createRule)({
530
530
  });
531
531
  }
532
532
  function checkJSXAttribute(node) {
533
- if (node.value == null ||
534
- node.value.type !== utils_1.AST_NODE_TYPES.JSXExpressionContainer) {
533
+ if (node.value?.type !== utils_1.AST_NODE_TYPES.JSXExpressionContainer) {
535
534
  return;
536
535
  }
537
536
  const expressionContainer = services.esTreeNodeToTSNodeMap.get(node.value);
@@ -188,9 +188,8 @@ exports.default = (0, util_1.createRule)({
188
188
  findVariablesInScope(scope);
189
189
  // Node.js or ES modules has a special scope.
190
190
  if (scope.type === scope_manager_1.ScopeType.global &&
191
- scope.childScopes[0] &&
192
191
  // The special scope's block is the Program node.
193
- scope.block === scope.childScopes[0].block) {
192
+ scope.block === scope.childScopes[0]?.block) {
194
193
  findVariablesInScope(scope.childScopes[0]);
195
194
  }
196
195
  },
@@ -165,8 +165,7 @@ exports.default = (0, util_1.createRule)({
165
165
  }
166
166
  if (type.node.type === utils_1.AST_NODE_TYPES.TSTypeOperator &&
167
167
  ['keyof', 'readonly'].includes(type.node.operator) &&
168
- type.node.typeAnnotation &&
169
- type.node.typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTupleType) {
168
+ type.node.typeAnnotation?.type === utils_1.AST_NODE_TYPES.TSTupleType) {
170
169
  return true;
171
170
  }
172
171
  return false;
@@ -26,8 +26,7 @@ exports.default = (0, util_1.createRule)({
26
26
  }
27
27
  // Get tokens of the declaration header.
28
28
  const moduleType = context.sourceCode.getTokenBefore(node.id);
29
- if (moduleType &&
30
- moduleType.type === utils_1.AST_TOKEN_TYPES.Identifier &&
29
+ if (moduleType?.type === utils_1.AST_TOKEN_TYPES.Identifier &&
31
30
  moduleType.value === 'module') {
32
31
  context.report({
33
32
  node,
@@ -395,8 +395,7 @@ exports.default = (0, util_1.createRule)({
395
395
  else if (node.consequent.type === utils_1.AST_NODE_TYPES.ExpressionStatement) {
396
396
  assignmentExpression = node.consequent.expression;
397
397
  }
398
- if (!assignmentExpression ||
399
- assignmentExpression.type !== utils_1.AST_NODE_TYPES.AssignmentExpression ||
398
+ if (assignmentExpression?.type !== utils_1.AST_NODE_TYPES.AssignmentExpression ||
400
399
  !isMemberAccessLike(assignmentExpression.left)) {
401
400
  return;
402
401
  }
@@ -177,6 +177,40 @@ const analyzeOrChainOperand = (parserServices, operand, index, chain) => {
177
177
  return null;
178
178
  }
179
179
  };
180
+ const resolveOperandSubset = (previousOperand, lastChainOperand) => {
181
+ const isNameSubset = (0, compareNodes_1.compareNodes)(previousOperand.comparedName, lastChainOperand.comparedName) === compareNodes_1.NodeComparisonResult.Subset;
182
+ if (lastChainOperand.yoda !== gatherLogicalOperands_1.Yoda.Unknown) {
183
+ return {
184
+ comparedName: lastChainOperand.comparedName,
185
+ comparisonValue: lastChainOperand.comparisonValue,
186
+ isSubset: isNameSubset,
187
+ isYoda: lastChainOperand.yoda === gatherLogicalOperands_1.Yoda.Yes,
188
+ };
189
+ }
190
+ const isValueSubset = (0, compareNodes_1.compareNodes)(previousOperand.comparedName, lastChainOperand.comparisonValue) === compareNodes_1.NodeComparisonResult.Subset;
191
+ if (isNameSubset && !isValueSubset) {
192
+ return {
193
+ comparedName: lastChainOperand.comparedName,
194
+ comparisonValue: lastChainOperand.comparisonValue,
195
+ isSubset: true,
196
+ isYoda: false,
197
+ };
198
+ }
199
+ if (!isNameSubset && isValueSubset) {
200
+ return {
201
+ comparedName: lastChainOperand.comparisonValue,
202
+ comparisonValue: lastChainOperand.comparedName,
203
+ isSubset: true,
204
+ isYoda: true,
205
+ };
206
+ }
207
+ return {
208
+ comparedName: lastChainOperand.comparisonValue,
209
+ comparisonValue: lastChainOperand.comparisonValue,
210
+ isSubset: false,
211
+ isYoda: true,
212
+ };
213
+ };
180
214
  /**
181
215
  * Returns the range that needs to be reported from the chain.
182
216
  * @param chain The chain of logical expressions.
@@ -516,13 +550,18 @@ function analyzeChain(context, parserServices, options, node, operator, chain, l
516
550
  }
517
551
  const lastOperand = subChain.flat().at(-1);
518
552
  if (lastOperand && lastChainOperand) {
519
- const comparisonResult = (0, compareNodes_1.compareNodes)(lastOperand.comparedName, lastChainOperand.comparedName);
520
553
  const isValidLastChainOperand = operator === '&&'
521
554
  ? isValidAndLastChainOperand
522
555
  : isValidOrLastChainOperand;
523
- if (comparisonResult === compareNodes_1.NodeComparisonResult.Subset &&
524
- isValidLastChainOperand(lastChainOperand.comparisonValue, lastChainOperand.comparisonType, parserServices)) {
525
- lastChain = lastChainOperand;
556
+ const { comparedName, comparisonValue, isSubset, isYoda } = resolveOperandSubset(lastOperand, lastChainOperand);
557
+ if (isSubset &&
558
+ isValidLastChainOperand(comparisonValue, lastChainOperand.comparisonType, parserServices)) {
559
+ lastChain = {
560
+ ...lastChainOperand,
561
+ comparedName,
562
+ comparisonValue,
563
+ isYoda,
564
+ };
526
565
  }
527
566
  }
528
567
  // check the leftovers
@@ -1,6 +1,11 @@
1
1
  import type { ParserServicesWithTypeInformation, TSESTree } from '@typescript-eslint/utils';
2
2
  import type { SourceCode } from '@typescript-eslint/utils/ts-eslint';
3
3
  import type { PreferOptionalChainOptions } from './PreferOptionalChainOptions';
4
+ export declare const enum Yoda {
5
+ Yes = 0,
6
+ No = 1,
7
+ Unknown = 2
8
+ }
4
9
  export declare const enum OperandValidity {
5
10
  Valid = "Valid",
6
11
  Last = "Last",
@@ -41,7 +46,7 @@ export interface LastChainOperand {
41
46
  comparedName: TSESTree.Node;
42
47
  comparisonType: ComparisonType;
43
48
  comparisonValue: TSESTree.Node;
44
- isYoda: boolean;
49
+ yoda: Yoda;
45
50
  node: TSESTree.BinaryExpression;
46
51
  type: OperandValidity.Last;
47
52
  }
@@ -33,12 +33,18 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.ComparisonType = exports.NullishComparisonType = exports.OperandValidity = void 0;
36
+ exports.ComparisonType = exports.NullishComparisonType = exports.OperandValidity = exports.Yoda = void 0;
37
37
  exports.gatherLogicalOperands = gatherLogicalOperands;
38
38
  const utils_1 = require("@typescript-eslint/utils");
39
39
  const ts_api_utils_1 = require("ts-api-utils");
40
40
  const ts = __importStar(require("typescript"));
41
41
  const util_1 = require("../../util");
42
+ var Yoda;
43
+ (function (Yoda) {
44
+ Yoda[Yoda["Yes"] = 0] = "Yes";
45
+ Yoda[Yoda["No"] = 1] = "No";
46
+ Yoda[Yoda["Unknown"] = 2] = "Unknown";
47
+ })(Yoda || (exports.Yoda = Yoda = {}));
42
48
  var ComparisonValueType;
43
49
  (function (ComparisonValueType) {
44
50
  ComparisonValueType["Null"] = "Null";
@@ -224,7 +230,7 @@ function gatherLogicalOperands(node, parserServices, sourceCode, options) {
224
230
  // x !== something :(
225
231
  const binaryComparisonChain = getBinaryComparisonChain(operand);
226
232
  if (binaryComparisonChain) {
227
- const { comparedName, comparedValue, isYoda } = binaryComparisonChain;
233
+ const { comparedName, comparedValue, yoda } = binaryComparisonChain;
228
234
  switch (operand.operator) {
229
235
  case '==':
230
236
  case '===': {
@@ -235,9 +241,9 @@ function gatherLogicalOperands(node, parserServices, sourceCode, options) {
235
241
  comparedName,
236
242
  comparisonType,
237
243
  comparisonValue: comparedValue,
238
- isYoda,
239
244
  node: operand,
240
245
  type: OperandValidity.Last,
246
+ yoda,
241
247
  });
242
248
  continue;
243
249
  }
@@ -250,9 +256,9 @@ function gatherLogicalOperands(node, parserServices, sourceCode, options) {
250
256
  comparedName,
251
257
  comparisonType,
252
258
  comparisonValue: comparedValue,
253
- isYoda,
254
259
  node: operand,
255
260
  type: OperandValidity.Last,
261
+ yoda,
256
262
  });
257
263
  continue;
258
264
  }
@@ -362,26 +368,41 @@ function gatherLogicalOperands(node, parserServices, sourceCode, options) {
362
368
  }
363
369
  return null;
364
370
  }
371
+ function isMemberBasedExpression(node) {
372
+ if (node.type === utils_1.AST_NODE_TYPES.MemberExpression) {
373
+ return true;
374
+ }
375
+ if (node.type === utils_1.AST_NODE_TYPES.CallExpression &&
376
+ node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
377
+ return true;
378
+ }
379
+ return false;
380
+ }
365
381
  function getBinaryComparisonChain(node) {
366
382
  const { left, right } = node;
367
- let isYoda = false;
368
- const isLeftMemberExpression = left.type === utils_1.AST_NODE_TYPES.MemberExpression;
369
- const isRightMemberExpression = right.type === utils_1.AST_NODE_TYPES.MemberExpression;
383
+ const isLeftMemberExpression = isMemberBasedExpression(left);
384
+ const isRightMemberExpression = isMemberBasedExpression(right);
370
385
  if (isLeftMemberExpression && !isRightMemberExpression) {
371
386
  const [comparedName, comparedValue] = [left, right];
372
387
  return {
373
388
  comparedName,
374
389
  comparedValue,
375
- isYoda,
390
+ yoda: Yoda.No,
376
391
  };
377
392
  }
378
393
  if (!isLeftMemberExpression && isRightMemberExpression) {
379
394
  const [comparedName, comparedValue] = [right, left];
380
- isYoda = true;
381
395
  return {
382
396
  comparedName,
383
397
  comparedValue,
384
- isYoda,
398
+ yoda: Yoda.Yes,
399
+ };
400
+ }
401
+ if (isLeftMemberExpression && isRightMemberExpression) {
402
+ return {
403
+ comparedName: left,
404
+ comparedValue: right,
405
+ yoda: Yoda.Unknown,
385
406
  };
386
407
  }
387
408
  return null;
@@ -171,9 +171,7 @@ exports.default = (0, util_1.createRule)({
171
171
  : undefined;
172
172
  }
173
173
  function isThisParam(param) {
174
- return (param != null &&
175
- param.type === utils_1.AST_NODE_TYPES.Identifier &&
176
- param.name === 'this');
174
+ return param?.type === utils_1.AST_NODE_TYPES.Identifier && param.name === 'this';
177
175
  }
178
176
  function isThisVoidParam(param) {
179
177
  return (isThisParam(param) &&
@@ -306,7 +304,7 @@ exports.default = (0, util_1.createRule)({
306
304
  context.sourceCode.getText(b.typeAnnotation)));
307
305
  }
308
306
  function constraintsAreEqual(a, b) {
309
- return a === b || (a != null && b != null && a.type === b.type);
307
+ return a === b || (a != null && a.type === b?.type);
310
308
  }
311
309
  /* Returns the first index where `a` and `b` differ. */
312
310
  function getIndexOfFirstDifference(a, b, equal) {
@@ -356,8 +354,7 @@ exports.default = (0, util_1.createRule)({
356
354
  }
357
355
  function addOverload(signature, key, containingNode) {
358
356
  key ??= getOverloadKey(signature);
359
- if (currentScope &&
360
- (containingNode ?? signature).parent === currentScope.parent) {
357
+ if ((containingNode ?? signature).parent === currentScope?.parent) {
361
358
  const overloads = currentScope.overloads.get(key);
362
359
  if (overloads != null) {
363
360
  overloads.push(signature);
@@ -227,7 +227,7 @@ class ThisScope extends scope_manager_1.Visitor {
227
227
  // ```
228
228
  case utils_1.AST_NODE_TYPES.VariableDeclarator: {
229
229
  const value = firstDef.node.init;
230
- if (value == null || value.type !== utils_1.AST_NODE_TYPES.ThisExpression) {
230
+ if (value?.type !== utils_1.AST_NODE_TYPES.ThisExpression) {
231
231
  return null;
232
232
  }
233
233
  if (variable.references.some(ref => ref.isWrite() && ref.init !== true)) {
@@ -82,7 +82,7 @@ function isConstructorArgument(node) {
82
82
  * ```
83
83
  */
84
84
  function isPropertyOfObjectWithType(property) {
85
- if (!property || property.type !== utils_1.AST_NODE_TYPES.Property) {
85
+ if (property?.type !== utils_1.AST_NODE_TYPES.Property) {
86
86
  return false;
87
87
  }
88
88
  const objectExpr = property.parent;
package/dist/util/misc.js CHANGED
@@ -91,10 +91,7 @@ function arrayGroupByToMap(array, getKey) {
91
91
  }
92
92
  function arraysAreEqual(a, b, eq) {
93
93
  return (a === b ||
94
- (a != null &&
95
- b != null &&
96
- a.length === b.length &&
97
- a.every((x, idx) => eq(x, b[idx]))));
94
+ (a != null && a.length === b?.length && a.every((x, idx) => eq(x, b[idx]))));
98
95
  }
99
96
  /** Returns the first non-`undefined` result. */
100
97
  function findFirstResult(inputs, getResult) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typescript-eslint/eslint-plugin",
3
- "version": "8.50.2-alpha.12",
3
+ "version": "8.50.2-alpha.13",
4
4
  "description": "TypeScript plugin for ESLint",
5
5
  "files": [
6
6
  "dist",
@@ -59,10 +59,10 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "@eslint-community/regexpp": "^4.10.0",
62
- "@typescript-eslint/scope-manager": "8.50.2-alpha.12",
63
- "@typescript-eslint/type-utils": "8.50.2-alpha.12",
64
- "@typescript-eslint/utils": "8.50.2-alpha.12",
65
- "@typescript-eslint/visitor-keys": "8.50.2-alpha.12",
62
+ "@typescript-eslint/scope-manager": "8.50.2-alpha.13",
63
+ "@typescript-eslint/type-utils": "8.50.2-alpha.13",
64
+ "@typescript-eslint/utils": "8.50.2-alpha.13",
65
+ "@typescript-eslint/visitor-keys": "8.50.2-alpha.13",
66
66
  "ignore": "^7.0.0",
67
67
  "natural-compare": "^1.4.0",
68
68
  "ts-api-utils": "^2.2.0"
@@ -70,11 +70,10 @@
70
70
  "devDependencies": {
71
71
  "@types/mdast": "^4.0.3",
72
72
  "@types/natural-compare": "*",
73
- "@typescript-eslint/rule-schema-to-typescript-types": "8.50.2-alpha.12",
74
- "@typescript-eslint/rule-tester": "8.50.2-alpha.12",
73
+ "@typescript-eslint/rule-schema-to-typescript-types": "8.50.2-alpha.13",
74
+ "@typescript-eslint/rule-tester": "8.50.2-alpha.13",
75
75
  "@vitest/coverage-v8": "^3.1.3",
76
76
  "ajv": "^6.12.6",
77
- "cross-fetch": "*",
78
77
  "eslint": "*",
79
78
  "json-schema": "*",
80
79
  "markdown-table": "^3.0.3",
@@ -91,7 +90,7 @@
91
90
  "vitest": "^3.1.3"
92
91
  },
93
92
  "peerDependencies": {
94
- "@typescript-eslint/parser": "^8.50.2-alpha.12",
93
+ "@typescript-eslint/parser": "^8.50.2-alpha.13",
95
94
  "eslint": "^8.57.0 || ^9.0.0",
96
95
  "typescript": ">=4.8.4 <6.0.0"
97
96
  },