terser 5.16.0 → 5.16.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 +3098 -3044
- package/lib/ast.js +3 -2
- package/lib/compress/drop-unused.js +482 -0
- package/lib/compress/evaluate.js +7 -0
- package/lib/compress/index.js +5 -392
- package/lib/compress/inference.js +1 -2
- package/lib/compress/inline.js +1 -19
- package/lib/compress/tighten-body.js +29 -28
- package/lib/parse.js +2 -1
- package/lib/scope.js +30 -8
- package/lib/size.js +6 -8
- package/package.json +1 -1
package/lib/compress/index.js
CHANGED
@@ -56,7 +56,6 @@ import {
|
|
56
56
|
AST_Catch,
|
57
57
|
AST_Chain,
|
58
58
|
AST_Class,
|
59
|
-
AST_ClassExpression,
|
60
59
|
AST_ClassProperty,
|
61
60
|
AST_ClassStaticBlock,
|
62
61
|
AST_ConciseMethod,
|
@@ -66,7 +65,6 @@ import {
|
|
66
65
|
AST_Debugger,
|
67
66
|
AST_Default,
|
68
67
|
AST_DefaultAssign,
|
69
|
-
AST_DefClass,
|
70
68
|
AST_Definitions,
|
71
69
|
AST_Defun,
|
72
70
|
AST_Destructuring,
|
@@ -110,8 +108,6 @@ import {
|
|
110
108
|
AST_Switch,
|
111
109
|
AST_SwitchBranch,
|
112
110
|
AST_Symbol,
|
113
|
-
AST_SymbolBlockDeclaration,
|
114
|
-
AST_SymbolCatch,
|
115
111
|
AST_SymbolClassProperty,
|
116
112
|
AST_SymbolDeclaration,
|
117
113
|
AST_SymbolDefun,
|
@@ -121,7 +117,6 @@ import {
|
|
121
117
|
AST_SymbolLet,
|
122
118
|
AST_SymbolMethod,
|
123
119
|
AST_SymbolRef,
|
124
|
-
AST_SymbolVar,
|
125
120
|
AST_TemplateString,
|
126
121
|
AST_This,
|
127
122
|
AST_Toplevel,
|
@@ -149,10 +144,8 @@ import {
|
|
149
144
|
import {
|
150
145
|
defaults,
|
151
146
|
HOP,
|
152
|
-
keep_name,
|
153
147
|
make_node,
|
154
148
|
makePredicate,
|
155
|
-
map_add,
|
156
149
|
MAP,
|
157
150
|
remove,
|
158
151
|
return_false,
|
@@ -170,14 +163,12 @@ import {
|
|
170
163
|
PRECEDENCE,
|
171
164
|
} from "../parse.js";
|
172
165
|
import { OutputStream } from "../output.js";
|
173
|
-
import {
|
174
|
-
base54,
|
175
|
-
SymbolDef,
|
176
|
-
} from "../scope.js";
|
166
|
+
import { base54, format_mangler_options } from "../scope.js";
|
177
167
|
import "../size.js";
|
178
168
|
|
179
169
|
import "./evaluate.js";
|
180
170
|
import "./drop-side-effect-free.js";
|
171
|
+
import "./drop-unused.js";
|
181
172
|
import "./reduce-vars.js";
|
182
173
|
import {
|
183
174
|
is_undeclared_ref,
|
@@ -192,7 +183,6 @@ import {
|
|
192
183
|
OPTIMIZED,
|
193
184
|
CLEAR_BETWEEN_PASSES,
|
194
185
|
TOP,
|
195
|
-
WRITE_ONLY,
|
196
186
|
UNDEFINED,
|
197
187
|
UNUSED,
|
198
188
|
TRUTHY,
|
@@ -214,7 +204,6 @@ import {
|
|
214
204
|
is_empty,
|
215
205
|
is_identifier_atom,
|
216
206
|
is_reachable,
|
217
|
-
is_ref_of,
|
218
207
|
can_be_evicted_from_block,
|
219
208
|
as_statement_array,
|
220
209
|
retain_top_func,
|
@@ -332,7 +321,9 @@ class Compressor extends TreeWalker {
|
|
332
321
|
this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
|
333
322
|
this.evaluated_regexps = new Map();
|
334
323
|
this._toplevel = undefined;
|
335
|
-
this.mangle_options = mangle_options
|
324
|
+
this.mangle_options = mangle_options
|
325
|
+
? format_mangler_options(mangle_options)
|
326
|
+
: mangle_options;
|
336
327
|
}
|
337
328
|
|
338
329
|
option(key) {
|
@@ -653,382 +644,6 @@ function opt_AST_Lambda(self, compressor) {
|
|
653
644
|
}
|
654
645
|
def_optimize(AST_Lambda, opt_AST_Lambda);
|
655
646
|
|
656
|
-
const r_keep_assign = /keep_assign/;
|
657
|
-
AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
658
|
-
if (!compressor.option("unused")) return;
|
659
|
-
if (compressor.has_directive("use asm")) return;
|
660
|
-
var self = this;
|
661
|
-
if (self.pinned()) return;
|
662
|
-
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
|
663
|
-
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
|
664
|
-
const assign_as_unused = r_keep_assign.test(compressor.option("unused")) ? return_false : function(node) {
|
665
|
-
if (node instanceof AST_Assign
|
666
|
-
&& !node.logical
|
667
|
-
&& (has_flag(node, WRITE_ONLY) || node.operator == "=")
|
668
|
-
) {
|
669
|
-
return node.left;
|
670
|
-
}
|
671
|
-
if (node instanceof AST_Unary && has_flag(node, WRITE_ONLY)) {
|
672
|
-
return node.expression;
|
673
|
-
}
|
674
|
-
};
|
675
|
-
var in_use_ids = new Map();
|
676
|
-
var fixed_ids = new Map();
|
677
|
-
if (self instanceof AST_Toplevel && compressor.top_retain) {
|
678
|
-
self.variables.forEach(function(def) {
|
679
|
-
if (compressor.top_retain(def) && !in_use_ids.has(def.id)) {
|
680
|
-
in_use_ids.set(def.id, def);
|
681
|
-
}
|
682
|
-
});
|
683
|
-
}
|
684
|
-
var var_defs_by_id = new Map();
|
685
|
-
var initializations = new Map();
|
686
|
-
// pass 1: find out which symbols are directly used in
|
687
|
-
// this scope (not in nested scopes).
|
688
|
-
var scope = this;
|
689
|
-
var tw = new TreeWalker(function(node, descend) {
|
690
|
-
if (node instanceof AST_Lambda && node.uses_arguments && !tw.has_directive("use strict")) {
|
691
|
-
node.argnames.forEach(function(argname) {
|
692
|
-
if (!(argname instanceof AST_SymbolDeclaration)) return;
|
693
|
-
var def = argname.definition();
|
694
|
-
if (!in_use_ids.has(def.id)) {
|
695
|
-
in_use_ids.set(def.id, def);
|
696
|
-
}
|
697
|
-
});
|
698
|
-
}
|
699
|
-
if (node === self) return;
|
700
|
-
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
|
701
|
-
var node_def = node.name.definition();
|
702
|
-
const in_export = tw.parent() instanceof AST_Export;
|
703
|
-
if (in_export || !drop_funcs && scope === self) {
|
704
|
-
if (node_def.global && !in_use_ids.has(node_def.id)) {
|
705
|
-
in_use_ids.set(node_def.id, node_def);
|
706
|
-
}
|
707
|
-
}
|
708
|
-
if (node instanceof AST_DefClass) {
|
709
|
-
if (
|
710
|
-
node.extends
|
711
|
-
&& (node.extends.has_side_effects(compressor)
|
712
|
-
|| node.extends.may_throw(compressor))
|
713
|
-
) {
|
714
|
-
node.extends.walk(tw);
|
715
|
-
}
|
716
|
-
for (const prop of node.properties) {
|
717
|
-
if (
|
718
|
-
prop.has_side_effects(compressor) ||
|
719
|
-
prop.may_throw(compressor)
|
720
|
-
) {
|
721
|
-
prop.walk(tw);
|
722
|
-
}
|
723
|
-
}
|
724
|
-
}
|
725
|
-
map_add(initializations, node_def.id, node);
|
726
|
-
return true; // don't go in nested scopes
|
727
|
-
}
|
728
|
-
if (node instanceof AST_SymbolFunarg && scope === self) {
|
729
|
-
map_add(var_defs_by_id, node.definition().id, node);
|
730
|
-
}
|
731
|
-
if (node instanceof AST_Definitions && scope === self) {
|
732
|
-
const in_export = tw.parent() instanceof AST_Export;
|
733
|
-
node.definitions.forEach(function(def) {
|
734
|
-
if (def.name instanceof AST_SymbolVar) {
|
735
|
-
map_add(var_defs_by_id, def.name.definition().id, def);
|
736
|
-
}
|
737
|
-
if (in_export || !drop_vars) {
|
738
|
-
walk(def.name, node => {
|
739
|
-
if (node instanceof AST_SymbolDeclaration) {
|
740
|
-
const def = node.definition();
|
741
|
-
if (
|
742
|
-
(in_export || def.global)
|
743
|
-
&& !in_use_ids.has(def.id)
|
744
|
-
) {
|
745
|
-
in_use_ids.set(def.id, def);
|
746
|
-
}
|
747
|
-
}
|
748
|
-
});
|
749
|
-
}
|
750
|
-
if (def.value) {
|
751
|
-
if (def.name instanceof AST_Destructuring) {
|
752
|
-
def.walk(tw);
|
753
|
-
} else {
|
754
|
-
var node_def = def.name.definition();
|
755
|
-
map_add(initializations, node_def.id, def.value);
|
756
|
-
if (!node_def.chained && def.name.fixed_value() === def.value) {
|
757
|
-
fixed_ids.set(node_def.id, def);
|
758
|
-
}
|
759
|
-
}
|
760
|
-
if (def.value.has_side_effects(compressor)) {
|
761
|
-
def.value.walk(tw);
|
762
|
-
}
|
763
|
-
}
|
764
|
-
});
|
765
|
-
return true;
|
766
|
-
}
|
767
|
-
return scan_ref_scoped(node, descend);
|
768
|
-
});
|
769
|
-
self.walk(tw);
|
770
|
-
// pass 2: for every used symbol we need to walk its
|
771
|
-
// initialization code to figure out if it uses other
|
772
|
-
// symbols (that may not be in_use).
|
773
|
-
tw = new TreeWalker(scan_ref_scoped);
|
774
|
-
in_use_ids.forEach(function (def) {
|
775
|
-
var init = initializations.get(def.id);
|
776
|
-
if (init) init.forEach(function(init) {
|
777
|
-
init.walk(tw);
|
778
|
-
});
|
779
|
-
});
|
780
|
-
// pass 3: we should drop declarations not in_use
|
781
|
-
var tt = new TreeTransformer(
|
782
|
-
function before(node, descend, in_list) {
|
783
|
-
var parent = tt.parent();
|
784
|
-
if (drop_vars) {
|
785
|
-
const sym = assign_as_unused(node);
|
786
|
-
if (sym instanceof AST_SymbolRef) {
|
787
|
-
var def = sym.definition();
|
788
|
-
var in_use = in_use_ids.has(def.id);
|
789
|
-
if (node instanceof AST_Assign) {
|
790
|
-
if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
|
791
|
-
return maintain_this_binding(parent, node, node.right.transform(tt));
|
792
|
-
}
|
793
|
-
} else if (!in_use) return in_list ? MAP.skip : make_node(AST_Number, node, {
|
794
|
-
value: 0
|
795
|
-
});
|
796
|
-
}
|
797
|
-
}
|
798
|
-
if (scope !== self) return;
|
799
|
-
var def;
|
800
|
-
if (node.name
|
801
|
-
&& (node instanceof AST_ClassExpression
|
802
|
-
&& !keep_name(compressor.option("keep_classnames"), (def = node.name.definition()).name)
|
803
|
-
|| node instanceof AST_Function
|
804
|
-
&& !keep_name(compressor.option("keep_fnames"), (def = node.name.definition()).name))) {
|
805
|
-
// any declarations with same name will overshadow
|
806
|
-
// name of this anonymous function and can therefore
|
807
|
-
// never be used anywhere
|
808
|
-
if (!in_use_ids.has(def.id) || def.orig.length > 1) node.name = null;
|
809
|
-
}
|
810
|
-
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
|
811
|
-
var trim = !compressor.option("keep_fargs");
|
812
|
-
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
813
|
-
var sym = a[i];
|
814
|
-
if (sym instanceof AST_Expansion) {
|
815
|
-
sym = sym.expression;
|
816
|
-
}
|
817
|
-
if (sym instanceof AST_DefaultAssign) {
|
818
|
-
sym = sym.left;
|
819
|
-
}
|
820
|
-
// Do not drop destructuring arguments.
|
821
|
-
// They constitute a type assertion, so dropping
|
822
|
-
// them would stop that TypeError which would happen
|
823
|
-
// if someone called it with an incorrectly formatted
|
824
|
-
// parameter.
|
825
|
-
if (!(sym instanceof AST_Destructuring) && !in_use_ids.has(sym.definition().id)) {
|
826
|
-
set_flag(sym, UNUSED);
|
827
|
-
if (trim) {
|
828
|
-
a.pop();
|
829
|
-
}
|
830
|
-
} else {
|
831
|
-
trim = false;
|
832
|
-
}
|
833
|
-
}
|
834
|
-
}
|
835
|
-
if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
|
836
|
-
const def = node.name.definition();
|
837
|
-
const keep = def.global && !drop_funcs || in_use_ids.has(def.id);
|
838
|
-
// Class "extends" and static blocks may have side effects
|
839
|
-
const has_side_effects = !keep
|
840
|
-
&& node instanceof AST_Class
|
841
|
-
&& node.has_side_effects(compressor);
|
842
|
-
if (!keep && !has_side_effects) {
|
843
|
-
def.eliminated++;
|
844
|
-
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
845
|
-
}
|
846
|
-
}
|
847
|
-
if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) {
|
848
|
-
var drop_block = !(parent instanceof AST_Toplevel) && !(node instanceof AST_Var);
|
849
|
-
// place uninitialized names at the start
|
850
|
-
var body = [], head = [], tail = [];
|
851
|
-
// for unused names whose initialization has
|
852
|
-
// side effects, we can cascade the init. code
|
853
|
-
// into the next one, or next statement.
|
854
|
-
var side_effects = [];
|
855
|
-
node.definitions.forEach(function(def) {
|
856
|
-
if (def.value) def.value = def.value.transform(tt);
|
857
|
-
var is_destructure = def.name instanceof AST_Destructuring;
|
858
|
-
var sym = is_destructure
|
859
|
-
? new SymbolDef(null, { name: "<destructure>" }) /* fake SymbolDef */
|
860
|
-
: def.name.definition();
|
861
|
-
if (drop_block && sym.global) return tail.push(def);
|
862
|
-
if (!(drop_vars || drop_block)
|
863
|
-
|| is_destructure
|
864
|
-
&& (def.name.names.length
|
865
|
-
|| def.name.is_array
|
866
|
-
|| compressor.option("pure_getters") != true)
|
867
|
-
|| in_use_ids.has(sym.id)
|
868
|
-
) {
|
869
|
-
if (def.value && fixed_ids.has(sym.id) && fixed_ids.get(sym.id) !== def) {
|
870
|
-
def.value = def.value.drop_side_effect_free(compressor);
|
871
|
-
}
|
872
|
-
if (def.name instanceof AST_SymbolVar) {
|
873
|
-
var var_defs = var_defs_by_id.get(sym.id);
|
874
|
-
if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) {
|
875
|
-
if (def.value) {
|
876
|
-
var ref = make_node(AST_SymbolRef, def.name, def.name);
|
877
|
-
sym.references.push(ref);
|
878
|
-
var assign = make_node(AST_Assign, def, {
|
879
|
-
operator: "=",
|
880
|
-
logical: false,
|
881
|
-
left: ref,
|
882
|
-
right: def.value
|
883
|
-
});
|
884
|
-
if (fixed_ids.get(sym.id) === def) {
|
885
|
-
fixed_ids.set(sym.id, assign);
|
886
|
-
}
|
887
|
-
side_effects.push(assign.transform(tt));
|
888
|
-
}
|
889
|
-
remove(var_defs, def);
|
890
|
-
sym.eliminated++;
|
891
|
-
return;
|
892
|
-
}
|
893
|
-
}
|
894
|
-
if (def.value) {
|
895
|
-
if (side_effects.length > 0) {
|
896
|
-
if (tail.length > 0) {
|
897
|
-
side_effects.push(def.value);
|
898
|
-
def.value = make_sequence(def.value, side_effects);
|
899
|
-
} else {
|
900
|
-
body.push(make_node(AST_SimpleStatement, node, {
|
901
|
-
body: make_sequence(node, side_effects)
|
902
|
-
}));
|
903
|
-
}
|
904
|
-
side_effects = [];
|
905
|
-
}
|
906
|
-
tail.push(def);
|
907
|
-
} else {
|
908
|
-
head.push(def);
|
909
|
-
}
|
910
|
-
} else if (sym.orig[0] instanceof AST_SymbolCatch) {
|
911
|
-
var value = def.value && def.value.drop_side_effect_free(compressor);
|
912
|
-
if (value) side_effects.push(value);
|
913
|
-
def.value = null;
|
914
|
-
head.push(def);
|
915
|
-
} else {
|
916
|
-
var value = def.value && def.value.drop_side_effect_free(compressor);
|
917
|
-
if (value) {
|
918
|
-
side_effects.push(value);
|
919
|
-
}
|
920
|
-
sym.eliminated++;
|
921
|
-
}
|
922
|
-
});
|
923
|
-
if (head.length > 0 || tail.length > 0) {
|
924
|
-
node.definitions = head.concat(tail);
|
925
|
-
body.push(node);
|
926
|
-
}
|
927
|
-
if (side_effects.length > 0) {
|
928
|
-
body.push(make_node(AST_SimpleStatement, node, {
|
929
|
-
body: make_sequence(node, side_effects)
|
930
|
-
}));
|
931
|
-
}
|
932
|
-
switch (body.length) {
|
933
|
-
case 0:
|
934
|
-
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
935
|
-
case 1:
|
936
|
-
return body[0];
|
937
|
-
default:
|
938
|
-
return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
|
939
|
-
body: body
|
940
|
-
});
|
941
|
-
}
|
942
|
-
}
|
943
|
-
// certain combination of unused name + side effect leads to:
|
944
|
-
// https://github.com/mishoo/UglifyJS2/issues/44
|
945
|
-
// https://github.com/mishoo/UglifyJS2/issues/1830
|
946
|
-
// https://github.com/mishoo/UglifyJS2/issues/1838
|
947
|
-
// that's an invalid AST.
|
948
|
-
// We fix it at this stage by moving the `var` outside the `for`.
|
949
|
-
if (node instanceof AST_For) {
|
950
|
-
descend(node, this);
|
951
|
-
var block;
|
952
|
-
if (node.init instanceof AST_BlockStatement) {
|
953
|
-
block = node.init;
|
954
|
-
node.init = block.body.pop();
|
955
|
-
block.body.push(node);
|
956
|
-
}
|
957
|
-
if (node.init instanceof AST_SimpleStatement) {
|
958
|
-
node.init = node.init.body;
|
959
|
-
} else if (is_empty(node.init)) {
|
960
|
-
node.init = null;
|
961
|
-
}
|
962
|
-
return !block ? node : in_list ? MAP.splice(block.body) : block;
|
963
|
-
}
|
964
|
-
if (node instanceof AST_LabeledStatement
|
965
|
-
&& node.body instanceof AST_For
|
966
|
-
) {
|
967
|
-
descend(node, this);
|
968
|
-
if (node.body instanceof AST_BlockStatement) {
|
969
|
-
var block = node.body;
|
970
|
-
node.body = block.body.pop();
|
971
|
-
block.body.push(node);
|
972
|
-
return in_list ? MAP.splice(block.body) : block;
|
973
|
-
}
|
974
|
-
return node;
|
975
|
-
}
|
976
|
-
if (node instanceof AST_BlockStatement) {
|
977
|
-
descend(node, this);
|
978
|
-
if (in_list && node.body.every(can_be_evicted_from_block)) {
|
979
|
-
return MAP.splice(node.body);
|
980
|
-
}
|
981
|
-
return node;
|
982
|
-
}
|
983
|
-
if (node instanceof AST_Scope) {
|
984
|
-
const save_scope = scope;
|
985
|
-
scope = node;
|
986
|
-
descend(node, this);
|
987
|
-
scope = save_scope;
|
988
|
-
return node;
|
989
|
-
}
|
990
|
-
}
|
991
|
-
);
|
992
|
-
|
993
|
-
self.transform(tt);
|
994
|
-
|
995
|
-
function scan_ref_scoped(node, descend) {
|
996
|
-
var node_def;
|
997
|
-
const sym = assign_as_unused(node);
|
998
|
-
if (sym instanceof AST_SymbolRef
|
999
|
-
&& !is_ref_of(node.left, AST_SymbolBlockDeclaration)
|
1000
|
-
&& self.variables.get(sym.name) === (node_def = sym.definition())
|
1001
|
-
) {
|
1002
|
-
if (node instanceof AST_Assign) {
|
1003
|
-
node.right.walk(tw);
|
1004
|
-
if (!node_def.chained && node.left.fixed_value() === node.right) {
|
1005
|
-
fixed_ids.set(node_def.id, node);
|
1006
|
-
}
|
1007
|
-
}
|
1008
|
-
return true;
|
1009
|
-
}
|
1010
|
-
if (node instanceof AST_SymbolRef) {
|
1011
|
-
node_def = node.definition();
|
1012
|
-
if (!in_use_ids.has(node_def.id)) {
|
1013
|
-
in_use_ids.set(node_def.id, node_def);
|
1014
|
-
if (node_def.orig[0] instanceof AST_SymbolCatch) {
|
1015
|
-
const redef = node_def.scope.is_block_scope()
|
1016
|
-
&& node_def.scope.get_defun_scope().variables.get(node_def.name);
|
1017
|
-
if (redef) in_use_ids.set(redef.id, redef);
|
1018
|
-
}
|
1019
|
-
}
|
1020
|
-
return true;
|
1021
|
-
}
|
1022
|
-
if (node instanceof AST_Scope) {
|
1023
|
-
var save_scope = scope;
|
1024
|
-
scope = node;
|
1025
|
-
descend();
|
1026
|
-
scope = save_scope;
|
1027
|
-
return true;
|
1028
|
-
}
|
1029
|
-
}
|
1030
|
-
});
|
1031
|
-
|
1032
647
|
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
|
1033
648
|
var self = this;
|
1034
649
|
if (compressor.has_directive("use asm")) return self;
|
@@ -1173,8 +788,6 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
|
|
1173
788
|
var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
|
1174
789
|
var defs_by_id = new Map();
|
1175
790
|
var hoister = new TreeTransformer(function(node, descend) {
|
1176
|
-
if (node instanceof AST_Definitions
|
1177
|
-
&& hoister.parent() instanceof AST_Export) return node;
|
1178
791
|
if (node instanceof AST_VarDef) {
|
1179
792
|
const sym = node.name;
|
1180
793
|
let def;
|
@@ -573,7 +573,6 @@ export function is_nullish(node, compressor) {
|
|
573
573
|
return true;
|
574
574
|
}
|
575
575
|
if (node instanceof AST_This && this instanceof AST_Arrow) {
|
576
|
-
// TODO check arguments too!
|
577
576
|
result = false;
|
578
577
|
return walk_abort;
|
579
578
|
}
|
@@ -694,7 +693,7 @@ export function is_nullish(node, compressor) {
|
|
694
693
|
return this.tail_node()._dot_throw(compressor);
|
695
694
|
});
|
696
695
|
def_may_throw_on_access(AST_SymbolRef, function(compressor) {
|
697
|
-
if (this.name === "arguments") return false;
|
696
|
+
if (this.name === "arguments" && this.scope instanceof AST_Lambda) return false;
|
698
697
|
if (has_flag(this, UNDEFINED)) return true;
|
699
698
|
if (!is_strict(compressor)) return false;
|
700
699
|
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
package/lib/compress/inline.js
CHANGED
@@ -57,10 +57,8 @@ import {
|
|
57
57
|
AST_Expansion,
|
58
58
|
AST_Export,
|
59
59
|
AST_Function,
|
60
|
-
AST_Infinity,
|
61
60
|
AST_IterationStatement,
|
62
61
|
AST_Lambda,
|
63
|
-
AST_NaN,
|
64
62
|
AST_Node,
|
65
63
|
AST_Number,
|
66
64
|
AST_Object,
|
@@ -81,7 +79,6 @@ import {
|
|
81
79
|
AST_Undefined,
|
82
80
|
AST_Var,
|
83
81
|
AST_VarDef,
|
84
|
-
AST_With,
|
85
82
|
|
86
83
|
walk,
|
87
84
|
|
@@ -95,7 +92,7 @@ import "../size.js";
|
|
95
92
|
import "./evaluate.js";
|
96
93
|
import "./drop-side-effect-free.js";
|
97
94
|
import "./reduce-vars.js";
|
98
|
-
import {
|
95
|
+
import { is_lhs } from "./inference.js";
|
99
96
|
import {
|
100
97
|
SQUEEZED,
|
101
98
|
INLINED,
|
@@ -146,21 +143,6 @@ function scope_encloses_variables_in_this_scope(scope, pulled_scope) {
|
|
146
143
|
}
|
147
144
|
|
148
145
|
export function inline_into_symbolref(self, compressor) {
|
149
|
-
if (
|
150
|
-
!compressor.option("ie8")
|
151
|
-
&& is_undeclared_ref(self)
|
152
|
-
&& !compressor.find_parent(AST_With)
|
153
|
-
) {
|
154
|
-
switch (self.name) {
|
155
|
-
case "undefined":
|
156
|
-
return make_node(AST_Undefined, self).optimize(compressor);
|
157
|
-
case "NaN":
|
158
|
-
return make_node(AST_NaN, self).optimize(compressor);
|
159
|
-
case "Infinity":
|
160
|
-
return make_node(AST_Infinity, self).optimize(compressor);
|
161
|
-
}
|
162
|
-
}
|
163
|
-
|
164
146
|
const parent = compressor.parent();
|
165
147
|
if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
|
166
148
|
const def = self.definition();
|
@@ -205,9 +205,10 @@ export function trim_unreachable_code(compressor, stat, target) {
|
|
205
205
|
|
206
206
|
/** Tighten a bunch of statements together, and perform statement-level optimization. */
|
207
207
|
export function tighten_body(statements, compressor) {
|
208
|
-
|
209
|
-
|
210
|
-
find_loop_scope_try();
|
208
|
+
const nearest_scope = compressor.find_scope();
|
209
|
+
const defun_scope = nearest_scope.get_defun_scope();
|
210
|
+
const { in_loop, in_try } = find_loop_scope_try();
|
211
|
+
|
211
212
|
var CHANGED, max_iter = 10;
|
212
213
|
do {
|
213
214
|
CHANGED = false;
|
@@ -231,19 +232,20 @@ export function tighten_body(statements, compressor) {
|
|
231
232
|
} while (CHANGED && max_iter-- > 0);
|
232
233
|
|
233
234
|
function find_loop_scope_try() {
|
234
|
-
var node = compressor.self(), level = 0;
|
235
|
+
var node = compressor.self(), level = 0, in_loop = false, in_try = false;
|
235
236
|
do {
|
236
237
|
if (node instanceof AST_Catch || node instanceof AST_Finally) {
|
237
238
|
level++;
|
238
239
|
} else if (node instanceof AST_IterationStatement) {
|
239
240
|
in_loop = true;
|
240
241
|
} else if (node instanceof AST_Scope) {
|
241
|
-
scope = node;
|
242
242
|
break;
|
243
243
|
} else if (node instanceof AST_Try) {
|
244
244
|
in_try = true;
|
245
245
|
}
|
246
246
|
} while (node = compressor.parent(level++));
|
247
|
+
|
248
|
+
return { in_loop, in_try };
|
247
249
|
}
|
248
250
|
|
249
251
|
// Search from right to left for assignment-like expressions:
|
@@ -255,7 +257,7 @@ export function tighten_body(statements, compressor) {
|
|
255
257
|
// Will not attempt to collapse assignments into or past code blocks
|
256
258
|
// which are not sequentially executed, e.g. loops and conditionals.
|
257
259
|
function collapse(statements, compressor) {
|
258
|
-
if (
|
260
|
+
if (nearest_scope.pinned() || defun_scope.pinned())
|
259
261
|
return statements;
|
260
262
|
var args;
|
261
263
|
var candidates = [];
|
@@ -319,10 +321,11 @@ export function tighten_body(statements, compressor) {
|
|
319
321
|
stop_if_hit = parent;
|
320
322
|
}
|
321
323
|
// Replace variable with assignment when found
|
322
|
-
if (
|
324
|
+
if (
|
325
|
+
can_replace
|
323
326
|
&& !(node instanceof AST_SymbolDeclaration)
|
324
327
|
&& lhs.equivalent_to(node)
|
325
|
-
&& !shadows(
|
328
|
+
&& !shadows(scanner.find_scope() || nearest_scope, lvalues)
|
326
329
|
) {
|
327
330
|
if (stop_if_hit) {
|
328
331
|
abort = true;
|
@@ -527,9 +530,9 @@ export function tighten_body(statements, compressor) {
|
|
527
530
|
return true;
|
528
531
|
if (node instanceof AST_SymbolRef && (fn.variables.has(node.name) || redefined_within_scope(node.definition(), fn))) {
|
529
532
|
var s = node.definition().scope;
|
530
|
-
if (s !==
|
533
|
+
if (s !== defun_scope)
|
531
534
|
while (s = s.parent_scope) {
|
532
|
-
if (s ===
|
535
|
+
if (s === defun_scope)
|
533
536
|
return true;
|
534
537
|
}
|
535
538
|
return found = true;
|
@@ -851,7 +854,7 @@ export function tighten_body(statements, compressor) {
|
|
851
854
|
while (lhs instanceof AST_PropAccess)
|
852
855
|
lhs = lhs.expression;
|
853
856
|
return lhs instanceof AST_SymbolRef
|
854
|
-
&& lhs.definition().scope ===
|
857
|
+
&& lhs.definition().scope.get_defun_scope() === defun_scope
|
855
858
|
&& !(in_loop
|
856
859
|
&& (lvalues.has(lhs.name)
|
857
860
|
|| candidate instanceof AST_Unary
|
@@ -886,15 +889,11 @@ export function tighten_body(statements, compressor) {
|
|
886
889
|
var def = sym.definition();
|
887
890
|
if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun)
|
888
891
|
return false;
|
889
|
-
if (def.scope.get_defun_scope() !==
|
892
|
+
if (def.scope.get_defun_scope() !== defun_scope)
|
890
893
|
return true;
|
891
|
-
return
|
892
|
-
|
893
|
-
|
894
|
-
if (s.TYPE == "Scope")
|
895
|
-
s = s.parent_scope;
|
896
|
-
return s === scope;
|
897
|
-
});
|
894
|
+
return def.references.some((ref) =>
|
895
|
+
ref.scope.get_defun_scope() !== defun_scope
|
896
|
+
);
|
898
897
|
}
|
899
898
|
|
900
899
|
function side_effects_external(node, lhs) {
|
@@ -910,18 +909,20 @@ export function tighten_body(statements, compressor) {
|
|
910
909
|
if (node instanceof AST_Sub)
|
911
910
|
return side_effects_external(node.expression, true);
|
912
911
|
if (node instanceof AST_SymbolRef)
|
913
|
-
return node.definition().scope !==
|
912
|
+
return node.definition().scope.get_defun_scope() !== defun_scope;
|
914
913
|
}
|
915
914
|
return false;
|
916
915
|
}
|
917
916
|
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
917
|
+
/**
|
918
|
+
* Will any of the pulled-in lvalues shadow a variable in newScope or parents?
|
919
|
+
* similar to scope_encloses_variables_in_this_scope */
|
920
|
+
function shadows(my_scope, lvalues) {
|
921
|
+
for (const { def } of lvalues.values()) {
|
922
|
+
const looked_up = my_scope.find_variable(def.name);
|
923
|
+
if (looked_up) {
|
924
|
+
if (looked_up === def) continue;
|
925
|
+
return true;
|
925
926
|
}
|
926
927
|
}
|
927
928
|
return false;
|
@@ -1343,7 +1344,7 @@ export function tighten_body(statements, compressor) {
|
|
1343
1344
|
break;
|
1344
1345
|
if (def.name.name != sym.name)
|
1345
1346
|
break;
|
1346
|
-
if (!node.right.is_constant_expression(
|
1347
|
+
if (!node.right.is_constant_expression(nearest_scope))
|
1347
1348
|
break;
|
1348
1349
|
var prop = node.left.property;
|
1349
1350
|
if (prop instanceof AST_Node) {
|