Compare commits
22 Commits
harmony-v3
...
harmony-v3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
873755b35c | ||
|
|
744032755d | ||
|
|
4fac8076b8 | ||
|
|
6920e898d1 | ||
|
|
dd71639264 | ||
|
|
2dcc552ce0 | ||
|
|
a020d2ead3 | ||
|
|
68645b28d3 | ||
|
|
aaa8212837 | ||
|
|
bd84007cf4 | ||
|
|
55387e8fd0 | ||
|
|
1241600013 | ||
|
|
7e3e9da860 | ||
|
|
a784717fe2 | ||
|
|
00f509405b | ||
|
|
e8235657e4 | ||
|
|
c46b9f361a | ||
|
|
3b0b4d6abf | ||
|
|
d73500e8d1 | ||
|
|
aceb0af36b | ||
|
|
4f0953f7e9 | ||
|
|
182a47bfb1 |
@@ -631,6 +631,13 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
- `unsafe_math` (default: false) -- optimize numerical expressions like
|
||||
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
|
||||
|
||||
- `unsafe_methods` (default: false) -- Converts `{ m: function(){} }` to
|
||||
`{ m(){} }`. `ecma` must be set to `6` or greater to enable this transform.
|
||||
If `unsafe_methods` is a RegExp then key/value pairs with keys matching the
|
||||
RegExp will be converted to concise methods.
|
||||
Note: if enabled there is a risk of getting a "`<method name>` is not a
|
||||
constructor" TypeError should any code try to `new` the former function.
|
||||
|
||||
- `unsafe_proto` (default: false) -- optimize expressions like
|
||||
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
|
||||
|
||||
|
||||
@@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, {
|
||||
$documentation: "Represents a debugger statement",
|
||||
}, AST_Statement);
|
||||
|
||||
var AST_Directive = DEFNODE("Directive", "value scope quote", {
|
||||
var AST_Directive = DEFNODE("Directive", "value quote", {
|
||||
$documentation: "Represents a directive, like \"use strict\";",
|
||||
$propdoc: {
|
||||
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
||||
scope: "[AST_Scope/S] The scope that this directive affects",
|
||||
quote: "[string] the original quote character"
|
||||
},
|
||||
}, AST_Statement);
|
||||
@@ -303,10 +302,9 @@ var AST_With = DEFNODE("With", "expression", {
|
||||
|
||||
/* -----[ scope and functions ]----- */
|
||||
|
||||
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
|
||||
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
|
||||
$documentation: "Base class for all statements introducing a lexical scope",
|
||||
$propdoc: {
|
||||
directives: "[string*/S] an array of directives declared in this scope",
|
||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
||||
|
||||
@@ -88,6 +88,7 @@ function Compressor(options, false_by_default) {
|
||||
unsafe_comps : false,
|
||||
unsafe_Func : false,
|
||||
unsafe_math : false,
|
||||
unsafe_methods: false,
|
||||
unsafe_proto : false,
|
||||
unsafe_regexp : false,
|
||||
unused : !false_by_default,
|
||||
@@ -289,6 +290,10 @@ merge(Compressor.prototype, {
|
||||
|
||||
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) {
|
||||
var reduce_vars = rescan && compressor.option("reduce_vars");
|
||||
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
||||
// properly assigned before use:
|
||||
// - `push()` & `pop()` when visiting conditional branches
|
||||
// - backup & restore via `save_ids` when visiting out-of-order sections
|
||||
var safe_ids = Object.create(null);
|
||||
var suppressor = new TreeWalker(function(node) {
|
||||
if (!(node instanceof AST_Symbol)) return;
|
||||
@@ -404,10 +409,9 @@ merge(Compressor.prototype, {
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Accessor) {
|
||||
var save_ids = safe_ids;
|
||||
safe_ids = Object.create(null);
|
||||
push();
|
||||
descend();
|
||||
safe_ids = save_ids;
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Binary
|
||||
@@ -579,6 +583,8 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function is_lhs_read_only(lhs) {
|
||||
if (lhs instanceof AST_Super) return true;
|
||||
if (lhs instanceof AST_This) return true;
|
||||
if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
||||
if (lhs instanceof AST_PropAccess) {
|
||||
lhs = lhs.expression;
|
||||
@@ -782,7 +788,7 @@ merge(Compressor.prototype, {
|
||||
while (candidates.length > 0) {
|
||||
var candidate = candidates.pop();
|
||||
var lhs = get_lhs(candidate);
|
||||
if (!lhs || is_lhs_read_only(lhs)) continue;
|
||||
if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor)) continue;
|
||||
// Locate symbols which may execute code outside of scanning range
|
||||
var lvalues = get_lvalues(candidate);
|
||||
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
|
||||
@@ -872,7 +878,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
function has_overlapping_symbol(fn, arg) {
|
||||
function has_overlapping_symbol(fn, arg, fn_strict) {
|
||||
var found = false, scan_this = !(fn instanceof AST_Arrow);
|
||||
arg.walk(new TreeWalker(function(node, descend) {
|
||||
if (found) return true;
|
||||
@@ -883,7 +889,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
return found = true;
|
||||
}
|
||||
if (scan_this && node instanceof AST_This) {
|
||||
if ((fn_strict || scan_this) && node instanceof AST_This) {
|
||||
return found = true;
|
||||
}
|
||||
if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) {
|
||||
@@ -908,6 +914,8 @@ merge(Compressor.prototype, {
|
||||
&& all(iife.args, function(arg) {
|
||||
return !(arg instanceof AST_Expansion);
|
||||
})) {
|
||||
var fn_strict = compressor.has_directive("use strict");
|
||||
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
|
||||
var names = Object.create(null);
|
||||
for (var i = fn.argnames.length; --i >= 0;) {
|
||||
var sym = fn.argnames[i];
|
||||
@@ -916,7 +924,7 @@ merge(Compressor.prototype, {
|
||||
if (sym instanceof AST_Expansion) {
|
||||
var elements = iife.args.slice(i);
|
||||
if (all(elements, function(arg) {
|
||||
return !has_overlapping_symbol(fn, arg);
|
||||
return !has_overlapping_symbol(fn, arg, fn_strict);
|
||||
})) {
|
||||
candidates.unshift(make_node(AST_VarDef, sym, {
|
||||
name: sym.expression,
|
||||
@@ -928,7 +936,7 @@ merge(Compressor.prototype, {
|
||||
} else {
|
||||
var arg = iife.args[i];
|
||||
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
|
||||
else if (has_overlapping_symbol(fn, arg)) arg = null;
|
||||
else if (has_overlapping_symbol(fn, arg, fn_strict)) arg = null;
|
||||
if (arg) candidates.unshift(make_node(AST_VarDef, sym, {
|
||||
name: sym,
|
||||
value: arg
|
||||
@@ -2108,6 +2116,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
def(AST_EmptyStatement, return_false);
|
||||
def(AST_Constant, return_false);
|
||||
def(AST_Super, return_false);
|
||||
def(AST_This, return_false);
|
||||
|
||||
def(AST_Call, function(compressor){
|
||||
@@ -2786,6 +2795,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
def(AST_Node, return_this);
|
||||
def(AST_Constant, return_null);
|
||||
def(AST_Super, return_null);
|
||||
def(AST_This, return_null);
|
||||
def(AST_Call, function(compressor, first_in_statement){
|
||||
if (!this.is_expr_pure(compressor)) {
|
||||
@@ -3710,7 +3720,10 @@ merge(Compressor.prototype, {
|
||||
&& (left.operator == "++" || left.operator == "--")) {
|
||||
left = left.expression;
|
||||
} else left = null;
|
||||
if (!left || is_lhs_read_only(left) || is_ref_of(left, AST_SymbolConst)) {
|
||||
if (!left
|
||||
|| is_lhs_read_only(left)
|
||||
|| left.has_side_effects(compressor)
|
||||
|| is_ref_of(left, AST_SymbolConst)) {
|
||||
expressions[++i] = cdr;
|
||||
continue;
|
||||
}
|
||||
@@ -4859,7 +4872,10 @@ merge(Compressor.prototype, {
|
||||
// p:async function(){} ---> async p(){}
|
||||
// p:()=>{} ---> p(){}
|
||||
// p:async()=>{} ---> async p(){}
|
||||
if (compressor.option("ecma") >= 6) {
|
||||
var unsafe_methods = compressor.option("unsafe_methods");
|
||||
if (unsafe_methods
|
||||
&& compressor.option("ecma") >= 6
|
||||
&& (!(unsafe_methods instanceof RegExp) || unsafe_methods.test(self.key + ""))) {
|
||||
var key = self.key;
|
||||
var value = self.value;
|
||||
var is_arrow_with_block = value instanceof AST_Arrow
|
||||
|
||||
@@ -506,13 +506,17 @@ function OutputStream(options) {
|
||||
nodetype.DEFMETHOD("_codegen", generator);
|
||||
};
|
||||
|
||||
var use_asm = false;
|
||||
var in_directive = false;
|
||||
var active_scope = null;
|
||||
var use_asm = null;
|
||||
|
||||
AST_Node.DEFMETHOD("print", function(stream, force_parens){
|
||||
var self = this, generator = self._codegen, prev_use_asm = use_asm;
|
||||
if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
|
||||
use_asm = true;
|
||||
var self = this, generator = self._codegen;
|
||||
if (self instanceof AST_Scope) {
|
||||
active_scope = self;
|
||||
}
|
||||
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
|
||||
use_asm = active_scope;
|
||||
}
|
||||
function doit() {
|
||||
self.add_comments(stream);
|
||||
@@ -526,8 +530,8 @@ function OutputStream(options) {
|
||||
doit();
|
||||
}
|
||||
stream.pop_node();
|
||||
if (self instanceof AST_Scope) {
|
||||
use_asm = prev_use_asm;
|
||||
if (self === use_asm) {
|
||||
use_asm = null;
|
||||
}
|
||||
});
|
||||
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||
@@ -1398,7 +1402,7 @@ function OutputStream(options) {
|
||||
self.expression.print(output);
|
||||
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
||||
return;
|
||||
if (self.expression instanceof AST_Lambda) {
|
||||
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
|
||||
output.add_mapping(self.start);
|
||||
}
|
||||
output.with_parens(function(){
|
||||
|
||||
28
lib/parse.js
28
lib/parse.js
@@ -44,9 +44,9 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var KEYWORDS = 'break case catch class const continue debugger default delete do else export extends finally for function if in instanceof new return switch throw try typeof var let void while with import';
|
||||
var KEYWORDS = 'break case catch class const continue debugger default delete do else export extends finally for function if in instanceof let new return switch throw try typeof var void while with';
|
||||
var KEYWORDS_ATOM = 'false null true';
|
||||
var RESERVED_WORDS = 'enum implements interface package private protected public static super this ' + KEYWORDS_ATOM + " " + KEYWORDS;
|
||||
var RESERVED_WORDS = 'enum implements import interface package private protected public static super this ' + KEYWORDS_ATOM + " " + KEYWORDS;
|
||||
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case yield await';
|
||||
|
||||
KEYWORDS = makePredicate(KEYWORDS);
|
||||
@@ -1013,6 +1013,12 @@ function parse($TEXT, options) {
|
||||
next();
|
||||
return function_(AST_Defun, false, true);
|
||||
}
|
||||
if (S.token.value == "import" && !is_token(peek(), "punc", "(")) {
|
||||
next();
|
||||
var node = import_();
|
||||
semicolon();
|
||||
return node;
|
||||
}
|
||||
return is_token(peek(), "punc", ":")
|
||||
? labeled_statement()
|
||||
: simple_statement();
|
||||
@@ -1149,15 +1155,11 @@ function parse($TEXT, options) {
|
||||
body : statement()
|
||||
});
|
||||
|
||||
case "import":
|
||||
next();
|
||||
var node = import_();
|
||||
semicolon();
|
||||
return node;
|
||||
|
||||
case "export":
|
||||
next();
|
||||
return export_();
|
||||
if (!is_token(peek(), "punc", "(")) {
|
||||
next();
|
||||
return export_();
|
||||
}
|
||||
}
|
||||
}
|
||||
unexpected();
|
||||
@@ -1320,6 +1322,9 @@ function parse($TEXT, options) {
|
||||
if (in_statement && !name)
|
||||
unexpected();
|
||||
|
||||
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
||||
unexpected(prev());
|
||||
|
||||
var args = parameters();
|
||||
var body = _function_body(true, is_generator || is_generator_property, is_async, name, args);
|
||||
return new ctor({
|
||||
@@ -1875,7 +1880,8 @@ function parse($TEXT, options) {
|
||||
: !no_in && kind === "const" && S.input.has_directive("use strict")
|
||||
? croak("Missing initializer in const declaration") : null,
|
||||
end : prev()
|
||||
})
|
||||
});
|
||||
if (def.name.name == "import") croak("Unexpected token: import");
|
||||
}
|
||||
a.push(def);
|
||||
if (!is("punc", ","))
|
||||
|
||||
@@ -546,7 +546,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
||||
var mangle_with_block_scope =
|
||||
(!options.ie8 && node instanceof AST_SymbolCatch) ||
|
||||
node instanceof AST_SymbolBlockDeclaration;
|
||||
if (mangle_with_block_scope) {
|
||||
if (mangle_with_block_scope && options.reserved.indexOf(node.name) < 0) {
|
||||
to_mangle.push(node.definition());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.3",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -290,6 +290,7 @@ issue_2105_1: {
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unsafe_methods: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
|
||||
@@ -104,3 +104,65 @@ asm_mixed: {
|
||||
}
|
||||
}
|
||||
|
||||
asm_toplevel: {
|
||||
options = {}
|
||||
input: {
|
||||
"use asm";
|
||||
0.0;
|
||||
function f() {
|
||||
0.0;
|
||||
(function(){
|
||||
0.0;
|
||||
});
|
||||
}
|
||||
0.0;
|
||||
}
|
||||
expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;'
|
||||
}
|
||||
|
||||
asm_function_expression: {
|
||||
options = {}
|
||||
input: {
|
||||
0.0;
|
||||
var a = function() {
|
||||
"use asm";
|
||||
0.0;
|
||||
}
|
||||
function f() {
|
||||
0.0;
|
||||
return function(){
|
||||
"use asm";
|
||||
0.0;
|
||||
}
|
||||
0.0;
|
||||
}
|
||||
0.0;
|
||||
}
|
||||
expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;'
|
||||
}
|
||||
|
||||
asm_nested_functions: {
|
||||
options = {}
|
||||
input: {
|
||||
0.0;
|
||||
function a() {
|
||||
"use asm";
|
||||
0.0;
|
||||
}
|
||||
0.0;
|
||||
function b() {
|
||||
0.0;
|
||||
function c(){
|
||||
"use asm";
|
||||
0.0;
|
||||
}
|
||||
0.0;
|
||||
function d(){
|
||||
0.0;
|
||||
}
|
||||
0.0;
|
||||
}
|
||||
0.0;
|
||||
}
|
||||
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
|
||||
}
|
||||
|
||||
@@ -2658,3 +2658,140 @@ issue_2298: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2313_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = 0;
|
||||
var foo = {
|
||||
get c() {
|
||||
a++;
|
||||
return 42;
|
||||
},
|
||||
set c(c) {
|
||||
b++;
|
||||
},
|
||||
d: function() {
|
||||
this.c++;
|
||||
if (this.c) console.log(a, b);
|
||||
}
|
||||
}
|
||||
foo.d();
|
||||
}
|
||||
expect: {
|
||||
var a = 0, b = 0;
|
||||
var foo = {
|
||||
get c() {
|
||||
a++;
|
||||
return 42;
|
||||
},
|
||||
set c(c) {
|
||||
b++;
|
||||
},
|
||||
d: function() {
|
||||
this.c++;
|
||||
this.c && console.log(a, b);
|
||||
}
|
||||
}
|
||||
foo.d();
|
||||
}
|
||||
expect_stdout: "2 1"
|
||||
}
|
||||
|
||||
issue_2313_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
!function a() {
|
||||
a && c++;
|
||||
var a = 0;
|
||||
a && c++;
|
||||
}();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
!function a() {
|
||||
a && c++;
|
||||
var a = 0;
|
||||
a && c++;
|
||||
}();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_2319_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(!function() {
|
||||
return this;
|
||||
}()));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return !function() {
|
||||
return this;
|
||||
}();
|
||||
}());
|
||||
}
|
||||
expect_stdout: "false"
|
||||
}
|
||||
|
||||
issue_2319_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
"use strict";
|
||||
return a;
|
||||
}(!function() {
|
||||
return this;
|
||||
}()));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
"use strict";
|
||||
return a;
|
||||
}(!function() {
|
||||
return this;
|
||||
}()));
|
||||
}
|
||||
expect_stdout: "false"
|
||||
}
|
||||
|
||||
issue_2319_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(!function() {
|
||||
return this;
|
||||
}()));
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
console.log(function(a) {
|
||||
return !function() {
|
||||
return this;
|
||||
}();
|
||||
}());
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
@@ -226,3 +226,27 @@ keyword_valid_3: {
|
||||
export { default as default } from "module.js";
|
||||
}
|
||||
}
|
||||
|
||||
dynamic_import: {
|
||||
mangle = {
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
import traditional from './traditional.js';
|
||||
function imp(x) {
|
||||
return import(x);
|
||||
}
|
||||
import("module_for_side_effects.js");
|
||||
let dynamic = import("some/module.js");
|
||||
dynamic.foo();
|
||||
}
|
||||
expect: {
|
||||
import o from "./traditional.js";
|
||||
function t(o) {
|
||||
return import(o);
|
||||
}
|
||||
import("module_for_side_effects.js");
|
||||
let r = import("some/module.js");
|
||||
r.foo();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -804,3 +804,38 @@ object_spread_of_sequence: {
|
||||
console.log({ ...o || o });
|
||||
}
|
||||
}
|
||||
|
||||
// issue 2316
|
||||
class_name_can_be_preserved_with_reserved: {
|
||||
mangle = {
|
||||
reserved: [ "Foo" ],
|
||||
}
|
||||
input: {
|
||||
function x() {
|
||||
class Foo {}
|
||||
Foo.bar;
|
||||
class Bar {}
|
||||
Bar.foo;
|
||||
}
|
||||
function y() {
|
||||
var Foo = class Foo {};
|
||||
Foo.bar;
|
||||
var Bar = class Bar {};
|
||||
Bar.bar;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function x() {
|
||||
class Foo {}
|
||||
Foo.bar;
|
||||
class a {}
|
||||
a.foo;
|
||||
}
|
||||
function y() {
|
||||
var Foo = class Foo {};
|
||||
Foo.bar;
|
||||
var a = class a {};
|
||||
a.bar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,6 +516,7 @@ variable_as_computed_property: {
|
||||
prop_func_to_concise_method: {
|
||||
options = {
|
||||
ecma: 6,
|
||||
unsafe_methods: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
@@ -544,6 +545,7 @@ prop_func_to_concise_method: {
|
||||
prop_arrow_to_concise_method: {
|
||||
options = {
|
||||
ecma: 6,
|
||||
unsafe_methods: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
@@ -592,6 +594,7 @@ concise_method_to_prop_arrow: {
|
||||
prop_func_to_async_concise_method: {
|
||||
options = {
|
||||
ecma: 8,
|
||||
unsafe_methods: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
@@ -614,6 +617,7 @@ prop_func_to_async_concise_method: {
|
||||
prop_func_to_concise_method_various: {
|
||||
options = {
|
||||
ecma: 6,
|
||||
unsafe_methods: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
@@ -646,6 +650,7 @@ prop_func_to_concise_method_various: {
|
||||
prop_arrows_to_concise_method_various: {
|
||||
options = {
|
||||
ecma: 6,
|
||||
unsafe_methods: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
@@ -674,6 +679,7 @@ prop_arrows_to_concise_method_various: {
|
||||
prop_arrow_with_this: {
|
||||
options = {
|
||||
ecma: 6,
|
||||
unsafe_methods: true,
|
||||
}
|
||||
input: {
|
||||
function run(arg) {
|
||||
@@ -711,6 +717,7 @@ prop_arrow_with_this: {
|
||||
prop_arrow_with_nested_this: {
|
||||
options = {
|
||||
ecma: 6,
|
||||
unsafe_methods: true,
|
||||
}
|
||||
input: {
|
||||
function run(arg) {
|
||||
|
||||
@@ -887,6 +887,7 @@ methods_keep_quoted_true: {
|
||||
options = {
|
||||
arrows: true,
|
||||
ecma: 6,
|
||||
unsafe_methods: true,
|
||||
}
|
||||
mangle = {
|
||||
properties: {
|
||||
@@ -906,6 +907,7 @@ methods_keep_quoted_false: {
|
||||
options = {
|
||||
arrows: true,
|
||||
ecma: 6,
|
||||
unsafe_methods: true,
|
||||
}
|
||||
mangle = {
|
||||
properties: {
|
||||
@@ -931,6 +933,7 @@ methods_keep_quoted_from_dead_code: {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unsafe_methods: true,
|
||||
}
|
||||
mangle = {
|
||||
properties: {
|
||||
@@ -964,3 +967,88 @@ issue_2256: {
|
||||
g.keep = g.g;
|
||||
}
|
||||
}
|
||||
|
||||
issue_2321: {
|
||||
options = {
|
||||
ecma: 6,
|
||||
unsafe_methods: false,
|
||||
}
|
||||
input: {
|
||||
var f = {
|
||||
foo: function(){ console.log("foo") },
|
||||
bar() { console.log("bar") }
|
||||
};
|
||||
var foo = new f.foo();
|
||||
var bar = f.bar();
|
||||
}
|
||||
expect: {
|
||||
var f = {
|
||||
foo: function() {
|
||||
console.log("foo");
|
||||
},
|
||||
bar() {
|
||||
console.log("bar");
|
||||
}
|
||||
};
|
||||
var foo = new f.foo();
|
||||
var bar = f.bar();
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"bar",
|
||||
]
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
unsafe_methods_regex: {
|
||||
options = {
|
||||
ecma: 6,
|
||||
unsafe_methods: /^[A-Z1]/,
|
||||
}
|
||||
input: {
|
||||
var f = {
|
||||
123: function(){ console.log("123") },
|
||||
foo: function(){ console.log("foo") },
|
||||
bar() { console.log("bar") },
|
||||
Baz: function(){ console.log("baz") },
|
||||
BOO: function(){ console.log("boo") },
|
||||
null: function(){ console.log("null") },
|
||||
undefined: function(){ console.log("undefined") },
|
||||
};
|
||||
f[123]();
|
||||
new f.foo();
|
||||
f.bar();
|
||||
f.Baz();
|
||||
f.BOO();
|
||||
new f.null();
|
||||
new f.undefined();
|
||||
}
|
||||
expect: {
|
||||
var f = {
|
||||
123() { console.log("123") },
|
||||
foo: function(){ console.log("foo") },
|
||||
bar() { console.log("bar"); },
|
||||
Baz() { console.log("baz") },
|
||||
BOO() { console.log("boo") },
|
||||
null: function(){ console.log("null") },
|
||||
undefined: function(){ console.log("undefined") },
|
||||
};
|
||||
f[123]();
|
||||
new f.foo();
|
||||
f.bar();
|
||||
f.Baz();
|
||||
f.BOO();
|
||||
new f.null();
|
||||
new f.undefined();
|
||||
}
|
||||
expect_stdout: [
|
||||
"123",
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
"boo",
|
||||
"null",
|
||||
"undefined",
|
||||
]
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
@@ -458,3 +458,265 @@ issue_2265_4: {
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
issue_2313_1: {
|
||||
options = {
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
pure_getters: "strict",
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
function x() {
|
||||
console.log(1);
|
||||
return {
|
||||
y: function() {
|
||||
console.log(2);
|
||||
return {
|
||||
z: 0
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
x().y().z++;
|
||||
if (x().y().z) {
|
||||
console.log(3);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function x() {
|
||||
return console.log(1), {
|
||||
y: function() {
|
||||
return console.log(2), {
|
||||
z: 0
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
x().y().z++,
|
||||
x().y().z && console.log(3);
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
"2",
|
||||
"1",
|
||||
"2",
|
||||
]
|
||||
}
|
||||
|
||||
issue_2313_2: {
|
||||
options = {
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
pure_getters: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
function x() {
|
||||
console.log(1);
|
||||
return {
|
||||
y: function() {
|
||||
console.log(2);
|
||||
return {
|
||||
z: 0
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
x().y().z++;
|
||||
if (x().y().z) {
|
||||
console.log(3);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function x() {
|
||||
return console.log(1), {
|
||||
y: function() {
|
||||
return console.log(2), {
|
||||
z: 0
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
x().y().z++,
|
||||
x().y().z && console.log(3);
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
"2",
|
||||
"1",
|
||||
"2",
|
||||
]
|
||||
}
|
||||
|
||||
issue_2313_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
pure_getters: "strict",
|
||||
}
|
||||
input: {
|
||||
function x() {
|
||||
console.log(1);
|
||||
return {
|
||||
y: function() {
|
||||
console.log(2);
|
||||
return {
|
||||
z: 0
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
x().y().z++;
|
||||
if (x().y().z) {
|
||||
console.log(3);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function x() {
|
||||
console.log(1);
|
||||
return {
|
||||
y: function() {
|
||||
console.log(2);
|
||||
return {
|
||||
z: 0
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
x().y().z++;
|
||||
x().y().z && console.log(3);
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
"2",
|
||||
"1",
|
||||
"2",
|
||||
]
|
||||
}
|
||||
|
||||
issue_2313_4: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
pure_getters: true,
|
||||
}
|
||||
input: {
|
||||
function x() {
|
||||
console.log(1);
|
||||
return {
|
||||
y: function() {
|
||||
console.log(2);
|
||||
return {
|
||||
z: 0
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
x().y().z++;
|
||||
if (x().y().z) {
|
||||
console.log(3);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function x() {
|
||||
console.log(1);
|
||||
return {
|
||||
y: function() {
|
||||
console.log(2);
|
||||
return {
|
||||
z: 0
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
x().y().z++;
|
||||
x().y().z && console.log(3);
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
"2",
|
||||
"1",
|
||||
"2",
|
||||
]
|
||||
}
|
||||
|
||||
issue_2313_5: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
x().y++;
|
||||
x().y;
|
||||
}
|
||||
expect: {
|
||||
x().y++;
|
||||
x().y;
|
||||
}
|
||||
}
|
||||
|
||||
issue_2313_6: {
|
||||
options = {
|
||||
pure_getters: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
x().y++;
|
||||
x().y;
|
||||
}
|
||||
expect: {
|
||||
x().y++;
|
||||
x();
|
||||
}
|
||||
}
|
||||
|
||||
issue_2313_7: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
pure_getters: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = 0;
|
||||
class foo {
|
||||
get c() {
|
||||
a++;
|
||||
return 42;
|
||||
}
|
||||
set c(c) {
|
||||
b++;
|
||||
}
|
||||
}
|
||||
class bar extends foo {
|
||||
d() {
|
||||
super.c++;
|
||||
if (super.c) console.log(a, b);
|
||||
}
|
||||
}
|
||||
new bar().d();
|
||||
}
|
||||
expect: {
|
||||
var a = 0, b = 0;
|
||||
class foo {
|
||||
get c() {
|
||||
a++;
|
||||
return 42;
|
||||
}
|
||||
set c(c) {
|
||||
b++;
|
||||
}
|
||||
}
|
||||
class bar extends foo {
|
||||
d() {
|
||||
super.c++;
|
||||
super.c && console.log(a, b);
|
||||
}
|
||||
}
|
||||
new bar().d();
|
||||
}
|
||||
expect_stdout: "2 1"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
@@ -2549,7 +2549,7 @@ issue_1922_2: {
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
accessor: {
|
||||
accessor_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
@@ -2578,6 +2578,89 @@ accessor: {
|
||||
expect_stdout: "1 1"
|
||||
}
|
||||
|
||||
accessor_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var A = 1;
|
||||
var B = {
|
||||
get c() {
|
||||
console.log(A);
|
||||
}
|
||||
};
|
||||
B.c;
|
||||
}
|
||||
expect: {
|
||||
({
|
||||
get c() {
|
||||
console.log(1);
|
||||
}
|
||||
}).c;
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
method_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
console.log(new class {
|
||||
a() {
|
||||
a = 2;
|
||||
return a;
|
||||
}
|
||||
}().a(), a);
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
console.log(new class {
|
||||
a() {
|
||||
a = 2;
|
||||
return a;
|
||||
}
|
||||
}().a(), a);
|
||||
}
|
||||
expect_stdout: "2 2"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
method_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var A = 1;
|
||||
var B = class {
|
||||
c() {
|
||||
console.log(A);
|
||||
}
|
||||
};
|
||||
new B().c();
|
||||
}
|
||||
expect: {
|
||||
new class {
|
||||
c() {
|
||||
console.log(1);
|
||||
}
|
||||
}().c();
|
||||
}
|
||||
expect_stdout: "1"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_2090_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
|
||||
@@ -763,3 +763,44 @@ issue_2062: {
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_2313: {
|
||||
options = {
|
||||
cascade: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = 0;
|
||||
var foo = {
|
||||
get c() {
|
||||
a++;
|
||||
return 42;
|
||||
},
|
||||
set c(c) {
|
||||
b++;
|
||||
},
|
||||
d: function() {
|
||||
this.c++;
|
||||
if (this.c) console.log(a, b);
|
||||
}
|
||||
}
|
||||
foo.d();
|
||||
}
|
||||
expect: {
|
||||
var a = 0, b = 0;
|
||||
var foo = {
|
||||
get c() {
|
||||
return a++, 42;
|
||||
},
|
||||
set c(c) {
|
||||
b++;
|
||||
},
|
||||
d: function() {
|
||||
if (this.c++, this.c) console.log(a, b);
|
||||
}
|
||||
}
|
||||
foo.d();
|
||||
}
|
||||
expect_stdout: "2 1"
|
||||
}
|
||||
|
||||
10
test/input/issue-2310/input.js
Normal file
10
test/input/issue-2310/input.js
Normal file
@@ -0,0 +1,10 @@
|
||||
function foo() {
|
||||
return function() {
|
||||
console.log("PASS");
|
||||
};
|
||||
}
|
||||
|
||||
(function() {
|
||||
var f = foo();
|
||||
f();
|
||||
})();
|
||||
@@ -666,6 +666,25 @@ describe("bin/uglifyjs", function () {
|
||||
return JSON.stringify(map).replace(/"/g, '\\"');
|
||||
}
|
||||
});
|
||||
it("Should include function calls in source map", function(done) {
|
||||
var command = [
|
||||
uglifyjscmd,
|
||||
"test/input/issue-2310/input.js",
|
||||
"-c",
|
||||
"--source-map", "url=inline",
|
||||
].join(" ");
|
||||
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(stdout, [
|
||||
'function foo(){return function(){console.log("PASS")}}foo()();',
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMjMxMC9pbnB1dC5qcyJdLCJuYW1lcyI6WyJmb28iLCJjb25zb2xlIiwibG9nIiwiZiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsTUFDTCxPQUFPLFdBQ0hDLFFBQVFDLElBQUksU0FLUkYsS0FDUkcifQ==",
|
||||
""
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should dump AST as JSON", function(done) {
|
||||
var command = uglifyjscmd + " test/input/global_defs/simple.js -mco ast";
|
||||
exec(command, function (err, stdout) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var assert = require("assert");
|
||||
var uglify = require("../node");
|
||||
|
||||
describe("Export", function() {
|
||||
describe("Export/Import", function() {
|
||||
it("Should parse export directives", function() {
|
||||
var inputs = [
|
||||
['export * from "a.js"', ['*'], "a.js"],
|
||||
@@ -36,4 +36,22 @@ describe("Export", function() {
|
||||
assert.equal(st.module_name.value, filename);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should not parse invalid uses of export", function() {
|
||||
assert.equal(uglify.minify("export").error.message, "Unexpected token: eof (undefined)");
|
||||
assert.equal(uglify.minify("export;").error.message, "Unexpected token: punc (;)");
|
||||
assert.equal(uglify.minify("export();").error.message, "Unexpected token: keyword (export)");
|
||||
assert.equal(uglify.minify("export(1);").error.message, "Unexpected token: keyword (export)");
|
||||
assert.equal(uglify.minify("var export;").error.message, "Name expected");
|
||||
assert.equal(uglify.minify("var export = 1;").error.message, "Name expected");
|
||||
assert.equal(uglify.minify("function f(export){}").error.message, "Invalid function parameter");
|
||||
});
|
||||
|
||||
it("Should not parse invalid uses of import", function() {
|
||||
assert.equal(uglify.minify("import").error.message, "Unexpected token: eof (undefined)");
|
||||
assert.equal(uglify.minify("import;").error.message, "Unexpected token: punc (;)");
|
||||
assert.equal(uglify.minify("var import;").error.message, "Unexpected token: import");
|
||||
assert.equal(uglify.minify("var import = 1;").error.message, "Unexpected token: import");
|
||||
assert.equal(uglify.minify("function f(import){}").error.message, "Unexpected token: name (import)");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,6 +73,13 @@ describe("minify", function() {
|
||||
assert.strictEqual(run_code(compressed), run_code(original));
|
||||
});
|
||||
|
||||
it("should not parse invalid use of reserved words", function() {
|
||||
assert.strictEqual(Uglify.minify("function enum(){}").error, undefined);
|
||||
assert.strictEqual(Uglify.minify("function static(){}").error, undefined);
|
||||
assert.strictEqual(Uglify.minify("function super(){}").error.message, "Unexpected token: name (super)");
|
||||
assert.strictEqual(Uglify.minify("function this(){}").error.message, "Unexpected token: name (this)");
|
||||
});
|
||||
|
||||
describe("keep_quoted_props", function() {
|
||||
it("Should preserve quotes in object literals", function() {
|
||||
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||
|
||||
Reference in New Issue
Block a user