UNPKG

13.2 kBJavaScriptView Raw
1"use strict";
2exports.__esModule = true;
3var parser_1 = require("@babel/parser");
4var b = require("@babel/types");
5var binaryOperation_1 = require("./binaryOperation");
6function expressionToConstant(expression, options) {
7 if (options === void 0) { options = {}; }
8 var constant = true;
9 function toConstant(expression) {
10 if (!constant)
11 return;
12 if (b.isArrayExpression(expression)) {
13 var result_1 = [];
14 for (var i = 0; constant && i < expression.elements.length; i++) {
15 var element = expression.elements[i];
16 if (b.isSpreadElement(element)) {
17 var spread = toConstant(element.argument);
18 if (!(isSpreadable(spread) && constant)) {
19 constant = false;
20 }
21 else {
22 result_1.push.apply(result_1, spread);
23 }
24 }
25 else if (b.isExpression(element)) {
26 result_1.push(toConstant(element));
27 }
28 else {
29 constant = false;
30 }
31 }
32 return result_1;
33 }
34 if (b.isBinaryExpression(expression)) {
35 var left = toConstant(expression.left);
36 var right = toConstant(expression.right);
37 return constant && binaryOperation_1["default"](expression.operator, left, right);
38 }
39 if (b.isBooleanLiteral(expression)) {
40 return expression.value;
41 }
42 if (b.isCallExpression(expression)) {
43 var args = [];
44 for (var i = 0; constant && i < expression.arguments.length; i++) {
45 var arg = expression.arguments[i];
46 if (b.isSpreadElement(arg)) {
47 var spread = toConstant(arg.argument);
48 if (!(isSpreadable(spread) && constant)) {
49 constant = false;
50 }
51 else {
52 args.push.apply(args, spread);
53 }
54 }
55 else if (b.isExpression(arg)) {
56 args.push(toConstant(arg));
57 }
58 else {
59 constant = false;
60 }
61 }
62 if (!constant)
63 return;
64 if (b.isMemberExpression(expression.callee)) {
65 var object = toConstant(expression.callee.object);
66 if (!object || !constant) {
67 constant = false;
68 return;
69 }
70 var member = expression.callee.computed
71 ? toConstant(expression.callee.property)
72 : b.isIdentifier(expression.callee.property)
73 ? expression.callee.property.name
74 : undefined;
75 if (member === undefined && !expression.callee.computed) {
76 constant = false;
77 }
78 if (!constant)
79 return;
80 if (canCallMethod(object, '' + member)) {
81 return object[member].apply(object, args);
82 }
83 }
84 else {
85 if (!b.isExpression(expression.callee)) {
86 constant = false;
87 return;
88 }
89 var callee = toConstant(expression.callee);
90 if (!constant)
91 return;
92 return callee.apply(null, args);
93 }
94 }
95 if (b.isConditionalExpression(expression)) {
96 var test = toConstant(expression.test);
97 return test
98 ? toConstant(expression.consequent)
99 : toConstant(expression.alternate);
100 }
101 if (b.isIdentifier(expression)) {
102 if (options.constants &&
103 {}.hasOwnProperty.call(options.constants, expression.name)) {
104 return options.constants[expression.name];
105 }
106 }
107 if (b.isLogicalExpression(expression)) {
108 var left = toConstant(expression.left);
109 var right = toConstant(expression.right);
110 if (constant && expression.operator === '&&') {
111 return left && right;
112 }
113 if (constant && expression.operator === '||') {
114 return left || right;
115 }
116 }
117 if (b.isMemberExpression(expression)) {
118 var object = toConstant(expression.object);
119 if (!object || !constant) {
120 constant = false;
121 return;
122 }
123 var member = expression.computed
124 ? toConstant(expression.property)
125 : b.isIdentifier(expression.property)
126 ? expression.property.name
127 : undefined;
128 if (member === undefined && !expression.computed) {
129 constant = false;
130 }
131 if (!constant)
132 return;
133 if ({}.hasOwnProperty.call(object, '' + member) && member[0] !== '_') {
134 return object[member];
135 }
136 }
137 if (b.isNullLiteral(expression)) {
138 return null;
139 }
140 if (b.isNumericLiteral(expression)) {
141 return expression.value;
142 }
143 if (b.isObjectExpression(expression)) {
144 var result_2 = {};
145 for (var i = 0; constant && i < expression.properties.length; i++) {
146 var property = expression.properties[i];
147 if (b.isObjectProperty(property)) {
148 if (property.shorthand) {
149 constant = false;
150 return;
151 }
152 var key = property.computed
153 ? toConstant(property.key)
154 : b.isIdentifier(property.key)
155 ? property.key.name
156 : b.isStringLiteral(property.key)
157 ? property.key.value
158 : undefined;
159 if (!key || key[0] === '_') {
160 constant = false;
161 }
162 if (!constant)
163 return;
164 if (b.isExpression(property.value)) {
165 var value = toConstant(property.value);
166 if (!constant)
167 return;
168 result_2[key] = value;
169 }
170 else {
171 constant = false;
172 }
173 }
174 else if (b.isObjectMethod(property)) {
175 constant = false;
176 }
177 else if (b.isSpreadProperty(property)) {
178 var argument = toConstant(property.argument);
179 if (!argument)
180 constant = false;
181 if (!constant)
182 return;
183 Object.assign(result_2, argument);
184 }
185 }
186 return result_2;
187 }
188 if (b.isParenthesizedExpression(expression)) {
189 return toConstant(expression.expression);
190 }
191 if (b.isRegExpLiteral(expression)) {
192 return new RegExp(expression.pattern, expression.flags);
193 }
194 if (b.isSequenceExpression(expression)) {
195 for (var i = 0; i < expression.expressions.length - 1 && constant; i++) {
196 toConstant(expression.expressions[i]);
197 }
198 return toConstant(expression.expressions[expression.expressions.length - 1]);
199 }
200 if (b.isStringLiteral(expression)) {
201 return expression.value;
202 }
203 // TODO: TaggedTemplateExpression
204 if (b.isTemplateLiteral(expression)) {
205 var result_3 = '';
206 for (var i = 0; i < expression.quasis.length; i++) {
207 var quasi = expression.quasis[i];
208 result_3 += quasi.value.cooked;
209 if (i < expression.expressions.length) {
210 result_3 += '' + toConstant(expression.expressions[i]);
211 }
212 }
213 return result_3;
214 }
215 if (b.isUnaryExpression(expression)) {
216 var argument = toConstant(expression.argument);
217 if (!constant) {
218 return;
219 }
220 switch (expression.operator) {
221 case '-':
222 return -argument;
223 case '+':
224 return +argument;
225 case '!':
226 return !argument;
227 case '~':
228 return ~argument;
229 case 'typeof':
230 return typeof argument;
231 case 'void':
232 return void argument;
233 }
234 }
235 constant = false;
236 }
237 var result = toConstant(expression);
238 return constant ? { constant: true, result: result } : { constant: false };
239}
240exports.expressionToConstant = expressionToConstant;
241function isSpreadable(value) {
242 return (typeof value === 'string' ||
243 Array.isArray(value) ||
244 (typeof Set !== 'undefined' && value instanceof Set) ||
245 (typeof Map !== 'undefined' && value instanceof Map));
246}
247function shallowEqual(a, b) {
248 if (a === b)
249 return true;
250 if (a && b && typeof a === 'object' && typeof b === 'object') {
251 for (var key in a) {
252 if (a[key] !== b[key]) {
253 return false;
254 }
255 }
256 for (var key in b) {
257 if (a[key] !== b[key]) {
258 return false;
259 }
260 }
261 return true;
262 }
263 return false;
264}
265function canCallMethod(object, member) {
266 switch (typeof object) {
267 case 'boolean':
268 switch (member) {
269 case 'toString':
270 return true;
271 default:
272 return false;
273 }
274 case 'number':
275 switch (member) {
276 case 'toExponential':
277 case 'toFixed':
278 case 'toPrecision':
279 case 'toString':
280 return true;
281 default:
282 return false;
283 }
284 case 'string':
285 switch (member) {
286 case 'charAt':
287 case 'charCodeAt':
288 case 'codePointAt':
289 case 'concat':
290 case 'endsWith':
291 case 'includes':
292 case 'indexOf':
293 case 'lastIndexOf':
294 case 'match':
295 case 'normalize':
296 case 'padEnd':
297 case 'padStart':
298 case 'repeat':
299 case 'replace':
300 case 'search':
301 case 'slice':
302 case 'split':
303 case 'startsWith':
304 case 'substr':
305 case 'substring':
306 case 'toLowerCase':
307 case 'toUpperCase':
308 case 'trim':
309 return true;
310 default:
311 return false;
312 }
313 default:
314 if (object instanceof RegExp) {
315 switch (member) {
316 case 'test':
317 case 'exec':
318 return true;
319 default:
320 return false;
321 }
322 }
323 return {}.hasOwnProperty.call(object, member) && member[0] !== '_';
324 }
325}
326var EMPTY_OBJECT = {};
327var lastSrc = '';
328var lastConstants = EMPTY_OBJECT;
329var lastOptions = EMPTY_OBJECT;
330var lastResult = null;
331var lastWasConstant = false;
332function isConstant(src, constants, options) {
333 if (constants === void 0) { constants = EMPTY_OBJECT; }
334 if (options === void 0) { options = EMPTY_OBJECT; }
335 if (lastSrc === src &&
336 shallowEqual(lastConstants, constants) &&
337 shallowEqual(lastOptions, options)) {
338 return lastWasConstant;
339 }
340 lastSrc = src;
341 lastConstants = constants;
342 var ast;
343 try {
344 ast = parser_1.parseExpression(src, options);
345 }
346 catch (ex) {
347 return (lastWasConstant = false);
348 }
349 var _a = expressionToConstant(ast, { constants: constants }), result = _a.result, constant = _a.constant;
350 lastResult = result;
351 return (lastWasConstant = constant);
352}
353exports.isConstant = isConstant;
354function toConstant(src, constants, options) {
355 if (constants === void 0) { constants = EMPTY_OBJECT; }
356 if (options === void 0) { options = EMPTY_OBJECT; }
357 if (!isConstant(src, constants, options)) {
358 throw new Error(JSON.stringify(src) + ' is not constant.');
359 }
360 return lastResult;
361}
362exports.toConstant = toConstant;
363exports["default"] = isConstant;
364module.exports = isConstant;
365module.exports["default"] = isConstant;
366module.exports.expressionToConstant = expressionToConstant;
367module.exports.isConstant = isConstant;
368module.exports.toConstant = toConstant;