terser 5.17.1 → 5.17.3

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,14 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.17.3
4
+
5
+ - Fix issue with trimming a static class property's contents accessing the class as `this`.
6
+
7
+ ## v5.17.2
8
+ - Be less conservative when detecting use-before-definition of `var` in hoisted functions.
9
+ - Support unusual (but perfectly valid) initializers of for-in and for-of loops.
10
+ - Fix issue where hoisted function would be dropped if it was after a `continue` statement
11
+
3
12
  ## v5.17.1
4
13
  - Fix evaluating `.length` when the source array might've been mutated
5
14
 
@@ -13918,6 +13918,7 @@ function is_nullish(node, compressor) {
13918
13918
  function is_lhs(node, parent) {
13919
13919
  if (parent instanceof AST_Unary && unary_side_effects.has(parent.operator)) return parent.expression;
13920
13920
  if (parent instanceof AST_Assign && parent.left === node) return node;
13921
+ if (parent instanceof AST_ForIn && parent.init === node) return node;
13921
13922
  }
13922
13923
 
13923
13924
  (function(def_find_defs) {
@@ -14154,6 +14155,19 @@ const aborts = (thing) => thing && thing.aborts();
14154
14155
  node.DEFMETHOD("aborts", func);
14155
14156
  });
14156
14157
 
14158
+ AST_Node.DEFMETHOD("contains_this", function() {
14159
+ return walk(this, node => {
14160
+ if (node instanceof AST_This) return walk_abort;
14161
+ if (
14162
+ node !== this
14163
+ && node instanceof AST_Scope
14164
+ && !(node instanceof AST_Arrow)
14165
+ ) {
14166
+ return true;
14167
+ }
14168
+ });
14169
+ });
14170
+
14157
14171
  function is_modified(compressor, tw, node, value, level, immutable) {
14158
14172
  var parent = tw.parent(level);
14159
14173
  var lhs = is_lhs(node, parent);
@@ -14759,6 +14773,15 @@ def_drop_side_effect_free(AST_Class, function (compressor) {
14759
14773
  }
14760
14774
  }
14761
14775
 
14776
+ if (
14777
+ prop instanceof AST_ClassProperty
14778
+ && prop.static
14779
+ && prop.value.has_side_effects(compressor)
14780
+ && prop.contains_this()
14781
+ ) {
14782
+ return this;
14783
+ }
14784
+
14762
14785
  const trimmed_prop = prop.drop_side_effect_free(compressor);
14763
14786
  if (trimmed_prop)
14764
14787
  with_effects.push(trimmed_prop);
@@ -15847,20 +15870,31 @@ function handle_defined_after_hoist(parent) {
15847
15870
  continue;
15848
15871
  }
15849
15872
 
15850
- // Detect `call_defun(); var used_in_defun = ...`
15851
- // Because `used_in_defun` can no longer be fixed
15852
- let found_defun = false;
15873
+ // Detect `call_defun(); var used_in_defun = X`
15874
+ // Because `used_in_defun` is not certainly X when it's defined after.
15875
+ let found_defun_ref = false;
15853
15876
  let found_def_after_defun = false;
15854
- walk(parent, node => {
15877
+ walk_parent(parent, (node, info) => {
15855
15878
  if (node === defun) return true;
15856
15879
 
15857
- if (node instanceof AST_Symbol) {
15858
- if (!found_defun && node.thedef === fname_def) {
15859
- found_defun = true;
15860
- } else if (found_defun && node.thedef === def) {
15861
- found_def_after_defun = true;
15862
- return walk_abort;
15863
- }
15880
+ // Step 1: find `call_defun()` or other refs to the defun
15881
+ if (
15882
+ !found_defun_ref
15883
+ && node.thedef === fname_def
15884
+ && node instanceof AST_Symbol
15885
+ ) {
15886
+ found_defun_ref = true;
15887
+ }
15888
+
15889
+ // Step 2: if Step 1 occurred, find a var the defun uses
15890
+ if (
15891
+ found_defun_ref
15892
+ && node.thedef === def
15893
+ && (node instanceof AST_SymbolDeclaration
15894
+ || is_lhs(node, info))
15895
+ ) {
15896
+ found_def_after_defun = true;
15897
+ return walk_abort;
15864
15898
  }
15865
15899
  });
15866
15900
 
@@ -16972,27 +17006,34 @@ function tighten_body(statements, compressor) {
16972
17006
  }
16973
17007
 
16974
17008
  if (stat instanceof AST_If) {
16975
- var ab = aborts(stat.body);
16976
- if (can_merge_flow(ab)) {
17009
+ let ab, new_else;
17010
+
17011
+ ab = aborts(stat.body);
17012
+ if (
17013
+ can_merge_flow(ab)
17014
+ && (new_else = as_statement_array_with_return(stat.body, ab))
17015
+ ) {
16977
17016
  if (ab.label) {
16978
17017
  remove(ab.label.thedef.references, ab);
16979
17018
  }
16980
17019
  CHANGED = true;
16981
17020
  stat = stat.clone();
16982
17021
  stat.condition = stat.condition.negate(compressor);
16983
- var body = as_statement_array_with_return(stat.body, ab);
16984
17022
  stat.body = make_node(AST_BlockStatement, stat, {
16985
17023
  body: as_statement_array(stat.alternative).concat(extract_functions())
16986
17024
  });
16987
17025
  stat.alternative = make_node(AST_BlockStatement, stat, {
16988
- body: body
17026
+ body: new_else
16989
17027
  });
16990
17028
  statements[i] = stat.transform(compressor);
16991
17029
  continue;
16992
17030
  }
16993
17031
 
16994
- var ab = aborts(stat.alternative);
16995
- if (can_merge_flow(ab)) {
17032
+ ab = aborts(stat.alternative);
17033
+ if (
17034
+ can_merge_flow(ab)
17035
+ && (new_else = as_statement_array_with_return(stat.alternative, ab))
17036
+ ) {
16996
17037
  if (ab.label) {
16997
17038
  remove(ab.label.thedef.references, ab);
16998
17039
  }
@@ -17001,9 +17042,8 @@ function tighten_body(statements, compressor) {
17001
17042
  stat.body = make_node(AST_BlockStatement, stat.body, {
17002
17043
  body: as_statement_array(stat.body).concat(extract_functions())
17003
17044
  });
17004
- var body = as_statement_array_with_return(stat.alternative, ab);
17005
17045
  stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
17006
- body: body
17046
+ body: new_else
17007
17047
  });
17008
17048
  statements[i] = stat.transform(compressor);
17009
17049
  continue;
@@ -17118,7 +17158,11 @@ function tighten_body(statements, compressor) {
17118
17158
  }
17119
17159
 
17120
17160
  function as_statement_array_with_return(node, ab) {
17121
- var body = as_statement_array(node).slice(0, -1);
17161
+ var body = as_statement_array(node);
17162
+ if (ab !== body[body.length - 1]) {
17163
+ return undefined;
17164
+ }
17165
+ body = body.slice(0, -1);
17122
17166
  if (ab.value) {
17123
17167
  body.push(make_node(AST_SimpleStatement, ab.value, {
17124
17168
  body: ab.value.expression
@@ -21207,19 +21251,6 @@ def_optimize(AST_Chain, function (self, compressor) {
21207
21251
  return self;
21208
21252
  });
21209
21253
 
21210
- AST_Lambda.DEFMETHOD("contains_this", function() {
21211
- return walk(this, node => {
21212
- if (node instanceof AST_This) return walk_abort;
21213
- if (
21214
- node !== this
21215
- && node instanceof AST_Scope
21216
- && !(node instanceof AST_Arrow)
21217
- ) {
21218
- return true;
21219
- }
21220
- });
21221
- });
21222
-
21223
21254
  def_optimize(AST_Dot, function(self, compressor) {
21224
21255
  const parent = compressor.parent();
21225
21256
  if (is_lhs(self, parent)) return self;
@@ -165,6 +165,15 @@ def_drop_side_effect_free(AST_Class, function (compressor) {
165
165
  }
166
166
  }
167
167
 
168
+ if (
169
+ prop instanceof AST_ClassProperty
170
+ && prop.static
171
+ && prop.value.has_side_effects(compressor)
172
+ && prop.contains_this()
173
+ ) {
174
+ return this;
175
+ }
176
+
168
177
  const trimmed_prop = prop.drop_side_effect_free(compressor);
169
178
  if (trimmed_prop)
170
179
  with_effects.push(trimmed_prop);
@@ -3358,19 +3358,6 @@ def_optimize(AST_Chain, function (self, compressor) {
3358
3358
  return self;
3359
3359
  });
3360
3360
 
3361
- AST_Lambda.DEFMETHOD("contains_this", function() {
3362
- return walk(this, node => {
3363
- if (node instanceof AST_This) return walk_abort;
3364
- if (
3365
- node !== this
3366
- && node instanceof AST_Scope
3367
- && !(node instanceof AST_Arrow)
3368
- ) {
3369
- return true;
3370
- }
3371
- });
3372
- });
3373
-
3374
3361
  def_optimize(AST_Dot, function(self, compressor) {
3375
3362
  const parent = compressor.parent();
3376
3363
  if (is_lhs(self, parent)) return self;
@@ -64,6 +64,7 @@ import {
64
64
  AST_EmptyStatement,
65
65
  AST_Expansion,
66
66
  AST_False,
67
+ AST_ForIn,
67
68
  AST_Function,
68
69
  AST_If,
69
70
  AST_Import,
@@ -83,6 +84,7 @@ import {
83
84
  AST_PropAccess,
84
85
  AST_RegExp,
85
86
  AST_Return,
87
+ AST_Scope,
86
88
  AST_Sequence,
87
89
  AST_SimpleStatement,
88
90
  AST_Statement,
@@ -712,6 +714,7 @@ export function is_nullish(node, compressor) {
712
714
  export function is_lhs(node, parent) {
713
715
  if (parent instanceof AST_Unary && unary_side_effects.has(parent.operator)) return parent.expression;
714
716
  if (parent instanceof AST_Assign && parent.left === node) return node;
717
+ if (parent instanceof AST_ForIn && parent.init === node) return node;
715
718
  }
716
719
 
717
720
  (function(def_find_defs) {
@@ -948,6 +951,19 @@ export const aborts = (thing) => thing && thing.aborts();
948
951
  node.DEFMETHOD("aborts", func);
949
952
  });
950
953
 
954
+ AST_Node.DEFMETHOD("contains_this", function() {
955
+ return walk(this, node => {
956
+ if (node instanceof AST_This) return walk_abort;
957
+ if (
958
+ node !== this
959
+ && node instanceof AST_Scope
960
+ && !(node instanceof AST_Arrow)
961
+ ) {
962
+ return true;
963
+ }
964
+ });
965
+ });
966
+
951
967
  export function is_modified(compressor, tw, node, value, level, immutable) {
952
968
  var parent = tw.parent(level);
953
969
  var lhs = is_lhs(node, parent);
@@ -77,6 +77,7 @@ import {
77
77
  AST_Symbol,
78
78
  AST_SymbolCatch,
79
79
  AST_SymbolConst,
80
+ AST_SymbolDeclaration,
80
81
  AST_SymbolDefun,
81
82
  AST_SymbolFunarg,
82
83
  AST_SymbolLambda,
@@ -92,6 +93,7 @@ import {
92
93
  AST_Yield,
93
94
 
94
95
  walk,
96
+ walk_parent,
95
97
  walk_abort,
96
98
  walk_body,
97
99
 
@@ -101,7 +103,7 @@ import {
101
103
  } from "../ast.js";
102
104
  import { HOP, make_node, noop } from "../utils/index.js";
103
105
 
104
- import { lazy_op, is_modified } from "./inference.js";
106
+ import { lazy_op, is_modified, is_lhs } from "./inference.js";
105
107
  import { INLINED, clear_flag } from "./compressor-flags.js";
106
108
  import { read_property, has_break_or_continue, is_recursive_ref } from "./common.js";
107
109
 
@@ -540,20 +542,31 @@ function handle_defined_after_hoist(parent) {
540
542
  continue;
541
543
  }
542
544
 
543
- // Detect `call_defun(); var used_in_defun = ...`
544
- // Because `used_in_defun` can no longer be fixed
545
- let found_defun = false;
545
+ // Detect `call_defun(); var used_in_defun = X`
546
+ // Because `used_in_defun` is not certainly X when it's defined after.
547
+ let found_defun_ref = false;
546
548
  let found_def_after_defun = false;
547
- walk(parent, node => {
549
+ walk_parent(parent, (node, info) => {
548
550
  if (node === defun) return true;
549
551
 
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
- }
552
+ // Step 1: find `call_defun()` or other refs to the defun
553
+ if (
554
+ !found_defun_ref
555
+ && node.thedef === fname_def
556
+ && node instanceof AST_Symbol
557
+ ) {
558
+ found_defun_ref = true;
559
+ }
560
+
561
+ // Step 2: if Step 1 occurred, find a var the defun uses
562
+ if (
563
+ found_defun_ref
564
+ && node.thedef === def
565
+ && (node instanceof AST_SymbolDeclaration
566
+ || is_lhs(node, info))
567
+ ) {
568
+ found_def_after_defun = true;
569
+ return walk_abort;
557
570
  }
558
571
  });
559
572
 
@@ -1002,27 +1002,34 @@ export function tighten_body(statements, compressor) {
1002
1002
  }
1003
1003
 
1004
1004
  if (stat instanceof AST_If) {
1005
- var ab = aborts(stat.body);
1006
- if (can_merge_flow(ab)) {
1005
+ let ab, new_else;
1006
+
1007
+ ab = aborts(stat.body);
1008
+ if (
1009
+ can_merge_flow(ab)
1010
+ && (new_else = as_statement_array_with_return(stat.body, ab))
1011
+ ) {
1007
1012
  if (ab.label) {
1008
1013
  remove(ab.label.thedef.references, ab);
1009
1014
  }
1010
1015
  CHANGED = true;
1011
1016
  stat = stat.clone();
1012
1017
  stat.condition = stat.condition.negate(compressor);
1013
- var body = as_statement_array_with_return(stat.body, ab);
1014
1018
  stat.body = make_node(AST_BlockStatement, stat, {
1015
1019
  body: as_statement_array(stat.alternative).concat(extract_functions())
1016
1020
  });
1017
1021
  stat.alternative = make_node(AST_BlockStatement, stat, {
1018
- body: body
1022
+ body: new_else
1019
1023
  });
1020
1024
  statements[i] = stat.transform(compressor);
1021
1025
  continue;
1022
1026
  }
1023
1027
 
1024
- var ab = aborts(stat.alternative);
1025
- if (can_merge_flow(ab)) {
1028
+ ab = aborts(stat.alternative);
1029
+ if (
1030
+ can_merge_flow(ab)
1031
+ && (new_else = as_statement_array_with_return(stat.alternative, ab))
1032
+ ) {
1026
1033
  if (ab.label) {
1027
1034
  remove(ab.label.thedef.references, ab);
1028
1035
  }
@@ -1031,9 +1038,8 @@ export function tighten_body(statements, compressor) {
1031
1038
  stat.body = make_node(AST_BlockStatement, stat.body, {
1032
1039
  body: as_statement_array(stat.body).concat(extract_functions())
1033
1040
  });
1034
- var body = as_statement_array_with_return(stat.alternative, ab);
1035
1041
  stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
1036
- body: body
1042
+ body: new_else
1037
1043
  });
1038
1044
  statements[i] = stat.transform(compressor);
1039
1045
  continue;
@@ -1148,7 +1154,11 @@ export function tighten_body(statements, compressor) {
1148
1154
  }
1149
1155
 
1150
1156
  function as_statement_array_with_return(node, ab) {
1151
- var body = as_statement_array(node).slice(0, -1);
1157
+ var body = as_statement_array(node);
1158
+ if (ab !== body[body.length - 1]) {
1159
+ return undefined;
1160
+ }
1161
+ body = body.slice(0, -1);
1152
1162
  if (ab.value) {
1153
1163
  body.push(make_node(AST_SimpleStatement, ab.value, {
1154
1164
  body: ab.value.expression
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.17.1",
7
+ "version": "5.17.3",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },