Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1f4a4dd82 | ||
|
|
ca49f6f41a | ||
|
|
8a82822654 | ||
|
|
ebe4e1ad28 | ||
|
|
a37ca558dd | ||
|
|
73a564343b | ||
|
|
4870747306 | ||
|
|
b179a2459f | ||
|
|
231c3d7c84 | ||
|
|
aed758ed5c | ||
|
|
0df028187d | ||
|
|
10fbf8e295 | ||
|
|
cf38b52afa | ||
|
|
e755d01a0b | ||
|
|
4084948d3b | ||
|
|
cea1fb5c58 | ||
|
|
1947a21824 |
@@ -1866,7 +1866,7 @@ merge(Compressor.prototype, {
|
||||
return null;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
return handle_custom_scan_order(node, multi_replacer);
|
||||
}
|
||||
}
|
||||
// Replace variable when found
|
||||
@@ -3054,7 +3054,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
|
||||
function can_merge_flow(ab) {
|
||||
function can_drop_abort(ab) {
|
||||
if (ab instanceof AST_Return) return in_lambda && is_return_void(ab.value);
|
||||
if (!(ab instanceof AST_LoopControl)) return false;
|
||||
var lct = compressor.loopcontrol_target(ab);
|
||||
@@ -3063,16 +3063,35 @@ merge(Compressor.prototype, {
|
||||
return match_target(lct);
|
||||
}
|
||||
|
||||
function can_merge_flow(ab) {
|
||||
if (!can_drop_abort(ab)) return false;
|
||||
for (var j = statements.length; --j > i;) {
|
||||
var stat = statements[j];
|
||||
if (stat instanceof AST_DefClass) {
|
||||
if (stat.name.definition().preinit) return false;
|
||||
} else if (stat instanceof AST_Const || stat instanceof AST_Let) {
|
||||
if (!all(stat.definitions, function(defn) {
|
||||
return !defn.name.match_symbol(function(node) {
|
||||
return node instanceof AST_SymbolDeclaration && node.definition().preinit;
|
||||
});
|
||||
})) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function extract_functions() {
|
||||
var defuns = [];
|
||||
var lexical = false;
|
||||
var tail = statements.splice(i + 1).filter(function(stat) {
|
||||
if (stat instanceof AST_LambdaDefinition) {
|
||||
defuns.push(stat);
|
||||
return false;
|
||||
}
|
||||
if (is_lexical_definition(stat)) lexical = true;
|
||||
return true;
|
||||
});
|
||||
[].push.apply(all(tail, safe_to_trim) ? statements : tail, defuns);
|
||||
[].push.apply(lexical ? tail : statements, defuns);
|
||||
return tail;
|
||||
}
|
||||
|
||||
@@ -6937,7 +6956,9 @@ merge(Compressor.prototype, {
|
||||
&& vars.has(sym.name)) {
|
||||
var def = vars.get(sym.name);
|
||||
if (def.value) break;
|
||||
def.value = expr.right.clone();
|
||||
var value = expr.right;
|
||||
if (value instanceof AST_Sequence) value = value.clone();
|
||||
def.value = value;
|
||||
remove(defs, def);
|
||||
defs.push(def);
|
||||
body.shift();
|
||||
@@ -8427,16 +8448,19 @@ merge(Compressor.prototype, {
|
||||
if (!all(args, function(arg) {
|
||||
return !(arg instanceof AST_Spread);
|
||||
})) return;
|
||||
var argnames = fn.argnames;
|
||||
var is_iife = fn === exp && !fn.name;
|
||||
if (fn.rest) {
|
||||
if (!(is_iife && compressor.option("rests"))) return;
|
||||
var insert = fn.argnames.length;
|
||||
var insert = argnames.length;
|
||||
args = args.slice(0, insert);
|
||||
while (args.length < insert) args.push(make_node(AST_Undefined, call).optimize(compressor));
|
||||
args.push(make_node(AST_Array, call, { elements: call.args.slice(insert) }));
|
||||
call.args = args;
|
||||
fn.argnames = fn.argnames.concat(fn.rest);
|
||||
argnames = argnames.concat(fn.rest);
|
||||
fn.rest = null;
|
||||
} else {
|
||||
args = args.slice();
|
||||
argnames = argnames.slice();
|
||||
}
|
||||
var pos = 0, last = 0;
|
||||
var drop_defaults = is_iife && compressor.option("default_values");
|
||||
@@ -8452,14 +8476,14 @@ merge(Compressor.prototype, {
|
||||
} : return_false;
|
||||
var side_effects = [];
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var argname = fn.argnames[i];
|
||||
var argname = argnames[i];
|
||||
if (drop_defaults && argname instanceof AST_DefaultValue && args[i].is_defined(compressor)) {
|
||||
fn.argnames[i] = argname = argname.name;
|
||||
argnames[i] = argname = argname.name;
|
||||
}
|
||||
if (!argname || "__unused" in argname) {
|
||||
var node = args[i].drop_side_effect_free(compressor);
|
||||
if (drop_fargs(argname)) {
|
||||
if (argname) fn.argnames.splice(i, 1);
|
||||
if (argname) argnames.splice(i, 1);
|
||||
args.splice(i, 1);
|
||||
if (node) side_effects.push(node);
|
||||
i--;
|
||||
@@ -8481,7 +8505,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
} else if (drop_fargs(argname, args[i])) {
|
||||
var node = args[i].drop_side_effect_free(compressor);
|
||||
fn.argnames.splice(i, 1);
|
||||
argnames.splice(i, 1);
|
||||
args.splice(i, 1);
|
||||
if (node) side_effects.push(node);
|
||||
i--;
|
||||
@@ -8493,15 +8517,17 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
last = pos;
|
||||
}
|
||||
for (; i < fn.argnames.length; i++) {
|
||||
if (drop_fargs(fn.argnames[i])) fn.argnames.splice(i--, 1);
|
||||
for (; i < argnames.length; i++) {
|
||||
if (drop_fargs(argnames[i])) argnames.splice(i--, 1);
|
||||
}
|
||||
fn.argnames = argnames;
|
||||
args.length = last;
|
||||
call.args = args;
|
||||
if (!side_effects.length) return;
|
||||
var arg = make_sequence(call, side_effects);
|
||||
args.push(args.length < fn.argnames.length ? make_node(AST_UnaryPrefix, call, {
|
||||
args.push(args.length < argnames.length ? make_node(AST_UnaryPrefix, call, {
|
||||
operator: "void",
|
||||
expression: arg
|
||||
expression: arg,
|
||||
}) : arg);
|
||||
}
|
||||
|
||||
@@ -9386,6 +9412,7 @@ merge(Compressor.prototype, {
|
||||
var seq = lift_sequence_in_expression(self, compressor);
|
||||
if (seq !== self) return seq.optimize(compressor);
|
||||
}
|
||||
if (compressor.option("unused")) drop_unused_call_args(self, compressor);
|
||||
if (compressor.option("unsafe")) {
|
||||
var exp = self.expression;
|
||||
if (is_undeclared_ref(exp)) {
|
||||
@@ -9667,6 +9694,7 @@ merge(Compressor.prototype, {
|
||||
if (node instanceof AST_Sequence) return is_object(node.tail_node());
|
||||
if (node instanceof AST_SymbolRef) return is_object(node.fixed_value());
|
||||
return node instanceof AST_Array
|
||||
|| node instanceof AST_Class
|
||||
|| node instanceof AST_Lambda
|
||||
|| node instanceof AST_New
|
||||
|| node instanceof AST_Object;
|
||||
@@ -11457,15 +11485,18 @@ merge(Compressor.prototype, {
|
||||
if (prop.key != key) continue;
|
||||
if (!all(props, can_hoist_property)) break;
|
||||
if (!safe_to_flatten(prop.value, compressor)) break;
|
||||
props = props.map(function(prop) {
|
||||
return prop.value;
|
||||
});
|
||||
if (prop instanceof AST_ObjectMethod
|
||||
&& prop.value instanceof AST_Function
|
||||
&& !(compressor.parent() instanceof AST_Call)) {
|
||||
if (prop.value.uses_arguments) break;
|
||||
props[i] = make_node(AST_Arrow, prop.value, prop.value);
|
||||
}
|
||||
return make_node(AST_Sub, this, {
|
||||
expression: make_node(AST_Array, expr, {
|
||||
elements: props.map(function(prop) {
|
||||
return prop.value;
|
||||
})
|
||||
}),
|
||||
property: make_node(AST_Number, this, {
|
||||
value: i
|
||||
})
|
||||
expression: make_node(AST_Array, expr, { elements: props }),
|
||||
property: make_node(AST_Number, this, { value: i }),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
221
lib/output.js
221
lib/output.js
@@ -49,8 +49,6 @@ function is_some_comments(comment) {
|
||||
}
|
||||
|
||||
function OutputStream(options) {
|
||||
|
||||
var readonly = !options;
|
||||
options = defaults(options, {
|
||||
annotations : false,
|
||||
ascii_only : false,
|
||||
@@ -103,12 +101,35 @@ function OutputStream(options) {
|
||||
}
|
||||
}
|
||||
|
||||
var indentation = options.indent_start;
|
||||
var current_col = 0;
|
||||
var current_line = 1;
|
||||
var current_pos = 0;
|
||||
var OUTPUT = "";
|
||||
var indentation = options.indent_start;
|
||||
var last;
|
||||
var line_end = 0;
|
||||
var line_fixed = true;
|
||||
var mappings = options.source_map && [];
|
||||
var mapping_name;
|
||||
var mapping_token;
|
||||
var might_need_space;
|
||||
var might_need_semicolon;
|
||||
var need_newline_indented = false;
|
||||
var need_space = false;
|
||||
var newline_insert = -1;
|
||||
var stack;
|
||||
var OUTPUT;
|
||||
|
||||
function reset() {
|
||||
last = "";
|
||||
might_need_space = false;
|
||||
might_need_semicolon = false;
|
||||
stack = [];
|
||||
var str = OUTPUT;
|
||||
OUTPUT = "";
|
||||
return str;
|
||||
}
|
||||
|
||||
reset();
|
||||
var to_utf8 = options.ascii_only ? function(str, identifier) {
|
||||
if (identifier) str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
|
||||
return "\\u{" + (ch.charCodeAt(0) - 0xd7c0 << 10 | ch.charCodeAt(1) - 0xdc00).toString(16) + "}";
|
||||
@@ -141,6 +162,25 @@ function OutputStream(options) {
|
||||
return j == 0 ? str : s + str.slice(j);
|
||||
};
|
||||
|
||||
function quote_single(str) {
|
||||
return "'" + str.replace(/\x27/g, "\\'") + "'";
|
||||
}
|
||||
|
||||
function quote_double(str) {
|
||||
return '"' + str.replace(/\x22/g, '\\"') + '"';
|
||||
}
|
||||
|
||||
var quote_string = [
|
||||
null,
|
||||
quote_single,
|
||||
quote_double,
|
||||
function(str, quote) {
|
||||
return quote == "'" ? quote_single(str) : quote_double(str);
|
||||
},
|
||||
][options.quote_style] || function(str, quote, dq, sq) {
|
||||
return dq > sq ? quote_single(str) : quote_double(str);
|
||||
};
|
||||
|
||||
function make_string(str, quote) {
|
||||
var dq = 0, sq = 0;
|
||||
str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s, i) {
|
||||
@@ -162,54 +202,11 @@ function OutputStream(options) {
|
||||
}
|
||||
return s;
|
||||
});
|
||||
function quote_single() {
|
||||
return "'" + str.replace(/\x27/g, "\\'") + "'";
|
||||
}
|
||||
function quote_double() {
|
||||
return '"' + str.replace(/\x22/g, '\\"') + '"';
|
||||
}
|
||||
str = to_utf8(str);
|
||||
switch (options.quote_style) {
|
||||
case 1:
|
||||
return quote_single();
|
||||
case 2:
|
||||
return quote_double();
|
||||
case 3:
|
||||
return quote == "'" ? quote_single() : quote_double();
|
||||
default:
|
||||
return dq > sq ? quote_single() : quote_double();
|
||||
}
|
||||
}
|
||||
|
||||
function encode_string(str, quote) {
|
||||
var ret = make_string(str, quote);
|
||||
if (options.inline_script) {
|
||||
ret = ret.replace(/<\x2f(script)([>\/\t\n\f\r ])/gi, "<\\/$1$2");
|
||||
ret = ret.replace(/\x3c!--/g, "\\x3c!--");
|
||||
ret = ret.replace(/--\x3e/g, "--\\x3e");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function make_name(name) {
|
||||
name = name.toString();
|
||||
name = to_utf8(name, true);
|
||||
return name;
|
||||
return quote_string(to_utf8(str), quote, dq, sq);
|
||||
}
|
||||
|
||||
/* -----[ beautification/minification ]----- */
|
||||
|
||||
var has_parens = false;
|
||||
var line_end = 0;
|
||||
var line_fixed = true;
|
||||
var might_need_space = false;
|
||||
var might_need_semicolon = false;
|
||||
var need_newline_indented = false;
|
||||
var need_space = false;
|
||||
var newline_insert = -1;
|
||||
var last = "";
|
||||
var mapping_token, mapping_name, mappings = options.source_map && [];
|
||||
|
||||
var adjust_mappings = mappings ? function(line, col) {
|
||||
mappings.forEach(function(mapping) {
|
||||
mapping.line += line;
|
||||
@@ -257,8 +254,14 @@ function OutputStream(options) {
|
||||
|
||||
var requireSemicolonChars = makePredicate("( [ + * / - , .");
|
||||
|
||||
function print(str) {
|
||||
str = String(str);
|
||||
var print = options.beautify
|
||||
|| options.comments
|
||||
|| options.max_line_len
|
||||
|| options.preserve_line
|
||||
|| options.shebang
|
||||
|| !options.semicolons
|
||||
|| options.source_map
|
||||
|| options.width ? function(str) {
|
||||
var ch = str.charAt(0);
|
||||
if (need_newline_indented && ch) {
|
||||
need_newline_indented = false;
|
||||
@@ -328,7 +331,6 @@ function OutputStream(options) {
|
||||
}
|
||||
|
||||
OUTPUT += str;
|
||||
has_parens = str.slice(-1) == "(";
|
||||
current_pos += str.length;
|
||||
var a = str.split(/\r?\n/), n = a.length - 1;
|
||||
current_line += n;
|
||||
@@ -338,7 +340,30 @@ function OutputStream(options) {
|
||||
current_col = a[n].length;
|
||||
}
|
||||
last = str;
|
||||
}
|
||||
} : function(str) {
|
||||
var ch = str.charAt(0);
|
||||
var prev = last.slice(-1);
|
||||
if (might_need_semicolon) {
|
||||
might_need_semicolon = false;
|
||||
if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") {
|
||||
OUTPUT += ";";
|
||||
might_need_space = false;
|
||||
}
|
||||
}
|
||||
if (might_need_space) {
|
||||
if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\")
|
||||
|| (ch == "/" && ch == prev)
|
||||
|| ((ch == "+" || ch == "-") && ch == last)
|
||||
|| str == "--" && last == "!"
|
||||
|| str == "in" && prev == "/"
|
||||
|| last == "--" && ch == ">") {
|
||||
OUTPUT += " ";
|
||||
}
|
||||
if (prev != "<" || str != "!") might_need_space = false;
|
||||
}
|
||||
OUTPUT += str;
|
||||
last = str;
|
||||
};
|
||||
|
||||
var space = options.beautify ? function() {
|
||||
print(" ");
|
||||
@@ -351,14 +376,12 @@ function OutputStream(options) {
|
||||
print(repeat_string(" ", half ? indentation - (options.indent_level >> 1) : indentation));
|
||||
} : noop;
|
||||
|
||||
var with_indent = options.beautify ? function(col, cont) {
|
||||
if (col === true) col = next_indent();
|
||||
var with_indent = options.beautify ? function(cont) {
|
||||
var save_indentation = indentation;
|
||||
indentation = col;
|
||||
var ret = cont();
|
||||
indentation += options.indent_level;
|
||||
cont();
|
||||
indentation = save_indentation;
|
||||
return ret;
|
||||
} : function(col, cont) { return cont() };
|
||||
} : function(cont) { cont() };
|
||||
|
||||
var may_add_newline = options.max_line_len || options.preserve_line ? function() {
|
||||
fix_line();
|
||||
@@ -387,41 +410,28 @@ function OutputStream(options) {
|
||||
print(";");
|
||||
}
|
||||
|
||||
function next_indent() {
|
||||
return indentation + options.indent_level;
|
||||
}
|
||||
|
||||
function with_block(cont) {
|
||||
var ret;
|
||||
print("{");
|
||||
newline();
|
||||
with_indent(next_indent(), function() {
|
||||
ret = cont();
|
||||
});
|
||||
with_indent(cont);
|
||||
indent();
|
||||
print("}");
|
||||
return ret;
|
||||
}
|
||||
|
||||
function with_parens(cont) {
|
||||
print("(");
|
||||
may_add_newline();
|
||||
//XXX: still nice to have that for argument lists
|
||||
//var ret = with_indent(current_col, cont);
|
||||
var ret = cont();
|
||||
cont();
|
||||
may_add_newline();
|
||||
print(")");
|
||||
return ret;
|
||||
}
|
||||
|
||||
function with_square(cont) {
|
||||
print("[");
|
||||
may_add_newline();
|
||||
//var ret = with_indent(current_col, cont);
|
||||
var ret = cont();
|
||||
cont();
|
||||
may_add_newline();
|
||||
print("]");
|
||||
return ret;
|
||||
}
|
||||
|
||||
function comma() {
|
||||
@@ -553,15 +563,14 @@ function OutputStream(options) {
|
||||
if (OUTPUT.length > insert) newline_insert = insert;
|
||||
}
|
||||
|
||||
var stack = [];
|
||||
return {
|
||||
get : get,
|
||||
toString : get,
|
||||
reset : reset,
|
||||
indent : indent,
|
||||
should_break : readonly ? noop : function() {
|
||||
return options.width && current_col - indentation >= options.width;
|
||||
},
|
||||
has_parens : function() { return has_parens },
|
||||
should_break : options.width ? function() {
|
||||
return current_col - indentation >= options.width;
|
||||
} : return_false,
|
||||
has_parens : function() { return last.slice(-1) == "(" },
|
||||
newline : newline,
|
||||
print : print,
|
||||
space : space,
|
||||
@@ -571,20 +580,21 @@ function OutputStream(options) {
|
||||
semicolon : semicolon,
|
||||
force_semicolon : force_semicolon,
|
||||
to_utf8 : to_utf8,
|
||||
print_name : function(name) { print(make_name(name)) },
|
||||
print_string : function(str, quote) { print(encode_string(str, quote)) },
|
||||
next_indent : next_indent,
|
||||
print_name : function(name) { print(to_utf8(name.toString(), true)) },
|
||||
print_string : options.inline_script ? function(str, quote) {
|
||||
str = make_string(str, quote).replace(/<\x2f(script)([>\/\t\n\f\r ])/gi, "<\\/$1$2");
|
||||
print(str.replace(/\x3c!--/g, "\\x3c!--").replace(/--\x3e/g, "--\\x3e"));
|
||||
} : function(str, quote) {
|
||||
print(make_string(str, quote));
|
||||
},
|
||||
with_indent : with_indent,
|
||||
with_block : with_block,
|
||||
with_parens : with_parens,
|
||||
with_square : with_square,
|
||||
add_mapping : add_mapping,
|
||||
option : function(opt) { return options[opt] },
|
||||
prepend_comments: readonly ? noop : prepend_comments,
|
||||
append_comments : readonly || comment_filter === return_false ? noop : append_comments,
|
||||
line : function() { return current_line },
|
||||
col : function() { return current_col },
|
||||
pos : function() { return current_pos },
|
||||
prepend_comments: options.comments || options.shebang ? prepend_comments : noop,
|
||||
append_comments : options.comments ? append_comments : noop,
|
||||
push_node : function(node) { stack.push(node) },
|
||||
pop_node : options.preserve_line ? function() {
|
||||
var node = stack.pop();
|
||||
@@ -629,10 +639,19 @@ function OutputStream(options) {
|
||||
stream.append_comments(self);
|
||||
}
|
||||
});
|
||||
var readonly = OutputStream({
|
||||
inline_script: false,
|
||||
shebang: false,
|
||||
width: false,
|
||||
});
|
||||
AST_Node.DEFMETHOD("print_to_string", function(options) {
|
||||
var s = OutputStream(options);
|
||||
this.print(s);
|
||||
return s.get();
|
||||
if (options) {
|
||||
var stream = OutputStream(options);
|
||||
this.print(stream);
|
||||
return stream.get();
|
||||
}
|
||||
this.print(readonly);
|
||||
return readonly.reset();
|
||||
});
|
||||
|
||||
/* -----[ PARENTHESES ]----- */
|
||||
@@ -915,7 +934,7 @@ function OutputStream(options) {
|
||||
});
|
||||
function print_braced_empty(self, output) {
|
||||
output.print("{");
|
||||
output.with_indent(output.next_indent(), function() {
|
||||
output.with_indent(function() {
|
||||
output.append_comments(self, true);
|
||||
});
|
||||
output.print("}");
|
||||
@@ -1481,11 +1500,7 @@ function OutputStream(options) {
|
||||
output.print_string(prop);
|
||||
output.print("]");
|
||||
} else {
|
||||
if (expr instanceof AST_Number && expr.value >= 0) {
|
||||
if (!/[xa-f.)]/i.test(output.last())) {
|
||||
output.print(".");
|
||||
}
|
||||
}
|
||||
if (expr instanceof AST_Number && !/[ex.)]/i.test(output.last())) output.print(".");
|
||||
output.print(".");
|
||||
// the name after dot would be mapped about here.
|
||||
output.add_mapping(self.end);
|
||||
@@ -1735,7 +1750,7 @@ function OutputStream(options) {
|
||||
output.print("`");
|
||||
});
|
||||
DEFPRINT(AST_Constant, function(output) {
|
||||
output.print(this.value);
|
||||
output.print("" + this.value);
|
||||
});
|
||||
DEFPRINT(AST_String, function(output) {
|
||||
output.print_string(this.value, this.quote);
|
||||
@@ -1791,7 +1806,7 @@ function OutputStream(options) {
|
||||
function force_statement(stat, output) {
|
||||
if (output.option("braces") && !(stat instanceof AST_Const || stat instanceof AST_Let)) {
|
||||
make_block(stat, output);
|
||||
} else if (!stat || stat instanceof AST_EmptyStatement) {
|
||||
} else if (stat instanceof AST_EmptyStatement) {
|
||||
output.force_semicolon();
|
||||
} else {
|
||||
stat.print(output);
|
||||
@@ -1842,11 +1857,11 @@ function OutputStream(options) {
|
||||
}
|
||||
|
||||
function make_block(stmt, output) {
|
||||
if (!stmt || stmt instanceof AST_EmptyStatement)
|
||||
output.print("{}");
|
||||
else if (stmt instanceof AST_BlockStatement)
|
||||
if (stmt instanceof AST_EmptyStatement) {
|
||||
print_braced_empty(stmt, output);
|
||||
} else if (stmt instanceof AST_BlockStatement) {
|
||||
stmt.print(output);
|
||||
else output.with_block(function() {
|
||||
} else output.with_block(function() {
|
||||
output.indent();
|
||||
stmt.print(output);
|
||||
output.newline();
|
||||
|
||||
30
lib/parse.js
30
lib/parse.js
@@ -351,7 +351,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
|
||||
function read_while(pred) {
|
||||
var ret = "", ch;
|
||||
while ((ch = peek()) && pred(ch)) ret += next();
|
||||
while ((ch = peek()) && pred(ch, ret)) ret += next();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -359,24 +359,27 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
|
||||
}
|
||||
|
||||
function is_octal(num) {
|
||||
return /^0[0-7_]+$/.test(num);
|
||||
}
|
||||
|
||||
function read_num(prefix) {
|
||||
var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
|
||||
var num = read_while(function(ch) {
|
||||
var code = ch.charCodeAt(0);
|
||||
switch (code) {
|
||||
case 120: case 88: // xX
|
||||
var num = read_while(function(ch, str) {
|
||||
switch (ch) {
|
||||
case "x": case "X":
|
||||
return has_x ? false : (has_x = true);
|
||||
case 101: case 69: // eE
|
||||
case "e": case "E":
|
||||
return has_x ? true : has_e ? false : (has_e = after_e = true);
|
||||
case 43: case 45: // +-
|
||||
case "+": case "-":
|
||||
return after_e;
|
||||
case (after_e = false, 46): // .
|
||||
return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
|
||||
case (after_e = false, "."):
|
||||
return has_dot || has_e || has_x || is_octal(str) ? false : (has_dot = true);
|
||||
}
|
||||
return is_digit(code) || /[_0-9a-fo]/i.test(ch);
|
||||
return /[_0-9a-dfo]/i.test(ch);
|
||||
});
|
||||
if (prefix) num = prefix + num;
|
||||
if (/^0[0-7_]+$/.test(num)) {
|
||||
if (is_octal(num)) {
|
||||
if (next_token.has_directive("use strict")) parse_error("Legacy octal literals are not allowed in strict mode");
|
||||
} else {
|
||||
num = num.replace(has_x ? /([1-9a-f]|.0)_(?=[0-9a-f])/gi : /([1-9]|.0)_(?=[0-9])/gi, "$1");
|
||||
@@ -854,7 +857,8 @@ function parse($TEXT, options) {
|
||||
next();
|
||||
return export_();
|
||||
case "import":
|
||||
if (!is_token(peek(), "punc", "(")) {
|
||||
var token = peek();
|
||||
if (!(token.type == "punc" && /^[(.]$/.test(token.value))) {
|
||||
next();
|
||||
return import_();
|
||||
}
|
||||
@@ -1185,7 +1189,7 @@ function parse($TEXT, options) {
|
||||
var await = is("name", "await") && next();
|
||||
expect("(");
|
||||
var init = null;
|
||||
if (!is("punc", ";")) {
|
||||
if (await || !is("punc", ";")) {
|
||||
init = is("keyword", "const")
|
||||
? (next(), const_(true))
|
||||
: is("keyword", "let")
|
||||
|
||||
@@ -81,7 +81,9 @@ var builtins = function() {
|
||||
|
||||
function reserve_quoted_keys(ast, reserved) {
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_ObjectProperty) {
|
||||
if (node instanceof AST_ClassProperty) {
|
||||
if (node.start && node.start.quote) add(node.key);
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
if (node.start && node.start.quote) add(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
@@ -163,6 +165,8 @@ function mangle_properties(ast, options) {
|
||||
addStrings(node.args[0], add);
|
||||
break;
|
||||
}
|
||||
} else if (node instanceof AST_ClassProperty) {
|
||||
if (typeof node.key == "string") add(node.key);
|
||||
} else if (node instanceof AST_Dot) {
|
||||
add(node.property);
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
@@ -193,6 +197,8 @@ function mangle_properties(ast, options) {
|
||||
mangleStrings(node.args[0]);
|
||||
break;
|
||||
}
|
||||
} else if (node instanceof AST_ClassProperty) {
|
||||
if (typeof node.key == "string") node.key = mangle(node.key);
|
||||
} else if (node instanceof AST_Dot) {
|
||||
node.property = mangle(node.property);
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
@@ -222,9 +228,7 @@ function mangle_properties(ast, options) {
|
||||
}
|
||||
|
||||
function mangle(name) {
|
||||
if (!should_mangle(name)) {
|
||||
return name;
|
||||
}
|
||||
if (!should_mangle(name)) return name;
|
||||
var mangled = cache.get(name);
|
||||
if (!mangled) {
|
||||
if (debug) {
|
||||
@@ -236,6 +240,7 @@ function mangle_properties(ast, options) {
|
||||
if (!mangled) do {
|
||||
mangled = base54(++cname);
|
||||
} while (!can_mangle(mangled));
|
||||
if (/^#/.test(name)) mangled = "#" + mangled;
|
||||
cache.set(name, mangled);
|
||||
}
|
||||
return mangled;
|
||||
|
||||
12
lib/scope.js
12
lib/scope.js
@@ -273,16 +273,18 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolDeclaration) {
|
||||
var def = node.definition();
|
||||
def.preinit = def.references.length;
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
// ensure mangling works if `catch` reuses a scope variable
|
||||
var def = node.definition().redefined();
|
||||
if (def) for (var s = node.scope; s; s = s.parent_scope) {
|
||||
push_uniq(s.enclosed, def);
|
||||
if (s === def.scope) break;
|
||||
var redef = def.redefined();
|
||||
if (redef) for (var s = node.scope; s; s = s.parent_scope) {
|
||||
push_uniq(s.enclosed, redef);
|
||||
if (s === redef.scope) break;
|
||||
}
|
||||
} else if (node instanceof AST_SymbolConst) {
|
||||
// ensure compression works if `const` reuses a scope variable
|
||||
var redef = node.definition().redefined();
|
||||
var redef = def.redefined();
|
||||
if (redef) redef.const_redefs = true;
|
||||
}
|
||||
if (node.name != "arguments") return true;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.13.3",
|
||||
"version": "3.13.4",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -583,6 +583,31 @@ single_use_6: {
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
single_use_7: {
|
||||
options = {
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
class A {
|
||||
static foo() {}
|
||||
}
|
||||
var a = "foo" in A;
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
console.log("foo" in class {
|
||||
static foo() {}
|
||||
});
|
||||
}
|
||||
expect_stdout: "true"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
collapse_non_strict: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
@@ -654,6 +679,32 @@ collapse_rhs_static: {
|
||||
node_version: ">=12"
|
||||
}
|
||||
|
||||
self_comparison: {
|
||||
options = {
|
||||
booleans: true,
|
||||
comparisons: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
class A {}
|
||||
console.log(A == A, A != A);
|
||||
console.log(A === A, A !== A);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
console.log(!0, !1);
|
||||
console.log(!0, !1);
|
||||
}
|
||||
expect_stdout: [
|
||||
"true false",
|
||||
"true false",
|
||||
]
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
property_side_effects: {
|
||||
options = {
|
||||
inline: true,
|
||||
@@ -1344,3 +1395,149 @@ issue_4821_2: {
|
||||
expect_stdout: "function"
|
||||
node_version: ">=12"
|
||||
}
|
||||
|
||||
issue_4829_1: {
|
||||
options = {
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
try {
|
||||
class A extends { f(){} }.f {}
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
try {
|
||||
class A extends [ () => {} ][0] {}
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4829_2: {
|
||||
options = {
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
try {
|
||||
class A extends {
|
||||
f() {
|
||||
return arguments;
|
||||
},
|
||||
}.f {}
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
try {
|
||||
class A extends {
|
||||
f() {
|
||||
return arguments;
|
||||
},
|
||||
}.f {}
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
mangle_properties: {
|
||||
mangle = {
|
||||
properties: {
|
||||
keep_quoted: true,
|
||||
},
|
||||
}
|
||||
input: {
|
||||
class A {
|
||||
static #P = "PASS";
|
||||
static get Q() {
|
||||
return this.#P;
|
||||
}
|
||||
#p(n) {
|
||||
return (this["q"] = n) * this.r;
|
||||
}
|
||||
set q(v) {
|
||||
this.r = v + 1;
|
||||
}
|
||||
r = this.#p(6);
|
||||
}
|
||||
console.log(A.Q, new A().r);
|
||||
}
|
||||
expect: {
|
||||
class A {
|
||||
static #t = "PASS";
|
||||
static get s() {
|
||||
return this.#t;
|
||||
}
|
||||
#i(t) {
|
||||
return (this["q"] = t) * this.e;
|
||||
}
|
||||
set q(t) {
|
||||
this.e = t + 1;
|
||||
}
|
||||
e = this.#i(6);
|
||||
}
|
||||
console.log(A.s, new A().e);
|
||||
}
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=14.6"
|
||||
}
|
||||
|
||||
issue_4848: {
|
||||
options = {
|
||||
if_return: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
a(function() {
|
||||
new A();
|
||||
});
|
||||
if (!console)
|
||||
return;
|
||||
class A {
|
||||
constructor() {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
}
|
||||
var g;
|
||||
f(function(h) {
|
||||
g = h;
|
||||
});
|
||||
g();
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
a(function() {
|
||||
new A();
|
||||
});
|
||||
if (!console)
|
||||
return;
|
||||
class A {
|
||||
constructor() {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
}
|
||||
var g;
|
||||
f(function(h) {
|
||||
g = h;
|
||||
});
|
||||
g();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
@@ -8897,3 +8897,38 @@ issue_4806: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4852: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
(function(b) {
|
||||
switch (b = a) {
|
||||
case 42:
|
||||
try {
|
||||
console;
|
||||
} catch (b) {
|
||||
b.p;
|
||||
}
|
||||
case console.log(b):
|
||||
}
|
||||
})("FAIL");
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
(function(b) {
|
||||
switch (a) {
|
||||
case 42:
|
||||
try {
|
||||
console;
|
||||
} catch (b) {
|
||||
b.p;
|
||||
}
|
||||
case console.log(a):
|
||||
}
|
||||
})("FAIL");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -1498,3 +1498,40 @@ issue_4691: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4848: {
|
||||
options = {
|
||||
if_return: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
a(function() {
|
||||
console.log(b);
|
||||
});
|
||||
if (!console)
|
||||
return;
|
||||
const b = "PASS";
|
||||
}
|
||||
var g;
|
||||
f(function(h) {
|
||||
g = h;
|
||||
});
|
||||
g();
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
a(function() {
|
||||
console.log(b);
|
||||
});
|
||||
if (!console)
|
||||
return;
|
||||
const b = "PASS";
|
||||
}
|
||||
var g;
|
||||
f(function(h) {
|
||||
g = h;
|
||||
});
|
||||
g();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -3357,3 +3357,34 @@ issue_4806_3: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4834: {
|
||||
options = {
|
||||
inline: true,
|
||||
keep_fargs: false,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
new function(a, b) {
|
||||
b;
|
||||
b.p;
|
||||
}(42);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
void b.p;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
var b;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@ issue_4664: {
|
||||
expect: {
|
||||
(function f() {
|
||||
new function(a) {
|
||||
console.log(typeof f, 2 ** 30, typeof this);
|
||||
}(0, A = 0);
|
||||
console.log(typeof f, 1073741824, typeof this);
|
||||
}(A = 0);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "function 1073741824 object"
|
||||
|
||||
@@ -140,7 +140,6 @@ issue_4487: {
|
||||
functions: true,
|
||||
hoist_vars: true,
|
||||
keep_fnames: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
@@ -240,3 +239,29 @@ issue_4736: {
|
||||
}
|
||||
expect_stdout: "1073741824"
|
||||
}
|
||||
|
||||
issue_4839: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
hoist_vars: true,
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = function(a, b) {
|
||||
return b && b;
|
||||
}("foo");
|
||||
for (var k in o)
|
||||
throw "FAIL";
|
||||
console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
var k, o = void 0;
|
||||
for (k in o)
|
||||
throw "FAIL";
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -54,13 +54,22 @@ dynamic_nought: {
|
||||
expect_exact: "import(foo);"
|
||||
}
|
||||
|
||||
import_meta: {
|
||||
import_meta_1: {
|
||||
input: {
|
||||
console.log(import.meta, import.meta.url);
|
||||
}
|
||||
expect_exact: "console.log(import.meta,import.meta.url);"
|
||||
}
|
||||
|
||||
import_meta_2: {
|
||||
input: {
|
||||
import.meta.url.split("/").forEach(function(part, index) {
|
||||
console.log(index, part);
|
||||
});
|
||||
}
|
||||
expect_exact: 'import.meta.url.split("/").forEach(function(part,index){console.log(index,part)});'
|
||||
}
|
||||
|
||||
same_quotes: {
|
||||
beautify = {
|
||||
beautify: true,
|
||||
|
||||
@@ -1506,3 +1506,43 @@ issue_4691: {
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4848: {
|
||||
options = {
|
||||
if_return: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
a(function() {
|
||||
console.log(b);
|
||||
});
|
||||
if (!console)
|
||||
return;
|
||||
let b = "PASS";
|
||||
}
|
||||
var g;
|
||||
f(function(h) {
|
||||
g = h;
|
||||
});
|
||||
g();
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
a(function() {
|
||||
console.log(b);
|
||||
});
|
||||
if (!console)
|
||||
return;
|
||||
let b = "PASS";
|
||||
}
|
||||
var g;
|
||||
f(function(h) {
|
||||
g = h;
|
||||
});
|
||||
g();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
@@ -104,6 +104,40 @@ parentheses_for_prototype_functions_galio: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
octal: {
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
console.log(052);
|
||||
console.log(-052);
|
||||
|
||||
console.log(018);
|
||||
console.log(-018);
|
||||
|
||||
console.log(052.toFixed(0));
|
||||
console.log(-052.toFixed(0));
|
||||
|
||||
console.log(018..toFixed(0));
|
||||
console.log(-018..toFixed(0));
|
||||
})();
|
||||
}
|
||||
expect_exact: [
|
||||
"(function() {",
|
||||
" console.log(42);",
|
||||
" console.log(-42);",
|
||||
" console.log(18);",
|
||||
" console.log(-18);",
|
||||
" console.log(42..toFixed(0));",
|
||||
" console.log(-42..toFixed(0));",
|
||||
" console.log(18..toFixed(0));",
|
||||
" console.log(-18..toFixed(0));",
|
||||
"})();",
|
||||
]
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
comparisons: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
|
||||
@@ -1400,3 +1400,49 @@ object_super: {
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4831_1: {
|
||||
options = {
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
f() {
|
||||
return arguments;
|
||||
},
|
||||
}.f("PASS")[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log([
|
||||
function() {
|
||||
return arguments;
|
||||
},
|
||||
][0]("PASS")[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4831_2: {
|
||||
options = {
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
var f = {
|
||||
f() {
|
||||
return arguments;
|
||||
},
|
||||
}.f;
|
||||
console.log(f("PASS")[0]);
|
||||
}
|
||||
expect: {
|
||||
var f = {
|
||||
f() {
|
||||
return arguments;
|
||||
},
|
||||
}.f;
|
||||
console.log(f("PASS")[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
@@ -1045,3 +1045,26 @@ issue_4614: {
|
||||
expect_stdout: true
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4849: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
while (function() {
|
||||
while (!console);
|
||||
}(new function(a) {
|
||||
console.log(typeof { ...a });
|
||||
}(function() {})));
|
||||
}
|
||||
expect: {
|
||||
while (function() {
|
||||
while (!console);
|
||||
}(function(a) {
|
||||
console.log(typeof { ...function() {} });
|
||||
}()));
|
||||
}
|
||||
expect_stdout: "object"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
1
test/input/invalid/for-await.js
Normal file
1
test/input/invalid/for-await.js
Normal file
@@ -0,0 +1 @@
|
||||
for await (; console.log(42););
|
||||
@@ -679,6 +679,20 @@ describe("bin/uglifyjs", function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (for-await)", function(done) {
|
||||
var command = uglifyjscmd + " test/input/invalid/for-await.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||
"Parse error at test/input/invalid/for-await.js:1,11",
|
||||
"for await (; console.log(42););",
|
||||
" ^",
|
||||
"ERROR: Unexpected token: punc «;»",
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (switch defaults)", function(done) {
|
||||
var command = uglifyjscmd + " test/input/invalid/switch.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
|
||||
@@ -183,6 +183,24 @@ describe("test/reduce.js", function() {
|
||||
"// }",
|
||||
].join("\n"));
|
||||
});
|
||||
it("Should reduce `for (const ... in ...)` without invalid intermediate AST", function() {
|
||||
if (semver.satisfies(process.version, "<4")) return;
|
||||
var code = [
|
||||
"var a = 0;",
|
||||
"",
|
||||
"for (const b in [ 1, 2, 3 ]) {",
|
||||
" a = +a + 1 - .2;",
|
||||
" console.log(a);",
|
||||
"}",
|
||||
].join("\n");
|
||||
var result = reduce_test(code, {
|
||||
compress: {
|
||||
unsafe_math: true,
|
||||
},
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.deepEqual(result.warnings, []);
|
||||
});
|
||||
it("Should reduce infinite loops with reasonable performance", function() {
|
||||
if (semver.satisfies(process.version, "<=0.10")) return;
|
||||
this.timeout(120000);
|
||||
@@ -379,4 +397,21 @@ describe("test/reduce.js", function() {
|
||||
"// }",
|
||||
].join("\n"));
|
||||
});
|
||||
it("Should reduce object with method syntax without invalid intermediate AST", function() {
|
||||
if (semver.satisfies(process.version, "<4")) return;
|
||||
var code = [
|
||||
"console.log({",
|
||||
" f() {",
|
||||
" return 1 - .8;",
|
||||
" },",
|
||||
"}.f());",
|
||||
].join("\n");
|
||||
var result = reduce_test(code, {
|
||||
compress: {
|
||||
unsafe_math: true,
|
||||
},
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.deepEqual(result.warnings, []);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -316,10 +316,11 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
var expr;
|
||||
switch ((node.start._permute * steps | 0) % 3) {
|
||||
case 0:
|
||||
if (!(node.init instanceof U.AST_Definitions
|
||||
&& node.init.definitions[0].name instanceof U.AST_Destructured)) {
|
||||
expr = node.init;
|
||||
if (node.init instanceof U.AST_Definitions) {
|
||||
if (node.init instanceof U.AST_Const) break;
|
||||
if (node.init.definitions[0].name instanceof U.AST_Destructured) break;
|
||||
}
|
||||
expr = node.init;
|
||||
break;
|
||||
case 1:
|
||||
expr = node.object;
|
||||
@@ -484,23 +485,27 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
CHANGED = true;
|
||||
return newNode;
|
||||
}, function(node, in_list) {
|
||||
if (node instanceof U.AST_Sequence) {
|
||||
if (node instanceof U.AST_Definitions) {
|
||||
// remove empty var statement
|
||||
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
|
||||
start: {},
|
||||
});
|
||||
} else if (node instanceof U.AST_ObjectMethod) {
|
||||
if (!/Function$/.test(node.value.TYPE)) return new U.AST_ObjectKeyVal({
|
||||
key: node.key,
|
||||
value: node.value,
|
||||
start: {},
|
||||
});
|
||||
} else if (node instanceof U.AST_Sequence) {
|
||||
// expand single-element sequence
|
||||
if (node.expressions.length == 1) return node.expressions[0];
|
||||
}
|
||||
else if (node instanceof U.AST_Try) {
|
||||
} else if (node instanceof U.AST_Try) {
|
||||
// expand orphaned try block
|
||||
if (!node.bcatch && !node.bfinally) return new U.AST_BlockStatement({
|
||||
body: node.body,
|
||||
start: {},
|
||||
});
|
||||
}
|
||||
else if (node instanceof U.AST_Definitions) {
|
||||
// remove empty var statement
|
||||
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
|
||||
start: {},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var diff_error_message;
|
||||
|
||||
@@ -55,6 +55,8 @@ exports.patch_module_statements = function(code) {
|
||||
if (!header) return "";
|
||||
if (header.length == 1) return "0, " + header;
|
||||
return header.slice(0, -1) + " _" + ++count + header.slice(-1);
|
||||
}).replace(/\bimport\.meta\b/g, function() {
|
||||
return '({ url: "https://example.com/path/index.html" })';
|
||||
}).replace(/\bimport\b(?:\s*([^('"]+)\bfrom\b)?\s*(['"]).*?\2(?:$|\n|;)/g, function(match, symbols) {
|
||||
if (symbols) {
|
||||
if (!/^[{*]/.test(symbols)) symbols = "default:" + symbols;
|
||||
@@ -220,7 +222,7 @@ function setup(global, builtins, setup_log, setup_tty) {
|
||||
if (arg === global) return "[object global]";
|
||||
if (/Error$/.test(arg.name)) return arg.toString();
|
||||
if (typeof arg.then == "function") return "[object Promise]";
|
||||
arg.constructor.toString();
|
||||
if (arg.constructor) arg.constructor.toString();
|
||||
var index = cache.original.indexOf(arg);
|
||||
if (index >= 0) return cache.replaced[index];
|
||||
if (--cache.level < 0) return "[object Object]";
|
||||
|
||||
@@ -204,12 +204,20 @@ var VALUES = [
|
||||
'"function"',
|
||||
"this",
|
||||
];
|
||||
VALUES = VALUES.concat(VALUES);
|
||||
VALUES = VALUES.concat(VALUES);
|
||||
VALUES = VALUES.concat(VALUES);
|
||||
if (SUPPORT.bigint) VALUES = VALUES.concat([
|
||||
"(!0o644n)",
|
||||
"([3n][0] > 2)",
|
||||
"(-42n).toString()",
|
||||
"Number(0XDEADn << 16n | 0xbeefn)",
|
||||
]);
|
||||
VALUES = VALUES.concat(VALUES);
|
||||
VALUES = VALUES.concat(VALUES);
|
||||
VALUES = VALUES.concat(VALUES);
|
||||
VALUES = VALUES.concat(VALUES);
|
||||
VALUES.push("import.meta");
|
||||
|
||||
var BINARY_OPS = [
|
||||
" + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors)
|
||||
|
||||
Reference in New Issue
Block a user