Compare commits

..

14 Commits

Author SHA1 Message Date
Alex Lam S.L
bce7ee5f6a v3.4.0 2018-06-02 05:57:10 +00:00
Jiavan
b39043f3ab re-introduce enclose (#3163)
fixes #2443
2018-06-01 16:47:11 +08:00
Alex Lam S.L
caf96acb08 handle asynchronous test failures (#3164) 2018-05-31 20:21:39 +08:00
Alex Lam S.L
c76749084b update JetStream URL (#3165) 2018-05-31 16:23:49 +08:00
Alex Lam S.L
5843494ee2 v3.3.28 2018-05-29 12:25:42 +00:00
Alex Lam S.L
efa21ae3e6 fix corner case in reduce_vars (#3151) 2018-05-26 05:45:44 +08:00
Alex Lam S.L
24d9633a35 fix corner cases with eval() (#3147)
fixes #3146
2018-05-24 14:29:30 +08:00
Alex Lam S.L
7963b96681 augment tests for inline source maps (#3145) 2018-05-24 02:37:51 +08:00
Alex Lam S.L
8c62d854ce augment tests for RegExp (#3144) 2018-05-23 17:24:13 +08:00
Alex Lam S.L
69931574e1 v3.3.27 2018-05-22 17:09:12 +00:00
Alex Lam S.L
b5af8a1914 fix corner case in reduce_vars (#3141)
fixes #3140
2018-05-21 15:53:51 +08:00
Alex Lam S.L
c14d09ba84 v3.3.26 2018-05-20 17:32:32 +00:00
Alex Lam S.L
4fc39d8dad fix corner case in collapse_vars (#3139) 2018-05-19 05:45:14 +08:00
exvisory
0b7c70f726 Update README.md to clarify --source-map filename option (#3137)
Clarify that the --source-map filename option does NOT change the source map output filename but does set the 'file' attribute within the output source map. This was already documented in the API section of the README so I just copied that to the CLI options section, and a fragment to the CLI summary.
2018-05-18 15:50:36 +08:00
19 changed files with 615 additions and 53 deletions

View File

@@ -104,6 +104,8 @@ a double dash to prevent input files being used as option arguments:
sequences. sequences.
--config-file <file> Read `minify()` options from JSON file. --config-file <file> Read `minify()` options from JSON file.
-d, --define <expr>[=value] Global definitions. -d, --define <expr>[=value] Global definitions.
-e, --enclose [arg[:value]] Embed everything in a big function, with configurable
argument(s) & value(s).
--ie8 Support non-standard Internet Explorer 8. --ie8 Support non-standard Internet Explorer 8.
Equivalent to setting `ie8: true` in `minify()` Equivalent to setting `ie8: true` in `minify()`
for `compress`, `mangle` and `output` options. for `compress`, `mangle` and `output` options.
@@ -118,7 +120,8 @@ a double dash to prevent input files being used as option arguments:
JS that was generated from some other original JS that was generated from some other original
code. Specify "inline" if the source map is code. Specify "inline" if the source map is
included within the sources. included within the sources.
`filename` Name and/or location of the output source. `filename` Filename and/or location of the output source
(sets `file` attribute in source map).
`includeSources` Pass this flag if you want to include `includeSources` Pass this flag if you want to include
the content of source files in the the content of source files in the
source map as sourcesContent property. source map as sourcesContent property.
@@ -149,7 +152,9 @@ debugging your compressed JavaScript. To get a source map, pass
Additional options: Additional options:
- `--source-map "filename='<NAME>'"` to specify the name of the source map. - `--source-map "filename='<NAME>'"` to specify the name of the source map. The value of
`filename` is only used to set `file` attribute (see [the spec][sm-spec])
in source map file.
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found. - `--source-map "root='<URL>'"` to pass the URL where the original files can be found.

View File

@@ -40,6 +40,7 @@ program.option("-o, --output <file>", "Output file (default STDOUT).");
program.option("--comments [filter]", "Preserve copyright comments in the output."); program.option("--comments [filter]", "Preserve copyright comments in the output.");
program.option("--config-file <file>", "Read minify() options from JSON file."); program.option("--config-file <file>", "Read minify() options from JSON file.");
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define")); program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
program.option("-e, --enclose [arg[,...][:value[,...]]]", "Embed everything in a big function, with configurable argument(s) & value(s).");
program.option("--ie8", "Support non-standard Internet Explorer 8."); program.option("--ie8", "Support non-standard Internet Explorer 8.");
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name."); program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
program.option("--name-cache <file>", "File to hold mangled name mappings."); program.option("--name-cache <file>", "File to hold mangled name mappings.");
@@ -47,7 +48,7 @@ program.option("--rename", "Force symbol expansion.");
program.option("--no-rename", "Disable symbol expansion."); program.option("--no-rename", "Disable symbol expansion.");
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)"); program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js()); program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js());
program.option("--timings", "Display operations run time on STDERR.") program.option("--timings", "Display operations run time on STDERR.");
program.option("--toplevel", "Compress and/or mangle variables in toplevel scope."); program.option("--toplevel", "Compress and/or mangle variables in toplevel scope.");
program.option("--verbose", "Print diagnostic messages."); program.option("--verbose", "Print diagnostic messages.");
program.option("--warn", "Print warning messages."); program.option("--warn", "Print warning messages.");
@@ -61,6 +62,7 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
} }
[ [
"compress", "compress",
"enclose",
"ie8", "ie8",
"mangle", "mangle",
"sourceMap", "sourceMap",

View File

@@ -314,6 +314,9 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
if (this.functions) node.functions = this.functions.clone(); if (this.functions) node.functions = this.functions.clone();
if (this.enclosed) node.enclosed = this.enclosed.slice(); if (this.enclosed) node.enclosed = this.enclosed.slice();
return node; return node;
},
pinned: function() {
return this.uses_eval || this.uses_with;
} }
}, AST_Block); }, AST_Block);
@@ -332,6 +335,23 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
} }
})); }));
return wrapped_tl; return wrapped_tl;
},
wrap_enclose: function(args_values) {
if (typeof args_values != "string") args_values = "";
var index = args_values.indexOf(":");
if (index < 0) index = args_values.length;
var body = this.body;
return parse([
"(function(",
args_values.slice(0, index),
'){"$ORIG"})(',
args_values.slice(index + 1),
")"
].join("")).transform(new TreeTransformer(function(node) {
if (node instanceof AST_Directive && node.value == "$ORIG") {
return MAP.splice(body);
}
}));
} }
}, AST_Scope); }, AST_Scope);

View File

@@ -348,14 +348,14 @@ merge(Compressor.prototype, {
def.chained = false; def.chained = false;
def.direct_access = false; def.direct_access = false;
def.escaped = false; def.escaped = false;
if (def.scope.uses_eval || def.scope.uses_with) { if (def.scope.pinned()) {
def.fixed = false; def.fixed = false;
} else if (!compressor.exposed(def)) { } else if (!compressor.exposed(def)) {
def.fixed = def.init; def.fixed = def.init;
} else { } else {
def.fixed = false; def.fixed = false;
} }
if (def.init instanceof AST_Defun && !all(def.references, function(ref) { if (def.fixed instanceof AST_Defun && !all(def.references, function(ref) {
var scope = ref.scope; var scope = ref.scope;
do { do {
if (def.scope === scope) return true; if (def.scope === scope) return true;
@@ -380,6 +380,15 @@ merge(Compressor.prototype, {
mark(tw, def, true); mark(tw, def, true);
} }
}); });
scope.may_call_this = function() {
scope.may_call_this = noop;
if (!scope.contains_this()) return;
scope.functions.each(function(def) {
if (def.init instanceof AST_Defun && !(def.id in tw.defun_ids)) {
tw.defun_ids[def.id] = false;
}
});
};
} }
function mark_defun(tw, def) { function mark_defun(tw, def) {
@@ -461,8 +470,7 @@ merge(Compressor.prototype, {
function ref_once(tw, compressor, def) { function ref_once(tw, compressor, def) {
return compressor.option("unused") return compressor.option("unused")
&& !def.scope.uses_eval && !def.scope.pinned()
&& !def.scope.uses_with
&& def.references.length - def.recursive_refs == 1 && def.references.length - def.recursive_refs == 1
&& tw.loop_ids[def.id] === tw.in_loop; && tw.loop_ids[def.id] === tw.in_loop;
} }
@@ -556,6 +564,7 @@ merge(Compressor.prototype, {
return true; return true;
}); });
def(AST_Call, function(tw, descend) { def(AST_Call, function(tw, descend) {
tw.find_parent(AST_Scope).may_call_this();
var exp = this.expression; var exp = this.expression;
if (!(exp instanceof AST_SymbolRef)) return; if (!(exp instanceof AST_SymbolRef)) return;
var def = exp.definition(); var def = exp.definition();
@@ -714,7 +723,7 @@ merge(Compressor.prototype, {
if (value instanceof AST_Lambda && recursive_ref(tw, d)) { if (value instanceof AST_Lambda && recursive_ref(tw, d)) {
d.recursive_refs++; d.recursive_refs++;
} else if (value && ref_once(tw, compressor, d)) { } else if (value && ref_once(tw, compressor, d)) {
d.single_use = value instanceof AST_Lambda d.single_use = value instanceof AST_Lambda && !value.pinned()
|| d.scope === this.scope && value.is_constant_expression(); || d.scope === this.scope && value.is_constant_expression();
} else { } else {
d.single_use = false; d.single_use = false;
@@ -1055,7 +1064,7 @@ merge(Compressor.prototype, {
// Will not attempt to collapse assignments into or past code blocks // Will not attempt to collapse assignments into or past code blocks
// which are not sequentially executed, e.g. loops and conditionals. // which are not sequentially executed, e.g. loops and conditionals.
function collapse(statements, compressor) { function collapse(statements, compressor) {
if (scope.uses_eval || scope.uses_with) return statements; if (scope.pinned()) return statements;
var args; var args;
var candidates = []; var candidates = [];
var stat_index = statements.length; var stat_index = statements.length;
@@ -1240,7 +1249,10 @@ merge(Compressor.prototype, {
} }
function should_stop(node, parent) { function should_stop(node, parent) {
if (node instanceof AST_Assign) return node.operator != "=" && lhs.equivalent_to(node.left); if (parent instanceof AST_For) return node !== parent.init;
if (node instanceof AST_Assign) {
return node.operator != "=" && lhs.equivalent_to(node.left);
}
if (node instanceof AST_Call) { if (node instanceof AST_Call) {
return lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression); return lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression);
} }
@@ -1249,7 +1261,6 @@ merge(Compressor.prototype, {
if (node instanceof AST_LoopControl) return true; if (node instanceof AST_LoopControl) return true;
if (node instanceof AST_Try) return true; if (node instanceof AST_Try) return true;
if (node instanceof AST_With) return true; if (node instanceof AST_With) return true;
if (parent instanceof AST_For) return node !== parent.init;
if (replace_all) return false; if (replace_all) return false;
return node instanceof AST_SymbolRef && !node.is_declared(compressor); return node instanceof AST_SymbolRef && !node.is_declared(compressor);
} }
@@ -1289,7 +1300,7 @@ merge(Compressor.prototype, {
if (fn instanceof AST_Function if (fn instanceof AST_Function
&& !fn.name && !fn.name
&& !fn.uses_arguments && !fn.uses_arguments
&& !fn.uses_eval && !fn.pinned()
&& (iife = compressor.parent()) instanceof AST_Call && (iife = compressor.parent()) instanceof AST_Call
&& iife.expression === fn) { && iife.expression === fn) {
var fn_strict = compressor.has_directive("use strict"); var fn_strict = compressor.has_directive("use strict");
@@ -1306,9 +1317,12 @@ merge(Compressor.prototype, {
})); }));
if (sym.name in names) continue; if (sym.name in names) continue;
names[sym.name] = true; names[sym.name] = true;
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor); if (!arg) {
else { arg = make_node(AST_Undefined, sym).transform(compressor);
var tw = new TreeWalker(function(node) { } else if (arg instanceof AST_Lambda && arg.pinned()) {
arg = null;
} else {
arg.walk(new TreeWalker(function(node) {
if (!arg) return true; if (!arg) return true;
if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) { if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) {
var s = node.definition().scope; var s = node.definition().scope;
@@ -1317,12 +1331,11 @@ merge(Compressor.prototype, {
} }
arg = null; arg = null;
} }
if (node instanceof AST_This && (fn_strict || !tw.find_parent(AST_Scope))) { if (node instanceof AST_This && (fn_strict || !this.find_parent(AST_Scope))) {
arg = null; arg = null;
return true; return true;
} }
}); }));
arg.walk(tw);
} }
if (arg) candidates.unshift([ make_node(AST_VarDef, sym, { if (arg) candidates.unshift([ make_node(AST_VarDef, sym, {
name: sym, name: sym,
@@ -3250,7 +3263,7 @@ merge(Compressor.prototype, {
if (!compressor.option("unused")) return; if (!compressor.option("unused")) return;
if (compressor.has_directive("use asm")) return; if (compressor.has_directive("use asm")) return;
var self = this; var self = this;
if (self.uses_eval || self.uses_with) return; if (self.pinned()) return;
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs; var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars; var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node, props) { var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node, props) {
@@ -4513,7 +4526,7 @@ merge(Compressor.prototype, {
if (compressor.option("unused") if (compressor.option("unused")
&& is_func && is_func
&& !fn.uses_arguments && !fn.uses_arguments
&& !fn.uses_eval) { && !fn.pinned()) {
var pos = 0, last = 0; var pos = 0, last = 0;
for (var i = 0, len = self.args.length; i < len; i++) { for (var i = 0, len = self.args.length; i < len; i++) {
var trim = i >= fn.argnames.length; var trim = i >= fn.argnames.length;
@@ -4793,7 +4806,7 @@ merge(Compressor.prototype, {
var def, value, scope, in_loop, level = -1; var def, value, scope, in_loop, level = -1;
if (can_inline if (can_inline
&& !fn.uses_arguments && !fn.uses_arguments
&& !fn.uses_eval && !fn.pinned()
&& !(fn.name && fn instanceof AST_Function) && !(fn.name && fn instanceof AST_Function)
&& (value = can_flatten_body(stat)) && (value = can_flatten_body(stat))
&& (exp === fn && (exp === fn
@@ -6276,7 +6289,7 @@ merge(Compressor.prototype, {
return self; return self;
}); });
AST_Lambda.DEFMETHOD("contains_this", function() { AST_Scope.DEFMETHOD("contains_this", function() {
var result; var result;
var self = this; var self = this;
self.walk(new TreeWalker(function(node) { self.walk(new TreeWalker(function(node) {

View File

@@ -55,6 +55,7 @@ function minify(files, options) {
try { try {
options = defaults(options, { options = defaults(options, {
compress: {}, compress: {},
enclose: false,
ie8: false, ie8: false,
keep_fnames: false, keep_fnames: false,
mangle: {}, mangle: {},
@@ -157,6 +158,9 @@ function minify(files, options) {
if (options.wrap) { if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap); toplevel = toplevel.wrap_commonjs(options.wrap);
} }
if (options.enclose) {
toplevel = toplevel.wrap_enclose(options.enclose);
}
if (timings) timings.rename = Date.now(); if (timings) timings.rename = Date.now();
if (options.rename) { if (options.rename) {
toplevel.figure_out_scope(options.mangle); toplevel.figure_out_scope(options.mangle);

View File

@@ -63,12 +63,12 @@ SymbolDef.prototype = {
unmangleable: function(options) { unmangleable: function(options) {
if (!options) options = {}; if (!options) options = {};
return (this.global && !options.toplevel) return this.global && !options.toplevel
|| this.undeclared || this.undeclared
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with)) || !options.eval && this.scope.pinned()
|| (options.keep_fnames || options.keep_fnames
&& (this.orig[0] instanceof AST_SymbolLambda && (this.orig[0] instanceof AST_SymbolLambda
|| this.orig[0] instanceof AST_SymbolDefun)); || this.orig[0] instanceof AST_SymbolDefun);
}, },
mangle: function(options) { mangle: function(options) {
var cache = options.cache && options.cache.props; var cache = options.cache && options.cache.props;
@@ -364,8 +364,7 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options){
AST_Label.DEFMETHOD("unmangleable", return_false); AST_Label.DEFMETHOD("unmangleable", return_false);
AST_Symbol.DEFMETHOD("unreferenced", function() { AST_Symbol.DEFMETHOD("unreferenced", function() {
return this.definition().references.length == 0 return !this.definition().references.length && !this.scope.pinned();
&& !(this.scope.uses_eval || this.scope.uses_with);
}); });
AST_Symbol.DEFMETHOD("definition", function() { AST_Symbol.DEFMETHOD("definition", function() {

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit", "description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)", "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"version": "3.3.25", "version": "3.4.0",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },

View File

@@ -4931,6 +4931,27 @@ collapse_rhs_lhs_2: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
collapse_rhs_loop: {
options = {
collapse_vars: true,
}
input: {
var s;
s = "<tpl>PASS</tpl>";
for (var m, r = /<tpl>(.*)<\/tpl>/; m = s.match(r);)
s = s.replace(m[0], m[1]);
console.log(s);
}
expect: {
var s;
s = "<tpl>PASS</tpl>";
for (var m, r = /<tpl>(.*)<\/tpl>/; m = s.match(r);)
s = s.replace(m[0], m[1]);
console.log(s);
}
expect_stdout: "PASS"
}
collapse_rhs_side_effects: { collapse_rhs_side_effects: {
options = { options = {
collapse_vars: true, collapse_vars: true,

View File

@@ -1814,3 +1814,115 @@ issue_2995: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3146_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect_stdout: "PASS"
}
issue_3146_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect_stdout: "PASS"
}
issue_3146_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect_stdout: "PASS"
}
issue_3146_4: {
options = {
reduce_vars: true,
unused: true,
}
input: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect_stdout: "PASS"
}

View File

@@ -6178,3 +6178,228 @@ issue_3125: {
} }
expect_stdout: "7" expect_stdout: "7"
} }
issue_3140_1: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
function f() {
}
f.g = function g() {
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
this();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect: {
(function() {
var a;
function f() {
}
f.g = function g() {
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
this();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect_stdout: "PASS"
}
issue_3140_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
function f() {
}
f.g = function g() {
var self = this;
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
self();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect: {
(function() {
var a;
function f() {
}
f.g = function g() {
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
this();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect_stdout: "PASS"
}
issue_3140_3: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
function f() {
}
f.g = function g() {
var self = this;
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
(function() {
return self;
})()();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect: {
(function() {
var a;
function f() {
}
f.g = function g() {
var self = this;
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
(function() {
return self;
})()();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect_stdout: "PASS"
}
issue_3140_4: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
function f() {
}
f.g = function g() {
var o = {
p: this
};
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
o.p();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect: {
(function() {
var a;
function f() {
}
f.g = function g() {
var o = {
p: this
};
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
o.p();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect_stdout: "PASS"
}
issue_3140_5: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var n = 1, c = 0;
(function(a) {
var b = function() {
this;
n-- && h();
}();
function h() {
b && c++;
}
h(b = 1);
})();
console.log(c);
}
expect: {
var n = 1, c = 0;
(function(a) {
var b = function() {
this;
n-- && h();
}();
function h() {
b && c++;
}
h(b = 1);
})();
console.log(c);
}
expect_stdout: "1"
}

37
test/compress/regexp.js Normal file
View File

@@ -0,0 +1,37 @@
regexp_simple: {
input: {
/rx/ig
}
expect_exact: "/rx/gi;"
}
regexp_slashes: {
input: {
/\\\/rx\/\\/ig
}
expect_exact: "/\\\\\\/rx\\/\\\\/gi;"
}
regexp_1: {
input: {
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/ig)));
}
expect: {
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/gi)));
}
expect_stdout: '["PASS","pass"]'
}
regexp_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(JSON.stringify("COMPASS? Overpass.".match(new RegExp("([Sap]+)", "ig"))));
}
expect: {
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/gi)));
}
expect_stdout: '["PASS","pass"]'
}

View File

@@ -14,6 +14,13 @@ issue_1929: {
function f(s) { function f(s) {
return s.split(/[\\/]/); return s.split(/[\\/]/);
} }
console.log(JSON.stringify(f("A/B\\C\\D/E\\F")));
} }
expect_exact: "function f(s){return s.split(/[\\\\/]/)}" expect: {
function f(s) {
return s.split(/[\\/]/);
}
console.log(JSON.stringify(f("A/B\\C\\D/E\\F")));
}
expect_stdout: '["A","B","C","D","E","F"]'
} }

View File

@@ -1,4 +1,5 @@
var fs = require("fs"); var fs = require("fs");
var parse = require("url").parse;
var path = require("path"); var path = require("path");
try { try {
@@ -19,7 +20,9 @@ module.exports = function(url, callback) {
var result = read(url); var result = read(url);
result.on("error", function(e) { result.on("error", function(e) {
if (e.code != "ENOENT") return callback(e); if (e.code != "ENOENT") return callback(e);
require(url.slice(0, url.indexOf(":"))).get(url, function(res) { var options = parse(url);
options.rejectUnauthorized = false;
require(options.protocol.slice(0, -1)).get(options, function(res) {
if (res.statusCode !== 200) return callback(res); if (res.statusCode !== 200) return callback(res);
res.pipe(fs.createWriteStream(local(url)).on("close", function() { res.pipe(fs.createWriteStream(local(url)).on("close", function() {
callback(null, read(url)); callback(null, read(url));

View File

@@ -0,0 +1,4 @@
function enclose() {
console.log("test enclose");
}
enclose();

View File

@@ -3,7 +3,7 @@
"use strict"; "use strict";
var site = "http://browserbench.org/JetStream"; var site = "https://browserbench.org/JetStream";
if (typeof phantom == "undefined") { if (typeof phantom == "undefined") {
require("../tools/exit"); require("../tools/exit");
var args = process.argv.slice(2); var args = process.argv.slice(2);

View File

@@ -55,8 +55,7 @@ process.nextTick(function run() {
var elapsed = Date.now(); var elapsed = Date.now();
var timer; var timer;
var done = function() { var done = function() {
clearTimeout(timer); reset();
done = function() {};
elapsed = Date.now() - elapsed; elapsed = Date.now() - elapsed;
if (elapsed > task.limit) { if (elapsed > task.limit) {
throw new Error("Timed out: " + elapsed + "ms > " + task.limit + "ms"); throw new Error("Timed out: " + elapsed + "ms > " + task.limit + "ms");
@@ -73,6 +72,7 @@ process.nextTick(function run() {
}, limit); }, limit);
}; };
task.timeout(task.limit); task.timeout(task.limit);
process.on("uncaughtException", raise);
task.call(task, done); task.call(task, done);
} else { } else {
task.timeout = config.timeout; task.timeout = config.timeout;
@@ -99,11 +99,16 @@ process.nextTick(function run() {
} }
function raise(err) { function raise(err) {
clearTimeout(timer); reset();
done = function() {};
task.titles.error = err; task.titles.error = err;
errors.push(task.titles); errors.push(task.titles);
log_titles(console.log, task.titles, red('\u00D7 ')); log_titles(console.log, task.titles, red('\u00D7 '));
process.nextTick(run); process.nextTick(run);
} }
function reset() {
clearTimeout(timer);
done = function() {};
process.removeListener("uncaughtException", raise);
}
}); });

View File

@@ -744,4 +744,36 @@ describe("bin/uglifyjs", function () {
done(); done();
}); });
}); });
it("Should work with --enclose", function(done) {
var command = uglifyjscmd + " test/input/enclose/input.js --enclose";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, '(function(){function enclose(){console.log("test enclose")}enclose()})();\n');
done();
});
});
it("Should work with --enclose arg", function(done) {
var command = uglifyjscmd + " test/input/enclose/input.js --enclose undefined";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, '(function(undefined){function enclose(){console.log("test enclose")}enclose()})();\n');
done();
});
});
it("Should work with --enclose arg:value", function(done) {
var command = uglifyjscmd + " test/input/enclose/input.js --enclose window,undefined:window";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, '(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window);\n');
done();
});
});
it("Should work with --enclose & --wrap", function(done) {
var command = uglifyjscmd + " test/input/enclose/input.js --enclose window,undefined:window --wrap exports";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, '(function(window,undefined){(function(exports){function enclose(){console.log("test enclose")}enclose()})(typeof exports=="undefined"?exports={}:exports)})(window);\n');
done();
});
});
}); });

View File

@@ -303,4 +303,45 @@ describe("minify", function() {
} }
}); });
}); });
describe("enclose", function() {
var code = read("test/input/enclose/input.js");
it("Should work with true", function() {
var result = Uglify.minify(code, {
compress: false,
enclose: true,
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(){function enclose(){console.log("test enclose")}enclose()})();');
});
it("Should work with arg", function() {
var result = Uglify.minify(code, {
compress: false,
enclose: 'undefined',
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(undefined){function enclose(){console.log("test enclose")}enclose()})();');
});
it("Should work with arg:value", function() {
var result = Uglify.minify(code, {
compress: false,
enclose: 'window,undefined:window',
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window);');
});
it("Should work alongside wrap", function() {
var result = Uglify.minify(code, {
compress: false,
enclose: 'window,undefined:window',
mangle: false,
wrap: 'exports',
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(window,undefined){(function(exports){function enclose(){console.log("test enclose")}enclose()})(typeof exports=="undefined"?exports={}:exports)})(window);');
});
});
}); });

View File

@@ -57,24 +57,23 @@ describe("sourcemaps", function() {
includeSources: true includeSources: true
} }
}); });
if (result.error) throw result.error;
var map = JSON.parse(result.map); var map = JSON.parse(result.map);
assert.equal(map.file, "simple.min.js");
assert.equal(map.file, 'simple.min.js');
assert.equal(map.sourcesContent.length, 1); assert.equal(map.sourcesContent.length, 1);
assert.equal(map.sourcesContent[0], assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
}); });
it("Should process inline source map", function() { it("Should process inline source map", function() {
var code = Uglify.minify(read("./test/input/issue-520/input.js"), { var result = Uglify.minify(read("./test/input/issue-520/input.js"), {
compress: { toplevel: true }, compress: { toplevel: true },
sourceMap: { sourceMap: {
content: "inline", content: "inline",
includeSources: true, includeSources: true,
url: "inline" url: "inline"
} }
}).code + "\n"; });
assert.strictEqual(code, readFileSync("test/input/issue-520/output.js", "utf8")); if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-520/output.js", "utf8"));
}); });
it("Should warn for missing inline source map", function() { it("Should warn for missing inline source map", function() {
var warn_function = Uglify.AST_Node.warn_function; var warn_function = Uglify.AST_Node.warn_function;
@@ -149,22 +148,24 @@ describe("sourcemaps", function() {
}); });
describe("sourceMapInline", function() { describe("sourceMapInline", function() {
it("should append source map to output js when sourceMapInline is enabled", function() { it("Should append source map to output js when sourceMapInline is enabled", function() {
var result = Uglify.minify('var a = function(foo) { return foo; };', { var result = Uglify.minify('var a = function(foo) { return foo; };', {
sourceMap: { sourceMap: {
url: "inline" url: "inline"
} }
}); });
if (result.error) throw result.error;
var code = result.code; var code = result.code;
assert.strictEqual(code, "var a=function(n){return n};\n" + assert.strictEqual(code, "var a=function(n){return n};\n" +
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BIn0="); "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BIn0=");
}); });
it("should not append source map to output js when sourceMapInline is not enabled", function() { it("Should not append source map to output js when sourceMapInline is not enabled", function() {
var result = Uglify.minify('var a = function(foo) { return foo; };'); var result = Uglify.minify('var a = function(foo) { return foo; };');
if (result.error) throw result.error;
var code = result.code; var code = result.code;
assert.strictEqual(code, "var a=function(n){return n};"); assert.strictEqual(code, "var a=function(n){return n};");
}); });
it("should work with max_line_len", function() { it("Should work with max_line_len", function() {
var result = Uglify.minify(read("./test/input/issue-505/input.js"), { var result = Uglify.minify(read("./test/input/issue-505/input.js"), {
output: { output: {
max_line_len: 20 max_line_len: 20
@@ -173,8 +174,39 @@ describe("sourcemaps", function() {
url: "inline" url: "inline"
} }
}); });
assert.strictEqual(result.error, undefined); if (result.error) throw result.error;
assert.strictEqual(result.code, read("./test/input/issue-505/output.js")); assert.strictEqual(result.code, read("./test/input/issue-505/output.js"));
}); });
it("Should work with unicode characters", function() {
var code = [
"var tëst = '→unicøde←';",
"alert(tëst);",
].join("\n");
var result = Uglify.minify(code, {
sourceMap: {
includeSources: true,
url: "inline",
}
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
assert.strictEqual(map.sourcesContent.length, 1);
assert.strictEqual(map.sourcesContent[0], code);
var encoded = result.code.slice(result.code.lastIndexOf(",") + 1);
map = JSON.parse(new Buffer(encoded, "base64").toString());
assert.strictEqual(map.sourcesContent.length, 1);
assert.strictEqual(map.sourcesContent[0], code);
result = Uglify.minify(result.code, {
sourceMap: {
content: "inline",
includeSources: true,
}
});
if (result.error) throw result.error;
map = JSON.parse(result.map);
assert.strictEqual(map.names.length, 2);
assert.strictEqual(map.names[0], "tëst");
assert.strictEqual(map.names[1], "alert");
});
}); });
}); });