terser 5.7.0 → 5.7.1

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.7.1
4
+
5
+ - Avoided collapsing assignments together if it would place a chain assignment on the left hand side, which is invalid syntax (`a?.b = c`)
6
+ - Removed undefined from object expansions (`{ ...void 0 }` -> `{}`)
7
+ - Fix crash when checking if something is nullish or undefined (#1009)
8
+ - Fixed comparison of private class properties (#1015)
9
+ - Minor performance improvements (#993)
10
+ - Fixed scope of function defs in strict mode (they are block scoped)
11
+
3
12
  ## v5.7.0
4
13
 
5
14
  - Several compile-time evaluation and inlining fixes
@@ -72,10 +72,8 @@ class DefaultsError extends Error {
72
72
  function defaults(args, defs, croak) {
73
73
  if (args === true) {
74
74
  args = {};
75
- }
76
-
77
- if (args != null && typeof args === "object") {
78
- args = Object.assign({}, args);
75
+ } else if (args != null && typeof args === "object") {
76
+ args = {...args};
79
77
  }
80
78
 
81
79
  const ret = args || {};
@@ -3701,8 +3699,6 @@ function walk_body(node, visitor) {
3701
3699
  function clone_block_scope(deep) {
3702
3700
  var clone = this._clone(deep);
3703
3701
  if (this.block_scope) {
3704
- // TODO this is sometimes undefined during compression.
3705
- // But it should always have a value!
3706
3702
  clone.block_scope = this.block_scope.clone();
3707
3703
  }
3708
3704
  return clone;
@@ -3886,7 +3882,6 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
3886
3882
  $documentation: "Base class for all statements introducing a lexical scope",
3887
3883
  $propdoc: {
3888
3884
  variables: "[Map/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
3889
- functions: "[Map/S] like `variables`, but only lists function declarations",
3890
3885
  uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
3891
3886
  uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
3892
3887
  parent_scope: "[AST_Scope?/S] link to the parent scope",
@@ -3909,7 +3904,6 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
3909
3904
  });
3910
3905
  } else {
3911
3906
  if (this.variables) node.variables = new Map(this.variables);
3912
- if (this.functions) node.functions = new Map(this.functions);
3913
3907
  if (this.enclosed) node.enclosed = this.enclosed.slice();
3914
3908
  if (this._block_scope) node._block_scope = this._block_scope;
3915
3909
  }
@@ -7097,11 +7091,15 @@ function OutputStream(options) {
7097
7091
  var do_add_mapping = mappings ? function() {
7098
7092
  mappings.forEach(function(mapping) {
7099
7093
  try {
7094
+ let name = !mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name;
7095
+ if (name instanceof AST_Symbol) {
7096
+ name = name.name;
7097
+ }
7100
7098
  options.source_map.add(
7101
7099
  mapping.token.file,
7102
7100
  mapping.line, mapping.col,
7103
7101
  mapping.token.line, mapping.token.col,
7104
- !mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name
7102
+ is_basic_identifier_string(name) ? name : undefined
7105
7103
  );
7106
7104
  } catch(ex) {
7107
7105
  // Ignore bad mapping
@@ -9196,6 +9194,10 @@ AST_Dot.prototype.shallow_cmp = mkshallow({
9196
9194
  property: "eq"
9197
9195
  });
9198
9196
 
9197
+ AST_DotHash.prototype.shallow_cmp = mkshallow({
9198
+ property: "eq"
9199
+ });
9200
+
9199
9201
  AST_Unary.prototype.shallow_cmp = mkshallow({
9200
9202
  operator: "eq"
9201
9203
  });
@@ -9501,7 +9503,14 @@ AST_Scope.DEFMETHOD("figure_out_scope", function(options, { parent_scope = null,
9501
9503
  // scope when we encounter the AST_Defun node (which is
9502
9504
  // instanceof AST_Scope) but we get to the symbol a bit
9503
9505
  // later.
9504
- mark_export((node.scope = defun.parent_scope.get_defun_scope()).def_function(node, defun), 1);
9506
+ const closest_scope = defun.parent_scope;
9507
+
9508
+ // In strict mode, function definitions are block-scoped
9509
+ node.scope = tw.directives["use strict"]
9510
+ ? closest_scope
9511
+ : closest_scope.get_defun_scope();
9512
+
9513
+ mark_export(node.scope.def_function(node, defun), 1);
9505
9514
  } else if (node instanceof AST_SymbolClass) {
9506
9515
  mark_export(defun.def_variable(node, defun), 1);
9507
9516
  } else if (node instanceof AST_SymbolImport) {
@@ -9680,7 +9689,6 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
9680
9689
 
9681
9690
  AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
9682
9691
  this.variables = new Map(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
9683
- this.functions = new Map(); // map name to AST_SymbolDefun (functions defined in this scope)
9684
9692
  this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
9685
9693
  this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
9686
9694
  this.parent_scope = parent_scope; // the parent scope
@@ -9843,7 +9851,6 @@ AST_Scope.DEFMETHOD("find_variable", function(name) {
9843
9851
  AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
9844
9852
  var def = this.def_variable(symbol, init);
9845
9853
  if (!def.init || def.init instanceof AST_Defun) def.init = init;
9846
- this.functions.set(symbol.name, def);
9847
9854
  return def;
9848
9855
  });
9849
9856
 
@@ -11951,6 +11958,7 @@ function tighten_body(statements, compressor) {
11951
11958
  if (stop_after === node) abort = true;
11952
11959
  if (stop_if_hit === node) stop_if_hit = null;
11953
11960
  });
11961
+
11954
11962
  var multi_replacer = new TreeTransformer(function(node) {
11955
11963
  if (abort) return node;
11956
11964
  // Skip nodes before `candidate` as quickly as possible
@@ -11973,6 +11981,7 @@ function tighten_body(statements, compressor) {
11973
11981
  // Skip (non-executed) functions and (leading) default case in switch statements
11974
11982
  if (node instanceof AST_Default || node instanceof AST_Scope) return node;
11975
11983
  });
11984
+
11976
11985
  while (--stat_index >= 0) {
11977
11986
  // Treat parameters as collapsible in IIFE, i.e.
11978
11987
  // function(a, b){ ... }(x());
@@ -12148,7 +12157,10 @@ function tighten_body(statements, compressor) {
12148
12157
  function extract_candidates(expr) {
12149
12158
  hit_stack.push(expr);
12150
12159
  if (expr instanceof AST_Assign) {
12151
- if (!expr.left.has_side_effects(compressor)) {
12160
+ if (
12161
+ !expr.left.has_side_effects(compressor)
12162
+ && !(expr.right instanceof AST_Chain)
12163
+ ) {
12152
12164
  candidates.push(hit_stack.slice());
12153
12165
  }
12154
12166
  extract_candidates(expr.right);
@@ -12211,7 +12223,7 @@ function tighten_body(statements, compressor) {
12211
12223
  candidates.push(hit_stack.slice());
12212
12224
  }
12213
12225
  } else if (expr instanceof AST_VarDef) {
12214
- if (expr.value) {
12226
+ if (expr.value && !(expr.value instanceof AST_Chain)) {
12215
12227
  candidates.push(hit_stack.slice());
12216
12228
  extract_candidates(expr.value);
12217
12229
  }
@@ -13919,7 +13931,7 @@ const pure_prop_access_globals = new Set([
13919
13931
  || this.expression.has_side_effects(compressor);
13920
13932
  });
13921
13933
  def_has_side_effects(AST_Sub, function(compressor) {
13922
- if (this.optional && is_nullish(this.expression)) {
13934
+ if (this.optional && is_nullish(this.expression, compressor)) {
13923
13935
  return false;
13924
13936
  }
13925
13937
 
@@ -13989,7 +14001,7 @@ const pure_prop_access_globals = new Set([
13989
14001
  return any(this.body, compressor);
13990
14002
  });
13991
14003
  def_may_throw(AST_Call, function(compressor) {
13992
- if (this.optional && is_nullish(this.expression)) return false;
14004
+ if (this.optional && is_nullish(this.expression, compressor)) return false;
13993
14005
  if (any(this.args, compressor)) return true;
13994
14006
  if (this.is_callee_pure(compressor)) return false;
13995
14007
  if (this.expression.may_throw(compressor)) return true;
@@ -14052,7 +14064,7 @@ const pure_prop_access_globals = new Set([
14052
14064
  || this.expression.may_throw(compressor);
14053
14065
  });
14054
14066
  def_may_throw(AST_Sub, function(compressor) {
14055
- if (this.optional && is_nullish(this.expression)) return false;
14067
+ if (this.optional && is_nullish(this.expression, compressor)) return false;
14056
14068
 
14057
14069
  return !this.optional && this.expression.may_throw_on_access(compressor)
14058
14070
  || this.expression.may_throw(compressor)
@@ -14865,7 +14877,7 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
14865
14877
  def_drop_side_effect_free(AST_Constant, return_null);
14866
14878
  def_drop_side_effect_free(AST_This, return_null);
14867
14879
  def_drop_side_effect_free(AST_Call, function(compressor, first_in_statement) {
14868
- if (this.optional && is_nullish(this.expression)) {
14880
+ if (this.optional && is_nullish(this.expression, compressor)) {
14869
14881
  return make_node(AST_Undefined, this);
14870
14882
  }
14871
14883
 
@@ -15012,7 +15024,7 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
15012
15024
  });
15013
15025
  def_drop_side_effect_free(AST_Dot, function(compressor, first_in_statement) {
15014
15026
  if (this.optional) {
15015
- return is_nullish(this.expression) ? make_node(AST_Undefined, this) : this;
15027
+ return is_nullish(this.expression, compressor) ? make_node(AST_Undefined, this) : this;
15016
15028
  }
15017
15029
  if (this.expression.may_throw_on_access(compressor)) return this;
15018
15030
 
@@ -15020,7 +15032,7 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
15020
15032
  });
15021
15033
  def_drop_side_effect_free(AST_Sub, function(compressor, first_in_statement) {
15022
15034
  if (this.optional) {
15023
- return is_nullish(this.expression) ? make_node(AST_Undefined, this): this;
15035
+ return is_nullish(this.expression, compressor) ? make_node(AST_Undefined, this): this;
15024
15036
  }
15025
15037
  if (this.expression.may_throw_on_access(compressor)) return this;
15026
15038
 
@@ -15545,11 +15557,11 @@ def_optimize(AST_Definitions, function(self) {
15545
15557
  return self;
15546
15558
  });
15547
15559
 
15548
- def_optimize(AST_VarDef, function(self) {
15560
+ def_optimize(AST_VarDef, function(self, compressor) {
15549
15561
  if (
15550
15562
  self.name instanceof AST_SymbolLet
15551
15563
  && self.value != null
15552
- && is_undefined(self.value)
15564
+ && is_undefined(self.value, compressor)
15553
15565
  ) {
15554
15566
  self.value = null;
15555
15567
  }
@@ -15587,7 +15599,7 @@ def_optimize(AST_Call, function(self, compressor) {
15587
15599
  }
15588
15600
  }
15589
15601
 
15590
- if (self.optional && is_nullish(fn)) {
15602
+ if (self.optional && is_nullish(fn, compressor)) {
15591
15603
  return make_node(AST_Undefined, self);
15592
15604
  }
15593
15605
 
@@ -16613,7 +16625,7 @@ def_optimize(AST_Binary, function(self, compressor) {
16613
16625
  }
16614
16626
  break;
16615
16627
  case "??":
16616
- if (is_nullish(self.left)) {
16628
+ if (is_nullish(self.left, compressor)) {
16617
16629
  return self.right;
16618
16630
  }
16619
16631
 
@@ -17221,20 +17233,20 @@ def_optimize(AST_DefaultAssign, function(self, compressor) {
17221
17233
  return self;
17222
17234
  });
17223
17235
 
17224
- function is_nullish(node) {
17236
+ function is_nullish(node, compressor) {
17225
17237
  let fixed;
17226
17238
  return (
17227
17239
  node instanceof AST_Null
17228
- || is_undefined(node)
17240
+ || is_undefined(node, compressor)
17229
17241
  || (
17230
17242
  node instanceof AST_SymbolRef
17231
17243
  && (fixed = node.definition().fixed) instanceof AST_Node
17232
- && is_nullish(fixed)
17244
+ && is_nullish(fixed, compressor)
17233
17245
  )
17234
17246
  // Recurse into those optional chains!
17235
- || node instanceof AST_PropAccess && node.optional && is_nullish(node.expression)
17236
- || node instanceof AST_Call && node.optional && is_nullish(node.expression)
17237
- || node instanceof AST_Chain && is_nullish(node.expression)
17247
+ || node instanceof AST_PropAccess && node.optional && is_nullish(node.expression, compressor)
17248
+ || node instanceof AST_Call && node.optional && is_nullish(node.expression, compressor)
17249
+ || node instanceof AST_Chain && is_nullish(node.expression, compressor)
17238
17250
  );
17239
17251
  }
17240
17252
 
@@ -17249,8 +17261,8 @@ function is_nullish_check(check, check_subject, compressor) {
17249
17261
  && check.operator === "=="
17250
17262
  // which side is nullish?
17251
17263
  && (
17252
- (nullish_side = is_nullish(check.left) && check.left)
17253
- || (nullish_side = is_nullish(check.right) && check.right)
17264
+ (nullish_side = is_nullish(check.left, compressor) && check.left)
17265
+ || (nullish_side = is_nullish(check.right, compressor) && check.right)
17254
17266
  )
17255
17267
  // is the other side the same as the check_subject
17256
17268
  && (
@@ -17288,12 +17300,12 @@ function is_nullish_check(check, check_subject, compressor) {
17288
17300
  null_cmp = cmp;
17289
17301
  defined_side = cmp.left;
17290
17302
  }
17291
- if (is_undefined(cmp.left)) {
17303
+ if (is_undefined(cmp.left, compressor)) {
17292
17304
  found++;
17293
17305
  undefined_cmp = cmp;
17294
17306
  defined_side = cmp.right;
17295
17307
  }
17296
- if (is_undefined(cmp.right)) {
17308
+ if (is_undefined(cmp.right, compressor)) {
17297
17309
  found++;
17298
17310
  undefined_cmp = cmp;
17299
17311
  defined_side = cmp.left;
@@ -17794,7 +17806,7 @@ def_optimize(AST_Sub, function(self, compressor) {
17794
17806
  ev = make_node_from_constant(ev, self).optimize(compressor);
17795
17807
  return best_of(compressor, ev, self);
17796
17808
  }
17797
- if (self.optional && is_nullish(self.expression)) {
17809
+ if (self.optional && is_nullish(self.expression, compressor)) {
17798
17810
  return make_node(AST_Undefined, self);
17799
17811
  }
17800
17812
  return self;
@@ -17868,7 +17880,7 @@ def_optimize(AST_Dot, function(self, compressor) {
17868
17880
  ev = make_node_from_constant(ev, self).optimize(compressor);
17869
17881
  return best_of(compressor, ev, self);
17870
17882
  }
17871
- if (self.optional && is_nullish(self.expression)) {
17883
+ if (self.optional && is_nullish(self.expression, compressor)) {
17872
17884
  return make_node(AST_Undefined, self);
17873
17885
  }
17874
17886
  return self;
@@ -17912,7 +17924,7 @@ def_optimize(AST_Array, function(self, compressor) {
17912
17924
  return self;
17913
17925
  });
17914
17926
 
17915
- function inline_object_prop_spread(props) {
17927
+ function inline_object_prop_spread(props, compressor) {
17916
17928
  for (var i = 0; i < props.length; i++) {
17917
17929
  var prop = props[i];
17918
17930
  if (prop instanceof AST_Expansion) {
@@ -17930,6 +17942,9 @@ function inline_object_prop_spread(props) {
17930
17942
  // non-iterable value silently does nothing; it is thus safe
17931
17943
  // to remove. AST_String is the only iterable AST_Constant.
17932
17944
  props.splice(i, 1);
17945
+ } else if (is_nullish(expr, compressor)) {
17946
+ // Likewise, null and undefined can be silently removed.
17947
+ props.splice(i, 1);
17933
17948
  }
17934
17949
  }
17935
17950
  }
@@ -17940,7 +17955,7 @@ def_optimize(AST_Object, function(self, compressor) {
17940
17955
  if (optimized !== self) {
17941
17956
  return optimized;
17942
17957
  }
17943
- inline_object_prop_spread(self.properties);
17958
+ inline_object_prop_spread(self.properties, compressor);
17944
17959
  return self;
17945
17960
  });
17946
17961
 
@@ -18033,7 +18048,7 @@ def_optimize(AST_TemplateString, function(self, compressor) {
18033
18048
  && (
18034
18049
  segments[1].is_string(compressor)
18035
18050
  || segments[1].is_number(compressor)
18036
- || is_nullish(segments[1])
18051
+ || is_nullish(segments[1], compressor)
18037
18052
  || compressor.option("unsafe")
18038
18053
  )
18039
18054
  ) {
@@ -26902,7 +26917,6 @@ async function run_cli({ program, packageJson, fs, path }) {
26902
26917
  case "enclosed":
26903
26918
  return value.length ? value.map(symdef) : undefined;
26904
26919
  case "variables":
26905
- case "functions":
26906
26920
  case "globals":
26907
26921
  return value.size ? collect_from_map(value, symdef) : undefined;
26908
26922
  }
@@ -26915,7 +26929,6 @@ async function run_cli({ program, packageJson, fs, path }) {
26915
26929
  };
26916
26930
  if (value.block_scope) {
26917
26931
  result.variables = value.block_scope.variables;
26918
- result.functions = value.block_scope.functions;
26919
26932
  result.enclosed = value.block_scope.enclosed;
26920
26933
  }
26921
26934
  value.CTOR.PROPS.forEach(function(prop) {
package/lib/ast.js CHANGED
@@ -214,8 +214,6 @@ function walk_body(node, visitor) {
214
214
  function clone_block_scope(deep) {
215
215
  var clone = this._clone(deep);
216
216
  if (this.block_scope) {
217
- // TODO this is sometimes undefined during compression.
218
- // But it should always have a value!
219
217
  clone.block_scope = this.block_scope.clone();
220
218
  }
221
219
  return clone;
@@ -399,7 +397,6 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
399
397
  $documentation: "Base class for all statements introducing a lexical scope",
400
398
  $propdoc: {
401
399
  variables: "[Map/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
402
- functions: "[Map/S] like `variables`, but only lists function declarations",
403
400
  uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
404
401
  uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
405
402
  parent_scope: "[AST_Scope?/S] link to the parent scope",
@@ -422,7 +419,6 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
422
419
  });
423
420
  } else {
424
421
  if (this.variables) node.variables = new Map(this.variables);
425
- if (this.functions) node.functions = new Map(this.functions);
426
422
  if (this.enclosed) node.enclosed = this.enclosed.slice();
427
423
  if (this._block_scope) node._block_scope = this._block_scope;
428
424
  }
package/lib/cli.js CHANGED
@@ -264,7 +264,6 @@ export async function run_cli({ program, packageJson, fs, path }) {
264
264
  case "enclosed":
265
265
  return value.length ? value.map(symdef) : undefined;
266
266
  case "variables":
267
- case "functions":
268
267
  case "globals":
269
268
  return value.size ? collect_from_map(value, symdef) : undefined;
270
269
  }
@@ -277,7 +276,6 @@ export async function run_cli({ program, packageJson, fs, path }) {
277
276
  };
278
277
  if (value.block_scope) {
279
278
  result.variables = value.block_scope.variables;
280
- result.functions = value.block_scope.functions;
281
279
  result.enclosed = value.block_scope.enclosed;
282
280
  }
283
281
  value.CTOR.PROPS.forEach(function(prop) {
@@ -1508,6 +1508,7 @@ function tighten_body(statements, compressor) {
1508
1508
  if (stop_after === node) abort = true;
1509
1509
  if (stop_if_hit === node) stop_if_hit = null;
1510
1510
  });
1511
+
1511
1512
  var multi_replacer = new TreeTransformer(function(node) {
1512
1513
  if (abort) return node;
1513
1514
  // Skip nodes before `candidate` as quickly as possible
@@ -1530,6 +1531,7 @@ function tighten_body(statements, compressor) {
1530
1531
  // Skip (non-executed) functions and (leading) default case in switch statements
1531
1532
  if (node instanceof AST_Default || node instanceof AST_Scope) return node;
1532
1533
  });
1534
+
1533
1535
  while (--stat_index >= 0) {
1534
1536
  // Treat parameters as collapsible in IIFE, i.e.
1535
1537
  // function(a, b){ ... }(x());
@@ -1705,7 +1707,10 @@ function tighten_body(statements, compressor) {
1705
1707
  function extract_candidates(expr) {
1706
1708
  hit_stack.push(expr);
1707
1709
  if (expr instanceof AST_Assign) {
1708
- if (!expr.left.has_side_effects(compressor)) {
1710
+ if (
1711
+ !expr.left.has_side_effects(compressor)
1712
+ && !(expr.right instanceof AST_Chain)
1713
+ ) {
1709
1714
  candidates.push(hit_stack.slice());
1710
1715
  }
1711
1716
  extract_candidates(expr.right);
@@ -1768,7 +1773,7 @@ function tighten_body(statements, compressor) {
1768
1773
  candidates.push(hit_stack.slice());
1769
1774
  }
1770
1775
  } else if (expr instanceof AST_VarDef) {
1771
- if (expr.value) {
1776
+ if (expr.value && !(expr.value instanceof AST_Chain)) {
1772
1777
  candidates.push(hit_stack.slice());
1773
1778
  extract_candidates(expr.value);
1774
1779
  }
@@ -3476,7 +3481,7 @@ const pure_prop_access_globals = new Set([
3476
3481
  || this.expression.has_side_effects(compressor);
3477
3482
  });
3478
3483
  def_has_side_effects(AST_Sub, function(compressor) {
3479
- if (this.optional && is_nullish(this.expression)) {
3484
+ if (this.optional && is_nullish(this.expression, compressor)) {
3480
3485
  return false;
3481
3486
  }
3482
3487
 
@@ -3546,7 +3551,7 @@ const pure_prop_access_globals = new Set([
3546
3551
  return any(this.body, compressor);
3547
3552
  });
3548
3553
  def_may_throw(AST_Call, function(compressor) {
3549
- if (this.optional && is_nullish(this.expression)) return false;
3554
+ if (this.optional && is_nullish(this.expression, compressor)) return false;
3550
3555
  if (any(this.args, compressor)) return true;
3551
3556
  if (this.is_callee_pure(compressor)) return false;
3552
3557
  if (this.expression.may_throw(compressor)) return true;
@@ -3609,7 +3614,7 @@ const pure_prop_access_globals = new Set([
3609
3614
  || this.expression.may_throw(compressor);
3610
3615
  });
3611
3616
  def_may_throw(AST_Sub, function(compressor) {
3612
- if (this.optional && is_nullish(this.expression)) return false;
3617
+ if (this.optional && is_nullish(this.expression, compressor)) return false;
3613
3618
 
3614
3619
  return !this.optional && this.expression.may_throw_on_access(compressor)
3615
3620
  || this.expression.may_throw(compressor)
@@ -4422,7 +4427,7 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
4422
4427
  def_drop_side_effect_free(AST_Constant, return_null);
4423
4428
  def_drop_side_effect_free(AST_This, return_null);
4424
4429
  def_drop_side_effect_free(AST_Call, function(compressor, first_in_statement) {
4425
- if (this.optional && is_nullish(this.expression)) {
4430
+ if (this.optional && is_nullish(this.expression, compressor)) {
4426
4431
  return make_node(AST_Undefined, this);
4427
4432
  }
4428
4433
 
@@ -4569,7 +4574,7 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
4569
4574
  });
4570
4575
  def_drop_side_effect_free(AST_Dot, function(compressor, first_in_statement) {
4571
4576
  if (this.optional) {
4572
- return is_nullish(this.expression) ? make_node(AST_Undefined, this) : this;
4577
+ return is_nullish(this.expression, compressor) ? make_node(AST_Undefined, this) : this;
4573
4578
  }
4574
4579
  if (this.expression.may_throw_on_access(compressor)) return this;
4575
4580
 
@@ -4577,7 +4582,7 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
4577
4582
  });
4578
4583
  def_drop_side_effect_free(AST_Sub, function(compressor, first_in_statement) {
4579
4584
  if (this.optional) {
4580
- return is_nullish(this.expression) ? make_node(AST_Undefined, this): this;
4585
+ return is_nullish(this.expression, compressor) ? make_node(AST_Undefined, this): this;
4581
4586
  }
4582
4587
  if (this.expression.may_throw_on_access(compressor)) return this;
4583
4588
 
@@ -5102,11 +5107,11 @@ def_optimize(AST_Definitions, function(self) {
5102
5107
  return self;
5103
5108
  });
5104
5109
 
5105
- def_optimize(AST_VarDef, function(self) {
5110
+ def_optimize(AST_VarDef, function(self, compressor) {
5106
5111
  if (
5107
5112
  self.name instanceof AST_SymbolLet
5108
5113
  && self.value != null
5109
- && is_undefined(self.value)
5114
+ && is_undefined(self.value, compressor)
5110
5115
  ) {
5111
5116
  self.value = null;
5112
5117
  }
@@ -5144,7 +5149,7 @@ def_optimize(AST_Call, function(self, compressor) {
5144
5149
  }
5145
5150
  }
5146
5151
 
5147
- if (self.optional && is_nullish(fn)) {
5152
+ if (self.optional && is_nullish(fn, compressor)) {
5148
5153
  return make_node(AST_Undefined, self);
5149
5154
  }
5150
5155
 
@@ -6170,7 +6175,7 @@ def_optimize(AST_Binary, function(self, compressor) {
6170
6175
  }
6171
6176
  break;
6172
6177
  case "??":
6173
- if (is_nullish(self.left)) {
6178
+ if (is_nullish(self.left, compressor)) {
6174
6179
  return self.right;
6175
6180
  }
6176
6181
 
@@ -6778,20 +6783,20 @@ def_optimize(AST_DefaultAssign, function(self, compressor) {
6778
6783
  return self;
6779
6784
  });
6780
6785
 
6781
- function is_nullish(node) {
6786
+ function is_nullish(node, compressor) {
6782
6787
  let fixed;
6783
6788
  return (
6784
6789
  node instanceof AST_Null
6785
- || is_undefined(node)
6790
+ || is_undefined(node, compressor)
6786
6791
  || (
6787
6792
  node instanceof AST_SymbolRef
6788
6793
  && (fixed = node.definition().fixed) instanceof AST_Node
6789
- && is_nullish(fixed)
6794
+ && is_nullish(fixed, compressor)
6790
6795
  )
6791
6796
  // Recurse into those optional chains!
6792
- || node instanceof AST_PropAccess && node.optional && is_nullish(node.expression)
6793
- || node instanceof AST_Call && node.optional && is_nullish(node.expression)
6794
- || node instanceof AST_Chain && is_nullish(node.expression)
6797
+ || node instanceof AST_PropAccess && node.optional && is_nullish(node.expression, compressor)
6798
+ || node instanceof AST_Call && node.optional && is_nullish(node.expression, compressor)
6799
+ || node instanceof AST_Chain && is_nullish(node.expression, compressor)
6795
6800
  );
6796
6801
  }
6797
6802
 
@@ -6806,8 +6811,8 @@ function is_nullish_check(check, check_subject, compressor) {
6806
6811
  && check.operator === "=="
6807
6812
  // which side is nullish?
6808
6813
  && (
6809
- (nullish_side = is_nullish(check.left) && check.left)
6810
- || (nullish_side = is_nullish(check.right) && check.right)
6814
+ (nullish_side = is_nullish(check.left, compressor) && check.left)
6815
+ || (nullish_side = is_nullish(check.right, compressor) && check.right)
6811
6816
  )
6812
6817
  // is the other side the same as the check_subject
6813
6818
  && (
@@ -6845,12 +6850,12 @@ function is_nullish_check(check, check_subject, compressor) {
6845
6850
  null_cmp = cmp;
6846
6851
  defined_side = cmp.left;
6847
6852
  }
6848
- if (is_undefined(cmp.left)) {
6853
+ if (is_undefined(cmp.left, compressor)) {
6849
6854
  found++;
6850
6855
  undefined_cmp = cmp;
6851
6856
  defined_side = cmp.right;
6852
6857
  }
6853
- if (is_undefined(cmp.right)) {
6858
+ if (is_undefined(cmp.right, compressor)) {
6854
6859
  found++;
6855
6860
  undefined_cmp = cmp;
6856
6861
  defined_side = cmp.left;
@@ -7351,7 +7356,7 @@ def_optimize(AST_Sub, function(self, compressor) {
7351
7356
  ev = make_node_from_constant(ev, self).optimize(compressor);
7352
7357
  return best_of(compressor, ev, self);
7353
7358
  }
7354
- if (self.optional && is_nullish(self.expression)) {
7359
+ if (self.optional && is_nullish(self.expression, compressor)) {
7355
7360
  return make_node(AST_Undefined, self);
7356
7361
  }
7357
7362
  return self;
@@ -7425,7 +7430,7 @@ def_optimize(AST_Dot, function(self, compressor) {
7425
7430
  ev = make_node_from_constant(ev, self).optimize(compressor);
7426
7431
  return best_of(compressor, ev, self);
7427
7432
  }
7428
- if (self.optional && is_nullish(self.expression)) {
7433
+ if (self.optional && is_nullish(self.expression, compressor)) {
7429
7434
  return make_node(AST_Undefined, self);
7430
7435
  }
7431
7436
  return self;
@@ -7469,7 +7474,7 @@ def_optimize(AST_Array, function(self, compressor) {
7469
7474
  return self;
7470
7475
  });
7471
7476
 
7472
- function inline_object_prop_spread(props) {
7477
+ function inline_object_prop_spread(props, compressor) {
7473
7478
  for (var i = 0; i < props.length; i++) {
7474
7479
  var prop = props[i];
7475
7480
  if (prop instanceof AST_Expansion) {
@@ -7487,6 +7492,9 @@ function inline_object_prop_spread(props) {
7487
7492
  // non-iterable value silently does nothing; it is thus safe
7488
7493
  // to remove. AST_String is the only iterable AST_Constant.
7489
7494
  props.splice(i, 1);
7495
+ } else if (is_nullish(expr, compressor)) {
7496
+ // Likewise, null and undefined can be silently removed.
7497
+ props.splice(i, 1);
7490
7498
  }
7491
7499
  }
7492
7500
  }
@@ -7497,7 +7505,7 @@ def_optimize(AST_Object, function(self, compressor) {
7497
7505
  if (optimized !== self) {
7498
7506
  return optimized;
7499
7507
  }
7500
- inline_object_prop_spread(self.properties);
7508
+ inline_object_prop_spread(self.properties, compressor);
7501
7509
  return self;
7502
7510
  });
7503
7511
 
@@ -7590,7 +7598,7 @@ def_optimize(AST_TemplateString, function(self, compressor) {
7590
7598
  && (
7591
7599
  segments[1].is_string(compressor)
7592
7600
  || segments[1].is_number(compressor)
7593
- || is_nullish(segments[1])
7601
+ || is_nullish(segments[1], compressor)
7594
7602
  || compressor.option("unsafe")
7595
7603
  )
7596
7604
  ) {
@@ -18,6 +18,7 @@ import {
18
18
  AST_Directive,
19
19
  AST_Do,
20
20
  AST_Dot,
21
+ AST_DotHash,
21
22
  AST_EmptyStatement,
22
23
  AST_Expansion,
23
24
  AST_Export,
@@ -233,6 +234,10 @@ AST_Dot.prototype.shallow_cmp = mkshallow({
233
234
  property: "eq"
234
235
  });
235
236
 
237
+ AST_DotHash.prototype.shallow_cmp = mkshallow({
238
+ property: "eq"
239
+ });
240
+
236
241
  AST_Unary.prototype.shallow_cmp = mkshallow({
237
242
  operator: "eq"
238
243
  });
package/lib/output.js CHANGED
@@ -349,11 +349,15 @@ function OutputStream(options) {
349
349
  var do_add_mapping = mappings ? function() {
350
350
  mappings.forEach(function(mapping) {
351
351
  try {
352
+ let name = !mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name;
353
+ if (name instanceof AST_Symbol) {
354
+ name = name.name;
355
+ }
352
356
  options.source_map.add(
353
357
  mapping.token.file,
354
358
  mapping.line, mapping.col,
355
359
  mapping.token.line, mapping.token.col,
356
- !mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name
360
+ is_basic_identifier_string(name) ? name : undefined
357
361
  );
358
362
  } catch(ex) {
359
363
  // Ignore bad mapping
package/lib/scope.js CHANGED
@@ -299,7 +299,14 @@ AST_Scope.DEFMETHOD("figure_out_scope", function(options, { parent_scope = null,
299
299
  // scope when we encounter the AST_Defun node (which is
300
300
  // instanceof AST_Scope) but we get to the symbol a bit
301
301
  // later.
302
- mark_export((node.scope = defun.parent_scope.get_defun_scope()).def_function(node, defun), 1);
302
+ const closest_scope = defun.parent_scope;
303
+
304
+ // In strict mode, function definitions are block-scoped
305
+ node.scope = tw.directives["use strict"]
306
+ ? closest_scope
307
+ : closest_scope.get_defun_scope();
308
+
309
+ mark_export(node.scope.def_function(node, defun), 1);
303
310
  } else if (node instanceof AST_SymbolClass) {
304
311
  mark_export(defun.def_variable(node, defun), 1);
305
312
  } else if (node instanceof AST_SymbolImport) {
@@ -478,7 +485,6 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
478
485
 
479
486
  AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
480
487
  this.variables = new Map(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
481
- this.functions = new Map(); // map name to AST_SymbolDefun (functions defined in this scope)
482
488
  this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
483
489
  this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
484
490
  this.parent_scope = parent_scope; // the parent scope
@@ -641,7 +647,6 @@ AST_Scope.DEFMETHOD("find_variable", function(name) {
641
647
  AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
642
648
  var def = this.def_variable(symbol, init);
643
649
  if (!def.init || def.init instanceof AST_Defun) def.init = init;
644
- this.functions.set(symbol.name, def);
645
650
  return def;
646
651
  });
647
652
 
@@ -64,10 +64,8 @@ class DefaultsError extends Error {
64
64
  function defaults(args, defs, croak) {
65
65
  if (args === true) {
66
66
  args = {};
67
- }
68
-
69
- if (args != null && typeof args === "object") {
70
- args = Object.assign({}, args);
67
+ } else if (args != null && typeof args === "object") {
68
+ args = {...args};
71
69
  }
72
70
 
73
71
  const ret = args || {};
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.7.0",
7
+ "version": "5.7.1",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },