source: frontend/node_modules/terser/lib/compress/drop-side-effect-free.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: 13.4 KB
Line 
1/***********************************************************************
2
3 A JavaScript tokenizer / parser / beautifier / compressor.
4 https://github.com/mishoo/UglifyJS2
5
6 -------------------------------- (C) ---------------------------------
7
8 Author: Mihai Bazon
9 <mihai.bazon@gmail.com>
10 http://mihai.bazon.net/blog
11
12 Distributed under the BSD license:
13
14 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
15
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
18 are met:
19
20 * Redistributions of source code must retain the above
21 copyright notice, this list of conditions and the following
22 disclaimer.
23
24 * Redistributions in binary form must reproduce the above
25 copyright notice, this list of conditions and the following
26 disclaimer in the documentation and/or other materials
27 provided with the distribution.
28
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
30 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
33 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
38 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
39 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 SUCH DAMAGE.
41
42 ***********************************************************************/
43
44import {
45 AST_Accessor,
46 AST_Array,
47 AST_Arrow,
48 AST_Assign,
49 AST_Binary,
50 AST_Call,
51 AST_Chain,
52 AST_Class,
53 AST_ClassPrivateProperty,
54 AST_ClassProperty,
55 AST_ClassStaticBlock,
56 AST_ConciseMethod,
57 AST_Conditional,
58 AST_Constant,
59 AST_DefClass,
60 AST_Dot,
61 AST_DynamicImport,
62 AST_Expansion,
63 AST_Function,
64 AST_Node,
65 AST_Number,
66 AST_Object,
67 AST_ObjectGetter,
68 AST_ObjectKeyVal,
69 AST_ObjectSetter,
70 AST_PrivateGetter,
71 AST_PrivateSetter,
72 AST_PrivateMethod,
73 AST_PropAccess,
74 AST_Scope,
75 AST_Sequence,
76 AST_SimpleStatement,
77 AST_Sub,
78 AST_SymbolRef,
79 AST_TemplateSegment,
80 AST_TemplateString,
81 AST_This,
82 AST_Unary,
83} from "../ast.js";
84import { make_node, return_null, return_this } from "../utils/index.js";
85import { first_in_statement } from "../utils/first_in_statement.js";
86
87import { pure_prop_access_globals } from "./native-objects.js";
88import { lazy_op, unary_side_effects, is_nullish_shortcircuited } from "./inference.js";
89import { WRITE_ONLY, set_flag, clear_flag } from "./compressor-flags.js";
90import { make_sequence, is_func_expr, is_iife_call } from "./common.js";
91
92// AST_Node#drop_side_effect_free() gets called when we don't care about the value,
93// only about side effects. We'll be defining this method for each node type in this module
94//
95// Examples:
96// foo++ -> foo++
97// 1 + func() -> func()
98// 10 -> (nothing)
99// knownPureFunc(foo++) -> foo++
100
101function def_drop_side_effect_free(node_or_nodes, func) {
102 for (const node of [].concat(node_or_nodes)) {
103 node.DEFMETHOD("drop_side_effect_free", func);
104 }
105}
106
107// Drop side-effect-free elements from an array of expressions.
108// Returns an array of expressions with side-effects or null
109// if all elements were dropped. Note: original array may be
110// returned if nothing changed.
111function trim(nodes, compressor, first_in_statement) {
112 var len = nodes.length;
113 if (!len) return null;
114
115 var ret = [], changed = false;
116 for (var i = 0; i < len; i++) {
117 var node = nodes[i].drop_side_effect_free(compressor, first_in_statement);
118 changed |= node !== nodes[i];
119 if (node) {
120 ret.push(node);
121 first_in_statement = false;
122 }
123 }
124 return changed ? ret.length ? ret : null : nodes;
125}
126
127def_drop_side_effect_free(AST_Node, return_this);
128def_drop_side_effect_free(AST_Constant, return_null);
129def_drop_side_effect_free(AST_This, return_null);
130
131def_drop_side_effect_free(AST_Call, function (compressor, first_in_statement) {
132 if (is_nullish_shortcircuited(this, compressor)) {
133 return this.expression.drop_side_effect_free(compressor, first_in_statement);
134 }
135
136 if (!this.is_callee_pure(compressor)) {
137 if (this.expression.is_call_pure(compressor)) {
138 var exprs = this.args.slice();
139 exprs.unshift(this.expression.expression);
140 exprs = trim(exprs, compressor, first_in_statement);
141 return exprs && make_sequence(this, exprs);
142 }
143 if (is_func_expr(this.expression)
144 && (!this.expression.name || !this.expression.name.definition().references.length)) {
145 var node = this.clone();
146 node.expression.process_expression(false, compressor);
147 return node;
148 }
149 return this;
150 }
151
152 var args = trim(this.args, compressor, first_in_statement);
153 return args && make_sequence(this, args);
154});
155
156def_drop_side_effect_free(AST_DynamicImport, function (compressor, first_in_statement) {
157 if (this.phase !== "source") return this;
158 var args = trim(this.args, compressor, first_in_statement);
159 return args && make_sequence(this, args);
160});
161
162def_drop_side_effect_free(AST_Accessor, return_null);
163
164def_drop_side_effect_free(AST_Function, return_null);
165
166def_drop_side_effect_free(AST_Arrow, return_null);
167
168def_drop_side_effect_free(AST_Class, function (compressor) {
169 const with_effects = [];
170
171 if (this.is_self_referential() && this.has_side_effects(compressor)) {
172 return this;
173 }
174
175 const trimmed_extends = this.extends && this.extends.drop_side_effect_free(compressor);
176 if (trimmed_extends) with_effects.push(trimmed_extends);
177
178 for (const prop of this.properties) {
179 if (prop instanceof AST_ClassStaticBlock) {
180 if (prop.has_side_effects(compressor)) {
181 return this; // Be cautious about these
182 }
183 } else {
184 const trimmed_prop = prop.drop_side_effect_free(compressor);
185 if (trimmed_prop) with_effects.push(trimmed_prop);
186 }
187 }
188
189 if (!with_effects.length)
190 return null;
191
192 const exprs = make_sequence(this, with_effects);
193 if (this instanceof AST_DefClass) {
194 // We want a statement
195 return make_node(AST_SimpleStatement, this, { body: exprs });
196 } else {
197 return exprs;
198 }
199});
200
201def_drop_side_effect_free([
202 AST_ClassProperty,
203 AST_ClassPrivateProperty,
204], function (compressor) {
205 const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
206
207 const value = this.static && this.value
208 && this.value.drop_side_effect_free(compressor);
209
210 if (key && value)
211 return make_sequence(this, [key, value]);
212 return key || value || null;
213});
214
215def_drop_side_effect_free(AST_Binary, function (compressor, first_in_statement) {
216 var right = this.right.drop_side_effect_free(compressor);
217 if (!right)
218 return this.left.drop_side_effect_free(compressor, first_in_statement);
219 if (lazy_op.has(this.operator)) {
220 if (right === this.right)
221 return this;
222 var node = this.clone();
223 node.right = right;
224 return node;
225 } else {
226 var left = this.left.drop_side_effect_free(compressor, first_in_statement);
227 if (!left)
228 return this.right.drop_side_effect_free(compressor, first_in_statement);
229 return make_sequence(this, [left, right]);
230 }
231});
232
233def_drop_side_effect_free(AST_Assign, function (compressor) {
234 if (this.logical)
235 return this;
236
237 var left = this.left;
238 if (left.has_side_effects(compressor)
239 || compressor.has_directive("use strict")
240 && left instanceof AST_PropAccess
241 && left.expression.is_constant()) {
242 return this;
243 }
244 set_flag(this, WRITE_ONLY);
245 while (left instanceof AST_PropAccess) {
246 left = left.expression;
247 }
248 if (left.is_constant_expression(compressor.find_parent(AST_Scope))) {
249 return this.right.drop_side_effect_free(compressor);
250 }
251 return this;
252});
253
254def_drop_side_effect_free(AST_Conditional, function (compressor) {
255 var consequent = this.consequent.drop_side_effect_free(compressor);
256 var alternative = this.alternative.drop_side_effect_free(compressor);
257 if (consequent === this.consequent && alternative === this.alternative)
258 return this;
259 if (!consequent)
260 return alternative ? make_node(AST_Binary, this, {
261 operator: "||",
262 left: this.condition,
263 right: alternative
264 }) : this.condition.drop_side_effect_free(compressor);
265 if (!alternative)
266 return make_node(AST_Binary, this, {
267 operator: "&&",
268 left: this.condition,
269 right: consequent
270 });
271 var node = this.clone();
272 node.consequent = consequent;
273 node.alternative = alternative;
274 return node;
275});
276
277def_drop_side_effect_free(AST_Unary, function (compressor, first_in_statement) {
278 if (unary_side_effects.has(this.operator)) {
279 if (!this.expression.has_side_effects(compressor)) {
280 set_flag(this, WRITE_ONLY);
281 } else {
282 clear_flag(this, WRITE_ONLY);
283 }
284 return this;
285 }
286 if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef)
287 return null;
288 var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
289 if (first_in_statement && expression && is_iife_call(expression)) {
290 if (expression === this.expression && this.operator == "!")
291 return this;
292 return expression.negate(compressor, first_in_statement);
293 }
294 return expression;
295});
296
297def_drop_side_effect_free(AST_SymbolRef, function (compressor) {
298 const safe_access = this.is_declared(compressor)
299 || pure_prop_access_globals.has(this.name);
300 return safe_access ? null : this;
301});
302
303def_drop_side_effect_free(AST_Object, function (compressor, first_in_statement) {
304 var values = trim(this.properties, compressor, first_in_statement);
305 return values && make_sequence(this, values);
306});
307
308def_drop_side_effect_free(AST_ObjectKeyVal, function (compressor, first_in_statement) {
309 const computed_key = this.key instanceof AST_Node;
310 const key = computed_key && this.key.drop_side_effect_free(compressor, first_in_statement);
311 const value = this.value.drop_side_effect_free(compressor, first_in_statement);
312 if (key && value) {
313 return make_sequence(this, [key, value]);
314 }
315 return key || value;
316});
317
318def_drop_side_effect_free([
319 AST_ConciseMethod,
320 AST_ObjectGetter,
321 AST_ObjectSetter,
322], function (compressor, first_in_statement) {
323 return this.computed_key() ? this.key.drop_side_effect_free(compressor, first_in_statement) : null;
324});
325
326def_drop_side_effect_free([
327 AST_PrivateMethod,
328 AST_PrivateGetter,
329 AST_PrivateSetter,
330], function () {
331 return null;
332});
333
334def_drop_side_effect_free(AST_Array, function (compressor, first_in_statement) {
335 var values = trim(this.elements, compressor, first_in_statement);
336 return values && make_sequence(this, values);
337});
338
339def_drop_side_effect_free(AST_Dot, function (compressor, first_in_statement) {
340 if (is_nullish_shortcircuited(this, compressor)) {
341 return this.expression.drop_side_effect_free(compressor, first_in_statement);
342 }
343 if (!this.optional && this.expression.may_throw_on_access(compressor)) {
344 return this;
345 }
346
347 return this.expression.drop_side_effect_free(compressor, first_in_statement);
348});
349
350def_drop_side_effect_free(AST_Sub, function (compressor, first_in_statement) {
351 if (is_nullish_shortcircuited(this, compressor)) {
352 return this.expression.drop_side_effect_free(compressor, first_in_statement);
353 }
354 if (!this.optional && this.expression.may_throw_on_access(compressor)) {
355 return this;
356 }
357
358 var property = this.property.drop_side_effect_free(compressor);
359 if (property && this.optional) return this;
360
361 var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
362
363 if (expression && property) return make_sequence(this, [expression, property]);
364 return expression || property;
365});
366
367def_drop_side_effect_free(AST_Chain, function (compressor, first_in_statement) {
368 return this.expression.drop_side_effect_free(compressor, first_in_statement);
369});
370
371def_drop_side_effect_free(AST_Sequence, function (compressor) {
372 var last = this.tail_node();
373 var expr = last.drop_side_effect_free(compressor);
374 if (expr === last)
375 return this;
376 var expressions = this.expressions.slice(0, -1);
377 if (expr)
378 expressions.push(expr);
379 if (!expressions.length) {
380 return make_node(AST_Number, this, { value: 0 });
381 }
382 return make_sequence(this, expressions);
383});
384
385def_drop_side_effect_free(AST_Expansion, function (compressor, first_in_statement) {
386 return this.expression.drop_side_effect_free(compressor, first_in_statement);
387});
388
389def_drop_side_effect_free(AST_TemplateSegment, return_null);
390
391def_drop_side_effect_free(AST_TemplateString, function (compressor) {
392 var values = trim(this.segments, compressor, first_in_statement);
393 return values && make_sequence(this, values);
394});
Note: See TracBrowser for help on using the repository browser.