terser 1.2.3 → 1.2.4

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.
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