terser 5.6.1 → 5.8.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.
@@ -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/minify.js CHANGED
@@ -7,14 +7,14 @@ 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";
14
- import { base54 } from "./scope.js";
15
14
  import { SourceMap } from "./sourcemap.js";
16
15
  import {
17
16
  mangle_properties,
17
+ mangle_private_properties,
18
18
  reserve_quoted_keys,
19
19
  } from "./propmangle.js";
20
20
 
@@ -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") {
@@ -190,9 +203,9 @@ async function minify(files, options) {
190
203
  if (options.mangle) toplevel.figure_out_scope(options.mangle);
191
204
  if (timings) timings.mangle = Date.now();
192
205
  if (options.mangle) {
193
- base54.reset();
194
206
  toplevel.compute_char_frequency(options.mangle);
195
207
  toplevel.mangle_names(options.mangle);
208
+ toplevel = mangle_private_properties(toplevel, options.mangle);
196
209
  }
197
210
  if (timings) timings.properties = Date.now();
198
211
  if (options.mangle && options.mangle.properties) {
@@ -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();
package/lib/output.js CHANGED
@@ -159,7 +159,7 @@ import {
159
159
  is_basic_identifier_string,
160
160
  is_identifier_string,
161
161
  PRECEDENCE,
162
- RESERVED_WORDS,
162
+ ALL_RESERVED_WORDS,
163
163
  } from "./parse.js";
164
164
 
165
165
  const EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
@@ -349,11 +349,17 @@ function OutputStream(options) {
349
349
  var do_add_mapping = mappings ? function() {
350
350
  mappings.forEach(function(mapping) {
351
351
  try {
352
+ let { name, token } = mapping;
353
+ if (token.type == "name" || token.type === "privatename") {
354
+ name = token.value;
355
+ } else if (name instanceof AST_Symbol) {
356
+ name = token.type === "string" ? token.value : name.name;
357
+ }
352
358
  options.source_map.add(
353
359
  mapping.token.file,
354
360
  mapping.line, mapping.col,
355
361
  mapping.token.line, mapping.token.col,
356
- !mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name
362
+ is_basic_identifier_string(name) ? name : undefined
357
363
  );
358
364
  } catch(ex) {
359
365
  // Ignore bad mapping
@@ -1713,7 +1719,11 @@ function OutputStream(options) {
1713
1719
  // https://github.com/mishoo/UglifyJS2/issues/60
1714
1720
  if (noin) {
1715
1721
  parens = walk(node, node => {
1716
- if (node instanceof AST_Scope) return true;
1722
+ // Don't go into scopes -- except arrow functions:
1723
+ // https://github.com/terser/terser/issues/1019#issuecomment-877642607
1724
+ if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) {
1725
+ return true;
1726
+ }
1717
1727
  if (node instanceof AST_Binary && node.operator == "in") {
1718
1728
  return walk_abort; // makes walk() return true
1719
1729
  }
@@ -1783,7 +1793,7 @@ function OutputStream(options) {
1783
1793
  var expr = self.expression;
1784
1794
  expr.print(output);
1785
1795
  var prop = self.property;
1786
- var print_computed = RESERVED_WORDS.has(prop)
1796
+ var print_computed = ALL_RESERVED_WORDS.has(prop)
1787
1797
  ? output.option("ie8")
1788
1798
  : !is_identifier_string(
1789
1799
  prop,
@@ -1816,6 +1826,7 @@ function OutputStream(options) {
1816
1826
 
1817
1827
  if (self.optional) output.print("?");
1818
1828
  output.print(".#");
1829
+ output.add_mapping(self.end);
1819
1830
  output.print_name(prop);
1820
1831
  });
1821
1832
  DEFPRINT(AST_Sub, function(self, output) {
@@ -1964,7 +1975,7 @@ function OutputStream(options) {
1964
1975
  }
1965
1976
  return output.print(make_num(key));
1966
1977
  }
1967
- var print_string = RESERVED_WORDS.has(key)
1978
+ var print_string = ALL_RESERVED_WORDS.has(key)
1968
1979
  ? output.option("ie8")
1969
1980
  : (
1970
1981
  output.option("ecma") < 2015 || output.option("safari10")
@@ -1991,7 +2002,7 @@ function OutputStream(options) {
1991
2002
  output.option("ecma") >= 2015 || output.option("safari10")
1992
2003
  ) &&
1993
2004
  get_name(self.value) === self.key &&
1994
- !RESERVED_WORDS.has(self.key)
2005
+ !ALL_RESERVED_WORDS.has(self.key)
1995
2006
  ) {
1996
2007
  print_property_name(self.key, self.quote, output);
1997
2008
 
@@ -2269,8 +2280,10 @@ function OutputStream(options) {
2269
2280
  DEFMAP([
2270
2281
  AST_ObjectGetter,
2271
2282
  AST_ObjectSetter,
2283
+ AST_PrivateGetter,
2284
+ AST_PrivateSetter,
2272
2285
  ], function(output) {
2273
- output.add_mapping(this.start, this.key.name);
2286
+ output.add_mapping(this.key.end, this.key.name);
2274
2287
  });
2275
2288
 
2276
2289
  DEFMAP([ AST_ObjectProperty ], function(output) {
package/lib/parse.js CHANGED
@@ -102,7 +102,6 @@ import {
102
102
  AST_Label,
103
103
  AST_LabeledStatement,
104
104
  AST_LabelRef,
105
- AST_Lambda,
106
105
  AST_Let,
107
106
  AST_NameMapping,
108
107
  AST_New,
@@ -167,13 +166,15 @@ var LATEST_TEMPLATE_END = true;
167
166
 
168
167
  var KEYWORDS = "break case catch class const continue debugger default delete do else export extends finally for function if in instanceof let new return switch throw try typeof var void while with";
169
168
  var KEYWORDS_ATOM = "false null true";
170
- var RESERVED_WORDS = "enum implements import interface package private protected public static super this " + KEYWORDS_ATOM + " " + KEYWORDS;
169
+ var RESERVED_WORDS = "enum import super this " + KEYWORDS_ATOM + " " + KEYWORDS;
170
+ var ALL_RESERVED_WORDS = "implements interface package private protected public static " + RESERVED_WORDS;
171
171
  var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case yield await";
172
172
 
173
173
  KEYWORDS = makePredicate(KEYWORDS);
174
174
  RESERVED_WORDS = makePredicate(RESERVED_WORDS);
175
175
  KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
176
176
  KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
177
+ ALL_RESERVED_WORDS = makePredicate(ALL_RESERVED_WORDS);
177
178
 
178
179
  var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
179
180
 
@@ -1293,7 +1294,7 @@ function parse($TEXT, options) {
1293
1294
  if (is_if_body) {
1294
1295
  croak("classes are not allowed as the body of an if");
1295
1296
  }
1296
- return class_(AST_DefClass);
1297
+ return class_(AST_DefClass, is_export_default);
1297
1298
 
1298
1299
  case "function":
1299
1300
  next();
@@ -2488,7 +2489,7 @@ function parse($TEXT, options) {
2488
2489
  return new AST_Object({ properties: a });
2489
2490
  });
2490
2491
 
2491
- function class_(KindOfClass) {
2492
+ function class_(KindOfClass, is_export_default) {
2492
2493
  var start, method, class_name, extends_, a = [];
2493
2494
 
2494
2495
  S.input.push_directives_stack(); // Push directive stack, but not scope stack
@@ -2499,7 +2500,11 @@ function parse($TEXT, options) {
2499
2500
  }
2500
2501
 
2501
2502
  if (KindOfClass === AST_DefClass && !class_name) {
2502
- unexpected();
2503
+ if (is_export_default) {
2504
+ KindOfClass = AST_ClassExpression;
2505
+ } else {
2506
+ unexpected();
2507
+ }
2503
2508
  }
2504
2509
 
2505
2510
  if (S.token.value == "extends") {
@@ -2532,9 +2537,9 @@ function parse($TEXT, options) {
2532
2537
  }
2533
2538
 
2534
2539
  function concise_method_or_getset(name, start, is_class) {
2535
- var get_method_name_ast = function(name, start) {
2540
+ const get_symbol_ast = (name, SymbolClass = AST_SymbolMethod) => {
2536
2541
  if (typeof name === "string" || typeof name === "number") {
2537
- return new AST_SymbolMethod({
2542
+ return new SymbolClass({
2538
2543
  start,
2539
2544
  name: "" + name,
2540
2545
  end: prev()
@@ -2544,47 +2549,71 @@ function parse($TEXT, options) {
2544
2549
  }
2545
2550
  return name;
2546
2551
  };
2547
- const get_class_property_key_ast = (name) => {
2548
- if (typeof name === "string" || typeof name === "number") {
2549
- return new AST_SymbolClassProperty({
2550
- start: property_token,
2551
- end: property_token,
2552
- name: "" + name
2553
- });
2554
- } else if (name === null) {
2555
- unexpected();
2556
- }
2557
- return name;
2558
- };
2559
- var privatename = start.type == "privatename";
2552
+
2553
+ const is_not_method_start = () =>
2554
+ !is("punc", "(") && !is("punc", ",") && !is("punc", "}") && !is("operator", "=");
2555
+
2560
2556
  var is_async = false;
2561
2557
  var is_static = false;
2562
2558
  var is_generator = false;
2563
- var property_token = start;
2564
- if (is_class && name === "static" && !is("punc", "(")) {
2559
+ var is_private = false;
2560
+ var accessor_type = null;
2561
+
2562
+ if (is_class && name === "static" && is_not_method_start()) {
2565
2563
  is_static = true;
2566
- property_token = S.token;
2567
- privatename = property_token.type == "privatename";
2568
2564
  name = as_property_name();
2569
2565
  }
2570
- if (name === "async" && !is("punc", "(") && !is("punc", ",") && !is("punc", "}") && !is("operator", "=")) {
2566
+ if (name === "async" && is_not_method_start()) {
2571
2567
  is_async = true;
2572
- property_token = S.token;
2573
- privatename = property_token.type == "privatename";
2574
2568
  name = as_property_name();
2575
2569
  }
2576
- if (name === null) {
2570
+ if (prev().type === "operator" && prev().value === "*") {
2577
2571
  is_generator = true;
2578
- property_token = S.token;
2579
- privatename = property_token.type == "privatename";
2580
2572
  name = as_property_name();
2581
- if (name === null) {
2582
- unexpected();
2573
+ }
2574
+ if ((name === "get" || name === "set") && is_not_method_start()) {
2575
+ accessor_type = name;
2576
+ name = as_property_name();
2577
+ }
2578
+ if (prev().type === "privatename") {
2579
+ is_private = true;
2580
+ }
2581
+
2582
+ const property_token = prev();
2583
+
2584
+ if (accessor_type != null) {
2585
+ if (!is_private) {
2586
+ const AccessorClass = accessor_type === "get"
2587
+ ? AST_ObjectGetter
2588
+ : AST_ObjectSetter;
2589
+
2590
+ name = get_symbol_ast(name);
2591
+ return new AccessorClass({
2592
+ start,
2593
+ static: is_static,
2594
+ key: name,
2595
+ quote: name instanceof AST_SymbolMethod ? property_token.quote : undefined,
2596
+ value: create_accessor(),
2597
+ end: prev()
2598
+ });
2599
+ } else {
2600
+ const AccessorClass = accessor_type === "get"
2601
+ ? AST_PrivateGetter
2602
+ : AST_PrivateSetter;
2603
+
2604
+ return new AccessorClass({
2605
+ start,
2606
+ static: is_static,
2607
+ key: get_symbol_ast(name),
2608
+ value: create_accessor(),
2609
+ end: prev(),
2610
+ });
2583
2611
  }
2584
2612
  }
2613
+
2585
2614
  if (is("punc", "(")) {
2586
- name = get_method_name_ast(name, start);
2587
- const AST_MethodVariant = privatename
2615
+ name = get_symbol_ast(name);
2616
+ const AST_MethodVariant = is_private
2588
2617
  ? AST_PrivateMethod
2589
2618
  : AST_ConciseMethod;
2590
2619
  var node = new AST_MethodVariant({
@@ -2600,57 +2629,13 @@ function parse($TEXT, options) {
2600
2629
  });
2601
2630
  return node;
2602
2631
  }
2603
- const setter_token = S.token;
2604
- if ((name === "get" || name === "set") && setter_token.type === "privatename") {
2605
- next();
2606
-
2607
- const AST_AccessorVariant =
2608
- name === "get"
2609
- ? AST_PrivateGetter
2610
- : AST_PrivateSetter;
2611
-
2612
- return new AST_AccessorVariant({
2613
- start,
2614
- static: is_static,
2615
- key: get_method_name_ast(setter_token.value, start),
2616
- value: create_accessor(),
2617
- end: prev(),
2618
- });
2619
- }
2620
2632
 
2621
- if (name == "get") {
2622
- if (!is("punc") || is("punc", "[")) {
2623
- name = get_method_name_ast(as_property_name(), start);
2624
- return new AST_ObjectGetter({
2625
- start : start,
2626
- static: is_static,
2627
- key : name,
2628
- quote : name instanceof AST_SymbolMethod ?
2629
- setter_token.quote : undefined,
2630
- value : create_accessor(),
2631
- end : prev()
2632
- });
2633
- }
2634
- } else if (name == "set") {
2635
- if (!is("punc") || is("punc", "[")) {
2636
- name = get_method_name_ast(as_property_name(), start);
2637
- return new AST_ObjectSetter({
2638
- start : start,
2639
- static: is_static,
2640
- key : name,
2641
- quote : name instanceof AST_SymbolMethod ?
2642
- setter_token.quote : undefined,
2643
- value : create_accessor(),
2644
- end : prev()
2645
- });
2646
- }
2647
- }
2648
2633
  if (is_class) {
2649
- const key = get_class_property_key_ast(name, property_token);
2634
+ const key = get_symbol_ast(name, AST_SymbolClassProperty);
2650
2635
  const quote = key instanceof AST_SymbolClassProperty
2651
2636
  ? property_token.quote
2652
2637
  : undefined;
2653
- const AST_ClassPropertyVariant = privatename
2638
+ const AST_ClassPropertyVariant = is_private
2654
2639
  ? AST_ClassPrivateProperty
2655
2640
  : AST_ClassProperty;
2656
2641
  if (is("operator", "=")) {
@@ -2872,8 +2857,17 @@ function parse($TEXT, options) {
2872
2857
  semicolon();
2873
2858
  } else if ((node = statement(is_default)) instanceof AST_Definitions && is_default) {
2874
2859
  unexpected(node.start);
2875
- } else if (node instanceof AST_Definitions || node instanceof AST_Lambda || node instanceof AST_DefClass) {
2860
+ } else if (
2861
+ node instanceof AST_Definitions
2862
+ || node instanceof AST_Defun
2863
+ || node instanceof AST_DefClass
2864
+ ) {
2876
2865
  exported_definition = node;
2866
+ } else if (
2867
+ node instanceof AST_ClassExpression
2868
+ || node instanceof AST_Function
2869
+ ) {
2870
+ exported_value = node;
2877
2871
  } else if (node instanceof AST_SimpleStatement) {
2878
2872
  exported_value = node.body;
2879
2873
  } else {
@@ -3347,6 +3341,6 @@ export {
3347
3341
  JS_Parse_Error,
3348
3342
  parse,
3349
3343
  PRECEDENCE,
3350
- RESERVED_WORDS,
3344
+ ALL_RESERVED_WORDS,
3351
3345
  tokenizer,
3352
3346
  };
package/lib/propmangle.js CHANGED
@@ -59,6 +59,8 @@ import {
59
59
  AST_ObjectKeyVal,
60
60
  AST_ObjectProperty,
61
61
  AST_PrivateMethod,
62
+ AST_PrivateGetter,
63
+ AST_PrivateSetter,
62
64
  AST_Sequence,
63
65
  AST_String,
64
66
  AST_Sub,
@@ -140,28 +142,59 @@ function addStrings(node, add) {
140
142
  }));
141
143
  }
142
144
 
145
+ function mangle_private_properties(ast, options) {
146
+ var cprivate = -1;
147
+ var private_cache = new Map();
148
+ var nth_identifier = options.nth_identifier || base54;
149
+
150
+ ast = ast.transform(new TreeTransformer(function(node) {
151
+ if (
152
+ node instanceof AST_ClassPrivateProperty
153
+ || node instanceof AST_PrivateMethod
154
+ || node instanceof AST_PrivateGetter
155
+ || node instanceof AST_PrivateSetter
156
+ ) {
157
+ node.key.name = mangle_private(node.key.name);
158
+ } else if (node instanceof AST_DotHash) {
159
+ node.property = mangle_private(node.property);
160
+ }
161
+ }));
162
+ return ast;
163
+
164
+ function mangle_private(name) {
165
+ let mangled = private_cache.get(name);
166
+ if (!mangled) {
167
+ mangled = nth_identifier.get(++cprivate);
168
+ private_cache.set(name, mangled);
169
+ }
170
+
171
+ return mangled;
172
+ }
173
+ }
174
+
143
175
  function mangle_properties(ast, options) {
144
176
  options = defaults(options, {
145
177
  builtins: false,
146
178
  cache: null,
147
179
  debug: false,
148
180
  keep_quoted: false,
181
+ nth_identifier: base54,
149
182
  only_cache: false,
150
183
  regex: null,
151
184
  reserved: null,
152
185
  undeclared: false,
153
186
  }, true);
154
187
 
188
+ var nth_identifier = options.nth_identifier;
189
+
155
190
  var reserved_option = options.reserved;
156
191
  if (!Array.isArray(reserved_option)) reserved_option = [reserved_option];
157
192
  var reserved = new Set(reserved_option);
158
193
  if (!options.builtins) find_builtins(reserved);
159
194
 
160
195
  var cname = -1;
161
- var cprivate = -1;
162
196
 
163
197
  var cache;
164
- var private_cache = new Map();
165
198
  if (options.cache) {
166
199
  cache = options.cache.props;
167
200
  cache.forEach(function(mangled_name) {
@@ -184,27 +217,26 @@ function mangle_properties(ast, options) {
184
217
 
185
218
  var names_to_mangle = new Set();
186
219
  var unmangleable = new Set();
187
- var private_properties = new Set();
188
220
 
189
- var keep_quoted_strict = options.keep_quoted === "strict";
221
+ var keep_quoted = !!options.keep_quoted;
190
222
 
191
223
  // step 1: find candidates to mangle
192
224
  ast.walk(new TreeWalker(function(node) {
193
225
  if (
194
226
  node instanceof AST_ClassPrivateProperty
195
227
  || node instanceof AST_PrivateMethod
228
+ || node instanceof AST_PrivateGetter
229
+ || node instanceof AST_PrivateSetter
230
+ || node instanceof AST_DotHash
196
231
  ) {
197
- private_properties.add(node.key.name);
198
- } else if (node instanceof AST_DotHash) {
199
- private_properties.add(node.property);
232
+ // handled by mangle_private_properties
200
233
  } else if (node instanceof AST_ObjectKeyVal) {
201
- if (typeof node.key == "string" &&
202
- (!keep_quoted_strict || !node.quote)) {
234
+ if (typeof node.key == "string" && (!keep_quoted || !node.quote)) {
203
235
  add(node.key);
204
236
  }
205
237
  } else if (node instanceof AST_ObjectProperty) {
206
238
  // setter or getter, since KeyVal is handled above
207
- if (!keep_quoted_strict || !node.key.end.quote) {
239
+ if (!keep_quoted || !node.quote) {
208
240
  add(node.key.name);
209
241
  }
210
242
  } else if (node instanceof AST_Dot) {
@@ -217,11 +249,11 @@ function mangle_properties(ast, options) {
217
249
  declared = !(root.thedef && root.thedef.undeclared);
218
250
  }
219
251
  if (declared &&
220
- (!keep_quoted_strict || !node.quote)) {
252
+ (!keep_quoted || !node.quote)) {
221
253
  add(node.property);
222
254
  }
223
255
  } else if (node instanceof AST_Sub) {
224
- if (!keep_quoted_strict) {
256
+ if (!keep_quoted) {
225
257
  addStrings(node.property, add);
226
258
  }
227
259
  } else if (node instanceof AST_Call
@@ -237,25 +269,25 @@ function mangle_properties(ast, options) {
237
269
  if (
238
270
  node instanceof AST_ClassPrivateProperty
239
271
  || node instanceof AST_PrivateMethod
272
+ || node instanceof AST_PrivateGetter
273
+ || node instanceof AST_PrivateSetter
274
+ || node instanceof AST_DotHash
240
275
  ) {
241
- node.key.name = mangle_private(node.key.name);
242
- } else if (node instanceof AST_DotHash) {
243
- node.property = mangle_private(node.property);
276
+ // handled by mangle_private_properties
244
277
  } else if (node instanceof AST_ObjectKeyVal) {
245
- if (typeof node.key == "string" &&
246
- (!keep_quoted_strict || !node.quote)) {
278
+ if (typeof node.key == "string" && (!keep_quoted || !node.quote)) {
247
279
  node.key = mangle(node.key);
248
280
  }
249
281
  } else if (node instanceof AST_ObjectProperty) {
250
282
  // setter, getter, method or class field
251
- if (!keep_quoted_strict || !node.key.end.quote) {
283
+ if (!keep_quoted || !node.quote) {
252
284
  node.key.name = mangle(node.key.name);
253
285
  }
254
286
  } else if (node instanceof AST_Dot) {
255
- if (!keep_quoted_strict || !node.quote) {
287
+ if (!keep_quoted || !node.quote) {
256
288
  node.property = mangle(node.property);
257
289
  }
258
- } else if (!options.keep_quoted && node instanceof AST_Sub) {
290
+ } else if (!keep_quoted && node instanceof AST_Sub) {
259
291
  node.property = mangleStrings(node.property);
260
292
  } else if (node instanceof AST_Call
261
293
  && node.expression.print_to_string() == "Object.defineProperty") {
@@ -312,7 +344,7 @@ function mangle_properties(ast, options) {
312
344
  // either debug mode is off, or it is on and we could not use the mangled name
313
345
  if (!mangled) {
314
346
  do {
315
- mangled = base54(++cname);
347
+ mangled = nth_identifier.get(++cname);
316
348
  } while (!can_mangle(mangled));
317
349
  }
318
350
 
@@ -321,16 +353,6 @@ function mangle_properties(ast, options) {
321
353
  return mangled;
322
354
  }
323
355
 
324
- function mangle_private(name) {
325
- let mangled = private_cache.get(name);
326
- if (!mangled) {
327
- mangled = base54(++cprivate);
328
- private_cache.set(name, mangled);
329
- }
330
-
331
- return mangled;
332
- }
333
-
334
356
  function mangleStrings(node) {
335
357
  return node.transform(new TreeTransformer(function(node) {
336
358
  if (node instanceof AST_Sequence) {
@@ -350,4 +372,5 @@ function mangle_properties(ast, options) {
350
372
  export {
351
373
  reserve_quoted_keys,
352
374
  mangle_properties,
375
+ mangle_private_properties,
353
376
  };