terser 5.31.0 → 5.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.31.1
4
+ - Allow drop-unused to drop the whole assignment (not just the assigned name) in more situations, in order to avoid duplication of long strings.
5
+
3
6
  ## v5.31.0
4
7
  - Sync up property mangler exceptions with current contents of Firefox and Chrome environments
5
8
  - Add more webcomponent properties to property mangler exceptions (#1525)
@@ -13159,7 +13159,17 @@ function has_break_or_continue(loop, parent) {
13159
13159
  // func(something) because that changes the meaning of
13160
13160
  // the func (becomes lexical instead of global).
13161
13161
  function maintain_this_binding(parent, orig, val) {
13162
- if (
13162
+ if (requires_sequence_to_maintain_binding(parent, orig, val)) {
13163
+ const zero = make_node(AST_Number, orig, { value: 0 });
13164
+ return make_sequence(orig, [ zero, val ]);
13165
+ } else {
13166
+ return val;
13167
+ }
13168
+ }
13169
+
13170
+ /** Detect (1, x.noThis)(), (0, eval)(), which need sequences */
13171
+ function requires_sequence_to_maintain_binding(parent, orig, val) {
13172
+ return (
13163
13173
  parent instanceof AST_UnaryPrefix && parent.operator == "delete"
13164
13174
  || parent instanceof AST_Call && parent.expression === orig
13165
13175
  && (
@@ -13167,12 +13177,7 @@ function maintain_this_binding(parent, orig, val) {
13167
13177
  || val instanceof AST_PropAccess
13168
13178
  || val instanceof AST_SymbolRef && val.name == "eval"
13169
13179
  )
13170
- ) {
13171
- const zero = make_node(AST_Number, orig, { value: 0 });
13172
- return make_sequence(orig, [ zero, val ]);
13173
- } else {
13174
- return val;
13175
- }
13180
+ );
13176
13181
  }
13177
13182
 
13178
13183
  function is_func_expr(node) {
@@ -15361,7 +15366,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15361
15366
  var in_use = in_use_ids.has(def.id);
15362
15367
  if (node instanceof AST_Assign) {
15363
15368
  if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
15364
- return maintain_this_binding(parent, node, node.right.transform(tt));
15369
+ const assignee = node.right.transform(tt);
15370
+ if (!in_use && !assignee.has_side_effects(compressor) && !is_used_in_expression(tt)) {
15371
+ return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
15372
+ }
15373
+ return maintain_this_binding(parent, node, assignee);
15365
15374
  }
15366
15375
  } else if (!in_use) {
15367
15376
  return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
@@ -15568,6 +15577,14 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15568
15577
  scope = save_scope;
15569
15578
  return node;
15570
15579
  }
15580
+ },
15581
+ function after(node, in_list) {
15582
+ if (node instanceof AST_Sequence) {
15583
+ switch (node.expressions.length) {
15584
+ case 0: return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
15585
+ case 1: return node.expressions[0];
15586
+ }
15587
+ }
15571
15588
  }
15572
15589
  );
15573
15590
 
@@ -15614,6 +15631,45 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15614
15631
  }
15615
15632
  });
15616
15633
 
15634
+ /**
15635
+ * Check if a node may be used by the expression it's in
15636
+ * void (0, 1, {node}, 2) -> false
15637
+ * console.log(0, {node}) -> true
15638
+ */
15639
+ function is_used_in_expression(tw) {
15640
+ for (let p = -1, node, parent; node = tw.parent(p), parent = tw.parent(p + 1); p++) {
15641
+ if (parent instanceof AST_Sequence) {
15642
+ const nth_expression = parent.expressions.indexOf(node);
15643
+ if (nth_expression !== parent.expressions.length - 1) {
15644
+ // Detect (0, x.noThis)() constructs
15645
+ const grandparent = tw.parent(p + 2);
15646
+ if (
15647
+ parent.expressions.length > 2
15648
+ || parent.expressions.length === 1
15649
+ || !requires_sequence_to_maintain_binding(grandparent, parent, parent.expressions[1])
15650
+ ) {
15651
+ return false;
15652
+ }
15653
+ return true;
15654
+ } else {
15655
+ continue;
15656
+ }
15657
+ }
15658
+ if (parent instanceof AST_Unary) {
15659
+ const op = parent.operator;
15660
+ if (op === "void") {
15661
+ return false;
15662
+ }
15663
+ if (op === "typeof" || op === "+" || op === "-" || op === "!" || op === "~") {
15664
+ continue;
15665
+ }
15666
+ }
15667
+ return true;
15668
+ }
15669
+
15670
+ return true;
15671
+ }
15672
+
15617
15673
  /***********************************************************************
15618
15674
 
15619
15675
  A JavaScript tokenizer / parser / beautifier / compressor.
@@ -226,7 +226,17 @@ export function has_break_or_continue(loop, parent) {
226
226
  // func(something) because that changes the meaning of
227
227
  // the func (becomes lexical instead of global).
228
228
  export function maintain_this_binding(parent, orig, val) {
229
- if (
229
+ if (requires_sequence_to_maintain_binding(parent, orig, val)) {
230
+ const zero = make_node(AST_Number, orig, { value: 0 });
231
+ return make_sequence(orig, [ zero, val ]);
232
+ } else {
233
+ return val;
234
+ }
235
+ }
236
+
237
+ /** Detect (1, x.noThis)(), (0, eval)(), which need sequences */
238
+ export function requires_sequence_to_maintain_binding(parent, orig, val) {
239
+ return (
230
240
  parent instanceof AST_UnaryPrefix && parent.operator == "delete"
231
241
  || parent instanceof AST_Call && parent.expression === orig
232
242
  && (
@@ -234,12 +244,7 @@ export function maintain_this_binding(parent, orig, val) {
234
244
  || val instanceof AST_PropAccess
235
245
  || val instanceof AST_SymbolRef && val.name == "eval"
236
246
  )
237
- ) {
238
- const zero = make_node(AST_Number, orig, { value: 0 });
239
- return make_sequence(orig, [ zero, val ]);
240
- } else {
241
- return val;
242
- }
247
+ );
243
248
  }
244
249
 
245
250
  export function is_func_expr(node) {
@@ -63,6 +63,7 @@ import {
63
63
  AST_Lambda,
64
64
  AST_Number,
65
65
  AST_Scope,
66
+ AST_Sequence,
66
67
  AST_SimpleStatement,
67
68
  AST_SymbolBlockDeclaration,
68
69
  AST_SymbolCatch,
@@ -101,6 +102,7 @@ import {
101
102
  is_empty,
102
103
  is_ref_of,
103
104
  can_be_evicted_from_block,
105
+ requires_sequence_to_maintain_binding,
104
106
  } from "./common.js";
105
107
 
106
108
  const r_keep_assign = /keep_assign/;
@@ -231,7 +233,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
231
233
  var in_use = in_use_ids.has(def.id);
232
234
  if (node instanceof AST_Assign) {
233
235
  if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
234
- return maintain_this_binding(parent, node, node.right.transform(tt));
236
+ const assignee = node.right.transform(tt);
237
+ if (!in_use && !assignee.has_side_effects(compressor) && !is_used_in_expression(tt)) {
238
+ return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
239
+ }
240
+ return maintain_this_binding(parent, node, assignee);
235
241
  }
236
242
  } else if (!in_use) {
237
243
  return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
@@ -438,6 +444,14 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
438
444
  scope = save_scope;
439
445
  return node;
440
446
  }
447
+ },
448
+ function after(node, in_list) {
449
+ if (node instanceof AST_Sequence) {
450
+ switch (node.expressions.length) {
451
+ case 0: return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
452
+ case 1: return node.expressions[0];
453
+ }
454
+ }
441
455
  }
442
456
  );
443
457
 
@@ -484,3 +498,41 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
484
498
  }
485
499
  });
486
500
 
501
+ /**
502
+ * Check if a node may be used by the expression it's in
503
+ * void (0, 1, {node}, 2) -> false
504
+ * console.log(0, {node}) -> true
505
+ */
506
+ function is_used_in_expression(tw) {
507
+ for (let p = -1, node, parent; node = tw.parent(p), parent = tw.parent(p + 1); p++) {
508
+ if (parent instanceof AST_Sequence) {
509
+ const nth_expression = parent.expressions.indexOf(node);
510
+ if (nth_expression !== parent.expressions.length - 1) {
511
+ // Detect (0, x.noThis)() constructs
512
+ const grandparent = tw.parent(p + 2);
513
+ if (
514
+ parent.expressions.length > 2
515
+ || parent.expressions.length === 1
516
+ || !requires_sequence_to_maintain_binding(grandparent, parent, parent.expressions[1])
517
+ ) {
518
+ return false;
519
+ }
520
+ return true;
521
+ } else {
522
+ continue;
523
+ }
524
+ }
525
+ if (parent instanceof AST_Unary) {
526
+ const op = parent.operator;
527
+ if (op === "void") {
528
+ return false;
529
+ }
530
+ if (op === "typeof" || op === "+" || op === "-" || op === "!" || op === "~") {
531
+ continue;
532
+ }
533
+ }
534
+ return true;
535
+ }
536
+
537
+ return true;
538
+ }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "homepage": "https://terser.org",
5
5
  "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
6
6
  "license": "BSD-2-Clause",
7
- "version": "5.31.0",
7
+ "version": "5.31.1",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },