terser 5.16.6 → 5.16.8

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,10 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.16.8
4
+
5
+ - Become even less conservative around function definitions for `reduce_vars`
6
+ - Fix parsing context of `import.meta` expressions such that method calls are allowed
7
+
3
8
  ## v5.16.7
4
9
 
5
10
  - Become less conservative with analyzing function definitions for `reduce_vars`
package/bin/terser.mjs ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+
3
+ "use strict";
4
+
5
+ import "../tools/exit.cjs";
6
+
7
+ import fs from "fs";
8
+ import path from "path";
9
+ import program from "commander";
10
+
11
+ import { run_cli } from "../lib/cli.js";
12
+
13
+ const packageJson = {
14
+ name: "terser",
15
+ version: "experimental module CLI"
16
+ };
17
+
18
+ run_cli({ program, packageJson, fs, path }).catch((error) => {
19
+ console.error(error);
20
+ process.exitCode = 1;
21
+ });
@@ -2451,7 +2451,7 @@ function parse($TEXT, options) {
2451
2451
  return new_(allow_calls);
2452
2452
  }
2453
2453
  if (is("name", "import") && is_token(peek(), "punc", ".")) {
2454
- return import_meta();
2454
+ return import_meta(allow_calls);
2455
2455
  }
2456
2456
  var start = S.token;
2457
2457
  var peeked;
@@ -2944,7 +2944,7 @@ function parse($TEXT, options) {
2944
2944
  });
2945
2945
  }
2946
2946
 
2947
- function import_meta() {
2947
+ function import_meta(allow_calls) {
2948
2948
  var start = S.token;
2949
2949
  expect_token("name", "import");
2950
2950
  expect_token("punc", ".");
@@ -2952,7 +2952,7 @@ function parse($TEXT, options) {
2952
2952
  return subscripts(new AST_ImportMeta({
2953
2953
  start: start,
2954
2954
  end: prev()
2955
- }), false);
2955
+ }), allow_calls);
2956
2956
  }
2957
2957
 
2958
2958
  function map_name(is_import) {
@@ -3850,21 +3850,8 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", function AST_Simple
3850
3850
 
3851
3851
  function walk_body(node, visitor) {
3852
3852
  const body = node.body;
3853
- if (visitor.walk_defun_first) {
3854
- for (var i = 0, len = body.length; i < len; i++) {
3855
- if (body[i] instanceof AST_Defun) {
3856
- body[i]._walk(visitor);
3857
- }
3858
- }
3859
- for (var i = 0, len = body.length; i < len; i++) {
3860
- if (!(body[i] instanceof AST_Defun)) {
3861
- body[i]._walk(visitor);
3862
- }
3863
- }
3864
- } else {
3865
- for (var i = 0, len = body.length; i < len; i++) {
3866
- body[i]._walk(visitor);
3867
- }
3853
+ for (var i = 0, len = body.length; i < len; i++) {
3854
+ body[i]._walk(visitor);
3868
3855
  }
3869
3856
  }
3870
3857
 
@@ -6643,11 +6630,10 @@ const walk_abort = Symbol("abort walk");
6643
6630
  /* -----[ TreeWalker ]----- */
6644
6631
 
6645
6632
  class TreeWalker {
6646
- constructor(callback, { walk_defun_first = false } = {}) {
6633
+ constructor(callback) {
6647
6634
  this.visit = callback;
6648
6635
  this.stack = [];
6649
6636
  this.directives = Object.create(null);
6650
- this.walk_defun_first = walk_defun_first;
6651
6637
  }
6652
6638
 
6653
6639
  _visit(node, descend) {
@@ -15723,9 +15709,7 @@ def_reduce_vars(AST_Default, function(tw, descend) {
15723
15709
 
15724
15710
  function mark_lambda(tw, descend, compressor) {
15725
15711
  clear_flag(this, INLINED);
15726
-
15727
15712
  push(tw);
15728
-
15729
15713
  reset_variables(tw, compressor, this);
15730
15714
 
15731
15715
  var iife;
@@ -15760,9 +15744,86 @@ function mark_lambda(tw, descend, compressor) {
15760
15744
  descend();
15761
15745
  pop(tw);
15762
15746
 
15747
+ handle_defined_after_hoist(this);
15748
+
15763
15749
  return true;
15764
15750
  }
15765
15751
 
15752
+ /**
15753
+ * It's possible for a hoisted function to use something that's not defined yet. Example:
15754
+ *
15755
+ * hoisted();
15756
+ * var defined_after = true;
15757
+ * function hoisted() {
15758
+ * // use defined_after
15759
+ * }
15760
+ *
15761
+ * This function is called on the parent to handle this issue.
15762
+ */
15763
+ function handle_defined_after_hoist(parent) {
15764
+ const defuns = [];
15765
+ walk(parent, node => {
15766
+ if (node === parent) return;
15767
+ if (node instanceof AST_Defun) defuns.push(node);
15768
+ if (
15769
+ node instanceof AST_Scope
15770
+ || node instanceof AST_SimpleStatement
15771
+ ) return true;
15772
+ });
15773
+
15774
+ for (const defun of defuns) {
15775
+ const fname_def = defun.name.definition();
15776
+ const found_self_ref_in_other_defuns = defuns.some(
15777
+ d => d !== defun && d.enclosed.indexOf(fname_def) !== -1
15778
+ );
15779
+
15780
+ for (const def of defun.enclosed) {
15781
+ if (
15782
+ def.fixed === false
15783
+ || def === fname_def
15784
+ || def.scope.get_defun_scope() !== parent
15785
+ ) {
15786
+ continue;
15787
+ }
15788
+
15789
+ // defun is hoisted, so always safe
15790
+ if (
15791
+ def.assignments === 0
15792
+ && def.orig.length === 1
15793
+ && def.orig[0] instanceof AST_SymbolDefun
15794
+ ) {
15795
+ continue;
15796
+ }
15797
+
15798
+ if (found_self_ref_in_other_defuns) {
15799
+ def.fixed = false;
15800
+ continue;
15801
+ }
15802
+
15803
+ // Detect `call_defun(); var used_in_defun = ...`
15804
+ // Because `used_in_defun` can no longer be fixed
15805
+ let found_defun = false;
15806
+ let found_def_after_defun = false;
15807
+ walk(parent, node => {
15808
+ if (node === defun) return true;
15809
+
15810
+ if (node instanceof AST_Symbol) {
15811
+ if (!found_defun && node.thedef === fname_def) {
15812
+ found_defun = true;
15813
+ } else if (found_defun && node.thedef === def) {
15814
+ found_def_after_defun = true;
15815
+ return walk_abort;
15816
+ }
15817
+ }
15818
+ });
15819
+
15820
+ if (found_def_after_defun) {
15821
+ def.fixed = false;
15822
+ }
15823
+ }
15824
+ }
15825
+ }
15826
+
15766
15827
  def_reduce_vars(AST_Lambda, mark_lambda);
15767
15828
 
15768
15829
  def_reduce_vars(AST_Do, function(tw, descend, compressor) {
@@ -15883,6 +15944,9 @@ def_reduce_vars(AST_Toplevel, function(tw, descend, compressor) {
15883
15944
  reset_def(compressor, def);
15884
15945
  });
15885
15946
  reset_variables(tw, compressor, this);
15947
+ descend();
15948
+ handle_defined_after_hoist(this);
15949
+ return true;
15886
15950
  });
15887
15951
 
15888
15952
  def_reduce_vars(AST_Try, function(tw, descend, compressor) {
@@ -18258,7 +18322,7 @@ AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
18258
18322
  }
18259
18323
  return node.reduce_vars(preparation, descend, compressor);
18260
18324
  }
18261
- }, { walk_defun_first: true });
18325
+ });
18262
18326
  // Stack of look-up tables to keep track of whether a `SymbolDef` has been
18263
18327
  // properly assigned before use:
18264
18328
  // - `push()` & `pop()` when visiting conditional branches
package/lib/ast.js CHANGED
@@ -249,21 +249,8 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", function AST_Simple
249
249
 
250
250
  function walk_body(node, visitor) {
251
251
  const body = node.body;
252
- if (visitor.walk_defun_first) {
253
- for (var i = 0, len = body.length; i < len; i++) {
254
- if (body[i] instanceof AST_Defun) {
255
- body[i]._walk(visitor);
256
- }
257
- }
258
- for (var i = 0, len = body.length; i < len; i++) {
259
- if (!(body[i] instanceof AST_Defun)) {
260
- body[i]._walk(visitor);
261
- }
262
- }
263
- } else {
264
- for (var i = 0, len = body.length; i < len; i++) {
265
- body[i]._walk(visitor);
266
- }
252
+ for (var i = 0, len = body.length; i < len; i++) {
253
+ body[i]._walk(visitor);
267
254
  }
268
255
  }
269
256
 
@@ -3042,11 +3029,10 @@ const walk_abort = Symbol("abort walk");
3042
3029
  /* -----[ TreeWalker ]----- */
3043
3030
 
3044
3031
  class TreeWalker {
3045
- constructor(callback, { walk_defun_first = false } = {}) {
3032
+ constructor(callback) {
3046
3033
  this.visit = callback;
3047
3034
  this.stack = [];
3048
3035
  this.directives = Object.create(null);
3049
- this.walk_defun_first = walk_defun_first;
3050
3036
  }
3051
3037
 
3052
3038
  _visit(node, descend) {
@@ -539,7 +539,7 @@ AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
539
539
  }
540
540
  return node.reduce_vars(preparation, descend, compressor);
541
541
  }
542
- }, { walk_defun_first: true });
542
+ });
543
543
  // Stack of look-up tables to keep track of whether a `SymbolDef` has been
544
544
  // properly assigned before use:
545
545
  // - `push()` & `pop()` when visiting conditional branches
@@ -71,6 +71,7 @@ import {
71
71
  AST_Number,
72
72
  AST_ObjectKeyVal,
73
73
  AST_PropAccess,
74
+ AST_Scope,
74
75
  AST_Sequence,
75
76
  AST_SimpleStatement,
76
77
  AST_Symbol,
@@ -91,6 +92,7 @@ import {
91
92
  AST_Yield,
92
93
 
93
94
  walk,
95
+ walk_abort,
94
96
  walk_body,
95
97
 
96
98
  _INLINE,
@@ -447,9 +449,7 @@ def_reduce_vars(AST_Default, function(tw, descend) {
447
449
 
448
450
  function mark_lambda(tw, descend, compressor) {
449
451
  clear_flag(this, INLINED);
450
-
451
452
  push(tw);
452
-
453
453
  reset_variables(tw, compressor, this);
454
454
 
455
455
  var iife;
@@ -484,9 +484,86 @@ function mark_lambda(tw, descend, compressor) {
484
484
  descend();
485
485
  pop(tw);
486
486
 
487
+ handle_defined_after_hoist(this);
488
+
487
489
  return true;
488
490
  }
489
491
 
492
+ /**
493
+ * It's possible for a hoisted function to use something that's not defined yet. Example:
494
+ *
495
+ * hoisted();
496
+ * var defined_after = true;
497
+ * function hoisted() {
498
+ * // use defined_after
499
+ * }
500
+ *
501
+ * This function is called on the parent to handle this issue.
502
+ */
503
+ function handle_defined_after_hoist(parent) {
504
+ const defuns = [];
505
+ walk(parent, node => {
506
+ if (node === parent) return;
507
+ if (node instanceof AST_Defun) defuns.push(node);
508
+ if (
509
+ node instanceof AST_Scope
510
+ || node instanceof AST_SimpleStatement
511
+ ) return true;
512
+ });
513
+
514
+ for (const defun of defuns) {
515
+ const fname_def = defun.name.definition();
516
+ const found_self_ref_in_other_defuns = defuns.some(
517
+ d => d !== defun && d.enclosed.indexOf(fname_def) !== -1
518
+ );
519
+
520
+ for (const def of defun.enclosed) {
521
+ if (
522
+ def.fixed === false
523
+ || def === fname_def
524
+ || def.scope.get_defun_scope() !== parent
525
+ ) {
526
+ continue;
527
+ }
528
+
529
+ // defun is hoisted, so always safe
530
+ if (
531
+ def.assignments === 0
532
+ && def.orig.length === 1
533
+ && def.orig[0] instanceof AST_SymbolDefun
534
+ ) {
535
+ continue;
536
+ }
537
+
538
+ if (found_self_ref_in_other_defuns) {
539
+ def.fixed = false;
540
+ continue;
541
+ }
542
+
543
+ // Detect `call_defun(); var used_in_defun = ...`
544
+ // Because `used_in_defun` can no longer be fixed
545
+ let found_defun = false;
546
+ let found_def_after_defun = false;
547
+ walk(parent, node => {
548
+ if (node === defun) return true;
549
+
550
+ if (node instanceof AST_Symbol) {
551
+ if (!found_defun && node.thedef === fname_def) {
552
+ found_defun = true;
553
+ } else if (found_defun && node.thedef === def) {
554
+ found_def_after_defun = true;
555
+ return walk_abort;
556
+ }
557
+ }
558
+ });
559
+
560
+ if (found_def_after_defun) {
561
+ def.fixed = false;
562
+ }
563
+ }
564
+ }
565
+ }
566
+
490
567
  def_reduce_vars(AST_Lambda, mark_lambda);
491
568
 
492
569
  def_reduce_vars(AST_Do, function(tw, descend, compressor) {
@@ -607,6 +684,9 @@ def_reduce_vars(AST_Toplevel, function(tw, descend, compressor) {
607
684
  reset_def(compressor, def);
608
685
  });
609
686
  reset_variables(tw, compressor, this);
687
+ descend();
688
+ handle_defined_after_hoist(this);
689
+ return true;
610
690
  });
611
691
 
612
692
  def_reduce_vars(AST_Try, function(tw, descend, compressor) {
package/lib/parse.js CHANGED
@@ -2308,7 +2308,7 @@ function parse($TEXT, options) {
2308
2308
  return new_(allow_calls);
2309
2309
  }
2310
2310
  if (is("name", "import") && is_token(peek(), "punc", ".")) {
2311
- return import_meta();
2311
+ return import_meta(allow_calls);
2312
2312
  }
2313
2313
  var start = S.token;
2314
2314
  var peeked;
@@ -2801,7 +2801,7 @@ function parse($TEXT, options) {
2801
2801
  });
2802
2802
  }
2803
2803
 
2804
- function import_meta() {
2804
+ function import_meta(allow_calls) {
2805
2805
  var start = S.token;
2806
2806
  expect_token("name", "import");
2807
2807
  expect_token("punc", ".");
@@ -2809,7 +2809,7 @@ function parse($TEXT, options) {
2809
2809
  return subscripts(new AST_ImportMeta({
2810
2810
  start: start,
2811
2811
  end: prev()
2812
- }), false);
2812
+ }), allow_calls);
2813
2813
  }
2814
2814
 
2815
2815
  function map_name(is_import) {
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.16.6",
7
+ "version": "5.16.8",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },