eslint 6.6.0 → 6.8.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 (62) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +7 -8
  3. package/conf/config-schema.js +2 -0
  4. package/conf/default-cli-options.js +1 -1
  5. package/conf/eslint-recommended.js +0 -1
  6. package/lib/cli-engine/cascading-config-array-factory.js +38 -13
  7. package/lib/cli-engine/cli-engine.js +41 -14
  8. package/lib/cli-engine/config-array/config-array.js +13 -0
  9. package/lib/cli-engine/config-array/extracted-config.js +27 -0
  10. package/lib/cli-engine/config-array/ignore-pattern.js +231 -0
  11. package/lib/cli-engine/config-array/index.js +2 -0
  12. package/lib/cli-engine/config-array-factory.js +115 -1
  13. package/lib/cli-engine/file-enumerator.js +73 -40
  14. package/lib/cli-engine/lint-result-cache.js +2 -1
  15. package/lib/cli.js +2 -1
  16. package/lib/init/config-initializer.js +4 -3
  17. package/lib/linter/config-comment-parser.js +1 -1
  18. package/lib/linter/report-translator.js +73 -7
  19. package/lib/options.js +6 -0
  20. package/lib/rule-tester/rule-tester.js +42 -6
  21. package/lib/rules/array-bracket-spacing.js +8 -8
  22. package/lib/rules/camelcase.js +19 -6
  23. package/lib/rules/comma-dangle.js +5 -2
  24. package/lib/rules/computed-property-spacing.js +4 -4
  25. package/lib/rules/curly.js +9 -4
  26. package/lib/rules/function-call-argument-newline.js +3 -1
  27. package/lib/rules/grouped-accessor-pairs.js +224 -0
  28. package/lib/rules/indent.js +11 -0
  29. package/lib/rules/index.js +5 -0
  30. package/lib/rules/key-spacing.js +34 -15
  31. package/lib/rules/lines-between-class-members.js +42 -53
  32. package/lib/rules/multiline-comment-style.js +237 -106
  33. package/lib/rules/no-cond-assign.js +14 -4
  34. package/lib/rules/no-constructor-return.js +62 -0
  35. package/lib/rules/no-dupe-else-if.js +122 -0
  36. package/lib/rules/no-implicit-globals.js +90 -8
  37. package/lib/rules/no-inline-comments.js +25 -11
  38. package/lib/rules/no-invalid-this.js +16 -2
  39. package/lib/rules/no-multiple-empty-lines.js +1 -1
  40. package/lib/rules/no-octal-escape.js +1 -1
  41. package/lib/rules/no-restricted-imports.js +2 -2
  42. package/lib/rules/no-setter-return.js +227 -0
  43. package/lib/rules/no-underscore-dangle.js +23 -4
  44. package/lib/rules/no-unexpected-multiline.js +8 -0
  45. package/lib/rules/no-unsafe-negation.js +30 -5
  46. package/lib/rules/no-useless-computed-key.js +60 -33
  47. package/lib/rules/no-useless-escape.js +26 -3
  48. package/lib/rules/object-curly-spacing.js +8 -8
  49. package/lib/rules/operator-assignment.js +11 -2
  50. package/lib/rules/prefer-const.js +14 -7
  51. package/lib/rules/prefer-exponentiation-operator.js +189 -0
  52. package/lib/rules/prefer-numeric-literals.js +29 -28
  53. package/lib/rules/require-atomic-updates.js +1 -1
  54. package/lib/rules/require-await.js +8 -0
  55. package/lib/rules/semi.js +6 -3
  56. package/lib/rules/space-infix-ops.js +1 -1
  57. package/lib/rules/spaced-comment.js +5 -4
  58. package/lib/rules/utils/ast-utils.js +31 -4
  59. package/lib/shared/types.js +9 -0
  60. package/lib/source-code/source-code.js +87 -10
  61. package/package.json +4 -3
  62. package/lib/cli-engine/ignored-paths.js +0 -363
@@ -15,6 +15,12 @@ const astUtils = require("./utils/ast-utils");
15
15
  // Helpers
16
16
  //------------------------------------------------------------------------------
17
17
 
18
+ const radixMap = new Map([
19
+ [2, { system: "binary", literalPrefix: "0b" }],
20
+ [8, { system: "octal", literalPrefix: "0o" }],
21
+ [16, { system: "hexadecimal", literalPrefix: "0x" }]
22
+ ]);
23
+
18
24
  /**
19
25
  * Checks to see if a CallExpression's callee node is `parseInt` or
20
26
  * `Number.parseInt`.
@@ -54,49 +60,44 @@ module.exports = {
54
60
  },
55
61
 
56
62
  schema: [],
63
+
64
+ messages: {
65
+ useLiteral: "Use {{system}} literals instead of {{functionName}}()."
66
+ },
67
+
57
68
  fixable: "code"
58
69
  },
59
70
 
60
71
  create(context) {
61
72
  const sourceCode = context.getSourceCode();
62
73
 
63
- const radixMap = {
64
- 2: "binary",
65
- 8: "octal",
66
- 16: "hexadecimal"
67
- };
68
-
69
- const prefixMap = {
70
- 2: "0b",
71
- 8: "0o",
72
- 16: "0x"
73
- };
74
-
75
74
  //----------------------------------------------------------------------
76
75
  // Public
77
76
  //----------------------------------------------------------------------
78
77
 
79
78
  return {
80
79
 
81
- CallExpression(node) {
82
-
83
- // doesn't check parseInt() if it doesn't have a radix argument
84
- if (node.arguments.length !== 2) {
85
- return;
86
- }
80
+ "CallExpression[arguments.length=2]"(node) {
81
+ const [strNode, radixNode] = node.arguments,
82
+ str = strNode.value,
83
+ radix = radixNode.value;
84
+
85
+ if (
86
+ strNode.type === "Literal" &&
87
+ radixNode.type === "Literal" &&
88
+ typeof str === "string" &&
89
+ typeof radix === "number" &&
90
+ radixMap.has(radix) &&
91
+ isParseInt(node.callee)
92
+ ) {
87
93
 
88
- // only error if the radix is 2, 8, or 16
89
- const radixName = radixMap[node.arguments[1].value];
94
+ const { system, literalPrefix } = radixMap.get(radix);
90
95
 
91
- if (isParseInt(node.callee) &&
92
- radixName &&
93
- node.arguments[0].type === "Literal"
94
- ) {
95
96
  context.report({
96
97
  node,
97
- message: "Use {{radixName}} literals instead of {{functionName}}().",
98
+ messageId: "useLiteral",
98
99
  data: {
99
- radixName,
100
+ system,
100
101
  functionName: sourceCode.getText(node.callee)
101
102
  },
102
103
  fix(fixer) {
@@ -104,9 +105,9 @@ module.exports = {
104
105
  return null;
105
106
  }
106
107
 
107
- const replacement = `${prefixMap[node.arguments[1].value]}${node.arguments[0].value}`;
108
+ const replacement = `${literalPrefix}${str}`;
108
109
 
109
- if (+replacement !== parseInt(node.arguments[0].value, node.arguments[1].value)) {
110
+ if (+replacement !== parseInt(str, radix)) {
110
111
 
111
112
  /*
112
113
  * If the newly-produced literal would be invalid, (e.g. 0b1234),
@@ -162,7 +162,7 @@ module.exports = {
162
162
  docs: {
163
163
  description: "disallow assignments that can lead to race conditions due to usage of `await` or `yield`",
164
164
  category: "Possible Errors",
165
- recommended: true,
165
+ recommended: false,
166
166
  url: "https://eslint.org/docs/rules/require-atomic-updates"
167
167
  },
168
168
 
@@ -89,9 +89,17 @@ module.exports = {
89
89
  "ArrowFunctionExpression:exit": exitFunction,
90
90
 
91
91
  AwaitExpression() {
92
+ if (!scopeInfo) {
93
+ return;
94
+ }
95
+
92
96
  scopeInfo.hasAwait = true;
93
97
  },
94
98
  ForOfStatement(node) {
99
+ if (!scopeInfo) {
100
+ return;
101
+ }
102
+
95
103
  if (node.await) {
96
104
  scopeInfo.hasAwait = true;
97
105
  }
package/lib/rules/semi.js CHANGED
@@ -93,17 +93,20 @@ module.exports = {
93
93
  const lastToken = sourceCode.getLastToken(node);
94
94
  let message,
95
95
  fix,
96
- loc = lastToken.loc;
96
+ loc;
97
97
 
98
98
  if (!missing) {
99
99
  message = "Missing semicolon.";
100
- loc = loc.end;
100
+ loc = {
101
+ start: lastToken.loc.end,
102
+ end: astUtils.getNextLocation(sourceCode, lastToken.loc.end)
103
+ };
101
104
  fix = function(fixer) {
102
105
  return fixer.insertTextAfter(lastToken, ";");
103
106
  };
104
107
  } else {
105
108
  message = "Extra semicolon.";
106
- loc = loc.start;
109
+ loc = lastToken.loc;
107
110
  fix = function(fixer) {
108
111
 
109
112
  /*
@@ -69,7 +69,7 @@ module.exports = {
69
69
  function report(mainNode, culpritToken) {
70
70
  context.report({
71
71
  node: mainNode,
72
- loc: culpritToken.loc.start,
72
+ loc: culpritToken.loc,
73
73
  message: "Operator '{{operator}}' must be spaced.",
74
74
  data: {
75
75
  operator: culpritToken.value
@@ -249,7 +249,8 @@ module.exports = {
249
249
  beginRegex: requireSpace ? createAlwaysStylePattern(markers, exceptions) : createNeverStylePattern(markers),
250
250
  endRegex: balanced && requireSpace ? new RegExp(`${createExceptionsPattern(exceptions)}$`, "u") : new RegExp(endNeverPattern, "u"),
251
251
  hasExceptions: exceptions.length > 0,
252
- markers: new RegExp(`^(${markers.map(escape).join("|")})`, "u")
252
+ captureMarker: new RegExp(`^(${markers.map(escape).join("|")})`, "u"),
253
+ markers: new Set(markers)
253
254
  };
254
255
 
255
256
  return rule;
@@ -322,8 +323,8 @@ module.exports = {
322
323
  rule = styleRules[type],
323
324
  commentIdentifier = type === "block" ? "/*" : "//";
324
325
 
325
- // Ignores empty comments.
326
- if (node.value.length === 0) {
326
+ // Ignores empty comments and comments that consist only of a marker.
327
+ if (node.value.length === 0 || rule.markers.has(node.value)) {
327
328
  return;
328
329
  }
329
330
 
@@ -333,7 +334,7 @@ module.exports = {
333
334
  // Checks.
334
335
  if (requireSpace) {
335
336
  if (!beginMatch) {
336
- const hasMarker = rule.markers.exec(node.value);
337
+ const hasMarker = rule.captureMarker.exec(node.value);
337
338
  const marker = hasMarker ? commentIdentifier + hasMarker[0] : commentIdentifier;
338
339
 
339
340
  if (rule.hasExceptions) {
@@ -581,23 +581,31 @@ module.exports = {
581
581
  *
582
582
  * First, this checks the node:
583
583
  *
584
- * - The function name does not start with uppercase (it's a constructor).
584
+ * - The function name does not start with uppercase. It's a convention to capitalize the names
585
+ * of constructor functions. This check is not performed if `capIsConstructor` is set to `false`.
585
586
  * - The function does not have a JSDoc comment that has a @this tag.
586
587
  *
587
588
  * Next, this checks the location of the node.
588
589
  * If the location is below, this judges `this` is valid.
589
590
  *
590
591
  * - The location is not on an object literal.
591
- * - The location is not assigned to a variable which starts with an uppercase letter.
592
+ * - The location is not assigned to a variable which starts with an uppercase letter. Applies to anonymous
593
+ * functions only, as the name of the variable is considered to be the name of the function in this case.
594
+ * This check is not performed if `capIsConstructor` is set to `false`.
592
595
  * - The location is not on an ES2015 class.
593
596
  * - Its `bind`/`call`/`apply` method is not called directly.
594
597
  * - The function is not a callback of array methods (such as `.forEach()`) if `thisArg` is given.
595
598
  * @param {ASTNode} node A function node to check.
596
599
  * @param {SourceCode} sourceCode A SourceCode instance to get comments.
600
+ * @param {boolean} [capIsConstructor = true] `false` disables the assumption that functions which name starts
601
+ * with an uppercase or are assigned to a variable which name starts with an uppercase are constructors.
597
602
  * @returns {boolean} The function node is the default `this` binding.
598
603
  */
599
- isDefaultThisBinding(node, sourceCode) {
600
- if (isES5Constructor(node) || hasJSDocThisTag(node, sourceCode)) {
604
+ isDefaultThisBinding(node, sourceCode, { capIsConstructor = true } = {}) {
605
+ if (
606
+ (capIsConstructor && isES5Constructor(node)) ||
607
+ hasJSDocThisTag(node, sourceCode)
608
+ ) {
601
609
  return false;
602
610
  }
603
611
  const isAnonymous = node.id === null;
@@ -671,6 +679,7 @@ module.exports = {
671
679
  return false;
672
680
  }
673
681
  if (
682
+ capIsConstructor &&
674
683
  isAnonymous &&
675
684
  parent.left.type === "Identifier" &&
676
685
  startsWithUpperCase(parent.left.name)
@@ -685,6 +694,7 @@ module.exports = {
685
694
  */
686
695
  case "VariableDeclarator":
687
696
  return !(
697
+ capIsConstructor &&
688
698
  isAnonymous &&
689
699
  parent.init === currentNode &&
690
700
  parent.id.type === "Identifier" &&
@@ -1200,6 +1210,23 @@ module.exports = {
1200
1210
  };
1201
1211
  },
1202
1212
 
1213
+ /**
1214
+ * Gets next location when the result is not out of bound, otherwise returns null.
1215
+ * @param {SourceCode} sourceCode The sourceCode
1216
+ * @param {{line: number, column: number}} location The location
1217
+ * @returns {{line: number, column: number} | null} Next location
1218
+ */
1219
+ getNextLocation(sourceCode, location) {
1220
+ const index = sourceCode.getIndexFromLoc(location);
1221
+
1222
+ // Avoid out of bound location
1223
+ if (index + 1 > sourceCode.text.length) {
1224
+ return null;
1225
+ }
1226
+
1227
+ return sourceCode.getLocFromIndex(index + 1);
1228
+ },
1229
+
1203
1230
  /**
1204
1231
  * Gets the parenthesized text of a node. This is similar to sourceCode.getText(node), but it also includes any parentheses
1205
1232
  * surrounding the node.
@@ -30,6 +30,7 @@ module.exports = {};
30
30
  * @property {Record<string, boolean>} [env] The environment settings.
31
31
  * @property {string | string[]} [extends] The path to other config files or the package name of shareable configs.
32
32
  * @property {Record<string, GlobalConf>} [globals] The global variable settings.
33
+ * @property {string | string[]} [ignorePatterns] The glob patterns that ignore to lint.
33
34
  * @property {boolean} [noInlineConfig] The flag that disables directive comments.
34
35
  * @property {OverrideConfigData[]} [overrides] The override settings per kind of files.
35
36
  * @property {string} [parser] The path to a parser or the package name of a parser.
@@ -91,6 +92,14 @@ module.exports = {};
91
92
  * @property {string} message The error message.
92
93
  * @property {string|null} ruleId The ID of the rule which makes this message.
93
94
  * @property {0|1|2} severity The severity of this message.
95
+ * @property {Array<{desc?: string, messageId?: string, fix: {range: [number, number], text: string}}>} [suggestions] Information for suggestions.
96
+ */
97
+
98
+ /**
99
+ * @typedef {Object} SuggestionResult
100
+ * @property {string} desc A short description.
101
+ * @property {string} [messageId] Id referencing a message for the description.
102
+ * @property {{ text: string, range: number[] }} fix fix result info
94
103
  */
95
104
 
96
105
  /**
@@ -78,6 +78,68 @@ function sortedMerge(tokens, comments) {
78
78
  return result;
79
79
  }
80
80
 
81
+ /**
82
+ * Determines if two nodes or tokens overlap.
83
+ * @param {ASTNode|Token} first The first node or token to check.
84
+ * @param {ASTNode|Token} second The second node or token to check.
85
+ * @returns {boolean} True if the two nodes or tokens overlap.
86
+ * @private
87
+ */
88
+ function nodesOrTokensOverlap(first, second) {
89
+ return (first.range[0] <= second.range[0] && first.range[1] >= second.range[0]) ||
90
+ (second.range[0] <= first.range[0] && second.range[1] >= first.range[0]);
91
+ }
92
+
93
+ /**
94
+ * Determines if two nodes or tokens have at least one whitespace character
95
+ * between them. Order does not matter. Returns false if the given nodes or
96
+ * tokens overlap.
97
+ * @param {SourceCode} sourceCode The source code object.
98
+ * @param {ASTNode|Token} first The first node or token to check between.
99
+ * @param {ASTNode|Token} second The second node or token to check between.
100
+ * @param {boolean} checkInsideOfJSXText If `true` is present, check inside of JSXText tokens for backward compatibility.
101
+ * @returns {boolean} True if there is a whitespace character between
102
+ * any of the tokens found between the two given nodes or tokens.
103
+ * @public
104
+ */
105
+ function isSpaceBetween(sourceCode, first, second, checkInsideOfJSXText) {
106
+ if (nodesOrTokensOverlap(first, second)) {
107
+ return false;
108
+ }
109
+
110
+ const [startingNodeOrToken, endingNodeOrToken] = first.range[1] <= second.range[0]
111
+ ? [first, second]
112
+ : [second, first];
113
+ const firstToken = sourceCode.getLastToken(startingNodeOrToken) || startingNodeOrToken;
114
+ const finalToken = sourceCode.getFirstToken(endingNodeOrToken) || endingNodeOrToken;
115
+ let currentToken = firstToken;
116
+
117
+ while (currentToken !== finalToken) {
118
+ const nextToken = sourceCode.getTokenAfter(currentToken, { includeComments: true });
119
+
120
+ if (
121
+ currentToken.range[1] !== nextToken.range[0] ||
122
+
123
+ /*
124
+ * For backward compatibility, check speces in JSXText.
125
+ * https://github.com/eslint/eslint/issues/12614
126
+ */
127
+ (
128
+ checkInsideOfJSXText &&
129
+ nextToken !== finalToken &&
130
+ nextToken.type === "JSXText" &&
131
+ /\s/u.test(nextToken.value)
132
+ )
133
+ ) {
134
+ return true;
135
+ }
136
+
137
+ currentToken = nextToken;
138
+ }
139
+
140
+ return false;
141
+ }
142
+
81
143
  //------------------------------------------------------------------------------
82
144
  // Public Interface
83
145
  //------------------------------------------------------------------------------
@@ -411,19 +473,34 @@ class SourceCode extends TokenStore {
411
473
  }
412
474
 
413
475
  /**
414
- * Determines if two tokens have at least one whitespace character
415
- * between them. This completely disregards comments in making the
416
- * determination, so comments count as zero-length substrings.
417
- * @param {Token} first The token to check after.
418
- * @param {Token} second The token to check before.
419
- * @returns {boolean} True if there is only space between tokens, false
420
- * if there is anything other than whitespace between tokens.
476
+ * Determines if two nodes or tokens have at least one whitespace character
477
+ * between them. Order does not matter. Returns false if the given nodes or
478
+ * tokens overlap.
479
+ * @param {ASTNode|Token} first The first node or token to check between.
480
+ * @param {ASTNode|Token} second The second node or token to check between.
481
+ * @returns {boolean} True if there is a whitespace character between
482
+ * any of the tokens found between the two given nodes or tokens.
421
483
  * @public
422
484
  */
423
- isSpaceBetweenTokens(first, second) {
424
- const text = this.text.slice(first.range[1], second.range[0]);
485
+ isSpaceBetween(first, second) {
486
+ return isSpaceBetween(this, first, second, false);
487
+ }
425
488
 
426
- return /\s/u.test(text.replace(/\/\*.*?\*\//gus, ""));
489
+ /**
490
+ * Determines if two nodes or tokens have at least one whitespace character
491
+ * between them. Order does not matter. Returns false if the given nodes or
492
+ * tokens overlap.
493
+ * For backward compatibility, this method returns true if there are
494
+ * `JSXText` tokens that contain whitespaces between the two.
495
+ * @param {ASTNode|Token} first The first node or token to check between.
496
+ * @param {ASTNode|Token} second The second node or token to check between.
497
+ * @returns {boolean} True if there is a whitespace character between
498
+ * any of the tokens found between the two given nodes or tokens.
499
+ * @deprecated in favor of isSpaceBetween().
500
+ * @public
501
+ */
502
+ isSpaceBetweenTokens(first, second) {
503
+ return isSpaceBetween(this, first, second, true);
427
504
  }
428
505
 
429
506
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "6.6.0",
3
+ "version": "6.8.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {
@@ -42,6 +42,7 @@
42
42
  "messages"
43
43
  ],
44
44
  "repository": "eslint/eslint",
45
+ "funding": "https://opencollective.com/eslint",
45
46
  "homepage": "https://eslint.org",
46
47
  "bugs": "https://github.com/eslint/eslint/issues/",
47
48
  "dependencies": {
@@ -60,7 +61,7 @@
60
61
  "file-entry-cache": "^5.0.1",
61
62
  "functional-red-black-tree": "^1.0.1",
62
63
  "glob-parent": "^5.0.0",
63
- "globals": "^11.7.0",
64
+ "globals": "^12.1.0",
64
65
  "ignore": "^4.0.6",
65
66
  "import-fresh": "^3.0.0",
66
67
  "imurmurhash": "^0.1.4",
@@ -73,7 +74,7 @@
73
74
  "minimatch": "^3.0.4",
74
75
  "mkdirp": "^0.5.1",
75
76
  "natural-compare": "^1.4.0",
76
- "optionator": "^0.8.2",
77
+ "optionator": "^0.8.3",
77
78
  "progress": "^2.0.0",
78
79
  "regexpp": "^2.0.1",
79
80
  "semver": "^6.1.2",