eslint 3.15.0 → 3.17.1

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 (118) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/conf/{eslint.json → eslint-recommended.js} +87 -71
  3. package/lib/ast-utils.js +182 -80
  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/internal-rules/internal-no-invalid-meta.js +2 -40
  11. package/lib/rules/array-callback-return.js +15 -5
  12. package/lib/rules/arrow-body-style.js +7 -4
  13. package/lib/rules/arrow-spacing.js +7 -6
  14. package/lib/rules/block-spacing.js +2 -2
  15. package/lib/rules/brace-style.js +2 -6
  16. package/lib/rules/capitalized-comments.js +8 -7
  17. package/lib/rules/comma-spacing.js +3 -3
  18. package/lib/rules/complexity.js +14 -8
  19. package/lib/rules/consistent-return.js +18 -11
  20. package/lib/rules/constructor-super.js +3 -3
  21. package/lib/rules/curly.js +11 -7
  22. package/lib/rules/default-case.js +3 -3
  23. package/lib/rules/eqeqeq.js +15 -6
  24. package/lib/rules/func-call-spacing.js +10 -13
  25. package/lib/rules/func-names.js +20 -5
  26. package/lib/rules/generator-star-spacing.js +18 -19
  27. package/lib/rules/id-blacklist.js +2 -2
  28. package/lib/rules/id-length.js +3 -3
  29. package/lib/rules/id-match.js +2 -2
  30. package/lib/rules/indent.js +7 -6
  31. package/lib/rules/key-spacing.js +12 -16
  32. package/lib/rules/keyword-spacing.js +21 -17
  33. package/lib/rules/line-comment-position.js +16 -6
  34. package/lib/rules/linebreak-style.js +7 -1
  35. package/lib/rules/lines-around-comment.js +23 -4
  36. package/lib/rules/lines-around-directive.js +3 -3
  37. package/lib/rules/max-lines.js +2 -2
  38. package/lib/rules/max-params.js +17 -4
  39. package/lib/rules/max-statements-per-line.js +7 -6
  40. package/lib/rules/max-statements.js +11 -10
  41. package/lib/rules/newline-after-var.js +7 -2
  42. package/lib/rules/newline-per-chained-call.js +3 -1
  43. package/lib/rules/no-compare-neg-zero.js +53 -0
  44. package/lib/rules/no-cond-assign.js +3 -3
  45. package/lib/rules/no-else-return.js +13 -1
  46. package/lib/rules/no-empty-function.js +9 -16
  47. package/lib/rules/no-extend-native.js +3 -3
  48. package/lib/rules/no-extra-bind.js +3 -4
  49. package/lib/rules/no-extra-boolean-cast.js +8 -0
  50. package/lib/rules/no-extra-parens.js +1 -2
  51. package/lib/rules/no-extra-semi.js +13 -1
  52. package/lib/rules/no-inner-declarations.js +4 -4
  53. package/lib/rules/no-invalid-regexp.js +2 -1
  54. package/lib/rules/no-irregular-whitespace.js +7 -1
  55. package/lib/rules/no-lone-blocks.js +10 -10
  56. package/lib/rules/no-mixed-operators.js +1 -7
  57. package/lib/rules/no-multi-spaces.js +4 -1
  58. package/lib/rules/no-multi-str.js +7 -3
  59. package/lib/rules/no-multiple-empty-lines.js +2 -4
  60. package/lib/rules/no-param-reassign.js +29 -6
  61. package/lib/rules/no-restricted-properties.js +2 -0
  62. package/lib/rules/no-return-assign.js +7 -14
  63. package/lib/rules/no-return-await.js +1 -1
  64. package/lib/rules/no-sequences.js +7 -6
  65. package/lib/rules/no-trailing-spaces.js +8 -2
  66. package/lib/rules/no-undefined.js +45 -6
  67. package/lib/rules/no-unexpected-multiline.js +9 -8
  68. package/lib/rules/no-unneeded-ternary.js +5 -1
  69. package/lib/rules/no-unused-labels.js +17 -2
  70. package/lib/rules/no-unused-vars.js +13 -27
  71. package/lib/rules/no-use-before-define.js +1 -1
  72. package/lib/rules/no-useless-computed-key.js +8 -3
  73. package/lib/rules/no-useless-concat.js +10 -7
  74. package/lib/rules/no-useless-escape.js +2 -2
  75. package/lib/rules/no-useless-return.js +14 -9
  76. package/lib/rules/no-var.js +1 -3
  77. package/lib/rules/no-whitespace-before-property.js +5 -16
  78. package/lib/rules/nonblock-statement-body-position.js +114 -0
  79. package/lib/rules/object-curly-newline.js +2 -2
  80. package/lib/rules/object-curly-spacing.js +7 -25
  81. package/lib/rules/object-property-newline.js +3 -3
  82. package/lib/rules/object-shorthand.js +4 -3
  83. package/lib/rules/operator-assignment.js +2 -2
  84. package/lib/rules/operator-linebreak.js +8 -10
  85. package/lib/rules/padded-blocks.js +39 -30
  86. package/lib/rules/prefer-destructuring.js +1 -1
  87. package/lib/rules/prefer-spread.js +1 -1
  88. package/lib/rules/prefer-template.js +1 -1
  89. package/lib/rules/quotes.js +10 -6
  90. package/lib/rules/semi-spacing.js +4 -0
  91. package/lib/rules/semi.js +13 -1
  92. package/lib/rules/space-before-function-paren.js +8 -5
  93. package/lib/rules/space-unary-ops.js +19 -1
  94. package/lib/rules/spaced-comment.js +2 -2
  95. package/lib/rules/strict.js +10 -4
  96. package/lib/rules/unicode-bom.js +1 -1
  97. package/lib/rules/wrap-iife.js +5 -5
  98. package/lib/rules/yoda.js +4 -9
  99. package/lib/testers/rule-tester.js +46 -9
  100. package/lib/token-store/backward-token-comment-cursor.js +57 -0
  101. package/lib/token-store/backward-token-cursor.js +56 -0
  102. package/lib/token-store/cursor.js +76 -0
  103. package/lib/token-store/cursors.js +92 -0
  104. package/lib/token-store/decorative-cursor.js +39 -0
  105. package/lib/token-store/filter-cursor.js +43 -0
  106. package/lib/token-store/forward-token-comment-cursor.js +57 -0
  107. package/lib/token-store/forward-token-cursor.js +61 -0
  108. package/lib/token-store/index.js +604 -0
  109. package/lib/token-store/limit-cursor.js +40 -0
  110. package/lib/token-store/padded-token-cursor.js +38 -0
  111. package/lib/token-store/skip-cursor.js +42 -0
  112. package/lib/token-store/utils.js +100 -0
  113. package/lib/util/fix-tracker.js +121 -0
  114. package/lib/util/source-code-fixer.js +35 -39
  115. package/lib/util/source-code.js +129 -16
  116. package/messages/extend-config-missing.txt +3 -0
  117. package/package.json +5 -6
  118. package/lib/token-store.js +0 -203
@@ -13,7 +13,7 @@ const lodash = require("lodash"),
13
13
  eslint = require("../eslint"),
14
14
  configRule = require("./config-rule"),
15
15
  ConfigOps = require("./config-ops"),
16
- recConfig = require("../../conf/eslint.json");
16
+ recConfig = require("../../conf/eslint-recommended");
17
17
 
18
18
  const debug = require("debug")("eslint:autoconfig");
19
19
 
@@ -300,8 +300,8 @@ class Registry {
300
300
  // (https://github.com/eslint/eslint/issues/5992)
301
301
  // (https://github.com/eslint/eslint/issues/7860)
302
302
  if (
303
- lintedRegistry.rules[result.ruleId]
304
- && lintedRegistry.rules[result.ruleId][ruleSetIdx]
303
+ lintedRegistry.rules[result.ruleId] &&
304
+ lintedRegistry.rules[result.ruleId][ruleSetIdx]
305
305
  ) {
306
306
  lintedRegistry.rules[result.ruleId][ruleSetIdx].errorCount += 1;
307
307
  }
@@ -23,7 +23,7 @@ const fs = require("fs"),
23
23
  stripBom = require("strip-bom"),
24
24
  stripComments = require("strip-json-comments"),
25
25
  stringify = require("json-stable-stringify"),
26
- defaultOptions = require("../../conf/eslint.json"),
26
+ defaultOptions = require("../../conf/eslint-recommended"),
27
27
  requireUncached = require("require-uncached");
28
28
 
29
29
  const debug = require("debug")("eslint:config-file");
@@ -364,10 +364,10 @@ function applyExtends(config, filePath, relativeTo) {
364
364
  if (parentPath === "eslint:recommended") {
365
365
 
366
366
  /*
367
- * Add an explicit substitution for eslint:recommended to conf/eslint.json
368
- * this lets us use the eslint.json file as the recommended rules
367
+ * Add an explicit substitution for eslint:recommended to
368
+ * conf/eslint-recommended.js.
369
369
  */
370
- parentPath = path.resolve(__dirname, "../../conf/eslint.json");
370
+ parentPath = path.resolve(__dirname, "../../conf/eslint-recommended.js");
371
371
  } else if (parentPath === "eslint:all") {
372
372
 
373
373
  /*
@@ -380,9 +380,9 @@ function applyExtends(config, filePath, relativeTo) {
380
380
  * If the `extends` path is relative, use the directory of the current configuration
381
381
  * file as the reference point. Otherwise, use as-is.
382
382
  */
383
- parentPath = (!path.isAbsolute(parentPath) ?
384
- path.join(relativeTo || path.dirname(filePath), parentPath) :
385
- parentPath
383
+ parentPath = (!path.isAbsolute(parentPath)
384
+ ? path.join(relativeTo || path.dirname(filePath), parentPath)
385
+ : parentPath
386
386
  );
387
387
  }
388
388
 
@@ -390,6 +390,13 @@ function applyExtends(config, filePath, relativeTo) {
390
390
  debug(`Loading ${parentPath}`);
391
391
  return ConfigOps.merge(load(parentPath, false, relativeTo), previousValue);
392
392
  } catch (e) {
393
+ if (parentPath.indexOf("plugin:") === 0 || parentPath.indexOf("eslint:") === 0) {
394
+ e.message = `Failed to load config "${parentPath}" to extend from.`;
395
+ e.messageTemplate = "extend-config-missing";
396
+ e.messageData = {
397
+ configName: parentPath
398
+ };
399
+ }
393
400
 
394
401
  /*
395
402
  * If the file referenced by `extends` failed to load, add the path
@@ -17,7 +17,7 @@ const util = require("util"),
17
17
  ConfigOps = require("./config-ops"),
18
18
  getSourceCodeOfFiles = require("../util/source-code-util").getSourceCodeOfFiles,
19
19
  npmUtil = require("../util/npm-util"),
20
- recConfig = require("../../conf/eslint.json"),
20
+ recConfig = require("../../conf/eslint-recommended"),
21
21
  log = require("../logging");
22
22
 
23
23
  const debug = require("debug")("eslint:config-initializer");
package/lib/config.js CHANGED
@@ -234,8 +234,9 @@ class Config {
234
234
  }
235
235
 
236
236
  /**
237
- * Build a config object merging the base config (conf/eslint.json), the
238
- * environments config (conf/environments.js) and eventually the user config.
237
+ * Build a config object merging the base config (conf/eslint-recommended),
238
+ * the environments config (conf/environments.js) and eventually the user
239
+ * config.
239
240
  * @param {string} filePath a file in whose directory we start looking for a local config
240
241
  * @returns {Object} config object
241
242
  */
package/lib/eslint.js CHANGED
@@ -14,7 +14,7 @@ const assert = require("assert"),
14
14
  escope = require("escope"),
15
15
  levn = require("levn"),
16
16
  blankScriptAST = require("../conf/blank-script.json"),
17
- DEFAULT_PARSER = require("../conf/eslint.json").parser,
17
+ DEFAULT_PARSER = require("../conf/eslint-recommended").parser,
18
18
  replacements = require("../conf/replacements.json"),
19
19
  CodePathAnalyzer = require("./code-path-analysis/code-path-analyzer"),
20
20
  ConfigOps = require("./config/config-ops"),
@@ -864,8 +864,8 @@ module.exports = (function() {
864
864
  (parseResult && parseResult.services ? parseResult.services : {})
865
865
  );
866
866
 
867
- const rule = ruleCreator.create ? ruleCreator.create(ruleContext) :
868
- ruleCreator(ruleContext);
867
+ const rule = ruleCreator.create ? ruleCreator.create(ruleContext)
868
+ : ruleCreator(ruleContext);
869
869
 
870
870
  // add all the node types as listeners
871
871
  Object.keys(rule).forEach(nodeType => {
@@ -1192,7 +1192,7 @@ module.exports = (function() {
1192
1192
  * @returns {Object} Object mapping rule IDs to their default configurations
1193
1193
  */
1194
1194
  api.defaults = function() {
1195
- return require("../conf/eslint.json");
1195
+ return require("../conf/eslint-recommended");
1196
1196
  };
1197
1197
 
1198
1198
  /**
@@ -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
  }
@@ -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
  //------------------------------------------------------------------------------
@@ -136,10 +142,7 @@ module.exports = {
136
142
  loc: arrowBody.loc.start,
137
143
  message: "Expected block statement surrounding arrow body.",
138
144
  fix(fixer) {
139
- const lastTokenBeforeBody = sourceCode.getTokensBetween(sourceCode.getFirstToken(node), arrowBody)
140
- .reverse()
141
- .find(token => token.value !== "(");
142
-
145
+ const lastTokenBeforeBody = sourceCode.getLastTokenBetween(sourceCode.getFirstToken(node), arrowBody, astUtils.isNotOpeningParenToken);
143
146
  const firstBodyToken = sourceCode.getTokenAfter(lastTokenBeforeBody);
144
147
 
145
148
  return fixer.replaceTextRange(
@@ -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
  //------------------------------------------------------------------------------
@@ -51,12 +57,7 @@ module.exports = {
51
57
  * @returns {Object} Tokens of arrow and before/after arrow.
52
58
  */
53
59
  function getTokens(node) {
54
- let arrow = sourceCode.getTokenBefore(node.body);
55
-
56
- // skip '(' tokens.
57
- while (arrow.value !== "=>") {
58
- arrow = sourceCode.getTokenBefore(arrow);
59
- }
60
+ const arrow = sourceCode.getTokenBefore(node.body, astUtils.isArrowToken);
60
61
 
61
62
  return {
62
63
  before: sourceCode.getTokenBefore(arrow),
@@ -74,8 +74,8 @@ module.exports = {
74
74
  // Gets braces and the first/last token of content.
75
75
  const openBrace = getOpenBrace(node);
76
76
  const closeBrace = sourceCode.getLastToken(node);
77
- const firstToken = sourceCode.getTokenOrCommentAfter(openBrace);
78
- const lastToken = sourceCode.getTokenOrCommentBefore(closeBrace);
77
+ const firstToken = sourceCode.getTokenAfter(openBrace, { includeComments: true });
78
+ const lastToken = sourceCode.getTokenBefore(closeBrace, { includeComments: true });
79
79
 
80
80
  // Skip if the node is invalid or empty.
81
81
  if (openBrace.type !== "Punctuator" ||
@@ -62,7 +62,7 @@ module.exports = {
62
62
  function removeNewlineBetween(firstToken, secondToken) {
63
63
  const textRange = [firstToken.range[1], secondToken.range[0]];
64
64
  const textBetween = sourceCode.text.slice(textRange[0], textRange[1]);
65
- const NEWLINE_REGEX = /\r\n|\r|\n|\u2028|\u2029/g;
65
+ const NEWLINE_REGEX = astUtils.createGlobalLinebreakMatcher();
66
66
 
67
67
  // Don't do a fix if there is a comment between the tokens
68
68
  return fixer => fixer.replaceTextRange(textRange, textBetween.trim() ? null : textBetween.replace(NEWLINE_REGEX, ""));
@@ -144,11 +144,7 @@ module.exports = {
144
144
 
145
145
  return {
146
146
  BlockStatement(node) {
147
- if (
148
- node.parent.type !== "BlockStatement" &&
149
- node.parent.type !== "SwitchCase" &&
150
- node.parent.type !== "Program"
151
- ) {
147
+ if (!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)) {
152
148
  validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
153
149
  }
154
150
  },
@@ -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 = {
@@ -163,8 +164,8 @@ module.exports = {
163
164
  * otherwise.
164
165
  */
165
166
  function isInlineComment(comment) {
166
- const previousToken = sourceCode.getTokenOrCommentBefore(comment),
167
- nextToken = sourceCode.getTokenOrCommentAfter(comment);
167
+ const previousToken = sourceCode.getTokenBefore(comment, { includeComments: true }),
168
+ nextToken = sourceCode.getTokenAfter(comment, { includeComments: true });
168
169
 
169
170
  return Boolean(
170
171
  previousToken &&
@@ -181,7 +182,7 @@ module.exports = {
181
182
  * @returns {boolean} True if the comment follows a valid comment.
182
183
  */
183
184
  function isConsecutiveComment(comment) {
184
- const previousTokenOrComment = sourceCode.getTokenOrCommentBefore(comment);
185
+ const previousTokenOrComment = sourceCode.getTokenBefore(comment, { includeComments: true });
185
186
 
186
187
  return Boolean(
187
188
  previousTokenOrComment &&
@@ -264,9 +265,9 @@ module.exports = {
264
265
  commentValid = isCommentValid(comment, options);
265
266
 
266
267
  if (!commentValid) {
267
- const message = capitalize === "always" ?
268
- ALWAYS_MESSAGE :
269
- NEVER_MESSAGE;
268
+ const message = capitalize === "always"
269
+ ? ALWAYS_MESSAGE
270
+ : NEVER_MESSAGE;
270
271
 
271
272
  context.report({
272
273
  node: null, // Intentionally using loc instead
@@ -96,9 +96,9 @@ module.exports = {
96
96
  return fixer.replaceTextRange([start, end], newText);
97
97
 
98
98
  },
99
- message: options[dir] ?
100
- "A space is required {{dir}} ','." :
101
- "There should be no space {{dir}} ','.",
99
+ message: options[dir]
100
+ ? "A space is required {{dir}} ','."
101
+ : "There should be no space {{dir}} ','.",
102
102
  data: {
103
103
  dir
104
104
  }
@@ -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
- loc = context.getSourceCode().getTokenBefore(node.body).loc.start;
108
- type = "function";
109
+ loc = context.getSourceCode().getTokenBefore(node.body, astUtils.isArrowToken).loc.start;
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) {
@@ -209,9 +209,9 @@ module.exports = {
209
209
 
210
210
  if (!calledInEveryPaths) {
211
211
  context.report({
212
- message: calledInSomePaths ?
213
- "Lacked a call of 'super()' in some code paths." :
214
- "Expected to call 'super()'.",
212
+ message: calledInSomePaths
213
+ ? "Lacked a call of 'super()' in some code paths."
214
+ : "Expected to call 'super()'.",
215
215
  node: node.parent
216
216
  });
217
217
  }
@@ -94,19 +94,23 @@ module.exports = {
94
94
  return first.loc.start.line === last.loc.end.line;
95
95
  }
96
96
 
97
+ /**
98
+ * Checks if the given token is an `else` token or not.
99
+ *
100
+ * @param {Token} token - The token to check.
101
+ * @returns {boolean} `true` if the token is an `else` token.
102
+ */
103
+ function isElseKeywordToken(token) {
104
+ return token.value === "else" && token.type === "Keyword";
105
+ }
106
+
97
107
  /**
98
108
  * Gets the `else` keyword token of a given `IfStatement` node.
99
109
  * @param {ASTNode} node - A `IfStatement` node to get.
100
110
  * @returns {Token} The `else` keyword token.
101
111
  */
102
112
  function getElseKeyword(node) {
103
- let token = sourceCode.getTokenAfter(node.consequent);
104
-
105
- while (token.type !== "Keyword" || token.value !== "else") {
106
- token = sourceCode.getTokenAfter(token);
107
- }
108
-
109
- return token;
113
+ return node.alternate && sourceCode.getFirstTokenBetween(node.consequent, node.alternate, isElseKeywordToken);
110
114
  }
111
115
 
112
116
  /**
@@ -31,9 +31,9 @@ module.exports = {
31
31
 
32
32
  create(context) {
33
33
  const options = context.options[0] || {};
34
- const commentPattern = options.commentPattern ?
35
- new RegExp(options.commentPattern) :
36
- DEFAULT_COMMENT_PATTERN;
34
+ const commentPattern = options.commentPattern
35
+ ? new RegExp(options.commentPattern)
36
+ : DEFAULT_COMMENT_PATTERN;
37
37
 
38
38
  const sourceCode = context.getSourceCode();
39
39
 
@@ -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,9 +63,9 @@ module.exports = {
57
63
  const options = context.options[1] || {};
58
64
  const sourceCode = context.getSourceCode();
59
65
 
60
- const nullOption = (config === "always") ?
61
- options.null || "always" :
62
- "ignore";
66
+ const nullOption = (config === "always")
67
+ ? options.null || "always"
68
+ : "ignore";
63
69
  const enforceRuleForNull = (nullOption === "always");
64
70
  const enforceInverseRuleForNull = (nullOption === "never");
65
71
 
@@ -100,8 +106,7 @@ module.exports = {
100
106
  * @private
101
107
  */
102
108
  function isNullCheck(node) {
103
- return (node.right.type === "Literal" && node.right.value === null) ||
104
- (node.left.type === "Literal" && node.left.value === null);
109
+ return astUtils.isNullLiteral(node.right) || astUtils.isNullLiteral(node.left);
105
110
  }
106
111
 
107
112
  /**
@@ -134,7 +139,11 @@ module.exports = {
134
139
 
135
140
  // If the comparison is a `typeof` comparison or both sides are literals with the same type, then it's safe to fix.
136
141
  if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) {
137
- const operatorToken = sourceCode.getTokensBetween(node.left, node.right).find(token => token.value === node.operator);
142
+ const operatorToken = sourceCode.getFirstTokenBetween(
143
+ node.left,
144
+ node.right,
145
+ token => token.value === node.operator
146
+ );
138
147
 
139
148
  return fixer.replaceText(operatorToken, expectedOperator);
140
149
  }