eslint 8.22.0 → 8.33.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 (80) hide show
  1. package/README.md +51 -45
  2. package/bin/eslint.js +2 -4
  3. package/conf/globals.js +6 -1
  4. package/conf/rule-type-list.json +2 -2
  5. package/lib/cli-engine/file-enumerator.js +4 -2
  6. package/lib/cli-engine/formatters/formatters-meta.json +46 -0
  7. package/lib/cli-engine/formatters/html.js +76 -51
  8. package/lib/cli.js +163 -40
  9. package/lib/config/default-config.js +2 -2
  10. package/lib/config/flat-config-array.js +1 -1
  11. package/lib/eslint/eslint-helpers.js +409 -87
  12. package/lib/eslint/eslint.js +5 -2
  13. package/lib/eslint/flat-eslint.js +113 -110
  14. package/lib/linter/code-path-analysis/code-path-segment.js +2 -2
  15. package/lib/linter/code-path-analysis/code-path-state.js +7 -7
  16. package/lib/linter/code-path-analysis/debug-helpers.js +3 -3
  17. package/lib/linter/code-path-analysis/id-generator.js +2 -2
  18. package/lib/linter/config-comment-parser.js +1 -2
  19. package/lib/linter/linter.js +17 -7
  20. package/lib/linter/timing.js +4 -4
  21. package/lib/options.js +293 -239
  22. package/lib/rule-tester/flat-rule-tester.js +13 -11
  23. package/lib/rule-tester/rule-tester.js +15 -11
  24. package/lib/rules/array-callback-return.js +2 -2
  25. package/lib/rules/comma-dangle.js +3 -3
  26. package/lib/rules/for-direction.js +1 -1
  27. package/lib/rules/func-name-matching.js +2 -2
  28. package/lib/rules/getter-return.js +14 -8
  29. package/lib/rules/global-require.js +2 -1
  30. package/lib/rules/id-length.js +43 -2
  31. package/lib/rules/indent-legacy.js +4 -4
  32. package/lib/rules/indent.js +23 -15
  33. package/lib/rules/index.js +3 -0
  34. package/lib/rules/key-spacing.js +50 -38
  35. package/lib/rules/lines-around-comment.js +2 -2
  36. package/lib/rules/logical-assignment-operators.js +474 -0
  37. package/lib/rules/multiline-ternary.js +2 -2
  38. package/lib/rules/new-cap.js +2 -2
  39. package/lib/rules/no-else-return.js +1 -1
  40. package/lib/rules/no-empty-static-block.js +47 -0
  41. package/lib/rules/no-empty.js +19 -2
  42. package/lib/rules/no-extra-boolean-cast.js +1 -1
  43. package/lib/rules/no-extra-parens.js +18 -3
  44. package/lib/rules/no-fallthrough.js +26 -5
  45. package/lib/rules/no-implicit-coercion.js +20 -1
  46. package/lib/rules/no-implicit-globals.js +5 -0
  47. package/lib/rules/no-invalid-regexp.js +40 -18
  48. package/lib/rules/no-labels.js +1 -1
  49. package/lib/rules/no-lone-blocks.js +1 -1
  50. package/lib/rules/no-loss-of-precision.js +2 -2
  51. package/lib/rules/no-magic-numbers.js +18 -1
  52. package/lib/rules/no-misleading-character-class.js +4 -4
  53. package/lib/rules/no-new-native-nonconstructor.js +64 -0
  54. package/lib/rules/no-obj-calls.js +1 -1
  55. package/lib/rules/no-restricted-exports.js +106 -10
  56. package/lib/rules/no-return-await.js +28 -1
  57. package/lib/rules/no-underscore-dangle.js +36 -11
  58. package/lib/rules/no-unneeded-ternary.js +1 -1
  59. package/lib/rules/no-use-before-define.js +1 -1
  60. package/lib/rules/no-useless-computed-key.js +1 -1
  61. package/lib/rules/no-var.js +2 -2
  62. package/lib/rules/no-warning-comments.js +24 -5
  63. package/lib/rules/padded-blocks.js +1 -1
  64. package/lib/rules/prefer-arrow-callback.js +4 -3
  65. package/lib/rules/prefer-const.js +13 -1
  66. package/lib/rules/prefer-named-capture-group.js +71 -6
  67. package/lib/rules/prefer-object-spread.js +1 -1
  68. package/lib/rules/prefer-regex-literals.js +147 -32
  69. package/lib/rules/prefer-rest-params.js +1 -1
  70. package/lib/rules/require-yield.js +0 -1
  71. package/lib/rules/strict.js +1 -1
  72. package/lib/rules/utils/ast-utils.js +10 -4
  73. package/lib/shared/directives.js +15 -0
  74. package/lib/shared/logging.js +1 -1
  75. package/lib/shared/runtime-info.js +1 -1
  76. package/lib/shared/traverser.js +1 -1
  77. package/lib/shared/types.js +15 -2
  78. package/lib/source-code/token-store/cursor.js +1 -1
  79. package/messages/print-config-with-directory-path.js +1 -1
  80. package/package.json +27 -27
@@ -16,7 +16,7 @@ const astUtils = require("./utils/ast-utils");
16
16
  //------------------------------------------------------------------------------
17
17
 
18
18
  const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/u;
19
- const TARGET_METHODS = /^(?:every|filter|find(?:Index)?|flatMap|forEach|map|reduce(?:Right)?|some|sort)$/u;
19
+ const TARGET_METHODS = /^(?:every|filter|find(?:Last)?(?:Index)?|flatMap|forEach|map|reduce(?:Right)?|some|sort)$/u;
20
20
 
21
21
  /**
22
22
  * Checks a given code path segment is reachable.
@@ -125,7 +125,7 @@ function getArrayMethodName(node) {
125
125
  }
126
126
  }
127
127
 
128
- /* istanbul ignore next: unreachable */
128
+ /* c8 ignore next */
129
129
  return null;
130
130
  }
131
131
 
@@ -50,7 +50,7 @@ function normalizeOptions(optionValue, ecmaVersion) {
50
50
  objects: optionValue,
51
51
  imports: optionValue,
52
52
  exports: optionValue,
53
- functions: (!ecmaVersion || ecmaVersion < 8) ? "ignore" : optionValue
53
+ functions: ecmaVersion < 2017 ? "ignore" : optionValue
54
54
  };
55
55
  }
56
56
  if (typeof optionValue === "object" && optionValue !== null) {
@@ -134,7 +134,7 @@ module.exports = {
134
134
  },
135
135
 
136
136
  create(context) {
137
- const options = normalizeOptions(context.options[0], context.parserOptions.ecmaVersion);
137
+ const options = normalizeOptions(context.options[0], context.languageOptions.ecmaVersion);
138
138
 
139
139
  const sourceCode = context.getSourceCode();
140
140
 
@@ -346,7 +346,7 @@ module.exports = {
346
346
  "always-multiline": forceTrailingCommaIfMultiline,
347
347
  "only-multiline": allowTrailingCommaIfMultiline,
348
348
  never: forbidTrailingComma,
349
- ignore: () => {}
349
+ ignore() {}
350
350
  };
351
351
 
352
352
  return {
@@ -15,7 +15,7 @@ module.exports = {
15
15
  type: "problem",
16
16
 
17
17
  docs: {
18
- description: "Enforce \"for\" loop update clause moving the counter in the right direction.",
18
+ description: "Enforce \"for\" loop update clause moving the counter in the right direction",
19
19
  recommended: true,
20
20
  url: "https://eslint.org/docs/rules/for-direction"
21
21
  },
@@ -44,7 +44,7 @@ function isModuleExports(pattern) {
44
44
  * @returns {boolean} True if the string is a valid identifier
45
45
  */
46
46
  function isIdentifier(name, ecmaVersion) {
47
- if (ecmaVersion >= 6) {
47
+ if (ecmaVersion >= 2015) {
48
48
  return esutils.keyword.isIdentifierES6(name);
49
49
  }
50
50
  return esutils.keyword.isIdentifierES5(name);
@@ -104,7 +104,7 @@ module.exports = {
104
104
  const nameMatches = typeof context.options[0] === "string" ? context.options[0] : "always";
105
105
  const considerPropertyDescriptor = options.considerPropertyDescriptor;
106
106
  const includeModuleExports = options.includeCommonJSModuleExports;
107
- const ecmaVersion = context.parserOptions && context.parserOptions.ecmaVersion ? context.parserOptions.ecmaVersion : 5;
107
+ const ecmaVersion = context.languageOptions.ecmaVersion;
108
108
 
109
109
  /**
110
110
  * Check whether node is a certain CallExpression.
@@ -112,18 +112,24 @@ module.exports = {
112
112
  }
113
113
  if (parent.type === "Property" && astUtils.getStaticPropertyName(parent) === "get" && parent.parent.type === "ObjectExpression") {
114
114
 
115
- // Object.defineProperty()
116
- if (parent.parent.parent.type === "CallExpression" &&
117
- astUtils.getStaticPropertyName(parent.parent.parent.callee) === "defineProperty") {
118
- return true;
115
+ // Object.defineProperty() or Reflect.defineProperty()
116
+ if (parent.parent.parent.type === "CallExpression") {
117
+ const callNode = parent.parent.parent.callee;
118
+
119
+ if (astUtils.isSpecificMemberAccess(callNode, "Object", "defineProperty") ||
120
+ astUtils.isSpecificMemberAccess(callNode, "Reflect", "defineProperty")) {
121
+ return true;
122
+ }
119
123
  }
120
124
 
121
- // Object.defineProperties()
125
+ // Object.defineProperties() or Object.create()
122
126
  if (parent.parent.parent.type === "Property" &&
123
127
  parent.parent.parent.parent.type === "ObjectExpression" &&
124
- parent.parent.parent.parent.parent.type === "CallExpression" &&
125
- astUtils.getStaticPropertyName(parent.parent.parent.parent.parent.callee) === "defineProperties") {
126
- return true;
128
+ parent.parent.parent.parent.parent.type === "CallExpression") {
129
+ const callNode = parent.parent.parent.parent.parent.callee;
130
+
131
+ return astUtils.isSpecificMemberAccess(callNode, "Object", "defineProperties") ||
132
+ astUtils.isSpecificMemberAccess(callNode, "Object", "create");
127
133
  }
128
134
  }
129
135
  }
@@ -28,10 +28,11 @@ function findReference(scope, node) {
28
28
  const references = scope.references.filter(reference => reference.identifier.range[0] === node.range[0] &&
29
29
  reference.identifier.range[1] === node.range[1]);
30
30
 
31
- /* istanbul ignore else: correctly returns null */
32
31
  if (references.length === 1) {
33
32
  return references[0];
34
33
  }
34
+
35
+ /* c8 ignore next */
35
36
  return null;
36
37
 
37
38
  }
@@ -6,6 +6,45 @@
6
6
 
7
7
  "use strict";
8
8
 
9
+ //------------------------------------------------------------------------------
10
+ // Requirements
11
+ //------------------------------------------------------------------------------
12
+ const GraphemeSplitter = require("grapheme-splitter");
13
+
14
+ //------------------------------------------------------------------------------
15
+ // Helpers
16
+ //------------------------------------------------------------------------------
17
+
18
+ /**
19
+ * Checks if the string given as argument is ASCII or not.
20
+ * @param {string} value A string that you want to know if it is ASCII or not.
21
+ * @returns {boolean} `true` if `value` is ASCII string.
22
+ */
23
+ function isASCII(value) {
24
+ if (typeof value !== "string") {
25
+ return false;
26
+ }
27
+ return /^[\u0020-\u007f]*$/u.test(value);
28
+ }
29
+
30
+ /** @type {GraphemeSplitter | undefined} */
31
+ let splitter;
32
+
33
+ /**
34
+ * Gets the length of the string. If the string is not in ASCII, counts graphemes.
35
+ * @param {string} value A string that you want to get the length.
36
+ * @returns {number} The length of `value`.
37
+ */
38
+ function getStringLength(value) {
39
+ if (isASCII(value)) {
40
+ return value.length;
41
+ }
42
+ if (!splitter) {
43
+ splitter = new GraphemeSplitter();
44
+ }
45
+ return splitter.countGraphemes(value);
46
+ }
47
+
9
48
  //------------------------------------------------------------------------------
10
49
  // Rule Definition
11
50
  //------------------------------------------------------------------------------
@@ -130,8 +169,10 @@ module.exports = {
130
169
  const name = node.name;
131
170
  const parent = node.parent;
132
171
 
133
- const isShort = name.length < minLength;
134
- const isLong = name.length > maxLength;
172
+ const nameLength = getStringLength(name);
173
+
174
+ const isShort = nameLength < minLength;
175
+ const isLong = nameLength > maxLength;
135
176
 
136
177
  if (!(isShort || isLong) || exceptions.has(name) || matchesExceptionPattern(name)) {
137
178
  return; // Nothing to report
@@ -18,8 +18,8 @@ const astUtils = require("./utils/ast-utils");
18
18
  //------------------------------------------------------------------------------
19
19
  // Rule Definition
20
20
  //------------------------------------------------------------------------------
21
-
22
- /* istanbul ignore next: this rule has known coverage issues, but it's deprecated and shouldn't be updated in the future anyway. */
21
+ // this rule has known coverage issues, but it's deprecated and shouldn't be updated in the future anyway.
22
+ /* c8 ignore next */
23
23
  /** @type {import('../shared/types').Rule} */
24
24
  module.exports = {
25
25
  meta: {
@@ -212,10 +212,10 @@ module.exports = {
212
212
  if (context.options[0] === "tab") {
213
213
  indentSize = 1;
214
214
  indentType = "tab";
215
- } else /* istanbul ignore else : this will be caught by options validation */ if (typeof context.options[0] === "number") {
215
+ } else /* c8 ignore start */ if (typeof context.options[0] === "number") {
216
216
  indentSize = context.options[0];
217
217
  indentType = "space";
218
- }
218
+ }/* c8 ignore stop */
219
219
 
220
220
  if (context.options[1]) {
221
221
  const opts = context.options[1];
@@ -12,7 +12,7 @@
12
12
  // Requirements
13
13
  //------------------------------------------------------------------------------
14
14
 
15
- const createTree = require("functional-red-black-tree");
15
+ const { OrderedMap } = require("js-sdsl");
16
16
 
17
17
  const astUtils = require("./utils/ast-utils");
18
18
 
@@ -135,7 +135,8 @@ class BinarySearchTree {
135
135
  * Creates an empty tree
136
136
  */
137
137
  constructor() {
138
- this._rbTree = createTree();
138
+ this._orderedMap = new OrderedMap();
139
+ this._orderedMapEnd = this._orderedMap.end();
139
140
  }
140
141
 
141
142
  /**
@@ -145,13 +146,7 @@ class BinarySearchTree {
145
146
  * @returns {void}
146
147
  */
147
148
  insert(key, value) {
148
- const iterator = this._rbTree.find(key);
149
-
150
- if (iterator.valid) {
151
- this._rbTree = iterator.update(value);
152
- } else {
153
- this._rbTree = this._rbTree.insert(key, value);
154
- }
149
+ this._orderedMap.setElement(key, value);
155
150
  }
156
151
 
157
152
  /**
@@ -160,9 +155,13 @@ class BinarySearchTree {
160
155
  * @returns {{key: number, value: *}|null} The found entry, or null if no such entry exists.
161
156
  */
162
157
  findLe(key) {
163
- const iterator = this._rbTree.le(key);
158
+ const iterator = this._orderedMap.reverseLowerBound(key);
164
159
 
165
- return iterator && { key: iterator.key, value: iterator.value };
160
+ if (iterator.equals(this._orderedMapEnd)) {
161
+ return {};
162
+ }
163
+
164
+ return { key: iterator.pointer[0], value: iterator.pointer[1] };
166
165
  }
167
166
 
168
167
  /**
@@ -177,11 +176,20 @@ class BinarySearchTree {
177
176
  if (start === end) {
178
177
  return;
179
178
  }
180
- const iterator = this._rbTree.ge(start);
179
+ const iterator = this._orderedMap.lowerBound(start);
181
180
 
182
- while (iterator.valid && iterator.key < end) {
183
- this._rbTree = this._rbTree.remove(iterator.key);
184
- iterator.next();
181
+ if (iterator.equals(this._orderedMapEnd)) {
182
+ return;
183
+ }
184
+
185
+ if (end > this._orderedMap.back()[0]) {
186
+ while (!iterator.equals(this._orderedMapEnd)) {
187
+ this._orderedMap.eraseElementByIterator(iterator);
188
+ }
189
+ } else {
190
+ while (iterator.pointer[0] < end) {
191
+ this._orderedMap.eraseElementByIterator(iterator);
192
+ }
185
193
  }
186
194
  }
187
195
  }
@@ -72,6 +72,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
72
72
  "lines-around-comment": () => require("./lines-around-comment"),
73
73
  "lines-around-directive": () => require("./lines-around-directive"),
74
74
  "lines-between-class-members": () => require("./lines-between-class-members"),
75
+ "logical-assignment-operators": () => require("./logical-assignment-operators"),
75
76
  "max-classes-per-file": () => require("./max-classes-per-file"),
76
77
  "max-depth": () => require("./max-depth"),
77
78
  "max-len": () => require("./max-len"),
@@ -122,6 +123,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
122
123
  "no-empty-character-class": () => require("./no-empty-character-class"),
123
124
  "no-empty-function": () => require("./no-empty-function"),
124
125
  "no-empty-pattern": () => require("./no-empty-pattern"),
126
+ "no-empty-static-block": () => require("./no-empty-static-block"),
125
127
  "no-eq-null": () => require("./no-eq-null"),
126
128
  "no-eval": () => require("./no-eval"),
127
129
  "no-ex-assign": () => require("./no-ex-assign"),
@@ -166,6 +168,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
166
168
  "no-nested-ternary": () => require("./no-nested-ternary"),
167
169
  "no-new": () => require("./no-new"),
168
170
  "no-new-func": () => require("./no-new-func"),
171
+ "no-new-native-nonconstructor": () => require("./no-new-native-nonconstructor"),
169
172
  "no-new-object": () => require("./no-new-object"),
170
173
  "no-new-require": () => require("./no-new-require"),
171
174
  "no-new-symbol": () => require("./no-new-symbol"),
@@ -334,6 +334,53 @@ module.exports = {
334
334
 
335
335
  const sourceCode = context.getSourceCode();
336
336
 
337
+ /**
338
+ * Determines if the given property is key-value property.
339
+ * @param {ASTNode} property Property node to check.
340
+ * @returns {boolean} Whether the property is a key-value property.
341
+ */
342
+ function isKeyValueProperty(property) {
343
+ return !(
344
+ (property.method ||
345
+ property.shorthand ||
346
+ property.kind !== "init" || property.type !== "Property") // Could be "ExperimentalSpreadProperty" or "SpreadElement"
347
+ );
348
+ }
349
+
350
+ /**
351
+ * Starting from the given node (a property.key node here) looks forward
352
+ * until it finds the colon punctuator and returns it.
353
+ * @param {ASTNode} node The node to start looking from.
354
+ * @returns {ASTNode} The colon punctuator.
355
+ */
356
+ function getNextColon(node) {
357
+ return sourceCode.getTokenAfter(node, astUtils.isColonToken);
358
+ }
359
+
360
+ /**
361
+ * Starting from the given node (a property.key node here) looks forward
362
+ * until it finds the last token before a colon punctuator and returns it.
363
+ * @param {ASTNode} node The node to start looking from.
364
+ * @returns {ASTNode} The last token before a colon punctuator.
365
+ */
366
+ function getLastTokenBeforeColon(node) {
367
+ const colonToken = getNextColon(node);
368
+
369
+ return sourceCode.getTokenBefore(colonToken);
370
+ }
371
+
372
+ /**
373
+ * Starting from the given node (a property.key node here) looks forward
374
+ * until it finds the first token after a colon punctuator and returns it.
375
+ * @param {ASTNode} node The node to start looking from.
376
+ * @returns {ASTNode} The first token after a colon punctuator.
377
+ */
378
+ function getFirstTokenAfterColon(node) {
379
+ const colonToken = getNextColon(node);
380
+
381
+ return sourceCode.getTokenAfter(colonToken);
382
+ }
383
+
337
384
  /**
338
385
  * Checks whether a property is a member of the property group it follows.
339
386
  * @param {ASTNode} lastMember The last Property known to be in the group.
@@ -342,9 +389,9 @@ module.exports = {
342
389
  */
343
390
  function continuesPropertyGroup(lastMember, candidate) {
344
391
  const groupEndLine = lastMember.loc.start.line,
345
- candidateStartLine = candidate.loc.start.line;
392
+ candidateValueStartLine = (isKeyValueProperty(candidate) ? getFirstTokenAfterColon(candidate.key) : candidate).loc.start.line;
346
393
 
347
- if (candidateStartLine - groupEndLine <= 1) {
394
+ if (candidateValueStartLine - groupEndLine <= 1) {
348
395
  return true;
349
396
  }
350
397
 
@@ -358,7 +405,7 @@ module.exports = {
358
405
  if (
359
406
  leadingComments.length &&
360
407
  leadingComments[0].loc.start.line - groupEndLine <= 1 &&
361
- candidateStartLine - last(leadingComments).loc.end.line <= 1
408
+ candidateValueStartLine - last(leadingComments).loc.end.line <= 1
362
409
  ) {
363
410
  for (let i = 1; i < leadingComments.length; i++) {
364
411
  if (leadingComments[i].loc.start.line - leadingComments[i - 1].loc.end.line > 1) {
@@ -371,41 +418,6 @@ module.exports = {
371
418
  return false;
372
419
  }
373
420
 
374
- /**
375
- * Determines if the given property is key-value property.
376
- * @param {ASTNode} property Property node to check.
377
- * @returns {boolean} Whether the property is a key-value property.
378
- */
379
- function isKeyValueProperty(property) {
380
- return !(
381
- (property.method ||
382
- property.shorthand ||
383
- property.kind !== "init" || property.type !== "Property") // Could be "ExperimentalSpreadProperty" or "SpreadElement"
384
- );
385
- }
386
-
387
- /**
388
- * Starting from the given a node (a property.key node here) looks forward
389
- * until it finds the last token before a colon punctuator and returns it.
390
- * @param {ASTNode} node The node to start looking from.
391
- * @returns {ASTNode} The last token before a colon punctuator.
392
- */
393
- function getLastTokenBeforeColon(node) {
394
- const colonToken = sourceCode.getTokenAfter(node, astUtils.isColonToken);
395
-
396
- return sourceCode.getTokenBefore(colonToken);
397
- }
398
-
399
- /**
400
- * Starting from the given a node (a property.key node here) looks forward
401
- * until it finds the colon punctuator and returns it.
402
- * @param {ASTNode} node The node to start looking from.
403
- * @returns {ASTNode} The colon punctuator.
404
- */
405
- function getNextColon(node) {
406
- return sourceCode.getTokenAfter(node, astUtils.isColonToken);
407
- }
408
-
409
421
  /**
410
422
  * Gets an object literal property's key as the identifier name or string value.
411
423
  * @param {ASTNode} property Property node whose key to retrieve.
@@ -15,7 +15,7 @@ const astUtils = require("./utils/ast-utils");
15
15
  //------------------------------------------------------------------------------
16
16
 
17
17
  /**
18
- * Return an array with with any line numbers that are empty.
18
+ * Return an array with any line numbers that are empty.
19
19
  * @param {Array} lines An array of each line of the file.
20
20
  * @returns {Array} An array of line numbers.
21
21
  */
@@ -29,7 +29,7 @@ function getEmptyLineNums(lines) {
29
29
  }
30
30
 
31
31
  /**
32
- * Return an array with with any line numbers that contain comments.
32
+ * Return an array with any line numbers that contain comments.
33
33
  * @param {Array} comments An array of comment tokens.
34
34
  * @returns {Array} An array of line numbers.
35
35
  */