eslint 3.16.1 → 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 (86) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +1 -0
  3. package/conf/eslint-recommended.js +2 -0
  4. package/lib/ast-utils.js +3 -67
  5. package/lib/code-path-analysis/code-path-analyzer.js +2 -7
  6. package/lib/code-path-analysis/debug-helpers.js +17 -16
  7. package/lib/config/config-file.js +68 -38
  8. package/lib/config/config-rule.js +14 -10
  9. package/lib/config/plugins.js +19 -8
  10. package/lib/eslint.js +11 -10
  11. package/lib/formatters/codeframe.js +4 -9
  12. package/lib/formatters/stylish.js +5 -4
  13. package/lib/ignored-paths.js +6 -0
  14. package/lib/internal-rules/internal-no-invalid-meta.js +2 -40
  15. package/lib/rules/array-callback-return.js +15 -5
  16. package/lib/rules/arrow-body-style.js +2 -2
  17. package/lib/rules/arrow-parens.js +9 -3
  18. package/lib/rules/capitalized-comments.js +2 -1
  19. package/lib/rules/comma-dangle.js +3 -2
  20. package/lib/rules/comma-spacing.js +4 -14
  21. package/lib/rules/comma-style.js +8 -14
  22. package/lib/rules/complexity.js +14 -8
  23. package/lib/rules/consistent-return.js +17 -10
  24. package/lib/rules/curly.js +2 -2
  25. package/lib/rules/dot-notation.js +12 -6
  26. package/lib/rules/func-name-matching.js +18 -7
  27. package/lib/rules/func-names.js +20 -5
  28. package/lib/rules/keyword-spacing.js +19 -4
  29. package/lib/rules/line-comment-position.js +15 -5
  30. package/lib/rules/lines-around-comment.js +19 -0
  31. package/lib/rules/lines-around-directive.js +1 -1
  32. package/lib/rules/max-params.js +17 -4
  33. package/lib/rules/max-statements.js +11 -10
  34. package/lib/rules/new-parens.js +7 -21
  35. package/lib/rules/no-compare-neg-zero.js +53 -0
  36. package/lib/rules/no-cond-assign.js +4 -17
  37. package/lib/rules/no-else-return.js +19 -4
  38. package/lib/rules/no-empty-function.js +9 -16
  39. package/lib/rules/no-extra-parens.js +110 -121
  40. package/lib/rules/no-extra-semi.js +16 -3
  41. package/lib/rules/no-global-assign.js +1 -1
  42. package/lib/rules/no-implicit-coercion.js +21 -8
  43. package/lib/rules/no-invalid-regexp.js +2 -1
  44. package/lib/rules/no-multiple-empty-lines.js +2 -4
  45. package/lib/rules/no-native-reassign.js +1 -1
  46. package/lib/rules/no-negated-in-lhs.js +1 -1
  47. package/lib/rules/no-new-func.js +6 -8
  48. package/lib/rules/no-new.js +2 -6
  49. package/lib/rules/no-param-reassign.js +37 -7
  50. package/lib/rules/no-process-exit.js +2 -10
  51. package/lib/rules/no-restricted-properties.js +2 -0
  52. package/lib/rules/no-restricted-syntax.js +32 -21
  53. package/lib/rules/no-return-await.js +1 -1
  54. package/lib/rules/no-sequences.js +2 -2
  55. package/lib/rules/no-sync.js +8 -13
  56. package/lib/rules/no-unsafe-negation.js +1 -1
  57. package/lib/rules/no-unused-expressions.js +10 -1
  58. package/lib/rules/no-unused-vars.js +12 -12
  59. package/lib/rules/no-use-before-define.js +1 -1
  60. package/lib/rules/no-useless-computed-key.js +12 -1
  61. package/lib/rules/no-useless-escape.js +8 -2
  62. package/lib/rules/no-useless-return.js +13 -2
  63. package/lib/rules/nonblock-statement-body-position.js +114 -0
  64. package/lib/rules/object-curly-spacing.js +2 -2
  65. package/lib/rules/object-shorthand.js +10 -3
  66. package/lib/rules/operator-assignment.js +20 -3
  67. package/lib/rules/padded-blocks.js +37 -31
  68. package/lib/rules/prefer-const.js +1 -1
  69. package/lib/rules/prefer-destructuring.js +1 -1
  70. package/lib/rules/quotes.js +1 -0
  71. package/lib/rules/semi-spacing.js +2 -15
  72. package/lib/rules/semi.js +17 -13
  73. package/lib/rules/sort-vars.js +3 -5
  74. package/lib/rules/space-before-function-paren.js +53 -77
  75. package/lib/rules/space-in-parens.js +4 -8
  76. package/lib/rules/space-unary-ops.js +19 -1
  77. package/lib/rules/strict.js +8 -2
  78. package/lib/rules/yoda.js +2 -2
  79. package/lib/testers/rule-tester.js +44 -13
  80. package/lib/util/fix-tracker.js +121 -0
  81. package/lib/util/glob-util.js +1 -1
  82. package/lib/util/node-event-generator.js +274 -4
  83. package/lib/util/source-code-fixer.js +3 -9
  84. package/lib/util/source-code.js +99 -2
  85. package/lib/util/traverser.js +16 -25
  86. package/package.json +34 -34
@@ -94,16 +94,6 @@ function hasMetaSchema(metaPropertyNode) {
94
94
  return getPropertyFromObject("schema", metaPropertyNode.value);
95
95
  }
96
96
 
97
- /**
98
- * Whether this `meta` ObjectExpression has a `fixable` property defined or not.
99
- *
100
- * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
101
- * @returns {boolean} `true` if a `fixable` property exists.
102
- */
103
- function hasMetaFixable(metaPropertyNode) {
104
- return getPropertyFromObject("fixable", metaPropertyNode.value);
105
- }
106
-
107
97
  /**
108
98
  * Checks the validity of the meta definition of this rule and reports any errors found.
109
99
  *
@@ -112,7 +102,7 @@ function hasMetaFixable(metaPropertyNode) {
112
102
  * @param {boolean} ruleIsFixable whether the rule is fixable or not.
113
103
  * @returns {void}
114
104
  */
115
- function checkMetaValidity(context, exportsNode, ruleIsFixable) {
105
+ function checkMetaValidity(context, exportsNode) {
116
106
  const metaProperty = getMetaPropertyFromExportsNode(exportsNode);
117
107
 
118
108
  if (!metaProperty) {
@@ -142,11 +132,6 @@ function checkMetaValidity(context, exportsNode, ruleIsFixable) {
142
132
 
143
133
  if (!hasMetaSchema(metaProperty)) {
144
134
  context.report(metaProperty, "Rule is missing a meta.schema property.");
145
- return;
146
- }
147
-
148
- if (ruleIsFixable && !hasMetaFixable(metaProperty)) {
149
- context.report(metaProperty, "Rule is fixable, but is missing a meta.fixable property.");
150
135
  }
151
136
  }
152
137
 
@@ -177,7 +162,6 @@ module.exports = {
177
162
 
178
163
  create(context) {
179
164
  let exportsNode;
180
- let ruleIsFixable = false;
181
165
 
182
166
  return {
183
167
  AssignmentExpression(node) {
@@ -191,35 +175,13 @@ module.exports = {
191
175
  }
192
176
  },
193
177
 
194
- CallExpression(node) {
195
-
196
- // If the rule has a call for `context.report` and a property `fix`
197
- // is being passed in, then we consider that the rule is fixable.
198
- //
199
- // Note that we only look for context.report() calls in the new
200
- // style (with single MessageDescriptor argument), because only
201
- // calls in the new style can specify a fix.
202
- if (node.callee.type === "MemberExpression" &&
203
- node.callee.object.type === "Identifier" &&
204
- node.callee.object.name === "context" &&
205
- node.callee.property.type === "Identifier" &&
206
- node.callee.property.name === "report" &&
207
- node.arguments.length === 1 &&
208
- node.arguments[0].type === "ObjectExpression") {
209
-
210
- if (getPropertyFromObject("fix", node.arguments[0])) {
211
- ruleIsFixable = true;
212
- }
213
- }
214
- },
215
-
216
178
  "Program:exit"() {
217
179
  if (!isCorrectExportsFormat(exportsNode)) {
218
180
  context.report({ node: exportsNode, message: "Rule does not export an Object. Make sure the rule follows the new rule format." });
219
181
  return;
220
182
  }
221
183
 
222
- checkMetaValidity(context, exportsNode, ruleIsFixable);
184
+ checkMetaValidity(context, exportsNode);
223
185
  }
224
186
  };
225
187
  }
@@ -9,6 +9,8 @@
9
9
  // Requirements
10
10
  //------------------------------------------------------------------------------
11
11
 
12
+ const lodash = require("lodash");
13
+
12
14
  const astUtils = require("../ast-utils");
13
15
 
14
16
  //------------------------------------------------------------------------------
@@ -147,7 +149,8 @@ module.exports = {
147
149
  upper: null,
148
150
  codePath: null,
149
151
  hasReturn: false,
150
- shouldCheck: false
152
+ shouldCheck: false,
153
+ node: null
151
154
  };
152
155
 
153
156
  /**
@@ -168,8 +171,11 @@ module.exports = {
168
171
  node,
169
172
  loc: getLocation(node, context.getSourceCode()).loc.start,
170
173
  message: funcInfo.hasReturn
171
- ? "Expected to return a value at the end of this function."
172
- : "Expected to return a value in this function."
174
+ ? "Expected to return a value at the end of {{name}}."
175
+ : "Expected to return a value in {{name}}.",
176
+ data: {
177
+ name: astUtils.getFunctionNameWithKind(funcInfo.node)
178
+ }
173
179
  });
174
180
  }
175
181
  }
@@ -187,7 +193,8 @@ module.exports = {
187
193
  node.body.type === "BlockStatement" &&
188
194
  isCallbackOfArrayMethod(node) &&
189
195
  !node.async &&
190
- !node.generator
196
+ !node.generator,
197
+ node
191
198
  };
192
199
  },
193
200
 
@@ -204,7 +211,10 @@ module.exports = {
204
211
  if (!node.argument) {
205
212
  context.report({
206
213
  node,
207
- message: "Expected a return value."
214
+ message: "{{name}} expected a return value.",
215
+ data: {
216
+ name: lodash.upperFirst(astUtils.getFunctionNameWithKind(funcInfo.node))
217
+ }
208
218
  });
209
219
  }
210
220
  }
@@ -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,
@@ -9,6 +9,7 @@
9
9
  //------------------------------------------------------------------------------
10
10
 
11
11
  const LETTER_PATTERN = require("../util/patterns/letters");
12
+ const astUtils = require("../ast-utils");
12
13
 
13
14
  //------------------------------------------------------------------------------
14
15
  // Helpers
@@ -16,7 +17,7 @@ const LETTER_PATTERN = require("../util/patterns/letters");
16
17
 
17
18
  const ALWAYS_MESSAGE = "Comments should not begin with a lowercase character",
18
19
  NEVER_MESSAGE = "Comments should not begin with an uppercase character",
19
- DEFAULT_IGNORE_PATTERN = /^\s*(?:eslint|istanbul|jscs|jshint|globals?|exported)\b/,
20
+ DEFAULT_IGNORE_PATTERN = astUtils.COMMENTS_IGNORE_PATTERN,
20
21
  WHITESPACE = /\s/g,
21
22
  MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/, // TODO: Combine w/ max-len pattern?
22
23
  DEFAULTS = {
@@ -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,
@@ -6,6 +6,14 @@
6
6
 
7
7
  "use strict";
8
8
 
9
+ //------------------------------------------------------------------------------
10
+ // Requirements
11
+ //------------------------------------------------------------------------------
12
+
13
+ const lodash = require("lodash");
14
+
15
+ const astUtils = require("../ast-utils");
16
+
9
17
  //------------------------------------------------------------------------------
10
18
  // Rule Definition
11
19
  //------------------------------------------------------------------------------
@@ -81,17 +89,15 @@ module.exports = {
81
89
  * @private
82
90
  */
83
91
  function endFunction(node) {
92
+ const name = lodash.upperFirst(astUtils.getFunctionNameWithKind(node));
84
93
  const complexity = fns.pop();
85
- let name = "anonymous";
86
-
87
- if (node.id) {
88
- name = node.id.name;
89
- } else if (node.parent.type === "MethodDefinition" || node.parent.type === "Property") {
90
- name = node.parent.key.name;
91
- }
92
94
 
93
95
  if (complexity > THRESHOLD) {
94
- context.report({ node, message: "Function '{{name}}' has a complexity of {{complexity}}.", data: { name, complexity } });
96
+ context.report({
97
+ node,
98
+ message: "{{name}} has a complexity of {{complexity}}.",
99
+ data: { name, complexity }
100
+ });
95
101
  }
96
102
  }
97
103
 
@@ -8,6 +8,8 @@
8
8
  // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
+ const lodash = require("lodash");
12
+
11
13
  const astUtils = require("../ast-utils");
12
14
 
13
15
  //------------------------------------------------------------------------------
@@ -81,7 +83,7 @@ module.exports = {
81
83
  * @returns {void}
82
84
  */
83
85
  function checkLastSegment(node) {
84
- let loc, type;
86
+ let loc, name;
85
87
 
86
88
  /*
87
89
  * Skip if it expected no return value or unreachable.
@@ -100,12 +102,11 @@ module.exports = {
100
102
 
101
103
  // The head of program.
102
104
  loc = { line: 1, column: 0 };
103
- type = "program";
105
+ name = "program";
104
106
  } else if (node.type === "ArrowFunctionExpression") {
105
107
 
106
108
  // `=>` token
107
109
  loc = context.getSourceCode().getTokenBefore(node.body, astUtils.isArrowToken).loc.start;
108
- type = "function";
109
110
  } else if (
110
111
  node.parent.type === "MethodDefinition" ||
111
112
  (node.parent.type === "Property" && node.parent.method)
@@ -113,33 +114,36 @@ module.exports = {
113
114
 
114
115
  // Method name.
115
116
  loc = node.parent.key.loc.start;
116
- type = "method";
117
117
  } else {
118
118
 
119
119
  // Function name or `function` keyword.
120
120
  loc = (node.id || node).loc.start;
121
- type = "function";
121
+ }
122
+
123
+ if (!name) {
124
+ name = astUtils.getFunctionNameWithKind(node);
122
125
  }
123
126
 
124
127
  // Reports.
125
128
  context.report({
126
129
  node,
127
130
  loc,
128
- message: "Expected to return a value at the end of this {{type}}.",
129
- data: { type }
131
+ message: "Expected to return a value at the end of {{name}}.",
132
+ data: { name }
130
133
  });
131
134
  }
132
135
 
133
136
  return {
134
137
 
135
138
  // Initializes/Disposes state of each code path.
136
- onCodePathStart(codePath) {
139
+ onCodePathStart(codePath, node) {
137
140
  funcInfo = {
138
141
  upper: funcInfo,
139
142
  codePath,
140
143
  hasReturn: false,
141
144
  hasReturnValue: false,
142
- message: ""
145
+ message: "",
146
+ node
143
147
  };
144
148
  },
145
149
  onCodePathEnd() {
@@ -158,8 +162,11 @@ module.exports = {
158
162
  if (!funcInfo.hasReturn) {
159
163
  funcInfo.hasReturn = true;
160
164
  funcInfo.hasReturnValue = hasReturnValue;
161
- funcInfo.message = "Expected {{which}} return value.";
165
+ funcInfo.message = "{{name}} expected {{which}} return value.";
162
166
  funcInfo.data = {
167
+ name: funcInfo.node.type === "Program"
168
+ ? "Program"
169
+ : lodash.upperFirst(astUtils.getFunctionNameWithKind(funcInfo.node)),
163
170
  which: hasReturnValue ? "a" : "no"
164
171
  };
165
172
  } else if (funcInfo.hasReturnValue !== hasReturnValue) {
@@ -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
  });
@@ -132,6 +132,15 @@ module.exports = {
132
132
  });
133
133
  }
134
134
 
135
+ /**
136
+ * Determines whether a given node is a string literal
137
+ * @param {ASTNode} node The node to check
138
+ * @returns {boolean} `true` if the node is a string literal
139
+ */
140
+ function isStringLiteral(node) {
141
+ return node.type === "Literal" && typeof node.value === "string";
142
+ }
143
+
135
144
  //--------------------------------------------------------------------------
136
145
  // Public
137
146
  //--------------------------------------------------------------------------
@@ -139,7 +148,7 @@ module.exports = {
139
148
  return {
140
149
 
141
150
  VariableDeclarator(node) {
142
- if (!node.init || node.init.type !== "FunctionExpression") {
151
+ if (!node.init || node.init.type !== "FunctionExpression" || node.id.type !== "Identifier") {
143
152
  return;
144
153
  }
145
154
  if (node.init.id && shouldWarn(node.id.name, node.init.id.name)) {
@@ -148,10 +157,12 @@ module.exports = {
148
157
  },
149
158
 
150
159
  AssignmentExpression(node) {
151
- if (node.right.type !== "FunctionExpression" ||
152
- (node.left.computed && node.left.property.type !== "Literal") ||
153
- (!includeModuleExports && isModuleExports(node.left))
154
- ) {
160
+ if (
161
+ node.right.type !== "FunctionExpression" ||
162
+ (node.left.computed && node.left.property.type !== "Literal") ||
163
+ (!includeModuleExports && isModuleExports(node.left)) ||
164
+ (node.left.type !== "Identifier" && node.left.type !== "MemberExpression")
165
+ ) {
155
166
  return;
156
167
  }
157
168
 
@@ -164,13 +175,13 @@ module.exports = {
164
175
  },
165
176
 
166
177
  Property(node) {
167
- if (node.value.type !== "FunctionExpression" || !node.value.id || node.computed && node.key.type !== "Literal") {
178
+ if (node.value.type !== "FunctionExpression" || !node.value.id || node.computed && !isStringLiteral(node.key)) {
168
179
  return;
169
180
  }
170
181
  if (node.key.type === "Identifier" && shouldWarn(node.key.name, node.value.id.name)) {
171
182
  report(node, node.key.name, node.value.id.name, true);
172
183
  } else if (
173
- node.key.type === "Literal" &&
184
+ isStringLiteral(node.key) &&
174
185
  isIdentifier(node.key.value, ecmaVersion) &&
175
186
  shouldWarn(node.key.value, node.value.id.name)
176
187
  ) {
@@ -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
  * Checks whether or not a given variable is a function name.
10
16
  * @param {escope.Variable} variable - A variable to check.
@@ -82,15 +88,24 @@ module.exports = {
82
88
  return;
83
89
  }
84
90
 
85
- const name = node.id && node.id.name;
91
+ const hasName = Boolean(node.id && node.id.name);
92
+ const name = astUtils.getFunctionNameWithKind(node);
86
93
 
87
94
  if (never) {
88
- if (name) {
89
- context.report({ node, message: "Unexpected function expression name." });
95
+ if (hasName) {
96
+ context.report({
97
+ node,
98
+ message: "Unexpected named {{name}}.",
99
+ data: { name }
100
+ });
90
101
  }
91
102
  } else {
92
- if (!name && (asNeeded ? !hasInferredName(node) : !isObjectOrClassMethod(node))) {
93
- context.report({ node, message: "Missing function expression name." });
103
+ if (!hasName && (asNeeded ? !hasInferredName(node) : !isObjectOrClassMethod(node))) {
104
+ context.report({
105
+ node,
106
+ message: "Unexpected unnamed {{name}}.",
107
+ data: { name }
108
+ });
94
109
  }
95
110
  }
96
111
  }
@@ -359,7 +359,8 @@ module.exports = {
359
359
  const firstToken = node && sourceCode.getFirstToken(node);
360
360
 
361
361
  if (firstToken &&
362
- (firstToken.type === "Keyword" || firstToken.value === "async")
362
+ ((firstToken.type === "Keyword" && firstToken.value === "function") ||
363
+ firstToken.value === "async")
363
364
  ) {
364
365
  checkSpacingBefore(firstToken);
365
366
  }
@@ -495,11 +496,25 @@ module.exports = {
495
496
  node.value.async
496
497
  )
497
498
  ) {
498
- const token = sourceCode.getFirstToken(
499
- node,
500
- node.static ? 1 : 0
499
+ const token = sourceCode.getTokenBefore(
500
+ node.key,
501
+ tok => {
502
+ switch (tok.value) {
503
+ case "get":
504
+ case "set":
505
+ case "async":
506
+ return true;
507
+ default:
508
+ return false;
509
+ }
510
+ }
501
511
  );
502
512
 
513
+ if (!token) {
514
+ throw new Error("Failed to find token get, set, or async beside method name");
515
+ }
516
+
517
+
503
518
  checkSpacingAround(token);
504
519
  }
505
520
  }