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 +8 -0
- package/dist/bundle.min.js +115 -73
- package/lib/ast.js +2 -0
- package/lib/compress/drop-unused.js +15 -12
- package/lib/minify.js +6 -1
- package/lib/output.js +50 -18
- package/lib/parse.js +8 -8
- package/lib/propmangle.js +38 -36
- package/package.json +1 -1
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
|
|
package/dist/bundle.min.js
CHANGED
@@ -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 (
|
9164
|
-
name
|
9165
|
-
|
9166
|
-
|
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
|
-
&&
|
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
|
-
|
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
|
-
|
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 (
|
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
|
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
|
-
//
|
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 && !
|
30085
|
+
if (only_annotated && !annotated_props.has(name)) return false;
|
30048
30086
|
if (regex && !regex.test(name)) {
|
30049
|
-
return
|
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 (
|
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 (
|
402
|
-
name
|
403
|
-
|
404
|
-
|
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
|
-
&&
|
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
|
-
|
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.
|
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
|
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
|
-
//
|
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 && !
|
362
|
+
if (only_annotated && !annotated_props.has(name)) return false;
|
362
363
|
if (regex && !regex.test(name)) {
|
363
|
-
return
|
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
|
};
|