@@ -3337,12 +3337,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
3337
3337
}
3338
3338
if ( node instanceof AST_SymbolRef ) {
3339
3339
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 ) {
3341
3342
for ( var s = node . scope ; s && ! s . uses_eval ; s = s . parent_scope ) {
3342
3343
s . uses_eval = true ;
3343
3344
}
3344
3345
}
3345
3346
var sym = node . scope . find_variable ( name ) ;
3347
+ if ( node . scope instanceof AST_Lambda && name == "arguments" ) {
3348
+ node . scope . uses_arguments = true ;
3349
+ }
3346
3350
if ( ! sym ) {
3347
3351
var g ;
3348
3352
if ( globals . has ( name ) ) {
@@ -3353,12 +3357,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
3353
3357
g . global = true ;
3354
3358
globals . set ( name , g ) ;
3355
3359
}
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 ;
3362
3366
}
3363
3367
node . reference ( ) ;
3364
3368
return true ;
@@ -3848,9 +3852,54 @@ function OutputStream(options) {
3848
3852
screw_ie8 : true ,
3849
3853
preamble : null ,
3850
3854
quote_style : 0 ,
3851
- keep_quoted_props : false
3855
+ keep_quoted_props : false ,
3856
+ wrap_iife : false
3852
3857
} , true ) ;
3853
3858
3859
+ // Convert comment option to RegExp if neccessary and set up comments filter
3860
+ if ( typeof options . comments === "string" && / ^ \/ .* \/ [ a - z A - 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 / @ p r e s e r v e | @ l i c e n s e | @ c c _ o n / 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
+
3854
3903
var indentation = 0 ;
3855
3904
var current_col = 0 ;
3856
3905
var current_line = 1 ;
@@ -4216,7 +4265,7 @@ function OutputStream(options) {
4216
4265
4217
4266
AST_Node . DEFMETHOD ( "add_comments" , function ( output ) {
4218
4267
if ( output . _readonly ) return ;
4219
- var c = output . option ( "comments" ) , self = this ;
4268
+ var self = this ;
4220
4269
var start = self . start ;
4221
4270
if ( start && ! start . _comments_dumped ) {
4222
4271
start . _comments_dumped = true ;
@@ -4239,19 +4288,7 @@ function OutputStream(options) {
4239
4288
} ) ) ;
4240
4289
}
4241
4290
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 ) ;
4255
4292
4256
4293
// Keep single line comments after nlb, after nlb
4257
4294
if ( ! output . option ( "beautify" ) && comments . length > 0 &&
@@ -4302,7 +4339,16 @@ function OutputStream(options) {
4302
4339
// a function expression needs parens around it when it's provably
4303
4340
// the first token to appear in a statement.
4304
4341
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 ;
4306
4352
} ) ;
4307
4353
4308
4354
// same goes for an object literal, because otherwise it would be
@@ -5266,6 +5312,7 @@ function Compressor(options, false_by_default) {
5266
5312
if_return : ! false_by_default ,
5267
5313
join_vars : ! false_by_default ,
5268
5314
collapse_vars : false ,
5315
+ reduce_vars : false ,
5269
5316
cascade : ! false_by_default ,
5270
5317
side_effects : ! false_by_default ,
5271
5318
pure_getters : false ,
@@ -6306,7 +6353,7 @@ merge(Compressor.prototype, {
6306
6353
this . _evaluating = true ;
6307
6354
try {
6308
6355
var d = this . definition ( ) ;
6309
- if ( d && d . constant && d . init ) {
6356
+ if ( d && ( d . constant || compressor . option ( "reduce_vars" ) && ! d . modified ) && d . init ) {
6310
6357
return ev ( d . init , compressor ) ;
6311
6358
}
6312
6359
} finally {
@@ -7512,6 +7559,12 @@ merge(Compressor.prototype, {
7512
7559
// typeof always returns a non-empty string, thus it's
7513
7560
// always true in booleans
7514
7561
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
+ }
7515
7568
return make_node ( AST_True , self ) ;
7516
7569
}
7517
7570
if ( e instanceof AST_Binary && self . operator == "!" ) {
@@ -7698,8 +7751,8 @@ merge(Compressor.prototype, {
7698
7751
case "+" :
7699
7752
var ll = self . left . evaluate ( compressor ) ;
7700
7753
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 ) ) ) {
7703
7756
compressor . warn ( "+ in boolean context always true [{file}:{line},{col}]" , self . start ) ;
7704
7757
return make_node ( AST_True , self ) ;
7705
7758
}
@@ -7854,16 +7907,26 @@ merge(Compressor.prototype, {
7854
7907
} ) ;
7855
7908
7856
7909
var ASSIGN_OPS = [ '+' , '-' , '/' , '*' , '%' , '>>' , '<<' , '>>>' , '|' , '^' , '&' ] ;
7910
+ var ASSIGN_OPS_COMMUTATIVE = [ '*' , '|' , '^' , '&' ] ;
7857
7911
OPT ( AST_Assign , function ( self , compressor ) {
7858
7912
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
+ }
7867
7930
}
7868
7931
return self ;
7869
7932
} ) ;
@@ -9057,6 +9120,7 @@ exports.minify = function(files, options, name) {
9057
9120
sourceRoot : null ,
9058
9121
inSourceMap : null ,
9059
9122
sourceMapUrl : null ,
9123
+ sourceMapInline : false ,
9060
9124
fromString : false ,
9061
9125
warnings : false ,
9062
9126
mangle : { } ,
@@ -9130,7 +9194,7 @@ exports.minify = function(files, options, name) {
9130
9194
if ( typeof options . inSourceMap == "string" ) {
9131
9195
inMap = JSON . parse ( rjsFile . readFile ( options . inSourceMap , "utf8" ) ) ;
9132
9196
}
9133
- if ( options . outSourceMap ) {
9197
+ if ( options . outSourceMap || options . sourceMapInline ) {
9134
9198
output . source_map = SourceMap ( {
9135
9199
file : options . outSourceMap ,
9136
9200
orig : inMap ,
@@ -9151,16 +9215,19 @@ exports.minify = function(files, options, name) {
9151
9215
var stream = OutputStream ( output ) ;
9152
9216
toplevel . print ( stream ) ;
9153
9217
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
- }
9158
9218
9159
9219
var source_map = output . source_map ;
9160
9220
if ( source_map ) {
9161
9221
source_map = source_map + "" ;
9162
9222
}
9163
9223
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
+
9164
9231
return {
9165
9232
code : stream + "" ,
9166
9233
map : source_map
@@ -9216,4 +9283,42 @@ exports.describe_ast = function() {
9216
9283
return out + "" ;
9217
9284
} ;
9218
9285
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
+
9219
9324
} ) ;
0 commit comments