eslint 7.0.0 → 7.3.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 (70) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +14 -10
  3. package/lib/cli-engine/cli-engine.js +2 -2
  4. package/lib/cli-engine/config-array-factory.js +34 -2
  5. package/lib/init/config-initializer.js +92 -74
  6. package/lib/linter/code-path-analysis/code-path-analyzer.js +2 -2
  7. package/lib/linter/code-path-analysis/code-path-state.js +34 -12
  8. package/lib/linter/config-comment-parser.js +1 -1
  9. package/lib/linter/linter.js +2 -1
  10. package/lib/rule-tester/rule-tester.js +9 -0
  11. package/lib/rules/accessor-pairs.js +1 -1
  12. package/lib/rules/arrow-parens.js +19 -3
  13. package/lib/rules/block-spacing.js +19 -2
  14. package/lib/rules/callback-return.js +1 -1
  15. package/lib/rules/comma-dangle.js +2 -1
  16. package/lib/rules/curly.js +8 -1
  17. package/lib/rules/func-call-spacing.js +18 -3
  18. package/lib/rules/global-require.js +1 -1
  19. package/lib/rules/handle-callback-err.js +1 -1
  20. package/lib/rules/id-match.js +2 -1
  21. package/lib/rules/index.js +3 -0
  22. package/lib/rules/key-spacing.js +6 -2
  23. package/lib/rules/keyword-spacing.js +9 -2
  24. package/lib/rules/linebreak-style.js +8 -2
  25. package/lib/rules/max-lines-per-function.js +1 -1
  26. package/lib/rules/max-lines.js +34 -8
  27. package/lib/rules/multiline-ternary.js +44 -25
  28. package/lib/rules/no-buffer-constructor.js +1 -1
  29. package/lib/rules/no-control-regex.js +1 -1
  30. package/lib/rules/no-extra-boolean-cast.js +3 -0
  31. package/lib/rules/no-extra-parens.js +30 -2
  32. package/lib/rules/no-invalid-regexp.js +1 -1
  33. package/lib/rules/no-loss-of-precision.js +198 -0
  34. package/lib/rules/no-misleading-character-class.js +1 -1
  35. package/lib/rules/no-mixed-operators.js +3 -2
  36. package/lib/rules/no-mixed-requires.js +1 -1
  37. package/lib/rules/no-mixed-spaces-and-tabs.js +14 -6
  38. package/lib/rules/no-new-func.js +22 -19
  39. package/lib/rules/no-new-require.js +1 -1
  40. package/lib/rules/no-new-symbol.js +2 -1
  41. package/lib/rules/no-path-concat.js +1 -1
  42. package/lib/rules/no-process-env.js +1 -1
  43. package/lib/rules/no-process-exit.js +1 -1
  44. package/lib/rules/no-promise-executor-return.js +121 -0
  45. package/lib/rules/no-regex-spaces.js +1 -1
  46. package/lib/rules/no-restricted-exports.js +6 -0
  47. package/lib/rules/no-restricted-modules.js +1 -1
  48. package/lib/rules/no-sync.js +1 -1
  49. package/lib/rules/no-unneeded-ternary.js +6 -4
  50. package/lib/rules/no-unreachable-loop.js +150 -0
  51. package/lib/rules/no-unused-expressions.js +1 -1
  52. package/lib/rules/no-unused-vars.js +5 -2
  53. package/lib/rules/no-useless-backreference.js +1 -1
  54. package/lib/rules/object-property-newline.js +1 -1
  55. package/lib/rules/one-var-declaration-per-line.js +1 -1
  56. package/lib/rules/operator-linebreak.js +2 -5
  57. package/lib/rules/padded-blocks.js +19 -5
  58. package/lib/rules/prefer-named-capture-group.js +1 -1
  59. package/lib/rules/quote-props.js +2 -2
  60. package/lib/rules/rest-spread-spacing.js +3 -6
  61. package/lib/rules/semi-spacing.js +33 -8
  62. package/lib/rules/template-tag-spacing.js +8 -2
  63. package/lib/rules/utils/ast-utils.js +106 -9
  64. package/lib/source-code/source-code.js +1 -0
  65. package/messages/extend-config-missing.txt +1 -1
  66. package/messages/no-config-found.txt +1 -1
  67. package/messages/plugin-conflict.txt +1 -1
  68. package/messages/plugin-missing.txt +1 -1
  69. package/messages/whitespace-found.txt +1 -1
  70. package/package.json +6 -6
@@ -12,7 +12,7 @@ module.exports = {
12
12
  meta: {
13
13
  deprecated: true,
14
14
 
15
- replacedBy: ["node/no-deprecated-api"],
15
+ replacedBy: [],
16
16
 
17
17
  type: "problem",
18
18
 
@@ -35,7 +35,7 @@ const collector = new (class {
35
35
  try {
36
36
  this._source = regexpStr;
37
37
  this._validator.validatePattern(regexpStr); // Call onCharacter hook
38
- } catch (err) {
38
+ } catch {
39
39
 
40
40
  // Ignore syntax errors in RegExp.
41
41
  }
@@ -172,6 +172,9 @@ module.exports = {
172
172
  case "UnaryExpression":
173
173
  return precedence(node) < precedence(parent);
174
174
  case "LogicalExpression":
175
+ if (astUtils.isMixedLogicalAndCoalesceExpressions(node, parent)) {
176
+ return true;
177
+ }
175
178
  if (previousNode === parent.left) {
176
179
  return precedence(node) < precedence(parent);
177
180
  }
@@ -51,7 +51,8 @@ module.exports = {
51
51
  ignoreJSX: { enum: ["none", "all", "single-line", "multi-line"] },
52
52
  enforceForArrowConditionals: { type: "boolean" },
53
53
  enforceForSequenceExpressions: { type: "boolean" },
54
- enforceForNewInMemberExpressions: { type: "boolean" }
54
+ enforceForNewInMemberExpressions: { type: "boolean" },
55
+ enforceForFunctionPrototypeMethods: { type: "boolean" }
55
56
  },
56
57
  additionalProperties: false
57
58
  }
@@ -83,12 +84,28 @@ module.exports = {
83
84
  context.options[1].enforceForSequenceExpressions === false;
84
85
  const IGNORE_NEW_IN_MEMBER_EXPR = ALL_NODES && context.options[1] &&
85
86
  context.options[1].enforceForNewInMemberExpressions === false;
87
+ const IGNORE_FUNCTION_PROTOTYPE_METHODS = ALL_NODES && context.options[1] &&
88
+ context.options[1].enforceForFunctionPrototypeMethods === false;
86
89
 
87
90
  const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" });
88
91
  const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" });
89
92
 
90
93
  let reportsBuffer;
91
94
 
95
+ /**
96
+ * Determines whether the given node is a `call` or `apply` method call, invoked directly on a `FunctionExpression` node.
97
+ * Example: function(){}.call()
98
+ * @param {ASTNode} node The node to be checked.
99
+ * @returns {boolean} True if the node is an immediate `call` or `apply` method call.
100
+ * @private
101
+ */
102
+ function isImmediateFunctionPrototypeMethodCall(node) {
103
+ return node.type === "CallExpression" &&
104
+ node.callee.type === "MemberExpression" &&
105
+ node.callee.object.type === "FunctionExpression" &&
106
+ ["call", "apply"].includes(astUtils.getStaticPropertyName(node.callee));
107
+ }
108
+
92
109
  /**
93
110
  * Determines if this rule should be enforced for a node given the current configuration.
94
111
  * @param {ASTNode} node The node to be checked.
@@ -125,6 +142,10 @@ module.exports = {
125
142
  return false;
126
143
  }
127
144
 
145
+ if (isImmediateFunctionPrototypeMethodCall(node) && IGNORE_FUNCTION_PROTOTYPE_METHODS) {
146
+ return false;
147
+ }
148
+
128
149
  return ALL_NODES || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
129
150
  }
130
151
 
@@ -478,6 +499,7 @@ module.exports = {
478
499
  if (!shouldSkipLeft && hasExcessParens(node.left)) {
479
500
  if (
480
501
  !(node.left.type === "UnaryExpression" && isExponentiation) &&
502
+ !astUtils.isMixedLogicalAndCoalesceExpressions(node.left, node) &&
481
503
  (leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation)) ||
482
504
  isParenthesisedTwice(node.left)
483
505
  ) {
@@ -487,6 +509,7 @@ module.exports = {
487
509
 
488
510
  if (!shouldSkipRight && hasExcessParens(node.right)) {
489
511
  if (
512
+ !astUtils.isMixedLogicalAndCoalesceExpressions(node.right, node) &&
490
513
  (rightPrecedence > prec || (rightPrecedence === prec && isExponentiation)) ||
491
514
  isParenthesisedTwice(node.right)
492
515
  ) {
@@ -927,7 +950,12 @@ module.exports = {
927
950
  LogicalExpression: checkBinaryLogical,
928
951
 
929
952
  MemberExpression(node) {
930
- const nodeObjHasExcessParens = hasExcessParens(node.object);
953
+ const nodeObjHasExcessParens = hasExcessParens(node.object) &&
954
+ !(
955
+ isImmediateFunctionPrototypeMethodCall(node.parent) &&
956
+ node.parent.callee === node &&
957
+ IGNORE_FUNCTION_PROTOTYPE_METHODS
958
+ );
931
959
 
932
960
  if (
933
961
  nodeObjHasExcessParens &&
@@ -93,7 +93,7 @@ module.exports = {
93
93
  try {
94
94
  validator.validateFlags(flags);
95
95
  return null;
96
- } catch (err) {
96
+ } catch {
97
97
  return `Invalid flags supplied to RegExp constructor '${flags}'`;
98
98
  }
99
99
  }
@@ -0,0 +1,198 @@
1
+ /**
2
+ * @fileoverview Rule to flag numbers that will lose significant figure precision at runtime
3
+ * @author Jacob Moore
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Rule Definition
10
+ //------------------------------------------------------------------------------
11
+
12
+ module.exports = {
13
+ meta: {
14
+ type: "problem",
15
+
16
+ docs: {
17
+ description: "disallow literal numbers that lose precision",
18
+ category: "Possible Errors",
19
+ recommended: false,
20
+ url: "https://eslint.org/docs/rules/no-loss-of-precision"
21
+ },
22
+ schema: [],
23
+ messages: {
24
+ noLossOfPrecision: "This number literal will lose precision at runtime."
25
+ }
26
+ },
27
+
28
+ create(context) {
29
+
30
+ /**
31
+ * Returns whether the node is number literal
32
+ * @param {Node} node the node literal being evaluated
33
+ * @returns {boolean} true if the node is a number literal
34
+ */
35
+ function isNumber(node) {
36
+ return typeof node.value === "number";
37
+ }
38
+
39
+
40
+ /**
41
+ * Checks whether the number is base ten
42
+ * @param {ASTNode} node the node being evaluated
43
+ * @returns {boolean} true if the node is in base ten
44
+ */
45
+ function isBaseTen(node) {
46
+ const prefixes = ["0x", "0X", "0b", "0B", "0o", "0O"];
47
+
48
+ return prefixes.every(prefix => !node.raw.startsWith(prefix)) &&
49
+ !/^0[0-7]+$/u.test(node.raw);
50
+ }
51
+
52
+ /**
53
+ * Checks that the user-intended non-base ten number equals the actual number after is has been converted to the Number type
54
+ * @param {Node} node the node being evaluated
55
+ * @returns {boolean} true if they do not match
56
+ */
57
+ function notBaseTenLosesPrecision(node) {
58
+ const rawString = node.raw.toUpperCase();
59
+ let base = 0;
60
+
61
+ if (rawString.startsWith("0B")) {
62
+ base = 2;
63
+ } else if (rawString.startsWith("0X")) {
64
+ base = 16;
65
+ } else {
66
+ base = 8;
67
+ }
68
+
69
+ return !rawString.endsWith(node.value.toString(base).toUpperCase());
70
+ }
71
+
72
+ /**
73
+ * Adds a decimal point to the numeric string at index 1
74
+ * @param {string} stringNumber the numeric string without any decimal point
75
+ * @returns {string} the numeric string with a decimal point in the proper place
76
+ */
77
+ function addDecimalPointToNumber(stringNumber) {
78
+ return `${stringNumber.slice(0, 1)}.${stringNumber.slice(1)}`;
79
+ }
80
+
81
+ /**
82
+ * Returns the number stripped of leading zeros
83
+ * @param {string} numberAsString the string representation of the number
84
+ * @returns {string} the stripped string
85
+ */
86
+ function removeLeadingZeros(numberAsString) {
87
+ return numberAsString.replace(/^0*/u, "");
88
+ }
89
+
90
+ /**
91
+ * Returns the number stripped of trailing zeros
92
+ * @param {string} numberAsString the string representation of the number
93
+ * @returns {string} the stripped string
94
+ */
95
+ function removeTrailingZeros(numberAsString) {
96
+ return numberAsString.replace(/0*$/u, "");
97
+ }
98
+
99
+ /**
100
+ * Converts an integer to to an object containing the the integer's coefficient and order of magnitude
101
+ * @param {string} stringInteger the string representation of the integer being converted
102
+ * @returns {Object} the object containing the the integer's coefficient and order of magnitude
103
+ */
104
+ function normalizeInteger(stringInteger) {
105
+ const significantDigits = removeTrailingZeros(removeLeadingZeros(stringInteger));
106
+
107
+ return {
108
+ magnitude: stringInteger.startsWith("0") ? stringInteger.length - 2 : stringInteger.length - 1,
109
+ coefficient: addDecimalPointToNumber(significantDigits)
110
+ };
111
+ }
112
+
113
+ /**
114
+ *
115
+ * Converts a float to to an object containing the the floats's coefficient and order of magnitude
116
+ * @param {string} stringFloat the string representation of the float being converted
117
+ * @returns {Object} the object containing the the integer's coefficient and order of magnitude
118
+ */
119
+ function normalizeFloat(stringFloat) {
120
+ const trimmedFloat = removeLeadingZeros(stringFloat);
121
+
122
+ if (trimmedFloat.startsWith(".")) {
123
+ const decimalDigits = trimmedFloat.split(".").pop();
124
+ const significantDigits = removeLeadingZeros(decimalDigits);
125
+
126
+ return {
127
+ magnitude: significantDigits.length - decimalDigits.length - 1,
128
+ coefficient: addDecimalPointToNumber(significantDigits)
129
+ };
130
+
131
+ }
132
+ return {
133
+ magnitude: trimmedFloat.indexOf(".") - 1,
134
+ coefficient: addDecimalPointToNumber(trimmedFloat.replace(".", ""))
135
+
136
+ };
137
+ }
138
+
139
+
140
+ /**
141
+ * Converts a base ten number to proper scientific notation
142
+ * @param {string} stringNumber the string representation of the base ten number to be converted
143
+ * @returns {string} the number converted to scientific notation
144
+ */
145
+ function convertNumberToScientificNotation(stringNumber) {
146
+ const splitNumber = stringNumber.replace("E", "e").split("e");
147
+ const originalCoefficient = splitNumber[0];
148
+ const normalizedNumber = stringNumber.includes(".") ? normalizeFloat(originalCoefficient)
149
+ : normalizeInteger(originalCoefficient);
150
+ const normalizedCoefficient = normalizedNumber.coefficient;
151
+ const magnitude = splitNumber.length > 1 ? (parseInt(splitNumber[1], 10) + normalizedNumber.magnitude)
152
+ : normalizedNumber.magnitude;
153
+
154
+ return `${normalizedCoefficient}e${magnitude}`;
155
+
156
+ }
157
+
158
+ /**
159
+ * Checks that the user-intended base ten number equals the actual number after is has been converted to the Number type
160
+ * @param {Node} node the node being evaluated
161
+ * @returns {boolean} true if they do not match
162
+ */
163
+ function baseTenLosesPrecision(node) {
164
+ const normalizedRawNumber = convertNumberToScientificNotation(node.raw);
165
+ const requestedPrecision = normalizedRawNumber.split("e")[0].replace(".", "").length;
166
+
167
+ if (requestedPrecision > 100) {
168
+ return true;
169
+ }
170
+ const storedNumber = node.value.toPrecision(requestedPrecision);
171
+ const normalizedStoredNumber = convertNumberToScientificNotation(storedNumber);
172
+
173
+ return normalizedRawNumber !== normalizedStoredNumber;
174
+ }
175
+
176
+
177
+ /**
178
+ * Checks that the user-intended number equals the actual number after is has been converted to the Number type
179
+ * @param {Node} node the node being evaluated
180
+ * @returns {boolean} true if they do not match
181
+ */
182
+ function losesPrecision(node) {
183
+ return isBaseTen(node) ? baseTenLosesPrecision(node) : notBaseTenLosesPrecision(node);
184
+ }
185
+
186
+
187
+ return {
188
+ Literal(node) {
189
+ if (node.value && isNumber(node) && losesPrecision(node)) {
190
+ context.report({
191
+ messageId: "noLossOfPrecision",
192
+ node
193
+ });
194
+ }
195
+ }
196
+ };
197
+ }
198
+ };
@@ -147,7 +147,7 @@ module.exports = {
147
147
  pattern.length,
148
148
  flags.includes("u")
149
149
  );
150
- } catch (e) {
150
+ } catch {
151
151
 
152
152
  // Ignore regular expressions with syntax errors
153
153
  return;
@@ -21,13 +21,15 @@ const COMPARISON_OPERATORS = ["==", "!=", "===", "!==", ">", ">=", "<", "<="];
21
21
  const LOGICAL_OPERATORS = ["&&", "||"];
22
22
  const RELATIONAL_OPERATORS = ["in", "instanceof"];
23
23
  const TERNARY_OPERATOR = ["?:"];
24
+ const COALESCE_OPERATOR = ["??"];
24
25
  const ALL_OPERATORS = [].concat(
25
26
  ARITHMETIC_OPERATORS,
26
27
  BITWISE_OPERATORS,
27
28
  COMPARISON_OPERATORS,
28
29
  LOGICAL_OPERATORS,
29
30
  RELATIONAL_OPERATORS,
30
- TERNARY_OPERATOR
31
+ TERNARY_OPERATOR,
32
+ COALESCE_OPERATOR
31
33
  );
32
34
  const DEFAULT_GROUPS = [
33
35
  ARITHMETIC_OPERATORS,
@@ -236,7 +238,6 @@ module.exports = {
236
238
  return {
237
239
  BinaryExpression: check,
238
240
  LogicalExpression: check
239
-
240
241
  };
241
242
  }
242
243
  };
@@ -13,7 +13,7 @@ module.exports = {
13
13
  meta: {
14
14
  deprecated: true,
15
15
 
16
- replacedBy: ["node/no-mixed-requires"],
16
+ replacedBy: [],
17
17
 
18
18
  type: "suggestion",
19
19
 
@@ -67,7 +67,7 @@ module.exports = {
67
67
  * or the reverse before non-tab/-space
68
68
  * characters begin.
69
69
  */
70
- let regex = /^(?=[\t ]*(\t | \t))/u;
70
+ let regex = /^(?=( +|\t+))\1(?:\t| )/u;
71
71
 
72
72
  if (smartTabs) {
73
73
 
@@ -75,19 +75,27 @@ module.exports = {
75
75
  * At least one space followed by a tab
76
76
  * before non-tab/-space characters begin.
77
77
  */
78
- regex = /^(?=[\t ]* \t)/u;
78
+ regex = /^(?=(\t*))\1(?=( +))\2\t/u;
79
79
  }
80
80
 
81
81
  lines.forEach((line, i) => {
82
82
  const match = regex.exec(line);
83
83
 
84
84
  if (match) {
85
- const lineNumber = i + 1,
86
- column = match.index + 1,
87
- loc = { line: lineNumber, column };
85
+ const lineNumber = i + 1;
86
+ const loc = {
87
+ start: {
88
+ line: lineNumber,
89
+ column: match[0].length - 2
90
+ },
91
+ end: {
92
+ line: lineNumber,
93
+ column: match[0].length
94
+ }
95
+ };
88
96
 
89
97
  if (!ignoredCommentLines.has(lineNumber)) {
90
- const containingNode = sourceCode.getNodeByRangeIndex(sourceCode.getIndexFromLoc(loc));
98
+ const containingNode = sourceCode.getNodeByRangeIndex(sourceCode.getIndexFromLoc(loc.start));
91
99
 
92
100
  if (!(containingNode && ["Literal", "TemplateElement"].includes(containingNode.type))) {
93
101
  context.report({
@@ -29,26 +29,29 @@ module.exports = {
29
29
 
30
30
  create(context) {
31
31
 
32
- //--------------------------------------------------------------------------
33
- // Helpers
34
- //--------------------------------------------------------------------------
35
-
36
- /**
37
- * Reports a node.
38
- * @param {ASTNode} node The node to report
39
- * @returns {void}
40
- * @private
41
- */
42
- function report(node) {
43
- context.report({
44
- node,
45
- messageId: "noFunctionConstructor"
46
- });
47
- }
48
-
49
32
  return {
50
- "NewExpression[callee.name = 'Function']": report,
51
- "CallExpression[callee.name = 'Function']": report
33
+ "Program:exit"() {
34
+ const globalScope = context.getScope();
35
+ const variable = globalScope.set.get("Function");
36
+
37
+ if (variable && variable.defs.length === 0) {
38
+ variable.references.forEach(ref => {
39
+ const node = ref.identifier;
40
+ const { parent } = node;
41
+
42
+ if (
43
+ parent &&
44
+ (parent.type === "NewExpression" || parent.type === "CallExpression") &&
45
+ node === parent.callee
46
+ ) {
47
+ context.report({
48
+ node: parent,
49
+ messageId: "noFunctionConstructor"
50
+ });
51
+ }
52
+ });
53
+ }
54
+ }
52
55
  };
53
56
 
54
57
  }
@@ -13,7 +13,7 @@ module.exports = {
13
13
  meta: {
14
14
  deprecated: true,
15
15
 
16
- replacedBy: ["node/no-new-require"],
16
+ replacedBy: [],
17
17
 
18
18
  type: "suggestion",
19
19
 
@@ -37,8 +37,9 @@ module.exports = {
37
37
  if (variable && variable.defs.length === 0) {
38
38
  variable.references.forEach(ref => {
39
39
  const node = ref.identifier;
40
+ const parent = node.parent;
40
41
 
41
- if (node.parent && node.parent.type === "NewExpression") {
42
+ if (parent && parent.type === "NewExpression" && parent.callee === node) {
42
43
  context.report({
43
44
  node,
44
45
  messageId: "noNewSymbol"
@@ -12,7 +12,7 @@ module.exports = {
12
12
  meta: {
13
13
  deprecated: true,
14
14
 
15
- replacedBy: ["node/no-path-concat"],
15
+ replacedBy: [],
16
16
 
17
17
  type: "suggestion",
18
18
 
@@ -12,7 +12,7 @@ module.exports = {
12
12
  meta: {
13
13
  deprecated: true,
14
14
 
15
- replacedBy: ["node/no-process-env"],
15
+ replacedBy: [],
16
16
 
17
17
  type: "suggestion",
18
18
 
@@ -12,7 +12,7 @@ module.exports = {
12
12
  meta: {
13
13
  deprecated: true,
14
14
 
15
- replacedBy: ["node/no-process-exit"],
15
+ replacedBy: [],
16
16
 
17
17
  type: "suggestion",
18
18
 
@@ -0,0 +1,121 @@
1
+ /**
2
+ * @fileoverview Rule to disallow returning values from Promise executor functions
3
+ * @author Milos Djermanovic
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const { findVariable } = require("eslint-utils");
13
+
14
+ //------------------------------------------------------------------------------
15
+ // Helpers
16
+ //------------------------------------------------------------------------------
17
+
18
+ const functionTypesToCheck = new Set(["ArrowFunctionExpression", "FunctionExpression"]);
19
+
20
+ /**
21
+ * Determines whether the given identifier node is a reference to a global variable.
22
+ * @param {ASTNode} node `Identifier` node to check.
23
+ * @param {Scope} scope Scope to which the node belongs.
24
+ * @returns {boolean} True if the identifier is a reference to a global variable.
25
+ */
26
+ function isGlobalReference(node, scope) {
27
+ const variable = findVariable(scope, node);
28
+
29
+ return variable !== null && variable.scope.type === "global" && variable.defs.length === 0;
30
+ }
31
+
32
+ /**
33
+ * Finds function's outer scope.
34
+ * @param {Scope} scope Function's own scope.
35
+ * @returns {Scope} Function's outer scope.
36
+ */
37
+ function getOuterScope(scope) {
38
+ const upper = scope.upper;
39
+
40
+ if (upper.type === "function-expression-name") {
41
+ return upper.upper;
42
+ }
43
+ return upper;
44
+ }
45
+
46
+ /**
47
+ * Determines whether the given function node is used as a Promise executor.
48
+ * @param {ASTNode} node The node to check.
49
+ * @param {Scope} scope Function's own scope.
50
+ * @returns {boolean} `true` if the node is a Promise executor.
51
+ */
52
+ function isPromiseExecutor(node, scope) {
53
+ const parent = node.parent;
54
+
55
+ return parent.type === "NewExpression" &&
56
+ parent.arguments[0] === node &&
57
+ parent.callee.type === "Identifier" &&
58
+ parent.callee.name === "Promise" &&
59
+ isGlobalReference(parent.callee, getOuterScope(scope));
60
+ }
61
+
62
+ //------------------------------------------------------------------------------
63
+ // Rule Definition
64
+ //------------------------------------------------------------------------------
65
+
66
+ module.exports = {
67
+ meta: {
68
+ type: "problem",
69
+
70
+ docs: {
71
+ description: "disallow returning values from Promise executor functions",
72
+ category: "Possible Errors",
73
+ recommended: false,
74
+ url: "https://eslint.org/docs/rules/no-promise-executor-return"
75
+ },
76
+
77
+ schema: [],
78
+
79
+ messages: {
80
+ returnsValue: "Return values from promise executor functions cannot be read."
81
+ }
82
+ },
83
+
84
+ create(context) {
85
+
86
+ let funcInfo = null;
87
+
88
+ /**
89
+ * Reports the given node.
90
+ * @param {ASTNode} node Node to report.
91
+ * @returns {void}
92
+ */
93
+ function report(node) {
94
+ context.report({ node, messageId: "returnsValue" });
95
+ }
96
+
97
+ return {
98
+
99
+ onCodePathStart(_, node) {
100
+ funcInfo = {
101
+ upper: funcInfo,
102
+ shouldCheck: functionTypesToCheck.has(node.type) && isPromiseExecutor(node, context.getScope())
103
+ };
104
+
105
+ if (funcInfo.shouldCheck && node.type === "ArrowFunctionExpression" && node.expression) {
106
+ report(node.body);
107
+ }
108
+ },
109
+
110
+ onCodePathEnd() {
111
+ funcInfo = funcInfo.upper;
112
+ },
113
+
114
+ ReturnStatement(node) {
115
+ if (funcInfo.shouldCheck && node.argument) {
116
+ report(node);
117
+ }
118
+ }
119
+ };
120
+ }
121
+ };
@@ -76,7 +76,7 @@ module.exports = {
76
76
 
77
77
  try {
78
78
  regExpAST = regExpParser.parsePattern(pattern, 0, pattern.length, flags.includes("u"));
79
- } catch (e) {
79
+ } catch {
80
80
 
81
81
  // Ignore regular expressions with syntax errors
82
82
  return;
@@ -61,6 +61,12 @@ module.exports = {
61
61
  }
62
62
 
63
63
  return {
64
+ ExportAllDeclaration(node) {
65
+ if (node.exported) {
66
+ checkExportedName(node.exported);
67
+ }
68
+ },
69
+
64
70
  ExportNamedDeclaration(node) {
65
71
  const declaration = node.declaration;
66
72
 
@@ -42,7 +42,7 @@ module.exports = {
42
42
  meta: {
43
43
  deprecated: true,
44
44
 
45
- replacedBy: ["node/no-restricted-require"],
45
+ replacedBy: [],
46
46
 
47
47
  type: "suggestion",
48
48
 
@@ -15,7 +15,7 @@ module.exports = {
15
15
  meta: {
16
16
  deprecated: true,
17
17
 
18
- replacedBy: ["node/no-sync"],
18
+ replacedBy: [],
19
19
 
20
20
  type: "suggestion",
21
21