terser 5.5.1 → 5.7.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
@@ -522,6 +522,21 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator as
522
522
 
523
523
  if (this.name) push(this.name);
524
524
  },
525
+ is_braceless() {
526
+ return this.body[0] instanceof AST_Return && this.body[0].value;
527
+ },
528
+ // Default args and expansion don't count, so .argnames.length doesn't cut it
529
+ length_property() {
530
+ let length = 0;
531
+
532
+ for (const arg of this.argnames) {
533
+ if (arg instanceof AST_SymbolFunarg || arg instanceof AST_Destructuring) {
534
+ length++;
535
+ }
536
+ }
537
+
538
+ return length;
539
+ }
525
540
  }, AST_Scope);
526
541
 
527
542
  var AST_Accessor = DEFNODE("Accessor", null, {
@@ -1007,7 +1022,7 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression property optional", {
1007
1022
  $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
1008
1023
  $propdoc: {
1009
1024
  expression: "[AST_Node] the “container” expression",
1010
- 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",
1025
+ property: "[AST_Node|string] the property to access. For AST_Dot & AST_DotHash this is always a plain string, while for AST_Sub it's an arbitrary AST_Node",
1011
1026
 
1012
1027
  optional: "[boolean] whether this is an optional property access (IE ?.)"
1013
1028
  }
@@ -1028,6 +1043,18 @@ var AST_Dot = DEFNODE("Dot", "quote", {
1028
1043
  },
1029
1044
  }, AST_PropAccess);
1030
1045
 
1046
+ var AST_DotHash = DEFNODE("DotHash", "", {
1047
+ $documentation: "A dotted property access to a private property",
1048
+ _walk: function(visitor) {
1049
+ return visitor._visit(this, function() {
1050
+ this.expression._walk(visitor);
1051
+ });
1052
+ },
1053
+ _children_backwards(push) {
1054
+ push(this.expression);
1055
+ },
1056
+ }, AST_PropAccess);
1057
+
1031
1058
  var AST_Sub = DEFNODE("Sub", null, {
1032
1059
  $documentation: "Index-style property access, i.e. `a[\"foo\"]`",
1033
1060
  _walk: function(visitor) {
@@ -1045,7 +1072,7 @@ var AST_Sub = DEFNODE("Sub", null, {
1045
1072
  var AST_Chain = DEFNODE("Chain", "expression", {
1046
1073
  $documentation: "A chain expression like a?.b?.(c)?.[d]",
1047
1074
  $propdoc: {
1048
- expression: "[AST_Call|AST_Dot|AST_Sub] chain element."
1075
+ expression: "[AST_Call|AST_Dot|AST_DotHash|AST_Sub] chain element."
1049
1076
  },
1050
1077
  _walk: function (visitor) {
1051
1078
  return visitor._visit(this, function() {
@@ -1201,6 +1228,26 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
1201
1228
  }
1202
1229
  }, AST_ObjectProperty);
1203
1230
 
1231
+ var AST_PrivateSetter = DEFNODE("PrivateSetter", "static", {
1232
+ $propdoc: {
1233
+ static: "[boolean] whether this is a static private setter"
1234
+ },
1235
+ $documentation: "A private setter property",
1236
+ computed_key() {
1237
+ return false;
1238
+ }
1239
+ }, AST_ObjectProperty);
1240
+
1241
+ var AST_PrivateGetter = DEFNODE("PrivateGetter", "static", {
1242
+ $propdoc: {
1243
+ static: "[boolean] whether this is a static private getter"
1244
+ },
1245
+ $documentation: "A private getter property",
1246
+ computed_key() {
1247
+ return false;
1248
+ }
1249
+ }, AST_ObjectProperty);
1250
+
1204
1251
  var AST_ObjectSetter = DEFNODE("ObjectSetter", "quote static", {
1205
1252
  $propdoc: {
1206
1253
  quote: "[string|undefined] the original quote character, if any",
@@ -1236,6 +1283,10 @@ var AST_ConciseMethod = DEFNODE("ConciseMethod", "quote static is_generator asyn
1236
1283
  }
1237
1284
  }, AST_ObjectProperty);
1238
1285
 
1286
+ var AST_PrivateMethod = DEFNODE("PrivateMethod", "", {
1287
+ $documentation: "A private class method inside a class",
1288
+ }, AST_ConciseMethod);
1289
+
1239
1290
  var AST_Class = DEFNODE("Class", "name extends properties", {
1240
1291
  $propdoc: {
1241
1292
  name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.",
@@ -1285,6 +1336,10 @@ var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", {
1285
1336
  }
1286
1337
  }, AST_ObjectProperty);
1287
1338
 
1339
+ var AST_ClassPrivateProperty = DEFNODE("ClassProperty", "", {
1340
+ $documentation: "A class property for a private property",
1341
+ }, AST_ClassProperty);
1342
+
1288
1343
  var AST_DefClass = DEFNODE("DefClass", null, {
1289
1344
  $documentation: "A class definition",
1290
1345
  }, AST_Class);
@@ -1684,6 +1739,7 @@ export {
1684
1739
  AST_Chain,
1685
1740
  AST_Class,
1686
1741
  AST_ClassExpression,
1742
+ AST_ClassPrivateProperty,
1687
1743
  AST_ClassProperty,
1688
1744
  AST_ConciseMethod,
1689
1745
  AST_Conditional,
@@ -1700,6 +1756,7 @@ export {
1700
1756
  AST_Directive,
1701
1757
  AST_Do,
1702
1758
  AST_Dot,
1759
+ AST_DotHash,
1703
1760
  AST_DWLoop,
1704
1761
  AST_EmptyStatement,
1705
1762
  AST_Exit,
@@ -1737,6 +1794,9 @@ export {
1737
1794
  AST_ObjectProperty,
1738
1795
  AST_ObjectSetter,
1739
1796
  AST_PrefixedTemplateString,
1797
+ AST_PrivateGetter,
1798
+ AST_PrivateMethod,
1799
+ AST_PrivateSetter,
1740
1800
  AST_PropAccess,
1741
1801
  AST_RegExp,
1742
1802
  AST_Return,
package/lib/cli.js CHANGED
@@ -42,7 +42,7 @@ export async function run_cli({ program, packageJson, fs, path }) {
42
42
  program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
43
43
  program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
44
44
  program.option("-f, --format [options]", "Format options.", parse_js());
45
- program.option("-b, --beautify [options]", "Alias for --format beautify=true.", parse_js());
45
+ program.option("-b, --beautify [options]", "Alias for --format.", parse_js());
46
46
  program.option("-o, --output <file>", "Output file (default STDOUT).");
47
47
  program.option("--comments [filter]", "Preserve copyright comments in the output.");
48
48
  program.option("--config-file <file>", "Read minify() options from JSON file.");
@@ -93,19 +93,9 @@ export async function run_cli({ program, packageJson, fs, path }) {
93
93
  else
94
94
  options.ecma = ecma;
95
95
  }
96
- if (program.beautify || program.format) {
97
- if (program.beautify && program.format) {
98
- fatal("Please only specify one of --beautify or --format");
99
- }
100
- if (program.beautify) {
101
- options.format = typeof program.beautify == "object" ? program.beautify : {};
102
- if (!("beautify" in options.format)) {
103
- options.format.beautify = true;
104
- }
105
- }
106
- if (program.format) {
107
- options.format = typeof program.format == "object" ? program.format : {};
108
- }
96
+ if (program.format || program.beautify) {
97
+ const chosenOption = program.format || program.beautify;
98
+ options.format = typeof chosenOption === "object" ? chosenOption : {};
109
99
  }
110
100
  if (program.comments) {
111
101
  if (typeof options.format != "object") options.format = {};
@@ -209,11 +209,8 @@ const TOP = 0b0000010000000000;
209
209
 
210
210
  const CLEAR_BETWEEN_PASSES = SQUEEZED | OPTIMIZED | TOP;
211
211
 
212
- /*@__INLINE__*/
213
212
  const has_flag = (node, flag) => node.flags & flag;
214
- /*@__INLINE__*/
215
213
  const set_flag = (node, flag) => { node.flags |= flag; };
216
- /*@__INLINE__*/
217
214
  const clear_flag = (node, flag) => { node.flags &= ~flag; };
218
215
 
219
216
  class Compressor extends TreeWalker {
@@ -256,7 +253,7 @@ class Compressor extends TreeWalker {
256
253
  properties : !false_by_default,
257
254
  pure_getters : !false_by_default && "strict",
258
255
  pure_funcs : null,
259
- reduce_funcs : null, // legacy
256
+ reduce_funcs : !false_by_default,
260
257
  reduce_vars : !false_by_default,
261
258
  sequences : !false_by_default,
262
259
  side_effects : !false_by_default,
@@ -556,7 +553,7 @@ function is_modified(compressor, tw, node, value, level, immutable) {
556
553
  && parent.expression === node
557
554
  && !(value instanceof AST_Arrow)
558
555
  && !(value instanceof AST_Class)
559
- && !parent.is_expr_pure(compressor)
556
+ && !parent.is_callee_pure(compressor)
560
557
  && (!(value instanceof AST_Function)
561
558
  || !(parent instanceof AST_New) && value.contains_this())) {
562
559
  return true;
@@ -861,9 +858,6 @@ function is_modified(compressor, tw, node, value, level, immutable) {
861
858
  return true;
862
859
  });
863
860
  def_reduce_vars(AST_Call, function (tw) {
864
- // TODO this block should just be { return } but
865
- // for some reason the _walk function of AST_Call walks the callee last
866
-
867
861
  this.expression.walk(tw);
868
862
 
869
863
  if (this.optional) {
@@ -1416,8 +1410,11 @@ function tighten_body(statements, compressor) {
1416
1410
  || node instanceof AST_Debugger
1417
1411
  || node instanceof AST_Destructuring
1418
1412
  || node instanceof AST_Expansion
1419
- && node.expression instanceof AST_Symbol
1420
- && node.expression.definition().references.length > 1
1413
+ && node.expression instanceof AST_Symbol
1414
+ && (
1415
+ node.expression instanceof AST_This
1416
+ || node.expression.definition().references.length > 1
1417
+ )
1421
1418
  || node instanceof AST_IterationStatement && !(node instanceof AST_For)
1422
1419
  || node instanceof AST_LoopControl
1423
1420
  || node instanceof AST_Try
@@ -2586,7 +2583,13 @@ function is_undefined(node, compressor) {
2586
2583
  });
2587
2584
  def_may_throw_on_access(AST_Dot, function(compressor) {
2588
2585
  if (!is_strict(compressor)) return false;
2589
- if (this.expression instanceof AST_Function && this.property == "prototype") return false;
2586
+
2587
+ if (this.property == "prototype") {
2588
+ return !(
2589
+ this.expression instanceof AST_Function
2590
+ || this.expression instanceof AST_Class
2591
+ );
2592
+ }
2590
2593
  return true;
2591
2594
  });
2592
2595
  def_may_throw_on_access(AST_Chain, function(compressor) {
@@ -2928,9 +2931,7 @@ var static_fns = convert_to_predicate({
2928
2931
  if (compressor.option("unsafe")) {
2929
2932
  var fn = function() {};
2930
2933
  fn.node = this;
2931
- fn.toString = function() {
2932
- return this.node.print_to_string();
2933
- };
2934
+ fn.toString = () => this.print_to_string();
2934
2935
  return fn;
2935
2936
  }
2936
2937
  return this;
@@ -3111,6 +3112,14 @@ var static_fns = convert_to_predicate({
3111
3112
  "POSITIVE_INFINITY",
3112
3113
  ],
3113
3114
  });
3115
+ const regexp_flags = new Set([
3116
+ "dotAll",
3117
+ "global",
3118
+ "ignoreCase",
3119
+ "multiline",
3120
+ "sticky",
3121
+ "unicode",
3122
+ ]);
3114
3123
  def_eval(AST_PropAccess, function(compressor, depth) {
3115
3124
  if (this.optional) {
3116
3125
  const obj = this.expression._eval(compressor, depth);
@@ -3143,12 +3152,19 @@ var static_fns = convert_to_predicate({
3143
3152
  val = global_objs[exp.name];
3144
3153
  } else {
3145
3154
  val = exp._eval(compressor, depth + 1);
3155
+ if (val instanceof RegExp) {
3156
+ if (key == "source") {
3157
+ return regexp_source_fix(val.source);
3158
+ } else if (key == "flags" || regexp_flags.has(key)) {
3159
+ return val[key];
3160
+ }
3161
+ }
3146
3162
  if (!val || val === exp || !HOP(val, key)) return this;
3147
3163
  if (typeof val == "function") switch (key) {
3148
3164
  case "name":
3149
3165
  return val.node.name ? val.node.name.name : "";
3150
3166
  case "length":
3151
- return val.node.argnames.length;
3167
+ return val.node.length_property();
3152
3168
  default:
3153
3169
  return this;
3154
3170
  }
@@ -3200,6 +3216,7 @@ var static_fns = convert_to_predicate({
3200
3216
  var arg = this.args[i];
3201
3217
  var value = arg._eval(compressor, depth);
3202
3218
  if (arg === value) return this;
3219
+ if (arg instanceof AST_Lambda) return this;
3203
3220
  args.push(value);
3204
3221
  }
3205
3222
  try {
@@ -3299,7 +3316,7 @@ var static_fns = convert_to_predicate({
3299
3316
  });
3300
3317
 
3301
3318
  var global_pure_fns = makePredicate("Boolean decodeURI decodeURIComponent Date encodeURI encodeURIComponent Error escape EvalError isFinite isNaN Number Object parseFloat parseInt RangeError ReferenceError String SyntaxError TypeError unescape URIError");
3302
- AST_Call.DEFMETHOD("is_expr_pure", function(compressor) {
3319
+ AST_Call.DEFMETHOD("is_callee_pure", function(compressor) {
3303
3320
  if (compressor.option("unsafe")) {
3304
3321
  var expr = this.expression;
3305
3322
  var first_arg = (this.args && this.args[0] && this.args[0].evaluate(compressor));
@@ -3369,7 +3386,7 @@ const pure_prop_access_globals = new Set([
3369
3386
  });
3370
3387
  def_has_side_effects(AST_Call, function(compressor) {
3371
3388
  if (
3372
- !this.is_expr_pure(compressor)
3389
+ !this.is_callee_pure(compressor)
3373
3390
  && (!this.expression.is_call_pure(compressor)
3374
3391
  || this.expression.has_side_effects(compressor))
3375
3392
  ) {
@@ -3433,7 +3450,7 @@ const pure_prop_access_globals = new Set([
3433
3450
  def_has_side_effects(AST_ObjectProperty, function(compressor) {
3434
3451
  return (
3435
3452
  this.computed_key() && this.key.has_side_effects(compressor)
3436
- || this.value.has_side_effects(compressor)
3453
+ || this.value && this.value.has_side_effects(compressor)
3437
3454
  );
3438
3455
  });
3439
3456
  def_has_side_effects(AST_ClassProperty, function(compressor) {
@@ -3531,7 +3548,7 @@ const pure_prop_access_globals = new Set([
3531
3548
  def_may_throw(AST_Call, function(compressor) {
3532
3549
  if (this.optional && is_nullish(this.expression)) return false;
3533
3550
  if (any(this.args, compressor)) return true;
3534
- if (this.is_expr_pure(compressor)) return false;
3551
+ if (this.is_callee_pure(compressor)) return false;
3535
3552
  if (this.expression.may_throw(compressor)) return true;
3536
3553
  return !(this.expression instanceof AST_Lambda)
3537
3554
  || any(this.expression.body, compressor);
@@ -3561,7 +3578,7 @@ const pure_prop_access_globals = new Set([
3561
3578
  });
3562
3579
  def_may_throw(AST_ObjectProperty, function(compressor) {
3563
3580
  // TODO key may throw too
3564
- return this.value.may_throw(compressor);
3581
+ return this.value ? this.value.may_throw(compressor) : false;
3565
3582
  });
3566
3583
  def_may_throw(AST_ClassProperty, function(compressor) {
3567
3584
  return (
@@ -3695,7 +3712,7 @@ const pure_prop_access_globals = new Set([
3695
3712
  return this.properties.every((l) => l.is_constant_expression());
3696
3713
  });
3697
3714
  def_is_constant_expression(AST_ObjectProperty, function() {
3698
- return !(this.key instanceof AST_Node) && this.value.is_constant_expression();
3715
+ return !!(!(this.key instanceof AST_Node) && this.value && this.value.is_constant_expression());
3699
3716
  });
3700
3717
  })(function(node, func) {
3701
3718
  node.DEFMETHOD("is_constant_expression", func);
@@ -4409,7 +4426,7 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
4409
4426
  return make_node(AST_Undefined, this);
4410
4427
  }
4411
4428
 
4412
- if (!this.is_expr_pure(compressor)) {
4429
+ if (!this.is_callee_pure(compressor)) {
4413
4430
  if (this.expression.is_call_pure(compressor)) {
4414
4431
  var exprs = this.args.slice();
4415
4432
  exprs.unshift(this.expression.expression);
@@ -4522,7 +4539,7 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
4522
4539
  def_drop_side_effect_free(AST_ObjectProperty, function(compressor, first_in_statement) {
4523
4540
  const computed_key = this instanceof AST_ObjectKeyVal && this.key instanceof AST_Node;
4524
4541
  const key = computed_key && this.key.drop_side_effect_free(compressor, first_in_statement);
4525
- const value = this.value.drop_side_effect_free(compressor, first_in_statement);
4542
+ const value = this.value && this.value.drop_side_effect_free(compressor, first_in_statement);
4526
4543
  if (key && value) {
4527
4544
  return make_sequence(this, [key, value]);
4528
4545
  }
@@ -5429,7 +5446,7 @@ def_optimize(AST_Call, function(self, compressor) {
5429
5446
 
5430
5447
  var stat = is_func && fn.body[0];
5431
5448
  var is_regular_func = is_func && !fn.is_generator && !fn.async;
5432
- var can_inline = is_regular_func && compressor.option("inline") && !self.is_expr_pure(compressor);
5449
+ var can_inline = is_regular_func && compressor.option("inline") && !self.is_callee_pure(compressor);
5433
5450
  if (can_inline && stat instanceof AST_Return) {
5434
5451
  let returned = stat.value;
5435
5452
  if (!returned || returned.is_constant_expression()) {
@@ -6455,19 +6472,26 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
6455
6472
  let fixed = self.fixed_value();
6456
6473
  let single_use = def.single_use
6457
6474
  && !(parent instanceof AST_Call
6458
- && (parent.is_expr_pure(compressor))
6475
+ && (parent.is_callee_pure(compressor))
6459
6476
  || has_annotation(parent, _NOINLINE))
6460
6477
  && !(parent instanceof AST_Export
6461
6478
  && fixed instanceof AST_Lambda
6462
6479
  && fixed.name);
6463
6480
 
6481
+ if (single_use && fixed instanceof AST_Node) {
6482
+ single_use =
6483
+ !fixed.has_side_effects(compressor)
6484
+ && !fixed.may_throw(compressor);
6485
+ }
6486
+
6464
6487
  if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
6465
6488
  if (retain_top_func(fixed, compressor)) {
6466
6489
  single_use = false;
6467
6490
  } else if (def.scope !== self.scope
6468
6491
  && (def.escaped == 1
6469
6492
  || has_flag(fixed, INLINED)
6470
- || within_array_or_object_literal(compressor))) {
6493
+ || within_array_or_object_literal(compressor)
6494
+ || !compressor.option("reduce_funcs"))) {
6471
6495
  single_use = false;
6472
6496
  } else if (recursive_ref(compressor, def)) {
6473
6497
  single_use = false;
@@ -6483,6 +6507,7 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
6483
6507
  }
6484
6508
  }
6485
6509
  }
6510
+
6486
6511
  if (single_use && fixed instanceof AST_Lambda) {
6487
6512
  single_use =
6488
6513
  def.scope === self.scope
@@ -6492,15 +6517,6 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
6492
6517
  && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
6493
6518
  && !(fixed.name && fixed.name.definition().recursive_refs > 0);
6494
6519
  }
6495
- if (single_use && fixed instanceof AST_Class) {
6496
- const extends_inert = !fixed.extends
6497
- || !fixed.extends.may_throw(compressor)
6498
- && !fixed.extends.has_side_effects(compressor);
6499
- single_use = extends_inert
6500
- && !fixed.properties.some(prop =>
6501
- prop.may_throw(compressor) || prop.has_side_effects(compressor)
6502
- );
6503
- }
6504
6520
 
6505
6521
  if (single_use && fixed) {
6506
6522
  if (fixed instanceof AST_DefClass) {
@@ -6577,6 +6593,7 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
6577
6593
  }
6578
6594
  }
6579
6595
  }
6596
+
6580
6597
  return self;
6581
6598
  });
6582
6599
 
@@ -7163,27 +7180,40 @@ function safe_to_flatten(value, compressor) {
7163
7180
 
7164
7181
  AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
7165
7182
  if (!compressor.option("properties")) return;
7183
+ if (key === "__proto__") return;
7184
+
7166
7185
  var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 2015;
7167
7186
  var expr = this.expression;
7168
7187
  if (expr instanceof AST_Object) {
7169
7188
  var props = expr.properties;
7189
+
7170
7190
  for (var i = props.length; --i >= 0;) {
7171
7191
  var prop = props[i];
7192
+
7172
7193
  if ("" + (prop instanceof AST_ConciseMethod ? prop.key.name : prop.key) == key) {
7173
- if (!props.every((prop) => {
7174
- return prop instanceof AST_ObjectKeyVal
7175
- || arrows && prop instanceof AST_ConciseMethod && !prop.is_generator;
7176
- })) break;
7177
- if (!safe_to_flatten(prop.value, compressor)) break;
7194
+ const all_props_flattenable = props.every((p) =>
7195
+ (p instanceof AST_ObjectKeyVal
7196
+ || arrows && p instanceof AST_ConciseMethod && !p.is_generator
7197
+ )
7198
+ && !p.computed_key()
7199
+ );
7200
+
7201
+ if (!all_props_flattenable) return;
7202
+ if (!safe_to_flatten(prop.value, compressor)) return;
7203
+
7178
7204
  return make_node(AST_Sub, this, {
7179
7205
  expression: make_node(AST_Array, expr, {
7180
7206
  elements: props.map(function(prop) {
7181
7207
  var v = prop.value;
7182
- if (v instanceof AST_Accessor) v = make_node(AST_Function, v, v);
7208
+ if (v instanceof AST_Accessor) {
7209
+ v = make_node(AST_Function, v, v);
7210
+ }
7211
+
7183
7212
  var k = prop.key;
7184
7213
  if (k instanceof AST_Node && !(k instanceof AST_SymbolMethod)) {
7185
7214
  return make_sequence(prop, [ k, v ]);
7186
7215
  }
7216
+
7187
7217
  return v;
7188
7218
  })
7189
7219
  }),
package/lib/minify.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  map_to_object,
8
8
  HOP,
9
9
  } from "./utils/index.js";
10
- import { AST_Toplevel } from "./ast.js";
10
+ import { AST_Toplevel, AST_Node } from "./ast.js";
11
11
  import { parse } from "./parse.js";
12
12
  import { OutputStream } from "./output.js";
13
13
  import { Compressor } from "./compress/index.js";
@@ -77,6 +77,7 @@ async function minify(files, options) {
77
77
  rename: undefined,
78
78
  safari10: false,
79
79
  sourceMap: false,
80
+ spidermonkey: false,
80
81
  timings: false,
81
82
  toplevel: false,
82
83
  warnings: false,
@@ -148,20 +149,32 @@ async function minify(files, options) {
148
149
  if (files instanceof AST_Toplevel) {
149
150
  toplevel = files;
150
151
  } else {
151
- if (typeof files == "string") {
152
+ if (typeof files == "string" || (options.parse.spidermonkey && !Array.isArray(files))) {
152
153
  files = [ files ];
153
154
  }
154
155
  options.parse = options.parse || {};
155
156
  options.parse.toplevel = null;
156
- for (var name in files) if (HOP(files, name)) {
157
- options.parse.filename = name;
158
- options.parse.toplevel = parse(files[name], options.parse);
159
- if (options.sourceMap && options.sourceMap.content == "inline") {
160
- if (Object.keys(files).length > 1)
161
- throw new Error("inline source map only works with singular input");
162
- options.sourceMap.content = read_source_map(files[name]);
157
+
158
+ if (options.parse.spidermonkey) {
159
+ options.parse.toplevel = AST_Node.from_mozilla_ast(Object.keys(files).reduce(function(toplevel, name) {
160
+ if (!toplevel) return files[name];
161
+ toplevel.body = toplevel.body.concat(files[name].body);
162
+ return toplevel;
163
+ }, null));
164
+ } else {
165
+ delete options.parse.spidermonkey;
166
+
167
+ for (var name in files) if (HOP(files, name)) {
168
+ options.parse.filename = name;
169
+ options.parse.toplevel = parse(files[name], options.parse);
170
+ if (options.sourceMap && options.sourceMap.content == "inline") {
171
+ if (Object.keys(files).length > 1)
172
+ throw new Error("inline source map only works with singular input");
173
+ options.sourceMap.content = read_source_map(files[name]);
174
+ }
163
175
  }
164
176
  }
177
+
165
178
  toplevel = options.parse.toplevel;
166
179
  }
167
180
  if (quoted_props && options.mangle.properties.keep_quoted !== "strict") {
@@ -203,6 +216,9 @@ async function minify(files, options) {
203
216
  if (options.format.ast) {
204
217
  result.ast = toplevel;
205
218
  }
219
+ if (options.format.spidermonkey) {
220
+ result.ast = toplevel.to_mozilla_ast();
221
+ }
206
222
  if (!HOP(options.format, "code") || options.format.code) {
207
223
  if (options.sourceMap) {
208
224
  options.format.source_map = await SourceMap({
@@ -220,6 +236,7 @@ async function minify(files, options) {
220
236
  }
221
237
  delete options.format.ast;
222
238
  delete options.format.code;
239
+ delete options.format.spidermonkey;
223
240
  var stream = OutputStream(options.format);
224
241
  toplevel.print(stream);
225
242
  result.code = stream.get();