source: frontend/node_modules/@babel/traverse/lib/path/evaluation.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 10.8 KB
Line 
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.evaluate = evaluate;
7exports.evaluateTruthy = evaluateTruthy;
8const VALID_OBJECT_CALLEES = ["Number", "String", "Math"];
9const VALID_IDENTIFIER_CALLEES = ["isFinite", "isNaN", "parseFloat", "parseInt", "decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", null, null];
10const INVALID_METHODS = ["random"];
11function isValidObjectCallee(val) {
12 return VALID_OBJECT_CALLEES.includes(val);
13}
14function isValidIdentifierCallee(val) {
15 return VALID_IDENTIFIER_CALLEES.includes(val);
16}
17function isInvalidMethod(val) {
18 return INVALID_METHODS.includes(val);
19}
20function evaluateTruthy() {
21 const res = this.evaluate();
22 if (res.confident) return !!res.value;
23}
24function deopt(path, state) {
25 if (!state.confident) return;
26 state.deoptPath = path;
27 state.confident = false;
28}
29const Globals = new Map([["undefined", undefined], ["Infinity", Infinity], ["NaN", NaN]]);
30function evaluateCached(path, state) {
31 const {
32 node
33 } = path;
34 const {
35 seen
36 } = state;
37 if (seen.has(node)) {
38 const existing = seen.get(node);
39 if (existing.resolved) {
40 return existing.value;
41 } else {
42 deopt(path, state);
43 return;
44 }
45 } else {
46 const item = {
47 resolved: false
48 };
49 seen.set(node, item);
50 const val = _evaluate(path, state);
51 if (state.confident) {
52 item.resolved = true;
53 item.value = val;
54 }
55 return val;
56 }
57}
58function _evaluate(path, state) {
59 if (!state.confident) return;
60 if (path.isSequenceExpression()) {
61 const exprs = path.get("expressions");
62 return evaluateCached(exprs[exprs.length - 1], state);
63 }
64 if (path.isStringLiteral() || path.isNumericLiteral() || path.isBooleanLiteral()) {
65 return path.node.value;
66 }
67 if (path.isNullLiteral()) {
68 return null;
69 }
70 if (path.isTemplateLiteral()) {
71 return evaluateQuasis(path, path.node.quasis, state);
72 }
73 if (path.isTaggedTemplateExpression() && path.get("tag").isMemberExpression()) {
74 const object = path.get("tag.object");
75 const {
76 node: {
77 name
78 }
79 } = object;
80 const property = path.get("tag.property");
81 if (object.isIdentifier() && name === "String" && !path.scope.getBinding(name) && property.isIdentifier() && property.node.name === "raw") {
82 return evaluateQuasis(path, path.node.quasi.quasis, state, true);
83 }
84 }
85 if (path.isConditionalExpression()) {
86 const testResult = evaluateCached(path.get("test"), state);
87 if (!state.confident) return;
88 if (testResult) {
89 return evaluateCached(path.get("consequent"), state);
90 } else {
91 return evaluateCached(path.get("alternate"), state);
92 }
93 }
94 if (path.isExpressionWrapper()) {
95 return evaluateCached(path.get("expression"), state);
96 }
97 if (path.isMemberExpression() && !path.parentPath.isCallExpression({
98 callee: path.node
99 })) {
100 const property = path.get("property");
101 const object = path.get("object");
102 if (object.isLiteral()) {
103 const value = object.node.value;
104 const type = typeof value;
105 let key = null;
106 if (path.node.computed) {
107 key = evaluateCached(property, state);
108 if (!state.confident) return;
109 } else if (property.isIdentifier()) {
110 key = property.node.name;
111 }
112 if ((type === "number" || type === "string") && key != null && (typeof key === "number" || typeof key === "string")) {
113 return value[key];
114 }
115 }
116 }
117 if (path.isReferencedIdentifier()) {
118 const binding = path.scope.getBinding(path.node.name);
119 if (binding) {
120 if (binding.constantViolations.length > 0 || path.node.start < binding.path.node.end) {
121 deopt(binding.path, state);
122 return;
123 }
124 const bindingPathScope = binding.path.scope;
125 if (binding.kind === "var" && bindingPathScope !== binding.scope) {
126 let hasUnsafeBlock = !bindingPathScope.path.parentPath.isBlockStatement();
127 for (let scope = bindingPathScope.parent; scope; scope = scope.parent) {
128 var _scope$path$parentPat;
129 if (scope === path.scope) {
130 if (hasUnsafeBlock) {
131 deopt(binding.path, state);
132 return;
133 }
134 break;
135 }
136 if ((_scope$path$parentPat = scope.path.parentPath) != null && _scope$path$parentPat.isBlockStatement()) {
137 hasUnsafeBlock = true;
138 }
139 }
140 }
141 if (binding.hasValue) {
142 return binding.value;
143 }
144 }
145 const name = path.node.name;
146 if (Globals.has(name)) {
147 if (!binding) {
148 return Globals.get(name);
149 }
150 deopt(binding.path, state);
151 return;
152 }
153 if (!binding) {
154 deopt(path, state);
155 return;
156 }
157 const bindingPath = binding.path;
158 if (!bindingPath.isVariableDeclarator()) {
159 deopt(bindingPath, state);
160 return;
161 }
162 const initPath = bindingPath.get("init");
163 const value = evaluateCached(initPath, state);
164 if (typeof value === "object" && value !== null && binding.references > 1) {
165 deopt(initPath, state);
166 return;
167 }
168 return value;
169 }
170 if (path.isUnaryExpression({
171 prefix: true
172 })) {
173 if (path.node.operator === "void") {
174 return undefined;
175 }
176 const argument = path.get("argument");
177 if (path.node.operator === "typeof" && (argument.isFunction() || argument.isClass())) {
178 return "function";
179 }
180 const arg = evaluateCached(argument, state);
181 if (!state.confident) return;
182 switch (path.node.operator) {
183 case "!":
184 return !arg;
185 case "+":
186 return +arg;
187 case "-":
188 return -arg;
189 case "~":
190 return ~arg;
191 case "typeof":
192 return typeof arg;
193 }
194 }
195 if (path.isArrayExpression()) {
196 const arr = [];
197 const elems = path.get("elements");
198 for (const elem of elems) {
199 const elemValue = elem.evaluate();
200 if (elemValue.confident) {
201 arr.push(elemValue.value);
202 } else {
203 deopt(elemValue.deopt, state);
204 return;
205 }
206 }
207 return arr;
208 }
209 if (path.isObjectExpression()) {
210 const obj = {};
211 const props = path.get("properties");
212 for (const prop of props) {
213 if (prop.isObjectMethod() || prop.isSpreadElement()) {
214 deopt(prop, state);
215 return;
216 }
217 const keyPath = prop.get("key");
218 let key;
219 if (prop.node.computed) {
220 key = keyPath.evaluate();
221 if (!key.confident) {
222 deopt(key.deopt, state);
223 return;
224 }
225 key = key.value;
226 } else if (keyPath.isIdentifier()) {
227 key = keyPath.node.name;
228 } else {
229 key = keyPath.node.value;
230 }
231 const valuePath = prop.get("value");
232 let value = valuePath.evaluate();
233 if (!value.confident) {
234 deopt(value.deopt, state);
235 return;
236 }
237 value = value.value;
238 obj[key] = value;
239 }
240 return obj;
241 }
242 if (path.isLogicalExpression()) {
243 const wasConfident = state.confident;
244 const left = evaluateCached(path.get("left"), state);
245 const leftConfident = state.confident;
246 state.confident = wasConfident;
247 const right = evaluateCached(path.get("right"), state);
248 const rightConfident = state.confident;
249 switch (path.node.operator) {
250 case "||":
251 state.confident = leftConfident && (!!left || rightConfident);
252 if (!state.confident) return;
253 return left || right;
254 case "&&":
255 state.confident = leftConfident && (!left || rightConfident);
256 if (!state.confident) return;
257 return left && right;
258 case "??":
259 state.confident = leftConfident && (left != null || rightConfident);
260 if (!state.confident) return;
261 return left != null ? left : right;
262 }
263 }
264 if (path.isBinaryExpression()) {
265 const left = evaluateCached(path.get("left"), state);
266 if (!state.confident) return;
267 const right = evaluateCached(path.get("right"), state);
268 if (!state.confident) return;
269 switch (path.node.operator) {
270 case "-":
271 return left - right;
272 case "+":
273 return left + right;
274 case "/":
275 return left / right;
276 case "*":
277 return left * right;
278 case "%":
279 return left % right;
280 case "**":
281 return Math.pow(left, right);
282 case "<":
283 return left < right;
284 case ">":
285 return left > right;
286 case "<=":
287 return left <= right;
288 case ">=":
289 return left >= right;
290 case "==":
291 return left == right;
292 case "!=":
293 return left != right;
294 case "===":
295 return left === right;
296 case "!==":
297 return left !== right;
298 case "|":
299 return left | right;
300 case "&":
301 return left & right;
302 case "^":
303 return left ^ right;
304 case "<<":
305 return left << right;
306 case ">>":
307 return left >> right;
308 case ">>>":
309 return left >>> right;
310 }
311 }
312 if (path.isCallExpression()) {
313 const callee = path.get("callee");
314 let context;
315 let func;
316 if (callee.isIdentifier() && !path.scope.getBinding(callee.node.name) && (isValidObjectCallee(callee.node.name) || isValidIdentifierCallee(callee.node.name))) {
317 func = global[callee.node.name];
318 }
319 if (callee.isMemberExpression()) {
320 const object = callee.get("object");
321 const property = callee.get("property");
322 if (object.isIdentifier() && property.isIdentifier() && isValidObjectCallee(object.node.name) && !isInvalidMethod(property.node.name)) {
323 context = global[object.node.name];
324 const key = property.node.name;
325 if (hasOwnProperty.call(context, key)) {
326 func = context[key];
327 }
328 }
329 if (object.isLiteral() && property.isIdentifier()) {
330 const type = typeof object.node.value;
331 if (type === "string" || type === "number") {
332 context = object.node.value;
333 func = context[property.node.name];
334 }
335 }
336 }
337 if (func) {
338 const args = path.get("arguments").map(arg => evaluateCached(arg, state));
339 if (!state.confident) return;
340 return func.apply(context, args);
341 }
342 }
343 deopt(path, state);
344}
345function evaluateQuasis(path, quasis, state, raw = false) {
346 let str = "";
347 let i = 0;
348 const exprs = path.isTemplateLiteral() ? path.get("expressions") : path.get("quasi.expressions");
349 for (const elem of quasis) {
350 if (!state.confident) break;
351 str += raw ? elem.value.raw : elem.value.cooked;
352 const expr = exprs[i++];
353 if (expr) str += String(evaluateCached(expr, state));
354 }
355 if (!state.confident) return;
356 return str;
357}
358function evaluate() {
359 const state = {
360 confident: true,
361 deoptPath: null,
362 seen: new Map()
363 };
364 let value = evaluateCached(this, state);
365 if (!state.confident) value = undefined;
366 return {
367 confident: state.confident,
368 deopt: state.deoptPath,
369 value: value
370 };
371}
372
373//# sourceMappingURL=evaluation.js.map
Note: See TracBrowser for help on using the repository browser.