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
package/lib/ast-utils.js CHANGED
@@ -24,6 +24,12 @@ const bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/;
24
24
  const breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/;
25
25
  const thisTagPattern = /^[\s*]*@this/m;
26
26
 
27
+ const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
28
+ const LINEBREAK_MATCHER = /\r\n|[\r\n\u2028\u2029]/;
29
+
30
+ // A set of node types that can contain a list of statements
31
+ const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]);
32
+
27
33
  /**
28
34
  * Checks reference if is non initializer and writable.
29
35
  * @param {Reference} reference - A reference to check.
@@ -142,7 +148,7 @@ function isInLoop(node) {
142
148
  */
143
149
  function isNullOrUndefined(node) {
144
150
  return (
145
- (node.type === "Literal" && node.value === null) ||
151
+ module.exports.isNullLiteral(node) ||
146
152
  (node.type === "Identifier" && node.name === "undefined") ||
147
153
  (node.type === "UnaryExpression" && node.operator === "void")
148
154
  );
@@ -158,9 +164,9 @@ function isCallee(node) {
158
164
  }
159
165
 
160
166
  /**
161
- * Checks whether or not a node is `Reclect.apply`.
167
+ * Checks whether or not a node is `Reflect.apply`.
162
168
  * @param {ASTNode} node - A node to check.
163
- * @returns {boolean} Whether or not the node is a `Reclect.apply`.
169
+ * @returns {boolean} Whether or not the node is a `Reflect.apply`.
164
170
  */
165
171
  function isReflectApply(node) {
166
172
  return (
@@ -210,6 +216,15 @@ function isMethodWhichHasThisArg(node) {
210
216
  return false;
211
217
  }
212
218
 
219
+ /**
220
+ * Creates the negate function of the given function.
221
+ * @param {Function} f - The function to negate.
222
+ * @returns {Function} Negated function.
223
+ */
224
+ function negate(f) {
225
+ return token => !f(token);
226
+ }
227
+
213
228
  /**
214
229
  * Checks whether or not a node has a `@this` tag in its comments.
215
230
  * @param {ASTNode} node - A node to check.
@@ -247,20 +262,123 @@ function isParenthesised(sourceCode, node) {
247
262
  }
248
263
 
249
264
  /**
250
- * Gets the `=>` token of the given arrow function node.
265
+ * Checks if the given token is an arrow token or not.
251
266
  *
252
- * @param {ASTNode} node - The arrow function node to get.
253
- * @param {SourceCode} sourceCode - The source code object to get tokens.
254
- * @returns {Token} `=>` token.
267
+ * @param {Token} token - The token to check.
268
+ * @returns {boolean} `true` if the token is an arrow token.
255
269
  */
256
- function getArrowToken(node, sourceCode) {
257
- let token = sourceCode.getTokenBefore(node.body);
270
+ function isArrowToken(token) {
271
+ return token.value === "=>" && token.type === "Punctuator";
272
+ }
258
273
 
259
- while (token.value !== "=>") {
260
- token = sourceCode.getTokenBefore(token);
261
- }
274
+ /**
275
+ * Checks if the given token is a comma token or not.
276
+ *
277
+ * @param {Token} token - The token to check.
278
+ * @returns {boolean} `true` if the token is a comma token.
279
+ */
280
+ function isCommaToken(token) {
281
+ return token.value === "," && token.type === "Punctuator";
282
+ }
283
+
284
+ /**
285
+ * Checks if the given token is a semicolon token or not.
286
+ *
287
+ * @param {Token} token - The token to check.
288
+ * @returns {boolean} `true` if the token is a semicolon token.
289
+ */
290
+ function isSemicolonToken(token) {
291
+ return token.value === ";" && token.type === "Punctuator";
292
+ }
293
+
294
+ /**
295
+ * Checks if the given token is a colon token or not.
296
+ *
297
+ * @param {Token} token - The token to check.
298
+ * @returns {boolean} `true` if the token is a colon token.
299
+ */
300
+ function isColonToken(token) {
301
+ return token.value === ":" && token.type === "Punctuator";
302
+ }
303
+
304
+ /**
305
+ * Checks if the given token is an opening parenthesis token or not.
306
+ *
307
+ * @param {Token} token - The token to check.
308
+ * @returns {boolean} `true` if the token is an opening parenthesis token.
309
+ */
310
+ function isOpeningParenToken(token) {
311
+ return token.value === "(" && token.type === "Punctuator";
312
+ }
313
+
314
+ /**
315
+ * Checks if the given token is a closing parenthesis token or not.
316
+ *
317
+ * @param {Token} token - The token to check.
318
+ * @returns {boolean} `true` if the token is a closing parenthesis token.
319
+ */
320
+ function isClosingParenToken(token) {
321
+ return token.value === ")" && token.type === "Punctuator";
322
+ }
323
+
324
+ /**
325
+ * Checks if the given token is an opening square bracket token or not.
326
+ *
327
+ * @param {Token} token - The token to check.
328
+ * @returns {boolean} `true` if the token is an opening square bracket token.
329
+ */
330
+ function isOpeningBracketToken(token) {
331
+ return token.value === "[" && token.type === "Punctuator";
332
+ }
333
+
334
+ /**
335
+ * Checks if the given token is a closing square bracket token or not.
336
+ *
337
+ * @param {Token} token - The token to check.
338
+ * @returns {boolean} `true` if the token is a closing square bracket token.
339
+ */
340
+ function isClosingBracketToken(token) {
341
+ return token.value === "]" && token.type === "Punctuator";
342
+ }
343
+
344
+ /**
345
+ * Checks if the given token is an opening brace token or not.
346
+ *
347
+ * @param {Token} token - The token to check.
348
+ * @returns {boolean} `true` if the token is an opening brace token.
349
+ */
350
+ function isOpeningBraceToken(token) {
351
+ return token.value === "{" && token.type === "Punctuator";
352
+ }
353
+
354
+ /**
355
+ * Checks if the given token is a closing brace token or not.
356
+ *
357
+ * @param {Token} token - The token to check.
358
+ * @returns {boolean} `true` if the token is a closing brace token.
359
+ */
360
+ function isClosingBraceToken(token) {
361
+ return token.value === "}" && token.type === "Punctuator";
362
+ }
262
363
 
263
- return token;
364
+ /**
365
+ * Checks if the given token is a comment token or not.
366
+ *
367
+ * @param {Token} token - The token to check.
368
+ * @returns {boolean} `true` if the token is a comment token.
369
+ */
370
+ function isCommentToken(token) {
371
+ return token.type === "Line" || token.type === "Block" || token.type === "Shebang";
372
+ }
373
+
374
+ /**
375
+ * Checks if the given token is a keyword token or not.
376
+ *
377
+ * @param {Token} token - The token to check.
378
+ * @returns {boolean} `true` if the token is a keyword token.
379
+ */
380
+ function isKeywordToken(token) {
381
+ return token.type === "Keyword";
264
382
  }
265
383
 
266
384
  /**
@@ -271,13 +389,18 @@ function getArrowToken(node, sourceCode) {
271
389
  * @returns {Token} `(` token.
272
390
  */
273
391
  function getOpeningParenOfParams(node, sourceCode) {
274
- let token = node.id ? sourceCode.getTokenAfter(node.id) : sourceCode.getFirstToken(node);
275
-
276
- while (token.value !== "(") {
277
- token = sourceCode.getTokenAfter(token);
278
- }
392
+ return node.id
393
+ ? sourceCode.getTokenAfter(node.id, isOpeningParenToken)
394
+ : sourceCode.getFirstToken(node, isOpeningParenToken);
395
+ }
279
396
 
280
- return token;
397
+ /**
398
+ * Creates a version of the LINEBREAK_MATCHER regex with the global flag.
399
+ * Global regexes are mutable, so this needs to be a function instead of a constant.
400
+ * @returns {RegExp} A global regular expression that matches line terminators
401
+ */
402
+ function createGlobalLinebreakMatcher() {
403
+ return new RegExp(LINEBREAK_MATCHER.source, "g");
281
404
  }
282
405
 
283
406
  const lineIndexCache = new WeakMap();
@@ -290,8 +413,23 @@ const lineIndexCache = new WeakMap();
290
413
  function getLineIndices(sourceCode) {
291
414
 
292
415
  if (!lineIndexCache.has(sourceCode)) {
293
- const lineIndices = (sourceCode.text.match(/[^\r\n\u2028\u2029]*(\r\n|\r|\n|\u2028|\u2029)/g) || [])
294
- .reduce((indices, line) => indices.concat(indices[indices.length - 1] + line.length), [0]);
416
+ const lineIndices = [0];
417
+ const lineEndingPattern = createGlobalLinebreakMatcher();
418
+ let match;
419
+
420
+ /*
421
+ * Previously, this function was implemented using a regex that
422
+ * matched a sequence of non-linebreak characters followed by a
423
+ * linebreak, then adding the lengths of the matches. However,
424
+ * this caused a catastrophic backtracking issue when the end
425
+ * of a file contained a large number of non-newline characters.
426
+ * To avoid this, the current implementation just matches newlines
427
+ * and uses match.index to get the correct line start indices.
428
+ */
429
+
430
+ while ((match = lineEndingPattern.exec(sourceCode.text))) {
431
+ lineIndices.push(match.index + match[0].length);
432
+ }
295
433
 
296
434
  // Store the sourceCode object in a WeakMap to avoid iterating over all of the lines every time a sourceCode object is passed in.
297
435
  lineIndexCache.set(sourceCode, lineIndices);
@@ -304,6 +442,9 @@ function getLineIndices(sourceCode) {
304
442
  //------------------------------------------------------------------------------
305
443
 
306
444
  module.exports = {
445
+ LINEBREAKS,
446
+ LINEBREAK_MATCHER,
447
+ STATEMENT_LIST_PARENTS,
307
448
 
308
449
  /**
309
450
  * Determines whether two adjacent tokens are on the same line.
@@ -325,6 +466,29 @@ module.exports = {
325
466
  isInLoop,
326
467
  isArrayFromMethod,
327
468
  isParenthesised,
469
+ createGlobalLinebreakMatcher,
470
+
471
+ isArrowToken,
472
+ isClosingBraceToken,
473
+ isClosingBracketToken,
474
+ isClosingParenToken,
475
+ isColonToken,
476
+ isCommaToken,
477
+ isCommentToken,
478
+ isKeywordToken,
479
+ isNotClosingBraceToken: negate(isClosingBraceToken),
480
+ isNotClosingBracketToken: negate(isClosingBracketToken),
481
+ isNotClosingParenToken: negate(isClosingParenToken),
482
+ isNotColonToken: negate(isColonToken),
483
+ isNotCommaToken: negate(isCommaToken),
484
+ isNotOpeningBraceToken: negate(isOpeningBraceToken),
485
+ isNotOpeningBracketToken: negate(isOpeningBracketToken),
486
+ isNotOpeningParenToken: negate(isOpeningParenToken),
487
+ isNotSemicolonToken: negate(isSemicolonToken),
488
+ isOpeningBraceToken,
489
+ isOpeningBracketToken,
490
+ isOpeningParenToken,
491
+ isSemicolonToken,
328
492
 
329
493
  /**
330
494
  * Checks whether or not a given node is a string literal.
@@ -658,6 +822,8 @@ module.exports = {
658
822
  case "/":
659
823
  case "%":
660
824
  return 13;
825
+ case "**":
826
+ return 15;
661
827
 
662
828
  // no default
663
829
  }
@@ -666,10 +832,10 @@ module.exports = {
666
832
 
667
833
  case "UnaryExpression":
668
834
  case "AwaitExpression":
669
- return 14;
835
+ return 16;
670
836
 
671
837
  case "UpdateExpression":
672
- return 15;
838
+ return 17;
673
839
 
674
840
  case "CallExpression":
675
841
 
@@ -677,14 +843,14 @@ module.exports = {
677
843
  if (node.callee.type === "FunctionExpression") {
678
844
  return -1;
679
845
  }
680
- return 16;
846
+ return 18;
681
847
 
682
848
  case "NewExpression":
683
- return 17;
849
+ return 19;
684
850
 
685
851
  // no default
686
852
  }
687
- return 18;
853
+ return 20;
688
854
  },
689
855
 
690
856
  /**
@@ -1023,7 +1189,7 @@ module.exports = {
1023
1189
  let end = null;
1024
1190
 
1025
1191
  if (node.type === "ArrowFunctionExpression") {
1026
- const arrowToken = getArrowToken(node, sourceCode);
1192
+ const arrowToken = sourceCode.getTokenBefore(node.body, isArrowToken);
1027
1193
 
1028
1194
  start = arrowToken.loc.start;
1029
1195
  end = arrowToken.loc.end;
@@ -1037,7 +1203,7 @@ module.exports = {
1037
1203
 
1038
1204
  return {
1039
1205
  start: Object.assign({}, start),
1040
- end: Object.assign({}, end),
1206
+ end: Object.assign({}, end)
1041
1207
  };
1042
1208
  },
1043
1209
 
@@ -1097,5 +1263,58 @@ module.exports = {
1097
1263
  }
1098
1264
 
1099
1265
  return sourceCode.getText().slice(leftToken.range[0], rightToken.range[1]);
1266
+ },
1267
+
1268
+ /*
1269
+ * Determine if a node has a possiblity to be an Error object
1270
+ * @param {ASTNode} node ASTNode to check
1271
+ * @returns {boolean} True if there is a chance it contains an Error obj
1272
+ */
1273
+ couldBeError(node) {
1274
+ switch (node.type) {
1275
+ case "Identifier":
1276
+ case "CallExpression":
1277
+ case "NewExpression":
1278
+ case "MemberExpression":
1279
+ case "TaggedTemplateExpression":
1280
+ case "YieldExpression":
1281
+ case "AwaitExpression":
1282
+ return true; // possibly an error object.
1283
+
1284
+ case "AssignmentExpression":
1285
+ return module.exports.couldBeError(node.right);
1286
+
1287
+ case "SequenceExpression": {
1288
+ const exprs = node.expressions;
1289
+
1290
+ return exprs.length !== 0 && module.exports.couldBeError(exprs[exprs.length - 1]);
1291
+ }
1292
+
1293
+ case "LogicalExpression":
1294
+ return module.exports.couldBeError(node.left) || module.exports.couldBeError(node.right);
1295
+
1296
+ case "ConditionalExpression":
1297
+ return module.exports.couldBeError(node.consequent) || module.exports.couldBeError(node.alternate);
1298
+
1299
+ default:
1300
+ return false;
1301
+ }
1302
+ },
1303
+
1304
+ /**
1305
+ * Determines whether the given node is a `null` literal.
1306
+ * @param {ASTNode} node The node to check
1307
+ * @returns {boolean} `true` if the node is a `null` literal
1308
+ */
1309
+ isNullLiteral(node) {
1310
+
1311
+ /*
1312
+ * Checking `node.value === null` does not guarantee that a literal is a null literal.
1313
+ * When parsing values that cannot be represented in the current environment (e.g. unicode
1314
+ * regexes in Node 4), `node.value` is set to `null` because it wouldn't be possible to
1315
+ * set `node.value` to a unicode regex. To make sure a literal is actually `null`, check
1316
+ * `node.regex` instead. Also see: https://github.com/eslint/eslint/issues/8020
1317
+ */
1318
+ return node.type === "Literal" && node.value === null && !node.regex;
1100
1319
  }
1101
1320
  };
package/lib/cli.js CHANGED
@@ -188,9 +188,9 @@ const cli = {
188
188
  }
189
189
 
190
190
  return (report.errorCount || tooManyWarnings) ? 1 : 0;
191
- } else {
192
- return 1;
193
191
  }
192
+ return 1;
193
+
194
194
 
195
195
  }
196
196
 
@@ -467,8 +467,8 @@ class CodePathState {
467
467
  * Creates the next path from own true/false fork context.
468
468
  */
469
469
  const prevForkContext =
470
- context.kind === "&&" ? context.trueForkContext :
471
- /* kind === "||" */ context.falseForkContext;
470
+ context.kind === "&&" ? context.trueForkContext
471
+ /* kind === "||" */ : context.falseForkContext;
472
472
 
473
473
  forkContext.replaceHead(prevForkContext.makeNext(0, -1));
474
474
  prevForkContext.clear();
@@ -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
 
@@ -65,17 +65,16 @@ function makeRegistryItems(rulesConfig) {
65
65
  * Unless a rulesConfig is provided at construction, the registry will not contain
66
66
  * any rules, only methods. This will be useful for building up registries manually.
67
67
  *
68
- * @constructor
69
- * @class Registry
70
- * @param {rulesConfig} [rulesConfig] Hash of rule names and arrays of possible configurations
68
+ * Registry class
71
69
  */
72
- function Registry(rulesConfig) {
73
- this.rules = (rulesConfig) ? makeRegistryItems(rulesConfig) : {};
74
- }
75
-
76
- Registry.prototype = {
70
+ class Registry {
77
71
 
78
- constructor: Registry,
72
+ /**
73
+ * @param {rulesConfig} [rulesConfig] Hash of rule names and arrays of possible configurations
74
+ */
75
+ constructor(rulesConfig) {
76
+ this.rules = (rulesConfig) ? makeRegistryItems(rulesConfig) : {};
77
+ }
79
78
 
80
79
  /**
81
80
  * Populate the registry with core rule configs.
@@ -89,7 +88,7 @@ Registry.prototype = {
89
88
  const rulesConfig = configRule.createCoreRuleConfigs();
90
89
 
91
90
  this.rules = makeRegistryItems(rulesConfig);
92
- },
91
+ }
93
92
 
94
93
  /**
95
94
  * Creates sets of rule configurations which can be used for linting
@@ -156,7 +155,7 @@ Registry.prototype = {
156
155
  }
157
156
 
158
157
  return ruleSets;
159
- },
158
+ }
160
159
 
161
160
  /**
162
161
  * Remove all items from the registry with a non-zero number of errors
@@ -182,7 +181,7 @@ Registry.prototype = {
182
181
  });
183
182
 
184
183
  return newRegistry;
185
- },
184
+ }
186
185
 
187
186
  /**
188
187
  * Removes rule configurations which were not included in a ruleSet
@@ -199,7 +198,7 @@ Registry.prototype = {
199
198
  });
200
199
 
201
200
  return newRegistry;
202
- },
201
+ }
203
202
 
204
203
  /**
205
204
  * Creates a registry of rules which had no error-free configs.
@@ -221,7 +220,7 @@ Registry.prototype = {
221
220
  });
222
221
 
223
222
  return failingRegistry;
224
- },
223
+ }
225
224
 
226
225
  /**
227
226
  * Create an eslint config for any rules which only have one configuration
@@ -240,7 +239,7 @@ Registry.prototype = {
240
239
  });
241
240
 
242
241
  return config;
243
- },
242
+ }
244
243
 
245
244
  /**
246
245
  * Return a cloned registry containing only configs with a desired specificity
@@ -258,7 +257,7 @@ Registry.prototype = {
258
257
  });
259
258
 
260
259
  return newRegistry;
261
- },
260
+ }
262
261
 
263
262
  /**
264
263
  * Lint SourceCodes against all configurations in the registry, and record results
@@ -297,8 +296,13 @@ Registry.prototype = {
297
296
 
298
297
  // It is possible that the error is from a configuration comment
299
298
  // in a linted file, in which case there may not be a config
300
- // set in this ruleSetIdx. (https://github.com/eslint/eslint/issues/5992)
301
- if (lintedRegistry.rules[result.ruleId][ruleSetIdx]) {
299
+ // set in this ruleSetIdx.
300
+ // (https://github.com/eslint/eslint/issues/5992)
301
+ // (https://github.com/eslint/eslint/issues/7860)
302
+ if (
303
+ lintedRegistry.rules[result.ruleId] &&
304
+ lintedRegistry.rules[result.ruleId][ruleSetIdx]
305
+ ) {
302
306
  lintedRegistry.rules[result.ruleId][ruleSetIdx].errorCount += 1;
303
307
  }
304
308
  });
@@ -316,7 +320,7 @@ Registry.prototype = {
316
320
 
317
321
  return lintedRegistry;
318
322
  }
319
- };
323
+ }
320
324
 
321
325
  /**
322
326
  * Extract rule configuration into eslint:recommended where possible.
@@ -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
@@ -461,24 +468,24 @@ function normalizePackageName(name, prefix) {
461
468
  function resolve(filePath, relativeTo) {
462
469
  if (isFilePath(filePath)) {
463
470
  return { filePath: path.resolve(relativeTo || "", filePath) };
464
- } else {
465
- let normalizedPackageName;
466
-
467
- if (filePath.indexOf("plugin:") === 0) {
468
- const packagePath = filePath.substr(7, filePath.lastIndexOf("/") - 7);
469
- const configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1);
470
-
471
- normalizedPackageName = normalizePackageName(packagePath, "eslint-plugin");
472
- debug(`Attempting to resolve ${normalizedPackageName}`);
473
- filePath = resolver.resolve(normalizedPackageName, getLookupPath(relativeTo));
474
- return { filePath, configName };
475
- } else {
476
- normalizedPackageName = normalizePackageName(filePath, "eslint-config");
477
- debug(`Attempting to resolve ${normalizedPackageName}`);
478
- filePath = resolver.resolve(normalizedPackageName, getLookupPath(relativeTo));
479
- return { filePath };
480
- }
481
471
  }
472
+ let normalizedPackageName;
473
+
474
+ if (filePath.indexOf("plugin:") === 0) {
475
+ const packagePath = filePath.substr(7, filePath.lastIndexOf("/") - 7);
476
+ const configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1);
477
+
478
+ normalizedPackageName = normalizePackageName(packagePath, "eslint-plugin");
479
+ debug(`Attempting to resolve ${normalizedPackageName}`);
480
+ filePath = resolver.resolve(normalizedPackageName, getLookupPath(relativeTo));
481
+ return { filePath, configName };
482
+ }
483
+ normalizedPackageName = normalizePackageName(filePath, "eslint-config");
484
+ debug(`Attempting to resolve ${normalizedPackageName}`);
485
+ filePath = resolver.resolve(normalizedPackageName, getLookupPath(relativeTo));
486
+ return { filePath };
487
+
488
+
482
489
 
483
490
  }
484
491
 
@@ -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");
@@ -317,7 +317,7 @@ function promptUser(callback) {
317
317
  default: false,
318
318
  when(answers) {
319
319
  return answers.styleguide === "airbnb";
320
- },
320
+ }
321
321
  },
322
322
  {
323
323
  type: "input",