Merge 263fb4c2d9 into eb55d8a9bb
This commit is contained in:
commit
520db07334
|
|
@ -450,6 +450,9 @@ UglifyJS will warn about the condition being always false and about dropping
|
||||||
unreachable code; for now there is no option to turn off only this specific
|
unreachable code; for now there is no option to turn off only this specific
|
||||||
warning, you can pass `warnings=false` to turn off *all* warnings.
|
warning, you can pass `warnings=false` to turn off *all* warnings.
|
||||||
|
|
||||||
|
You can specify nested constants like `--define env.DEBUG=false` which requires
|
||||||
|
`-c unsafe` in order to work.
|
||||||
|
|
||||||
Another way of doing that is to declare your globals as constants in a
|
Another way of doing that is to declare your globals as constants in a
|
||||||
separate file and include it into the build. For example you can have a
|
separate file and include it into the build. For example you can have a
|
||||||
`build/defines.js` file with the following:
|
`build/defines.js` file with the following:
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ if (ARGS.reserve_domprops) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.d) {
|
if (ARGS.d) {
|
||||||
if (COMPRESS) COMPRESS.global_defs = getOptions("d");
|
if (COMPRESS) COMPRESS.global_defs = getOptions("d", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.pure_funcs) {
|
if (ARGS.pure_funcs) {
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,22 @@ function Compressor(options, false_by_default) {
|
||||||
}, true);
|
}, true);
|
||||||
var sequences = this.options["sequences"];
|
var sequences = this.options["sequences"];
|
||||||
this.sequences_limit = sequences == 1 ? 200 : sequences | 0;
|
this.sequences_limit = sequences == 1 ? 200 : sequences | 0;
|
||||||
|
if ("global_defs" in this.options) {
|
||||||
|
var global_defs = this.options["global_defs"];
|
||||||
|
for (var key in global_defs) {
|
||||||
|
var tokens = key.split(/\./);
|
||||||
|
if (tokens.length > 1) {
|
||||||
|
var last = tokens.pop();
|
||||||
|
tokens.reduce(function(o, token) {
|
||||||
|
if (!(token in o)) {
|
||||||
|
o[token] = {};
|
||||||
|
}
|
||||||
|
return o[token];
|
||||||
|
}, global_defs)[last] = global_defs[key];
|
||||||
|
delete global_defs[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
this.warnings_produced = {};
|
this.warnings_produced = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -154,7 +170,7 @@ merge(Compressor.prototype, {
|
||||||
this.walk(new TreeWalker(function(node){
|
this.walk(new TreeWalker(function(node){
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var d = node.definition();
|
var d = node.definition();
|
||||||
if (d && d.init) {
|
if (d.init) {
|
||||||
delete d.init._evaluated;
|
delete d.init._evaluated;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -175,17 +191,6 @@ merge(Compressor.prototype, {
|
||||||
};
|
};
|
||||||
|
|
||||||
function make_node_from_constant(compressor, val, orig) {
|
function make_node_from_constant(compressor, val, orig) {
|
||||||
// XXX: WIP.
|
|
||||||
// if (val instanceof AST_Node) return val.transform(new TreeTransformer(null, function(node){
|
|
||||||
// if (node instanceof AST_SymbolRef) {
|
|
||||||
// var scope = compressor.find_parent(AST_Scope);
|
|
||||||
// var def = scope.find_variable(node);
|
|
||||||
// node.thedef = def;
|
|
||||||
// return node;
|
|
||||||
// }
|
|
||||||
// })).transform(compressor);
|
|
||||||
|
|
||||||
if (val instanceof AST_Node) return val.transform(compressor);
|
|
||||||
switch (typeof val) {
|
switch (typeof val) {
|
||||||
case "string":
|
case "string":
|
||||||
return make_node(AST_String, orig, {
|
return make_node(AST_String, orig, {
|
||||||
|
|
@ -977,8 +982,11 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
|
|
||||||
function isLHS(node, parent) {
|
function isLHS(node, parent) {
|
||||||
return parent instanceof AST_Unary && (parent.operator === "++" || parent.operator === "--")
|
return (parent instanceof AST_Unary
|
||||||
|| parent instanceof AST_Assign && parent.left === node;
|
&& parent.expression === node
|
||||||
|
&& (parent.operator == "++" || parent.operator == "--"))
|
||||||
|
|| (parent instanceof AST_Assign
|
||||||
|
&& parent.left === node);
|
||||||
}
|
}
|
||||||
|
|
||||||
function best_of(ast1, ast2) {
|
function best_of(ast1, ast2) {
|
||||||
|
|
@ -998,12 +1006,15 @@ merge(Compressor.prototype, {
|
||||||
// constant; otherwise it's the original or a replacement node.
|
// constant; otherwise it's the original or a replacement node.
|
||||||
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
||||||
if (!compressor.option("evaluate")) return [ this ];
|
if (!compressor.option("evaluate")) return [ this ];
|
||||||
var val;
|
var val, has_global_defs;
|
||||||
try {
|
try {
|
||||||
val = this._eval(compressor);
|
val = this._eval(compressor);
|
||||||
|
has_global_defs = compressor._ev_has_global_defs;
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex !== def) throw ex;
|
if (ex !== def) throw ex;
|
||||||
return [ this ];
|
return [ this ];
|
||||||
|
} finally {
|
||||||
|
delete compressor._ev_has_global_defs;
|
||||||
}
|
}
|
||||||
var node;
|
var node;
|
||||||
try {
|
try {
|
||||||
|
|
@ -1011,6 +1022,17 @@ merge(Compressor.prototype, {
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
return [ this ];
|
return [ this ];
|
||||||
}
|
}
|
||||||
|
if (has_global_defs) {
|
||||||
|
var lhs, parent = this, level = 0;
|
||||||
|
do {
|
||||||
|
lhs = parent;
|
||||||
|
parent = compressor.parent(level++);
|
||||||
|
} while (parent instanceof AST_PropAccess && parent.expression === lhs);
|
||||||
|
if (isLHS(lhs, parent)) {
|
||||||
|
compressor.warn('global_defs ' + lhs.print_to_string() + ' redefined [{file}:{line},{col}]', lhs.start);
|
||||||
|
return [ this ];
|
||||||
|
}
|
||||||
|
}
|
||||||
return [ best_of(node, this), val ];
|
return [ best_of(node, this), val ];
|
||||||
});
|
});
|
||||||
var unaryPrefix = makePredicate("! ~ - +");
|
var unaryPrefix = makePredicate("! ~ - +");
|
||||||
|
|
@ -1167,7 +1189,14 @@ merge(Compressor.prototype, {
|
||||||
this._evaluating = true;
|
this._evaluating = true;
|
||||||
try {
|
try {
|
||||||
var d = this.definition();
|
var d = this.definition();
|
||||||
if (d && (d.constant || compressor.option("reduce_vars") && !d.modified) && d.init) {
|
if (d.undeclared) {
|
||||||
|
var defines = compressor.option("global_defs");
|
||||||
|
if (defines && HOP(defines, d.name)) {
|
||||||
|
compressor._ev_has_global_defs = true;
|
||||||
|
return defines[d.name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((d.constant || compressor.option("reduce_vars") && !d.modified) && d.init) {
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
if (!HOP(d.init, '_evaluated')) {
|
if (!HOP(d.init, '_evaluated')) {
|
||||||
d.init._evaluated = ev(d.init, compressor);
|
d.init._evaluated = ev(d.init, compressor);
|
||||||
|
|
@ -2686,13 +2715,14 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_SymbolRef, function(self, compressor){
|
OPT(AST_SymbolRef, function(self, compressor){
|
||||||
if (self.undeclared() && !isLHS(self, compressor.parent())) {
|
if (self.undeclared()) {
|
||||||
var defines = compressor.option("global_defs");
|
var e = self.evaluate(compressor);
|
||||||
if (defines && HOP(defines, self.name)) {
|
if (e.length > 1) {
|
||||||
return make_node_from_constant(compressor, defines[self.name], self);
|
return self === e[0] ? make_node_from_constant(compressor, e[1], self) : e[0];
|
||||||
}
|
}
|
||||||
// testing against !self.scope.uses_with first is an optimization
|
// testing against !self.scope.uses_with first is an optimization
|
||||||
if (!self.scope.uses_with || !compressor.find_parent(AST_With)) {
|
if (!isLHS(self, compressor)
|
||||||
|
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
||||||
switch (self.name) {
|
switch (self.name) {
|
||||||
case "undefined":
|
case "undefined":
|
||||||
return make_node(AST_Undefined, self);
|
return make_node(AST_Undefined, self);
|
||||||
|
|
|
||||||
144
test/compress/global_defs.js
Normal file
144
test/compress/global_defs.js
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
must_replace: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
global_defs: {
|
||||||
|
D: "foo bar",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(D);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("foo bar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
global_defs: {
|
||||||
|
undefined: 0,
|
||||||
|
NaN: 1,
|
||||||
|
Infinity: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(undefined, NaN, Infinity);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(0, 1, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
global_defs: {
|
||||||
|
CONFIG: {
|
||||||
|
DEBUG: [ 0 ],
|
||||||
|
VALUE: 42,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(CONFIG) {
|
||||||
|
return CONFIG.VALUE;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
var CONFIG = { VALUE: 1 };
|
||||||
|
return CONFIG.VALUE;
|
||||||
|
}
|
||||||
|
function h() {
|
||||||
|
return CONFIG.VALUE;
|
||||||
|
}
|
||||||
|
if (CONFIG.DEBUG[0])
|
||||||
|
console.debug("foo");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(CONFIG) {
|
||||||
|
return CONFIG.VALUE;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
var CONFIG = { VALUE: 1 };
|
||||||
|
return CONFIG.VALUE;
|
||||||
|
}
|
||||||
|
function h() {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
if (0)
|
||||||
|
console.debug("foo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expanded: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
global_defs: {
|
||||||
|
"CONFIG.DEBUG": [ 0 ],
|
||||||
|
"CONFIG.VALUE": 42,
|
||||||
|
},
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(CONFIG) {
|
||||||
|
return CONFIG.VALUE;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
var CONFIG = { VALUE: 1 };
|
||||||
|
return CONFIG.VALUE;
|
||||||
|
}
|
||||||
|
function h() {
|
||||||
|
return CONFIG.VALUE;
|
||||||
|
}
|
||||||
|
if (CONFIG.DEBUG[0])
|
||||||
|
console.debug("foo");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(CONFIG) {
|
||||||
|
return CONFIG.VALUE;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
var CONFIG = { VALUE: 1 };
|
||||||
|
return CONFIG.VALUE;
|
||||||
|
}
|
||||||
|
function h() {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
if (0)
|
||||||
|
console.debug("foo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixed: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
global_defs: {
|
||||||
|
"CONFIG.VALUE": 42,
|
||||||
|
},
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(++CONFIG.DEBUG);
|
||||||
|
console.log(++CONFIG.VALUE);
|
||||||
|
console.log(++CONFIG["VAL" + "UE"]);
|
||||||
|
console.log(++DEBUG[CONFIG.VALUE]);
|
||||||
|
CONFIG.VALUE.FOO = "bar";
|
||||||
|
console.log(CONFIG, ++(1 + 1));
|
||||||
|
console.log(({ 42: "foo" })[CONFIG.VALUE] += "bar");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(++CONFIG.DEBUG);
|
||||||
|
console.log(++CONFIG.VALUE);
|
||||||
|
console.log(++CONFIG["VALUE"]);
|
||||||
|
console.log(++DEBUG[42]);
|
||||||
|
CONFIG.VALUE.FOO = "bar";
|
||||||
|
console.log(CONFIG, ++2);
|
||||||
|
console.log("foo" += "bar");
|
||||||
|
}
|
||||||
|
expect_warnings: [
|
||||||
|
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:123,22]',
|
||||||
|
'WARN: global_defs CONFIG["VALUE"] redefined [test/compress/global_defs.js:124,22]',
|
||||||
|
'WARN: global_defs CONFIG.VALUE.FOO redefined [test/compress/global_defs.js:126,8]',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
do_not_update_lhs: {
|
do_not_update_lhs: {
|
||||||
options = {
|
options = {
|
||||||
|
evaluate: true,
|
||||||
global_defs: { DEBUG: 0 }
|
global_defs: { DEBUG: 0 }
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
|
@ -16,6 +17,7 @@ do_not_update_lhs: {
|
||||||
|
|
||||||
do_update_rhs: {
|
do_update_rhs: {
|
||||||
options = {
|
options = {
|
||||||
|
evaluate: true,
|
||||||
global_defs: { DEBUG: 0 }
|
global_defs: { DEBUG: 0 }
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
|
@ -27,3 +29,29 @@ do_update_rhs: {
|
||||||
MY_DEBUG += 0;
|
MY_DEBUG += 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mixed: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
global_defs: { DEBUG: 0 }
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
DEBUG = 1;
|
||||||
|
DEBUG++;
|
||||||
|
DEBUG += 1;
|
||||||
|
f(DEBUG);
|
||||||
|
x = DEBUG;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
DEBUG = 1;
|
||||||
|
DEBUG++;
|
||||||
|
DEBUG += 1;
|
||||||
|
f(0);
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
expect_warnings: [
|
||||||
|
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:39,8]',
|
||||||
|
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:40,8]',
|
||||||
|
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:41,8]',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
|
||||||
1
test/input/issue-1467/simple.js
Normal file
1
test/input/issue-1467/simple.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
console.log(D);
|
||||||
1
test/input/issue-1467/unsafe.js
Normal file
1
test/input/issue-1467/unsafe.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
console.log(C.V, C.D);
|
||||||
|
|
@ -100,4 +100,24 @@ describe("bin/uglifyjs", function () {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Should work with --define", function (done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/issue-1467/simple.js --define D=5 -c';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
assert.strictEqual(stdout, "console.log(5);\n");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should work with --define & -c unsafe", function (done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/issue-1467/unsafe.js --define C.D=5,C.V=3 -c unsafe';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
assert.strictEqual(stdout, "console.log(3,5);\n");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user