eslint 3.18.0 → 3.19.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 (38) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +1 -0
  3. package/lib/config/config-rule.js +14 -10
  4. package/lib/config/plugins.js +19 -8
  5. package/lib/eslint.js +6 -5
  6. package/lib/formatters/codeframe.js +4 -9
  7. package/lib/rules/arrow-body-style.js +2 -2
  8. package/lib/rules/arrow-parens.js +9 -3
  9. package/lib/rules/comma-dangle.js +3 -2
  10. package/lib/rules/comma-spacing.js +4 -14
  11. package/lib/rules/comma-style.js +8 -14
  12. package/lib/rules/curly.js +2 -2
  13. package/lib/rules/dot-notation.js +12 -6
  14. package/lib/rules/lines-around-directive.js +1 -1
  15. package/lib/rules/new-parens.js +7 -21
  16. package/lib/rules/no-cond-assign.js +4 -17
  17. package/lib/rules/no-else-return.js +6 -3
  18. package/lib/rules/no-extra-parens.js +47 -103
  19. package/lib/rules/no-extra-semi.js +3 -2
  20. package/lib/rules/no-implicit-coercion.js +21 -8
  21. package/lib/rules/no-native-reassign.js +1 -1
  22. package/lib/rules/no-negated-in-lhs.js +1 -1
  23. package/lib/rules/no-param-reassign.js +8 -1
  24. package/lib/rules/no-restricted-syntax.js +33 -6
  25. package/lib/rules/no-sequences.js +2 -2
  26. package/lib/rules/no-unsafe-negation.js +1 -1
  27. package/lib/rules/no-useless-computed-key.js +12 -1
  28. package/lib/rules/object-curly-spacing.js +2 -2
  29. package/lib/rules/object-shorthand.js +8 -2
  30. package/lib/rules/operator-assignment.js +20 -3
  31. package/lib/rules/prefer-const.js +1 -1
  32. package/lib/rules/quotes.js +1 -0
  33. package/lib/rules/semi-spacing.js +2 -15
  34. package/lib/rules/semi.js +4 -12
  35. package/lib/rules/space-before-function-paren.js +53 -77
  36. package/lib/rules/space-in-parens.js +4 -8
  37. package/lib/util/glob-util.js +1 -1
  38. package/package.json +29 -29
package/CHANGELOG.md CHANGED
@@ -1,3 +1,42 @@
1
+ v3.19.0 - March 31, 2017
2
+
3
+ * e09132f Fix: no-extra-parens false positive with exports and object literals (#8359) (Teddy Katz)
4
+ * 91baed4 Update: allow custom messages in no-restricted-syntax (fixes #8298) (#8357) (Vitor Balocco)
5
+ * 35c93e6 Fix: prevent space-before-function-paren from checking type annotations (#8349) (Teddy Katz)
6
+ * 3342e9f Fix: don't modify operator precedence in operator-assignment autofixer (#8358) (Teddy Katz)
7
+ * f88375f Docs: clarify that no-unsafe-negation is in eslint:recommended (#8371) (Teddy Katz)
8
+ * 02f0d27 Docs: Add soda0289 to Development Team (#8367) (Kai Cataldo)
9
+ * 155424c Fix: ignore empty path in patterns (fixes #8362) (#8364) (alberto)
10
+ * 27616a8 Fix: prefer-const false positive with object spread (fixes #8187) (#8297) (Vitor Balocco)
11
+ * 8569a90 Docs: add note about git's linebreak handling to linebreak-style docs (#8361) (Teddy Katz)
12
+ * 5878593 Chore: fix invalid syntax in no-param-reassign test (#8360) (Teddy Katz)
13
+ * 1b1046b Fix: don't classify plugins that throw errors as "missing" (fixes #6874) (#8323) (Teddy Katz)
14
+ * 29f4ba5 Fix: no-useless-computed-key invalid autofix for getters and setters (#8335) (Teddy Katz)
15
+ * 0541eaf Fix: no-implicit-coercion invalid autofix with consecutive identifiers (#8340) (Teddy Katz)
16
+ * 41b9786 Fix: no-extra-parens false positive with objects following arrows (#8339) (Teddy Katz)
17
+ * 3146167 Fix: `eslint.verify` should not mutate config argument (fixes #8329) (#8334) (alberto)
18
+ * 927de90 Fix: dot-notation autofix produces invalid syntax for integer properties (#8332) (Teddy Katz)
19
+ * a9d1bea Fix: comma-style autofix produces errors on parenthesized elements (#8331) (Teddy Katz)
20
+ * d52173f Fix: don't generate invalid options in config-rule (#8326) (Teddy Katz)
21
+ * 6eda3b5 Fix: no-extra-parens invalid autofix in for-of statements (#8337) (Teddy Katz)
22
+ * 6c819d8 Fix: dot-notation autofix produces errors on parenthesized computed keys (#8330) (Teddy Katz)
23
+ * 2d883d7 Fix: object-shorthand autofix produces errors on parenthesized functions (#8328) (Teddy Katz)
24
+ * cd9b774 Fix: quotes false positive with backtick option in method names (#8327) (Teddy Katz)
25
+ * d064ba2 Fix: no-else-return false positive for ifs in single-statement position (#8338) (Teddy Katz)
26
+ * 6a718ba Chore: enable max-statements-per-line on ESLint codebase (#8321) (Teddy Katz)
27
+ * 614b62e Chore: update sinon calls to deprecated API. (#8310) (alberto)
28
+ * 0491572 Chore: use precalculated counts in codeframe formatter (#8296) (Vitor Balocco)
29
+ * 8733e6a Chore: Fix incorrect error location properties in tests (#8307) (alberto)
30
+ * c4ffb49 Chore: Fix typos in test option assertions (#8305) (Teddy Katz)
31
+ * 79a97cb Upgrade: devDependencies (#8303) (alberto)
32
+ * e4da200 Upgrade: Mocha to 3.2.0 (#8299) (Ilya Volodin)
33
+ * 2f144ca Fix: operator-assignment autofix errors with parentheses (fixes #8293) (#8294) (Teddy Katz)
34
+ * 7521cd5 Chore: update token logic in rules to use ast-utils (#8288) (Teddy Katz)
35
+ * 9b509ce Chore: refactor space-before-function-paren rule (#8284) (Teddy Katz)
36
+ * ddc6350 Fix: no-param-reassign false positive on destructuring (fixes #8279) (#8281) (Teddy Katz)
37
+ * f8176b3 Chore: improve test coverage for node-event-generator (#8287) (Teddy Katz)
38
+ * 602e9c2 Docs: fix incorrect selector examples (#8278) (Teddy Katz)
39
+
1
40
  v3.18.0 - March 17, 2017
2
41
 
3
42
  * 85f74ca Fix: broken code path of direct nested loops (fixes #8248) (#8274) (Toru Nagashima)
package/README.md CHANGED
@@ -130,6 +130,7 @@ These folks keep the project moving and are resources for help.
130
130
  * Kevin Partington ([@platinumazure](https://github.com/platinumazure))
131
131
  * Vitor Balocco ([@vitorbal](https://github.com/vitorbal))
132
132
  * James Henry ([@JamesHenry](https://github.com/JamesHenry))
133
+ * Reyad Attiyat ([@soda0289](https://github.com/soda0289))
133
134
 
134
135
  ## Releases
135
136
 
@@ -223,7 +223,7 @@ class RuleConfigSet {
223
223
  /**
224
224
  * Add rule configurations from a schema object
225
225
  * @param {Object} obj Schema item with type === "object"
226
- * @returns {void}
226
+ * @returns {boolean} true if at least one schema for the object could be generated, false otherwise
227
227
  */
228
228
  addObject(obj) {
229
229
  const objectConfigSet = {
@@ -258,7 +258,10 @@ class RuleConfigSet {
258
258
 
259
259
  if (objectConfigSet.objectConfigs.length > 0) {
260
260
  this.ruleConfigs = this.ruleConfigs.concat(combineArrays(this.ruleConfigs, objectConfigSet.objectConfigs));
261
+ return true;
261
262
  }
263
+
264
+ return false;
262
265
  }
263
266
  }
264
267
 
@@ -271,20 +274,21 @@ function generateConfigsFromSchema(schema) {
271
274
  const configSet = new RuleConfigSet();
272
275
 
273
276
  if (Array.isArray(schema)) {
274
- schema.forEach(opt => {
277
+ for (const opt of schema) {
275
278
  if (opt.enum) {
276
279
  configSet.addEnums(opt.enum);
277
- }
278
-
279
- if (opt.type && opt.type === "object") {
280
- configSet.addObject(opt);
281
- }
280
+ } else if (opt.type && opt.type === "object") {
281
+ if (!configSet.addObject(opt)) {
282
+ break;
283
+ }
282
284
 
283
- if (opt.oneOf) {
285
+ // TODO (IanVS): support oneOf
286
+ } else {
284
287
 
285
- // TODO (IanVS): not yet implemented
288
+ // If we don't know how to fill in this option, don't fill in any of the following options.
289
+ break;
286
290
  }
287
- });
291
+ }
288
292
  }
289
293
  configSet.addErrorSeverity();
290
294
  return configSet.ruleConfigs;
@@ -127,14 +127,25 @@ module.exports = {
127
127
  if (!plugins[shortName]) {
128
128
  try {
129
129
  plugin = require(longName);
130
- } catch (err) {
131
- debug(`Failed to load plugin ${longName}.`);
132
- err.message = `Failed to load plugin ${pluginName}: ${err.message}`;
133
- err.messageTemplate = "plugin-missing";
134
- err.messageData = {
135
- pluginName: longName
136
- };
137
- throw err;
130
+ } catch (pluginLoadErr) {
131
+ try {
132
+
133
+ // Check whether the plugin exists
134
+ require.resolve(longName);
135
+ } catch (missingPluginErr) {
136
+
137
+ // If the plugin can't be resolved, display the missing plugin error (usually a config or install error)
138
+ debug(`Failed to load plugin ${longName}.`);
139
+ missingPluginErr.message = `Failed to load plugin ${pluginName}: ${missingPluginErr.message}`;
140
+ missingPluginErr.messageTemplate = "plugin-missing";
141
+ missingPluginErr.messageData = {
142
+ pluginName: longName
143
+ };
144
+ throw missingPluginErr;
145
+ }
146
+
147
+ // Otherwise, the plugin exists and is throwing on module load for some reason, so print the stack trace.
148
+ throw pluginLoadErr;
138
149
  }
139
150
 
140
151
  this.define(pluginName, plugin);
package/lib/eslint.js CHANGED
@@ -778,17 +778,18 @@ module.exports = (function() {
778
778
  // search and apply "eslint-env *".
779
779
  const envInFile = findEslintEnv(text || textOrSourceCode.text);
780
780
 
781
+ config = Object.assign({}, config);
782
+
781
783
  if (envInFile) {
782
- if (!config || !config.env) {
783
- config = Object.assign({}, config || {}, { env: envInFile });
784
- } else {
785
- config = Object.assign({}, config);
784
+ if (config.env) {
786
785
  config.env = Object.assign({}, config.env, envInFile);
786
+ } else {
787
+ config.env = envInFile;
787
788
  }
788
789
  }
789
790
 
790
791
  // process initial config to make it safe to extend
791
- config = prepareConfig(config || {});
792
+ config = prepareConfig(config);
792
793
 
793
794
  // only do this for text
794
795
  if (text !== null) {
@@ -101,15 +101,10 @@ module.exports = function(results) {
101
101
  const resultsWithMessages = results.filter(result => result.messages.length > 0);
102
102
 
103
103
  let output = resultsWithMessages.reduce((resultsOutput, result) => {
104
- const messages = result.messages.map(message => {
105
- if (message.fatal || message.severity === 2) {
106
- errors++;
107
- } else {
108
- warnings++;
109
- }
110
-
111
- return `${formatMessage(message, result)}\n\n`;
112
- });
104
+ const messages = result.messages.map(message => `${formatMessage(message, result)}\n\n`);
105
+
106
+ errors += result.errorCount;
107
+ warnings += result.warningCount;
113
108
 
114
109
  return resultsOutput.concat(messages);
115
110
  }, []).join("\n");
@@ -100,7 +100,7 @@ module.exports = {
100
100
  const firstValueToken = sourceCode.getTokenAfter(returnKeyword);
101
101
  let lastValueToken = sourceCode.getLastToken(blockBody[0]);
102
102
 
103
- if (lastValueToken.type === "Punctuator" && lastValueToken.value === ";") {
103
+ if (astUtils.isSemicolonToken(lastValueToken)) {
104
104
 
105
105
  /* The last token of the returned value is the last token of the ReturnExpression (if
106
106
  * the ReturnExpression has no semicolon), or the second-to-last token (if the ReturnExpression
@@ -120,7 +120,7 @@ module.exports = {
120
120
  const textBeforeReturn = sourceText.slice(arrowBody.range[0] + 1, returnKeyword.range[0]);
121
121
  const textBetweenReturnAndValue = sourceText.slice(returnKeyword.range[1], firstValueToken.range[0]);
122
122
  const rawReturnValueText = sourceText.slice(firstValueToken.range[0], lastValueToken.range[1]);
123
- const returnValueText = firstValueToken.value === "{" ? `(${rawReturnValueText})` : rawReturnValueText;
123
+ const returnValueText = astUtils.isOpeningBraceToken(firstValueToken) ? `(${rawReturnValueText})` : rawReturnValueText;
124
124
  const textAfterValue = sourceText.slice(lastValueToken.range[1], blockBody[0].range[1] - 1);
125
125
  const textAfterReturnStatement = sourceText.slice(blockBody[0].range[1], arrowBody.range[1] - 1);
126
126
 
@@ -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
  //------------------------------------------------------------------------------
@@ -62,7 +68,7 @@ module.exports = {
62
68
  node.body.type !== "BlockStatement" &&
63
69
  !node.returnType
64
70
  ) {
65
- if (token.type === "Punctuator" && token.value === "(") {
71
+ if (astUtils.isOpeningParenToken(token)) {
66
72
  context.report({
67
73
  node,
68
74
  message: requireForBlockBodyMessage,
@@ -84,7 +90,7 @@ module.exports = {
84
90
  requireForBlockBody &&
85
91
  node.body.type === "BlockStatement"
86
92
  ) {
87
- if (token.type !== "Punctuator" || token.value !== "(") {
93
+ if (!astUtils.isOpeningParenToken(token)) {
88
94
  context.report({
89
95
  node,
90
96
  message: requireForBlockBodyNoParensMessage,
@@ -103,7 +109,7 @@ module.exports = {
103
109
  !node.params[0].typeAnnotation &&
104
110
  !node.returnType
105
111
  ) {
106
- if (token.type === "Punctuator" && token.value === "(") {
112
+ if (astUtils.isOpeningParenToken(token)) {
107
113
  context.report({
108
114
  node,
109
115
  message: asNeededMessage,
@@ -10,6 +10,7 @@
10
10
  //------------------------------------------------------------------------------
11
11
 
12
12
  const lodash = require("lodash");
13
+ const astUtils = require("../ast-utils");
13
14
 
14
15
  //------------------------------------------------------------------------------
15
16
  // Helpers
@@ -178,7 +179,7 @@ module.exports = {
178
179
  default: {
179
180
  const nextToken = sourceCode.getTokenAfter(lastItem);
180
181
 
181
- if (nextToken.value === ",") {
182
+ if (astUtils.isCommaToken(nextToken)) {
182
183
  return nextToken;
183
184
  }
184
185
  return sourceCode.getLastToken(lastItem);
@@ -224,7 +225,7 @@ module.exports = {
224
225
 
225
226
  const trailingToken = getTrailingToken(node, lastItem);
226
227
 
227
- if (trailingToken.value === ",") {
228
+ if (astUtils.isCommaToken(trailingToken)) {
228
229
  context.report({
229
230
  node: lastItem,
230
231
  loc: trailingToken.loc.start,
@@ -53,16 +53,6 @@ module.exports = {
53
53
  // list of comma tokens to ignore for the check of leading whitespace
54
54
  const commaTokensToIgnore = [];
55
55
 
56
- /**
57
- * Determines if a given token is a comma operator.
58
- * @param {ASTNode} token The token to check.
59
- * @returns {boolean} True if the token is a comma, false if not.
60
- * @private
61
- */
62
- function isComma(token) {
63
- return !!token && (token.type === "Punctuator") && (token.value === ",");
64
- }
65
-
66
56
  /**
67
57
  * Reports a spacing error with an appropriate message.
68
58
  * @param {ASTNode} node The binary expression node to report.
@@ -147,7 +137,7 @@ module.exports = {
147
137
  if (element === null) {
148
138
  token = sourceCode.getTokenAfter(previousToken);
149
139
 
150
- if (isComma(token)) {
140
+ if (astUtils.isCommaToken(token)) {
151
141
  commaTokensToIgnore.push(token);
152
142
  }
153
143
  } else {
@@ -166,7 +156,7 @@ module.exports = {
166
156
  "Program:exit"() {
167
157
  tokensAndComments.forEach((token, i) => {
168
158
 
169
- if (!isComma(token)) {
159
+ if (!astUtils.isCommaToken(token)) {
170
160
  return;
171
161
  }
172
162
 
@@ -179,8 +169,8 @@ module.exports = {
179
169
 
180
170
  validateCommaItemSpacing({
181
171
  comma: token,
182
- left: isComma(previousToken) || commaTokensToIgnore.indexOf(token) > -1 ? null : previousToken,
183
- right: isComma(nextToken) ? null : nextToken
172
+ left: astUtils.isCommaToken(previousToken) || commaTokensToIgnore.indexOf(token) > -1 ? null : previousToken,
173
+ right: astUtils.isCommaToken(nextToken) ? null : nextToken
184
174
  }, token);
185
175
  });
186
176
  },
@@ -63,16 +63,6 @@ module.exports = {
63
63
  // Helpers
64
64
  //--------------------------------------------------------------------------
65
65
 
66
- /**
67
- * Determines if a given token is a comma operator.
68
- * @param {ASTNode} token The token to check.
69
- * @returns {boolean} True if the token is a comma, false if not.
70
- * @private
71
- */
72
- function isComma(token) {
73
- return !!token && (token.type === "Punctuator") && (token.value === ",");
74
- }
75
-
76
66
  /**
77
67
  * Modified text based on the style
78
68
  * @param {string} styleType Style type
@@ -192,7 +182,7 @@ module.exports = {
192
182
  tokenBeforeComma = sourceCode.getTokenBefore(commaToken);
193
183
 
194
184
  // Check if previous token is wrapped in parentheses
195
- if (tokenBeforeComma && tokenBeforeComma.value === ")") {
185
+ if (tokenBeforeComma && astUtils.isClosingParenToken(tokenBeforeComma)) {
196
186
  previousItemToken = tokenBeforeComma;
197
187
  }
198
188
 
@@ -210,12 +200,16 @@ module.exports = {
210
200
  * All comparisons are done based on these tokens directly, so
211
201
  * they are always valid regardless of an undefined item.
212
202
  */
213
- if (isComma(commaToken)) {
203
+ if (astUtils.isCommaToken(commaToken)) {
214
204
  validateCommaItemSpacing(previousItemToken, commaToken,
215
205
  currentItemToken, reportItem);
216
206
  }
217
207
 
218
- previousItemToken = item ? sourceCode.getLastToken(item) : previousItemToken;
208
+ if (item) {
209
+ const tokenAfterItem = sourceCode.getTokenAfter(item, astUtils.isNotClosingParenToken);
210
+
211
+ previousItemToken = tokenAfterItem ? sourceCode.getTokenBefore(tokenAfterItem) : sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1];
212
+ }
219
213
  });
220
214
 
221
215
  /*
@@ -229,7 +223,7 @@ module.exports = {
229
223
  const lastToken = sourceCode.getLastToken(node),
230
224
  nextToLastToken = sourceCode.getTokenBefore(lastToken);
231
225
 
232
- if (isComma(nextToLastToken)) {
226
+ if (astUtils.isCommaToken(nextToLastToken)) {
233
227
  validateCommaItemSpacing(
234
228
  sourceCode.getTokenBefore(nextToLastToken),
235
229
  nextToLastToken,
@@ -76,7 +76,7 @@ module.exports = {
76
76
  function isCollapsedOneLiner(node) {
77
77
  const before = sourceCode.getTokenBefore(node);
78
78
  const last = sourceCode.getLastToken(node);
79
- const lastExcludingSemicolon = last.type === "Punctuator" && last.value === ";" ? sourceCode.getTokenBefore(last) : last;
79
+ const lastExcludingSemicolon = astUtils.isSemicolonToken(last) ? sourceCode.getTokenBefore(last) : last;
80
80
 
81
81
  return before.loc.start.line === lastExcludingSemicolon.loc.end.line;
82
82
  }
@@ -174,7 +174,7 @@ module.exports = {
174
174
  const tokenAfter = sourceCode.getTokenAfter(closingBracket);
175
175
  const lastBlockNode = sourceCode.getNodeByRangeIndex(tokenBefore.range[0]);
176
176
 
177
- if (tokenBefore.value === ";") {
177
+ if (astUtils.isSemicolonToken(tokenBefore)) {
178
178
 
179
179
  // If the last statement already has a semicolon, don't add another one.
180
180
  return false;
@@ -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
  //------------------------------------------------------------------------------
@@ -64,20 +70,20 @@ module.exports = {
64
70
  propertyValue: JSON.stringify(node.property.value)
65
71
  },
66
72
  fix(fixer) {
67
- const leftBracket = sourceCode.getTokenBefore(node.property);
68
- const rightBracket = sourceCode.getTokenAfter(node.property);
69
- const textBeforeProperty = sourceCode.text.slice(leftBracket.range[1], node.property.range[0]);
70
- const textAfterProperty = sourceCode.text.slice(node.property.range[1], rightBracket.range[0]);
73
+ const leftBracket = sourceCode.getTokenAfter(node.object, astUtils.isOpeningBracketToken);
74
+ const rightBracket = sourceCode.getLastToken(node);
71
75
 
72
- if (textBeforeProperty.trim() || textAfterProperty.trim()) {
76
+ if (sourceCode.getFirstTokenBetween(leftBracket, rightBracket, { includeComments: true, filter: astUtils.isCommentToken })) {
73
77
 
74
78
  // Don't perform any fixes if there are comments inside the brackets.
75
79
  return null;
76
80
  }
77
81
 
82
+ const textBeforeDot = astUtils.isDecimalInteger(node.object) ? " " : "";
83
+
78
84
  return fixer.replaceTextRange(
79
85
  [leftBracket.range[0], rightBracket.range[1]],
80
- `.${node.property.value}`
86
+ `${textBeforeDot}.${node.property.value}`
81
87
  );
82
88
  }
83
89
  });
@@ -74,7 +74,7 @@ module.exports = {
74
74
  const lastToken = sourceCode.getLastToken(node);
75
75
  const secondToLastToken = sourceCode.getTokenBefore(lastToken);
76
76
 
77
- return lastToken.type === "Punctuator" && lastToken.value === ";" && lastToken.loc.start.line > secondToLastToken.loc.end.line
77
+ return astUtils.isSemicolonToken(lastToken) && lastToken.loc.start.line > secondToLastToken.loc.end.line
78
78
  ? secondToLastToken
79
79
  : lastToken;
80
80
  }
@@ -6,28 +6,14 @@
6
6
  "use strict";
7
7
 
8
8
  //------------------------------------------------------------------------------
9
- // Helpers
9
+ // Requirements
10
10
  //------------------------------------------------------------------------------
11
11
 
12
- /**
13
- * Checks whether the given token is an opening parenthesis or not.
14
- *
15
- * @param {Token} token - The token to check.
16
- * @returns {boolean} `true` if the token is an opening parenthesis.
17
- */
18
- function isOpeningParen(token) {
19
- return token.type === "Punctuator" && token.value === "(";
20
- }
12
+ const astUtils = require("../ast-utils");
21
13
 
22
- /**
23
- * Checks whether the given token is an closing parenthesis or not.
24
- *
25
- * @param {Token} token - The token to check.
26
- * @returns {boolean} `true` if the token is an closing parenthesis.
27
- */
28
- function isClosingParen(token) {
29
- return token.type === "Punctuator" && token.value === ")";
30
- }
14
+ //------------------------------------------------------------------------------
15
+ // Helpers
16
+ //------------------------------------------------------------------------------
31
17
 
32
18
  //------------------------------------------------------------------------------
33
19
  // Rule Definition
@@ -56,8 +42,8 @@ module.exports = {
56
42
  }
57
43
 
58
44
  const lastToken = sourceCode.getLastToken(node);
59
- const hasLastParen = lastToken && isClosingParen(lastToken);
60
- const hasParens = hasLastParen && isOpeningParen(sourceCode.getTokenBefore(lastToken));
45
+ const hasLastParen = lastToken && astUtils.isClosingParenToken(lastToken);
46
+ const hasParens = hasLastParen && astUtils.isOpeningParenToken(sourceCode.getTokenBefore(lastToken));
61
47
 
62
48
  if (!hasParens) {
63
49
  context.report({
@@ -66,19 +66,6 @@ module.exports = {
66
66
  return null;
67
67
  }
68
68
 
69
- /**
70
- * Check whether the code represented by an AST node is enclosed in parentheses.
71
- * @param {!Object} node The node to test.
72
- * @returns {boolean} `true` if the code is enclosed in parentheses; otherwise, `false`.
73
- */
74
- function isParenthesised(node) {
75
- const previousToken = sourceCode.getTokenBefore(node),
76
- nextToken = sourceCode.getTokenAfter(node);
77
-
78
- return previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
79
- nextToken.value === ")" && nextToken.range[0] >= node.range[1];
80
- }
81
-
82
69
  /**
83
70
  * Check whether the code represented by an AST node is enclosed in two sets of parentheses.
84
71
  * @param {!Object} node The node to test.
@@ -88,9 +75,9 @@ module.exports = {
88
75
  const previousToken = sourceCode.getTokenBefore(node, 1),
89
76
  nextToken = sourceCode.getTokenAfter(node, 1);
90
77
 
91
- return isParenthesised(node) &&
92
- previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
93
- nextToken.value === ")" && nextToken.range[0] >= node.range[1];
78
+ return astUtils.isParenthesised(sourceCode, node) &&
79
+ astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
80
+ astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
94
81
  }
95
82
 
96
83
  /**
@@ -102,7 +89,7 @@ module.exports = {
102
89
  if (node.test &&
103
90
  (node.test.type === "AssignmentExpression") &&
104
91
  (node.type === "ForStatement"
105
- ? !isParenthesised(node.test)
92
+ ? !astUtils.isParenthesised(sourceCode, node.test)
106
93
  : !isParenthesisedTwice(node.test)
107
94
  )
108
95
  ) {
@@ -9,6 +9,7 @@
9
9
  // Requirements
10
10
  //------------------------------------------------------------------------------
11
11
 
12
+ const astUtils = require("../ast-utils");
12
13
  const FixTracker = require("../util/fix-tracker");
13
14
 
14
15
  //------------------------------------------------------------------------------
@@ -199,9 +200,11 @@ module.exports = {
199
200
  let consequents,
200
201
  alternate;
201
202
 
202
- // Only "top-level" if statements are checked, meaning the first `if`
203
- // in a `if-else-if-...` chain.
204
- if (parent.type === "IfStatement" && parent.alternate === node) {
203
+ /*
204
+ * Fixing this would require splitting one statement into two, so no error should
205
+ * be reported if this node is in a position where only one statement is allowed.
206
+ */
207
+ if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
205
208
  return;
206
209
  }
207
210