source: imaps-frontend/node_modules/terser/lib/compress/drop-side-effect-free.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 7 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 12.9 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_ClassStaticBlock,
54 AST_ClassProperty,
55 AST_ConciseMethod,
56 AST_Conditional,
57 AST_Constant,
58 AST_DefClass,
59 AST_Dot,
60 AST_Expansion,
61 AST_Function,
62 AST_Node,
63 AST_Number,
64 AST_Object,
65 AST_ObjectGetter,
66 AST_ObjectKeyVal,
67 AST_ObjectProperty,
68 AST_ObjectSetter,
69 AST_PropAccess,
70 AST_Scope,
71 AST_Sequence,
72 AST_SimpleStatement,
73 AST_Sub,
74 AST_SymbolRef,
75 AST_TemplateSegment,
76 AST_TemplateString,
77 AST_This,
78 AST_Unary,
79} from "../ast.js";
80import { make_node, return_null, return_this } from "../utils/index.js";
81import { first_in_statement } from "../utils/first_in_statement.js";
82
83import { pure_prop_access_globals } from "./native-objects.js";
84import { lazy_op, unary_side_effects, is_nullish_shortcircuited } from "./inference.js";
85import { WRITE_ONLY, set_flag, clear_flag } from "./compressor-flags.js";
86import { make_sequence, is_func_expr, is_iife_call } from "./common.js";
87
88// AST_Node#drop_side_effect_free() gets called when we don't care about the value,
89// only about side effects. We'll be defining this method for each node type in this module
90//
91// Examples:
92// foo++ -> foo++
93// 1 + func() -> func()
94// 10 -> (nothing)
95// knownPureFunc(foo++) -> foo++
96
97function def_drop_side_effect_free(node, func) {
98 node.DEFMETHOD("drop_side_effect_free", func);
99}
100
101// Drop side-effect-free elements from an array of expressions.
102// Returns an array of expressions with side-effects or null
103// if all elements were dropped. Note: original array may be
104// returned if nothing changed.
105function trim(nodes, compressor, first_in_statement) {
106 var len = nodes.length;
107 if (!len) return null;
108
109 var ret = [], changed = false;
110 for (var i = 0; i < len; i++) {
111 var node = nodes[i].drop_side_effect_free(compressor, first_in_statement);
112 changed |= node !== nodes[i];
113 if (node) {
114 ret.push(node);
115 first_in_statement = false;
116 }
117 }
118 return changed ? ret.length ? ret : null : nodes;
119}
120
121def_drop_side_effect_free(AST_Node, return_this);
122def_drop_side_effect_free(AST_Constant, return_null);
123def_drop_side_effect_free(AST_This, return_null);
124
125def_drop_side_effect_free(AST_Call, function (compressor, first_in_statement) {
126 if (is_nullish_shortcircuited(this, compressor)) {
127 return this.expression.drop_side_effect_free(compressor, first_in_statement);
128 }
129
130 if (!this.is_callee_pure(compressor)) {
131 if (this.expression.is_call_pure(compressor)) {
132 var exprs = this.args.slice();
133 exprs.unshift(this.expression.expression);
134 exprs = trim(exprs, compressor, first_in_statement);
135 return exprs && make_sequence(this, exprs);
136 }
137 if (is_func_expr(this.expression)
138 && (!this.expression.name || !this.expression.name.definition().references.length)) {
139 var node = this.clone();
140 node.expression.process_expression(false, compressor);
141 return node;
142 }
143 return this;
144 }
145
146 var args = trim(this.args, compressor, first_in_statement);
147 return args && make_sequence(this, args);
148});
149
150def_drop_side_effect_free(AST_Accessor, return_null);
151
152def_drop_side_effect_free(AST_Function, return_null);
153
154def_drop_side_effect_free(AST_Arrow, return_null);
155
156def_drop_side_effect_free(AST_Class, function (compressor) {
157 const with_effects = [];
158
159 if (this.is_self_referential() && this.has_side_effects(compressor)) {
160 return this;
161 }
162
163 const trimmed_extends = this.extends && this.extends.drop_side_effect_free(compressor);
164 if (trimmed_extends) with_effects.push(trimmed_extends);
165
166 for (const prop of this.properties) {
167 if (prop instanceof AST_ClassStaticBlock) {
168 if (prop.has_side_effects(compressor)) {
169 return this; // Be cautious about these
170 }
171 } else {
172 const trimmed_prop = prop.drop_side_effect_free(compressor);
173 if (trimmed_prop) with_effects.push(trimmed_prop);
174 }
175 }
176
177 if (!with_effects.length)
178 return null;
179
180 const exprs = make_sequence(this, with_effects);
181 if (this instanceof AST_DefClass) {
182 // We want a statement
183 return make_node(AST_SimpleStatement, this, { body: exprs });
184 } else {
185 return exprs;
186 }
187});
188
189def_drop_side_effect_free(AST_ClassProperty, function (compressor) {
190 const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
191
192 const value = this.static && this.value
193 && this.value.drop_side_effect_free(compressor);
194
195 if (key && value)
196 return make_sequence(this, [key, value]);
197 return key || value || null;
198});
199
200def_drop_side_effect_free(AST_Binary, function (compressor, first_in_statement) {
201 var right = this.right.drop_side_effect_free(compressor);
202 if (!right)
203 return this.left.drop_side_effect_free(compressor, first_in_statement);
204 if (lazy_op.has(this.operator)) {
205 if (right === this.right)
206 return this;
207 var node = this.clone();
208 node.right = right;
209 return node;
210 } else {
211 var left = this.left.drop_side_effect_free(compressor, first_in_statement);
212 if (!left)
213 return this.right.drop_side_effect_free(compressor, first_in_statement);
214 return make_sequence(this, [left, right]);
215 }
216});
217
218def_drop_side_effect_free(AST_Assign, function (compressor) {
219 if (this.logical)
220 return this;
221
222 var left = this.left;
223 if (left.has_side_effects(compressor)
224 || compressor.has_directive("use strict")
225 && left instanceof AST_PropAccess
226 && left.expression.is_constant()) {
227 return this;
228 }
229 set_flag(this, WRITE_ONLY);
230 while (left instanceof AST_PropAccess) {
231 left = left.expression;
232 }
233 if (left.is_constant_expression(compressor.find_parent(AST_Scope))) {
234 return this.right.drop_side_effect_free(compressor);
235 }
236 return this;
237});
238
239def_drop_side_effect_free(AST_Conditional, function (compressor) {
240 var consequent = this.consequent.drop_side_effect_free(compressor);
241 var alternative = this.alternative.drop_side_effect_free(compressor);
242 if (consequent === this.consequent && alternative === this.alternative)
243 return this;
244 if (!consequent)
245 return alternative ? make_node(AST_Binary, this, {
246 operator: "||",
247 left: this.condition,
248 right: alternative
249 }) : this.condition.drop_side_effect_free(compressor);
250 if (!alternative)
251 return make_node(AST_Binary, this, {
252 operator: "&&",
253 left: this.condition,
254 right: consequent
255 });
256 var node = this.clone();
257 node.consequent = consequent;
258 node.alternative = alternative;
259 return node;
260});
261
262def_drop_side_effect_free(AST_Unary, function (compressor, first_in_statement) {
263 if (unary_side_effects.has(this.operator)) {
264 if (!this.expression.has_side_effects(compressor)) {
265 set_flag(this, WRITE_ONLY);
266 } else {
267 clear_flag(this, WRITE_ONLY);
268 }
269 return this;
270 }
271 if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef)
272 return null;
273 var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
274 if (first_in_statement && expression && is_iife_call(expression)) {
275 if (expression === this.expression && this.operator == "!")
276 return this;
277 return expression.negate(compressor, first_in_statement);
278 }
279 return expression;
280});
281
282def_drop_side_effect_free(AST_SymbolRef, function (compressor) {
283 const safe_access = this.is_declared(compressor)
284 || pure_prop_access_globals.has(this.name);
285 return safe_access ? null : this;
286});
287
288def_drop_side_effect_free(AST_Object, function (compressor, first_in_statement) {
289 var values = trim(this.properties, compressor, first_in_statement);
290 return values && make_sequence(this, values);
291});
292
293def_drop_side_effect_free(AST_ObjectProperty, function (compressor, first_in_statement) {
294 const computed_key = this instanceof AST_ObjectKeyVal && this.key instanceof AST_Node;
295 const key = computed_key && this.key.drop_side_effect_free(compressor, first_in_statement);
296 const value = this.value && this.value.drop_side_effect_free(compressor, first_in_statement);
297 if (key && value) {
298 return make_sequence(this, [key, value]);
299 }
300 return key || value;
301});
302
303def_drop_side_effect_free(AST_ConciseMethod, function () {
304 return this.computed_key() ? this.key : null;
305});
306
307def_drop_side_effect_free(AST_ObjectGetter, function () {
308 return this.computed_key() ? this.key : null;
309});
310
311def_drop_side_effect_free(AST_ObjectSetter, function () {
312 return this.computed_key() ? this.key : null;
313});
314
315def_drop_side_effect_free(AST_Array, function (compressor, first_in_statement) {
316 var values = trim(this.elements, compressor, first_in_statement);
317 return values && make_sequence(this, values);
318});
319
320def_drop_side_effect_free(AST_Dot, function (compressor, first_in_statement) {
321 if (is_nullish_shortcircuited(this, compressor)) {
322 return this.expression.drop_side_effect_free(compressor, first_in_statement);
323 }
324 if (!this.optional && this.expression.may_throw_on_access(compressor)) {
325 return this;
326 }
327
328 return this.expression.drop_side_effect_free(compressor, first_in_statement);
329});
330
331def_drop_side_effect_free(AST_Sub, function (compressor, first_in_statement) {
332 if (is_nullish_shortcircuited(this, compressor)) {
333 return this.expression.drop_side_effect_free(compressor, first_in_statement);
334 }
335 if (!this.optional && this.expression.may_throw_on_access(compressor)) {
336 return this;
337 }
338
339 var property = this.property.drop_side_effect_free(compressor);
340 if (property && this.optional) return this;
341
342 var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
343
344 if (expression && property) return make_sequence(this, [expression, property]);
345 return expression || property;
346});
347
348def_drop_side_effect_free(AST_Chain, function (compressor, first_in_statement) {
349 return this.expression.drop_side_effect_free(compressor, first_in_statement);
350});
351
352def_drop_side_effect_free(AST_Sequence, function (compressor) {
353 var last = this.tail_node();
354 var expr = last.drop_side_effect_free(compressor);
355 if (expr === last)
356 return this;
357 var expressions = this.expressions.slice(0, -1);
358 if (expr)
359 expressions.push(expr);
360 if (!expressions.length) {
361 return make_node(AST_Number, this, { value: 0 });
362 }
363 return make_sequence(this, expressions);
364});
365
366def_drop_side_effect_free(AST_Expansion, function (compressor, first_in_statement) {
367 return this.expression.drop_side_effect_free(compressor, first_in_statement);
368});
369
370def_drop_side_effect_free(AST_TemplateSegment, return_null);
371
372def_drop_side_effect_free(AST_TemplateString, function (compressor) {
373 var values = trim(this.segments, compressor, first_in_statement);
374 return values && make_sequence(this, values);
375});
Note: See TracBrowser for help on using the repository browser.