eslint 3.15.0 → 3.16.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 (97) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/conf/{eslint.json → eslint-recommended.js} +85 -71
  3. package/lib/ast-utils.js +185 -19
  4. package/lib/code-path-analysis/code-path-state.js +2 -2
  5. package/lib/config/autoconfig.js +3 -3
  6. package/lib/config/config-file.js +14 -7
  7. package/lib/config/config-initializer.js +1 -1
  8. package/lib/config.js +3 -2
  9. package/lib/eslint.js +4 -4
  10. package/lib/rules/arrow-body-style.js +7 -4
  11. package/lib/rules/arrow-spacing.js +7 -6
  12. package/lib/rules/block-spacing.js +2 -2
  13. package/lib/rules/brace-style.js +2 -6
  14. package/lib/rules/capitalized-comments.js +6 -6
  15. package/lib/rules/comma-spacing.js +3 -3
  16. package/lib/rules/consistent-return.js +1 -1
  17. package/lib/rules/constructor-super.js +3 -3
  18. package/lib/rules/curly.js +11 -7
  19. package/lib/rules/default-case.js +3 -3
  20. package/lib/rules/eqeqeq.js +15 -6
  21. package/lib/rules/func-call-spacing.js +10 -13
  22. package/lib/rules/generator-star-spacing.js +18 -19
  23. package/lib/rules/id-blacklist.js +2 -2
  24. package/lib/rules/id-length.js +3 -3
  25. package/lib/rules/id-match.js +2 -2
  26. package/lib/rules/indent.js +7 -6
  27. package/lib/rules/key-spacing.js +12 -16
  28. package/lib/rules/keyword-spacing.js +2 -13
  29. package/lib/rules/line-comment-position.js +1 -1
  30. package/lib/rules/linebreak-style.js +7 -1
  31. package/lib/rules/lines-around-comment.js +4 -4
  32. package/lib/rules/lines-around-directive.js +3 -3
  33. package/lib/rules/max-lines.js +2 -2
  34. package/lib/rules/max-statements-per-line.js +7 -6
  35. package/lib/rules/newline-after-var.js +7 -2
  36. package/lib/rules/newline-per-chained-call.js +3 -1
  37. package/lib/rules/no-cond-assign.js +3 -3
  38. package/lib/rules/no-extend-native.js +3 -3
  39. package/lib/rules/no-extra-bind.js +3 -4
  40. package/lib/rules/no-extra-boolean-cast.js +8 -0
  41. package/lib/rules/no-extra-parens.js +1 -2
  42. package/lib/rules/no-inner-declarations.js +4 -4
  43. package/lib/rules/no-irregular-whitespace.js +7 -1
  44. package/lib/rules/no-lone-blocks.js +10 -10
  45. package/lib/rules/no-mixed-operators.js +1 -7
  46. package/lib/rules/no-multi-spaces.js +4 -1
  47. package/lib/rules/no-multi-str.js +7 -3
  48. package/lib/rules/no-return-assign.js +7 -14
  49. package/lib/rules/no-sequences.js +7 -6
  50. package/lib/rules/no-trailing-spaces.js +8 -2
  51. package/lib/rules/no-undefined.js +45 -6
  52. package/lib/rules/no-unexpected-multiline.js +9 -8
  53. package/lib/rules/no-unneeded-ternary.js +5 -1
  54. package/lib/rules/no-unused-labels.js +17 -2
  55. package/lib/rules/no-unused-vars.js +2 -16
  56. package/lib/rules/no-useless-computed-key.js +8 -3
  57. package/lib/rules/no-useless-concat.js +10 -7
  58. package/lib/rules/no-useless-escape.js +1 -1
  59. package/lib/rules/no-useless-return.js +1 -7
  60. package/lib/rules/no-var.js +1 -3
  61. package/lib/rules/no-whitespace-before-property.js +5 -16
  62. package/lib/rules/object-curly-newline.js +2 -2
  63. package/lib/rules/object-curly-spacing.js +7 -25
  64. package/lib/rules/object-property-newline.js +3 -3
  65. package/lib/rules/object-shorthand.js +2 -2
  66. package/lib/rules/operator-assignment.js +1 -1
  67. package/lib/rules/operator-linebreak.js +8 -10
  68. package/lib/rules/padded-blocks.js +4 -4
  69. package/lib/rules/prefer-spread.js +1 -1
  70. package/lib/rules/prefer-template.js +1 -1
  71. package/lib/rules/quotes.js +10 -6
  72. package/lib/rules/semi-spacing.js +4 -0
  73. package/lib/rules/space-before-function-paren.js +8 -5
  74. package/lib/rules/spaced-comment.js +2 -2
  75. package/lib/rules/strict.js +2 -2
  76. package/lib/rules/unicode-bom.js +1 -1
  77. package/lib/rules/wrap-iife.js +5 -5
  78. package/lib/rules/yoda.js +2 -7
  79. package/lib/testers/rule-tester.js +13 -6
  80. package/lib/token-store/backward-token-comment-cursor.js +57 -0
  81. package/lib/token-store/backward-token-cursor.js +56 -0
  82. package/lib/token-store/cursor.js +76 -0
  83. package/lib/token-store/cursors.js +92 -0
  84. package/lib/token-store/decorative-cursor.js +39 -0
  85. package/lib/token-store/filter-cursor.js +43 -0
  86. package/lib/token-store/forward-token-comment-cursor.js +57 -0
  87. package/lib/token-store/forward-token-cursor.js +61 -0
  88. package/lib/token-store/index.js +604 -0
  89. package/lib/token-store/limit-cursor.js +40 -0
  90. package/lib/token-store/padded-token-cursor.js +38 -0
  91. package/lib/token-store/skip-cursor.js +42 -0
  92. package/lib/token-store/utils.js +100 -0
  93. package/lib/util/source-code-fixer.js +35 -39
  94. package/lib/util/source-code.js +31 -15
  95. package/messages/extend-config-missing.txt +3 -0
  96. package/package.json +2 -2
  97. package/lib/token-store.js +0 -203
@@ -6,6 +6,8 @@
6
6
 
7
7
  "use strict";
8
8
 
9
+ const astUtils = require("../ast-utils");
10
+
9
11
  //------------------------------------------------------------------------------
10
12
  // Rule Definition
11
13
  //------------------------------------------------------------------------------
@@ -47,7 +49,7 @@ module.exports = {
47
49
  */
48
50
  function getPropertyText(node) {
49
51
  const prefix = node.computed ? "[" : ".";
50
- const lines = sourceCode.getText(node.property).split(/\r\n|\r|\n/g);
52
+ const lines = sourceCode.getText(node.property).split(astUtils.LINEBREAK_MATCHER);
51
53
  const suffix = node.computed && lines.length === 1 ? "]" : "";
52
54
 
53
55
  return prefix + lines[0] + suffix;
@@ -101,9 +101,9 @@ module.exports = {
101
101
  function testForAssign(node) {
102
102
  if (node.test &&
103
103
  (node.test.type === "AssignmentExpression") &&
104
- (node.type === "ForStatement" ?
105
- !isParenthesised(node.test) :
106
- !isParenthesisedTwice(node.test)
104
+ (node.type === "ForStatement"
105
+ ? !isParenthesised(node.test)
106
+ : !isParenthesisedTwice(node.test)
107
107
  )
108
108
  ) {
109
109
 
@@ -60,9 +60,9 @@ module.exports = {
60
60
  return;
61
61
  }
62
62
 
63
- const affectsProto = lhs.object.computed ?
64
- lhs.object.property.type === "Literal" && lhs.object.property.value === "prototype" :
65
- lhs.object.property.name === "prototype";
63
+ const affectsProto = lhs.object.computed
64
+ ? lhs.object.property.type === "Literal" && lhs.object.property.value === "prototype"
65
+ : lhs.object.property.name === "prototype";
66
66
 
67
67
  if (!affectsProto) {
68
68
  return;
@@ -8,7 +8,7 @@
8
8
  // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const getPropertyName = require("../ast-utils").getStaticPropertyName;
11
+ const astUtils = require("../ast-utils");
12
12
 
13
13
  //------------------------------------------------------------------------------
14
14
  // Rule Definition
@@ -44,8 +44,7 @@ module.exports = {
44
44
  loc: node.parent.property.loc.start,
45
45
  fix(fixer) {
46
46
  const firstTokenToRemove = context.getSourceCode()
47
- .getTokensBetween(node.parent.object, node.parent.property)
48
- .find(token => token.value !== ")");
47
+ .getFirstTokenBetween(node.parent.object, node.parent.property, astUtils.isNotClosingParenToken);
49
48
 
50
49
  return fixer.removeRange([firstTokenToRemove.range[0], node.parent.parent.range[1]]);
51
50
  }
@@ -73,7 +72,7 @@ module.exports = {
73
72
  grandparent.arguments.length === 1 &&
74
73
  parent.type === "MemberExpression" &&
75
74
  parent.object === node &&
76
- getPropertyName(parent) === "bind"
75
+ astUtils.getStaticPropertyName(parent) === "bind"
77
76
  );
78
77
  }
79
78
 
@@ -98,6 +98,14 @@ module.exports = {
98
98
  node,
99
99
  message: "Redundant Boolean call.",
100
100
  fix: fixer => {
101
+ if (!node.arguments.length) {
102
+ return fixer.replaceText(parent, "true");
103
+ }
104
+
105
+ if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement") {
106
+ return null;
107
+ }
108
+
101
109
  const argument = node.arguments[0];
102
110
 
103
111
  if (astUtils.getPrecedence(argument) < astUtils.getPrecedence(node.parent)) {
@@ -557,8 +557,7 @@ module.exports = {
557
557
  !(
558
558
  (node.object.type === "Literal" &&
559
559
  typeof node.object.value === "number" &&
560
- astUtils.isDecimalInteger(node.object))
561
- ||
560
+ astUtils.isDecimalInteger(node.object)) ||
562
561
 
563
562
  // RegExp literal is allowed to have parens (#1589)
564
563
  (node.object.type === "Literal" && node.object.regex)
@@ -64,10 +64,10 @@ module.exports = {
64
64
 
65
65
  if (!valid) {
66
66
  context.report({ node, message: "Move {{type}} declaration to {{body}} root.", data: {
67
- type: (node.type === "FunctionDeclaration" ?
68
- "function" : "variable"),
69
- body: (body.type === "Program" ?
70
- "program" : "function body")
67
+ type: (node.type === "FunctionDeclaration"
68
+ ? "function" : "variable"),
69
+ body: (body.type === "Program"
70
+ ? "program" : "function body")
71
71
  } });
72
72
  }
73
73
  }
@@ -6,6 +6,12 @@
6
6
 
7
7
  "use strict";
8
8
 
9
+ //------------------------------------------------------------------------------
10
+ // Requirements
11
+ //------------------------------------------------------------------------------
12
+
13
+ const astUtils = require("../ast-utils");
14
+
9
15
  //------------------------------------------------------------------------------
10
16
  // Constants
11
17
  //------------------------------------------------------------------------------
@@ -13,7 +19,7 @@
13
19
  const ALL_IRREGULARS = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000\u2028\u2029]/;
14
20
  const IRREGULAR_WHITESPACE = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000]+/mg;
15
21
  const IRREGULAR_LINE_TERMINATORS = /[\u2028\u2029]/mg;
16
- const LINE_BREAK = /\r\n|\r|\n|\u2028|\u2029/g;
22
+ const LINE_BREAK = astUtils.createGlobalLinebreakMatcher();
17
23
 
18
24
  //------------------------------------------------------------------------------
19
25
  // Rule Definition
@@ -32,22 +32,22 @@ module.exports = {
32
32
  * @returns {void}
33
33
  */
34
34
  function report(node) {
35
- const parent = context.getAncestors().pop();
35
+ const message = node.parent.type === "BlockStatement" ? "Nested block is redundant." : "Block is redundant.";
36
36
 
37
- context.report({ node, message: parent.type === "Program" ?
38
- "Block is redundant." :
39
- "Nested block is redundant."
40
- });
37
+ context.report({ node, message });
41
38
  }
42
39
 
43
40
  /**
44
- * Checks for any ocurrence of BlockStatement > BlockStatement or Program > BlockStatement
45
- * @returns {boolean} True if the current node is a lone block.
41
+ * Checks for any ocurrence of a BlockStatement in a place where lists of statements can appear
42
+ * @param {ASTNode} node The node to check
43
+ * @returns {boolean} True if the node is a lone block.
46
44
  */
47
- function isLoneBlock() {
48
- const parent = context.getAncestors().pop();
45
+ function isLoneBlock(node) {
46
+ return node.parent.type === "BlockStatement" ||
47
+ node.parent.type === "Program" ||
49
48
 
50
- return parent.type === "BlockStatement" || parent.type === "Program";
49
+ // Don't report blocks in switch cases if the block is the only statement of the case.
50
+ node.parent.type === "SwitchCase" && !(node.parent.consequent[0] === node && node.parent.consequent.length === 1);
51
51
  }
52
52
 
53
53
  /**
@@ -148,13 +148,7 @@ module.exports = {
148
148
  * @returns {Token} The operator token of the node.
149
149
  */
150
150
  function getOperatorToken(node) {
151
- let token = sourceCode.getTokenAfter(node.left);
152
-
153
- while (token.value === ")") {
154
- token = sourceCode.getTokenAfter(token);
155
- }
156
-
157
- return token;
151
+ return sourceCode.getTokenAfter(node.left, astUtils.isNotClosingParenToken);
158
152
  }
159
153
 
160
154
  /**
@@ -5,6 +5,8 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const astUtils = require("../ast-utils");
9
+
8
10
  //------------------------------------------------------------------------------
9
11
  // Rule Definition
10
12
  //------------------------------------------------------------------------------
@@ -93,7 +95,8 @@ module.exports = {
93
95
  const sourceCode = context.getSourceCode(),
94
96
  source = sourceCode.getText(),
95
97
  allComments = sourceCode.getAllComments(),
96
- pattern = /[^\n\r\u2028\u2029\t ].? {2,}/g; // note: repeating space
98
+ JOINED_LINEBEAKS = Array.from(astUtils.LINEBREAKS).join(""),
99
+ pattern = new RegExp(String.raw`[^ \t${JOINED_LINEBEAKS}].? {2,}`, "g"); // note: repeating space
97
100
  let parent;
98
101
 
99
102
 
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("../ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -39,9 +45,7 @@ module.exports = {
39
45
  return {
40
46
 
41
47
  Literal(node) {
42
- const lineBreak = /\n/;
43
-
44
- if (lineBreak.test(node.raw) && !isJSXElement(node.parent)) {
48
+ if (astUtils.LINEBREAK_MATCHER.test(node.raw) && !isJSXElement(node.parent)) {
45
49
  context.report({ node, message: "Multiline support is limited to browsers supporting ES5 only." });
46
50
  }
47
51
  }
@@ -5,23 +5,16 @@
5
5
  "use strict";
6
6
 
7
7
  //------------------------------------------------------------------------------
8
- // Helpers
8
+ // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExpression|ClassExpression)$/;
11
+ const astUtils = require("../ast-utils");
12
12
 
13
- /**
14
- * Checks whether or not a node is enclosed in parentheses.
15
- * @param {Node|null} node - A node to check.
16
- * @param {sourceCode} sourceCode - The ESLint SourceCode object.
17
- * @returns {boolean} Whether or not the node is enclosed in parentheses.
18
- */
19
- function isEnclosedInParens(node, sourceCode) {
20
- const prevToken = sourceCode.getTokenBefore(node);
21
- const nextToken = sourceCode.getTokenAfter(node);
13
+ //------------------------------------------------------------------------------
14
+ // Helpers
15
+ //------------------------------------------------------------------------------
22
16
 
23
- return prevToken && prevToken.value === "(" && nextToken && nextToken.value === ")";
24
- }
17
+ const SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExpression|ClassExpression)$/;
25
18
 
26
19
  //------------------------------------------------------------------------------
27
20
  // Rule Definition
@@ -48,7 +41,7 @@ module.exports = {
48
41
 
49
42
  return {
50
43
  AssignmentExpression(node) {
51
- if (!always && isEnclosedInParens(node, sourceCode)) {
44
+ if (!always && astUtils.isParenthesised(sourceCode, node)) {
52
45
  return;
53
46
  }
54
47
 
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("../ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -57,12 +63,7 @@ module.exports = {
57
63
  * @returns {boolean} True if the node has a paren on each side.
58
64
  */
59
65
  function isParenthesised(node) {
60
- const previousToken = sourceCode.getTokenBefore(node),
61
- nextToken = sourceCode.getTokenAfter(node);
62
-
63
- return previousToken && nextToken &&
64
- previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
65
- nextToken.value === ")" && nextToken.range[0] >= node.range[1];
66
+ return astUtils.isParenthesised(sourceCode, node);
66
67
  }
67
68
 
68
69
  /**
@@ -4,6 +4,12 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const astUtils = require("../ast-utils");
12
+
7
13
  //------------------------------------------------------------------------------
8
14
  // Rule Definition
9
15
  //------------------------------------------------------------------------------
@@ -34,7 +40,7 @@ module.exports = {
34
40
  create(context) {
35
41
  const sourceCode = context.getSourceCode();
36
42
 
37
- const BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u2028\u2029\u3000]",
43
+ const BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u3000]",
38
44
  SKIP_BLANK = `^${BLANK_CLASS}*$`,
39
45
  NONBLANK = `${BLANK_CLASS}+$`;
40
46
 
@@ -81,7 +87,7 @@ module.exports = {
81
87
  const re = new RegExp(NONBLANK),
82
88
  skipMatch = new RegExp(SKIP_BLANK),
83
89
  lines = sourceCode.lines,
84
- linebreaks = sourceCode.getText().match(/\r\n|\r|\n|\u2028|\u2029/g);
90
+ linebreaks = sourceCode.getText().match(astUtils.createGlobalLinebreakMatcher());
85
91
  let totalLength = 0,
86
92
  fixRange = [];
87
93
 
@@ -21,15 +21,54 @@ module.exports = {
21
21
 
22
22
  create(context) {
23
23
 
24
+ /**
25
+ * Report an invalid "undefined" identifier node.
26
+ * @param {ASTNode} node The node to report.
27
+ * @returns {void}
28
+ */
29
+ function report(node) {
30
+ context.report({
31
+ node,
32
+ message: "Unexpected use of undefined."
33
+ });
34
+ }
35
+
36
+ /**
37
+ * Checks the given scope for references to `undefined` and reports
38
+ * all references found.
39
+ * @param {escope.Scope} scope The scope to check.
40
+ * @returns {void}
41
+ */
42
+ function checkScope(scope) {
43
+ const undefinedVar = scope.set.get("undefined");
44
+
45
+ if (!undefinedVar) {
46
+ return;
47
+ }
48
+
49
+ const references = undefinedVar.references;
50
+
51
+ const defs = undefinedVar.defs;
52
+
53
+ // Report non-initializing references (those are covered in defs below)
54
+ references
55
+ .filter(ref => !ref.init)
56
+ .forEach(ref => report(ref.identifier));
57
+
58
+ defs.forEach(def => report(def.name));
59
+ }
60
+
24
61
  return {
62
+ "Program:exit"() {
63
+ const globalScope = context.getScope();
64
+
65
+ const stack = [globalScope];
25
66
 
26
- Identifier(node) {
27
- if (node.name === "undefined") {
28
- const parent = context.getAncestors().pop();
67
+ while (stack.length) {
68
+ const scope = stack.pop();
29
69
 
30
- if (!parent || parent.type !== "MemberExpression" || node !== parent.property || parent.computed) {
31
- context.report({ node, message: "Unexpected use of undefined." });
32
- }
70
+ stack.push.apply(stack, scope.childScopes);
71
+ checkScope(scope);
33
72
  }
34
73
  }
35
74
  };
@@ -4,9 +4,16 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const astUtils = require("../ast-utils");
12
+
7
13
  //------------------------------------------------------------------------------
8
14
  // Rule Definition
9
15
  //------------------------------------------------------------------------------
16
+
10
17
  module.exports = {
11
18
  meta: {
12
19
  docs: {
@@ -35,14 +42,8 @@ module.exports = {
35
42
  * @private
36
43
  */
37
44
  function checkForBreakAfter(node, msg) {
38
- let nodeExpressionEnd = node;
39
- let openParen = sourceCode.getTokenAfter(node);
40
-
41
- // Move along until the end of the wrapped expression
42
- while (openParen.value === ")") {
43
- nodeExpressionEnd = openParen;
44
- openParen = sourceCode.getTokenAfter(nodeExpressionEnd);
45
- }
45
+ const openParen = sourceCode.getTokenAfter(node, astUtils.isNotClosingParenToken);
46
+ const nodeExpressionEnd = sourceCode.getTokenBefore(openParen);
46
47
 
47
48
  if (openParen.loc.start.line !== nodeExpressionEnd.loc.end.line) {
48
49
  context.report({ node, loc: openParen.loc.start, message: msg, data: { char: openParen.value } });
@@ -67,7 +67,11 @@ module.exports = {
67
67
  */
68
68
  function invertExpression(node) {
69
69
  if (node.type === "BinaryExpression" && Object.prototype.hasOwnProperty.call(OPERATOR_INVERSES, node.operator)) {
70
- const operatorToken = sourceCode.getTokensBetween(node.left, node.right).find(token => token.value === node.operator);
70
+ const operatorToken = sourceCode.getFirstTokenBetween(
71
+ node.left,
72
+ node.right,
73
+ token => token.value === node.operator
74
+ );
71
75
 
72
76
  return sourceCode.getText().slice(node.range[0], operatorToken.range[0]) + OPERATOR_INVERSES[node.operator] + sourceCode.getText().slice(operatorToken.range[1], node.range[1]);
73
77
  }
@@ -17,10 +17,13 @@ module.exports = {
17
17
  recommended: true
18
18
  },
19
19
 
20
- schema: []
20
+ schema: [],
21
+
22
+ fixable: "code"
21
23
  },
22
24
 
23
25
  create(context) {
26
+ const sourceCode = context.getSourceCode();
24
27
  let scopeInfo = null;
25
28
 
26
29
  /**
@@ -49,7 +52,19 @@ module.exports = {
49
52
  context.report({
50
53
  node: node.label,
51
54
  message: "'{{name}}:' is defined but never used.",
52
- data: node.label
55
+ data: node.label,
56
+ fix(fixer) {
57
+
58
+ /*
59
+ * Only perform a fix if there are no comments between the label and the body. This will be the case
60
+ * when there is exactly one token/comment (the ":") between the label and the body.
61
+ */
62
+ if (sourceCode.getTokenAfter(node.label, { includeComments: true }) === sourceCode.getTokenBefore(node.body, { includeComments: true })) {
63
+ return fixer.removeRange([node.range[0], node.body.range[0]]);
64
+ }
65
+
66
+ return null;
67
+ }
53
68
  });
54
69
  }
55
70
 
@@ -62,6 +62,7 @@ module.exports = {
62
62
  },
63
63
 
64
64
  create(context) {
65
+ const sourceCode = context.getSourceCode();
65
66
 
66
67
  const DEFINED_MESSAGE = "'{{name}}' is defined but never used.";
67
68
  const ASSIGNED_MESSAGE = "'{{name}}' is assigned a value but never used.";
@@ -566,23 +567,8 @@ module.exports = {
566
567
  */
567
568
  function getLocation(variable) {
568
569
  const comment = variable.eslintExplicitGlobalComment;
569
- const baseLoc = comment.loc.start;
570
- let column = getColumnInComment(variable, comment);
571
- const prefix = comment.value.slice(0, column);
572
- const lineInComment = (prefix.match(/\n/g) || []).length;
573
570
 
574
- if (lineInComment > 0) {
575
- column -= 1 + prefix.lastIndexOf("\n");
576
- } else {
577
-
578
- // 2 is for `/*`
579
- column += baseLoc.column + 2;
580
- }
581
-
582
- return {
583
- line: baseLoc.line + lineInComment,
584
- column
585
- };
571
+ return astUtils.getLocationFromRangeIndex(sourceCode, comment.range[0] + 2 + getColumnInComment(variable, comment));
586
572
  }
587
573
 
588
574
  //--------------------------------------------------------------------------
@@ -4,6 +4,12 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const astUtils = require("../ast-utils");
12
+
7
13
  //------------------------------------------------------------------------------
8
14
  // Rule Definition
9
15
  //------------------------------------------------------------------------------
@@ -40,9 +46,8 @@ module.exports = {
40
46
  message: MESSAGE_UNNECESSARY_COMPUTED,
41
47
  data: { property: sourceCode.getText(key) },
42
48
  fix(fixer) {
43
- const leftSquareBracket = sourceCode.getFirstToken(node, node.value.generator || node.value.async ? 1 : 0);
44
- const rightSquareBracket = sourceCode.getTokensBetween(node.key, node.value).find(token => token.value === "]");
45
-
49
+ const leftSquareBracket = sourceCode.getFirstToken(node, astUtils.isOpeningBracketToken);
50
+ const rightSquareBracket = sourceCode.getFirstTokenBetween(node.key, node.value, astUtils.isClosingBracketToken);
46
51
  const tokensBetween = sourceCode.getTokensBetween(leftSquareBracket, rightSquareBracket, 1);
47
52
 
48
53
  if (tokensBetween.slice(0, -1).some((token, index) => sourceCode.getText().slice(token.range[1], tokensBetween[index + 1].range[0]).trim())) {
@@ -23,6 +23,15 @@ function isConcatenation(node) {
23
23
  return node.type === "BinaryExpression" && node.operator === "+";
24
24
  }
25
25
 
26
+ /**
27
+ * Checks if the given token is a `+` token or not.
28
+ * @param {Token} token - The token to check.
29
+ * @returns {boolean} `true` if the token is a `+` token.
30
+ */
31
+ function isConcatOperatorToken(token) {
32
+ return token.value === "+" && token.type === "Punctuator";
33
+ }
34
+
26
35
  /**
27
36
  * Get's the right most node on the left side of a BinaryExpression with + operator.
28
37
  * @param {ASTNode} node - A BinaryExpression node to check.
@@ -85,13 +94,7 @@ module.exports = {
85
94
  astUtils.isStringLiteral(right) &&
86
95
  astUtils.isTokenOnSameLine(left, right)
87
96
  ) {
88
-
89
- // move warning location to operator
90
- let operatorToken = sourceCode.getTokenAfter(left);
91
-
92
- while (operatorToken.value !== "+") {
93
- operatorToken = sourceCode.getTokenAfter(operatorToken);
94
- }
97
+ const operatorToken = sourceCode.getFirstTokenBetween(left, right, isConcatOperatorToken);
95
98
 
96
99
  context.report({
97
100
  node,
@@ -24,7 +24,7 @@ function union(setA, setB) {
24
24
  }());
25
25
  }
26
26
 
27
- const VALID_STRING_ESCAPES = new Set("\\nrvtbfux\n\r\u2028\u2029");
27
+ const VALID_STRING_ESCAPES = union(new Set("\\nrvtbfux"), astUtils.LINEBREAKS);
28
28
  const REGEX_GENERAL_ESCAPES = new Set("\\bcdDfnrsStvwWxu0123456789]");
29
29
  const REGEX_NON_CHARCLASS_ESCAPES = union(REGEX_GENERAL_ESCAPES, new Set("^/.$*+?[{}|()B"));
30
30
 
@@ -45,13 +45,7 @@ function remove(array, element) {
45
45
  * @returns {boolean} `true` if the node is removeable.
46
46
  */
47
47
  function isRemovable(node) {
48
- const parent = node.parent;
49
-
50
- return (
51
- parent.type === "Program" ||
52
- parent.type === "BlockStatement" ||
53
- parent.type === "SwitchCase"
54
- );
48
+ return astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type);
55
49
  }
56
50
 
57
51
  /**
@@ -274,9 +274,7 @@ module.exports = {
274
274
  if (
275
275
  !isLoopAssignee(node) &&
276
276
  !(node.parent.type === "ForStatement" && node.parent.init === node) &&
277
- node.parent.type !== "BlockStatement" &&
278
- node.parent.type !== "Program" &&
279
- node.parent.type !== "SwitchCase"
277
+ !astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)
280
278
  ) {
281
279
 
282
280
  // If the declaration is not in a block, e.g. `if (foo) var bar = 1;`, then it can't be fixed.
@@ -4,6 +4,10 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
7
11
  const astUtils = require("../ast-utils");
8
12
 
9
13
  //------------------------------------------------------------------------------
@@ -29,21 +33,6 @@ module.exports = {
29
33
  // Helpers
30
34
  //--------------------------------------------------------------------------
31
35
 
32
- /**
33
- * Finds opening bracket token of node's computed property
34
- * @param {ASTNode} node - the node to check
35
- * @returns {Token} opening bracket token of node's computed property
36
- * @private
37
- */
38
- function findOpeningBracket(node) {
39
- let token = sourceCode.getTokenBefore(node.property);
40
-
41
- while (token.value !== "[") {
42
- token = sourceCode.getTokenBefore(token);
43
- }
44
- return token;
45
- }
46
-
47
36
  /**
48
37
  * Reports whitespace before property token
49
38
  * @param {ASTNode} node - the node to report in the event of an error
@@ -87,7 +76,7 @@ module.exports = {
87
76
  }
88
77
 
89
78
  if (node.computed) {
90
- rightToken = findOpeningBracket(node);
79
+ rightToken = sourceCode.getTokenBefore(node.property, astUtils.isOpeningBracketToken);
91
80
  leftToken = sourceCode.getTokenBefore(rightToken);
92
81
  } else {
93
82
  rightToken = sourceCode.getFirstToken(node.property);