.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-implied-eval.js
1 /**
2  * @fileoverview Rule to flag use of implied eval via setTimeout and setInterval
3  * @author James Allardice
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const astUtils = require("./utils/ast-utils");
13 const { getStaticValue } = require("eslint-utils");
14
15 //------------------------------------------------------------------------------
16 // Rule Definition
17 //------------------------------------------------------------------------------
18
19 module.exports = {
20     meta: {
21         type: "suggestion",
22
23         docs: {
24             description: "disallow the use of `eval()`-like methods",
25             category: "Best Practices",
26             recommended: false,
27             url: "https://eslint.org/docs/rules/no-implied-eval"
28         },
29
30         schema: [],
31
32         messages: {
33             impliedEval: "Implied eval. Consider passing a function instead of a string."
34         }
35     },
36
37     create(context) {
38         const GLOBAL_CANDIDATES = Object.freeze(["global", "window", "globalThis"]);
39         const EVAL_LIKE_FUNC_PATTERN = /^(?:set(?:Interval|Timeout)|execScript)$/u;
40
41         /**
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.
45          */
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;
57         }
58
59         /**
60          * Reports if the `CallExpression` node has evaluated argument.
61          * @param {ASTNode} node A CallExpression to check.
62          * @returns {void}
63          */
64         function reportImpliedEvalCallExpression(node) {
65             const [firstArgument] = node.arguments;
66
67             if (firstArgument) {
68
69                 const staticValue = getStaticValue(firstArgument, context.getScope());
70                 const isStaticString = staticValue && typeof staticValue.value === "string";
71                 const isString = isStaticString || isEvaluatedString(firstArgument);
72
73                 if (isString) {
74                     context.report({
75                         node,
76                         messageId: "impliedEval"
77                     });
78                 }
79             }
80
81         }
82
83         /**
84          * Reports calls of `implied eval` via the global references.
85          * @param {Variable} globalVar A global variable to check.
86          * @returns {void}
87          */
88         function reportImpliedEvalViaGlobal(globalVar) {
89             const { references, name } = globalVar;
90
91             references.forEach(ref => {
92                 const identifier = ref.identifier;
93                 let node = identifier.parent;
94
95                 while (astUtils.isSpecificMemberAccess(node, null, name)) {
96                     node = node.parent;
97                 }
98
99                 if (astUtils.isSpecificMemberAccess(node, null, EVAL_LIKE_FUNC_PATTERN)) {
100                     const calleeNode = node.parent.type === "ChainExpression" ? node.parent : node;
101                     const parent = calleeNode.parent;
102
103                     if (parent.type === "CallExpression" && parent.callee === calleeNode) {
104                         reportImpliedEvalCallExpression(parent);
105                     }
106                 }
107             });
108         }
109
110         //--------------------------------------------------------------------------
111         // Public
112         //--------------------------------------------------------------------------
113
114         return {
115             CallExpression(node) {
116                 if (astUtils.isSpecificId(node.callee, EVAL_LIKE_FUNC_PATTERN)) {
117                     reportImpliedEvalCallExpression(node);
118                 }
119             },
120             "Program:exit"() {
121                 const globalScope = context.getScope();
122
123                 GLOBAL_CANDIDATES
124                     .map(candidate => astUtils.getVariableByName(globalScope, candidate))
125                     .filter(globalVar => !!globalVar && globalVar.defs.length === 0)
126                     .forEach(reportImpliedEvalViaGlobal);
127             }
128         };
129
130     }
131 };