eslint 3.13.1 → 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 (137) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +1 -1
  3. package/conf/{eslint.json → eslint-recommended.js} +88 -71
  4. package/lib/ast-utils.js +247 -28
  5. package/lib/cli.js +2 -2
  6. package/lib/code-path-analysis/code-path-state.js +2 -2
  7. package/lib/config/autoconfig.js +24 -20
  8. package/lib/config/config-file.js +31 -24
  9. package/lib/config/config-initializer.js +2 -2
  10. package/lib/config/config-rule.js +15 -16
  11. package/lib/config/config-validator.js +6 -6
  12. package/lib/config.js +3 -2
  13. package/lib/eslint.js +18 -18
  14. package/lib/formatters/checkstyle.js +2 -2
  15. package/lib/formatters/codeframe.js +1 -1
  16. package/lib/formatters/compact.js +2 -2
  17. package/lib/formatters/junit.js +2 -2
  18. package/lib/formatters/tap.js +2 -2
  19. package/lib/formatters/unix.js +2 -2
  20. package/lib/formatters/visualstudio.js +2 -2
  21. package/lib/internal-rules/internal-consistent-docs-description.js +1 -1
  22. package/lib/rule-context.js +2 -2
  23. package/lib/rules/arrow-body-style.js +7 -4
  24. package/lib/rules/arrow-spacing.js +7 -6
  25. package/lib/rules/block-spacing.js +2 -2
  26. package/lib/rules/brace-style.js +93 -202
  27. package/lib/rules/capitalized-comments.js +6 -6
  28. package/lib/rules/comma-dangle.js +6 -6
  29. package/lib/rules/comma-spacing.js +16 -16
  30. package/lib/rules/comma-style.js +1 -1
  31. package/lib/rules/consistent-return.js +1 -1
  32. package/lib/rules/constructor-super.js +3 -3
  33. package/lib/rules/curly.js +11 -7
  34. package/lib/rules/default-case.js +3 -3
  35. package/lib/rules/eqeqeq.js +15 -6
  36. package/lib/rules/func-call-spacing.js +12 -15
  37. package/lib/rules/func-name-matching.js +1 -1
  38. package/lib/rules/generator-star-spacing.js +18 -19
  39. package/lib/rules/global-require.js +2 -2
  40. package/lib/rules/id-blacklist.js +2 -2
  41. package/lib/rules/id-length.js +3 -3
  42. package/lib/rules/id-match.js +2 -2
  43. package/lib/rules/indent.js +21 -20
  44. package/lib/rules/key-spacing.js +20 -23
  45. package/lib/rules/keyword-spacing.js +2 -13
  46. package/lib/rules/line-comment-position.js +1 -1
  47. package/lib/rules/linebreak-style.js +7 -1
  48. package/lib/rules/lines-around-comment.js +4 -4
  49. package/lib/rules/lines-around-directive.js +4 -4
  50. package/lib/rules/max-lines.js +3 -3
  51. package/lib/rules/max-statements-per-line.js +8 -7
  52. package/lib/rules/new-cap.js +2 -2
  53. package/lib/rules/newline-after-var.js +7 -2
  54. package/lib/rules/newline-before-return.js +2 -2
  55. package/lib/rules/newline-per-chained-call.js +3 -1
  56. package/lib/rules/no-await-in-loop.js +5 -5
  57. package/lib/rules/no-cond-assign.js +3 -3
  58. package/lib/rules/no-dupe-keys.js +1 -1
  59. package/lib/rules/no-else-return.js +88 -25
  60. package/lib/rules/no-extend-native.js +3 -3
  61. package/lib/rules/no-extra-bind.js +3 -4
  62. package/lib/rules/no-extra-boolean-cast.js +22 -1
  63. package/lib/rules/no-extra-parens.js +57 -9
  64. package/lib/rules/no-inner-declarations.js +4 -4
  65. package/lib/rules/no-irregular-whitespace.js +7 -1
  66. package/lib/rules/no-lone-blocks.js +10 -10
  67. package/lib/rules/no-mixed-operators.js +1 -7
  68. package/lib/rules/no-mixed-requires.js +4 -4
  69. package/lib/rules/no-multi-assign.js +41 -0
  70. package/lib/rules/no-multi-spaces.js +4 -1
  71. package/lib/rules/no-multi-str.js +7 -3
  72. package/lib/rules/no-redeclare.js +7 -7
  73. package/lib/rules/no-return-assign.js +7 -14
  74. package/lib/rules/no-return-await.js +2 -2
  75. package/lib/rules/no-sequences.js +7 -6
  76. package/lib/rules/no-throw-literal.js +2 -39
  77. package/lib/rules/no-trailing-spaces.js +8 -2
  78. package/lib/rules/no-undefined.js +45 -6
  79. package/lib/rules/no-unexpected-multiline.js +9 -8
  80. package/lib/rules/no-unneeded-ternary.js +5 -1
  81. package/lib/rules/no-unused-labels.js +17 -2
  82. package/lib/rules/no-unused-vars.js +34 -19
  83. package/lib/rules/no-use-before-define.js +33 -29
  84. package/lib/rules/no-useless-computed-key.js +9 -4
  85. package/lib/rules/no-useless-concat.js +10 -7
  86. package/lib/rules/no-useless-escape.js +1 -1
  87. package/lib/rules/no-useless-return.js +5 -11
  88. package/lib/rules/no-var.js +69 -3
  89. package/lib/rules/no-whitespace-before-property.js +5 -16
  90. package/lib/rules/object-curly-newline.js +2 -2
  91. package/lib/rules/object-curly-spacing.js +7 -25
  92. package/lib/rules/object-property-newline.js +3 -3
  93. package/lib/rules/object-shorthand.js +10 -10
  94. package/lib/rules/operator-assignment.js +2 -2
  95. package/lib/rules/operator-linebreak.js +8 -10
  96. package/lib/rules/padded-blocks.js +4 -4
  97. package/lib/rules/prefer-promise-reject-errors.js +124 -0
  98. package/lib/rules/prefer-spread.js +1 -1
  99. package/lib/rules/prefer-template.js +1 -1
  100. package/lib/rules/quotes.js +11 -7
  101. package/lib/rules/require-await.js +1 -1
  102. package/lib/rules/semi-spacing.js +4 -0
  103. package/lib/rules/sort-imports.js +4 -4
  104. package/lib/rules/sort-keys.js +2 -2
  105. package/lib/rules/sort-vars.js +2 -2
  106. package/lib/rules/space-before-function-paren.js +9 -6
  107. package/lib/rules/space-in-parens.js +8 -8
  108. package/lib/rules/spaced-comment.js +10 -10
  109. package/lib/rules/strict.js +2 -2
  110. package/lib/rules/template-tag-spacing.js +77 -0
  111. package/lib/rules/unicode-bom.js +1 -1
  112. package/lib/rules/wrap-iife.js +5 -5
  113. package/lib/rules/yoda.js +2 -7
  114. package/lib/rules.js +2 -2
  115. package/lib/testers/rule-tester.js +28 -21
  116. package/lib/token-store/backward-token-comment-cursor.js +57 -0
  117. package/lib/token-store/backward-token-cursor.js +56 -0
  118. package/lib/token-store/cursor.js +76 -0
  119. package/lib/token-store/cursors.js +92 -0
  120. package/lib/token-store/decorative-cursor.js +39 -0
  121. package/lib/token-store/filter-cursor.js +43 -0
  122. package/lib/token-store/forward-token-comment-cursor.js +57 -0
  123. package/lib/token-store/forward-token-cursor.js +61 -0
  124. package/lib/token-store/index.js +604 -0
  125. package/lib/token-store/limit-cursor.js +40 -0
  126. package/lib/token-store/padded-token-cursor.js +38 -0
  127. package/lib/token-store/skip-cursor.js +42 -0
  128. package/lib/token-store/utils.js +100 -0
  129. package/lib/util/comment-event-generator.js +17 -16
  130. package/lib/util/glob-util.js +1 -1
  131. package/lib/util/glob.js +1 -1
  132. package/lib/util/rule-fixer.js +3 -8
  133. package/lib/util/source-code-fixer.js +41 -45
  134. package/lib/util/source-code.js +35 -19
  135. package/messages/extend-config-missing.txt +3 -0
  136. package/package.json +3 -3
  137. package/lib/token-store.js +0 -203
@@ -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);
@@ -128,8 +128,8 @@ module.exports = {
128
128
  const options = normalizedOptions[node.type];
129
129
  const openBrace = sourceCode.getFirstToken(node);
130
130
  const closeBrace = sourceCode.getLastToken(node);
131
- let first = sourceCode.getTokenOrCommentAfter(openBrace);
132
- let last = sourceCode.getTokenOrCommentBefore(closeBrace);
131
+ let first = sourceCode.getTokenAfter(openBrace, { includeComments: true });
132
+ let last = sourceCode.getTokenBefore(closeBrace, { includeComments: true });
133
133
  const needsLinebreaks = (
134
134
  node.properties.length >= options.minProperties ||
135
135
  (
@@ -206,14 +206,8 @@ module.exports = {
206
206
  */
207
207
  function getClosingBraceOfObject(node) {
208
208
  const lastProperty = node.properties[node.properties.length - 1];
209
- let token = sourceCode.getTokenAfter(lastProperty);
210
209
 
211
- // skip ')' and trailing commas.
212
- while (token.type !== "Punctuator" || token.value !== "}") {
213
- token = sourceCode.getTokenAfter(token);
214
- }
215
-
216
- return token;
210
+ return sourceCode.getTokenAfter(lastProperty, astUtils.isClosingBraceToken);
217
211
  }
218
212
 
219
213
  /**
@@ -254,15 +248,9 @@ module.exports = {
254
248
  firstSpecifier = node.specifiers[1];
255
249
  }
256
250
 
257
- const first = sourceCode.getTokenBefore(firstSpecifier);
258
- let last = sourceCode.getTokenAfter(lastSpecifier);
259
-
260
- // to support a trailing comma.
261
- if (last.value === ",") {
262
- last = sourceCode.getTokenAfter(last);
263
- }
264
-
265
- const second = sourceCode.getTokenAfter(first),
251
+ const first = sourceCode.getTokenBefore(firstSpecifier),
252
+ last = sourceCode.getTokenAfter(lastSpecifier, astUtils.isNotCommaToken),
253
+ second = sourceCode.getTokenAfter(first),
266
254
  penultimate = sourceCode.getTokenBefore(last);
267
255
 
268
256
  validateBraceSpacing(node, first, second, penultimate, last);
@@ -280,15 +268,9 @@ module.exports = {
280
268
 
281
269
  const firstSpecifier = node.specifiers[0],
282
270
  lastSpecifier = node.specifiers[node.specifiers.length - 1],
283
- first = sourceCode.getTokenBefore(firstSpecifier);
284
- let last = sourceCode.getTokenAfter(lastSpecifier);
285
-
286
- // to support a trailing comma.
287
- if (last.value === ",") {
288
- last = sourceCode.getTokenAfter(last);
289
- }
290
-
291
- const second = sourceCode.getTokenAfter(first),
271
+ first = sourceCode.getTokenBefore(firstSpecifier),
272
+ last = sourceCode.getTokenAfter(lastSpecifier, astUtils.isNotCommaToken),
273
+ second = sourceCode.getTokenAfter(first),
292
274
  penultimate = sourceCode.getTokenBefore(last);
293
275
 
294
276
  validateBraceSpacing(node, first, second, penultimate, last);
@@ -34,9 +34,9 @@ module.exports = {
34
34
 
35
35
  create(context) {
36
36
  const allowSameLine = context.options[0] && Boolean(context.options[0].allowMultiplePropertiesPerLine);
37
- const errorMessage = allowSameLine ?
38
- "Object properties must go on a new line if they aren't all on the same line." :
39
- "Object properties must go on a new line.";
37
+ const errorMessage = allowSameLine
38
+ ? "Object properties must go on a new line if they aren't all on the same line."
39
+ : "Object properties must go on a new line.";
40
40
 
41
41
  const sourceCode = context.getSourceCode();
42
42
 
@@ -215,8 +215,8 @@ module.exports = {
215
215
  * @returns {Object} A fix for this node
216
216
  */
217
217
  function makeFunctionShorthand(fixer, node) {
218
- const firstKeyToken = node.computed ? sourceCode.getTokens(node).find(token => token.value === "[") : sourceCode.getFirstToken(node.key);
219
- const lastKeyToken = node.computed ? sourceCode.getTokensBetween(node.key, node.value).find(token => token.value === "]") : sourceCode.getLastToken(node.key);
218
+ const firstKeyToken = node.computed ? sourceCode.getFirstToken(node, astUtils.isOpeningBracketToken) : sourceCode.getFirstToken(node.key);
219
+ const lastKeyToken = node.computed ? sourceCode.getFirstTokenBetween(node.key, node.value, astUtils.isClosingBracketToken) : sourceCode.getLastToken(node.key);
220
220
  const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]);
221
221
  let keyPrefix = "";
222
222
 
@@ -231,15 +231,15 @@ module.exports = {
231
231
  const tokenBeforeParams = node.value.generator ? sourceCode.getTokenAfter(functionToken) : functionToken;
232
232
 
233
233
  return fixer.replaceTextRange([firstKeyToken.range[0], tokenBeforeParams.range[1]], keyPrefix + keyText);
234
- } else {
235
- const arrowToken = sourceCode.getTokens(node.value).find(token => token.value === "=>");
236
- const tokenBeforeArrow = sourceCode.getTokenBefore(arrowToken);
237
- const hasParensAroundParameters = tokenBeforeArrow.type === "Punctuator" && tokenBeforeArrow.value === ")";
238
- const oldParamText = sourceCode.text.slice(sourceCode.getFirstToken(node.value, node.value.async ? 1 : 0).range[0], tokenBeforeArrow.range[1]);
239
- const newParamText = hasParensAroundParameters ? oldParamText : `(${oldParamText})`;
240
-
241
- return fixer.replaceTextRange([firstKeyToken.range[0], arrowToken.range[1]], keyPrefix + keyText + newParamText);
242
234
  }
235
+ const arrowToken = sourceCode.getTokens(node.value).find(token => token.value === "=>");
236
+ const tokenBeforeArrow = sourceCode.getTokenBefore(arrowToken);
237
+ const hasParensAroundParameters = tokenBeforeArrow.type === "Punctuator" && tokenBeforeArrow.value === ")";
238
+ const oldParamText = sourceCode.text.slice(sourceCode.getFirstToken(node.value, node.value.async ? 1 : 0).range[0], tokenBeforeArrow.range[1]);
239
+ const newParamText = hasParensAroundParameters ? oldParamText : `(${oldParamText})`;
240
+
241
+ return fixer.replaceTextRange([firstKeyToken.range[0], arrowToken.range[1]], keyPrefix + keyText + newParamText);
242
+
243
243
  }
244
244
 
245
245
  /**
@@ -27,7 +27,7 @@ function isCommutativeOperatorWithShorthand(operator) {
27
27
  * a shorthand form.
28
28
  */
29
29
  function isNonCommutativeOperatorWithShorthand(operator) {
30
- return ["+", "-", "/", "%", "<<", ">>", ">>>"].indexOf(operator) >= 0;
30
+ return ["+", "-", "/", "%", "<<", ">>", ">>>", "**"].indexOf(operator) >= 0;
31
31
  }
32
32
 
33
33
  //------------------------------------------------------------------------------
@@ -108,7 +108,7 @@ module.exports = {
108
108
  * @returns {Token} The operator token in the node
109
109
  */
110
110
  function getOperatorToken(node) {
111
- return sourceCode.getTokensBetween(node.left, node.right).find(token => token.value === node.operator);
111
+ return sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
112
112
  }
113
113
 
114
114
  /**
@@ -5,14 +5,16 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
8
12
  const astUtils = require("../ast-utils");
9
13
 
10
14
  //------------------------------------------------------------------------------
11
15
  // Rule Definition
12
16
  //------------------------------------------------------------------------------
13
17
 
14
- const LINEBREAK_REGEX = /\r\n|\r|\n|\u2028|\u2029/g;
15
-
16
18
  module.exports = {
17
19
  meta: {
18
20
  docs: {
@@ -85,7 +87,7 @@ module.exports = {
85
87
  if (hasLinebreakBefore !== hasLinebreakAfter && desiredStyle !== "none") {
86
88
 
87
89
  // If there is a comment before and after the operator, don't do a fix.
88
- if (sourceCode.getTokenOrCommentBefore(operatorToken) !== tokenBefore && sourceCode.getTokenOrCommentAfter(operatorToken) !== tokenAfter) {
90
+ if (sourceCode.getTokenBefore(operatorToken, { includeComments: true }) !== tokenBefore && sourceCode.getTokenAfter(operatorToken, { includeComments: true }) !== tokenAfter) {
89
91
  return null;
90
92
  }
91
93
 
@@ -100,6 +102,7 @@ module.exports = {
100
102
  newTextBefore = textAfter;
101
103
  newTextAfter = textBefore;
102
104
  } else {
105
+ const LINEBREAK_REGEX = astUtils.createGlobalLinebreakMatcher();
103
106
 
104
107
  // Otherwise, if no linebreak is desired and no comments interfere, replace the linebreaks with empty strings.
105
108
  newTextBefore = desiredStyle === "before" || textBefore.trim() ? textBefore : textBefore.replace(LINEBREAK_REGEX, "");
@@ -129,19 +132,14 @@ module.exports = {
129
132
  * @returns {void}
130
133
  */
131
134
  function validateNode(node, leftSide) {
132
- let leftToken = sourceCode.getLastToken(leftSide);
133
- let operatorToken = sourceCode.getTokenAfter(leftToken);
134
135
 
135
136
  // When the left part of a binary expression is a single expression wrapped in
136
137
  // parentheses (ex: `(a) + b`), leftToken will be the last token of the expression
137
138
  // and operatorToken will be the closing parenthesis.
138
139
  // The leftToken should be the last closing parenthesis, and the operatorToken
139
140
  // should be the token right after that.
140
- while (operatorToken.value === ")") {
141
- leftToken = operatorToken;
142
- operatorToken = sourceCode.getTokenAfter(operatorToken);
143
- }
144
-
141
+ const operatorToken = sourceCode.getTokenAfter(leftSide, astUtils.isNotClosingParenToken);
142
+ const leftToken = sourceCode.getTokenBefore(operatorToken);
145
143
  const rightToken = sourceCode.getTokenAfter(operatorToken);
146
144
  const operator = operatorToken.value;
147
145
  const operatorStyleOverride = styleOverrides[operator];
@@ -101,7 +101,7 @@ module.exports = {
101
101
  let first = token;
102
102
 
103
103
  do {
104
- first = sourceCode.getTokenOrCommentAfter(first);
104
+ first = sourceCode.getTokenAfter(first, { includeComments: true });
105
105
  } while (isComment(first) && first.loc.start.line === tokenStartLine);
106
106
 
107
107
  const firstLine = first.loc.start.line;
@@ -120,7 +120,7 @@ module.exports = {
120
120
  let last = token;
121
121
 
122
122
  do {
123
- last = sourceCode.getTokenOrCommentBefore(last);
123
+ last = sourceCode.getTokenBefore(last, { includeComments: true });
124
124
  } while (isComment(last) && last.loc.end.line === blockEnd);
125
125
 
126
126
  const lastLine = last.loc.end.line;
@@ -182,7 +182,7 @@ module.exports = {
182
182
  }
183
183
  } else {
184
184
  if (blockHasTopPadding) {
185
- const nextToken = sourceCode.getTokenOrCommentAfter(openBrace);
185
+ const nextToken = sourceCode.getTokenAfter(openBrace, { includeComments: true });
186
186
 
187
187
  context.report({
188
188
  node,
@@ -195,7 +195,7 @@ module.exports = {
195
195
  }
196
196
 
197
197
  if (blockHasBottomPadding) {
198
- const previousToken = sourceCode.getTokenOrCommentBefore(closeBrace);
198
+ const previousToken = sourceCode.getTokenBefore(closeBrace, { includeComments: true });
199
199
 
200
200
  context.report({
201
201
  node,
@@ -0,0 +1,124 @@
1
+ /**
2
+ * @fileoverview restrict values that can be used as Promise rejection reasons
3
+ * @author Teddy Katz
4
+ */
5
+ "use strict";
6
+
7
+ const astUtils = require("../ast-utils");
8
+
9
+ //------------------------------------------------------------------------------
10
+ // Rule Definition
11
+ //------------------------------------------------------------------------------
12
+
13
+ module.exports = {
14
+ meta: {
15
+ docs: {
16
+ description: "require using Error objects as Promise rejection reasons",
17
+ category: "Best Practices",
18
+ recommended: false
19
+ },
20
+ fixable: null,
21
+ schema: [
22
+ {
23
+ type: "object",
24
+ properties: {
25
+ allowEmptyReject: { type: "boolean" }
26
+ },
27
+ additionalProperties: false
28
+ }
29
+ ]
30
+ },
31
+
32
+ create(context) {
33
+
34
+ const ALLOW_EMPTY_REJECT = context.options.length && context.options[0].allowEmptyReject;
35
+
36
+ //----------------------------------------------------------------------
37
+ // Helpers
38
+ //----------------------------------------------------------------------
39
+
40
+ /**
41
+ * Checks the argument of a reject() or Promise.reject() CallExpression, and reports it if it can't be an Error
42
+ * @param {ASTNode} callExpression A CallExpression node which is used to reject a Promise
43
+ * @returns {void}
44
+ */
45
+ function checkRejectCall(callExpression) {
46
+ if (!callExpression.arguments.length && ALLOW_EMPTY_REJECT) {
47
+ return;
48
+ }
49
+ if (
50
+ !callExpression.arguments.length ||
51
+ !astUtils.couldBeError(callExpression.arguments[0]) ||
52
+ callExpression.arguments[0].type === "Identifier" && callExpression.arguments[0].name === "undefined"
53
+ ) {
54
+ context.report({
55
+ node: callExpression,
56
+ message: "Expected the Promise rejection reason to be an Error."
57
+ });
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Determines whether a function call is a Promise.reject() call
63
+ * @param {ASTNode} node A CallExpression node
64
+ * @returns {boolean} `true` if the call is a Promise.reject() call
65
+ */
66
+ function isPromiseRejectCall(node) {
67
+ return node.callee.type === "MemberExpression" &&
68
+ node.callee.object.type === "Identifier" && node.callee.object.name === "Promise" &&
69
+ node.callee.property.type === "Identifier" && node.callee.property.name === "reject";
70
+ }
71
+
72
+ //----------------------------------------------------------------------
73
+ // Public
74
+ //----------------------------------------------------------------------
75
+
76
+ return {
77
+
78
+ // Check `Promise.reject(value)` calls.
79
+ CallExpression(node) {
80
+ if (isPromiseRejectCall(node)) {
81
+ checkRejectCall(node);
82
+ }
83
+ },
84
+
85
+ /*
86
+ * Check for `new Promise((resolve, reject) => {})`, and check for reject() calls.
87
+ * This function is run on "NewExpression:exit" instead of "NewExpression" to ensure that
88
+ * the nodes in the expression already have the `parent` property.
89
+ */
90
+ "NewExpression:exit"(node) {
91
+ if (
92
+ node.callee.type === "Identifier" && node.callee.name === "Promise" &&
93
+ node.arguments.length && astUtils.isFunction(node.arguments[0]) &&
94
+ node.arguments[0].params.length > 1 && node.arguments[0].params[1].type === "Identifier"
95
+ ) {
96
+ context.getDeclaredVariables(node.arguments[0])
97
+
98
+ /*
99
+ * Find the first variable that matches the second parameter's name.
100
+ * If the first parameter has the same name as the second parameter, then the variable will actually
101
+ * be "declared" when the first parameter is evaluated, but then it will be immediately overwritten
102
+ * by the second parameter. It's not possible for an expression with the variable to be evaluated before
103
+ * the variable is overwritten, because functions with duplicate parameters cannot have destructuring or
104
+ * default assignments in their parameter lists. Therefore, it's not necessary to explicitly account for
105
+ * this case.
106
+ */
107
+ .find(variable => variable.name === node.arguments[0].params[1].name)
108
+
109
+ // Get the references to that variable.
110
+ .references
111
+
112
+ // Only check the references that read the parameter's value.
113
+ .filter(ref => ref.isRead())
114
+
115
+ // Only check the references that are used as the callee in a function call, e.g. `reject(foo)`.
116
+ .filter(ref => ref.identifier.parent.type === "CallExpression" && ref.identifier === ref.identifier.parent.callee)
117
+
118
+ // Check the argument of the function call to determine whether it's an Error.
119
+ .forEach(ref => checkRejectCall(ref.identifier.parent));
120
+ }
121
+ }
122
+ };
123
+ }
124
+ };
@@ -108,7 +108,7 @@ module.exports = {
108
108
  return null;
109
109
  }
110
110
 
111
- const propertyDot = sourceCode.getTokensBetween(applied, node.callee.property).find(token => token.value === ".");
111
+ const propertyDot = sourceCode.getFirstTokenBetween(applied, node.callee.property, token => token.value === ".");
112
112
 
113
113
  return fixer.replaceTextRange([propertyDot.range[0], node.range[1]], `(...${sourceCode.getText(node.arguments[1])})`);
114
114
  }
@@ -157,7 +157,7 @@ module.exports = {
157
157
  }
158
158
 
159
159
  if (isConcatenation(currentNode) && hasStringLiteral(currentNode) && hasNonStringLiteral(currentNode)) {
160
- const plusSign = sourceCode.getTokensBetween(currentNode.left, currentNode.right).find(token => token.value === "+");
160
+ const plusSign = sourceCode.getFirstTokenBetween(currentNode.left, currentNode.right, token => token.value === "+");
161
161
  const textBeforePlus = getTextBetween(currentNode.left, plusSign);
162
162
  const textAfterPlus = getTextBetween(plusSign, currentNode.right);
163
163
  const leftEndsWithCurly = endsWithTemplateCurly(currentNode.left);
@@ -33,6 +33,9 @@ const QUOTE_SETTINGS = {
33
33
  }
34
34
  };
35
35
 
36
+ // An unescaped newline is a newline preceded by an even number of backslashes.
37
+ const UNESCAPED_LINEBREAK_PATTERN = new RegExp(String.raw`(^|[^\\])(\\\\)*[${Array.from(astUtils.LINEBREAKS).join("")}]`);
38
+
36
39
  /**
37
40
  * Switches quoting of javascript string between ' " and `
38
41
  * escaping and unescaping as necessary.
@@ -254,22 +257,23 @@ module.exports = {
254
257
  TemplateLiteral(node) {
255
258
 
256
259
  // If backticks are expected or it's a tagged template, then this shouldn't throw an errors
257
- if (allowTemplateLiterals || quoteOption === "backtick" || node.parent.type === "TaggedTemplateExpression") {
260
+ if (
261
+ allowTemplateLiterals ||
262
+ quoteOption === "backtick" ||
263
+ node.parent.type === "TaggedTemplateExpression" && node === node.parent.quasi
264
+ ) {
258
265
  return;
259
266
  }
260
267
 
261
- /*
262
- * A warning should be produced if the template literal only has one TemplateElement, and has no unescaped newlines.
263
- * An unescaped newline is a newline preceded by an even number of backslashes.
264
- */
265
- const shouldWarn = node.quasis.length === 1 && !/(^|[^\\])(\\\\)*[\r\n\u2028\u2029]/.test(node.quasis[0].value.raw);
268
+ // A warning should be produced if the template literal only has one TemplateElement, and has no unescaped newlines.
269
+ const shouldWarn = node.quasis.length === 1 && !UNESCAPED_LINEBREAK_PATTERN.test(node.quasis[0].value.raw);
266
270
 
267
271
  if (shouldWarn) {
268
272
  context.report({
269
273
  node,
270
274
  message: "Strings must use {{description}}.",
271
275
  data: {
272
- description: settings.description,
276
+ description: settings.description
273
277
  },
274
278
  fix(fixer) {
275
279
  if (isPartOfDirectivePrologue(node)) {
@@ -51,7 +51,7 @@ module.exports = {
51
51
  function enterFunction() {
52
52
  scopeInfo = {
53
53
  upper: scopeInfo,
54
- hasAwait: false,
54
+ hasAwait: false
55
55
  };
56
56
  }
57
57
 
@@ -206,6 +206,10 @@ module.exports = {
206
206
  DebuggerStatement: checkNode,
207
207
  ReturnStatement: checkNode,
208
208
  ThrowStatement: checkNode,
209
+ ImportDeclaration: checkNode,
210
+ ExportNamedDeclaration: checkNode,
211
+ ExportAllDeclaration: checkNode,
212
+ ExportDefaultDeclaration: checkNode,
209
213
  ForStatement(node) {
210
214
  if (node.init) {
211
215
  checkSemicolonSpacing(sourceCode.getTokenAfter(node.init), node);
@@ -71,9 +71,9 @@ module.exports = {
71
71
  return "all";
72
72
  } else if (node.specifiers.length === 1) {
73
73
  return "single";
74
- } else {
75
- return "multiple";
76
74
  }
75
+ return "multiple";
76
+
77
77
  }
78
78
 
79
79
  /**
@@ -93,9 +93,9 @@ module.exports = {
93
93
  function getFirstLocalMemberName(node) {
94
94
  if (node.specifiers[0]) {
95
95
  return node.specifiers[0].local.name;
96
- } else {
97
- return null;
98
96
  }
97
+ return null;
98
+
99
99
  }
100
100
 
101
101
  return {
@@ -64,7 +64,7 @@ const isValidOrders = {
64
64
  },
65
65
  descIN(a, b) {
66
66
  return isValidOrders.ascIN(b, a);
67
- },
67
+ }
68
68
  };
69
69
 
70
70
  //------------------------------------------------------------------------------
@@ -147,7 +147,7 @@ module.exports = {
147
147
  prevName,
148
148
  order,
149
149
  insensitive: insensitive ? "insensitive " : "",
150
- natual: natual ? "natural " : "",
150
+ natual: natual ? "natural " : ""
151
151
  }
152
152
  });
153
153
  }
@@ -53,9 +53,9 @@ module.exports = {
53
53
  if (currenVariableName < lastVariableName) {
54
54
  context.report({ node: decl, message: "Variables within the same declaration block should be sorted alphabetically." });
55
55
  return memo;
56
- } else {
57
- return decl;
58
56
  }
57
+ return decl;
58
+
59
59
  }, node.declarations[0]);
60
60
  }
61
61
  };
@@ -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
  //------------------------------------------------------------------------------
@@ -104,7 +110,7 @@ module.exports = {
104
110
  const isAnonymousGenerator = node.generator && !isNamed;
105
111
  const isNormalArrow = isArrow && !node.async;
106
112
  const isArrowWithoutParens = isArrow && sourceCode.getFirstToken(node, 1).value !== "(";
107
- let forbidSpacing, requireSpacing, rightToken;
113
+ let forbidSpacing, requireSpacing;
108
114
 
109
115
  // isAnonymousGenerator → `generator-star-spacing` should warn it. E.g. `function* () {}`
110
116
  // isNormalArrow → ignore always.
@@ -124,10 +130,7 @@ module.exports = {
124
130
  requireSpacing = requireAnonymousFunctionSpacing;
125
131
  }
126
132
 
127
- rightToken = sourceCode.getFirstToken(node);
128
- while (rightToken.value !== "(") {
129
- rightToken = sourceCode.getTokenAfter(rightToken);
130
- }
133
+ const rightToken = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
131
134
  const leftToken = sourceCode.getTokenBefore(rightToken);
132
135
  const location = leftToken.loc.end;
133
136
 
@@ -159,7 +162,7 @@ module.exports = {
159
162
  return {
160
163
  FunctionDeclaration: validateSpacingBeforeParentheses,
161
164
  FunctionExpression: validateSpacingBeforeParentheses,
162
- ArrowFunctionExpression: validateSpacingBeforeParentheses,
165
+ ArrowFunctionExpression: validateSpacingBeforeParentheses
163
166
  };
164
167
  }
165
168
  };
@@ -132,9 +132,9 @@ module.exports = {
132
132
  return false;
133
133
  }
134
134
  return !isOpenerException(right);
135
- } else {
136
- return isOpenerException(right);
137
135
  }
136
+ return isOpenerException(right);
137
+
138
138
  }
139
139
 
140
140
  /**
@@ -154,9 +154,9 @@ module.exports = {
154
154
 
155
155
  if (ALWAYS) {
156
156
  return !isCloserException(left);
157
- } else {
158
- return isCloserException(left);
159
157
  }
158
+ return isCloserException(left);
159
+
160
160
  }
161
161
 
162
162
  /**
@@ -180,9 +180,9 @@ module.exports = {
180
180
 
181
181
  if (ALWAYS) {
182
182
  return isOpenerException(right);
183
- } else {
184
- return !isOpenerException(right);
185
183
  }
184
+ return !isOpenerException(right);
185
+
186
186
  }
187
187
 
188
188
  /**
@@ -206,9 +206,9 @@ module.exports = {
206
206
 
207
207
  if (ALWAYS) {
208
208
  return isCloserException(left);
209
- } else {
210
- return !isCloserException(left);
211
209
  }
210
+ return !isCloserException(left);
211
+
212
212
  }
213
213
 
214
214
  //--------------------------------------------------------------------------