]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-eval.js
2 * @fileoverview Rule to flag use of eval() statement
3 * @author Nicholas C. Zakas
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const astUtils
= require("./utils/ast-utils");
14 //------------------------------------------------------------------------------
16 //------------------------------------------------------------------------------
18 const candidatesOfGlobalObject
= Object
.freeze([
25 * Checks a given node is a Identifier node of the specified name.
26 * @param {ASTNode} node A node to check.
27 * @param {string} name A name to check.
28 * @returns {boolean} `true` if the node is a Identifier node of the name.
30 function isIdentifier(node
, name
) {
31 return node
.type
=== "Identifier" && node
.name
=== name
;
35 * Checks a given node is a Literal node of the specified string value.
36 * @param {ASTNode} node A node to check.
37 * @param {string} name A name to check.
38 * @returns {boolean} `true` if the node is a Literal node of the name.
40 function isConstant(node
, name
) {
43 return node
.value
=== name
;
45 case "TemplateLiteral":
47 node
.expressions
.length
=== 0 &&
48 node
.quasis
[0].value
.cooked
=== name
57 * Checks a given node is a MemberExpression node which has the specified name's
59 * @param {ASTNode} node A node to check.
60 * @param {string} name A name to check.
61 * @returns {boolean} `true` if the node is a MemberExpression node which has
62 * the specified name's property
64 function isMember(node
, name
) {
66 node
.type
=== "MemberExpression" &&
67 (node
.computed
? isConstant
: isIdentifier
)(node
.property
, name
)
71 //------------------------------------------------------------------------------
73 //------------------------------------------------------------------------------
80 description
: "disallow the use of `eval()`",
81 category
: "Best Practices",
83 url
: "https://eslint.org/docs/rules/no-eval"
90 allowIndirect
: { type
: "boolean", default: false }
92 additionalProperties
: false
97 unexpected
: "eval can be harmful."
102 const allowIndirect
= Boolean(
103 context
.options
[0] &&
104 context
.options
[0].allowIndirect
106 const sourceCode
= context
.getSourceCode();
110 * Pushs a variable scope (Program or Function) information to the stack.
112 * This is used in order to check whether or not `this` binding is a
113 * reference to the global object.
114 * @param {ASTNode} node A node of the scope. This is one of Program,
115 * FunctionDeclaration, FunctionExpression, and ArrowFunctionExpression.
118 function enterVarScope(node
) {
119 const strict
= context
.getScope().isStrict
;
131 * Pops a variable scope from the stack.
134 function exitVarScope() {
135 funcInfo
= funcInfo
.upper
;
139 * Reports a given node.
141 * `node` is `Identifier` or `MemberExpression`.
142 * The parent of `node` might be `CallExpression`.
144 * The location of the report is always `eval` `Identifier` (or possibly
145 * `Literal`). The type of the report is `CallExpression` if the parent is
146 * `CallExpression`. Otherwise, it's the given node type.
147 * @param {ASTNode} node A node to report.
150 function report(node
) {
151 const parent
= node
.parent
;
152 const locationNode
= node
.type
=== "MemberExpression"
156 const reportNode
= parent
.type
=== "CallExpression" && parent
.callee
=== node
162 loc
: locationNode
.loc
,
163 messageId
: "unexpected"
168 * Reports accesses of `eval` via the global object.
169 * @param {eslint-scope.Scope} globalScope The global scope.
172 function reportAccessingEvalViaGlobalObject(globalScope
) {
173 for (let i
= 0; i
< candidatesOfGlobalObject
.length
; ++i
) {
174 const name
= candidatesOfGlobalObject
[i
];
175 const variable
= astUtils
.getVariableByName(globalScope
, name
);
181 const references
= variable
.references
;
183 for (let j
= 0; j
< references
.length
; ++j
) {
184 const identifier
= references
[j
].identifier
;
185 let node
= identifier
.parent
;
187 // To detect code like `window.window.eval`.
188 while (isMember(node
, name
)) {
193 if (isMember(node
, "eval")) {
201 * Reports all accesses of `eval` (excludes direct calls to eval).
202 * @param {eslint-scope.Scope} globalScope The global scope.
205 function reportAccessingEval(globalScope
) {
206 const variable
= astUtils
.getVariableByName(globalScope
, "eval");
212 const references
= variable
.references
;
214 for (let i
= 0; i
< references
.length
; ++i
) {
215 const reference
= references
[i
];
216 const id
= reference
.identifier
;
218 if (id
.name
=== "eval" && !astUtils
.isCallee(id
)) {
220 // Is accessing to eval (excludes direct calls to eval)
228 // Checks only direct calls to eval. It's simple!
230 "CallExpression:exit"(node
) {
231 const callee
= node
.callee
;
233 if (isIdentifier(callee
, "eval")) {
241 "CallExpression:exit"(node
) {
242 const callee
= node
.callee
;
244 if (isIdentifier(callee
, "eval")) {
250 const scope
= context
.getScope(),
251 features
= context
.parserOptions
.ecmaFeatures
|| {},
254 node
.sourceType
=== "module" ||
255 (features
.globalReturn
&& scope
.childScopes
[0].isStrict
);
267 const globalScope
= context
.getScope();
270 reportAccessingEval(globalScope
);
271 reportAccessingEvalViaGlobalObject(globalScope
);
274 FunctionDeclaration
: enterVarScope
,
275 "FunctionDeclaration:exit": exitVarScope
,
276 FunctionExpression
: enterVarScope
,
277 "FunctionExpression:exit": exitVarScope
,
278 ArrowFunctionExpression
: enterVarScope
,
279 "ArrowFunctionExpression:exit": exitVarScope
,
281 ThisExpression(node
) {
282 if (!isMember(node
.parent
, "eval")) {
287 * `this.eval` is found.
288 * Checks whether or not the value of `this` is the global object.
290 if (!funcInfo
.initialized
) {
291 funcInfo
.initialized
= true;
292 funcInfo
.defaultThis
= astUtils
.isDefaultThisBinding(
298 if (!funcInfo
.strict
&& funcInfo
.defaultThis
) {
300 // `this.eval` is possible built-in `eval`.