terser 5.17.1 → 5.17.2

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.17.2
4
+ - Be less conservative when detecting use-before-definition of `var` in hoisted functions.
5
+ - Support unusual (but perfectly valid) initializers of for-in and for-of loops.
6
+ - Fix issue where hoisted function would be dropped if it was after a `continue` statement
7
+
3
8
  ## v5.17.1
4
9
  - Fix evaluating `.length` when the source array might've been mutated
5
10
 
@@ -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) {
@@ -15847,20 +15848,31 @@ function handle_defined_after_hoist(parent) {
15847
15848
  continue;
15848
15849
  }
15849
15850
 
15850
- // Detect `call_defun(); var used_in_defun = ...`
15851
- // Because `used_in_defun` can no longer be fixed
15852
- let found_defun = false;
15851
+ // Detect `call_defun(); var used_in_defun = X`
15852
+ // Because `used_in_defun` is not certainly X when it's defined after.
15853
+ let found_defun_ref = false;
15853
15854
  let found_def_after_defun = false;
15854
- walk(parent, node => {
15855
+ walk_parent(parent, (node, info) => {
15855
15856
  if (node === defun) return true;
15856
15857
 
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
- }
15858
+ // Step 1: find `call_defun()` or other refs to the defun
15859
+ if (
15860
+ !found_defun_ref
15861
+ && node.thedef === fname_def
15862
+ && node instanceof AST_Symbol
15863
+ ) {
15864
+ found_defun_ref = true;
15865
+ }
15866
+
15867
+ // Step 2: if Step 1 occurred, find a var the defun uses
15868
+ if (
15869
+ found_defun_ref
15870
+ && node.thedef === def
15871
+ && (node instanceof AST_SymbolDeclaration
15872
+ || is_lhs(node, info))
15873
+ ) {
15874
+ found_def_after_defun = true;
15875
+ return walk_abort;
15864
15876
  }
15865
15877
  });
15866
15878
 
@@ -16972,27 +16984,34 @@ function tighten_body(statements, compressor) {
16972
16984
  }
16973
16985
 
16974
16986
  if (stat instanceof AST_If) {
16975
- var ab = aborts(stat.body);
16976
- if (can_merge_flow(ab)) {
16987
+ let ab, new_else;
16988
+
16989
+ ab = aborts(stat.body);
16990
+ if (
16991
+ can_merge_flow(ab)
16992
+ && (new_else = as_statement_array_with_return(stat.body, ab))
16993
+ ) {
16977
16994
  if (ab.label) {
16978
16995
  remove(ab.label.thedef.references, ab);
16979
16996
  }
16980
16997
  CHANGED = true;
16981
16998
  stat = stat.clone();
16982
16999
  stat.condition = stat.condition.negate(compressor);
16983
- var body = as_statement_array_with_return(stat.body, ab);
16984
17000
  stat.body = make_node(AST_BlockStatement, stat, {
16985
17001
  body: as_statement_array(stat.alternative).concat(extract_functions())
16986
17002
  });
16987
17003
  stat.alternative = make_node(AST_BlockStatement, stat, {
16988
- body: body
17004
+ body: new_else
16989
17005
  });
16990
17006
  statements[i] = stat.transform(compressor);
16991
17007
  continue;
16992
17008
  }
16993
17009
 
16994
- var ab = aborts(stat.alternative);
16995
- if (can_merge_flow(ab)) {
17010
+ ab = aborts(stat.alternative);
17011
+ if (
17012
+ can_merge_flow(ab)
17013
+ && (new_else = as_statement_array_with_return(stat.alternative, ab))
17014
+ ) {
16996
17015
  if (ab.label) {
16997
17016
  remove(ab.label.thedef.references, ab);
16998
17017
  }
@@ -17001,9 +17020,8 @@ function tighten_body(statements, compressor) {
17001
17020
  stat.body = make_node(AST_BlockStatement, stat.body, {
17002
17021
  body: as_statement_array(stat.body).concat(extract_functions())
17003
17022
  });
17004
- var body = as_statement_array_with_return(stat.alternative, ab);
17005
17023
  stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
17006
- body: body
17024
+ body: new_else
17007
17025
  });
17008
17026
  statements[i] = stat.transform(compressor);
17009
17027
  continue;
@@ -17118,7 +17136,11 @@ function tighten_body(statements, compressor) {
17118
17136
  }
17119
17137
 
17120
17138
  function as_statement_array_with_return(node, ab) {
17121
- var body = as_statement_array(node).slice(0, -1);
17139
+ var body = as_statement_array(node);
17140
+ if (ab !== body[body.length - 1]) {
17141
+ return undefined;
17142
+ }
17143
+ body = body.slice(0, -1);
17122
17144
  if (ab.value) {
17123
17145
  body.push(make_node(AST_SimpleStatement, ab.value, {
17124
17146
  body: ab.value.expression
@@ -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,
@@ -712,6 +713,7 @@ export function is_nullish(node, compressor) {
712
713
  export function is_lhs(node, parent) {
713
714
  if (parent instanceof AST_Unary && unary_side_effects.has(parent.operator)) return parent.expression;
714
715
  if (parent instanceof AST_Assign && parent.left === node) return node;
716
+ if (parent instanceof AST_ForIn && parent.init === node) return node;
715
717
  }
716
718
 
717
719
  (function(def_find_defs) {
@@ -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.2",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },