eslint 3.16.0 → 3.18.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 (59) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/conf/eslint-recommended.js +2 -0
  3. package/lib/ast-utils.js +3 -67
  4. package/lib/code-path-analysis/code-path-analyzer.js +2 -7
  5. package/lib/code-path-analysis/debug-helpers.js +17 -16
  6. package/lib/config/config-file.js +68 -38
  7. package/lib/eslint.js +5 -5
  8. package/lib/formatters/stylish.js +5 -4
  9. package/lib/ignored-paths.js +6 -0
  10. package/lib/internal-rules/internal-no-invalid-meta.js +2 -40
  11. package/lib/rules/array-callback-return.js +15 -5
  12. package/lib/rules/capitalized-comments.js +2 -1
  13. package/lib/rules/complexity.js +14 -8
  14. package/lib/rules/consistent-return.js +17 -10
  15. package/lib/rules/func-name-matching.js +18 -7
  16. package/lib/rules/func-names.js +20 -5
  17. package/lib/rules/keyword-spacing.js +19 -4
  18. package/lib/rules/line-comment-position.js +15 -5
  19. package/lib/rules/lines-around-comment.js +19 -0
  20. package/lib/rules/max-params.js +17 -4
  21. package/lib/rules/max-statements.js +11 -10
  22. package/lib/rules/no-compare-neg-zero.js +53 -0
  23. package/lib/rules/no-else-return.js +13 -1
  24. package/lib/rules/no-empty-function.js +9 -16
  25. package/lib/rules/no-extra-parens.js +64 -19
  26. package/lib/rules/no-extra-semi.js +13 -1
  27. package/lib/rules/no-global-assign.js +1 -1
  28. package/lib/rules/no-invalid-regexp.js +2 -1
  29. package/lib/rules/no-multiple-empty-lines.js +2 -4
  30. package/lib/rules/no-new-func.js +6 -8
  31. package/lib/rules/no-new.js +2 -6
  32. package/lib/rules/no-param-reassign.js +29 -6
  33. package/lib/rules/no-process-exit.js +2 -10
  34. package/lib/rules/no-restricted-properties.js +2 -0
  35. package/lib/rules/no-restricted-syntax.js +6 -22
  36. package/lib/rules/no-return-await.js +1 -1
  37. package/lib/rules/no-sync.js +8 -13
  38. package/lib/rules/no-unused-expressions.js +10 -1
  39. package/lib/rules/no-unused-vars.js +12 -12
  40. package/lib/rules/no-use-before-define.js +1 -1
  41. package/lib/rules/no-useless-escape.js +8 -2
  42. package/lib/rules/no-useless-return.js +13 -2
  43. package/lib/rules/nonblock-statement-body-position.js +114 -0
  44. package/lib/rules/object-shorthand.js +2 -1
  45. package/lib/rules/operator-assignment.js +1 -1
  46. package/lib/rules/padded-blocks.js +37 -28
  47. package/lib/rules/prefer-destructuring.js +1 -1
  48. package/lib/rules/semi.js +13 -1
  49. package/lib/rules/sort-vars.js +3 -5
  50. package/lib/rules/space-unary-ops.js +19 -1
  51. package/lib/rules/strict.js +8 -2
  52. package/lib/rules/yoda.js +2 -2
  53. package/lib/testers/rule-tester.js +44 -13
  54. package/lib/util/fix-tracker.js +121 -0
  55. package/lib/util/node-event-generator.js +274 -4
  56. package/lib/util/source-code-fixer.js +2 -2
  57. package/lib/util/source-code.js +99 -2
  58. package/lib/util/traverser.js +16 -25
  59. package/package.json +8 -8
@@ -67,6 +67,8 @@ module.exports = {
67
67
  const NESTED_BINARY = ALL_NODES && context.options[1] && context.options[1].nestedBinaryExpressions === false;
68
68
  const EXCEPT_RETURN_ASSIGN = ALL_NODES && context.options[1] && context.options[1].returnAssign === false;
69
69
  const IGNORE_JSX = ALL_NODES && context.options[1] && context.options[1].ignoreJSX;
70
+ const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" });
71
+ const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" });
70
72
 
71
73
  /**
72
74
  * Determines if this rule should be enforced for a node given the current configuration.
@@ -365,7 +367,7 @@ module.exports = {
365
367
  * @returns {void}
366
368
  * @private
367
369
  */
368
- function dryUnaryUpdate(node) {
370
+ function checkUnaryUpdate(node) {
369
371
  if (node.type === "UnaryExpression" && node.argument.type === "BinaryExpression" && node.argument.operator === "**") {
370
372
  return;
371
373
  }
@@ -381,7 +383,7 @@ module.exports = {
381
383
  * @returns {void}
382
384
  * @private
383
385
  */
384
- function dryCallNew(node) {
386
+ function checkCallNew(node) {
385
387
  if (hasExcessParens(node.callee) && precedence(node.callee) >= precedence(node) && !(
386
388
  node.type === "CallExpression" &&
387
389
  (node.callee.type === "FunctionExpression" ||
@@ -393,12 +395,12 @@ module.exports = {
393
395
  report(node.callee);
394
396
  }
395
397
  if (node.arguments.length === 1) {
396
- if (hasDoubleExcessParens(node.arguments[0]) && precedence(node.arguments[0]) >= precedence({ type: "AssignmentExpression" })) {
398
+ if (hasDoubleExcessParens(node.arguments[0]) && precedence(node.arguments[0]) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
397
399
  report(node.arguments[0]);
398
400
  }
399
401
  } else {
400
402
  [].forEach.call(node.arguments, arg => {
401
- if (hasExcessParens(arg) && precedence(arg) >= precedence({ type: "AssignmentExpression" })) {
403
+ if (hasExcessParens(arg) && precedence(arg) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
402
404
  report(arg);
403
405
  }
404
406
  });
@@ -411,7 +413,7 @@ module.exports = {
411
413
  * @returns {void}
412
414
  * @private
413
415
  */
414
- function dryBinaryLogical(node) {
416
+ function checkBinaryLogical(node) {
415
417
  const prec = precedence(node);
416
418
  const leftPrecedence = precedence(node.left);
417
419
  const rightPrecedence = precedence(node.right);
@@ -428,10 +430,46 @@ module.exports = {
428
430
  }
429
431
  }
430
432
 
433
+ /**
434
+ * Check the parentheses around the super class of the given class definition.
435
+ * @param {ASTNode} node The node of class declarations to check.
436
+ * @returns {void}
437
+ */
438
+ function checkClass(node) {
439
+ if (!node.superClass) {
440
+ return;
441
+ }
442
+
443
+ // If `node.superClass` is a LeftHandSideExpression, parentheses are extra.
444
+ // Otherwise, parentheses are needed.
445
+ const hasExtraParens = precedence(node.superClass) > PRECEDENCE_OF_UPDATE_EXPR
446
+ ? hasExcessParens(node.superClass)
447
+ : hasDoubleExcessParens(node.superClass);
448
+
449
+ if (hasExtraParens) {
450
+ report(node.superClass);
451
+ }
452
+ }
453
+
454
+ /**
455
+ * Check the parentheses around the argument of the given spread operator.
456
+ * @param {ASTNode} node The node of spread elements/properties to check.
457
+ * @returns {void}
458
+ */
459
+ function checkSpreadOperator(node) {
460
+ const hasExtraParens = precedence(node.argument) >= PRECEDENCE_OF_ASSIGNMENT_EXPR
461
+ ? hasExcessParens(node.argument)
462
+ : hasDoubleExcessParens(node.argument);
463
+
464
+ if (hasExtraParens) {
465
+ report(node.argument);
466
+ }
467
+ }
468
+
431
469
  return {
432
470
  ArrayExpression(node) {
433
471
  [].forEach.call(node.elements, e => {
434
- if (e && hasExcessParens(e) && precedence(e) >= precedence({ type: "AssignmentExpression" })) {
472
+ if (e && hasExcessParens(e) && precedence(e) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
435
473
  report(e);
436
474
  }
437
475
  });
@@ -443,7 +481,7 @@ module.exports = {
443
481
  }
444
482
 
445
483
  if (node.body.type !== "BlockStatement") {
446
- if (sourceCode.getFirstToken(node.body).value !== "{" && hasExcessParens(node.body) && precedence(node.body) >= precedence({ type: "AssignmentExpression" })) {
484
+ if (sourceCode.getFirstToken(node.body).value !== "{" && hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
447
485
  report(node.body);
448
486
  return;
449
487
  }
@@ -465,8 +503,8 @@ module.exports = {
465
503
  }
466
504
  },
467
505
 
468
- BinaryExpression: dryBinaryLogical,
469
- CallExpression: dryCallNew,
506
+ BinaryExpression: checkBinaryLogical,
507
+ CallExpression: checkCallNew,
470
508
 
471
509
  ConditionalExpression(node) {
472
510
  if (isReturnAssignException(node)) {
@@ -477,11 +515,11 @@ module.exports = {
477
515
  report(node.test);
478
516
  }
479
517
 
480
- if (hasExcessParens(node.consequent) && precedence(node.consequent) >= precedence({ type: "AssignmentExpression" })) {
518
+ if (hasExcessParens(node.consequent) && precedence(node.consequent) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
481
519
  report(node.consequent);
482
520
  }
483
521
 
484
- if (hasExcessParens(node.alternate) && precedence(node.alternate) >= precedence({ type: "AssignmentExpression" })) {
522
+ if (hasExcessParens(node.alternate) && precedence(node.alternate) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
485
523
  report(node.alternate);
486
524
  }
487
525
  },
@@ -546,7 +584,7 @@ module.exports = {
546
584
  }
547
585
  },
548
586
 
549
- LogicalExpression: dryBinaryLogical,
587
+ LogicalExpression: checkBinaryLogical,
550
588
 
551
589
  MemberExpression(node) {
552
590
  if (
@@ -576,13 +614,13 @@ module.exports = {
576
614
  }
577
615
  },
578
616
 
579
- NewExpression: dryCallNew,
617
+ NewExpression: checkCallNew,
580
618
 
581
619
  ObjectExpression(node) {
582
620
  [].forEach.call(node.properties, e => {
583
621
  const v = e.value;
584
622
 
585
- if (v && hasExcessParens(v) && precedence(v) >= precedence({ type: "AssignmentExpression" })) {
623
+ if (v && hasExcessParens(v) && precedence(v) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
586
624
  report(v);
587
625
  }
588
626
  });
@@ -632,13 +670,13 @@ module.exports = {
632
670
  }
633
671
  },
634
672
 
635
- UnaryExpression: dryUnaryUpdate,
636
- UpdateExpression: dryUnaryUpdate,
637
- AwaitExpression: dryUnaryUpdate,
673
+ UnaryExpression: checkUnaryUpdate,
674
+ UpdateExpression: checkUnaryUpdate,
675
+ AwaitExpression: checkUnaryUpdate,
638
676
 
639
677
  VariableDeclarator(node) {
640
678
  if (node.init && hasExcessParens(node.init) &&
641
- precedence(node.init) >= precedence({ type: "AssignmentExpression" }) &&
679
+ precedence(node.init) >= PRECEDENCE_OF_ASSIGNMENT_EXPR &&
642
680
 
643
681
  // RegExp literal is allowed to have parens (#1589)
644
682
  !(node.init.type === "Literal" && node.init.regex)) {
@@ -668,7 +706,14 @@ module.exports = {
668
706
  report(node.argument);
669
707
  }
670
708
  }
671
- }
709
+ },
710
+
711
+ ClassDeclaration: checkClass,
712
+ ClassExpression: checkClass,
713
+
714
+ SpreadElement: checkSpreadOperator,
715
+ SpreadProperty: checkSpreadOperator,
716
+ ExperimentalSpreadProperty: checkSpreadOperator
672
717
  };
673
718
 
674
719
  }
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const FixTracker = require("../util/fix-tracker");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -34,7 +40,13 @@ module.exports = {
34
40
  node: nodeOrToken,
35
41
  message: "Unnecessary semicolon.",
36
42
  fix(fixer) {
37
- return fixer.remove(nodeOrToken);
43
+
44
+ // Expand the replacement range to include the surrounding
45
+ // tokens to avoid conflicting with semi.
46
+ // https://github.com/eslint/eslint/issues/7928
47
+ return new FixTracker(fixer, context.getSourceCode())
48
+ .retainSurroundingTokens(nodeOrToken)
49
+ .remove(nodeOrToken);
38
50
  }
39
51
  });
40
52
  }
@@ -14,7 +14,7 @@ module.exports = {
14
14
  docs: {
15
15
  description: "disallow assignments to native objects or read-only global variables",
16
16
  category: "Best Practices",
17
- recommended: false
17
+ recommended: true
18
18
  },
19
19
 
20
20
  schema: [
@@ -74,7 +74,8 @@ module.exports = {
74
74
  } catch (e) {
75
75
  context.report({
76
76
  node,
77
- message: `${e.message}.`
77
+ message: "{{message}}.",
78
+ data: e
78
79
  });
79
80
  }
80
81
 
@@ -5,8 +5,6 @@
5
5
  */
6
6
  "use strict";
7
7
 
8
- const astUtils = require("../ast-utils");
9
-
10
8
  //------------------------------------------------------------------------------
11
9
  // Rule Definition
12
10
  //------------------------------------------------------------------------------
@@ -114,8 +112,8 @@ module.exports = {
114
112
  data: { max: maxAllowed, pluralizedLines: maxAllowed === 1 ? "line" : "lines" },
115
113
  fix(fixer) {
116
114
  return fixer.removeRange([
117
- astUtils.getRangeIndexFromLocation(sourceCode, { line: lastLineNumber + 1, column: 0 }),
118
- astUtils.getRangeIndexFromLocation(sourceCode, { line: lineNumber - maxAllowed, column: 0 })
115
+ sourceCode.getIndexFromLoc({ line: lastLineNumber + 1, column: 0 }),
116
+ sourceCode.getIndexFromLoc({ line: lineNumber - maxAllowed, column: 0 })
119
117
  ]);
120
118
  }
121
119
  });
@@ -27,20 +27,18 @@ module.exports = {
27
27
  //--------------------------------------------------------------------------
28
28
 
29
29
  /**
30
- * Checks if the callee is the Function constructor, and if so, reports an issue.
31
- * @param {ASTNode} node The node to check and report on
30
+ * Reports a node.
31
+ * @param {ASTNode} node The node to report
32
32
  * @returns {void}
33
33
  * @private
34
34
  */
35
- function validateCallee(node) {
36
- if (node.callee.name === "Function") {
37
- context.report({ node, message: "The Function constructor is eval." });
38
- }
35
+ function report(node) {
36
+ context.report({ node, message: "The Function constructor is eval." });
39
37
  }
40
38
 
41
39
  return {
42
- NewExpression: validateCallee,
43
- CallExpression: validateCallee
40
+ "NewExpression[callee.name = 'Function']": report,
41
+ "CallExpression[callee.name = 'Function']": report
44
42
  };
45
43
 
46
44
  }
@@ -24,12 +24,8 @@ module.exports = {
24
24
  create(context) {
25
25
 
26
26
  return {
27
-
28
- ExpressionStatement(node) {
29
-
30
- if (node.expression.type === "NewExpression") {
31
- context.report({ node, message: "Do not use 'new' for side effects." });
32
- }
27
+ "ExpressionStatement > NewExpression"(node) {
28
+ context.report({ node: node.parent, message: "Do not use 'new' for side effects." });
33
29
  }
34
30
  };
35
31
 
@@ -20,17 +20,40 @@ module.exports = {
20
20
 
21
21
  schema: [
22
22
  {
23
- type: "object",
24
- properties: {
25
- props: { type: "boolean" }
26
- },
27
- additionalProperties: false
23
+ oneOf: [
24
+ {
25
+ type: "object",
26
+ properties: {
27
+ props: {
28
+ enum: [false]
29
+ }
30
+ },
31
+ additionalProperties: false
32
+ },
33
+ {
34
+ type: "object",
35
+ properties: {
36
+ props: {
37
+ enum: [true]
38
+ },
39
+ ignorePropertyModificationsFor: {
40
+ type: "array",
41
+ items: {
42
+ type: "string"
43
+ },
44
+ uniqueItems: true
45
+ }
46
+ },
47
+ additionalProperties: false
48
+ }
49
+ ]
28
50
  }
29
51
  ]
30
52
  },
31
53
 
32
54
  create(context) {
33
55
  const props = context.options[0] && Boolean(context.options[0].props);
56
+ const ignoredPropertyAssignmentsFor = context.options[0] && context.options[0].ignorePropertyModificationsFor || [];
34
57
 
35
58
  /**
36
59
  * Checks whether or not the reference modifies properties of its variable.
@@ -103,7 +126,7 @@ module.exports = {
103
126
  ) {
104
127
  if (reference.isWrite()) {
105
128
  context.report({ node: identifier, message: "Assignment to function parameter '{{name}}'.", data: { name: identifier.name } });
106
- } else if (props && isModifyingProp(reference)) {
129
+ } else if (props && isModifyingProp(reference) && ignoredPropertyAssignmentsFor.indexOf(identifier.name) === -1) {
107
130
  context.report({ node: identifier, message: "Assignment to property of function parameter '{{name}}'.", data: { name: identifier.name } });
108
131
  }
109
132
  }
@@ -26,17 +26,9 @@ module.exports = {
26
26
  //--------------------------------------------------------------------------
27
27
 
28
28
  return {
29
-
30
- CallExpression(node) {
31
- const callee = node.callee;
32
-
33
- if (callee.type === "MemberExpression" && callee.object.name === "process" &&
34
- callee.property.name === "exit"
35
- ) {
36
- context.report({ node, message: "Don't use process.exit(); throw an error instead." });
37
- }
29
+ "CallExpression > MemberExpression.callee[object.name = 'process'][property.name = 'exit']"(node) {
30
+ context.report({ node: node.parent, message: "Don't use process.exit(); throw an error instead." });
38
31
  }
39
-
40
32
  };
41
33
 
42
34
  }
@@ -109,6 +109,7 @@ module.exports = {
109
109
  if (matchedObjectProperty) {
110
110
  const message = matchedObjectProperty.message ? ` ${matchedObjectProperty.message}` : "";
111
111
 
112
+ // eslint-disable-next-line eslint-plugin/report-message-format
112
113
  context.report({ node, message: "'{{objectName}}.{{propertyName}}' is restricted from being used.{{message}}", data: {
113
114
  objectName,
114
115
  propertyName,
@@ -117,6 +118,7 @@ module.exports = {
117
118
  } else if (globalMatchedProperty) {
118
119
  const message = globalMatchedProperty.message ? ` ${globalMatchedProperty.message}` : "";
119
120
 
121
+ // eslint-disable-next-line eslint-plugin/report-message-format
120
122
  context.report({ node, message: "'{{propertyName}}' is restricted from being used.{{message}}", data: {
121
123
  propertyName,
122
124
  message
@@ -8,8 +8,6 @@
8
8
  // Rule Definition
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const nodeTypes = require("espree").Syntax;
12
-
13
11
  module.exports = {
14
12
  meta: {
15
13
  docs: {
@@ -20,32 +18,18 @@ module.exports = {
20
18
 
21
19
  schema: {
22
20
  type: "array",
23
- items: [
24
- {
25
- enum: Object.keys(nodeTypes).map(k => nodeTypes[k])
26
- }
27
- ],
21
+ items: [{ type: "string" }],
28
22
  uniqueItems: true,
29
23
  minItems: 0
30
24
  }
31
25
  },
32
26
 
33
27
  create(context) {
34
-
35
- /**
36
- * Generates a warning from the provided node, saying that node type is not allowed.
37
- * @param {ASTNode} node The node to warn on
38
- * @returns {void}
39
- */
40
- function warn(node) {
41
- context.report({ node, message: "Using '{{type}}' is not allowed.", data: node });
42
- }
43
-
44
- return context.options.reduce((result, nodeType) => {
45
- result[nodeType] = warn;
46
-
47
- return result;
48
- }, {});
28
+ return context.options.reduce((result, selector) => Object.assign(result, {
29
+ [selector](node) {
30
+ context.report({ node, message: "Using '{{selector}}' is not allowed.", data: { selector } });
31
+ }
32
+ }), {});
49
33
 
50
34
  }
51
35
  };
@@ -19,7 +19,7 @@ module.exports = {
19
19
  category: "Best Practices",
20
20
  recommended: false // TODO: set to true
21
21
  },
22
- fixable: false,
22
+ fixable: null,
23
23
  schema: [
24
24
  ]
25
25
  },
@@ -26,19 +26,14 @@ module.exports = {
26
26
 
27
27
  return {
28
28
 
29
- MemberExpression(node) {
30
- const propertyName = node.property.name,
31
- syncRegex = /.*Sync$/;
32
-
33
- if (syncRegex.exec(propertyName) !== null) {
34
- context.report({
35
- node,
36
- message: "Unexpected sync method: '{{propertyName}}'.",
37
- data: {
38
- propertyName
39
- }
40
- });
41
- }
29
+ "MemberExpression[property.name=/.*Sync$/]"(node) {
30
+ context.report({
31
+ node,
32
+ message: "Unexpected sync method: '{{propertyName}}'.",
33
+ data: {
34
+ propertyName: node.property.name
35
+ }
36
+ });
42
37
  }
43
38
  };
44
39
 
@@ -25,6 +25,9 @@ module.exports = {
25
25
  },
26
26
  allowTernary: {
27
27
  type: "boolean"
28
+ },
29
+ allowTaggedTemplates: {
30
+ type: "boolean"
28
31
  }
29
32
  },
30
33
  additionalProperties: false
@@ -35,7 +38,8 @@ module.exports = {
35
38
  create(context) {
36
39
  const config = context.options[0] || {},
37
40
  allowShortCircuit = config.allowShortCircuit || false,
38
- allowTernary = config.allowTernary || false;
41
+ allowTernary = config.allowTernary || false,
42
+ allowTaggedTemplates = config.allowTaggedTemplates || false;
39
43
 
40
44
  /**
41
45
  * @param {ASTNode} node - any node
@@ -95,12 +99,17 @@ module.exports = {
95
99
  return isValidExpression(node.consequent) && isValidExpression(node.alternate);
96
100
  }
97
101
  }
102
+
98
103
  if (allowShortCircuit) {
99
104
  if (node.type === "LogicalExpression") {
100
105
  return isValidExpression(node.right);
101
106
  }
102
107
  }
103
108
 
109
+ if (allowTaggedTemplates && node.type === "TaggedTemplateExpression") {
110
+ return true;
111
+ }
112
+
104
113
  return /^(?:Assignment|Call|New|Update|Yield|Await)Expression$/.test(node.type) ||
105
114
  (node.type === "UnaryExpression" && ["delete", "void"].indexOf(node.operator) >= 0);
106
115
  }
@@ -66,6 +66,7 @@ module.exports = {
66
66
 
67
67
  const DEFINED_MESSAGE = "'{{name}}' is defined but never used.";
68
68
  const ASSIGNED_MESSAGE = "'{{name}}' is assigned a value but never used.";
69
+ const REST_PROPERTY_TYPE = /^(?:Experimental)?RestProperty$/;
69
70
 
70
71
  const config = {
71
72
  vars: "all",
@@ -139,17 +140,16 @@ module.exports = {
139
140
  */
140
141
  function hasRestSpreadSibling(variable) {
141
142
  if (config.ignoreRestSiblings) {
142
- const restProperties = new Set(["ExperimentalRestProperty", "RestProperty"]);
143
-
144
- return variable.defs
145
- .filter(def => def.name.type === "Identifier")
146
- .some(def => (
147
- def.node.id &&
148
- def.node.id.type === "ObjectPattern" &&
149
- def.node.id.properties.length &&
150
- restProperties.has(def.node.id.properties[def.node.id.properties.length - 1].type) && // last property is a rest property
151
- !restProperties.has(def.name.parent.type) // variable is sibling of the rest property
152
- ));
143
+ return variable.defs.some(def => {
144
+ const propertyNode = def.name.parent;
145
+ const patternNode = propertyNode.parent;
146
+
147
+ return (
148
+ propertyNode.type === "Property" &&
149
+ patternNode.type === "ObjectPattern" &&
150
+ REST_PROPERTY_TYPE.test(patternNode.properties[patternNode.properties.length - 1].type)
151
+ );
152
+ });
153
153
  }
154
154
 
155
155
  return false;
@@ -568,7 +568,7 @@ module.exports = {
568
568
  function getLocation(variable) {
569
569
  const comment = variable.eslintExplicitGlobalComment;
570
570
 
571
- return astUtils.getLocationFromRangeIndex(sourceCode, comment.range[0] + 2 + getColumnInComment(variable, comment));
571
+ return sourceCode.getLocFromIndex(comment.range[0] + 2 + getColumnInComment(variable, comment));
572
572
  }
573
573
 
574
574
  //--------------------------------------------------------------------------
@@ -166,7 +166,7 @@ module.exports = {
166
166
  const options = parseOptions(context.options[0]);
167
167
 
168
168
  /**
169
- * Determines whether a given use-before-define case should be reportedaccording to the options.
169
+ * Determines whether a given use-before-define case should be reported according to the options.
170
170
  * @param {escope.Variable} variable The variable that gets used before being defined
171
171
  * @param {escope.Reference} reference The reference to the variable
172
172
  * @returns {boolean} `true` if the usage should be reported
@@ -94,7 +94,7 @@ module.exports = {
94
94
  function report(node, startOffset, character) {
95
95
  context.report({
96
96
  node,
97
- loc: astUtils.getLocationFromRangeIndex(sourceCode, astUtils.getRangeIndexFromLocation(sourceCode, node.loc.start) + startOffset),
97
+ loc: sourceCode.getLocFromIndex(sourceCode.getIndexFromLoc(node.loc.start) + startOffset),
98
98
  message: "Unnecessary escape character: \\{{character}}.",
99
99
  data: { character }
100
100
  });
@@ -147,7 +147,13 @@ module.exports = {
147
147
  function check(node) {
148
148
  const isTemplateElement = node.type === "TemplateElement";
149
149
 
150
- if (isTemplateElement && node.parent && node.parent.parent && node.parent.parent.type === "TaggedTemplateExpression") {
150
+ if (
151
+ isTemplateElement &&
152
+ node.parent &&
153
+ node.parent.parent &&
154
+ node.parent.parent.type === "TaggedTemplateExpression" &&
155
+ node.parent === node.parent.parent.quasi
156
+ ) {
151
157
 
152
158
  // Don't report tagged template literals, because the backslash character is accessible to the tag function.
153
159
  return;
@@ -8,7 +8,8 @@
8
8
  // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const astUtils = require("../ast-utils");
11
+ const astUtils = require("../ast-utils"),
12
+ FixTracker = require("../util/fix-tracker");
12
13
 
13
14
  //------------------------------------------------------------------------------
14
15
  // Helpers
@@ -219,7 +220,17 @@ module.exports = {
219
220
  loc: node.loc,
220
221
  message: "Unnecessary return statement.",
221
222
  fix(fixer) {
222
- return isRemovable(node) ? fixer.remove(node) : null;
223
+ if (isRemovable(node)) {
224
+
225
+ // Extend the replacement range to include the
226
+ // entire function to avoid conflicting with
227
+ // no-else-return.
228
+ // https://github.com/eslint/eslint/issues/8026
229
+ return new FixTracker(fixer, context.getSourceCode())
230
+ .retainEnclosingFunction(node)
231
+ .remove(node);
232
+ }
233
+ return null;
223
234
  }
224
235
  });
225
236
  }