terser 5.0.0 → 5.3.0

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/lib/ast.js CHANGED
@@ -527,7 +527,7 @@ var AST_PrefixedTemplateString = DEFNODE("PrefixedTemplateString", "template_str
527
527
  $documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`",
528
528
  $propdoc: {
529
529
  template_string: "[AST_TemplateString] The template string",
530
- prefix: "[AST_SymbolRef|AST_PropAccess] The prefix, which can be a symbol such as `foo` or a dotted expression such as `String.raw`."
530
+ prefix: "[AST_Node] The prefix, which will get called."
531
531
  },
532
532
  _walk: function(visitor) {
533
533
  return visitor._visit(this, function () {
@@ -864,6 +864,10 @@ var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", {
864
864
  },
865
865
  });
866
866
 
867
+ var AST_ImportMeta = DEFNODE("ImportMeta", null, {
868
+ $documentation: "A reference to import.meta",
869
+ });
870
+
867
871
  var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name", {
868
872
  $documentation: "An `export` statement",
869
873
  $propdoc: {
@@ -904,11 +908,12 @@ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_defaul
904
908
 
905
909
  /* -----[ OTHER ]----- */
906
910
 
907
- var AST_Call = DEFNODE("Call", "expression args _annotations", {
911
+ var AST_Call = DEFNODE("Call", "expression args optional _annotations", {
908
912
  $documentation: "A function call expression",
909
913
  $propdoc: {
910
914
  expression: "[AST_Node] expression to invoke as function",
911
915
  args: "[AST_Node*] array of arguments",
916
+ optional: "[boolean] whether this is an optional call (IE ?.() )",
912
917
  _annotations: "[number] bitfield containing information about the call"
913
918
  },
914
919
  initialize() {
@@ -952,11 +957,13 @@ var AST_Sequence = DEFNODE("Sequence", "expressions", {
952
957
  },
953
958
  });
954
959
 
955
- var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
960
+ var AST_PropAccess = DEFNODE("PropAccess", "expression property optional", {
956
961
  $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
957
962
  $propdoc: {
958
963
  expression: "[AST_Node] the “container” expression",
959
- property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node"
964
+ property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node",
965
+
966
+ optional: "[boolean] whether this is an optional property access (IE ?.)"
960
967
  }
961
968
  });
962
969
 
@@ -989,6 +996,21 @@ var AST_Sub = DEFNODE("Sub", null, {
989
996
  },
990
997
  }, AST_PropAccess);
991
998
 
999
+ var AST_Chain = DEFNODE("Chain", "expression", {
1000
+ $documentation: "A chain expression like a?.b?.(c)?.[d]",
1001
+ $propdoc: {
1002
+ expression: "[AST_Call|AST_Dot|AST_Sub] chain element."
1003
+ },
1004
+ _walk: function (visitor) {
1005
+ return visitor._visit(this, function() {
1006
+ this.expression._walk(visitor);
1007
+ });
1008
+ },
1009
+ _children_backwards(push) {
1010
+ push(this.expression);
1011
+ },
1012
+ });
1013
+
992
1014
  var AST_Unary = DEFNODE("Unary", "operator expression", {
993
1015
  $documentation: "Base class for unary expressions",
994
1016
  $propdoc: {
@@ -1610,6 +1632,7 @@ export {
1610
1632
  AST_Call,
1611
1633
  AST_Case,
1612
1634
  AST_Catch,
1635
+ AST_Chain,
1613
1636
  AST_Class,
1614
1637
  AST_ClassExpression,
1615
1638
  AST_ClassProperty,
@@ -1642,6 +1665,7 @@ export {
1642
1665
  AST_Hole,
1643
1666
  AST_If,
1644
1667
  AST_Import,
1668
+ AST_ImportMeta,
1645
1669
  AST_Infinity,
1646
1670
  AST_IterationStatement,
1647
1671
  AST_Jump,
@@ -78,6 +78,7 @@ import {
78
78
  AST_Call,
79
79
  AST_Case,
80
80
  AST_Catch,
81
+ AST_Chain,
81
82
  AST_Class,
82
83
  AST_ClassExpression,
83
84
  AST_ClassProperty,
@@ -216,7 +217,7 @@ const set_flag = (node, flag) => { node.flags |= flag; };
216
217
  const clear_flag = (node, flag) => { node.flags &= ~flag; };
217
218
 
218
219
  class Compressor extends TreeWalker {
219
- constructor(options, false_by_default) {
220
+ constructor(options, { false_by_default = false, mangle_options = false }) {
220
221
  super();
221
222
  if (options.defaults !== undefined && !options.defaults) false_by_default = true;
222
223
  this.options = defaults(options, {
@@ -274,7 +275,7 @@ class Compressor extends TreeWalker {
274
275
  unsafe_regexp : false,
275
276
  unsafe_undefined: false,
276
277
  unused : !false_by_default,
277
- warnings : false, // legacy
278
+ warnings : false // legacy
278
279
  }, true);
279
280
  var global_defs = this.options["global_defs"];
280
281
  if (typeof global_defs == "object") for (var key in global_defs) {
@@ -324,6 +325,7 @@ class Compressor extends TreeWalker {
324
325
  this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
325
326
  this.evaluated_regexps = new Map();
326
327
  this._toplevel = undefined;
328
+ this.mangle_options = mangle_options;
327
329
  }
328
330
 
329
331
  option(key) {
@@ -792,13 +794,53 @@ function is_modified(compressor, tw, node, value, level, immutable) {
792
794
  pop(tw);
793
795
  return true;
794
796
  });
797
+
798
+ def_reduce_vars(AST_Chain, function(tw, descend) {
799
+ // Chains' conditions apply left-to-right, cumulatively.
800
+ // If we walk normally we don't go in that order because we would pop before pushing again
801
+ // Solution: AST_PropAccess and AST_Call push when they are optional, and never pop.
802
+ // Then we pop everything when they are done being walked.
803
+ const safe_ids = tw.safe_ids;
804
+
805
+ descend();
806
+
807
+ // Unroll back to start
808
+ tw.safe_ids = safe_ids;
809
+ return true;
810
+ });
811
+ def_reduce_vars(AST_Call, function (tw) {
812
+ // TODO this block should just be { return } but
813
+ // for some reason the _walk function of AST_Call walks the callee last
814
+
815
+ this.expression.walk(tw);
816
+
817
+ if (this.optional) {
818
+ // Never pop -- it's popped at AST_Chain above
819
+ push(tw);
820
+ }
821
+
822
+ for (const arg of this.args) arg.walk(tw);
823
+
824
+ return true;
825
+ });
826
+ def_reduce_vars(AST_PropAccess, function (tw) {
827
+ if (!this.optional) return;
828
+
829
+ this.expression.walk(tw);
830
+
831
+ // Never pop -- it's popped at AST_Chain above
832
+ push(tw);
833
+
834
+ if (this.property instanceof AST_Node) this.property.walk(tw);
835
+
836
+ return true;
837
+ });
795
838
  def_reduce_vars(AST_Default, function(tw, descend) {
796
839
  push(tw);
797
840
  descend();
798
841
  pop(tw);
799
842
  return true;
800
843
  });
801
-
802
844
  function mark_lambda(tw, descend, compressor) {
803
845
  clear_flag(this, INLINED);
804
846
  push(tw);
@@ -2480,6 +2522,9 @@ function is_undefined(node, compressor) {
2480
2522
  if (this.expression instanceof AST_Function && this.property == "prototype") return false;
2481
2523
  return true;
2482
2524
  });
2525
+ def_may_throw_on_access(AST_Chain, function(compressor) {
2526
+ return this.expression._dot_throw(compressor);
2527
+ });
2483
2528
  def_may_throw_on_access(AST_Sequence, function(compressor) {
2484
2529
  return this.tail_node()._dot_throw(compressor);
2485
2530
  });
@@ -2630,6 +2675,9 @@ function is_lhs(node, parent) {
2630
2675
  }));
2631
2676
  });
2632
2677
  def_find_defs(AST_Node, noop);
2678
+ def_find_defs(AST_Chain, function(compressor, suffix) {
2679
+ return this.expression._find_defs(compressor, suffix);
2680
+ });
2633
2681
  def_find_defs(AST_Dot, function(compressor, suffix) {
2634
2682
  return this.expression._find_defs(compressor, "." + this.property + suffix);
2635
2683
  });
@@ -2963,16 +3011,13 @@ var static_fns = convert_to_predicate({
2963
3011
 
2964
3012
  var fixed = this.fixed_value();
2965
3013
  if (!fixed) return this;
2966
- var value;
2967
- if (HOP(fixed, "_eval")) {
2968
- value = fixed._eval();
2969
- } else {
2970
- reentrant_ref_eval.add(this);
2971
- value = fixed._eval(compressor, depth);
2972
- reentrant_ref_eval.delete(this);
2973
3014
 
2974
- if (value === fixed) return this;
2975
- }
3015
+ reentrant_ref_eval.add(this);
3016
+ const value = fixed._eval(compressor, depth);
3017
+ reentrant_ref_eval.delete(this);
3018
+
3019
+ if (value === fixed) return this;
3020
+
2976
3021
  if (value && typeof value == "object") {
2977
3022
  var escaped = this.definition().escaped;
2978
3023
  if (escaped && depth > escaped) return this;
@@ -3000,6 +3045,10 @@ var static_fns = convert_to_predicate({
3000
3045
  ],
3001
3046
  });
3002
3047
  def_eval(AST_PropAccess, function(compressor, depth) {
3048
+ if (this.optional) {
3049
+ const obj = this.expression._eval(compressor, depth);
3050
+ if (obj == null) return undefined;
3051
+ }
3003
3052
  if (compressor.option("unsafe")) {
3004
3053
  var key = this.property;
3005
3054
  if (key instanceof AST_Node) {
@@ -3041,8 +3090,16 @@ var static_fns = convert_to_predicate({
3041
3090
  }
3042
3091
  return this;
3043
3092
  });
3093
+ def_eval(AST_Chain, function(compressor, depth) {
3094
+ const evaluated = this.expression._eval(compressor, depth);
3095
+ return evaluated === this.expression ? this : evaluated;
3096
+ });
3044
3097
  def_eval(AST_Call, function(compressor, depth) {
3045
3098
  var exp = this.expression;
3099
+ if (this.optional) {
3100
+ const callee = this.expression._eval(compressor, depth);
3101
+ if (callee == null) return undefined;
3102
+ }
3046
3103
  if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
3047
3104
  var key = exp.property;
3048
3105
  if (key instanceof AST_Node) {
@@ -3244,9 +3301,11 @@ const pure_prop_access_globals = new Set([
3244
3301
  return any(this.body, compressor);
3245
3302
  });
3246
3303
  def_has_side_effects(AST_Call, function(compressor) {
3247
- if (!this.is_expr_pure(compressor)
3304
+ if (
3305
+ !this.is_expr_pure(compressor)
3248
3306
  && (!this.expression.is_call_pure(compressor)
3249
- || this.expression.has_side_effects(compressor))) {
3307
+ || this.expression.has_side_effects(compressor))
3308
+ ) {
3250
3309
  return true;
3251
3310
  }
3252
3311
  return any(this.args, compressor);
@@ -3329,14 +3388,21 @@ const pure_prop_access_globals = new Set([
3329
3388
  return any(this.elements, compressor);
3330
3389
  });
3331
3390
  def_has_side_effects(AST_Dot, function(compressor) {
3332
- return this.expression.may_throw_on_access(compressor)
3391
+ return !this.optional && this.expression.may_throw_on_access(compressor)
3333
3392
  || this.expression.has_side_effects(compressor);
3334
3393
  });
3335
3394
  def_has_side_effects(AST_Sub, function(compressor) {
3336
- return this.expression.may_throw_on_access(compressor)
3395
+ if (this.optional && is_nullish(this.expression)) {
3396
+ return false;
3397
+ }
3398
+
3399
+ return !this.optional && this.expression.may_throw_on_access(compressor)
3337
3400
  || this.expression.has_side_effects(compressor)
3338
3401
  || this.property.has_side_effects(compressor);
3339
3402
  });
3403
+ def_has_side_effects(AST_Chain, function (compressor) {
3404
+ return this.expression.has_side_effects(compressor);
3405
+ });
3340
3406
  def_has_side_effects(AST_Sequence, function(compressor) {
3341
3407
  return any(this.expressions, compressor);
3342
3408
  });
@@ -3396,6 +3462,7 @@ const pure_prop_access_globals = new Set([
3396
3462
  return any(this.body, compressor);
3397
3463
  });
3398
3464
  def_may_throw(AST_Call, function(compressor) {
3465
+ if (this.optional && is_nullish(this.expression)) return false;
3399
3466
  if (any(this.args, compressor)) return true;
3400
3467
  if (this.is_expr_pure(compressor)) return false;
3401
3468
  if (this.expression.may_throw(compressor)) return true;
@@ -3414,10 +3481,6 @@ const pure_prop_access_globals = new Set([
3414
3481
  def_may_throw(AST_Definitions, function(compressor) {
3415
3482
  return any(this.definitions, compressor);
3416
3483
  });
3417
- def_may_throw(AST_Dot, function(compressor) {
3418
- return this.expression.may_throw_on_access(compressor)
3419
- || this.expression.may_throw(compressor);
3420
- });
3421
3484
  def_may_throw(AST_If, function(compressor) {
3422
3485
  return this.condition.may_throw(compressor)
3423
3486
  || this.body && this.body.may_throw(compressor)
@@ -3457,11 +3520,20 @@ const pure_prop_access_globals = new Set([
3457
3520
  def_may_throw(AST_SimpleStatement, function(compressor) {
3458
3521
  return this.body.may_throw(compressor);
3459
3522
  });
3523
+ def_may_throw(AST_Dot, function(compressor) {
3524
+ return !this.optional && this.expression.may_throw_on_access(compressor)
3525
+ || this.expression.may_throw(compressor);
3526
+ });
3460
3527
  def_may_throw(AST_Sub, function(compressor) {
3461
- return this.expression.may_throw_on_access(compressor)
3528
+ if (this.optional && is_nullish(this.expression)) return false;
3529
+
3530
+ return !this.optional && this.expression.may_throw_on_access(compressor)
3462
3531
  || this.expression.may_throw(compressor)
3463
3532
  || this.property.may_throw(compressor);
3464
3533
  });
3534
+ def_may_throw(AST_Chain, function(compressor) {
3535
+ return this.expression.may_throw(compressor);
3536
+ });
3465
3537
  def_may_throw(AST_Switch, function(compressor) {
3466
3538
  return this.expression.may_throw(compressor)
3467
3539
  || any(this.body, compressor);
@@ -3619,9 +3691,9 @@ def_optimize(AST_Block, function(self, compressor) {
3619
3691
 
3620
3692
  function can_be_extracted_from_if_block(node) {
3621
3693
  return !(
3622
- node instanceof AST_Const ||
3623
- node instanceof AST_Let ||
3624
- node instanceof AST_Class
3694
+ node instanceof AST_Const
3695
+ || node instanceof AST_Let
3696
+ || node instanceof AST_Class
3625
3697
  );
3626
3698
  }
3627
3699
 
@@ -4188,7 +4260,9 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
4188
4260
  && !top_retain(def)
4189
4261
  && (value = sym.fixed_value()) === node.value
4190
4262
  && value instanceof AST_Object
4191
- && !value.properties.some(prop => prop.computed_key())
4263
+ && !value.properties.some(prop =>
4264
+ prop instanceof AST_Expansion || prop.computed_key()
4265
+ )
4192
4266
  ) {
4193
4267
  descend(node, this);
4194
4268
  const defs = new Map();
@@ -4255,6 +4329,10 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
4255
4329
  def_drop_side_effect_free(AST_Constant, return_null);
4256
4330
  def_drop_side_effect_free(AST_This, return_null);
4257
4331
  def_drop_side_effect_free(AST_Call, function(compressor, first_in_statement) {
4332
+ if (this.optional && is_nullish(this.expression)) {
4333
+ return make_node(AST_Undefined, this);
4334
+ }
4335
+
4258
4336
  if (!this.is_expr_pure(compressor)) {
4259
4337
  if (this.expression.is_call_pure(compressor)) {
4260
4338
  var exprs = this.args.slice();
@@ -4395,17 +4473,28 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
4395
4473
  return values && make_sequence(this, values);
4396
4474
  });
4397
4475
  def_drop_side_effect_free(AST_Dot, function(compressor, first_in_statement) {
4476
+ if (this.optional) {
4477
+ return is_nullish(this.expression) ? make_node(AST_Undefined, this) : this;
4478
+ }
4398
4479
  if (this.expression.may_throw_on_access(compressor)) return this;
4480
+
4399
4481
  return this.expression.drop_side_effect_free(compressor, first_in_statement);
4400
4482
  });
4401
4483
  def_drop_side_effect_free(AST_Sub, function(compressor, first_in_statement) {
4484
+ if (this.optional) {
4485
+ return is_nullish(this.expression) ? make_node(AST_Undefined, this): this;
4486
+ }
4402
4487
  if (this.expression.may_throw_on_access(compressor)) return this;
4488
+
4403
4489
  var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
4404
4490
  if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
4405
4491
  var property = this.property.drop_side_effect_free(compressor);
4406
4492
  if (!property) return expression;
4407
4493
  return make_sequence(this, [ expression, property ]);
4408
4494
  });
4495
+ def_drop_side_effect_free(AST_Chain, function (compressor, first_in_statement) {
4496
+ return this.expression.drop_side_effect_free(compressor, first_in_statement);
4497
+ });
4409
4498
  def_drop_side_effect_free(AST_Sequence, function(compressor) {
4410
4499
  var last = this.tail_node();
4411
4500
  var expr = last.drop_side_effect_free(compressor);
@@ -4946,6 +5035,10 @@ def_optimize(AST_Call, function(self, compressor) {
4946
5035
  }
4947
5036
  }
4948
5037
 
5038
+ if (self.optional && is_nullish(fn)) {
5039
+ return make_node(AST_Undefined, self);
5040
+ }
5041
+
4949
5042
  var is_func = fn instanceof AST_Lambda;
4950
5043
 
4951
5044
  if (is_func && fn.pinned()) return self;
@@ -5157,6 +5250,7 @@ def_optimize(AST_Call, function(self, compressor) {
5157
5250
  return make_node(AST_Call, self, {
5158
5251
  expression: make_node(AST_Dot, exp, {
5159
5252
  expression: exp.expression,
5253
+ optional: false,
5160
5254
  property: "call"
5161
5255
  }),
5162
5256
  args: args
@@ -5203,7 +5297,9 @@ def_optimize(AST_Call, function(self, compressor) {
5203
5297
  var ast = parse(code);
5204
5298
  var mangle = { ie8: compressor.option("ie8") };
5205
5299
  ast.figure_out_scope(mangle);
5206
- var comp = new Compressor(compressor.options);
5300
+ var comp = new Compressor(compressor.options, {
5301
+ mangle_options: compressor.mangle_options
5302
+ });
5207
5303
  ast = ast.transform(comp);
5208
5304
  ast.figure_out_scope(mangle);
5209
5305
  base54.reset();
@@ -6285,7 +6381,8 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
6285
6381
  let single_use = def.single_use
6286
6382
  && !(parent instanceof AST_Call
6287
6383
  && (parent.is_expr_pure(compressor))
6288
- || has_annotation(parent, _NOINLINE));
6384
+ || has_annotation(parent, _NOINLINE))
6385
+ && !(fixed instanceof AST_Defun && parent instanceof AST_Export);
6289
6386
 
6290
6387
  if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
6291
6388
  if (retain_top_func(fixed, compressor)) {
@@ -6386,8 +6483,8 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
6386
6483
  }
6387
6484
 
6388
6485
  if (replace) {
6389
- const name_length = def.name.length;
6390
- const replace_size = replace.size();
6486
+ const name_length = self.size(compressor);
6487
+ const replace_size = replace.size(compressor);
6391
6488
 
6392
6489
  let overhead = 0;
6393
6490
  if (compressor.option("unused") && !compressor.exposed(def)) {
@@ -6592,6 +6689,10 @@ function is_nullish(node) {
6592
6689
  && (fixed = node.definition().fixed) instanceof AST_Node
6593
6690
  && is_nullish(fixed)
6594
6691
  )
6692
+ // Recurse into those optional chains!
6693
+ || node instanceof AST_PropAccess && node.optional && is_nullish(node.expression)
6694
+ || node instanceof AST_Call && node.optional && is_nullish(node.expression)
6695
+ || node instanceof AST_Chain && is_nullish(node.expression)
6595
6696
  );
6596
6697
  }
6597
6698
 
@@ -6974,6 +7075,41 @@ function safe_to_flatten(value, compressor) {
6974
7075
  return compressor.parent() instanceof AST_New;
6975
7076
  }
6976
7077
 
7078
+ AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
7079
+ if (!compressor.option("properties")) return;
7080
+ var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 2015;
7081
+ var expr = this.expression;
7082
+ if (expr instanceof AST_Object) {
7083
+ var props = expr.properties;
7084
+ for (var i = props.length; --i >= 0;) {
7085
+ var prop = props[i];
7086
+ if ("" + (prop instanceof AST_ConciseMethod ? prop.key.name : prop.key) == key) {
7087
+ if (!props.every((prop) => {
7088
+ return prop instanceof AST_ObjectKeyVal
7089
+ || arrows && prop instanceof AST_ConciseMethod && !prop.is_generator;
7090
+ })) break;
7091
+ if (!safe_to_flatten(prop.value, compressor)) break;
7092
+ return make_node(AST_Sub, this, {
7093
+ expression: make_node(AST_Array, expr, {
7094
+ elements: props.map(function(prop) {
7095
+ var v = prop.value;
7096
+ if (v instanceof AST_Accessor) v = make_node(AST_Function, v, v);
7097
+ var k = prop.key;
7098
+ if (k instanceof AST_Node && !(k instanceof AST_SymbolMethod)) {
7099
+ return make_sequence(prop, [ k, v ]);
7100
+ }
7101
+ return v;
7102
+ })
7103
+ }),
7104
+ property: make_node(AST_Number, this, {
7105
+ value: i
7106
+ })
7107
+ });
7108
+ }
7109
+ }
7110
+ }
7111
+ });
7112
+
6977
7113
  def_optimize(AST_Sub, function(self, compressor) {
6978
7114
  var expr = self.expression;
6979
7115
  var prop = self.property;
@@ -6996,6 +7132,7 @@ def_optimize(AST_Sub, function(self, compressor) {
6996
7132
  && property.length <= prop.size() + 1) {
6997
7133
  return make_node(AST_Dot, self, {
6998
7134
  expression: expr,
7135
+ optional: self.optional,
6999
7136
  property: property,
7000
7137
  quote: prop.quote,
7001
7138
  }).optimize(compressor);
@@ -7098,6 +7235,14 @@ def_optimize(AST_Sub, function(self, compressor) {
7098
7235
  ev = make_node_from_constant(ev, self).optimize(compressor);
7099
7236
  return best_of(compressor, ev, self);
7100
7237
  }
7238
+ if (self.optional && is_nullish(self.expression)) {
7239
+ return make_node(AST_Undefined, self);
7240
+ }
7241
+ return self;
7242
+ });
7243
+
7244
+ def_optimize(AST_Chain, function (self, compressor) {
7245
+ self.expression = self.expression.optimize(compressor);
7101
7246
  return self;
7102
7247
  });
7103
7248
 
@@ -7114,41 +7259,6 @@ AST_Lambda.DEFMETHOD("contains_this", function() {
7114
7259
  });
7115
7260
  });
7116
7261
 
7117
- AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
7118
- if (!compressor.option("properties")) return;
7119
- var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 2015;
7120
- var expr = this.expression;
7121
- if (expr instanceof AST_Object) {
7122
- var props = expr.properties;
7123
- for (var i = props.length; --i >= 0;) {
7124
- var prop = props[i];
7125
- if ("" + (prop instanceof AST_ConciseMethod ? prop.key.name : prop.key) == key) {
7126
- if (!props.every((prop) => {
7127
- return prop instanceof AST_ObjectKeyVal
7128
- || arrows && prop instanceof AST_ConciseMethod && !prop.is_generator;
7129
- })) break;
7130
- if (!safe_to_flatten(prop.value, compressor)) break;
7131
- return make_node(AST_Sub, this, {
7132
- expression: make_node(AST_Array, expr, {
7133
- elements: props.map(function(prop) {
7134
- var v = prop.value;
7135
- if (v instanceof AST_Accessor) v = make_node(AST_Function, v, v);
7136
- var k = prop.key;
7137
- if (k instanceof AST_Node && !(k instanceof AST_SymbolMethod)) {
7138
- return make_sequence(prop, [ k, v ]);
7139
- }
7140
- return v;
7141
- })
7142
- }),
7143
- property: make_node(AST_Number, this, {
7144
- value: i
7145
- })
7146
- });
7147
- }
7148
- }
7149
- }
7150
- });
7151
-
7152
7262
  def_optimize(AST_Dot, function(self, compressor) {
7153
7263
  const parent = compressor.parent();
7154
7264
  if (is_lhs(self, parent)) return self;
@@ -7199,6 +7309,9 @@ def_optimize(AST_Dot, function(self, compressor) {
7199
7309
  ev = make_node_from_constant(ev, self).optimize(compressor);
7200
7310
  return best_of(compressor, ev, self);
7201
7311
  }
7312
+ if (self.optional && is_nullish(self.expression)) {
7313
+ return make_node(AST_Undefined, self);
7314
+ }
7202
7315
  return self;
7203
7316
  });
7204
7317
 
@@ -7282,10 +7395,10 @@ def_optimize(AST_Function, function(self, compressor) {
7282
7395
  && !self.is_generator
7283
7396
  && !self.uses_arguments
7284
7397
  && !self.pinned()) {
7285
- const has_special_symbol = walk(self, node => {
7398
+ const uses_this = walk(self, node => {
7286
7399
  if (node instanceof AST_This) return walk_abort;
7287
7400
  });
7288
- if (!has_special_symbol) return make_node(AST_Arrow, self, self).optimize(compressor);
7401
+ if (!uses_this) return make_node(AST_Arrow, self, self).optimize(compressor);
7289
7402
  }
7290
7403
  return self;
7291
7404
  });
@@ -26,6 +26,7 @@ import {
26
26
  AST_ForOf,
27
27
  AST_If,
28
28
  AST_Import,
29
+ AST_ImportMeta,
29
30
  AST_Jump,
30
31
  AST_LabeledStatement,
31
32
  AST_Lambda,
@@ -209,6 +210,8 @@ AST_Import.prototype.shallow_cmp = mkshallow({
209
210
  imported_names: "exist"
210
211
  });
211
212
 
213
+ AST_ImportMeta.prototype.shallow_cmp = pass_through;
214
+
212
215
  AST_Export.prototype.shallow_cmp = mkshallow({
213
216
  exported_definition: "exist",
214
217
  exported_value: "exist",
package/lib/minify.js CHANGED
@@ -181,7 +181,11 @@ async function minify(files, options) {
181
181
  toplevel.expand_names(options.mangle);
182
182
  }
183
183
  if (timings) timings.compress = Date.now();
184
- if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel);
184
+ if (options.compress) {
185
+ toplevel = new Compressor(options.compress, {
186
+ mangle_options: options.mangle
187
+ }).compress(toplevel);
188
+ }
185
189
  if (timings) timings.scope = Date.now();
186
190
  if (options.mangle) toplevel.figure_out_scope(options.mangle);
187
191
  if (timings) timings.mangle = Date.now();
@@ -59,6 +59,7 @@ import {
59
59
  AST_Call,
60
60
  AST_Case,
61
61
  AST_Catch,
62
+ AST_Chain,
62
63
  AST_Class,
63
64
  AST_ClassExpression,
64
65
  AST_ClassProperty,
@@ -89,6 +90,7 @@ import {
89
90
  AST_Hole,
90
91
  AST_If,
91
92
  AST_Import,
93
+ AST_ImportMeta,
92
94
  AST_Label,
93
95
  AST_LabeledStatement,
94
96
  AST_LabelRef,
@@ -418,7 +420,15 @@ import {
418
420
  start : my_start_token(M),
419
421
  end : my_end_token(M),
420
422
  property : M.computed ? from_moz(M.property) : M.property.name,
421
- expression : from_moz(M.object)
423
+ expression : from_moz(M.object),
424
+ optional : M.optional || false
425
+ });
426
+ },
427
+ ChainExpression: function(M) {
428
+ return new AST_Chain({
429
+ start : my_start_token(M),
430
+ end : my_end_token(M),
431
+ expression : from_moz(M.expression)
422
432
  });
423
433
  },
424
434
  SwitchCase: function(M) {
@@ -545,6 +555,11 @@ import {
545
555
  start: my_start_token(M),
546
556
  end: my_end_token(M)
547
557
  });
558
+ } else if (M.meta.name === "import" && M.property.name === "meta") {
559
+ return new AST_ImportMeta({
560
+ start: my_start_token(M),
561
+ end: my_end_token(M)
562
+ });
548
563
  }
549
564
  },
550
565
  Identifier: function(M) {
@@ -629,7 +644,7 @@ import {
629
644
  map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
630
645
  map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
631
646
  map("NewExpression", AST_New, "callee>expression, arguments@args");
632
- map("CallExpression", AST_Call, "callee>expression, arguments@args");
647
+ map("CallExpression", AST_Call, "callee>expression, optional=optional, arguments@args");
633
648
 
634
649
  def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
635
650
  return to_moz_scope("Program", M);
@@ -836,6 +851,20 @@ import {
836
851
  };
837
852
  });
838
853
 
854
+ def_to_moz(AST_ImportMeta, function To_Moz_MetaProperty() {
855
+ return {
856
+ type: "MetaProperty",
857
+ meta: {
858
+ type: "Identifier",
859
+ name: "import"
860
+ },
861
+ property: {
862
+ type: "Identifier",
863
+ name: "meta"
864
+ }
865
+ };
866
+ });
867
+
839
868
  def_to_moz(AST_Sequence, function To_Moz_SequenceExpression(M) {
840
869
  return {
841
870
  type: "SequenceExpression",
@@ -849,7 +878,15 @@ import {
849
878
  type: "MemberExpression",
850
879
  object: to_moz(M.expression),
851
880
  computed: isComputed,
852
- property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property}
881
+ property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property},
882
+ optional: M.optional
883
+ };
884
+ });
885
+
886
+ def_to_moz(AST_Chain, function To_Moz_ChainExpression(M) {
887
+ return {
888
+ type: "ChainExpression",
889
+ expression: to_moz(M.expression)
853
890
  };
854
891
  });
855
892