eslint 7.0.0-alpha.1 → 7.0.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 (84) hide show
  1. package/CHANGELOG.md +329 -0
  2. package/README.md +7 -7
  3. package/bin/eslint.js +115 -77
  4. package/conf/category-list.json +2 -3
  5. package/conf/environments.js +2 -1
  6. package/conf/eslint-recommended.js +3 -0
  7. package/lib/api.js +2 -0
  8. package/lib/cli-engine/cascading-config-array-factory.js +16 -2
  9. package/lib/cli-engine/cli-engine.js +53 -47
  10. package/lib/cli-engine/config-array/config-array.js +30 -1
  11. package/lib/cli-engine/config-array/ignore-pattern.js +7 -1
  12. package/lib/cli-engine/config-array-factory.js +244 -235
  13. package/lib/cli.js +181 -95
  14. package/lib/eslint/eslint.js +656 -0
  15. package/lib/eslint/index.js +7 -0
  16. package/lib/init/autoconfig.js +4 -4
  17. package/lib/init/config-file.js +2 -2
  18. package/lib/init/config-initializer.js +2 -4
  19. package/lib/init/source-code-utils.js +2 -2
  20. package/lib/linter/node-event-generator.js +2 -2
  21. package/lib/options.js +0 -1
  22. package/lib/rule-tester/rule-tester.js +178 -23
  23. package/lib/rules/accessor-pairs.js +2 -2
  24. package/lib/rules/array-callback-return.js +3 -18
  25. package/lib/rules/arrow-body-style.js +26 -15
  26. package/lib/rules/callback-return.js +4 -0
  27. package/lib/rules/camelcase.js +38 -1
  28. package/lib/rules/comma-style.js +3 -8
  29. package/lib/rules/computed-property-spacing.js +2 -2
  30. package/lib/rules/curly.js +124 -40
  31. package/lib/rules/func-call-spacing.js +4 -3
  32. package/lib/rules/func-names.js +31 -24
  33. package/lib/rules/getter-return.js +2 -12
  34. package/lib/rules/global-require.js +4 -0
  35. package/lib/rules/handle-callback-err.js +4 -0
  36. package/lib/rules/id-blacklist.js +140 -64
  37. package/lib/rules/id-length.js +14 -4
  38. package/lib/rules/indent-legacy.js +0 -16
  39. package/lib/rules/key-spacing.js +1 -1
  40. package/lib/rules/new-cap.js +1 -1
  41. package/lib/rules/newline-per-chained-call.js +6 -3
  42. package/lib/rules/no-alert.js +5 -3
  43. package/lib/rules/no-buffer-constructor.js +4 -0
  44. package/lib/rules/no-dupe-else-if.js +1 -1
  45. package/lib/rules/no-empty-function.js +4 -2
  46. package/lib/rules/no-eval.js +3 -2
  47. package/lib/rules/no-extra-bind.js +1 -1
  48. package/lib/rules/no-extra-boolean-cast.js +168 -38
  49. package/lib/rules/no-extra-parens.js +9 -5
  50. package/lib/rules/no-implied-eval.js +83 -101
  51. package/lib/rules/no-import-assign.js +1 -1
  52. package/lib/rules/no-inner-declarations.js +31 -39
  53. package/lib/rules/no-lone-blocks.js +1 -1
  54. package/lib/rules/no-magic-numbers.js +72 -37
  55. package/lib/rules/no-mixed-requires.js +4 -0
  56. package/lib/rules/no-new-object.js +15 -3
  57. package/lib/rules/no-new-require.js +4 -0
  58. package/lib/rules/no-new-wrappers.js +1 -1
  59. package/lib/rules/no-obj-calls.js +24 -5
  60. package/lib/rules/no-path-concat.js +4 -0
  61. package/lib/rules/no-plusplus.js +39 -3
  62. package/lib/rules/no-process-env.js +4 -0
  63. package/lib/rules/no-process-exit.js +4 -0
  64. package/lib/rules/no-prototype-builtins.js +1 -1
  65. package/lib/rules/no-restricted-modules.js +52 -18
  66. package/lib/rules/no-setter-return.js +1 -1
  67. package/lib/rules/no-sync.js +4 -0
  68. package/lib/rules/no-underscore-dangle.js +1 -1
  69. package/lib/rules/no-unexpected-multiline.js +22 -12
  70. package/lib/rules/no-useless-concat.js +1 -1
  71. package/lib/rules/operator-assignment.js +3 -3
  72. package/lib/rules/operator-linebreak.js +4 -16
  73. package/lib/rules/prefer-numeric-literals.js +3 -3
  74. package/lib/rules/prefer-object-spread.js +2 -2
  75. package/lib/rules/require-await.js +1 -1
  76. package/lib/rules/space-before-function-paren.js +5 -2
  77. package/lib/rules/template-curly-spacing.js +59 -42
  78. package/lib/rules/utils/ast-utils.js +65 -4
  79. package/lib/rules/wrap-iife.js +54 -17
  80. package/lib/rules/yoda.js +101 -51
  81. package/lib/shared/relative-module-resolver.js +1 -0
  82. package/lib/shared/types.js +9 -2
  83. package/messages/plugin-conflict.txt +7 -0
  84. package/package.json +27 -26
@@ -5,6 +5,13 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("./utils/ast-utils");
13
+ const { getStaticValue } = require("eslint-utils");
14
+
8
15
  //------------------------------------------------------------------------------
9
16
  // Rule Definition
10
17
  //------------------------------------------------------------------------------
@@ -28,94 +35,97 @@ module.exports = {
28
35
  },
29
36
 
30
37
  create(context) {
31
- const CALLEE_RE = /^(setTimeout|setInterval|execScript)$/u;
32
-
33
- /*
34
- * Figures out if we should inspect a given binary expression. Is a stack
35
- * of stacks, where the first element in each substack is a CallExpression.
36
- */
37
- const impliedEvalAncestorsStack = [];
38
-
39
- //--------------------------------------------------------------------------
40
- // Helpers
41
- //--------------------------------------------------------------------------
38
+ const EVAL_LIKE_FUNCS = Object.freeze(["setTimeout", "execScript", "setInterval"]);
39
+ const GLOBAL_CANDIDATES = Object.freeze(["global", "window", "globalThis"]);
42
40
 
43
41
  /**
44
- * Get the last element of an array, without modifying arr, like pop(), but non-destructive.
45
- * @param {Array} arr What to inspect
46
- * @returns {*} The last element of arr
47
- * @private
42
+ * Checks whether a node is evaluated as a string or not.
43
+ * @param {ASTNode} node A node to check.
44
+ * @returns {boolean} True if the node is evaluated as a string.
48
45
  */
49
- function last(arr) {
50
- return arr ? arr[arr.length - 1] : null;
46
+ function isEvaluatedString(node) {
47
+ if (
48
+ (node.type === "Literal" && typeof node.value === "string") ||
49
+ node.type === "TemplateLiteral"
50
+ ) {
51
+ return true;
52
+ }
53
+ if (node.type === "BinaryExpression" && node.operator === "+") {
54
+ return isEvaluatedString(node.left) || isEvaluatedString(node.right);
55
+ }
56
+ return false;
51
57
  }
52
58
 
53
59
  /**
54
- * Checks if the given MemberExpression node is a potentially implied eval identifier on window.
55
- * @param {ASTNode} node The MemberExpression node to check.
56
- * @returns {boolean} Whether or not the given node is potentially an implied eval.
57
- * @private
60
+ * Checks whether a node is an Identifier node named one of the specified names.
61
+ * @param {ASTNode} node A node to check.
62
+ * @param {string[]} specifiers Array of specified name.
63
+ * @returns {boolean} True if the node is a Identifier node which has specified name.
58
64
  */
59
- function isImpliedEvalMemberExpression(node) {
60
- const object = node.object,
61
- property = node.property,
62
- hasImpliedEvalName = CALLEE_RE.test(property.name) || CALLEE_RE.test(property.value);
63
-
64
- return object.name === "window" && hasImpliedEvalName;
65
+ function isSpecifiedIdentifier(node, specifiers) {
66
+ return node.type === "Identifier" && specifiers.includes(node.name);
65
67
  }
66
68
 
67
69
  /**
68
- * Determines if a node represents a call to a potentially implied eval.
69
- *
70
- * This checks the callee name and that there's an argument, but not the type of the argument.
71
- * @param {ASTNode} node The CallExpression to check.
72
- * @returns {boolean} True if the node matches, false if not.
73
- * @private
70
+ * Checks a given node is a MemberExpression node which has the specified name's
71
+ * property.
72
+ * @param {ASTNode} node A node to check.
73
+ * @param {string[]} specifiers Array of specified name.
74
+ * @returns {boolean} `true` if the node is a MemberExpression node which has
75
+ * the specified name's property
74
76
  */
75
- function isImpliedEvalCallExpression(node) {
76
- const isMemberExpression = (node.callee.type === "MemberExpression"),
77
- isIdentifier = (node.callee.type === "Identifier"),
78
- isImpliedEvalCallee =
79
- (isIdentifier && CALLEE_RE.test(node.callee.name)) ||
80
- (isMemberExpression && isImpliedEvalMemberExpression(node.callee));
81
-
82
- return isImpliedEvalCallee && node.arguments.length;
77
+ function isSpecifiedMember(node, specifiers) {
78
+ return node.type === "MemberExpression" && specifiers.includes(astUtils.getStaticPropertyName(node));
83
79
  }
84
80
 
85
81
  /**
86
- * Checks that the parent is a direct descendent of an potential implied eval CallExpression, and if the parent is a CallExpression, that we're the first argument.
87
- * @param {ASTNode} node The node to inspect the parent of.
88
- * @returns {boolean} Was the parent a direct descendent, and is the child therefore potentially part of a dangerous argument?
89
- * @private
82
+ * Reports if the `CallExpression` node has evaluated argument.
83
+ * @param {ASTNode} node A CallExpression to check.
84
+ * @returns {void}
90
85
  */
91
- function hasImpliedEvalParent(node) {
86
+ function reportImpliedEvalCallExpression(node) {
87
+ const [firstArgument] = node.arguments;
92
88
 
93
- // make sure our parent is marked
94
- return node.parent === last(last(impliedEvalAncestorsStack)) &&
89
+ if (firstArgument) {
90
+
91
+ const staticValue = getStaticValue(firstArgument, context.getScope());
92
+ const isStaticString = staticValue && typeof staticValue.value === "string";
93
+ const isString = isStaticString || isEvaluatedString(firstArgument);
94
+
95
+ if (isString) {
96
+ context.report({
97
+ node,
98
+ messageId: "impliedEval"
99
+ });
100
+ }
101
+ }
95
102
 
96
- // if our parent is a CallExpression, make sure we're the first argument
97
- (node.parent.type !== "CallExpression" || node === node.parent.arguments[0]);
98
103
  }
99
104
 
100
105
  /**
101
- * Checks if our parent is marked as part of an implied eval argument. If
102
- * so, collapses the top of impliedEvalAncestorsStack and reports on the
103
- * original CallExpression.
104
- * @param {ASTNode} node The CallExpression to check.
105
- * @returns {boolean} True if the node matches, false if not.
106
- * @private
106
+ * Reports calls of `implied eval` via the global references.
107
+ * @param {Variable} globalVar A global variable to check.
108
+ * @returns {void}
107
109
  */
108
- function checkString(node) {
109
- if (hasImpliedEvalParent(node)) {
110
+ function reportImpliedEvalViaGlobal(globalVar) {
111
+ const { references, name } = globalVar;
110
112
 
111
- // remove the entire substack, to avoid duplicate reports
112
- const substack = impliedEvalAncestorsStack.pop();
113
+ references.forEach(ref => {
114
+ const identifier = ref.identifier;
115
+ let node = identifier.parent;
113
116
 
114
- context.report({
115
- node: substack[0],
116
- messageId: "impliedEval"
117
- });
118
- }
117
+ while (isSpecifiedMember(node, [name])) {
118
+ node = node.parent;
119
+ }
120
+
121
+ if (isSpecifiedMember(node, EVAL_LIKE_FUNCS)) {
122
+ const parent = node.parent;
123
+
124
+ if (parent.type === "CallExpression" && parent.callee === node) {
125
+ reportImpliedEvalCallExpression(parent);
126
+ }
127
+ }
128
+ });
119
129
  }
120
130
 
121
131
  //--------------------------------------------------------------------------
@@ -124,45 +134,17 @@ module.exports = {
124
134
 
125
135
  return {
126
136
  CallExpression(node) {
127
- if (isImpliedEvalCallExpression(node)) {
128
-
129
- // call expressions create a new substack
130
- impliedEvalAncestorsStack.push([node]);
131
- }
132
- },
133
-
134
- "CallExpression:exit"(node) {
135
- if (node === last(last(impliedEvalAncestorsStack))) {
136
-
137
- /*
138
- * Destroys the entire sub-stack, rather than just using
139
- * last(impliedEvalAncestorsStack).pop(), as a CallExpression is
140
- * always the bottom of a impliedEvalAncestorsStack substack.
141
- */
142
- impliedEvalAncestorsStack.pop();
143
- }
144
- },
145
-
146
- BinaryExpression(node) {
147
- if (node.operator === "+" && hasImpliedEvalParent(node)) {
148
- last(impliedEvalAncestorsStack).push(node);
149
- }
150
- },
151
-
152
- "BinaryExpression:exit"(node) {
153
- if (node === last(last(impliedEvalAncestorsStack))) {
154
- last(impliedEvalAncestorsStack).pop();
155
- }
156
- },
157
-
158
- Literal(node) {
159
- if (typeof node.value === "string") {
160
- checkString(node);
137
+ if (isSpecifiedIdentifier(node.callee, EVAL_LIKE_FUNCS)) {
138
+ reportImpliedEvalCallExpression(node);
161
139
  }
162
140
  },
141
+ "Program:exit"() {
142
+ const globalScope = context.getScope();
163
143
 
164
- TemplateLiteral(node) {
165
- checkString(node);
144
+ GLOBAL_CANDIDATES
145
+ .map(candidate => astUtils.getVariableByName(globalScope, candidate))
146
+ .filter(globalVar => !!globalVar && globalVar.defs.length === 0)
147
+ .forEach(reportImpliedEvalViaGlobal);
166
148
  }
167
149
  };
168
150
 
@@ -180,7 +180,7 @@ module.exports = {
180
180
  docs: {
181
181
  description: "disallow assigning to imported bindings",
182
182
  category: "Possible Errors",
183
- recommended: false,
183
+ recommended: true,
184
184
  url: "https://eslint.org/docs/rules/no-import-assign"
185
185
  },
186
186
 
@@ -5,10 +5,19 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("./utils/ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
11
17
 
18
+ const validParent = new Set(["Program", "ExportNamedDeclaration", "ExportDefaultDeclaration"]);
19
+ const validBlockStatementParent = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
20
+
12
21
  module.exports = {
13
22
  meta: {
14
23
  type: "problem",
@@ -33,54 +42,37 @@ module.exports = {
33
42
 
34
43
  create(context) {
35
44
 
36
- /**
37
- * Find the nearest Program or Function ancestor node.
38
- * @returns {Object} Ancestor's type and distance from node.
39
- */
40
- function nearestBody() {
41
- const ancestors = context.getAncestors();
42
- let ancestor = ancestors.pop(),
43
- generation = 1;
44
-
45
- while (ancestor && ["Program", "FunctionDeclaration",
46
- "FunctionExpression", "ArrowFunctionExpression"
47
- ].indexOf(ancestor.type) < 0) {
48
- generation += 1;
49
- ancestor = ancestors.pop();
50
- }
51
-
52
- return {
53
-
54
- // Type of containing ancestor
55
- type: ancestor.type,
56
-
57
- // Separation between ancestor and node
58
- distance: generation
59
- };
60
- }
61
-
62
45
  /**
63
46
  * Ensure that a given node is at a program or function body's root.
64
47
  * @param {ASTNode} node Declaration node to check.
65
48
  * @returns {void}
66
49
  */
67
50
  function check(node) {
68
- const body = nearestBody(),
69
- valid = ((body.type === "Program" && body.distance === 1) ||
70
- body.distance === 2);
71
-
72
- if (!valid) {
73
- context.report({
74
- node,
75
- messageId: "moveDeclToRoot",
76
- data: {
77
- type: (node.type === "FunctionDeclaration" ? "function" : "variable"),
78
- body: (body.type === "Program" ? "program" : "function body")
79
- }
80
- });
51
+ const parent = node.parent;
52
+
53
+ if (
54
+ parent.type === "BlockStatement" && validBlockStatementParent.has(parent.parent.type)
55
+ ) {
56
+ return;
57
+ }
58
+
59
+ if (validParent.has(parent.type)) {
60
+ return;
81
61
  }
62
+
63
+ const upperFunction = astUtils.getUpperFunction(parent);
64
+
65
+ context.report({
66
+ node,
67
+ messageId: "moveDeclToRoot",
68
+ data: {
69
+ type: (node.type === "FunctionDeclaration" ? "function" : "variable"),
70
+ body: (upperFunction === null ? "program" : "function body")
71
+ }
72
+ });
82
73
  }
83
74
 
75
+
84
76
  return {
85
77
 
86
78
  FunctionDeclaration: check,
@@ -49,7 +49,7 @@ module.exports = {
49
49
  }
50
50
 
51
51
  /**
52
- * Checks for any ocurrence of a BlockStatement in a place where lists of statements can appear
52
+ * Checks for any occurrence of a BlockStatement in a place where lists of statements can appear
53
53
  * @param {ASTNode} node The node to check
54
54
  * @returns {boolean} True if the node is a lone block.
55
55
  */
@@ -7,6 +7,9 @@
7
7
 
8
8
  const { isNumericLiteral } = require("./utils/ast-utils");
9
9
 
10
+ // Maximum array length by the ECMAScript Specification.
11
+ const MAX_ARRAY_LENGTH = 2 ** 32 - 1;
12
+
10
13
  //------------------------------------------------------------------------------
11
14
  // Rule Definition
12
15
  //------------------------------------------------------------------------------
@@ -76,83 +79,115 @@ module.exports = {
76
79
  ignore = (config.ignore || []).map(normalizeIgnoreValue),
77
80
  ignoreArrayIndexes = !!config.ignoreArrayIndexes;
78
81
 
82
+ const okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"];
83
+
79
84
  /**
80
- * Returns whether the number should be ignored
81
- * @param {number} num the number
82
- * @returns {boolean} true if the number should be ignored
85
+ * Returns whether the rule is configured to ignore the given value
86
+ * @param {bigint|number} value The value to check
87
+ * @returns {boolean} true if the value is ignored
83
88
  */
84
- function shouldIgnoreNumber(num) {
85
- return ignore.indexOf(num) !== -1;
89
+ function isIgnoredValue(value) {
90
+ return ignore.indexOf(value) !== -1;
86
91
  }
87
92
 
88
93
  /**
89
- * Returns whether the number should be ignored when used as a radix within parseInt() or Number.parseInt()
90
- * @param {ASTNode} parent the non-"UnaryExpression" parent
91
- * @param {ASTNode} node the node literal being evaluated
92
- * @returns {boolean} true if the number should be ignored
94
+ * Returns whether the given node is used as a radix within parseInt() or Number.parseInt()
95
+ * @param {ASTNode} fullNumberNode `Literal` or `UnaryExpression` full number node
96
+ * @returns {boolean} true if the node is radix
93
97
  */
94
- function shouldIgnoreParseInt(parent, node) {
95
- return parent.type === "CallExpression" && node === parent.arguments[1] &&
96
- (parent.callee.name === "parseInt" ||
97
- parent.callee.type === "MemberExpression" &&
98
- parent.callee.object.name === "Number" &&
99
- parent.callee.property.name === "parseInt");
98
+ function isParseIntRadix(fullNumberNode) {
99
+ const parent = fullNumberNode.parent;
100
+
101
+ return parent.type === "CallExpression" && fullNumberNode === parent.arguments[1] &&
102
+ (
103
+ parent.callee.name === "parseInt" ||
104
+ (
105
+ parent.callee.type === "MemberExpression" &&
106
+ parent.callee.object.name === "Number" &&
107
+ parent.callee.property.name === "parseInt"
108
+ )
109
+ );
100
110
  }
101
111
 
102
112
  /**
103
- * Returns whether the number should be ignored when used to define a JSX prop
104
- * @param {ASTNode} parent the non-"UnaryExpression" parent
105
- * @returns {boolean} true if the number should be ignored
113
+ * Returns whether the given node is a direct child of a JSX node.
114
+ * In particular, it aims to detect numbers used as prop values in JSX tags.
115
+ * Example: <input maxLength={10} />
116
+ * @param {ASTNode} fullNumberNode `Literal` or `UnaryExpression` full number node
117
+ * @returns {boolean} true if the node is a JSX number
106
118
  */
107
- function shouldIgnoreJSXNumbers(parent) {
108
- return parent.type.indexOf("JSX") === 0;
119
+ function isJSXNumber(fullNumberNode) {
120
+ return fullNumberNode.parent.type.indexOf("JSX") === 0;
109
121
  }
110
122
 
111
123
  /**
112
- * Returns whether the number should be ignored when used as an array index with enabled 'ignoreArrayIndexes' option.
113
- * @param {ASTNode} node Node to check
114
- * @returns {boolean} true if the number should be ignored
124
+ * Returns whether the given node is used as an array index.
125
+ * Value must coerce to a valid array index name: "0", "1", "2" ... "4294967294".
126
+ *
127
+ * All other values, like "-1", "2.5", or "4294967295", are just "normal" object properties,
128
+ * which can be created and accessed on an array in addition to the array index properties,
129
+ * but they don't affect array's length and are not considered by methods such as .map(), .forEach() etc.
130
+ *
131
+ * The maximum array length by the specification is 2 ** 32 - 1 = 4294967295,
132
+ * thus the maximum valid index is 2 ** 32 - 2 = 4294967294.
133
+ *
134
+ * All notations are allowed, as long as the value coerces to one of "0", "1", "2" ... "4294967294".
135
+ *
136
+ * Valid examples:
137
+ * a[0], a[1], a[1.2e1], a[0xAB], a[0n], a[1n]
138
+ * a[-0] (same as a[0] because -0 coerces to "0")
139
+ * a[-0n] (-0n evaluates to 0n)
140
+ *
141
+ * Invalid examples:
142
+ * a[-1], a[-0xAB], a[-1n], a[2.5], a[1.23e1], a[12e-1]
143
+ * a[4294967295] (above the max index, it's an access to a regular property a["4294967295"])
144
+ * a[999999999999999999999] (even if it wasn't above the max index, it would be a["1e+21"])
145
+ * a[1e310] (same as a["Infinity"])
146
+ * @param {ASTNode} fullNumberNode `Literal` or `UnaryExpression` full number node
147
+ * @param {bigint|number} value Value expressed by the fullNumberNode
148
+ * @returns {boolean} true if the node is a valid array index
115
149
  */
116
- function shouldIgnoreArrayIndexes(node) {
117
- const parent = node.parent;
150
+ function isArrayIndex(fullNumberNode, value) {
151
+ const parent = fullNumberNode.parent;
118
152
 
119
- return ignoreArrayIndexes &&
120
- parent.type === "MemberExpression" && parent.property === node;
153
+ return parent.type === "MemberExpression" && parent.property === fullNumberNode &&
154
+ (Number.isInteger(value) || typeof value === "bigint") &&
155
+ value >= 0 && value < MAX_ARRAY_LENGTH;
121
156
  }
122
157
 
123
158
  return {
124
159
  Literal(node) {
125
- const okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"];
126
-
127
160
  if (!isNumericLiteral(node)) {
128
161
  return;
129
162
  }
130
163
 
131
164
  let fullNumberNode;
132
- let parent;
133
165
  let value;
134
166
  let raw;
135
167
 
136
- // For negative magic numbers: update the value and parent node
168
+ // Treat unary minus as a part of the number
137
169
  if (node.parent.type === "UnaryExpression" && node.parent.operator === "-") {
138
170
  fullNumberNode = node.parent;
139
- parent = fullNumberNode.parent;
140
171
  value = -node.value;
141
172
  raw = `-${node.raw}`;
142
173
  } else {
143
174
  fullNumberNode = node;
144
- parent = node.parent;
145
175
  value = node.value;
146
176
  raw = node.raw;
147
177
  }
148
178
 
149
- if (shouldIgnoreNumber(value) ||
150
- shouldIgnoreParseInt(parent, fullNumberNode) ||
151
- shouldIgnoreArrayIndexes(fullNumberNode) ||
152
- shouldIgnoreJSXNumbers(parent)) {
179
+ // Always allow radix arguments and JSX props
180
+ if (
181
+ isIgnoredValue(value) ||
182
+ isParseIntRadix(fullNumberNode) ||
183
+ isJSXNumber(fullNumberNode) ||
184
+ (ignoreArrayIndexes && isArrayIndex(fullNumberNode, value))
185
+ ) {
153
186
  return;
154
187
  }
155
188
 
189
+ const parent = fullNumberNode.parent;
190
+
156
191
  if (parent.type === "VariableDeclarator") {
157
192
  if (enforceConst && parent.parent.kind !== "const") {
158
193
  context.report({
@@ -11,6 +11,10 @@
11
11
 
12
12
  module.exports = {
13
13
  meta: {
14
+ deprecated: true,
15
+
16
+ replacedBy: ["node/no-mixed-requires"],
17
+
14
18
  type: "suggestion",
15
19
 
16
20
  docs: {
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("./utils/ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -28,10 +34,17 @@ module.exports = {
28
34
  },
29
35
 
30
36
  create(context) {
31
-
32
37
  return {
33
-
34
38
  NewExpression(node) {
39
+ const variable = astUtils.getVariableByName(
40
+ context.getScope(),
41
+ node.callee.name
42
+ );
43
+
44
+ if (variable && variable.identifiers.length > 0) {
45
+ return;
46
+ }
47
+
35
48
  if (node.callee.name === "Object") {
36
49
  context.report({
37
50
  node,
@@ -40,6 +53,5 @@ module.exports = {
40
53
  }
41
54
  }
42
55
  };
43
-
44
56
  }
45
57
  };
@@ -11,6 +11,10 @@
11
11
 
12
12
  module.exports = {
13
13
  meta: {
14
+ deprecated: true,
15
+
16
+ replacedBy: ["node/no-new-require"],
17
+
14
18
  type: "suggestion",
15
19
 
16
20
  docs: {
@@ -32,7 +32,7 @@ module.exports = {
32
32
  return {
33
33
 
34
34
  NewExpression(node) {
35
- const wrapperObjects = ["String", "Number", "Boolean", "Math", "JSON"];
35
+ const wrapperObjects = ["String", "Number", "Boolean"];
36
36
 
37
37
  if (wrapperObjects.indexOf(node.callee.name) > -1) {
38
38
  context.report({
@@ -9,7 +9,8 @@
9
9
  // Requirements
10
10
  //------------------------------------------------------------------------------
11
11
 
12
- const { CALL, ReferenceTracker } = require("eslint-utils");
12
+ const { CALL, CONSTRUCT, ReferenceTracker } = require("eslint-utils");
13
+ const getPropertyName = require("./utils/ast-utils").getStaticPropertyName;
13
14
 
14
15
  //------------------------------------------------------------------------------
15
16
  // Helpers
@@ -17,6 +18,18 @@ const { CALL, ReferenceTracker } = require("eslint-utils");
17
18
 
18
19
  const nonCallableGlobals = ["Atomics", "JSON", "Math", "Reflect"];
19
20
 
21
+ /**
22
+ * Returns the name of the node to report
23
+ * @param {ASTNode} node A node to report
24
+ * @returns {string} name to report
25
+ */
26
+ function getReportNodeName(node) {
27
+ if (node.callee.type === "MemberExpression") {
28
+ return getPropertyName(node.callee);
29
+ }
30
+ return node.callee.name;
31
+ }
32
+
20
33
  //------------------------------------------------------------------------------
21
34
  // Rule Definition
22
35
  //------------------------------------------------------------------------------
@@ -35,7 +48,8 @@ module.exports = {
35
48
  schema: [],
36
49
 
37
50
  messages: {
38
- unexpectedCall: "'{{name}}' is not a function."
51
+ unexpectedCall: "'{{name}}' is not a function.",
52
+ unexpectedRefCall: "'{{name}}' is reference to '{{ref}}', which is not a function."
39
53
  }
40
54
  },
41
55
 
@@ -49,12 +63,17 @@ module.exports = {
49
63
 
50
64
  for (const g of nonCallableGlobals) {
51
65
  traceMap[g] = {
52
- [CALL]: true
66
+ [CALL]: true,
67
+ [CONSTRUCT]: true
53
68
  };
54
69
  }
55
70
 
56
- for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
57
- context.report({ node, messageId: "unexpectedCall", data: { name: node.callee.name } });
71
+ for (const { node, path } of tracker.iterateGlobalReferences(traceMap)) {
72
+ const name = getReportNodeName(node);
73
+ const ref = path[0];
74
+ const messageId = name === ref ? "unexpectedCall" : "unexpectedRefCall";
75
+
76
+ context.report({ node, messageId, data: { name, ref } });
58
77
  }
59
78
  }
60
79
  };
@@ -10,6 +10,10 @@
10
10
 
11
11
  module.exports = {
12
12
  meta: {
13
+ deprecated: true,
14
+
15
+ replacedBy: ["node/no-path-concat"],
16
+
13
17
  type: "suggestion",
14
18
 
15
19
  docs: {