terser 5.18.2 → 5.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.19.1
4
+ - Better avoid outputting `</script>` and HTML comments.
5
+ - Fix unused variables in class static blocks not being dropped correctly.
6
+ - Fix sourcemap names of methods that are `async` or `static`
7
+
8
+ ## v5.19.0
9
+ - Allow `/*@__MANGLE_PROP__*/` annotation in `object.property`, in addition to property declarations.
10
+
3
11
  ## v5.18.2
4
12
  - Stop using recursion in hoisted defuns fix.
5
13
 
@@ -3283,25 +3283,25 @@ function parse($TEXT, options) {
3283
3283
  if(is("privatename") && !S.in_class)
3284
3284
  croak("Private field must be used in an enclosing class");
3285
3285
  const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
3286
- return subscripts(new AST_DotVariant({
3286
+ return annotate(subscripts(new AST_DotVariant({
3287
3287
  start : start,
3288
3288
  expression : expr,
3289
3289
  optional : false,
3290
3290
  property : as_name(),
3291
3291
  end : prev()
3292
- }), allow_calls, is_chain);
3292
+ }), allow_calls, is_chain));
3293
3293
  }
3294
3294
  if (is("punc", "[")) {
3295
3295
  next();
3296
3296
  var prop = expression(true);
3297
3297
  expect("]");
3298
- return subscripts(new AST_Sub({
3298
+ return annotate(subscripts(new AST_Sub({
3299
3299
  start : start,
3300
3300
  expression : expr,
3301
3301
  optional : false,
3302
3302
  property : prop,
3303
3303
  end : prev()
3304
- }), allow_calls, is_chain);
3304
+ }), allow_calls, is_chain));
3305
3305
  }
3306
3306
  if (allow_calls && is("punc", "(")) {
3307
3307
  next();
@@ -3338,24 +3338,24 @@ function parse($TEXT, options) {
3338
3338
  if(is("privatename") && !S.in_class)
3339
3339
  croak("Private field must be used in an enclosing class");
3340
3340
  const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
3341
- chain_contents = subscripts(new AST_DotVariant({
3341
+ chain_contents = annotate(subscripts(new AST_DotVariant({
3342
3342
  start,
3343
3343
  expression: expr,
3344
3344
  optional: true,
3345
3345
  property: as_name(),
3346
3346
  end: prev()
3347
- }), allow_calls, true);
3347
+ }), allow_calls, true));
3348
3348
  } else if (is("punc", "[")) {
3349
3349
  next();
3350
3350
  const property = expression(true);
3351
3351
  expect("]");
3352
- chain_contents = subscripts(new AST_Sub({
3352
+ chain_contents = annotate(subscripts(new AST_Sub({
3353
3353
  start,
3354
3354
  expression: expr,
3355
3355
  optional: true,
3356
3356
  property,
3357
3357
  end: prev()
3358
- }), allow_calls, true);
3358
+ }), allow_calls, true));
3359
3359
  }
3360
3360
 
3361
3361
  if (!chain_contents) unexpected();
@@ -5333,6 +5333,7 @@ var AST_Dot = DEFNODE("Dot", "quote", function AST_Dot(props) {
5333
5333
  this.expression = props.expression;
5334
5334
  this.property = props.property;
5335
5335
  this.optional = props.optional;
5336
+ this._annotations = props._annotations;
5336
5337
  this.start = props.start;
5337
5338
  this.end = props.end;
5338
5339
  }
@@ -5380,6 +5381,7 @@ var AST_Sub = DEFNODE("Sub", null, function AST_Sub(props) {
5380
5381
  this.expression = props.expression;
5381
5382
  this.property = props.property;
5382
5383
  this.optional = props.optional;
5384
+ this._annotations = props._annotations;
5383
5385
  this.start = props.start;
5384
5386
  this.end = props.end;
5385
5387
  }
@@ -8952,6 +8954,18 @@ class Rope {
8952
8954
  this.current += str;
8953
8955
  }
8954
8956
 
8957
+ endsWith(str) {
8958
+ const { committed, current } = this;
8959
+ const len = str.length;
8960
+ if (committed.length >= len) {
8961
+ return committed.slice(committed.length - str.length) === str;
8962
+ } else {
8963
+ // `str` is small and this is a rare case so keep it simple
8964
+ const last_bit = committed.slice(-len) + current;
8965
+ return last_bit.endsWith(str);
8966
+ }
8967
+ }
8968
+
8955
8969
  insertAt(char, index) {
8956
8970
  const { committed, current } = this;
8957
8971
  if (index < committed.length) {
@@ -9160,10 +9174,12 @@ function OutputStream(options) {
9160
9174
  mappings.forEach(function(mapping) {
9161
9175
  try {
9162
9176
  let { name, token } = mapping;
9163
- if (token.type == "name" || token.type === "privatename") {
9164
- name = token.value;
9165
- } else if (name instanceof AST_Symbol) {
9166
- name = token.type === "string" ? token.value : name.name;
9177
+ if (name !== false) {
9178
+ if (token.type == "name" || token.type === "privatename") {
9179
+ name = token.value;
9180
+ } else if (name instanceof AST_Symbol) {
9181
+ name = token.type === "string" ? token.value : name.name;
9182
+ }
9167
9183
  }
9168
9184
  options.source_map.add(
9169
9185
  mapping.token.file,
@@ -9331,6 +9347,10 @@ function OutputStream(options) {
9331
9347
  might_need_semicolon = true;
9332
9348
  };
9333
9349
 
9350
+ function ends_with(str) {
9351
+ return OUTPUT.endsWith(str);
9352
+ }
9353
+
9334
9354
  function force_semicolon() {
9335
9355
  might_need_semicolon = false;
9336
9356
  print(";");
@@ -9600,6 +9620,7 @@ function OutputStream(options) {
9600
9620
  comma : comma,
9601
9621
  colon : colon,
9602
9622
  last : function() { return last; },
9623
+ ends_with : ends_with,
9603
9624
  semicolon : semicolon,
9604
9625
  force_semicolon : force_semicolon,
9605
9626
  to_utf8 : to_utf8,
@@ -10723,6 +10744,9 @@ function OutputStream(options) {
10723
10744
  });
10724
10745
  DEFPRINT(AST_UnaryPrefix, function(self, output) {
10725
10746
  var op = self.operator;
10747
+ if (op === "--" && output.ends_with("<!")) {
10748
+ output.print(" ");
10749
+ }
10726
10750
  output.print(op);
10727
10751
  if (/^[a-z]/i.test(op)
10728
10752
  || (/[+-]$/.test(op)
@@ -10740,8 +10764,7 @@ function OutputStream(options) {
10740
10764
  var op = self.operator;
10741
10765
  self.left.print(output);
10742
10766
  if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
10743
- && self.left instanceof AST_UnaryPostfix
10744
- && self.left.operator == "--") {
10767
+ && output.ends_with("--")) {
10745
10768
  // space is mandatory to avoid outputting -->
10746
10769
  output.print(" ");
10747
10770
  } else {
@@ -10749,17 +10772,7 @@ function OutputStream(options) {
10749
10772
  output.space();
10750
10773
  }
10751
10774
  output.print(op);
10752
- if ((op == "<" || op == "<<")
10753
- && self.right instanceof AST_UnaryPrefix
10754
- && self.right.operator == "!"
10755
- && self.right.expression instanceof AST_UnaryPrefix
10756
- && self.right.expression.operator == "--") {
10757
- // space is mandatory to avoid outputting <!--
10758
- output.print(" ");
10759
- } else {
10760
- // the space is optional depending on "beautify"
10761
- output.space();
10762
- }
10775
+ output.space();
10763
10776
  self.right.print(output);
10764
10777
  });
10765
10778
  DEFPRINT(AST_Conditional, function(self, output) {
@@ -10972,6 +10985,7 @@ function OutputStream(options) {
10972
10985
  if (self.key instanceof AST_SymbolMethod) {
10973
10986
  if (is_private) output.print("#");
10974
10987
  print_property_name(self.key.name, self.quote, output);
10988
+ self.key.add_source_map(output);
10975
10989
  } else {
10976
10990
  output.with_square(function() {
10977
10991
  self.key.print(output);
@@ -11060,12 +11074,18 @@ function OutputStream(options) {
11060
11074
  });
11061
11075
 
11062
11076
  const r_slash_script = /(<\s*\/\s*script)/i;
11077
+ const r_starts_with_script = /^\s*script/i;
11063
11078
  const slash_script_replace = (_, $1) => $1.replace("/", "\\/");
11064
11079
  DEFPRINT(AST_RegExp, function(self, output) {
11065
11080
  let { source, flags } = self.getValue();
11066
11081
  source = regexp_source_fix(source);
11067
11082
  flags = flags ? sort_regexp_flags(flags) : "";
11083
+
11084
+ // Avoid outputting end of script tag
11068
11085
  source = source.replace(r_slash_script, slash_script_replace);
11086
+ if (r_starts_with_script.test(source) && output.ends_with("<")) {
11087
+ output.print(" ");
11088
+ }
11069
11089
 
11070
11090
  output.print(output.to_utf8(`/${source}/${flags}`, false, true));
11071
11091
 
@@ -11189,8 +11209,22 @@ function OutputStream(options) {
11189
11209
  AST_ObjectSetter,
11190
11210
  AST_PrivateGetter,
11191
11211
  AST_PrivateSetter,
11212
+ AST_ConciseMethod,
11213
+ AST_PrivateMethod,
11214
+ ], function(output) {
11215
+ output.add_mapping(this.start, false /*name handled below*/);
11216
+ });
11217
+
11218
+ DEFMAP([
11219
+ AST_SymbolMethod,
11220
+ AST_SymbolPrivateProperty
11192
11221
  ], function(output) {
11193
- output.add_mapping(this.key.end, this.key.name);
11222
+ const tok_type = this.end && this.end.type;
11223
+ if (tok_type === "name" || tok_type === "privatename") {
11224
+ output.add_mapping(this.end, this.name);
11225
+ } else {
11226
+ output.add_mapping(this.end);
11227
+ }
11194
11228
  });
11195
11229
 
11196
11230
  DEFMAP([ AST_ObjectProperty ], function(output) {
@@ -15279,21 +15313,24 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15279
15313
  }
15280
15314
  }
15281
15315
  }
15282
- if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
15316
+ if (node instanceof AST_DefClass && node !== self) {
15317
+ const def = node.name.definition();
15318
+ descend(node, this);
15319
+ const keep_class = def.global && !drop_funcs || in_use_ids.has(def.id);
15320
+ if (!keep_class) {
15321
+ const kept = node.drop_side_effect_free(compressor);
15322
+ if (kept == null) {
15323
+ def.eliminated++;
15324
+ return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
15325
+ }
15326
+ return kept;
15327
+ }
15328
+ return node;
15329
+ }
15330
+ if (node instanceof AST_Defun && node !== self) {
15283
15331
  const def = node.name.definition();
15284
15332
  const keep = def.global && !drop_funcs || in_use_ids.has(def.id);
15285
15333
  if (!keep) {
15286
- // Class "extends" and static blocks may have side effects
15287
- if (node instanceof AST_Class) {
15288
- const kept = node.drop_side_effect_free(compressor);
15289
- if (kept !== node) {
15290
- def.eliminated++;
15291
- if (kept) return kept;
15292
- return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
15293
- } else {
15294
- return kept;
15295
- }
15296
- }
15297
15334
  def.eliminated++;
15298
15335
  return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
15299
15336
  }
@@ -29872,7 +29909,38 @@ function mangle_private_properties(ast, options) {
29872
29909
  }
29873
29910
  }
29874
29911
 
29875
- function mangle_properties(ast, options) {
29912
+ function find_annotated_props(ast) {
29913
+ var annotated_props = new Set();
29914
+ walk(ast, node => {
29915
+ if (
29916
+ node instanceof AST_ClassPrivateProperty
29917
+ || node instanceof AST_PrivateMethod
29918
+ || node instanceof AST_PrivateGetter
29919
+ || node instanceof AST_PrivateSetter
29920
+ || node instanceof AST_DotHash
29921
+ ) ; else if (node instanceof AST_ObjectKeyVal) {
29922
+ if (typeof node.key == "string" && has_annotation(node, _MANGLEPROP)) {
29923
+ annotated_props.add(node.key);
29924
+ }
29925
+ } else if (node instanceof AST_ObjectProperty) {
29926
+ // setter or getter, since KeyVal is handled above
29927
+ if (has_annotation(node, _MANGLEPROP)) {
29928
+ annotated_props.add(node.key.name);
29929
+ }
29930
+ } else if (node instanceof AST_Dot) {
29931
+ if (has_annotation(node, _MANGLEPROP)) {
29932
+ annotated_props.add(node.property);
29933
+ }
29934
+ } else if (node instanceof AST_Sub) {
29935
+ if (node.property instanceof AST_String && has_annotation(node, _MANGLEPROP)) {
29936
+ annotated_props.add(node.property.value);
29937
+ }
29938
+ }
29939
+ });
29940
+ return annotated_props;
29941
+ }
29942
+
29943
+ function mangle_properties(ast, options, annotated_props = find_annotated_props(ast)) {
29876
29944
  options = defaults(options, {
29877
29945
  builtins: false,
29878
29946
  cache: null,
@@ -29914,7 +29982,6 @@ function mangle_properties(ast, options) {
29914
29982
  debug_name_suffix = (options.debug === true ? "" : options.debug);
29915
29983
  }
29916
29984
 
29917
- var annotated_names = new Set();
29918
29985
  var names_to_mangle = new Set();
29919
29986
  var unmangleable = new Set();
29920
29987
  // Track each already-mangled name to prevent nth_identifier from generating
@@ -29923,36 +29990,7 @@ function mangle_properties(ast, options) {
29923
29990
 
29924
29991
  var keep_quoted = !!options.keep_quoted;
29925
29992
 
29926
- // Step 1: Find all annotated /*@__MANGLEPROP__*/
29927
- walk(ast, node => {
29928
- if (
29929
- node instanceof AST_ClassPrivateProperty
29930
- || node instanceof AST_PrivateMethod
29931
- || node instanceof AST_PrivateGetter
29932
- || node instanceof AST_PrivateSetter
29933
- || node instanceof AST_DotHash
29934
- ) ; else if (node instanceof AST_ObjectKeyVal) {
29935
- if (
29936
- typeof node.key == "string"
29937
- && has_annotation(node, _MANGLEPROP)
29938
- && can_mangle(node.key)
29939
- ) {
29940
- annotated_names.add(node.key);
29941
- clear_annotation(node, _MANGLEPROP);
29942
- }
29943
- } else if (node instanceof AST_ObjectProperty) {
29944
- // setter or getter, since KeyVal is handled above
29945
- if (
29946
- has_annotation(node, _MANGLEPROP)
29947
- && can_mangle(node.key.name)
29948
- ) {
29949
- annotated_names.add(node.key.name);
29950
- clear_annotation(node, _MANGLEPROP);
29951
- }
29952
- }
29953
- });
29954
-
29955
- // step 2: find candidates to mangle
29993
+ // step 1: find candidates to mangle
29956
29994
  ast.walk(new TreeWalker(function(node) {
29957
29995
  if (
29958
29996
  node instanceof AST_ClassPrivateProperty
@@ -30044,9 +30082,9 @@ function mangle_properties(ast, options) {
30044
30082
  }
30045
30083
 
30046
30084
  function should_mangle(name) {
30047
- if (only_annotated && !annotated_names.has(name)) return false;
30085
+ if (only_annotated && !annotated_props.has(name)) return false;
30048
30086
  if (regex && !regex.test(name)) {
30049
- return annotated_names.has(name);
30087
+ return annotated_props.has(name);
30050
30088
  }
30051
30089
  if (reserved.has(name)) return false;
30052
30090
  return cache.has(name)
@@ -30325,6 +30363,10 @@ async function minify(files, options, _fs_module) {
30325
30363
  if (quoted_props && options.mangle.properties.keep_quoted !== "strict") {
30326
30364
  reserve_quoted_keys(toplevel, quoted_props);
30327
30365
  }
30366
+ var annotated_props;
30367
+ if (options.mangle && options.mangle.properties) {
30368
+ annotated_props = find_annotated_props(toplevel);
30369
+ }
30328
30370
  if (options.wrap) {
30329
30371
  toplevel = toplevel.wrap_commonjs(options.wrap);
30330
30372
  }
@@ -30352,7 +30394,7 @@ async function minify(files, options, _fs_module) {
30352
30394
  }
30353
30395
  if (timings) timings.properties = Date.now();
30354
30396
  if (options.mangle && options.mangle.properties) {
30355
- toplevel = mangle_properties(toplevel, options.mangle.properties);
30397
+ toplevel = mangle_properties(toplevel, options.mangle.properties, annotated_props);
30356
30398
  }
30357
30399
 
30358
30400
  // Format phase
package/lib/ast.js CHANGED
@@ -1714,6 +1714,7 @@ var AST_Dot = DEFNODE("Dot", "quote", function AST_Dot(props) {
1714
1714
  this.expression = props.expression;
1715
1715
  this.property = props.property;
1716
1716
  this.optional = props.optional;
1717
+ this._annotations = props._annotations;
1717
1718
  this.start = props.start;
1718
1719
  this.end = props.end;
1719
1720
  }
@@ -1761,6 +1762,7 @@ var AST_Sub = DEFNODE("Sub", null, function AST_Sub(props) {
1761
1762
  this.expression = props.expression;
1762
1763
  this.property = props.property;
1763
1764
  this.optional = props.optional;
1765
+ this._annotations = props._annotations;
1764
1766
  this.start = props.start;
1765
1767
  this.end = props.end;
1766
1768
  }
@@ -273,21 +273,24 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
273
273
  }
274
274
  }
275
275
  }
276
- if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
276
+ if (node instanceof AST_DefClass && node !== self) {
277
+ const def = node.name.definition();
278
+ descend(node, this);
279
+ const keep_class = def.global && !drop_funcs || in_use_ids.has(def.id);
280
+ if (!keep_class) {
281
+ const kept = node.drop_side_effect_free(compressor);
282
+ if (kept == null) {
283
+ def.eliminated++;
284
+ return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
285
+ }
286
+ return kept;
287
+ }
288
+ return node;
289
+ }
290
+ if (node instanceof AST_Defun && node !== self) {
277
291
  const def = node.name.definition();
278
292
  const keep = def.global && !drop_funcs || in_use_ids.has(def.id);
279
293
  if (!keep) {
280
- // Class "extends" and static blocks may have side effects
281
- if (node instanceof AST_Class) {
282
- const kept = node.drop_side_effect_free(compressor);
283
- if (kept !== node) {
284
- def.eliminated++;
285
- if (kept) return kept;
286
- return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
287
- } else {
288
- return kept;
289
- }
290
- }
291
294
  def.eliminated++;
292
295
  return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
293
296
  }
package/lib/minify.js CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  mangle_properties,
18
18
  mangle_private_properties,
19
19
  reserve_quoted_keys,
20
+ find_annotated_props,
20
21
  } from "./propmangle.js";
21
22
 
22
23
  // to/from base64 functions
@@ -235,6 +236,10 @@ async function minify(files, options, _fs_module) {
235
236
  if (quoted_props && options.mangle.properties.keep_quoted !== "strict") {
236
237
  reserve_quoted_keys(toplevel, quoted_props);
237
238
  }
239
+ var annotated_props;
240
+ if (options.mangle && options.mangle.properties) {
241
+ annotated_props = find_annotated_props(toplevel);
242
+ }
238
243
  if (options.wrap) {
239
244
  toplevel = toplevel.wrap_commonjs(options.wrap);
240
245
  }
@@ -268,7 +273,7 @@ async function minify(files, options, _fs_module) {
268
273
  }
269
274
  if (timings) timings.properties = Date.now();
270
275
  if (options.mangle && options.mangle.properties) {
271
- toplevel = mangle_properties(toplevel, options.mangle.properties);
276
+ toplevel = mangle_properties(toplevel, options.mangle.properties, annotated_props);
272
277
  }
273
278
 
274
279
  // Format phase
package/lib/output.js CHANGED
@@ -190,6 +190,18 @@ class Rope {
190
190
  this.current += str;
191
191
  }
192
192
 
193
+ endsWith(str) {
194
+ const { committed, current } = this;
195
+ const len = str.length;
196
+ if (committed.length >= len) {
197
+ return committed.slice(committed.length - str.length) === str;
198
+ } else {
199
+ // `str` is small and this is a rare case so keep it simple
200
+ const last_bit = committed.slice(-len) + current;
201
+ return last_bit.endsWith(str);
202
+ }
203
+ }
204
+
193
205
  insertAt(char, index) {
194
206
  const { committed, current } = this;
195
207
  if (index < committed.length) {
@@ -398,10 +410,12 @@ function OutputStream(options) {
398
410
  mappings.forEach(function(mapping) {
399
411
  try {
400
412
  let { name, token } = mapping;
401
- if (token.type == "name" || token.type === "privatename") {
402
- name = token.value;
403
- } else if (name instanceof AST_Symbol) {
404
- name = token.type === "string" ? token.value : name.name;
413
+ if (name !== false) {
414
+ if (token.type == "name" || token.type === "privatename") {
415
+ name = token.value;
416
+ } else if (name instanceof AST_Symbol) {
417
+ name = token.type === "string" ? token.value : name.name;
418
+ }
405
419
  }
406
420
  options.source_map.add(
407
421
  mapping.token.file,
@@ -569,6 +583,10 @@ function OutputStream(options) {
569
583
  might_need_semicolon = true;
570
584
  };
571
585
 
586
+ function ends_with(str) {
587
+ return OUTPUT.endsWith(str);
588
+ }
589
+
572
590
  function force_semicolon() {
573
591
  might_need_semicolon = false;
574
592
  print(";");
@@ -838,6 +856,7 @@ function OutputStream(options) {
838
856
  comma : comma,
839
857
  colon : colon,
840
858
  last : function() { return last; },
859
+ ends_with : ends_with,
841
860
  semicolon : semicolon,
842
861
  force_semicolon : force_semicolon,
843
862
  to_utf8 : to_utf8,
@@ -1961,6 +1980,9 @@ function OutputStream(options) {
1961
1980
  });
1962
1981
  DEFPRINT(AST_UnaryPrefix, function(self, output) {
1963
1982
  var op = self.operator;
1983
+ if (op === "--" && output.ends_with("<!")) {
1984
+ output.print(" ");
1985
+ }
1964
1986
  output.print(op);
1965
1987
  if (/^[a-z]/i.test(op)
1966
1988
  || (/[+-]$/.test(op)
@@ -1978,8 +2000,7 @@ function OutputStream(options) {
1978
2000
  var op = self.operator;
1979
2001
  self.left.print(output);
1980
2002
  if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
1981
- && self.left instanceof AST_UnaryPostfix
1982
- && self.left.operator == "--") {
2003
+ && output.ends_with("--")) {
1983
2004
  // space is mandatory to avoid outputting -->
1984
2005
  output.print(" ");
1985
2006
  } else {
@@ -1987,17 +2008,7 @@ function OutputStream(options) {
1987
2008
  output.space();
1988
2009
  }
1989
2010
  output.print(op);
1990
- if ((op == "<" || op == "<<")
1991
- && self.right instanceof AST_UnaryPrefix
1992
- && self.right.operator == "!"
1993
- && self.right.expression instanceof AST_UnaryPrefix
1994
- && self.right.expression.operator == "--") {
1995
- // space is mandatory to avoid outputting <!--
1996
- output.print(" ");
1997
- } else {
1998
- // the space is optional depending on "beautify"
1999
- output.space();
2000
- }
2011
+ output.space();
2001
2012
  self.right.print(output);
2002
2013
  });
2003
2014
  DEFPRINT(AST_Conditional, function(self, output) {
@@ -2210,6 +2221,7 @@ function OutputStream(options) {
2210
2221
  if (self.key instanceof AST_SymbolMethod) {
2211
2222
  if (is_private) output.print("#");
2212
2223
  print_property_name(self.key.name, self.quote, output);
2224
+ self.key.add_source_map(output);
2213
2225
  } else {
2214
2226
  output.with_square(function() {
2215
2227
  self.key.print(output);
@@ -2298,12 +2310,18 @@ function OutputStream(options) {
2298
2310
  });
2299
2311
 
2300
2312
  const r_slash_script = /(<\s*\/\s*script)/i;
2313
+ const r_starts_with_script = /^\s*script/i;
2301
2314
  const slash_script_replace = (_, $1) => $1.replace("/", "\\/");
2302
2315
  DEFPRINT(AST_RegExp, function(self, output) {
2303
2316
  let { source, flags } = self.getValue();
2304
2317
  source = regexp_source_fix(source);
2305
2318
  flags = flags ? sort_regexp_flags(flags) : "";
2319
+
2320
+ // Avoid outputting end of script tag
2306
2321
  source = source.replace(r_slash_script, slash_script_replace);
2322
+ if (r_starts_with_script.test(source) && output.ends_with("<")) {
2323
+ output.print(" ");
2324
+ }
2307
2325
 
2308
2326
  output.print(output.to_utf8(`/${source}/${flags}`, false, true));
2309
2327
 
@@ -2427,8 +2445,22 @@ function OutputStream(options) {
2427
2445
  AST_ObjectSetter,
2428
2446
  AST_PrivateGetter,
2429
2447
  AST_PrivateSetter,
2448
+ AST_ConciseMethod,
2449
+ AST_PrivateMethod,
2430
2450
  ], function(output) {
2431
- output.add_mapping(this.key.end, this.key.name);
2451
+ output.add_mapping(this.start, false /*name handled below*/);
2452
+ });
2453
+
2454
+ DEFMAP([
2455
+ AST_SymbolMethod,
2456
+ AST_SymbolPrivateProperty
2457
+ ], function(output) {
2458
+ const tok_type = this.end && this.end.type;
2459
+ if (tok_type === "name" || tok_type === "privatename") {
2460
+ output.add_mapping(this.end, this.name);
2461
+ } else {
2462
+ output.add_mapping(this.end);
2463
+ }
2432
2464
  });
2433
2465
 
2434
2466
  DEFMAP([ AST_ObjectProperty ], function(output) {
package/lib/parse.js CHANGED
@@ -3138,25 +3138,25 @@ function parse($TEXT, options) {
3138
3138
  if(is("privatename") && !S.in_class)
3139
3139
  croak("Private field must be used in an enclosing class");
3140
3140
  const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
3141
- return subscripts(new AST_DotVariant({
3141
+ return annotate(subscripts(new AST_DotVariant({
3142
3142
  start : start,
3143
3143
  expression : expr,
3144
3144
  optional : false,
3145
3145
  property : as_name(),
3146
3146
  end : prev()
3147
- }), allow_calls, is_chain);
3147
+ }), allow_calls, is_chain));
3148
3148
  }
3149
3149
  if (is("punc", "[")) {
3150
3150
  next();
3151
3151
  var prop = expression(true);
3152
3152
  expect("]");
3153
- return subscripts(new AST_Sub({
3153
+ return annotate(subscripts(new AST_Sub({
3154
3154
  start : start,
3155
3155
  expression : expr,
3156
3156
  optional : false,
3157
3157
  property : prop,
3158
3158
  end : prev()
3159
- }), allow_calls, is_chain);
3159
+ }), allow_calls, is_chain));
3160
3160
  }
3161
3161
  if (allow_calls && is("punc", "(")) {
3162
3162
  next();
@@ -3193,24 +3193,24 @@ function parse($TEXT, options) {
3193
3193
  if(is("privatename") && !S.in_class)
3194
3194
  croak("Private field must be used in an enclosing class");
3195
3195
  const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
3196
- chain_contents = subscripts(new AST_DotVariant({
3196
+ chain_contents = annotate(subscripts(new AST_DotVariant({
3197
3197
  start,
3198
3198
  expression: expr,
3199
3199
  optional: true,
3200
3200
  property: as_name(),
3201
3201
  end: prev()
3202
- }), allow_calls, true);
3202
+ }), allow_calls, true));
3203
3203
  } else if (is("punc", "[")) {
3204
3204
  next();
3205
3205
  const property = expression(true);
3206
3206
  expect("]");
3207
- chain_contents = subscripts(new AST_Sub({
3207
+ chain_contents = annotate(subscripts(new AST_Sub({
3208
3208
  start,
3209
3209
  expression: expr,
3210
3210
  optional: true,
3211
3211
  property,
3212
3212
  end: prev()
3213
- }), allow_calls, true);
3213
+ }), allow_calls, true));
3214
3214
  }
3215
3215
 
3216
3216
  if (!chain_contents) unexpected();
package/lib/propmangle.js CHANGED
@@ -180,7 +180,40 @@ function mangle_private_properties(ast, options) {
180
180
  }
181
181
  }
182
182
 
183
- function mangle_properties(ast, options) {
183
+ function find_annotated_props(ast) {
184
+ var annotated_props = new Set();
185
+ walk(ast, node => {
186
+ if (
187
+ node instanceof AST_ClassPrivateProperty
188
+ || node instanceof AST_PrivateMethod
189
+ || node instanceof AST_PrivateGetter
190
+ || node instanceof AST_PrivateSetter
191
+ || node instanceof AST_DotHash
192
+ ) {
193
+ // handled by mangle_private_properties
194
+ } else if (node instanceof AST_ObjectKeyVal) {
195
+ if (typeof node.key == "string" && has_annotation(node, _MANGLEPROP)) {
196
+ annotated_props.add(node.key);
197
+ }
198
+ } else if (node instanceof AST_ObjectProperty) {
199
+ // setter or getter, since KeyVal is handled above
200
+ if (has_annotation(node, _MANGLEPROP)) {
201
+ annotated_props.add(node.key.name);
202
+ }
203
+ } else if (node instanceof AST_Dot) {
204
+ if (has_annotation(node, _MANGLEPROP)) {
205
+ annotated_props.add(node.property);
206
+ }
207
+ } else if (node instanceof AST_Sub) {
208
+ if (node.property instanceof AST_String && has_annotation(node, _MANGLEPROP)) {
209
+ annotated_props.add(node.property.value);
210
+ }
211
+ }
212
+ });
213
+ return annotated_props;
214
+ }
215
+
216
+ function mangle_properties(ast, options, annotated_props = find_annotated_props(ast)) {
184
217
  options = defaults(options, {
185
218
  builtins: false,
186
219
  cache: null,
@@ -222,7 +255,6 @@ function mangle_properties(ast, options) {
222
255
  debug_name_suffix = (options.debug === true ? "" : options.debug);
223
256
  }
224
257
 
225
- var annotated_names = new Set();
226
258
  var names_to_mangle = new Set();
227
259
  var unmangleable = new Set();
228
260
  // Track each already-mangled name to prevent nth_identifier from generating
@@ -231,38 +263,7 @@ function mangle_properties(ast, options) {
231
263
 
232
264
  var keep_quoted = !!options.keep_quoted;
233
265
 
234
- // Step 1: Find all annotated /*@__MANGLEPROP__*/
235
- walk(ast, node => {
236
- if (
237
- node instanceof AST_ClassPrivateProperty
238
- || node instanceof AST_PrivateMethod
239
- || node instanceof AST_PrivateGetter
240
- || node instanceof AST_PrivateSetter
241
- || node instanceof AST_DotHash
242
- ) {
243
- // handled by mangle_private_properties
244
- } else if (node instanceof AST_ObjectKeyVal) {
245
- if (
246
- typeof node.key == "string"
247
- && has_annotation(node, _MANGLEPROP)
248
- && can_mangle(node.key)
249
- ) {
250
- annotated_names.add(node.key);
251
- clear_annotation(node, _MANGLEPROP);
252
- }
253
- } else if (node instanceof AST_ObjectProperty) {
254
- // setter or getter, since KeyVal is handled above
255
- if (
256
- has_annotation(node, _MANGLEPROP)
257
- && can_mangle(node.key.name)
258
- ) {
259
- annotated_names.add(node.key.name);
260
- clear_annotation(node, _MANGLEPROP);
261
- }
262
- }
263
- });
264
-
265
- // step 2: find candidates to mangle
266
+ // step 1: find candidates to mangle
266
267
  ast.walk(new TreeWalker(function(node) {
267
268
  if (
268
269
  node instanceof AST_ClassPrivateProperty
@@ -358,9 +359,9 @@ function mangle_properties(ast, options) {
358
359
  }
359
360
 
360
361
  function should_mangle(name) {
361
- if (only_annotated && !annotated_names.has(name)) return false;
362
+ if (only_annotated && !annotated_props.has(name)) return false;
362
363
  if (regex && !regex.test(name)) {
363
- return annotated_names.has(name);
364
+ return annotated_props.has(name);
364
365
  }
365
366
  if (reserved.has(name)) return false;
366
367
  return cache.has(name)
@@ -427,4 +428,5 @@ export {
427
428
  reserve_quoted_keys,
428
429
  mangle_properties,
429
430
  mangle_private_properties,
431
+ find_annotated_props,
430
432
  };
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.18.2",
7
+ "version": "5.19.1",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },