terser 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a79c3ce462ccc7dbc82fac484b88f9d99d863113d831b46f450846cd0c16153
4
- data.tar.gz: 67113e1a30a5260a02ec66269a2a85884681a46377dfb564e13ae767d0b34dfc
3
+ metadata.gz: 74a43961686b1bf08bcaec1a1395f6f9bb4fd07ca66b6d154abed2e8b62c8e58
4
+ data.tar.gz: 2dea98bbf908aba6591e3aa2d2cce8edbed21cfee7b140a8377179c0821856a7
5
5
  SHA512:
6
- metadata.gz: d63da1e879cd56a5b43c5e4e6dc115a7b724cf6ff9a8abf42034154b925996da40858376dfb56cc14630c02f75206eec92c53b636c4069865d64ca283d87a0ce
7
- data.tar.gz: 2889a964e38a30c94610f5bb807561b085dc5c615058f47d8f445791ca57c61116b3e9e73153263a59c5d84a1616f5c9490d0ec549dd93aea44ac6f82e6629ea
6
+ metadata.gz: b3c6a287cd2101c155ea721e06615576d2328d63358ce7c1f5c4a13e81235a8baf59ac41d59e19e045956d9212baae2dbf2a10a7d9397cbd4272d3bd8ff2e4f9
7
+ data.tar.gz: f1f18ac66b8ea18431048e751355684c909bc919602a8f08747da95c31a6a59b8d98c220301ec14f97ec1cd2e2ec67219514bfe70c27a5ee6cb67bd208731574
data/CHANGELOG.md CHANGED
@@ -1,6 +1,9 @@
1
1
  Behavioural changes in TerserJS are listed [here](https://github.com/terser/terser/blob/master/CHANGELOG.md).
2
2
 
3
3
  ## Unreleased
4
+ ## 1.2.4 (7 October 2024)
5
+ - update TerserJS to [5.34.1]
6
+
4
7
  ## 1.2.3 (11 June 2024)
5
8
  - update TerserJS to [5.31.1]
6
9
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  class Terser
4
4
  # Current version of Terser.
5
- VERSION = "1.2.3"
5
+ VERSION = "1.2.4"
6
6
  end
data/lib/terser.js CHANGED
@@ -7571,6 +7571,19 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
7571
7571
  });
7572
7572
  },
7573
7573
 
7574
+ ImportExpression: function(M) {
7575
+ return new AST_Call({
7576
+ start: my_start_token(M),
7577
+ end: my_end_token(M),
7578
+ expression: from_moz({
7579
+ type: "Identifier",
7580
+ name: "import"
7581
+ }),
7582
+ optional: false,
7583
+ args: [from_moz(M.source)]
7584
+ });
7585
+ },
7586
+
7574
7587
  ExportAllDeclaration: function(M) {
7575
7588
  var foreign_name = M.exported == null ?
7576
7589
  new AST_SymbolExportForeign({ name: "*" }) :
@@ -7638,6 +7651,11 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
7638
7651
  args.value = { source, flags };
7639
7652
  return new AST_RegExp(args);
7640
7653
  }
7654
+ const bi = typeof M.value === "bigint" ? M.value.toString() : M.bigint;
7655
+ if (typeof bi === "string") {
7656
+ args.value = bi;
7657
+ return new AST_BigInt(args);
7658
+ }
7641
7659
  if (val === null) return new AST_Null(args);
7642
7660
  switch (typeof val) {
7643
7661
  case "string":
@@ -7705,14 +7723,6 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
7705
7723
  });
7706
7724
  },
7707
7725
 
7708
- BigIntLiteral(M) {
7709
- return new AST_BigInt({
7710
- start : my_start_token(M),
7711
- end : my_end_token(M),
7712
- value : M.value
7713
- });
7714
- },
7715
-
7716
7726
  EmptyStatement: function(M) {
7717
7727
  return new AST_EmptyStatement({
7718
7728
  start: my_start_token(M),
@@ -8185,6 +8195,14 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
8185
8195
  };
8186
8196
  });
8187
8197
  def_to_moz(AST_Call, function To_Moz_CallExpression(M) {
8198
+ if (M.expression instanceof AST_SymbolRef && M.expression.name === "import") {
8199
+ const [source] = M.args.map(to_moz);
8200
+ return {
8201
+ type: "ImportExpression",
8202
+ source,
8203
+ };
8204
+ }
8205
+
8188
8206
  return {
8189
8207
  type: "CallExpression",
8190
8208
  callee: to_moz(M.expression),
@@ -8730,8 +8748,13 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
8730
8748
  });
8731
8749
 
8732
8750
  def_to_moz(AST_BigInt, M => ({
8733
- type: "BigIntLiteral",
8734
- value: M.value
8751
+ type: "Literal",
8752
+ // value cannot be represented natively
8753
+ // see: https://github.com/estree/estree/blob/master/es2020.md#bigintliteral
8754
+ value: null,
8755
+ // `M.value` is a string that may be a hex number representation.
8756
+ // but "bigint" property should have only decimal digits
8757
+ bigint: typeof BigInt === "function" ? BigInt(M.value).toString() : M.value,
8735
8758
  }));
8736
8759
 
8737
8760
  AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
@@ -10276,7 +10299,9 @@ function OutputStream(options) {
10276
10299
  AST_Arrow.DEFMETHOD("_do_print", function(output) {
10277
10300
  var self = this;
10278
10301
  var parent = output.parent();
10279
- var needs_parens = (parent instanceof AST_Binary && !(parent instanceof AST_Assign)) ||
10302
+ var needs_parens = (parent instanceof AST_Binary &&
10303
+ !(parent instanceof AST_Assign) &&
10304
+ !(parent instanceof AST_DefaultAssign)) ||
10280
10305
  parent instanceof AST_Unary ||
10281
10306
  (parent instanceof AST_Call && self === parent.expression);
10282
10307
  if (needs_parens) { output.print("("); }
@@ -11649,7 +11674,7 @@ function redefined_catch_def(def) {
11649
11674
  }
11650
11675
  }
11651
11676
 
11652
- AST_Scope.DEFMETHOD("figure_out_scope", function(options, { parent_scope = null, toplevel = this } = {}) {
11677
+ AST_Scope.DEFMETHOD("figure_out_scope", function(options, { parent_scope = undefined, toplevel = this } = {}) {
11653
11678
  options = defaults(options, {
11654
11679
  cache: null,
11655
11680
  ie8: false,
@@ -11973,7 +11998,7 @@ AST_Scope.DEFMETHOD("add_child_scope", function (scope) {
11973
11998
  scope.parent_scope = this;
11974
11999
 
11975
12000
  // Propagate to this.uses_arguments from arrow functions
11976
- if ((scope instanceof AST_Arrow) && !this.uses_arguments) {
12001
+ if ((scope instanceof AST_Arrow) && (this instanceof AST_Lambda && !this.uses_arguments)) {
11977
12002
  this.uses_arguments = walk(scope, node => {
11978
12003
  if (
11979
12004
  node instanceof AST_SymbolRef
@@ -13040,6 +13065,23 @@ function make_sequence(orig, expressions) {
13040
13065
  });
13041
13066
  }
13042
13067
 
13068
+ function make_empty_function(self) {
13069
+ return make_node(AST_Function, self, {
13070
+ uses_arguments: false,
13071
+ argnames: [],
13072
+ body: [],
13073
+ is_generator: false,
13074
+ async: false,
13075
+ variables: new Map(),
13076
+ uses_with: false,
13077
+ uses_eval: false,
13078
+ parent_scope: null,
13079
+ enclosed: [],
13080
+ cname: 0,
13081
+ block_scope: undefined,
13082
+ });
13083
+ }
13084
+
13043
13085
  function make_node_from_constant(val, orig) {
13044
13086
  switch (typeof val) {
13045
13087
  case "string":
@@ -13266,9 +13308,9 @@ function is_reachable(scope_node, defs) {
13266
13308
  }
13267
13309
 
13268
13310
  /** Check if a ref refers to the name of a function/class it's defined within */
13269
- function is_recursive_ref(compressor, def) {
13311
+ function is_recursive_ref(tw, def) {
13270
13312
  var node;
13271
- for (var i = 0; node = compressor.parent(i); i++) {
13313
+ for (var i = 0; node = tw.parent(i); i++) {
13272
13314
  if (node instanceof AST_Lambda || node instanceof AST_Class) {
13273
13315
  var name = node.name;
13274
13316
  if (name && name.definition() === def) {
@@ -13834,7 +13876,7 @@ function is_nullish(node, compressor) {
13834
13876
  return any(this.definitions, compressor);
13835
13877
  });
13836
13878
  def_has_side_effects(AST_VarDef, function() {
13837
- return this.value;
13879
+ return this.value != null;
13838
13880
  });
13839
13881
  def_has_side_effects(AST_TemplateSegment, return_false);
13840
13882
  def_has_side_effects(AST_TemplateString, function(compressor) {
@@ -14393,6 +14435,54 @@ function is_modified(compressor, tw, node, value, level, immutable) {
14393
14435
  }
14394
14436
  }
14395
14437
 
14438
+ /**
14439
+ * Check if a node may be used by the expression it's in
14440
+ * void (0, 1, {node}, 2) -> false
14441
+ * console.log(0, {node}) -> true
14442
+ */
14443
+ function is_used_in_expression(tw) {
14444
+ for (let p = -1, node, parent; node = tw.parent(p), parent = tw.parent(p + 1); p++) {
14445
+ if (parent instanceof AST_Sequence) {
14446
+ const nth_expression = parent.expressions.indexOf(node);
14447
+ if (nth_expression !== parent.expressions.length - 1) {
14448
+ // Detect (0, x.noThis)() constructs
14449
+ const grandparent = tw.parent(p + 2);
14450
+ if (
14451
+ parent.expressions.length > 2
14452
+ || parent.expressions.length === 1
14453
+ || !requires_sequence_to_maintain_binding(grandparent, parent, parent.expressions[1])
14454
+ ) {
14455
+ return false;
14456
+ }
14457
+ return true;
14458
+ } else {
14459
+ continue;
14460
+ }
14461
+ }
14462
+ if (parent instanceof AST_Unary) {
14463
+ const op = parent.operator;
14464
+ if (op === "void") {
14465
+ return false;
14466
+ }
14467
+ if (op === "typeof" || op === "+" || op === "-" || op === "!" || op === "~") {
14468
+ continue;
14469
+ }
14470
+ }
14471
+ if (
14472
+ parent instanceof AST_SimpleStatement
14473
+ || parent instanceof AST_LabeledStatement
14474
+ ) {
14475
+ return false;
14476
+ }
14477
+ if (parent instanceof AST_Scope) {
14478
+ return false;
14479
+ }
14480
+ return true;
14481
+ }
14482
+
14483
+ return true;
14484
+ }
14485
+
14396
14486
  /***********************************************************************
14397
14487
 
14398
14488
  A JavaScript tokenizer / parser / beautifier / compressor.
@@ -14577,14 +14667,25 @@ def_eval(AST_Object, function (compressor, depth) {
14577
14667
  var non_converting_unary = makePredicate("! typeof void");
14578
14668
  def_eval(AST_UnaryPrefix, function (compressor, depth) {
14579
14669
  var e = this.expression;
14580
- // Function would be evaluated to an array and so typeof would
14581
- // incorrectly return 'object'. Hence making is a special case.
14582
14670
  if (compressor.option("typeofs")
14583
- && this.operator == "typeof"
14584
- && (e instanceof AST_Lambda
14671
+ && this.operator == "typeof") {
14672
+ // Function would be evaluated to an array and so typeof would
14673
+ // incorrectly return 'object'. Hence making is a special case.
14674
+ if (e instanceof AST_Lambda
14585
14675
  || e instanceof AST_SymbolRef
14586
- && e.fixed_value() instanceof AST_Lambda)) {
14587
- return typeof function () { };
14676
+ && e.fixed_value() instanceof AST_Lambda) {
14677
+ return typeof function () { };
14678
+ }
14679
+ if (
14680
+ (e instanceof AST_Object
14681
+ || e instanceof AST_Array
14682
+ || (e instanceof AST_SymbolRef
14683
+ && (e.fixed_value() instanceof AST_Object
14684
+ || e.fixed_value() instanceof AST_Array)))
14685
+ && !e.has_side_effects(compressor)
14686
+ ) {
14687
+ return typeof {};
14688
+ }
14588
14689
  }
14589
14690
  if (!non_converting_unary.has(this.operator))
14590
14691
  depth++;
@@ -15272,7 +15373,6 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15272
15373
  }
15273
15374
  var var_defs_by_id = new Map();
15274
15375
  var initializations = new Map();
15275
- var self_referential_classes = new Set();
15276
15376
 
15277
15377
  // pass 1: find out which symbols are directly used in
15278
15378
  // this scope (not in nested scopes).
@@ -15287,8 +15387,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15287
15387
  }
15288
15388
  if (node === self) return;
15289
15389
  if (node instanceof AST_Class && node.has_side_effects(compressor)) {
15290
- if (node.is_self_referential()) self_referential_classes.add(node);
15291
- node.visit_nondeferred_class_parts(tw);
15390
+ if (node.is_self_referential()) {
15391
+ descend();
15392
+ } else {
15393
+ node.visit_nondeferred_class_parts(tw);
15394
+ }
15292
15395
  }
15293
15396
  if (node instanceof AST_Defun || node instanceof AST_DefClass) {
15294
15397
  var node_def = node.name.definition();
@@ -15352,9 +15455,6 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15352
15455
  init.walk(tw);
15353
15456
  });
15354
15457
  });
15355
- self_referential_classes.forEach(function (cls) {
15356
- cls.walk(tw);
15357
- });
15358
15458
  // pass 3: we should drop declarations not in_use
15359
15459
  var tt = new TreeTransformer(
15360
15460
  function before(node, descend, in_list) {
@@ -15390,7 +15490,13 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15390
15490
  if (!in_use_ids.has(def.id) || def.orig.length > 1) node.name = null;
15391
15491
  }
15392
15492
  if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
15393
- var trim = !compressor.option("keep_fargs");
15493
+ var trim =
15494
+ !compressor.option("keep_fargs")
15495
+ // Is this an IIFE that won't refer to its name?
15496
+ || parent instanceof AST_Call
15497
+ && parent.expression === node
15498
+ && !node.pinned()
15499
+ && (!node.name || node.name.unreferenced());
15394
15500
  for (var a = node.argnames, i = a.length; --i >= 0;) {
15395
15501
  var sym = a[i];
15396
15502
  if (sym instanceof AST_Expansion) {
@@ -15631,45 +15737,6 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15631
15737
  }
15632
15738
  });
15633
15739
 
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
-
15673
15740
  /***********************************************************************
15674
15741
 
15675
15742
  A JavaScript tokenizer / parser / beautifier / compressor.
@@ -16106,28 +16173,50 @@ function mark_lambda(tw, descend, compressor) {
16106
16173
  * // use defined_after
16107
16174
  * }
16108
16175
  *
16109
- * This function is called on the parent to handle this issue.
16176
+ * Or even indirectly:
16177
+ *
16178
+ * B();
16179
+ * var defined_after = true;
16180
+ * function A() {
16181
+ * // use defined_after
16182
+ * }
16183
+ * function B() {
16184
+ * A();
16185
+ * }
16186
+ *
16187
+ * Access a variable before declaration will either throw a ReferenceError
16188
+ * (if the variable is declared with `let` or `const`),
16189
+ * or get an `undefined` (if the variable is declared with `var`).
16190
+ *
16191
+ * If the variable is inlined into the function, the behavior will change.
16192
+ *
16193
+ * This function is called on the parent to disallow inlining of such variables,
16110
16194
  */
16111
16195
  function handle_defined_after_hoist(parent) {
16112
16196
  const defuns = [];
16113
16197
  walk(parent, node => {
16114
16198
  if (node === parent) return;
16115
- if (node instanceof AST_Defun) defuns.push(node);
16199
+ if (node instanceof AST_Defun) {
16200
+ defuns.push(node);
16201
+ return true;
16202
+ }
16116
16203
  if (
16117
16204
  node instanceof AST_Scope
16118
16205
  || node instanceof AST_SimpleStatement
16119
16206
  ) return true;
16120
16207
  });
16121
16208
 
16209
+ // `defun` id to array of `defun` it uses
16210
+ const defun_dependencies_map = new Map();
16211
+ // `defun` id to array of enclosing `def` that are used by the function
16212
+ const dependencies_map = new Map();
16213
+ // all symbol ids that will be tracked for read/write
16122
16214
  const symbols_of_interest = new Set();
16123
16215
  const defuns_of_interest = new Set();
16124
- const potential_conflicts = [];
16125
16216
 
16126
16217
  for (const defun of defuns) {
16127
16218
  const fname_def = defun.name.definition();
16128
- const found_self_ref_in_other_defuns = defuns.some(
16129
- d => d !== defun && d.enclosed.indexOf(fname_def) !== -1
16130
- );
16219
+ const enclosing_defs = [];
16131
16220
 
16132
16221
  for (const def of defun.enclosed) {
16133
16222
  if (
@@ -16138,93 +16227,107 @@ function handle_defined_after_hoist(parent) {
16138
16227
  continue;
16139
16228
  }
16140
16229
 
16141
- // defun is hoisted, so always safe
16230
+ symbols_of_interest.add(def.id);
16231
+
16232
+ // found a reference to another function
16142
16233
  if (
16143
16234
  def.assignments === 0
16144
16235
  && def.orig.length === 1
16145
16236
  && def.orig[0] instanceof AST_SymbolDefun
16146
16237
  ) {
16147
- continue;
16148
- }
16238
+ defuns_of_interest.add(def.id);
16239
+ symbols_of_interest.add(def.id);
16240
+
16241
+ defuns_of_interest.add(fname_def.id);
16242
+ symbols_of_interest.add(fname_def.id);
16243
+
16244
+ if (!defun_dependencies_map.has(fname_def.id)) {
16245
+ defun_dependencies_map.set(fname_def.id, []);
16246
+ }
16247
+ defun_dependencies_map.get(fname_def.id).push(def.id);
16149
16248
 
16150
- if (found_self_ref_in_other_defuns) {
16151
- def.fixed = false;
16152
16249
  continue;
16153
16250
  }
16154
16251
 
16155
- // for the slower checks below this loop
16156
- potential_conflicts.push({ defun, def, fname_def });
16157
- symbols_of_interest.add(def.id);
16252
+ enclosing_defs.push(def);
16253
+ }
16254
+
16255
+ if (enclosing_defs.length) {
16256
+ dependencies_map.set(fname_def.id, enclosing_defs);
16257
+ defuns_of_interest.add(fname_def.id);
16158
16258
  symbols_of_interest.add(fname_def.id);
16159
- defuns_of_interest.add(defun);
16160
16259
  }
16161
16260
  }
16162
16261
 
16163
- // linearize all symbols, and locate defs that are read after the defun
16164
- if (potential_conflicts.length) {
16165
- // All "symbols of interest", that is, defuns or defs, that we found.
16166
- // These are placed in order so we can check which is after which.
16167
- const found_symbols = [];
16168
- // Indices of `found_symbols` which are writes
16169
- const found_symbol_writes = new Set();
16170
- // Defun ranges are recorded because we don't care if a function uses the def internally
16171
- const defun_ranges = new Map();
16262
+ // No defuns use outside constants
16263
+ if (!dependencies_map.size) {
16264
+ return;
16265
+ }
16172
16266
 
16173
- let tw;
16174
- parent.walk((tw = new TreeWalker((node, descend) => {
16175
- if (node instanceof AST_Defun && defuns_of_interest.has(node)) {
16176
- const start = found_symbols.length;
16177
- descend();
16178
- const end = found_symbols.length;
16267
+ // Increment to count "symbols of interest" (defuns or defs) that we found.
16268
+ // These are tracked in AST order so we can check which is after which.
16269
+ let symbol_index = 1;
16270
+ // Map a defun ID to its first read (a `symbol_index`)
16271
+ const defun_first_read_map = new Map();
16272
+ // Map a symbol ID to its last write (a `symbol_index`)
16273
+ const symbol_last_write_map = new Map();
16179
16274
 
16180
- defun_ranges.set(node, { start, end });
16181
- return true;
16182
- }
16183
- // if we found a defun on the list, mark IN_DEFUN=id and descend
16275
+ walk_parent(parent, (node, walk_info) => {
16276
+ if (node instanceof AST_Symbol && node.thedef) {
16277
+ const id = node.definition().id;
16184
16278
 
16185
- if (node instanceof AST_Symbol && node.thedef) {
16186
- const id = node.definition().id;
16187
- if (symbols_of_interest.has(id)) {
16188
- if (node instanceof AST_SymbolDeclaration || is_lhs(node, tw)) {
16189
- found_symbol_writes.add(found_symbols.length);
16190
- }
16191
- found_symbols.push(id);
16279
+ symbol_index++;
16280
+
16281
+ // Track last-writes to symbols
16282
+ if (symbols_of_interest.has(id)) {
16283
+ if (node instanceof AST_SymbolDeclaration || is_lhs(node, walk_info.parent())) {
16284
+ symbol_last_write_map.set(id, symbol_index);
16192
16285
  }
16193
16286
  }
16194
- })));
16195
16287
 
16196
- for (const { def, defun, fname_def } of potential_conflicts) {
16197
- const defun_range = defun_ranges.get(defun);
16288
+ // Track first-reads of defuns (refined later)
16289
+ if (defuns_of_interest.has(id)) {
16290
+ if (!defun_first_read_map.has(id) && !is_recursive_ref(walk_info, id)) {
16291
+ defun_first_read_map.set(id, symbol_index);
16292
+ }
16293
+ }
16294
+ }
16295
+ });
16198
16296
 
16199
- // find the index in `found_symbols`, with some special rules:
16200
- const find = (sym_id, starting_at = 0, must_be_write = false) => {
16201
- let index = starting_at;
16297
+ // Refine `defun_first_read_map` to be as high as possible
16298
+ for (const [defun, defun_first_read] of defun_first_read_map) {
16299
+ // Update all depdencies of `defun`
16300
+ const queue = new Set(defun_dependencies_map.get(defun));
16301
+ for (const enclosed_defun of queue) {
16302
+ let enclosed_defun_first_read = defun_first_read_map.get(enclosed_defun);
16303
+ if (enclosed_defun_first_read != null && enclosed_defun_first_read < defun_first_read) {
16304
+ continue;
16305
+ }
16202
16306
 
16203
- for (;;) {
16204
- index = found_symbols.indexOf(sym_id, index);
16307
+ defun_first_read_map.set(enclosed_defun, defun_first_read);
16205
16308
 
16206
- if (index === -1) {
16207
- break;
16208
- } else if (index >= defun_range.start && index < defun_range.end) {
16209
- index = defun_range.end;
16210
- continue;
16211
- } else if (must_be_write && !found_symbol_writes.has(index)) {
16212
- index++;
16213
- continue;
16214
- } else {
16215
- break;
16216
- }
16217
- }
16309
+ for (const enclosed_enclosed_defun of defun_dependencies_map.get(enclosed_defun) || []) {
16310
+ queue.add(enclosed_enclosed_defun);
16311
+ }
16312
+ }
16313
+ }
16218
16314
 
16219
- return index;
16220
- };
16315
+ // ensure write-then-read order, otherwise clear `fixed`
16316
+ // This is safe because last-writes (found_symbol_writes) are assumed to be as late as possible, and first-reads (defun_first_read_map) are assumed to be as early as possible.
16317
+ for (const [defun, defs] of dependencies_map) {
16318
+ const defun_first_read = defun_first_read_map.get(defun);
16319
+ if (defun_first_read === undefined) {
16320
+ continue;
16321
+ }
16221
16322
 
16222
- const read_defun_at = find(fname_def.id);
16223
- const wrote_def_at = find(def.id, read_defun_at + 1, true);
16323
+ for (const def of defs) {
16324
+ if (def.fixed === false) {
16325
+ continue;
16326
+ }
16224
16327
 
16225
- const wrote_def_after_reading_defun = read_defun_at != -1 && wrote_def_at != -1 && wrote_def_at > read_defun_at;
16328
+ let def_last_write = symbol_last_write_map.get(def.id) || 0;
16226
16329
 
16227
- if (wrote_def_after_reading_defun) {
16330
+ if (defun_first_read < def_last_write) {
16228
16331
  def.fixed = false;
16229
16332
  }
16230
16333
  }
@@ -18858,9 +18961,8 @@ def_optimize(AST_Node, function(self) {
18858
18961
  });
18859
18962
 
18860
18963
  AST_Toplevel.DEFMETHOD("drop_console", function(options) {
18861
- var isArray = Array.isArray(options);
18862
-
18863
- return this.transform(new TreeTransformer(function(self) {
18964
+ const isArray = Array.isArray(options);
18965
+ const tt = new TreeTransformer(function(self) {
18864
18966
  if (self.TYPE !== "Call") {
18865
18967
  return;
18866
18968
  }
@@ -18871,18 +18973,35 @@ AST_Toplevel.DEFMETHOD("drop_console", function(options) {
18871
18973
  return;
18872
18974
  }
18873
18975
 
18874
- if (isArray && options.indexOf(exp.property) === -1) {
18976
+ if (isArray && !options.includes(exp.property)) {
18875
18977
  return;
18876
18978
  }
18877
18979
 
18878
18980
  var name = exp.expression;
18981
+ var depth = 2;
18879
18982
  while (name.expression) {
18880
18983
  name = name.expression;
18984
+ depth++;
18881
18985
  }
18986
+
18882
18987
  if (is_undeclared_ref(name) && name.name == "console") {
18883
- return make_node(AST_Undefined, self);
18988
+ if (
18989
+ depth === 3
18990
+ && !["call", "apply"].includes(exp.property)
18991
+ && is_used_in_expression(tt)
18992
+ ) {
18993
+ // a (used) call to Function.prototype methods (eg: console.log.bind(console))
18994
+ // but not .call and .apply which would also return undefined.
18995
+ exp.expression = make_empty_function(self);
18996
+ set_flag(exp.expression, SQUEEZED);
18997
+ self.args = [];
18998
+ } else {
18999
+ return make_node(AST_Undefined, self);
19000
+ }
18884
19001
  }
18885
- }));
19002
+ });
19003
+
19004
+ return this.transform(tt);
18886
19005
  });
18887
19006
 
18888
19007
  AST_Node.DEFMETHOD("equivalent_to", function(node) {
@@ -19581,7 +19700,9 @@ def_optimize(AST_Switch, function(self, compressor) {
19581
19700
  eliminate_branch(branch, body[body.length - 1]);
19582
19701
  continue;
19583
19702
  }
19584
- if (exp instanceof AST_Node) exp = branch.expression.tail_node().evaluate(compressor);
19703
+ if (exp instanceof AST_Node && !exp.has_side_effects(compressor)) {
19704
+ exp = branch.expression.tail_node().evaluate(compressor);
19705
+ }
19585
19706
  if (exp === value) {
19586
19707
  exact_match = branch;
19587
19708
  if (default_branch) {
@@ -19763,12 +19884,9 @@ def_optimize(AST_Switch, function(self, compressor) {
19763
19884
  break DEFAULT;
19764
19885
  }
19765
19886
 
19766
- let sideEffect = body.find(branch => {
19767
- return (
19768
- branch !== default_or_exact
19769
- && branch.expression.has_side_effects(compressor)
19770
- );
19771
- });
19887
+ let sideEffect = body.find(
19888
+ branch => branch !== default_or_exact && branch.expression.has_side_effects(compressor)
19889
+ );
19772
19890
  // If no cases cause a side-effect, we can eliminate the switch entirely.
19773
19891
  if (!sideEffect) {
19774
19892
  return make_node(AST_BlockStatement, self, {
@@ -19876,9 +19994,10 @@ def_optimize(AST_Switch, function(self, compressor) {
19876
19994
  right: branch.expression,
19877
19995
  }),
19878
19996
  body: consequent,
19879
- alternative: null
19880
- })
19881
- ].concat(always)
19997
+ alternative: null,
19998
+ }),
19999
+ always,
20000
+ ],
19882
20001
  }).optimize(compressor);
19883
20002
  }
19884
20003
  return self;
@@ -19901,13 +20020,12 @@ def_optimize(AST_Switch, function(self, compressor) {
19901
20020
  let pblock = make_node(AST_BlockStatement, prev, { body: pbody });
19902
20021
  return bblock.equivalent_to(pblock);
19903
20022
  }
19904
- function statement(expression) {
19905
- return make_node(AST_SimpleStatement, expression, {
19906
- body: expression
19907
- });
20023
+ function statement(body) {
20024
+ return make_node(AST_SimpleStatement, body, { body });
19908
20025
  }
19909
20026
  function has_nested_break(root) {
19910
20027
  let has_break = false;
20028
+
19911
20029
  let tw = new TreeWalker(node => {
19912
20030
  if (has_break) return true;
19913
20031
  if (node instanceof AST_Lambda) return true;
@@ -20260,10 +20378,7 @@ def_optimize(AST_Call, function(self, compressor) {
20260
20378
  && is_undeclared_ref(exp)
20261
20379
  && exp.name == "Function") {
20262
20380
  // new Function() => function(){}
20263
- if (self.args.length == 0) return make_node(AST_Function, self, {
20264
- argnames: [],
20265
- body: []
20266
- }).optimize(compressor);
20381
+ if (self.args.length == 0) return make_empty_function(self).optimize(compressor);
20267
20382
  if (self.args.every((x) => x instanceof AST_String)) {
20268
20383
  // quite a corner-case, but we can handle it:
20269
20384
  // https://github.com/mishoo/UglifyJS2/issues/203
@@ -22023,10 +22138,7 @@ def_optimize(AST_Dot, function(self, compressor) {
22023
22138
  });
22024
22139
  break;
22025
22140
  case "Function":
22026
- self.expression = make_node(AST_Function, self.expression, {
22027
- argnames: [],
22028
- body: []
22029
- });
22141
+ self.expression = make_empty_function(self.expression);
22030
22142
  break;
22031
22143
  case "Number":
22032
22144
  self.expression = make_node(AST_Number, self.expression, {
@@ -30779,6 +30891,7 @@ var domprops = [
30779
30891
  "uint32",
30780
30892
  "uint8",
30781
30893
  "uint8Clamped",
30894
+ "unadjustedMovement",
30782
30895
  "unclippedDepth",
30783
30896
  "unconfigure",
30784
30897
  "undefined",
@@ -31570,7 +31683,9 @@ function mangle_properties(ast, options, annotated_props = find_annotated_props(
31570
31683
  } else if (node instanceof AST_ObjectProperty) {
31571
31684
  // setter, getter, method or class field
31572
31685
  if (!keep_quoted || !node.quote) {
31573
- node.key.name = mangle(node.key.name);
31686
+ if (!node.computed_key()) {
31687
+ node.key.name = mangle(node.key.name);
31688
+ }
31574
31689
  }
31575
31690
  } else if (node instanceof AST_Dot) {
31576
31691
  if (!keep_quoted || !node.quote) {
@@ -31947,7 +32062,7 @@ function* minify_sync_or_async(files, options, _fs_module) {
31947
32062
  if (node.block_scope) {
31948
32063
  node.block_scope.variables = undefined;
31949
32064
  node.block_scope.enclosed = undefined;
31950
- node.parent_scope = undefined;
32065
+ node.block_scope.parent_scope = undefined;
31951
32066
  }
31952
32067
  });
31953
32068
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: terser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Rosicky
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-11 00:00:00.000000000 Z
11
+ date: 2024-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: execjs
@@ -140,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
140
  - !ruby/object:Gem::Version
141
141
  version: '0'
142
142
  requirements: []
143
- rubygems_version: 3.6.0.dev
143
+ rubygems_version: 3.5.16
144
144
  signing_key:
145
145
  specification_version: 4
146
146
  summary: Ruby wrapper for Terser JavaScript compressor