terser 5.7.2 → 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.
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
  };
package/lib/scope.js CHANGED
@@ -667,8 +667,9 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
667
667
 
668
668
  function next_mangled(scope, options) {
669
669
  var ext = scope.enclosed;
670
+ var nth_identifier = options.nth_identifier;
670
671
  out: while (true) {
671
- var m = base54(++scope.cname);
672
+ var m = nth_identifier.get(++scope.cname);
672
673
  if (ALL_RESERVED_WORDS.has(m)) continue; // skip over "do"
673
674
 
674
675
  // https://github.com/mishoo/UglifyJS2/issues/242 -- do not
@@ -744,6 +745,7 @@ AST_Symbol.DEFMETHOD("global", function() {
744
745
  AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
745
746
  options = defaults(options, {
746
747
  eval : false,
748
+ nth_identifier : base54,
747
749
  ie8 : false,
748
750
  keep_classnames: false,
749
751
  keep_fnames : false,
@@ -765,6 +767,7 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
765
767
 
766
768
  AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
767
769
  options = this._default_mangler_options(options);
770
+ var nth_identifier = options.nth_identifier;
768
771
 
769
772
  // We only need to mangle declaration nodes. Special logic wired
770
773
  // into the code generator will display the mangled name if it's
@@ -816,7 +819,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
816
819
  if (node instanceof AST_Label) {
817
820
  let name;
818
821
  do {
819
- name = base54(++lname);
822
+ name = nth_identifier.get(++lname);
820
823
  } while (ALL_RESERVED_WORDS.has(name));
821
824
  node.mangled_name = name;
822
825
  return true;
@@ -878,9 +881,12 @@ AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
878
881
  });
879
882
 
880
883
  AST_Toplevel.DEFMETHOD("expand_names", function(options) {
881
- base54.reset();
882
- base54.sort();
883
884
  options = this._default_mangler_options(options);
885
+ var nth_identifier = options.nth_identifier;
886
+ if (nth_identifier.reset && nth_identifier.sort) {
887
+ nth_identifier.reset();
888
+ nth_identifier.sort();
889
+ }
884
890
  var avoid = this.find_colliding_names(options);
885
891
  var cname = 0;
886
892
  this.globals.forEach(rename);
@@ -892,7 +898,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
892
898
  function next_name() {
893
899
  var name;
894
900
  do {
895
- name = base54(cname++);
901
+ name = nth_identifier.get(cname++);
896
902
  } while (avoid.has(name) || ALL_RESERVED_WORDS.has(name));
897
903
  return name;
898
904
  }
@@ -919,30 +925,37 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
919
925
 
920
926
  AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
921
927
  options = this._default_mangler_options(options);
928
+ var nth_identifier = options.nth_identifier;
929
+ if (!nth_identifier.reset || !nth_identifier.consider || !nth_identifier.sort) {
930
+ // If the identifier mangler is invariant, skip computing character frequency.
931
+ return;
932
+ }
933
+ nth_identifier.reset();
934
+
922
935
  try {
923
936
  AST_Node.prototype.print = function(stream, force_parens) {
924
937
  this._print(stream, force_parens);
925
938
  if (this instanceof AST_Symbol && !this.unmangleable(options)) {
926
- base54.consider(this.name, -1);
939
+ nth_identifier.consider(this.name, -1);
927
940
  } else if (options.properties) {
928
941
  if (this instanceof AST_DotHash) {
929
- base54.consider("#" + this.property, -1);
942
+ nth_identifier.consider("#" + this.property, -1);
930
943
  } else if (this instanceof AST_Dot) {
931
- base54.consider(this.property, -1);
944
+ nth_identifier.consider(this.property, -1);
932
945
  } else if (this instanceof AST_Sub) {
933
946
  skip_string(this.property);
934
947
  }
935
948
  }
936
949
  };
937
- base54.consider(this.print_to_string(), 1);
950
+ nth_identifier.consider(this.print_to_string(), 1);
938
951
  } finally {
939
952
  AST_Node.prototype.print = AST_Node.prototype._print;
940
953
  }
941
- base54.sort();
954
+ nth_identifier.sort();
942
955
 
943
956
  function skip_string(node) {
944
957
  if (node instanceof AST_String) {
945
- base54.consider(node.value, -1);
958
+ nth_identifier.consider(node.value, -1);
946
959
  } else if (node instanceof AST_Conditional) {
947
960
  skip_string(node.consequent);
948
961
  skip_string(node.alternative);
@@ -966,19 +979,20 @@ const base54 = (() => {
966
979
  frequency.set(ch, 0);
967
980
  });
968
981
  }
969
- base54.consider = function(str, delta) {
982
+ function consider(str, delta) {
970
983
  for (var i = str.length; --i >= 0;) {
971
984
  frequency.set(str[i], frequency.get(str[i]) + delta);
972
985
  }
973
- };
986
+ }
974
987
  function compare(a, b) {
975
988
  return frequency.get(b) - frequency.get(a);
976
989
  }
977
- base54.sort = function() {
990
+ function sort() {
978
991
  chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
979
- };
980
- base54.reset = reset;
992
+ }
993
+ // Ensure this is in a usable initial state.
981
994
  reset();
995
+ sort();
982
996
  function base54(num) {
983
997
  var ret = "", base = 54;
984
998
  num++;
@@ -990,7 +1004,13 @@ const base54 = (() => {
990
1004
  } while (num > 0);
991
1005
  return ret;
992
1006
  }
993
- return base54;
1007
+
1008
+ return {
1009
+ get: base54,
1010
+ consider,
1011
+ reset,
1012
+ sort
1013
+ };
994
1014
  })();
995
1015
 
996
1016
  export {
package/lib/transform.js CHANGED
@@ -57,7 +57,6 @@ import {
57
57
  AST_Definitions,
58
58
  AST_Destructuring,
59
59
  AST_Do,
60
- AST_Dot,
61
60
  AST_Exit,
62
61
  AST_Expansion,
63
62
  AST_Export,
@@ -74,6 +73,7 @@ import {
74
73
  AST_Object,
75
74
  AST_ObjectProperty,
76
75
  AST_PrefixedTemplateString,
76
+ AST_PropAccess,
77
77
  AST_Sequence,
78
78
  AST_SimpleStatement,
79
79
  AST_Sub,
@@ -228,7 +228,7 @@ def_transform(AST_Sequence, function(self, tw) {
228
228
  : [new AST_Number({ value: 0 })];
229
229
  });
230
230
 
231
- def_transform(AST_Dot, function(self, tw) {
231
+ def_transform(AST_PropAccess, function(self, tw) {
232
232
  self.expression = self.expression.transform(tw);
233
233
  });
234
234
 
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.2",
7
+ "version": "5.8.0",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },
@@ -45,19 +45,19 @@
45
45
  "dependencies": {
46
46
  "commander": "^2.20.0",
47
47
  "source-map": "~0.7.2",
48
- "source-map-support": "~0.5.19"
48
+ "source-map-support": "~0.5.20"
49
49
  },
50
50
  "devDependencies": {
51
- "@ls-lint/ls-lint": "^1.9.2",
52
- "acorn": "^8.0.5",
53
- "astring": "^1.6.2",
54
- "eslint": "^7.19.0",
55
- "eslump": "^2.0.0",
51
+ "@ls-lint/ls-lint": "^1.10.0",
52
+ "acorn": "^8.5.0",
53
+ "astring": "^1.7.5",
54
+ "eslint": "^7.32.0",
55
+ "eslump": "^3.0.0",
56
56
  "esm": "^3.2.25",
57
- "mocha": "^8.2.1",
57
+ "mocha": "^9.1.1",
58
58
  "pre-commit": "^1.2.2",
59
59
  "rimraf": "^3.0.2",
60
- "rollup": "2.38.4",
60
+ "rollup": "2.56.3",
61
61
  "semver": "^7.3.4"
62
62
  },
63
63
  "scripts": {
package/tools/terser.d.ts CHANGED
@@ -80,16 +80,52 @@ export interface MangleOptions {
80
80
  keep_classnames?: boolean | RegExp;
81
81
  keep_fnames?: boolean | RegExp;
82
82
  module?: boolean;
83
+ nth_identifier?: SimpleIdentifierMangler | WeightedIdentifierMangler;
83
84
  properties?: boolean | ManglePropertiesOptions;
84
85
  reserved?: string[];
85
86
  safari10?: boolean;
86
87
  toplevel?: boolean;
87
88
  }
88
89
 
90
+ /**
91
+ * An identifier mangler for which the output is invariant with respect to the source code.
92
+ */
93
+ export interface SimpleIdentifierMangler {
94
+ /**
95
+ * Obtains the nth most favored (usually shortest) identifier to rename a variable to.
96
+ * The mangler will increment n and retry until the return value is not in use in scope, and is not a reserved word.
97
+ * This function is expected to be stable; Evaluating get(n) === get(n) should always return true.
98
+ * @param n The ordinal of the identifier.
99
+ */
100
+ get(n: number): string;
101
+ }
102
+
103
+ /**
104
+ * An identifier mangler that leverages character frequency analysis to determine identifier precedence.
105
+ */
106
+ export interface WeightedIdentifierMangler extends SimpleIdentifierMangler {
107
+ /**
108
+ * Modifies the internal weighting of the input characters by the specified delta.
109
+ * Will be invoked on the entire printed AST, and then deduct mangleable identifiers.
110
+ * @param chars The characters to modify the weighting of.
111
+ * @param delta The numeric weight to add to the characters.
112
+ */
113
+ consider(chars: string, delta: number): number;
114
+ /**
115
+ * Resets character weights.
116
+ */
117
+ reset(): void;
118
+ /**
119
+ * Sorts identifiers by character frequency, in preparation for calls to get(n).
120
+ */
121
+ sort(): void;
122
+ }
123
+
89
124
  export interface ManglePropertiesOptions {
90
125
  builtins?: boolean;
91
126
  debug?: boolean;
92
127
  keep_quoted?: boolean | 'strict';
128
+ nth_identifier?: SimpleIdentifierMangler | WeightedIdentifierMangler;
93
129
  regex?: RegExp | string;
94
130
  reserved?: string[];
95
131
  }