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.
- package/CHANGELOG.md +329 -0
- package/README.md +7 -7
- package/bin/eslint.js +115 -77
- package/conf/category-list.json +2 -3
- package/conf/environments.js +2 -1
- package/conf/eslint-recommended.js +3 -0
- package/lib/api.js +2 -0
- package/lib/cli-engine/cascading-config-array-factory.js +16 -2
- package/lib/cli-engine/cli-engine.js +53 -47
- package/lib/cli-engine/config-array/config-array.js +30 -1
- package/lib/cli-engine/config-array/ignore-pattern.js +7 -1
- package/lib/cli-engine/config-array-factory.js +244 -235
- package/lib/cli.js +181 -95
- package/lib/eslint/eslint.js +656 -0
- package/lib/eslint/index.js +7 -0
- package/lib/init/autoconfig.js +4 -4
- package/lib/init/config-file.js +2 -2
- package/lib/init/config-initializer.js +2 -4
- package/lib/init/source-code-utils.js +2 -2
- package/lib/linter/node-event-generator.js +2 -2
- package/lib/options.js +0 -1
- package/lib/rule-tester/rule-tester.js +178 -23
- package/lib/rules/accessor-pairs.js +2 -2
- package/lib/rules/array-callback-return.js +3 -18
- package/lib/rules/arrow-body-style.js +26 -15
- package/lib/rules/callback-return.js +4 -0
- package/lib/rules/camelcase.js +38 -1
- package/lib/rules/comma-style.js +3 -8
- package/lib/rules/computed-property-spacing.js +2 -2
- package/lib/rules/curly.js +124 -40
- package/lib/rules/func-call-spacing.js +4 -3
- package/lib/rules/func-names.js +31 -24
- package/lib/rules/getter-return.js +2 -12
- package/lib/rules/global-require.js +4 -0
- package/lib/rules/handle-callback-err.js +4 -0
- package/lib/rules/id-blacklist.js +140 -64
- package/lib/rules/id-length.js +14 -4
- package/lib/rules/indent-legacy.js +0 -16
- package/lib/rules/key-spacing.js +1 -1
- package/lib/rules/new-cap.js +1 -1
- package/lib/rules/newline-per-chained-call.js +6 -3
- package/lib/rules/no-alert.js +5 -3
- package/lib/rules/no-buffer-constructor.js +4 -0
- package/lib/rules/no-dupe-else-if.js +1 -1
- package/lib/rules/no-empty-function.js +4 -2
- package/lib/rules/no-eval.js +3 -2
- package/lib/rules/no-extra-bind.js +1 -1
- package/lib/rules/no-extra-boolean-cast.js +168 -38
- package/lib/rules/no-extra-parens.js +9 -5
- package/lib/rules/no-implied-eval.js +83 -101
- package/lib/rules/no-import-assign.js +1 -1
- package/lib/rules/no-inner-declarations.js +31 -39
- package/lib/rules/no-lone-blocks.js +1 -1
- package/lib/rules/no-magic-numbers.js +72 -37
- package/lib/rules/no-mixed-requires.js +4 -0
- package/lib/rules/no-new-object.js +15 -3
- package/lib/rules/no-new-require.js +4 -0
- package/lib/rules/no-new-wrappers.js +1 -1
- package/lib/rules/no-obj-calls.js +24 -5
- package/lib/rules/no-path-concat.js +4 -0
- package/lib/rules/no-plusplus.js +39 -3
- package/lib/rules/no-process-env.js +4 -0
- package/lib/rules/no-process-exit.js +4 -0
- package/lib/rules/no-prototype-builtins.js +1 -1
- package/lib/rules/no-restricted-modules.js +52 -18
- package/lib/rules/no-setter-return.js +1 -1
- package/lib/rules/no-sync.js +4 -0
- package/lib/rules/no-underscore-dangle.js +1 -1
- package/lib/rules/no-unexpected-multiline.js +22 -12
- package/lib/rules/no-useless-concat.js +1 -1
- package/lib/rules/operator-assignment.js +3 -3
- package/lib/rules/operator-linebreak.js +4 -16
- package/lib/rules/prefer-numeric-literals.js +3 -3
- package/lib/rules/prefer-object-spread.js +2 -2
- package/lib/rules/require-await.js +1 -1
- package/lib/rules/space-before-function-paren.js +5 -2
- package/lib/rules/template-curly-spacing.js +59 -42
- package/lib/rules/utils/ast-utils.js +65 -4
- package/lib/rules/wrap-iife.js +54 -17
- package/lib/rules/yoda.js +101 -51
- package/lib/shared/relative-module-resolver.js +1 -0
- package/lib/shared/types.js +9 -2
- package/messages/plugin-conflict.txt +7 -0
- 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
|
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
|
-
*
|
45
|
-
* @param {
|
46
|
-
* @returns {
|
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
|
50
|
-
|
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
|
55
|
-
* @param {ASTNode} node
|
56
|
-
* @
|
57
|
-
* @
|
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
|
60
|
-
|
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
|
-
*
|
69
|
-
*
|
70
|
-
*
|
71
|
-
* @param {
|
72
|
-
* @returns {boolean}
|
73
|
-
*
|
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
|
76
|
-
|
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
|
-
*
|
87
|
-
* @param {ASTNode} node
|
88
|
-
* @returns {
|
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
|
86
|
+
function reportImpliedEvalCallExpression(node) {
|
87
|
+
const [firstArgument] = node.arguments;
|
92
88
|
|
93
|
-
|
94
|
-
|
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
|
-
*
|
102
|
-
*
|
103
|
-
*
|
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
|
109
|
-
|
110
|
+
function reportImpliedEvalViaGlobal(globalVar) {
|
111
|
+
const { references, name } = globalVar;
|
110
112
|
|
111
|
-
|
112
|
-
const
|
113
|
+
references.forEach(ref => {
|
114
|
+
const identifier = ref.identifier;
|
115
|
+
let node = identifier.parent;
|
113
116
|
|
114
|
-
|
115
|
-
node
|
116
|
-
|
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 (
|
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
|
-
|
165
|
-
|
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
|
|
@@ -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
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
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
|
81
|
-
* @param {number}
|
82
|
-
* @returns {boolean} true if the
|
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
|
85
|
-
return ignore.indexOf(
|
89
|
+
function isIgnoredValue(value) {
|
90
|
+
return ignore.indexOf(value) !== -1;
|
86
91
|
}
|
87
92
|
|
88
93
|
/**
|
89
|
-
* Returns whether the
|
90
|
-
* @param {ASTNode}
|
91
|
-
* @
|
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
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
104
|
-
*
|
105
|
-
*
|
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
|
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
|
113
|
-
*
|
114
|
-
*
|
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
|
117
|
-
const parent =
|
150
|
+
function isArrayIndex(fullNumberNode, value) {
|
151
|
+
const parent = fullNumberNode.parent;
|
118
152
|
|
119
|
-
return
|
120
|
-
|
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
|
-
//
|
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
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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({
|
@@ -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
|
};
|
@@ -32,7 +32,7 @@ module.exports = {
|
|
32
32
|
return {
|
33
33
|
|
34
34
|
NewExpression(node) {
|
35
|
-
const wrapperObjects = ["String", "Number", "Boolean"
|
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
|
-
|
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
|
};
|