uglifier 0.5.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of uglifier might be problematic. Click here for more details.
- data/.gitmodules +1 -1
- data/.travis.yml +5 -0
- data/Gemfile +16 -7
- data/LICENSE.txt +1 -1
- data/README.rdoc +18 -7
- data/VERSION +1 -1
- data/lib/uglifier.rb +34 -5
- data/lib/uglify.js +102 -52
- data/spec/spec_helper.rb +1 -0
- data/spec/uglifier_spec.rb +23 -3
- data/uglifier.gemspec +10 -13
- metadata +33 -33
data/.gitmodules
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,16 +1,25 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
|
-
# Add dependencies required to use your gem here.
|
3
|
-
# Example:
|
4
|
-
# gem "activesupport", ">= 2.3.5"
|
5
2
|
|
6
3
|
gem "execjs", ">=0.3.0"
|
7
4
|
gem "multi_json", ">= 1.0.2"
|
8
5
|
|
9
|
-
#
|
10
|
-
|
6
|
+
# Depend on defined ExecJS runtime
|
7
|
+
execjs_runtimes = {
|
8
|
+
"RubyRacer" => "therubyracer",
|
9
|
+
"RubyRhino" => "therubyrhino",
|
10
|
+
"Mustang" => "mustang"
|
11
|
+
}
|
12
|
+
|
13
|
+
if ENV["EXECJS_RUNTIME"] && execjs_runtimes[ENV["EXECJS_RUNTIME"]]
|
14
|
+
gem execjs_runtimes[ENV["EXECJS_RUNTIME"]], :group => :development
|
15
|
+
end
|
16
|
+
|
17
|
+
# Engine
|
18
|
+
gem ENV["MULTI_JSON_ENGINE"], :group => :development if ENV["MULTI_JSON_ENGINE"]
|
19
|
+
|
11
20
|
group :development do
|
12
|
-
gem "rspec", "~> 2.
|
21
|
+
gem "rspec", "~> 2.6.0"
|
13
22
|
gem "bundler", "~> 1.0.0"
|
14
|
-
gem "jeweler", "~> 1.
|
23
|
+
gem "jeweler", "~> 1.6.0"
|
15
24
|
gem "rcov", ">= 0"
|
16
25
|
end
|
data/LICENSE.txt
CHANGED
data/README.rdoc
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
Ruby wrapper for UglifyJS[https://github.com/mishoo/UglifyJS] JavaScript compressor.
|
4
4
|
|
5
|
+
http://travis-ci.org/lautis/uglifier.png
|
6
|
+
|
5
7
|
== Installation
|
6
8
|
|
7
9
|
Uglifier is available as ruby gem.
|
@@ -17,27 +19,41 @@ Ensure that your environment has a JavaScript interpreter supported by ExecJS[ht
|
|
17
19
|
Uglifier.new.compile(File.read("source.js"))
|
18
20
|
# => js file minified
|
19
21
|
|
22
|
+
# Or alternatively
|
23
|
+
Uglifier.compile(File.read("source.js"))
|
24
|
+
|
20
25
|
When initializing UglifyJS, you can tune the behavior of UglifyJS by passing options. For example, if you want top-level variable names to be mangled:
|
21
26
|
|
22
27
|
Uglifier.new(:toplevel => true).compile(source)
|
23
28
|
|
24
|
-
|
29
|
+
# Or
|
30
|
+
Uglifier.compile(source, :toplevel => true)
|
25
31
|
|
32
|
+
Available options and their defaults are
|
26
33
|
{
|
27
34
|
:mangle => true, # Mangle variables names
|
28
35
|
:toplevel => false, # Mangle top-level variable names
|
36
|
+
:except => [], # Variable names to be excluded from mangling
|
37
|
+
:max_line_length => 32 * 1024, # Maximum line length
|
29
38
|
:squeeze => true, # Squeeze code resulting in smaller, but less-readable code
|
30
39
|
:seqs => true, # Reduce consecutive statements in blocks into single statement
|
31
40
|
:dead_code => true, # Remove dead code (e.g. after return)
|
41
|
+
:unsafe => false, # Optimizations known to be unsafe in some situations
|
42
|
+
:copyright => true, # Show copyright message
|
32
43
|
:beautify => false, # Ouput indented code
|
33
44
|
:beautify_options => {
|
34
45
|
:indent_level => 4,
|
35
46
|
:indent_start => 0,
|
36
47
|
:quote_keys => false,
|
37
|
-
:space_colon => 0
|
48
|
+
:space_colon => 0,
|
49
|
+
:ascii_only => false
|
38
50
|
}
|
39
51
|
}
|
40
52
|
|
53
|
+
== Submitting an issue
|
54
|
+
|
55
|
+
Uglifier uses the {GitHub issue tracker}[https://github.com/lautis/uglifier/issues] to track bugs and features. Before submitting a bug report or feature request, check to make sure it hasn't already been submitted. You can indicate support for an existing issuse by voting it up. When submitting a bug report, please include a Gist that includes a stack trace and any details that may be necessary to reproduce the bug, including your gem version, Ruby version, <b>MultiJSON engine</b> and <b>ExecJS runtime</b>. Ideally, a bug report should include a pull request with failing specs.
|
56
|
+
|
41
57
|
== Contributing to uglifier
|
42
58
|
|
43
59
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
@@ -47,8 +63,3 @@ Defaults are
|
|
47
63
|
* Commit and push until you are happy with your contribution
|
48
64
|
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
49
65
|
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
50
|
-
|
51
|
-
== Copyright
|
52
|
-
|
53
|
-
Copyright (c) 2010 Ville Lautanala. See LICENSE.txt for
|
54
|
-
further details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
data/lib/uglifier.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
require "execjs"
|
2
4
|
require "multi_json"
|
3
5
|
|
@@ -5,9 +7,12 @@ class Uglifier
|
|
5
7
|
Error = ExecJS::Error
|
6
8
|
# MultiJson.engine = :json_gem
|
7
9
|
|
10
|
+
# Default options for compilation
|
8
11
|
DEFAULTS = {
|
9
12
|
:mangle => true, # Mangle variables names
|
10
13
|
:toplevel => false, # Mangle top-level variable names
|
14
|
+
:except => [], # Variable names to be excluded from mangling
|
15
|
+
:max_line_length => 32 * 1024, # Maximum line length
|
11
16
|
:squeeze => true, # Squeeze code resulting in smaller, but less-readable code
|
12
17
|
:seqs => true, # Reduce consecutive statements in blocks into single statement
|
13
18
|
:dead_code => true, # Remove dead code (e.g. after return)
|
@@ -18,23 +23,37 @@ class Uglifier
|
|
18
23
|
:indent_level => 4,
|
19
24
|
:indent_start => 0,
|
20
25
|
:quote_keys => false,
|
21
|
-
:space_colon => 0
|
26
|
+
:space_colon => 0,
|
27
|
+
:ascii_only => false
|
22
28
|
}
|
23
29
|
}
|
24
30
|
|
25
31
|
SourcePath = File.expand_path("../uglify.js", __FILE__)
|
26
32
|
ES5FallbackPath = File.expand_path("../es5.js", __FILE__)
|
27
33
|
|
34
|
+
# Minifies JavaScript code using implicit context.
|
35
|
+
#
|
36
|
+
# source should be a String or IO object containing valid JavaScript.
|
37
|
+
# options contain optional overrides to Uglifier::DEFAULTS
|
38
|
+
#
|
39
|
+
# Returns minified code as String
|
28
40
|
def self.compile(source, options = {})
|
29
41
|
self.new(options).compile(source)
|
30
42
|
end
|
31
43
|
|
32
|
-
#
|
44
|
+
# Initialize new context for Uglifier with given options
|
45
|
+
#
|
46
|
+
# options - Hash of options to override Uglifier::DEFAULTS
|
33
47
|
def initialize(options = {})
|
34
48
|
@options = DEFAULTS.merge(options)
|
35
|
-
@context = ExecJS.compile(File.
|
49
|
+
@context = ExecJS.compile(File.open(ES5FallbackPath, "r:UTF-8").read + File.open(SourcePath, "r:UTF-8").read)
|
36
50
|
end
|
37
51
|
|
52
|
+
# Minifies JavaScript code
|
53
|
+
#
|
54
|
+
# source should be a String or IO object containing valid JavaScript.
|
55
|
+
#
|
56
|
+
# Returns minified code as String
|
38
57
|
def compile(source)
|
39
58
|
source = source.respond_to?(:read) ? source.read : source.to_s
|
40
59
|
|
@@ -66,6 +85,11 @@ class Uglifier
|
|
66
85
|
end
|
67
86
|
|
68
87
|
js << "result += UglifyJS.uglify.gen_code(ast, #{MultiJson.encode(gen_code_options)});"
|
88
|
+
|
89
|
+
if !@options[:beautify] && @options[:max_line_length]
|
90
|
+
js << "result = UglifyJS.uglify.split_lines(result, #{@options[:max_line_length].to_i})"
|
91
|
+
end
|
92
|
+
|
69
93
|
js << "return result;"
|
70
94
|
|
71
95
|
@context.exec js.join("\n")
|
@@ -75,7 +99,11 @@ class Uglifier
|
|
75
99
|
private
|
76
100
|
|
77
101
|
def mangle_options
|
78
|
-
|
102
|
+
{
|
103
|
+
"toplevel" => @options[:toplevel],
|
104
|
+
"defines" => {},
|
105
|
+
"except" => @options[:except]
|
106
|
+
}
|
79
107
|
end
|
80
108
|
|
81
109
|
def squeeze_options
|
@@ -87,6 +115,7 @@ class Uglifier
|
|
87
115
|
end
|
88
116
|
|
89
117
|
def gen_code_options
|
90
|
-
|
118
|
+
|
119
|
+
@options[:beautify] ? {:beautify => true}.merge(@options[:beautify_options]) : {}
|
91
120
|
end
|
92
121
|
end
|
data/lib/uglify.js
CHANGED
@@ -48,8 +48,7 @@
|
|
48
48
|
};
|
49
49
|
}
|
50
50
|
return this.require.define;
|
51
|
-
}).call(this)({"parse-js": function(exports, require, module) {
|
52
|
-
/***********************************************************************
|
51
|
+
}).call(this)({"parse-js": function(exports, require, module) {/***********************************************************************
|
53
52
|
|
54
53
|
A JavaScript tokenizer / parser / beautifier / compressor.
|
55
54
|
|
@@ -240,7 +239,7 @@ var OPERATORS = array_to_hash([
|
|
240
239
|
"||"
|
241
240
|
]);
|
242
241
|
|
243
|
-
var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t\u200b"));
|
242
|
+
var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\v\u200b"));
|
244
243
|
|
245
244
|
var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:"));
|
246
245
|
|
@@ -802,14 +801,17 @@ function parse($TEXT, exigent_mode, embed_tokens) {
|
|
802
801
|
return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end);
|
803
802
|
};
|
804
803
|
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
804
|
+
function maybe_embed_tokens(parser) {
|
805
|
+
if (embed_tokens) return function() {
|
806
|
+
var start = S.token;
|
807
|
+
var ast = parser.apply(this, arguments);
|
808
|
+
ast[0] = add_tokens(ast[0], start, prev());
|
809
|
+
return ast;
|
810
|
+
};
|
811
|
+
else return parser;
|
812
|
+
};
|
811
813
|
|
812
|
-
|
814
|
+
var statement = maybe_embed_tokens(function() {
|
813
815
|
if (is("operator", "/")) {
|
814
816
|
S.peeked = null;
|
815
817
|
S.token = S.input(true); // force regexp
|
@@ -903,7 +905,7 @@ function parse($TEXT, exigent_mode, embed_tokens) {
|
|
903
905
|
unexpected();
|
904
906
|
}
|
905
907
|
}
|
906
|
-
};
|
908
|
+
});
|
907
909
|
|
908
910
|
function labeled_statement(label) {
|
909
911
|
S.labels.push(label);
|
@@ -919,7 +921,10 @@ function parse($TEXT, exigent_mode, embed_tokens) {
|
|
919
921
|
};
|
920
922
|
|
921
923
|
function break_cont(type) {
|
922
|
-
var name
|
924
|
+
var name;
|
925
|
+
if (!can_insert_semicolon()) {
|
926
|
+
name = is("name") ? S.token.value : null;
|
927
|
+
}
|
923
928
|
if (name != null) {
|
924
929
|
next();
|
925
930
|
if (!member(name, S.labels))
|
@@ -961,14 +966,7 @@ function parse($TEXT, exigent_mode, embed_tokens) {
|
|
961
966
|
return as("for-in", init, lhs, obj, in_loop(statement));
|
962
967
|
};
|
963
968
|
|
964
|
-
var function_ =
|
965
|
-
var start = prev();
|
966
|
-
var ast = $function_.apply(this, arguments);
|
967
|
-
ast[0] = add_tokens(ast[0], start, prev());
|
968
|
-
return ast;
|
969
|
-
} : $function_;
|
970
|
-
|
971
|
-
function $function_(in_statement) {
|
969
|
+
var function_ = maybe_embed_tokens(function(in_statement) {
|
972
970
|
var name = is("name") ? prog1(S.token.value, next) : null;
|
973
971
|
if (in_statement && !name)
|
974
972
|
unexpected();
|
@@ -996,7 +994,7 @@ function parse($TEXT, exigent_mode, embed_tokens) {
|
|
996
994
|
S.in_loop = loop;
|
997
995
|
return a;
|
998
996
|
})());
|
999
|
-
};
|
997
|
+
});
|
1000
998
|
|
1001
999
|
function if_() {
|
1002
1000
|
var cond = parenthesised(), body = statement(), belse;
|
@@ -1104,7 +1102,7 @@ function parse($TEXT, exigent_mode, embed_tokens) {
|
|
1104
1102
|
return subscripts(as("new", newexp, args), true);
|
1105
1103
|
};
|
1106
1104
|
|
1107
|
-
|
1105
|
+
var expr_atom = maybe_embed_tokens(function(allow_calls) {
|
1108
1106
|
if (is("operator", "new")) {
|
1109
1107
|
next();
|
1110
1108
|
return new_();
|
@@ -1139,7 +1137,7 @@ function parse($TEXT, exigent_mode, embed_tokens) {
|
|
1139
1137
|
return subscripts(prog1(atom, next), allow_calls);
|
1140
1138
|
}
|
1141
1139
|
unexpected();
|
1142
|
-
};
|
1140
|
+
});
|
1143
1141
|
|
1144
1142
|
function expr_list(closing, allow_trailing_comma, allow_empty) {
|
1145
1143
|
var first = true, a = [];
|
@@ -1279,7 +1277,7 @@ function parse($TEXT, exigent_mode, embed_tokens) {
|
|
1279
1277
|
return left;
|
1280
1278
|
};
|
1281
1279
|
|
1282
|
-
|
1280
|
+
var expression = maybe_embed_tokens(function(commas, no_in) {
|
1283
1281
|
if (arguments.length == 0)
|
1284
1282
|
commas = true;
|
1285
1283
|
var expr = maybe_assign(no_in);
|
@@ -1288,7 +1286,7 @@ function parse($TEXT, exigent_mode, embed_tokens) {
|
|
1288
1286
|
return as("seq", expr, expression(true, no_in));
|
1289
1287
|
}
|
1290
1288
|
return expr;
|
1291
|
-
};
|
1289
|
+
});
|
1292
1290
|
|
1293
1291
|
function in_loop(cont) {
|
1294
1292
|
try {
|
@@ -1445,6 +1443,12 @@ function ast_walker(ast) {
|
|
1445
1443
|
return a;
|
1446
1444
|
}) ];
|
1447
1445
|
};
|
1446
|
+
function _block(statements) {
|
1447
|
+
var out = [ this[0] ];
|
1448
|
+
if (statements != null)
|
1449
|
+
out.push(MAP(statements, walk));
|
1450
|
+
return out;
|
1451
|
+
};
|
1448
1452
|
var walkers = {
|
1449
1453
|
"string": function(str) {
|
1450
1454
|
return [ this[0], str ];
|
@@ -1458,12 +1462,8 @@ function ast_walker(ast) {
|
|
1458
1462
|
"toplevel": function(statements) {
|
1459
1463
|
return [ this[0], MAP(statements, walk) ];
|
1460
1464
|
},
|
1461
|
-
"block":
|
1462
|
-
|
1463
|
-
if (statements != null)
|
1464
|
-
out.push(MAP(statements, walk));
|
1465
|
-
return out;
|
1466
|
-
},
|
1465
|
+
"block": _block,
|
1466
|
+
"splice": _block,
|
1467
1467
|
"var": _vardefs,
|
1468
1468
|
"const": _vardefs,
|
1469
1469
|
"try": function(t, c, f) {
|
@@ -1747,7 +1747,9 @@ function ast_add_scope(ast) {
|
|
1747
1747
|
};
|
1748
1748
|
|
1749
1749
|
function _lambda(name, args, body) {
|
1750
|
-
|
1750
|
+
var is_defun = this[0] == "defun";
|
1751
|
+
return [ this[0], is_defun ? define(name) : name, args, with_new_scope(function(){
|
1752
|
+
if (!is_defun) define(name);
|
1751
1753
|
MAP(args, define);
|
1752
1754
|
return MAP(body, walk);
|
1753
1755
|
})];
|
@@ -1833,9 +1835,24 @@ function ast_mangle(ast, options) {
|
|
1833
1835
|
return scope.get_mangled(name, newMangle);
|
1834
1836
|
};
|
1835
1837
|
|
1838
|
+
function get_define(name) {
|
1839
|
+
if (options.defines) {
|
1840
|
+
// we always lookup a defined symbol for the current scope FIRST, so declared
|
1841
|
+
// vars trump a DEFINE symbol, but if no such var is found, then match a DEFINE value
|
1842
|
+
if (!scope.has(name)) {
|
1843
|
+
if (HOP(options.defines, name)) {
|
1844
|
+
return options.defines[name];
|
1845
|
+
}
|
1846
|
+
}
|
1847
|
+
return null;
|
1848
|
+
}
|
1849
|
+
};
|
1850
|
+
|
1836
1851
|
function _lambda(name, args, body) {
|
1837
|
-
|
1852
|
+
var is_defun = this[0] == "defun";
|
1853
|
+
if (is_defun && name) name = get_mangled(name);
|
1838
1854
|
body = with_scope(body.scope, function(){
|
1855
|
+
if (!is_defun && name) name = get_mangled(name);
|
1839
1856
|
args = MAP(args, function(name){ return get_mangled(name) });
|
1840
1857
|
return MAP(body, walk);
|
1841
1858
|
});
|
@@ -1877,7 +1894,7 @@ function ast_mangle(ast, options) {
|
|
1877
1894
|
"var": _vardefs,
|
1878
1895
|
"const": _vardefs,
|
1879
1896
|
"name": function(name) {
|
1880
|
-
return [ this[0], get_mangled(name) ];
|
1897
|
+
return get_define(name) || [ this[0], get_mangled(name) ];
|
1881
1898
|
},
|
1882
1899
|
"try": function(t, c, f) {
|
1883
1900
|
return [ this[0],
|
@@ -1953,11 +1970,18 @@ function boolean_expr(expr) {
|
|
1953
1970
|
};
|
1954
1971
|
|
1955
1972
|
function make_conditional(c, t, e) {
|
1973
|
+
var make_real_conditional = function() {
|
1956
1974
|
if (c[0] == "unary-prefix" && c[1] == "!") {
|
1957
|
-
|
1975
|
+
return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ];
|
1958
1976
|
} else {
|
1959
|
-
|
1977
|
+
return e ? [ "conditional", c, t, e ] : [ "binary", "&&", c, t ];
|
1960
1978
|
}
|
1979
|
+
};
|
1980
|
+
// shortcut the conditional if the expression has a constant value
|
1981
|
+
return when_constant(c, function(ast, val){
|
1982
|
+
warn_unreachable(val ? e : t);
|
1983
|
+
return (val ? t : e);
|
1984
|
+
}, make_real_conditional);
|
1961
1985
|
};
|
1962
1986
|
|
1963
1987
|
function empty(b) {
|
@@ -2046,6 +2070,18 @@ var when_constant = (function(){
|
|
2046
2070
|
|| (boolean_expr(expr[2]) && boolean_expr(expr[3])))) {
|
2047
2071
|
expr[1] = expr[1].substr(0, 2);
|
2048
2072
|
}
|
2073
|
+
else if (no && expr[0] == "binary"
|
2074
|
+
&& (expr[1] == "||" || expr[1] == "&&")) {
|
2075
|
+
// the whole expression is not constant but the lval may be...
|
2076
|
+
try {
|
2077
|
+
var lval = evaluate(expr[2]);
|
2078
|
+
expr = ((expr[1] == "&&" && (lval ? expr[3] : lval)) ||
|
2079
|
+
(expr[1] == "||" && (lval ? lval : expr[3])) ||
|
2080
|
+
expr);
|
2081
|
+
} catch(ex2) {
|
2082
|
+
// IGNORE... lval is not constant
|
2083
|
+
}
|
2084
|
+
}
|
2049
2085
|
return no ? no.call(expr, expr) : null;
|
2050
2086
|
}
|
2051
2087
|
else throw ex;
|
@@ -2121,9 +2157,14 @@ function ast_squeeze(ast, options) {
|
|
2121
2157
|
};
|
2122
2158
|
|
2123
2159
|
function _lambda(name, args, body) {
|
2124
|
-
|
2125
|
-
|
2126
|
-
|
2160
|
+
var is_defun = this[0] == "defun";
|
2161
|
+
body = with_scope(body.scope, function(){
|
2162
|
+
var ret = tighten(MAP(body, walk), "lambda");
|
2163
|
+
if (!is_defun && name && !HOP(scope.refs, name))
|
2164
|
+
name = null;
|
2165
|
+
return ret;
|
2166
|
+
});
|
2167
|
+
return [ this[0], name, args, body ];
|
2127
2168
|
};
|
2128
2169
|
|
2129
2170
|
// we get here for blocks that have been already transformed.
|
@@ -2329,13 +2370,7 @@ function ast_squeeze(ast, options) {
|
|
2329
2370
|
return [ branch[0] ? walk(branch[0]) : null, block ];
|
2330
2371
|
}) ];
|
2331
2372
|
},
|
2332
|
-
"function":
|
2333
|
-
var ret = _lambda.apply(this, arguments);
|
2334
|
-
if (ret[1] && !HOP(scope.refs, ret[1])) {
|
2335
|
-
ret[1] = null;
|
2336
|
-
}
|
2337
|
-
return ret;
|
2338
|
-
},
|
2373
|
+
"function": _lambda,
|
2339
2374
|
"defun": _lambda,
|
2340
2375
|
"block": function(body) {
|
2341
2376
|
if (body) return rmblock([ "block", tighten(MAP(body, walk)) ]);
|
@@ -2387,8 +2422,7 @@ function ast_squeeze(ast, options) {
|
|
2387
2422
|
return [ "array", args ];
|
2388
2423
|
}
|
2389
2424
|
},
|
2390
|
-
"while": _do_while
|
2391
|
-
"do": _do_while
|
2425
|
+
"while": _do_while
|
2392
2426
|
}, function() {
|
2393
2427
|
return walk(ast_add_scope(ast));
|
2394
2428
|
});
|
@@ -2409,7 +2443,7 @@ var DOT_CALL_NO_PARENS = jsp.array_to_hash([
|
|
2409
2443
|
|
2410
2444
|
function make_string(str, ascii_only) {
|
2411
2445
|
var dq = 0, sq = 0;
|
2412
|
-
str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029]/g, function(s){
|
2446
|
+
str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){
|
2413
2447
|
switch (s) {
|
2414
2448
|
case "\\": return "\\\\";
|
2415
2449
|
case "\b": return "\\b";
|
@@ -2421,6 +2455,7 @@ function make_string(str, ascii_only) {
|
|
2421
2455
|
case "\u2029": return "\\u2029";
|
2422
2456
|
case '"': ++dq; return '"';
|
2423
2457
|
case "'": ++sq; return "'";
|
2458
|
+
case "\0": return "\\0";
|
2424
2459
|
}
|
2425
2460
|
return s;
|
2426
2461
|
});
|
@@ -2437,6 +2472,8 @@ function to_ascii(str) {
|
|
2437
2472
|
});
|
2438
2473
|
};
|
2439
2474
|
|
2475
|
+
var SPLICE_NEEDS_BRACKETS = jsp.array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]);
|
2476
|
+
|
2440
2477
|
function gen_code(ast, options) {
|
2441
2478
|
options = defaults(options, {
|
2442
2479
|
indent_start : 0,
|
@@ -2567,6 +2604,19 @@ function gen_code(ast, options) {
|
|
2567
2604
|
return make_block_statements(statements)
|
2568
2605
|
.join(newline + newline);
|
2569
2606
|
},
|
2607
|
+
"splice": function(statements) {
|
2608
|
+
var parent = $stack[$stack.length - 2][0];
|
2609
|
+
if (HOP(SPLICE_NEEDS_BRACKETS, parent)) {
|
2610
|
+
// we need block brackets in this case
|
2611
|
+
return make_block.apply(this, arguments);
|
2612
|
+
} else {
|
2613
|
+
return MAP(make_block_statements(statements, true),
|
2614
|
+
function(line, i) {
|
2615
|
+
// the first line is already indented
|
2616
|
+
return i > 0 ? indent(line) : line;
|
2617
|
+
}).join(newline);
|
2618
|
+
}
|
2619
|
+
},
|
2570
2620
|
"block": make_block,
|
2571
2621
|
"var": function(defs) {
|
2572
2622
|
return "var " + add_commas(MAP(defs, make_1vardef)) + ";";
|
@@ -2807,7 +2857,7 @@ function gen_code(ast, options) {
|
|
2807
2857
|
return add_spaces([ out, make_block(body) ]);
|
2808
2858
|
};
|
2809
2859
|
|
2810
|
-
function make_block_statements(statements) {
|
2860
|
+
function make_block_statements(statements, noindent) {
|
2811
2861
|
for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) {
|
2812
2862
|
var stat = statements[i];
|
2813
2863
|
var code = make(stat);
|
@@ -2825,7 +2875,7 @@ function gen_code(ast, options) {
|
|
2825
2875
|
a.push(code);
|
2826
2876
|
}
|
2827
2877
|
}
|
2828
|
-
return MAP(a, indent);
|
2878
|
+
return noindent ? a : MAP(a, indent);
|
2829
2879
|
};
|
2830
2880
|
|
2831
2881
|
function make_switch_block(body) {
|
@@ -2856,7 +2906,7 @@ function gen_code(ast, options) {
|
|
2856
2906
|
function make_1vardef(def) {
|
2857
2907
|
var name = def[0], val = def[1];
|
2858
2908
|
if (val != null)
|
2859
|
-
name = add_spaces([ make_name(name), "=",
|
2909
|
+
name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]);
|
2860
2910
|
return name;
|
2861
2911
|
};
|
2862
2912
|
|
data/spec/spec_helper.rb
CHANGED
data/spec/uglifier_spec.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
3
|
|
3
4
|
describe "Uglifier" do
|
4
5
|
it "minifies JS" do
|
5
|
-
source = File.
|
6
|
+
source = File.open("vendor/uglifyjs/lib/process.js", "r:UTF-8").read
|
6
7
|
minified = Uglifier.new.compile(source)
|
7
8
|
minified.length.should < source.length
|
8
9
|
lambda {
|
@@ -16,6 +17,10 @@ describe "Uglifier" do
|
|
16
17
|
}.should raise_error(Uglifier::Error)
|
17
18
|
end
|
18
19
|
|
20
|
+
it "doesn't omit null character in strings" do
|
21
|
+
Uglifier.new.compile('var foo="\0bar"').should match(/(\0|\\0)/)
|
22
|
+
end
|
23
|
+
|
19
24
|
describe "Copyright Preservation" do
|
20
25
|
before :all do
|
21
26
|
@source = <<-EOS
|
@@ -63,16 +68,31 @@ describe "Uglifier" do
|
|
63
68
|
Uglifier.compile(code, :squeeze => false).length.should > Uglifier.compile(code, :squeeze => true).length
|
64
69
|
end
|
65
70
|
|
71
|
+
it "should allow top level variables to be mangled" do
|
72
|
+
code = "var foo = 123"
|
73
|
+
Uglifier.compile(code, :toplevel => true).should_not include("var foo")
|
74
|
+
end
|
75
|
+
|
76
|
+
it "allows variables to be excluded from mangling" do
|
77
|
+
code = "var foo = {bar: 123};"
|
78
|
+
Uglifier.compile(code, :except => ["foo"], :toplevel => true).should include("var foo")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "honors max line length" do
|
82
|
+
code = "var foo = 123;var bar = 123456"
|
83
|
+
Uglifier.compile(code, :max_line_length => 8).split("\n").length.should == 2
|
84
|
+
end
|
85
|
+
|
66
86
|
describe "Input Formats" do
|
67
87
|
it "handles strings" do
|
68
88
|
lambda {
|
69
|
-
Uglifier.new.compile(File.
|
89
|
+
Uglifier.new.compile(File.open("vendor/uglifyjs/lib/process.js", "r:UTF-8").read).should_not be_empty
|
70
90
|
}.should_not raise_error
|
71
91
|
end
|
72
92
|
|
73
93
|
it "handles files" do
|
74
94
|
lambda {
|
75
|
-
Uglifier.new.compile(File.open("vendor/uglifyjs/lib/process.js", "r")).should_not be_empty
|
95
|
+
Uglifier.new.compile(File.open("vendor/uglifyjs/lib/process.js", "r:UTF-8")).should_not be_empty
|
76
96
|
}.should_not raise_error
|
77
97
|
end
|
78
98
|
end
|
data/uglifier.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{uglifier}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "1.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{Ville Lautanala}]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-06-21}
|
13
13
|
s.email = %q{lautis@gmail.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE.txt",
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
".document",
|
20
20
|
".gitmodules",
|
21
21
|
".rspec",
|
22
|
+
".travis.yml",
|
22
23
|
"Gemfile",
|
23
24
|
"LICENSE.txt",
|
24
25
|
"README.rdoc",
|
@@ -34,12 +35,8 @@ Gem::Specification.new do |s|
|
|
34
35
|
]
|
35
36
|
s.homepage = %q{http://github.com/lautis/uglifier}
|
36
37
|
s.require_paths = [%q{lib}]
|
37
|
-
s.rubygems_version = %q{1.8.
|
38
|
+
s.rubygems_version = %q{1.8.4}
|
38
39
|
s.summary = %q{Ruby wrapper for UglifyJS JavaScript compressor}
|
39
|
-
s.test_files = [
|
40
|
-
"spec/spec_helper.rb",
|
41
|
-
"spec/uglifier_spec.rb"
|
42
|
-
]
|
43
40
|
|
44
41
|
if s.respond_to? :specification_version then
|
45
42
|
s.specification_version = 3
|
@@ -47,24 +44,24 @@ Gem::Specification.new do |s|
|
|
47
44
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
48
45
|
s.add_runtime_dependency(%q<execjs>, [">= 0.3.0"])
|
49
46
|
s.add_runtime_dependency(%q<multi_json>, [">= 1.0.2"])
|
50
|
-
s.add_development_dependency(%q<rspec>, ["~> 2.
|
47
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
|
51
48
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
52
|
-
s.add_development_dependency(%q<jeweler>, ["~> 1.
|
49
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
|
53
50
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
54
51
|
else
|
55
52
|
s.add_dependency(%q<execjs>, [">= 0.3.0"])
|
56
53
|
s.add_dependency(%q<multi_json>, [">= 1.0.2"])
|
57
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
54
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
58
55
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
59
|
-
s.add_dependency(%q<jeweler>, ["~> 1.
|
56
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
60
57
|
s.add_dependency(%q<rcov>, [">= 0"])
|
61
58
|
end
|
62
59
|
else
|
63
60
|
s.add_dependency(%q<execjs>, [">= 0.3.0"])
|
64
61
|
s.add_dependency(%q<multi_json>, [">= 1.0.2"])
|
65
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
62
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
66
63
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
67
|
-
s.add_dependency(%q<jeweler>, ["~> 1.
|
64
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
68
65
|
s.add_dependency(%q<rcov>, [">= 0"])
|
69
66
|
end
|
70
67
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uglifier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
|
10
|
-
version: 0.5.4
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ville Lautanala
|
@@ -15,10 +15,11 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-06-21 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
|
21
|
+
type: :runtime
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
22
23
|
none: false
|
23
24
|
requirements:
|
24
25
|
- - ">="
|
@@ -29,12 +30,12 @@ dependencies:
|
|
29
30
|
- 3
|
30
31
|
- 0
|
31
32
|
version: 0.3.0
|
32
|
-
type: :runtime
|
33
|
-
requirement: *id001
|
34
33
|
prerelease: false
|
34
|
+
version_requirements: *id001
|
35
35
|
name: execjs
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
|
-
|
37
|
+
type: :runtime
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
39
|
none: false
|
39
40
|
requirements:
|
40
41
|
- - ">="
|
@@ -45,28 +46,28 @@ dependencies:
|
|
45
46
|
- 0
|
46
47
|
- 2
|
47
48
|
version: 1.0.2
|
48
|
-
type: :runtime
|
49
|
-
requirement: *id002
|
50
49
|
prerelease: false
|
50
|
+
version_requirements: *id002
|
51
51
|
name: multi_json
|
52
52
|
- !ruby/object:Gem::Dependency
|
53
|
-
|
53
|
+
type: :development
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
55
|
none: false
|
55
56
|
requirements:
|
56
57
|
- - ~>
|
57
58
|
- !ruby/object:Gem::Version
|
58
|
-
hash:
|
59
|
+
hash: 23
|
59
60
|
segments:
|
60
61
|
- 2
|
61
|
-
-
|
62
|
+
- 6
|
62
63
|
- 0
|
63
|
-
version: 2.
|
64
|
-
type: :development
|
65
|
-
requirement: *id003
|
64
|
+
version: 2.6.0
|
66
65
|
prerelease: false
|
66
|
+
version_requirements: *id003
|
67
67
|
name: rspec
|
68
68
|
- !ruby/object:Gem::Dependency
|
69
|
-
|
69
|
+
type: :development
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
71
|
none: false
|
71
72
|
requirements:
|
72
73
|
- - ~>
|
@@ -77,28 +78,28 @@ dependencies:
|
|
77
78
|
- 0
|
78
79
|
- 0
|
79
80
|
version: 1.0.0
|
80
|
-
type: :development
|
81
|
-
requirement: *id004
|
82
81
|
prerelease: false
|
82
|
+
version_requirements: *id004
|
83
83
|
name: bundler
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
|
-
|
85
|
+
type: :development
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
86
87
|
none: false
|
87
88
|
requirements:
|
88
89
|
- - ~>
|
89
90
|
- !ruby/object:Gem::Version
|
90
|
-
hash:
|
91
|
+
hash: 15
|
91
92
|
segments:
|
92
93
|
- 1
|
93
|
-
-
|
94
|
+
- 6
|
94
95
|
- 0
|
95
|
-
version: 1.
|
96
|
-
type: :development
|
97
|
-
requirement: *id005
|
96
|
+
version: 1.6.0
|
98
97
|
prerelease: false
|
98
|
+
version_requirements: *id005
|
99
99
|
name: jeweler
|
100
100
|
- !ruby/object:Gem::Dependency
|
101
|
-
|
101
|
+
type: :development
|
102
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
102
103
|
none: false
|
103
104
|
requirements:
|
104
105
|
- - ">="
|
@@ -107,9 +108,8 @@ dependencies:
|
|
107
108
|
segments:
|
108
109
|
- 0
|
109
110
|
version: "0"
|
110
|
-
type: :development
|
111
|
-
requirement: *id006
|
112
111
|
prerelease: false
|
112
|
+
version_requirements: *id006
|
113
113
|
name: rcov
|
114
114
|
description:
|
115
115
|
email: lautis@gmail.com
|
@@ -124,6 +124,7 @@ files:
|
|
124
124
|
- .document
|
125
125
|
- .gitmodules
|
126
126
|
- .rspec
|
127
|
+
- .travis.yml
|
127
128
|
- Gemfile
|
128
129
|
- LICENSE.txt
|
129
130
|
- README.rdoc
|
@@ -165,10 +166,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
166
|
requirements: []
|
166
167
|
|
167
168
|
rubyforge_project:
|
168
|
-
rubygems_version: 1.8.
|
169
|
+
rubygems_version: 1.8.4
|
169
170
|
signing_key:
|
170
171
|
specification_version: 3
|
171
172
|
summary: Ruby wrapper for UglifyJS JavaScript compressor
|
172
|
-
test_files:
|
173
|
-
|
174
|
-
- spec/uglifier_spec.rb
|
173
|
+
test_files: []
|
174
|
+
|