Skip to content

Commit 4b3f5c5

Browse files
committed
Fixes #943 uglify mangleProperties, also upgrade to uglify 2.7.4
1 parent aa349c7 commit 4b3f5c5

File tree

9 files changed

+184
-43
lines changed

9 files changed

+184
-43
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ build/tests/lib/stubModules/main-built.js
101101
build/tests/lib/stubModules/perModule/built
102102
build/tests/lib/transportBeforeMinify/www-built
103103
build/tests/lib/typescriptConfig/main-built.js
104+
build/tests/lib/uglifyMangleProperties/main-built.js
104105
build/tests/lib/umd/main-built.js
105106
build/tests/lib/umd2/built.js
106107
build/tests/lib/umd4/app-built.js

build/jslib/uglifyjs.js

Lines changed: 144 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3337,12 +3337,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
33373337
}
33383338
if (node instanceof AST_SymbolRef) {
33393339
var name = node.name;
3340-
if (name == "eval" && tw.parent() instanceof AST_Call) {
3340+
var parent = tw.parent();
3341+
if (name == "eval" && parent instanceof AST_Call) {
33413342
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
33423343
s.uses_eval = true;
33433344
}
33443345
}
33453346
var sym = node.scope.find_variable(name);
3347+
if (node.scope instanceof AST_Lambda && name == "arguments") {
3348+
node.scope.uses_arguments = true;
3349+
}
33463350
if (!sym) {
33473351
var g;
33483352
if (globals.has(name)) {
@@ -3353,12 +3357,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
33533357
g.global = true;
33543358
globals.set(name, g);
33553359
}
3356-
node.thedef = g;
3357-
if (func && name == "arguments") {
3358-
func.uses_arguments = true;
3359-
}
3360-
} else {
3361-
node.thedef = sym;
3360+
sym = g;
3361+
}
3362+
node.thedef = sym;
3363+
if (parent instanceof AST_Unary && (parent.operator === '++' || parent.operator === '--')
3364+
|| parent instanceof AST_Assign && parent.left === node) {
3365+
sym.modified = true;
33623366
}
33633367
node.reference();
33643368
return true;
@@ -3848,9 +3852,54 @@ function OutputStream(options) {
38483852
screw_ie8 : true,
38493853
preamble : null,
38503854
quote_style : 0,
3851-
keep_quoted_props: false
3855+
keep_quoted_props: false,
3856+
wrap_iife : false
38523857
}, true);
38533858

3859+
// Convert comment option to RegExp if neccessary and set up comments filter
3860+
if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) {
3861+
var regex_pos = options.comments.lastIndexOf("/");
3862+
options.comments = new RegExp(
3863+
options.comments.substr(1, regex_pos - 1),
3864+
options.comments.substr(regex_pos + 1)
3865+
);
3866+
}
3867+
if (options.comments instanceof RegExp) {
3868+
options.comments = (function(f) {
3869+
return function(comment) {
3870+
return comment.type == "comment5" || f.test(comment.value);
3871+
}
3872+
})(options.comments);
3873+
}
3874+
else if (typeof options.comments === "function") {
3875+
options.comments = (function(f) {
3876+
return function(comment) {
3877+
return comment.type == "comment5" || f(this, comment);
3878+
}
3879+
})(options.comments);
3880+
}
3881+
else if (options.comments === "some") {
3882+
options.comments = function(comment) {
3883+
var text = comment.value;
3884+
var type = comment.type;
3885+
if (type == "comment2") {
3886+
// multiline comment
3887+
return /@preserve|@license|@cc_on/i.test(text);
3888+
}
3889+
return type == "comment5";
3890+
}
3891+
}
3892+
else if (options.comments){ // NOTE includes "all" option
3893+
options.comments = function() {
3894+
return true;
3895+
}
3896+
} else {
3897+
// Falsy case, so reject all comments, except shebangs
3898+
options.comments = function(comment) {
3899+
return comment.type == "comment5";
3900+
}
3901+
}
3902+
38543903
var indentation = 0;
38553904
var current_col = 0;
38563905
var current_line = 1;
@@ -4216,7 +4265,7 @@ function OutputStream(options) {
42164265

42174266
AST_Node.DEFMETHOD("add_comments", function(output){
42184267
if (output._readonly) return;
4219-
var c = output.option("comments"), self = this;
4268+
var self = this;
42204269
var start = self.start;
42214270
if (start && !start._comments_dumped) {
42224271
start._comments_dumped = true;
@@ -4239,19 +4288,7 @@ function OutputStream(options) {
42394288
}));
42404289
}
42414290

4242-
if (!c) {
4243-
comments = comments.filter(function(comment) {
4244-
return comment.type == "comment5";
4245-
});
4246-
} else if (c.test) {
4247-
comments = comments.filter(function(comment){
4248-
return comment.type == "comment5" || c.test(comment.value);
4249-
});
4250-
} else if (typeof c == "function") {
4251-
comments = comments.filter(function(comment){
4252-
return comment.type == "comment5" || c(self, comment);
4253-
});
4254-
}
4291+
comments = comments.filter(output.option("comments"), self);
42554292

42564293
// Keep single line comments after nlb, after nlb
42574294
if (!output.option("beautify") && comments.length > 0 &&
@@ -4302,7 +4339,16 @@ function OutputStream(options) {
43024339
// a function expression needs parens around it when it's provably
43034340
// the first token to appear in a statement.
43044341
PARENS(AST_Function, function(output){
4305-
return first_in_statement(output);
4342+
if (first_in_statement(output)) {
4343+
return true;
4344+
}
4345+
4346+
if (output.option('wrap_iife')) {
4347+
var p = output.parent();
4348+
return p instanceof AST_Call && p.expression === this;
4349+
}
4350+
4351+
return false;
43064352
});
43074353

43084354
// same goes for an object literal, because otherwise it would be
@@ -5266,6 +5312,7 @@ function Compressor(options, false_by_default) {
52665312
if_return : !false_by_default,
52675313
join_vars : !false_by_default,
52685314
collapse_vars : false,
5315+
reduce_vars : false,
52695316
cascade : !false_by_default,
52705317
side_effects : !false_by_default,
52715318
pure_getters : false,
@@ -6306,7 +6353,7 @@ merge(Compressor.prototype, {
63066353
this._evaluating = true;
63076354
try {
63086355
var d = this.definition();
6309-
if (d && d.constant && d.init) {
6356+
if (d && (d.constant || compressor.option("reduce_vars") && !d.modified) && d.init) {
63106357
return ev(d.init, compressor);
63116358
}
63126359
} finally {
@@ -7512,6 +7559,12 @@ merge(Compressor.prototype, {
75127559
// typeof always returns a non-empty string, thus it's
75137560
// always true in booleans
75147561
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
7562+
if (self.expression.has_side_effects(compressor)) {
7563+
return make_node(AST_Seq, self, {
7564+
car: self.expression,
7565+
cdr: make_node(AST_True, self)
7566+
});
7567+
}
75157568
return make_node(AST_True, self);
75167569
}
75177570
if (e instanceof AST_Binary && self.operator == "!") {
@@ -7698,8 +7751,8 @@ merge(Compressor.prototype, {
76987751
case "+":
76997752
var ll = self.left.evaluate(compressor);
77007753
var rr = self.right.evaluate(compressor);
7701-
if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1]) ||
7702-
(rr.length > 1 && rr[0] instanceof AST_String && rr[1])) {
7754+
if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1] && !self.right.has_side_effects(compressor)) ||
7755+
(rr.length > 1 && rr[0] instanceof AST_String && rr[1] && !self.left.has_side_effects(compressor))) {
77037756
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
77047757
return make_node(AST_True, self);
77057758
}
@@ -7854,16 +7907,26 @@ merge(Compressor.prototype, {
78547907
});
78557908

78567909
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
7910+
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
78577911
OPT(AST_Assign, function(self, compressor){
78587912
self = self.lift_sequences(compressor);
7859-
if (self.operator == "="
7860-
&& self.left instanceof AST_SymbolRef
7861-
&& self.right instanceof AST_Binary
7862-
&& self.right.left instanceof AST_SymbolRef
7863-
&& self.right.left.name == self.left.name
7864-
&& member(self.right.operator, ASSIGN_OPS)) {
7865-
self.operator = self.right.operator + "=";
7866-
self.right = self.right.right;
7913+
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
7914+
// x = expr1 OP expr2
7915+
if (self.right.left instanceof AST_SymbolRef
7916+
&& self.right.left.name == self.left.name
7917+
&& member(self.right.operator, ASSIGN_OPS)) {
7918+
// x = x - 2 ---> x -= 2
7919+
self.operator = self.right.operator + "=";
7920+
self.right = self.right.right;
7921+
}
7922+
else if (self.right.right instanceof AST_SymbolRef
7923+
&& self.right.right.name == self.left.name
7924+
&& member(self.right.operator, ASSIGN_OPS_COMMUTATIVE)
7925+
&& !self.right.left.has_side_effects(compressor)) {
7926+
// x = 2 & x ---> x &= 2
7927+
self.operator = self.right.operator + "=";
7928+
self.right = self.right.left;
7929+
}
78677930
}
78687931
return self;
78697932
});
@@ -9057,6 +9120,7 @@ exports.minify = function(files, options, name) {
90579120
sourceRoot : null,
90589121
inSourceMap : null,
90599122
sourceMapUrl : null,
9123+
sourceMapInline : false,
90609124
fromString : false,
90619125
warnings : false,
90629126
mangle : {},
@@ -9130,7 +9194,7 @@ exports.minify = function(files, options, name) {
91309194
if (typeof options.inSourceMap == "string") {
91319195
inMap = JSON.parse(rjsFile.readFile(options.inSourceMap, "utf8"));
91329196
}
9133-
if (options.outSourceMap) {
9197+
if (options.outSourceMap || options.sourceMapInline) {
91349198
output.source_map = SourceMap({
91359199
file: options.outSourceMap,
91369200
orig: inMap,
@@ -9151,16 +9215,19 @@ exports.minify = function(files, options, name) {
91519215
var stream = OutputStream(output);
91529216
toplevel.print(stream);
91539217

9154-
var mappingUrlPrefix = "\n//# sourceMappingURL=";
9155-
if (options.outSourceMap && typeof options.outSourceMap === "string" && options.sourceMapUrl !== false) {
9156-
stream += mappingUrlPrefix + (typeof options.sourceMapUrl === "string" ? options.sourceMapUrl : options.outSourceMap);
9157-
}
91589218

91599219
var source_map = output.source_map;
91609220
if (source_map) {
91619221
source_map = source_map + "";
91629222
}
91639223

9224+
var mappingUrlPrefix = "\n//# sourceMappingURL=";
9225+
if (options.sourceMapInline) {
9226+
stream += mappingUrlPrefix + "data:application/json;charset=utf-8;base64," + new Buffer(source_map).toString("base64");
9227+
} else if (options.outSourceMap && typeof options.outSourceMap === "string" && options.sourceMapUrl !== false) {
9228+
stream += mappingUrlPrefix + (typeof options.sourceMapUrl === "string" ? options.sourceMapUrl : options.outSourceMap);
9229+
}
9230+
91649231
return {
91659232
code : stream + "",
91669233
map : source_map
@@ -9216,4 +9283,42 @@ exports.describe_ast = function() {
92169283
return out + "";
92179284
};
92189285

9286+
exports.readNameCache = function(filename, key) {
9287+
var cache = null;
9288+
if (filename) {
9289+
try {
9290+
var cache = rjsFile.readFile(filename, "utf8");
9291+
cache = JSON.parse(cache)[key];
9292+
if (!cache) throw "init";
9293+
cache.props = Dictionary.fromObject(cache.props);
9294+
} catch(ex) {
9295+
cache = {
9296+
cname: -1,
9297+
props: new Dictionary()
9298+
};
9299+
}
9300+
}
9301+
return cache;
9302+
};
9303+
var readNameCache = exports.readNameCache;
9304+
9305+
exports.writeNameCache = function(filename, key, cache) {
9306+
if (filename) {
9307+
var data;
9308+
try {
9309+
data = rjsFile.readFile(filename, "utf8");
9310+
data = JSON.parse(data);
9311+
} catch(ex) {
9312+
data = {};
9313+
}
9314+
data[key] = {
9315+
cname: cache.cname,
9316+
props: cache.props.toObject()
9317+
};
9318+
fs.writeFileSync(filename, JSON.stringify(data, null, 2), "utf8");
9319+
}
9320+
};
9321+
var writeNameCache = exports.writeNameCache;
9322+
9323+
92199324
});

build/jslib/uglifyjs/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Sets up uglifyjs for use in the optimizer.
22

3-
Current embedded version: 2.7.3, source-map 0.5.6
3+
Current embedded version: 2.7.4, source-map 0.5.6
44

55
Steps:
66

@@ -19,6 +19,4 @@ THINGS TO CHECK:
1919
* readReservedFile
2020
* exports.readReservedFile,
2121
* exports.readDefaultReservedFile,
22-
* exports.readNameCache,
23-
* exports.writeNameCache
2422
* exports.simple_glob

build/jslib/x.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ var requirejs, require, define, xpcUtil;
419419
} else if (commandOption === 'v') {
420420
console.log('r.js: ' + version +
421421
', RequireJS: ' + this.requirejsVars.require.version +
422-
', UglifyJS: 2.7.3');
422+
', UglifyJS: 2.7.4');
423423
} else if (commandOption === 'convert') {
424424
loadLib();
425425

build/tests/builds.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2853,4 +2853,21 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan
28532853
);
28542854
doh.run();
28552855

2856+
//Support mangleProperties in uglify config.
2857+
//See https://github.com/requirejs/r.js/issues/943
2858+
doh.register("uglifyMangleProperties",
2859+
[
2860+
function writeBundlesConfig(t) {
2861+
file.deleteFile("lib/uglifyMangleProperties/main-built.js");
2862+
2863+
build(["lib/uglifyMangleProperties/build.js"]);
2864+
2865+
t.is(nol(c("lib/uglifyMangleProperties/expected.js")),
2866+
nol(c("lib/uglifyMangleProperties/main-built.js")));
2867+
require._buildReset();
2868+
}
2869+
2870+
]
2871+
);
2872+
doh.run();
28562873
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
define({
2+
name: 'a',
3+
something: 'else'
4+
});
5+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
name: 'main',
3+
out: 'main-built.js',
4+
uglify: {
5+
mangleProperties: {
6+
regex: /something/
7+
}
8+
}
9+
}
10+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
define("a",{name:"a",a:"else"}),define("main",["a"],function(e){console.log(e)});
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
define(['a'], function(a) {
2+
console.log(a);
3+
});
4+

0 commit comments

Comments
 (0)