@@ -116,6 +116,8 @@ function merge(obj, ext) {
116
116
} ;
117
117
118
118
function noop ( ) { } ;
119
+ function return_false ( ) { return false ; }
120
+ function return_true ( ) { return true ; }
119
121
120
122
var MAP = ( function ( ) {
121
123
function MAP ( a , f , backwards ) {
@@ -3830,6 +3832,20 @@ AST_Toplevel.DEFMETHOD("scope_warnings", function(options){
3830
3832
3831
3833
var EXPECT_DIRECTIVE = / ^ $ | [ ; { ] [ \s \n ] * $ / ;
3832
3834
3835
+ function is_some_comments ( comment ) {
3836
+ var text = comment . value ;
3837
+ var type = comment . type ;
3838
+ if ( type == "comment2" ) {
3839
+ // multiline comment
3840
+ return / @ p r e s e r v e | @ l i c e n s e | @ c c _ o n / i. test ( text ) ;
3841
+ }
3842
+ return type == "comment5" ;
3843
+ }
3844
+
3845
+ function is_comment5 ( comment ) {
3846
+ return comment . type == "comment5" ;
3847
+ }
3848
+
3833
3849
function OutputStream ( options ) {
3834
3850
3835
3851
options = defaults ( options , {
@@ -3853,50 +3869,34 @@ function OutputStream(options) {
3853
3869
preamble : null ,
3854
3870
quote_style : 0 ,
3855
3871
keep_quoted_props : false ,
3856
- wrap_iife : false
3872
+ wrap_iife : false ,
3857
3873
} , true ) ;
3858
3874
3859
3875
// 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" ;
3876
+ var comment_filter = options . shebang ? is_comment5 : return_false ; // Default case, throw all comments away except shebangs
3877
+ if ( options . comments ) {
3878
+ var comments = options . comments ;
3879
+ if ( typeof options . comments === "string" && / ^ \/ .* \/ [ a - z A - Z ] * $ / . test ( options . comments ) ) {
3880
+ var regex_pos = options . comments . lastIndexOf ( "/" ) ;
3881
+ comments = new RegExp (
3882
+ options . comments . substr ( 1 , regex_pos - 1 ) ,
3883
+ options . comments . substr ( regex_pos + 1 )
3884
+ ) ;
3890
3885
}
3891
- }
3892
- else if ( options . comments ) { // NOTE includes "all" option
3893
- options . comments = function ( ) {
3894
- return true ;
3886
+ if ( comments instanceof RegExp ) {
3887
+ comment_filter = function ( comment ) {
3888
+ return comment . type == "comment5" || comments . test ( comment . value ) ;
3889
+ } ;
3895
3890
}
3896
- } else {
3897
- // Falsy case, so reject all comments, except shebangs
3898
- options . comments = function ( comment ) {
3899
- return comment . type == "comment5" ;
3891
+ else if ( typeof comments === "function" ) {
3892
+ comment_filter = function ( comment ) {
3893
+ return comment . type == "comment5" || comments ( this , comment ) ;
3894
+ } ;
3895
+ }
3896
+ else if ( comments === "some" ) {
3897
+ comment_filter = is_some_comments ;
3898
+ } else { // NOTE includes "all" option
3899
+ comment_filter = return_true ;
3900
3900
}
3901
3901
}
3902
3902
@@ -4206,6 +4206,7 @@ function OutputStream(options) {
4206
4206
with_square : with_square ,
4207
4207
add_mapping : add_mapping ,
4208
4208
option : function ( opt ) { return options [ opt ] } ,
4209
+ comment_filter : comment_filter ,
4209
4210
line : function ( ) { return current_line } ,
4210
4211
col : function ( ) { return current_col } ,
4211
4212
pos : function ( ) { return current_pos } ,
@@ -4288,7 +4289,7 @@ function OutputStream(options) {
4288
4289
} ) ) ;
4289
4290
}
4290
4291
4291
- comments = comments . filter ( output . option ( "comments" ) , self ) ;
4292
+ comments = comments . filter ( output . comment_filter , self ) ;
4292
4293
4293
4294
// Keep single line comments after nlb, after nlb
4294
4295
if ( ! output . option ( "beautify" ) && comments . length > 0 &&
@@ -6161,7 +6162,7 @@ merge(Compressor.prototype, {
6161
6162
( function ( def ) {
6162
6163
var unary_bool = [ "!" , "delete" ] ;
6163
6164
var binary_bool = [ "in" , "instanceof" , "==" , "!=" , "===" , "!==" , "<" , "<=" , ">=" , ">" ] ;
6164
- def ( AST_Node , function ( ) { return false } ) ;
6165
+ def ( AST_Node , return_false ) ;
6165
6166
def ( AST_UnaryPrefix , function ( ) {
6166
6167
return member ( this . operator , unary_bool ) ;
6167
6168
} ) ;
@@ -6179,16 +6180,16 @@ merge(Compressor.prototype, {
6179
6180
def ( AST_Seq , function ( ) {
6180
6181
return this . cdr . is_boolean ( ) ;
6181
6182
} ) ;
6182
- def ( AST_True , function ( ) { return true } ) ;
6183
- def ( AST_False , function ( ) { return true } ) ;
6183
+ def ( AST_True , return_true ) ;
6184
+ def ( AST_False , return_true ) ;
6184
6185
} ) ( function ( node , func ) {
6185
6186
node . DEFMETHOD ( "is_boolean" , func ) ;
6186
6187
} ) ;
6187
6188
6188
6189
// methods to determine if an expression has a string result type
6189
6190
( function ( def ) {
6190
- def ( AST_Node , function ( ) { return false } ) ;
6191
- def ( AST_String , function ( ) { return true } ) ;
6191
+ def ( AST_Node , return_false ) ;
6192
+ def ( AST_String , return_true ) ;
6192
6193
def ( AST_UnaryPrefix , function ( ) {
6193
6194
return this . operator == "typeof" ;
6194
6195
} ) ;
@@ -6442,11 +6443,11 @@ merge(Compressor.prototype, {
6442
6443
6443
6444
// determine if expression has side effects
6444
6445
( function ( def ) {
6445
- def ( AST_Node , function ( compressor ) { return true } ) ;
6446
+ def ( AST_Node , return_true ) ;
6446
6447
6447
- def ( AST_EmptyStatement , function ( compressor ) { return false } ) ;
6448
- def ( AST_Constant , function ( compressor ) { return false } ) ;
6449
- def ( AST_This , function ( compressor ) { return false } ) ;
6448
+ def ( AST_EmptyStatement , return_false ) ;
6449
+ def ( AST_Constant , return_false ) ;
6450
+ def ( AST_This , return_false ) ;
6450
6451
6451
6452
def ( AST_Call , function ( compressor ) {
6452
6453
var pure = compressor . option ( "pure_funcs" ) ;
@@ -6466,13 +6467,13 @@ merge(Compressor.prototype, {
6466
6467
def ( AST_SimpleStatement , function ( compressor ) {
6467
6468
return this . body . has_side_effects ( compressor ) ;
6468
6469
} ) ;
6469
- def ( AST_Defun , function ( compressor ) { return true } ) ;
6470
- def ( AST_Function , function ( compressor ) { return false } ) ;
6470
+ def ( AST_Defun , return_true ) ;
6471
+ def ( AST_Function , return_false ) ;
6471
6472
def ( AST_Binary , function ( compressor ) {
6472
6473
return this . left . has_side_effects ( compressor )
6473
6474
|| this . right . has_side_effects ( compressor ) ;
6474
6475
} ) ;
6475
- def ( AST_Assign , function ( compressor ) { return true } ) ;
6476
+ def ( AST_Assign , return_true ) ;
6476
6477
def ( AST_Conditional , function ( compressor ) {
6477
6478
return this . condition . has_side_effects ( compressor )
6478
6479
|| this . consequent . has_side_effects ( compressor )
@@ -8235,7 +8236,7 @@ function SourceMap(options) {
8235
8236
var orig_map = options . orig && new MOZ_SourceMap . SourceMapConsumer ( options . orig ) ;
8236
8237
8237
8238
if ( orig_map && Array . isArray ( options . orig . sources ) ) {
8238
- options . orig . sources . forEach ( function ( source ) {
8239
+ orig_map . _sources . toArray ( ) . forEach ( function ( source ) {
8239
8240
var sourceContent = orig_map . sourceContentFor ( source , true ) ;
8240
8241
if ( sourceContent ) {
8241
8242
generator . setSourceContent ( source , sourceContent ) ;
@@ -8949,7 +8950,8 @@ function mangle_properties(ast, options) {
8949
8950
cache : null ,
8950
8951
only_cache : false ,
8951
8952
regex : null ,
8952
- ignore_quoted : false
8953
+ ignore_quoted : false ,
8954
+ debug : false
8953
8955
} ) ;
8954
8956
8955
8957
var reserved = options . reserved ;
@@ -8967,6 +8969,15 @@ function mangle_properties(ast, options) {
8967
8969
var regex = options . regex ;
8968
8970
var ignore_quoted = options . ignore_quoted ;
8969
8971
8972
+ // note debug is either false (disabled), or a string of the debug suffix to use (enabled).
8973
+ // note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
8974
+ // the same as passing an empty string.
8975
+ var debug = ( options . debug !== false ) ;
8976
+ var debug_name_suffix ;
8977
+ if ( debug ) {
8978
+ debug_name_suffix = ( options . debug === true ? "" : options . debug ) ;
8979
+ }
8980
+
8970
8981
var names_to_mangle = [ ] ;
8971
8982
var unmangleable = [ ] ;
8972
8983
var ignored = { } ;
@@ -9060,9 +9071,25 @@ function mangle_properties(ast, options) {
9060
9071
9061
9072
var mangled = cache . props . get ( name ) ;
9062
9073
if ( ! mangled ) {
9063
- do {
9064
- mangled = base54 ( ++ cache . cname ) ;
9065
- } while ( ! can_mangle ( mangled ) ) ;
9074
+ if ( debug ) {
9075
+ // debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
9076
+ var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_" ;
9077
+
9078
+ if ( can_mangle ( debug_mangled ) && ! ( ignore_quoted && debug_mangled in ignored ) ) {
9079
+ mangled = debug_mangled ;
9080
+ }
9081
+ }
9082
+
9083
+ // either debug mode is off, or it is on and we could not use the mangled name
9084
+ if ( ! mangled ) {
9085
+ // note can_mangle() does not check if the name collides with the 'ignored' set
9086
+ // (filled with quoted properties when ignore_quoted set). Make sure we add this
9087
+ // check so we don't collide with a quoted name.
9088
+ do {
9089
+ mangled = base54 ( ++ cache . cname ) ;
9090
+ } while ( ! can_mangle ( mangled ) || ( ignore_quoted && mangled in ignored ) ) ;
9091
+ }
9092
+
9066
9093
cache . props . set ( name , mangled ) ;
9067
9094
}
9068
9095
return mangled ;
@@ -9117,6 +9144,7 @@ exports.minify = function(files, options, name) {
9117
9144
options = defaults ( options , {
9118
9145
spidermonkey : false ,
9119
9146
outSourceMap : null ,
9147
+ outFileName : null ,
9120
9148
sourceRoot : null ,
9121
9149
inSourceMap : null ,
9122
9150
sourceMapUrl : null ,
@@ -9196,7 +9224,8 @@ exports.minify = function(files, options, name) {
9196
9224
}
9197
9225
if ( options . outSourceMap || options . sourceMapInline ) {
9198
9226
output . source_map = SourceMap ( {
9199
- file : options . outSourceMap ,
9227
+ // prefer outFileName, otherwise use outSourceMap without .map suffix
9228
+ file : options . outFileName || ( typeof options . outSourceMap === 'string' ? options . outSourceMap . replace ( / \. m a p $ / i, '' ) : null ) ,
9200
9229
orig : inMap ,
9201
9230
root : options . sourceRoot
9202
9231
} ) ;
@@ -9283,7 +9312,7 @@ exports.describe_ast = function() {
9283
9312
return out + "" ;
9284
9313
} ;
9285
9314
9286
- exports . readNameCache = function ( filename , key ) {
9315
+ var readNameCache = function ( filename , key ) {
9287
9316
var cache = null ;
9288
9317
if ( filename ) {
9289
9318
try {
@@ -9300,9 +9329,8 @@ exports.readNameCache = function(filename, key) {
9300
9329
}
9301
9330
return cache ;
9302
9331
} ;
9303
- var readNameCache = exports . readNameCache ;
9304
9332
9305
- exports . writeNameCache = function ( filename , key , cache ) {
9333
+ var writeNameCache = function ( filename , key , cache ) {
9306
9334
if ( filename ) {
9307
9335
var data ;
9308
9336
try {
@@ -9318,7 +9346,6 @@ exports.writeNameCache = function(filename, key, cache) {
9318
9346
fs . writeFileSync ( filename , JSON . stringify ( data , null , 2 ) , "utf8" ) ;
9319
9347
}
9320
9348
} ;
9321
- var writeNameCache = exports . writeNameCache ;
9322
9349
9323
9350
9324
9351
} ) ;
0 commit comments