eslint 7.3.1 → 7.7.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.
Files changed (73) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +28 -16
  3. package/lib/cli-engine/config-array-factory.js +1 -33
  4. package/lib/cli-engine/formatters/checkstyle.js +2 -2
  5. package/lib/linter/code-path-analysis/code-path-analyzer.js +38 -0
  6. package/lib/linter/code-path-analysis/code-path-segment.js +0 -1
  7. package/lib/linter/code-path-analysis/code-path-state.js +59 -0
  8. package/lib/linter/code-path-analysis/debug-helpers.js +26 -19
  9. package/lib/rule-tester/rule-tester.js +10 -0
  10. package/lib/rules/accessor-pairs.js +1 -14
  11. package/lib/rules/array-callback-return.js +26 -17
  12. package/lib/rules/arrow-body-style.js +43 -8
  13. package/lib/rules/arrow-parens.js +91 -108
  14. package/lib/rules/camelcase.js +47 -0
  15. package/lib/rules/comma-dangle.js +1 -2
  16. package/lib/rules/consistent-return.js +1 -12
  17. package/lib/rules/constructor-super.js +1 -0
  18. package/lib/rules/dot-location.js +20 -14
  19. package/lib/rules/dot-notation.js +36 -33
  20. package/lib/rules/func-call-spacing.js +42 -6
  21. package/lib/rules/func-name-matching.js +1 -4
  22. package/lib/rules/global-require.js +2 -1
  23. package/lib/rules/id-blacklist.js +14 -11
  24. package/lib/rules/id-denylist.js +230 -0
  25. package/lib/rules/indent.js +23 -3
  26. package/lib/rules/index.js +1 -0
  27. package/lib/rules/keyword-spacing.js +2 -2
  28. package/lib/rules/max-len.js +13 -2
  29. package/lib/rules/new-cap.js +10 -14
  30. package/lib/rules/newline-per-chained-call.js +15 -5
  31. package/lib/rules/no-alert.js +10 -3
  32. package/lib/rules/no-duplicate-case.js +23 -4
  33. package/lib/rules/no-eval.js +8 -38
  34. package/lib/rules/no-extend-native.js +37 -40
  35. package/lib/rules/no-extra-bind.js +57 -17
  36. package/lib/rules/no-extra-boolean-cast.js +7 -0
  37. package/lib/rules/no-extra-parens.js +48 -10
  38. package/lib/rules/no-implicit-coercion.js +11 -6
  39. package/lib/rules/no-implied-eval.js +7 -28
  40. package/lib/rules/no-import-assign.js +33 -32
  41. package/lib/rules/no-irregular-whitespace.js +22 -12
  42. package/lib/rules/no-magic-numbers.js +4 -8
  43. package/lib/rules/no-obj-calls.js +7 -4
  44. package/lib/rules/no-prototype-builtins.js +13 -3
  45. package/lib/rules/no-self-assign.js +3 -53
  46. package/lib/rules/no-setter-return.js +5 -8
  47. package/lib/rules/no-underscore-dangle.js +66 -21
  48. package/lib/rules/no-unexpected-multiline.js +2 -2
  49. package/lib/rules/no-unneeded-ternary.js +0 -2
  50. package/lib/rules/no-unused-expressions.js +55 -23
  51. package/lib/rules/no-useless-call.js +10 -7
  52. package/lib/rules/no-whitespace-before-property.js +16 -4
  53. package/lib/rules/object-curly-newline.js +4 -4
  54. package/lib/rules/operator-assignment.js +3 -42
  55. package/lib/rules/padding-line-between-statements.js +2 -2
  56. package/lib/rules/prefer-arrow-callback.js +90 -25
  57. package/lib/rules/prefer-exponentiation-operator.js +1 -1
  58. package/lib/rules/prefer-numeric-literals.js +4 -13
  59. package/lib/rules/prefer-promise-reject-errors.js +1 -3
  60. package/lib/rules/prefer-regex-literals.js +68 -13
  61. package/lib/rules/prefer-spread.js +2 -6
  62. package/lib/rules/radix.js +5 -2
  63. package/lib/rules/sort-imports.js +28 -0
  64. package/lib/rules/use-isnan.js +1 -1
  65. package/lib/rules/utils/ast-utils.js +317 -153
  66. package/lib/rules/wrap-iife.js +9 -2
  67. package/lib/rules/yoda.js +2 -55
  68. package/messages/extend-config-missing.txt +1 -1
  69. package/messages/no-config-found.txt +1 -1
  70. package/messages/plugin-conflict.txt +1 -1
  71. package/messages/plugin-missing.txt +1 -1
  72. package/messages/whitespace-found.txt +1 -1
  73. package/package.json +6 -7
@@ -143,6 +143,23 @@ function isInLoop(node) {
143
143
  return false;
144
144
  }
145
145
 
146
+ /**
147
+ * Determines whether the given node is a `null` literal.
148
+ * @param {ASTNode} node The node to check
149
+ * @returns {boolean} `true` if the node is a `null` literal
150
+ */
151
+ function isNullLiteral(node) {
152
+
153
+ /*
154
+ * Checking `node.value === null` does not guarantee that a literal is a null literal.
155
+ * When parsing values that cannot be represented in the current environment (e.g. unicode
156
+ * regexes in Node 4), `node.value` is set to `null` because it wouldn't be possible to
157
+ * set `node.value` to a unicode regex. To make sure a literal is actually `null`, check
158
+ * `node.regex` instead. Also see: https://github.com/eslint/eslint/issues/8020
159
+ */
160
+ return node.type === "Literal" && node.value === null && !node.regex && !node.bigint;
161
+ }
162
+
146
163
  /**
147
164
  * Checks whether or not a node is `null` or `undefined`.
148
165
  * @param {ASTNode} node A node to check.
@@ -151,7 +168,7 @@ function isInLoop(node) {
151
168
  */
152
169
  function isNullOrUndefined(node) {
153
170
  return (
154
- module.exports.isNullLiteral(node) ||
171
+ isNullLiteral(node) ||
155
172
  (node.type === "Identifier" && node.name === "undefined") ||
156
173
  (node.type === "UnaryExpression" && node.operator === "void")
157
174
  );
@@ -166,20 +183,270 @@ function isCallee(node) {
166
183
  return node.parent.type === "CallExpression" && node.parent.callee === node;
167
184
  }
168
185
 
186
+ /**
187
+ * Returns the result of the string conversion applied to the evaluated value of the given expression node,
188
+ * if it can be determined statically.
189
+ *
190
+ * This function returns a `string` value for all `Literal` nodes and simple `TemplateLiteral` nodes only.
191
+ * In all other cases, this function returns `null`.
192
+ * @param {ASTNode} node Expression node.
193
+ * @returns {string|null} String value if it can be determined. Otherwise, `null`.
194
+ */
195
+ function getStaticStringValue(node) {
196
+ switch (node.type) {
197
+ case "Literal":
198
+ if (node.value === null) {
199
+ if (isNullLiteral(node)) {
200
+ return String(node.value); // "null"
201
+ }
202
+ if (node.regex) {
203
+ return `/${node.regex.pattern}/${node.regex.flags}`;
204
+ }
205
+ if (node.bigint) {
206
+ return node.bigint;
207
+ }
208
+
209
+ // Otherwise, this is an unknown literal. The function will return null.
210
+
211
+ } else {
212
+ return String(node.value);
213
+ }
214
+ break;
215
+ case "TemplateLiteral":
216
+ if (node.expressions.length === 0 && node.quasis.length === 1) {
217
+ return node.quasis[0].value.cooked;
218
+ }
219
+ break;
220
+
221
+ // no default
222
+ }
223
+
224
+ return null;
225
+ }
226
+
227
+ /**
228
+ * Gets the property name of a given node.
229
+ * The node can be a MemberExpression, a Property, or a MethodDefinition.
230
+ *
231
+ * If the name is dynamic, this returns `null`.
232
+ *
233
+ * For examples:
234
+ *
235
+ * a.b // => "b"
236
+ * a["b"] // => "b"
237
+ * a['b'] // => "b"
238
+ * a[`b`] // => "b"
239
+ * a[100] // => "100"
240
+ * a[b] // => null
241
+ * a["a" + "b"] // => null
242
+ * a[tag`b`] // => null
243
+ * a[`${b}`] // => null
244
+ *
245
+ * let a = {b: 1} // => "b"
246
+ * let a = {["b"]: 1} // => "b"
247
+ * let a = {['b']: 1} // => "b"
248
+ * let a = {[`b`]: 1} // => "b"
249
+ * let a = {[100]: 1} // => "100"
250
+ * let a = {[b]: 1} // => null
251
+ * let a = {["a" + "b"]: 1} // => null
252
+ * let a = {[tag`b`]: 1} // => null
253
+ * let a = {[`${b}`]: 1} // => null
254
+ * @param {ASTNode} node The node to get.
255
+ * @returns {string|null} The property name if static. Otherwise, null.
256
+ */
257
+ function getStaticPropertyName(node) {
258
+ let prop;
259
+
260
+ switch (node && node.type) {
261
+ case "ChainExpression":
262
+ return getStaticPropertyName(node.expression);
263
+
264
+ case "Property":
265
+ case "MethodDefinition":
266
+ prop = node.key;
267
+ break;
268
+
269
+ case "MemberExpression":
270
+ prop = node.property;
271
+ break;
272
+
273
+ // no default
274
+ }
275
+
276
+ if (prop) {
277
+ if (prop.type === "Identifier" && !node.computed) {
278
+ return prop.name;
279
+ }
280
+
281
+ return getStaticStringValue(prop);
282
+ }
283
+
284
+ return null;
285
+ }
286
+
287
+ /**
288
+ * Retrieve `ChainExpression#expression` value if the given node a `ChainExpression` node. Otherwise, pass through it.
289
+ * @param {ASTNode} node The node to address.
290
+ * @returns {ASTNode} The `ChainExpression#expression` value if the node is a `ChainExpression` node. Otherwise, the node.
291
+ */
292
+ function skipChainExpression(node) {
293
+ return node && node.type === "ChainExpression" ? node.expression : node;
294
+ }
295
+
296
+ /**
297
+ * Check if the `actual` is an expected value.
298
+ * @param {string} actual The string value to check.
299
+ * @param {string | RegExp} expected The expected string value or pattern.
300
+ * @returns {boolean} `true` if the `actual` is an expected value.
301
+ */
302
+ function checkText(actual, expected) {
303
+ return typeof expected === "string"
304
+ ? actual === expected
305
+ : expected.test(actual);
306
+ }
307
+
308
+ /**
309
+ * Check if a given node is an Identifier node with a given name.
310
+ * @param {ASTNode} node The node to check.
311
+ * @param {string | RegExp} name The expected name or the expected pattern of the object name.
312
+ * @returns {boolean} `true` if the node is an Identifier node with the name.
313
+ */
314
+ function isSpecificId(node, name) {
315
+ return node.type === "Identifier" && checkText(node.name, name);
316
+ }
317
+
318
+ /**
319
+ * Check if a given node is member access with a given object name and property name pair.
320
+ * This is regardless of optional or not.
321
+ * @param {ASTNode} node The node to check.
322
+ * @param {string | RegExp | null} objectName The expected name or the expected pattern of the object name. If this is nullish, this method doesn't check object.
323
+ * @param {string | RegExp | null} propertyName The expected name or the expected pattern of the property name. If this is nullish, this method doesn't check property.
324
+ * @returns {boolean} `true` if the node is member access with the object name and property name pair.
325
+ * The node is a `MemberExpression` or `ChainExpression`.
326
+ */
327
+ function isSpecificMemberAccess(node, objectName, propertyName) {
328
+ const checkNode = skipChainExpression(node);
329
+
330
+ if (checkNode.type !== "MemberExpression") {
331
+ return false;
332
+ }
333
+
334
+ if (objectName && !isSpecificId(checkNode.object, objectName)) {
335
+ return false;
336
+ }
337
+
338
+ if (propertyName) {
339
+ const actualPropertyName = getStaticPropertyName(checkNode);
340
+
341
+ if (typeof actualPropertyName !== "string" || !checkText(actualPropertyName, propertyName)) {
342
+ return false;
343
+ }
344
+ }
345
+
346
+ return true;
347
+ }
348
+
349
+ /**
350
+ * Check if two literal nodes are the same value.
351
+ * @param {ASTNode} left The Literal node to compare.
352
+ * @param {ASTNode} right The other Literal node to compare.
353
+ * @returns {boolean} `true` if the two literal nodes are the same value.
354
+ */
355
+ function equalLiteralValue(left, right) {
356
+
357
+ // RegExp literal.
358
+ if (left.regex || right.regex) {
359
+ return Boolean(
360
+ left.regex &&
361
+ right.regex &&
362
+ left.regex.pattern === right.regex.pattern &&
363
+ left.regex.flags === right.regex.flags
364
+ );
365
+ }
366
+
367
+ // BigInt literal.
368
+ if (left.bigint || right.bigint) {
369
+ return left.bigint === right.bigint;
370
+ }
371
+
372
+ return left.value === right.value;
373
+ }
374
+
375
+ /**
376
+ * Check if two expressions reference the same value. For example:
377
+ * a = a
378
+ * a.b = a.b
379
+ * a[0] = a[0]
380
+ * a['b'] = a['b']
381
+ * @param {ASTNode} left The left side of the comparison.
382
+ * @param {ASTNode} right The right side of the comparison.
383
+ * @param {boolean} [disableStaticComputedKey] Don't address `a.b` and `a["b"]` are the same if `true`. For backward compatibility.
384
+ * @returns {boolean} `true` if both sides match and reference the same value.
385
+ */
386
+ function isSameReference(left, right, disableStaticComputedKey = false) {
387
+ if (left.type !== right.type) {
388
+
389
+ // Handle `a.b` and `a?.b` are samely.
390
+ if (left.type === "ChainExpression") {
391
+ return isSameReference(left.expression, right, disableStaticComputedKey);
392
+ }
393
+ if (right.type === "ChainExpression") {
394
+ return isSameReference(left, right.expression, disableStaticComputedKey);
395
+ }
396
+
397
+ return false;
398
+ }
399
+
400
+ switch (left.type) {
401
+ case "Super":
402
+ case "ThisExpression":
403
+ return true;
404
+
405
+ case "Identifier":
406
+ return left.name === right.name;
407
+ case "Literal":
408
+ return equalLiteralValue(left, right);
409
+
410
+ case "ChainExpression":
411
+ return isSameReference(left.expression, right.expression, disableStaticComputedKey);
412
+
413
+ case "MemberExpression": {
414
+ if (!disableStaticComputedKey) {
415
+ const nameA = getStaticPropertyName(left);
416
+
417
+ // x.y = x["y"]
418
+ if (nameA !== null) {
419
+ return (
420
+ isSameReference(left.object, right.object, disableStaticComputedKey) &&
421
+ nameA === getStaticPropertyName(right)
422
+ );
423
+ }
424
+ }
425
+
426
+ /*
427
+ * x[0] = x[0]
428
+ * x[y] = x[y]
429
+ * x.y = x.y
430
+ */
431
+ return (
432
+ left.computed === right.computed &&
433
+ isSameReference(left.object, right.object, disableStaticComputedKey) &&
434
+ isSameReference(left.property, right.property, disableStaticComputedKey)
435
+ );
436
+ }
437
+
438
+ default:
439
+ return false;
440
+ }
441
+ }
442
+
169
443
  /**
170
444
  * Checks whether or not a node is `Reflect.apply`.
171
445
  * @param {ASTNode} node A node to check.
172
446
  * @returns {boolean} Whether or not the node is a `Reflect.apply`.
173
447
  */
174
448
  function isReflectApply(node) {
175
- return (
176
- node.type === "MemberExpression" &&
177
- node.object.type === "Identifier" &&
178
- node.object.name === "Reflect" &&
179
- node.property.type === "Identifier" &&
180
- node.property.name === "apply" &&
181
- node.computed === false
182
- );
449
+ return isSpecificMemberAccess(node, "Reflect", "apply");
183
450
  }
184
451
 
185
452
  /**
@@ -188,14 +455,7 @@ function isReflectApply(node) {
188
455
  * @returns {boolean} Whether or not the node is a `Array.from`.
189
456
  */
190
457
  function isArrayFromMethod(node) {
191
- return (
192
- node.type === "MemberExpression" &&
193
- node.object.type === "Identifier" &&
194
- arrayOrTypedArrayPattern.test(node.object.name) &&
195
- node.property.type === "Identifier" &&
196
- node.property.name === "from" &&
197
- node.computed === false
198
- );
458
+ return isSpecificMemberAccess(node, arrayOrTypedArrayPattern, "from");
199
459
  }
200
460
 
201
461
  /**
@@ -204,17 +464,7 @@ function isArrayFromMethod(node) {
204
464
  * @returns {boolean} Whether or not the node is a method which has `thisArg`.
205
465
  */
206
466
  function isMethodWhichHasThisArg(node) {
207
- for (
208
- let currentNode = node;
209
- currentNode.type === "MemberExpression" && !currentNode.computed;
210
- currentNode = currentNode.property
211
- ) {
212
- if (currentNode.property.type === "Identifier") {
213
- return arrayMethodPattern.test(currentNode.property.name);
214
- }
215
- }
216
-
217
- return false;
467
+ return isSpecificMemberAccess(node, null, arrayMethodPattern);
218
468
  }
219
469
 
220
470
  /**
@@ -289,6 +539,15 @@ function isDotToken(token) {
289
539
  return token.value === "." && token.type === "Punctuator";
290
540
  }
291
541
 
542
+ /**
543
+ * Checks if the given token is a `?.` token or not.
544
+ * @param {Token} token The token to check.
545
+ * @returns {boolean} `true` if the token is a `?.` token.
546
+ */
547
+ function isQuestionDotToken(token) {
548
+ return token.value === "?." && token.type === "Punctuator";
549
+ }
550
+
292
551
  /**
293
552
  * Checks if the given token is a semicolon token or not.
294
553
  * @param {Token} token The token to check.
@@ -505,6 +764,7 @@ module.exports = {
505
764
  isCommaToken,
506
765
  isCommentToken,
507
766
  isDotToken,
767
+ isQuestionDotToken,
508
768
  isKeywordToken,
509
769
  isNotClosingBraceToken: negate(isClosingBraceToken),
510
770
  isNotClosingBracketToken: negate(isClosingBracketToken),
@@ -512,6 +772,7 @@ module.exports = {
512
772
  isNotColonToken: negate(isColonToken),
513
773
  isNotCommaToken: negate(isCommaToken),
514
774
  isNotDotToken: negate(isDotToken),
775
+ isNotQuestionDotToken: negate(isQuestionDotToken),
515
776
  isNotOpeningBraceToken: negate(isOpeningBraceToken),
516
777
  isNotOpeningBracketToken: negate(isOpeningBracketToken),
517
778
  isNotOpeningParenToken: negate(isOpeningParenToken),
@@ -669,6 +930,7 @@ module.exports = {
669
930
  */
670
931
  case "LogicalExpression":
671
932
  case "ConditionalExpression":
933
+ case "ChainExpression":
672
934
  currentNode = parent;
673
935
  break;
674
936
 
@@ -755,14 +1017,21 @@ module.exports = {
755
1017
  * (function foo() { ... }).apply(obj, []);
756
1018
  */
757
1019
  case "MemberExpression":
758
- return (
759
- parent.object !== currentNode ||
760
- parent.property.type !== "Identifier" ||
761
- !bindOrCallOrApplyPattern.test(parent.property.name) ||
762
- !isCallee(parent) ||
763
- parent.parent.arguments.length === 0 ||
764
- isNullOrUndefined(parent.parent.arguments[0])
765
- );
1020
+ if (
1021
+ parent.object === currentNode &&
1022
+ isSpecificMemberAccess(parent, null, bindOrCallOrApplyPattern)
1023
+ ) {
1024
+ const maybeCalleeNode = parent.parent.type === "ChainExpression"
1025
+ ? parent.parent
1026
+ : parent;
1027
+
1028
+ return !(
1029
+ isCallee(maybeCalleeNode) &&
1030
+ maybeCalleeNode.parent.arguments.length >= 1 &&
1031
+ !isNullOrUndefined(maybeCalleeNode.parent.arguments[0])
1032
+ );
1033
+ }
1034
+ return true;
766
1035
 
767
1036
  /*
768
1037
  * e.g.
@@ -884,6 +1153,7 @@ module.exports = {
884
1153
  return 17;
885
1154
 
886
1155
  case "CallExpression":
1156
+ case "ChainExpression":
887
1157
  case "ImportExpression":
888
1158
  return 18;
889
1159
 
@@ -913,104 +1183,6 @@ module.exports = {
913
1183
  return isFunction(node) && module.exports.isEmptyBlock(node.body);
914
1184
  },
915
1185
 
916
- /**
917
- * Returns the result of the string conversion applied to the evaluated value of the given expression node,
918
- * if it can be determined statically.
919
- *
920
- * This function returns a `string` value for all `Literal` nodes and simple `TemplateLiteral` nodes only.
921
- * In all other cases, this function returns `null`.
922
- * @param {ASTNode} node Expression node.
923
- * @returns {string|null} String value if it can be determined. Otherwise, `null`.
924
- */
925
- getStaticStringValue(node) {
926
- switch (node.type) {
927
- case "Literal":
928
- if (node.value === null) {
929
- if (module.exports.isNullLiteral(node)) {
930
- return String(node.value); // "null"
931
- }
932
- if (node.regex) {
933
- return `/${node.regex.pattern}/${node.regex.flags}`;
934
- }
935
- if (node.bigint) {
936
- return node.bigint;
937
- }
938
-
939
- // Otherwise, this is an unknown literal. The function will return null.
940
-
941
- } else {
942
- return String(node.value);
943
- }
944
- break;
945
- case "TemplateLiteral":
946
- if (node.expressions.length === 0 && node.quasis.length === 1) {
947
- return node.quasis[0].value.cooked;
948
- }
949
- break;
950
-
951
- // no default
952
- }
953
-
954
- return null;
955
- },
956
-
957
- /**
958
- * Gets the property name of a given node.
959
- * The node can be a MemberExpression, a Property, or a MethodDefinition.
960
- *
961
- * If the name is dynamic, this returns `null`.
962
- *
963
- * For examples:
964
- *
965
- * a.b // => "b"
966
- * a["b"] // => "b"
967
- * a['b'] // => "b"
968
- * a[`b`] // => "b"
969
- * a[100] // => "100"
970
- * a[b] // => null
971
- * a["a" + "b"] // => null
972
- * a[tag`b`] // => null
973
- * a[`${b}`] // => null
974
- *
975
- * let a = {b: 1} // => "b"
976
- * let a = {["b"]: 1} // => "b"
977
- * let a = {['b']: 1} // => "b"
978
- * let a = {[`b`]: 1} // => "b"
979
- * let a = {[100]: 1} // => "100"
980
- * let a = {[b]: 1} // => null
981
- * let a = {["a" + "b"]: 1} // => null
982
- * let a = {[tag`b`]: 1} // => null
983
- * let a = {[`${b}`]: 1} // => null
984
- * @param {ASTNode} node The node to get.
985
- * @returns {string|null} The property name if static. Otherwise, null.
986
- */
987
- getStaticPropertyName(node) {
988
- let prop;
989
-
990
- switch (node && node.type) {
991
- case "Property":
992
- case "MethodDefinition":
993
- prop = node.key;
994
- break;
995
-
996
- case "MemberExpression":
997
- prop = node.property;
998
- break;
999
-
1000
- // no default
1001
- }
1002
-
1003
- if (prop) {
1004
- if (prop.type === "Identifier" && !node.computed) {
1005
- return prop.name;
1006
- }
1007
-
1008
- return module.exports.getStaticStringValue(prop);
1009
- }
1010
-
1011
- return null;
1012
- },
1013
-
1014
1186
  /**
1015
1187
  * Get directives from directive prologue of a Program or Function node.
1016
1188
  * @param {ASTNode} node The node to check.
@@ -1164,7 +1336,7 @@ module.exports = {
1164
1336
  if (node.id) {
1165
1337
  tokens.push(`'${node.id.name}'`);
1166
1338
  } else {
1167
- const name = module.exports.getStaticPropertyName(parent);
1339
+ const name = getStaticPropertyName(parent);
1168
1340
 
1169
1341
  if (name !== null) {
1170
1342
  tokens.push(`'${name}'`);
@@ -1391,6 +1563,7 @@ module.exports = {
1391
1563
  case "TaggedTemplateExpression":
1392
1564
  case "YieldExpression":
1393
1565
  case "AwaitExpression":
1566
+ case "ChainExpression":
1394
1567
  return true; // possibly an error object.
1395
1568
 
1396
1569
  case "AssignmentExpression":
@@ -1413,23 +1586,6 @@ module.exports = {
1413
1586
  }
1414
1587
  },
1415
1588
 
1416
- /**
1417
- * Determines whether the given node is a `null` literal.
1418
- * @param {ASTNode} node The node to check
1419
- * @returns {boolean} `true` if the node is a `null` literal
1420
- */
1421
- isNullLiteral(node) {
1422
-
1423
- /*
1424
- * Checking `node.value === null` does not guarantee that a literal is a null literal.
1425
- * When parsing values that cannot be represented in the current environment (e.g. unicode
1426
- * regexes in Node 4), `node.value` is set to `null` because it wouldn't be possible to
1427
- * set `node.value` to a unicode regex. To make sure a literal is actually `null`, check
1428
- * `node.regex` instead. Also see: https://github.com/eslint/eslint/issues/8020
1429
- */
1430
- return node.type === "Literal" && node.value === null && !node.regex && !node.bigint;
1431
- },
1432
-
1433
1589
  /**
1434
1590
  * Check if a given node is a numeric literal or not.
1435
1591
  * @param {ASTNode} node The node to check.
@@ -1590,5 +1746,13 @@ module.exports = {
1590
1746
 
1591
1747
  isLogicalExpression,
1592
1748
  isCoalesceExpression,
1593
- isMixedLogicalAndCoalesceExpressions
1749
+ isMixedLogicalAndCoalesceExpressions,
1750
+ isNullLiteral,
1751
+ getStaticStringValue,
1752
+ getStaticPropertyName,
1753
+ skipChainExpression,
1754
+ isSpecificId,
1755
+ isSpecificMemberAccess,
1756
+ equalLiteralValue,
1757
+ isSameReference
1594
1758
  };
@@ -23,7 +23,14 @@ const eslintUtils = require("eslint-utils");
23
23
  * @private
24
24
  */
25
25
  function isCalleeOfNewExpression(node) {
26
- return node.parent.type === "NewExpression" && node.parent.callee === node;
26
+ const maybeCallee = node.parent.type === "ChainExpression"
27
+ ? node.parent
28
+ : node;
29
+
30
+ return (
31
+ maybeCallee.parent.type === "NewExpression" &&
32
+ maybeCallee.parent.callee === maybeCallee
33
+ );
27
34
  }
28
35
 
29
36
  //------------------------------------------------------------------------------
@@ -98,7 +105,7 @@ module.exports = {
98
105
  * @returns {ASTNode} node that is the function expression of the given IIFE, or null if none exist
99
106
  */
100
107
  function getFunctionNodeFromIIFE(node) {
101
- const callee = node.callee;
108
+ const callee = astUtils.skipChainExpression(node.callee);
102
109
 
103
110
  if (callee.type === "FunctionExpression") {
104
111
  return callee;
package/lib/rules/yoda.js CHANGED
@@ -111,59 +111,6 @@ function getNormalizedLiteral(node) {
111
111
  return null;
112
112
  }
113
113
 
114
- /**
115
- * Checks whether two expressions reference the same value. For example:
116
- * a = a
117
- * a.b = a.b
118
- * a[0] = a[0]
119
- * a['b'] = a['b']
120
- * @param {ASTNode} a Left side of the comparison.
121
- * @param {ASTNode} b Right side of the comparison.
122
- * @returns {boolean} True if both sides match and reference the same value.
123
- */
124
- function same(a, b) {
125
- if (a.type !== b.type) {
126
- return false;
127
- }
128
-
129
- switch (a.type) {
130
- case "Identifier":
131
- return a.name === b.name;
132
-
133
- case "Literal":
134
- return a.value === b.value;
135
-
136
- case "MemberExpression": {
137
- const nameA = astUtils.getStaticPropertyName(a);
138
-
139
- // x.y = x["y"]
140
- if (nameA !== null) {
141
- return (
142
- same(a.object, b.object) &&
143
- nameA === astUtils.getStaticPropertyName(b)
144
- );
145
- }
146
-
147
- /*
148
- * x[0] = x[0]
149
- * x[y] = x[y]
150
- * x.y = x.y
151
- */
152
- return (
153
- a.computed === b.computed &&
154
- same(a.object, b.object) &&
155
- same(a.property, b.property)
156
- );
157
- }
158
-
159
- case "ThisExpression":
160
- return true;
161
-
162
- default:
163
- return false;
164
- }
165
- }
166
-
167
114
  //------------------------------------------------------------------------------
168
115
  // Rule Definition
169
116
  //------------------------------------------------------------------------------
@@ -236,7 +183,7 @@ module.exports = {
236
183
  * @returns {boolean} Whether node is a "between" range test.
237
184
  */
238
185
  function isBetweenTest() {
239
- if (node.operator === "&&" && same(left.right, right.left)) {
186
+ if (node.operator === "&&" && astUtils.isSameReference(left.right, right.left)) {
240
187
  const leftLiteral = getNormalizedLiteral(left.left);
241
188
  const rightLiteral = getNormalizedLiteral(right.right);
242
189
 
@@ -260,7 +207,7 @@ module.exports = {
260
207
  * @returns {boolean} Whether node is an "outside" range test.
261
208
  */
262
209
  function isOutsideTest() {
263
- if (node.operator === "||" && same(left.left, right.right)) {
210
+ if (node.operator === "||" && astUtils.isSameReference(left.left, right.right)) {
264
211
  const leftLiteral = getNormalizedLiteral(left.right);
265
212
  const rightLiteral = getNormalizedLiteral(right.left);
266
213
 
@@ -2,4 +2,4 @@ ESLint couldn't find the config "<%- configName %>" to extend from. Please check
2
2
 
3
3
  The config "<%- configName %>" was referenced from the config file in "<%- importerName %>".
4
4
 
5
- If you still have problems, please stop by https://eslint.org/chat to chat with the team.
5
+ If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.
@@ -4,4 +4,4 @@ ESLint couldn't find a configuration file. To set up a configuration file for th
4
4
 
5
5
  ESLint looked for configuration files in <%= directoryPath %> and its ancestors. If it found none, it then looked in your home directory.
6
6
 
7
- If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://eslint.org/chat
7
+ If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://eslint.org/chat/help