uglifier 0.1.0 → 0.1.1
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/VERSION +1 -1
- data/lib/uglifier.rb +4 -2
- data/spec/uglifier_spec.rb +10 -0
- data/uglifier.gemspec +83 -0
- data/vendor/uglifyjs/lib/parse-js.js +3 -2
- data/vendor/uglifyjs/lib/process.js +286 -101
- metadata +5 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/lib/uglifier.rb
CHANGED
@@ -10,6 +10,7 @@ class Uglifier
|
|
10
10
|
:squeeze => true, # Squeeze code resulting in smaller, but less-readable code
|
11
11
|
:seqs => true, # Reduce consecutive statements in blocks into single statement
|
12
12
|
:dead_code => true, # Remove dead code (e.g. after return)
|
13
|
+
:extra => false, # Additional and potentially unsafe optimizations
|
13
14
|
:beautify => false, # Ouput indented code
|
14
15
|
:beautify_options => {
|
15
16
|
:indent_level => 4,
|
@@ -51,12 +52,13 @@ class Uglifier
|
|
51
52
|
def squeeze(cxt, ast)
|
52
53
|
cxt["ast_squeeze"].call(ast, {
|
53
54
|
"make_seqs" => @options[:seqs],
|
54
|
-
"dead_code" => @options[:dead_code]
|
55
|
+
"dead_code" => @options[:dead_code],
|
56
|
+
"extra" => @options[:extra]
|
55
57
|
})
|
56
58
|
end
|
57
59
|
|
58
60
|
def initialize_v8(cxt)
|
59
|
-
cxt["process"] = { :version => "
|
61
|
+
cxt["process"] = { :version => "v0.2.0" }
|
60
62
|
exports = {
|
61
63
|
"sys" => {
|
62
64
|
:debug => lambda { |m| puts m }
|
data/spec/uglifier_spec.rb
CHANGED
@@ -15,4 +15,14 @@ describe "Uglifier" do
|
|
15
15
|
Uglifier.new.compile(")(")
|
16
16
|
}.should raise_error(Uglifier::Error)
|
17
17
|
end
|
18
|
+
|
19
|
+
it "logs to output" do
|
20
|
+
$stdout.should_receive(:write).at_least(:once)
|
21
|
+
lambda {
|
22
|
+
Uglifier.new.compile("function uglifyThis() {
|
23
|
+
return;
|
24
|
+
return 1; // This is an error
|
25
|
+
}")
|
26
|
+
}.should_not raise_error(Uglifier::Error)
|
27
|
+
end
|
18
28
|
end
|
data/uglifier.gemspec
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{uglifier}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ville Lautanala"]
|
12
|
+
s.date = %q{2010-11-18}
|
13
|
+
s.email = %q{lautis@gmail.com}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"LICENSE.txt",
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".document",
|
20
|
+
".gitmodules",
|
21
|
+
".rspec",
|
22
|
+
"Gemfile",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/uglifier.rb",
|
28
|
+
"spec/spec_helper.rb",
|
29
|
+
"spec/uglifier_spec.rb",
|
30
|
+
"uglifier.gemspec",
|
31
|
+
"vendor/uglifyjs/lib/parse-js.js",
|
32
|
+
"vendor/uglifyjs/lib/process.js"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://github.com/lautis/uglifier}
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = %q{1.3.7}
|
37
|
+
s.summary = %q{Ruby wrapper for UglifyJS JavaScript compressor}
|
38
|
+
s.test_files = [
|
39
|
+
"spec/spec_helper.rb",
|
40
|
+
"spec/uglifier_spec.rb"
|
41
|
+
]
|
42
|
+
|
43
|
+
if s.respond_to? :specification_version then
|
44
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
45
|
+
s.specification_version = 3
|
46
|
+
|
47
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
48
|
+
s.add_runtime_dependency(%q<therubyracer>, [">= 0.7.5"])
|
49
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.0.0"])
|
50
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
51
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre5"])
|
52
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<therubyracer>, [">= 0.7.5"])
|
54
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.0.0"])
|
55
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
56
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre5"])
|
57
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
58
|
+
else
|
59
|
+
s.add_dependency(%q<therubyracer>, [">= 0.7.5"])
|
60
|
+
s.add_dependency(%q<rspec>, ["~> 2.0.0"])
|
61
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
62
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre5"])
|
63
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
64
|
+
s.add_dependency(%q<therubyracer>, [">= 0.7.5"])
|
65
|
+
s.add_dependency(%q<rspec>, ["~> 2.0.0"])
|
66
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
67
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre5"])
|
68
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
69
|
+
end
|
70
|
+
else
|
71
|
+
s.add_dependency(%q<therubyracer>, [">= 0.7.5"])
|
72
|
+
s.add_dependency(%q<rspec>, ["~> 2.0.0"])
|
73
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
74
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre5"])
|
75
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
76
|
+
s.add_dependency(%q<therubyracer>, [">= 0.7.5"])
|
77
|
+
s.add_dependency(%q<rspec>, ["~> 2.0.0"])
|
78
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
79
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre5"])
|
80
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -460,9 +460,10 @@ function tokenizer($TEXT, skip_comments) {
|
|
460
460
|
|
461
461
|
var handle_slash = skip_comments ? function() {
|
462
462
|
next();
|
463
|
+
var regex_allowed = S.regex_allowed;
|
463
464
|
switch (peek()) {
|
464
|
-
case "/": read_line_comment(); return next_token();
|
465
|
-
case "*": read_multiline_comment(); return next_token();
|
465
|
+
case "/": read_line_comment(); S.regex_allowed = regex_allowed; return next_token();
|
466
|
+
case "*": read_multiline_comment(); S.regex_allowed = regex_allowed; return next_token();
|
466
467
|
}
|
467
468
|
return S.regex_allowed ? read_regexp() : read_operator("/");
|
468
469
|
} : function() {
|
@@ -405,9 +405,7 @@ function ast_add_scope(ast) {
|
|
405
405
|
if (c != null) return [
|
406
406
|
"try",
|
407
407
|
t.map(walk),
|
408
|
-
|
409
|
-
return [ define(c[0]), c[1].map(walk) ];
|
410
|
-
}),
|
408
|
+
[ define(c[0]), c[1].map(walk) ],
|
411
409
|
f != null ? f.map(walk) : null
|
412
410
|
];
|
413
411
|
},
|
@@ -509,9 +507,7 @@ function ast_mangle(ast, do_toplevel) {
|
|
509
507
|
"try": function(t, c, f) {
|
510
508
|
return [ "try",
|
511
509
|
t.map(walk),
|
512
|
-
c ?
|
513
|
-
return [ get_mangled(c[0]), c[1].map(walk) ];
|
514
|
-
}) : null,
|
510
|
+
c != null ? [ get_mangled(c[0]), c[1].map(walk) ] : null,
|
515
511
|
f != null ? f.map(walk) : null ];
|
516
512
|
},
|
517
513
|
"toplevel": function(body) {
|
@@ -527,36 +523,6 @@ function ast_mangle(ast, do_toplevel) {
|
|
527
523
|
});
|
528
524
|
};
|
529
525
|
|
530
|
-
// function ast_has_side_effects(ast) {
|
531
|
-
// var w = ast_walker();
|
532
|
-
// var FOUND_SIDE_EFFECTS = {};
|
533
|
-
// function _found() { throw FOUND_SIDE_EFFECTS };
|
534
|
-
// try {
|
535
|
-
// w.with_walkers({
|
536
|
-
// "new": _found,
|
537
|
-
// "call": _found,
|
538
|
-
// "assign": _found,
|
539
|
-
// "defun": _found,
|
540
|
-
// "var": _found,
|
541
|
-
// "const": _found,
|
542
|
-
// "throw": _found,
|
543
|
-
// "return": _found,
|
544
|
-
// "break": _found,
|
545
|
-
// "continue": _found,
|
546
|
-
// "label": _found,
|
547
|
-
// "function": function(name) {
|
548
|
-
// if (name) _found();
|
549
|
-
// }
|
550
|
-
// }, function(){
|
551
|
-
// w.walk(ast);
|
552
|
-
// });
|
553
|
-
// } catch(ex) {
|
554
|
-
// if (ex === FOUND_SIDE_EFFECTS)
|
555
|
-
// return true;
|
556
|
-
// throw ex;
|
557
|
-
// }
|
558
|
-
// };
|
559
|
-
|
560
526
|
/* -----[
|
561
527
|
- compress foo["bar"] into foo.bar,
|
562
528
|
- remove block brackets {} where possible
|
@@ -572,11 +538,72 @@ function warn(msg) {
|
|
572
538
|
sys.debug(msg);
|
573
539
|
};
|
574
540
|
|
541
|
+
function best_of(ast1, ast2) {
|
542
|
+
return gen_code(ast1).length > gen_code(ast2[0] == "stat" ? ast2[1] : ast2).length ? ast2 : ast1;
|
543
|
+
};
|
544
|
+
|
545
|
+
function last_stat(b) {
|
546
|
+
if (b[0] == "block" && b[1] && b[1].length > 0)
|
547
|
+
return b[1][b[1].length - 1];
|
548
|
+
return b;
|
549
|
+
}
|
550
|
+
|
551
|
+
function aborts(t) {
|
552
|
+
if (t) {
|
553
|
+
t = last_stat(t);
|
554
|
+
if (t[0] == "return" || t[0] == "break" || t[0] == "continue" || t[0] == "throw")
|
555
|
+
return true;
|
556
|
+
}
|
557
|
+
};
|
558
|
+
|
559
|
+
function negate(c) {
|
560
|
+
var not_c = [ "unary-prefix", "!", c ];
|
561
|
+
switch (c[0]) {
|
562
|
+
case "unary-prefix":
|
563
|
+
return c[1] == "!" ? c[2] : c;
|
564
|
+
case "atom":
|
565
|
+
switch (c[1]) {
|
566
|
+
case "false": return [ "num", 0 ];
|
567
|
+
case "true": return [ "num", 1 ];
|
568
|
+
}
|
569
|
+
break;
|
570
|
+
case "binary":
|
571
|
+
var op = c[1], left = c[2], right = c[3];
|
572
|
+
switch (op) {
|
573
|
+
case "<=": return [ "binary", ">", left, right ];
|
574
|
+
case "<": return [ "binary", ">=", left, right ];
|
575
|
+
case ">=": return [ "binary", "<", left, right ];
|
576
|
+
case ">": return [ "binary", "<=", left, right ];
|
577
|
+
case "==": return [ "binary", "!=", left, right ];
|
578
|
+
case "!=": return [ "binary", "==", left, right ];
|
579
|
+
case "===": return [ "binary", "!==", left, right ];
|
580
|
+
case "!==": return [ "binary", "===", left, right ];
|
581
|
+
case "&&": return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]);
|
582
|
+
case "||": return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]);
|
583
|
+
}
|
584
|
+
break;
|
585
|
+
}
|
586
|
+
return not_c;
|
587
|
+
};
|
588
|
+
|
589
|
+
function make_conditional(c, t, e) {
|
590
|
+
if (c[0] == "unary-prefix" && c[1] == "!") {
|
591
|
+
return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ];
|
592
|
+
} else {
|
593
|
+
return e ? [ "conditional", c, t, e ] : [ "binary", "&&", c, t ];
|
594
|
+
}
|
595
|
+
};
|
596
|
+
|
597
|
+
function empty(b) {
|
598
|
+
return !b || (b[0] == "block" && (!b[1] || b[1].length == 0));
|
599
|
+
};
|
600
|
+
|
575
601
|
function ast_squeeze(ast, options) {
|
576
602
|
options = defaults(options, {
|
577
|
-
make_seqs: true,
|
578
|
-
dead_code: true,
|
579
|
-
no_warnings: false
|
603
|
+
make_seqs : true,
|
604
|
+
dead_code : true,
|
605
|
+
no_warnings : false,
|
606
|
+
extra : false
|
580
607
|
});
|
581
608
|
|
582
609
|
var w = ast_walker(), walk = w.walk;
|
@@ -585,22 +612,98 @@ function ast_squeeze(ast, options) {
|
|
585
612
|
return node[0] == "string" || node[0] == "num";
|
586
613
|
};
|
587
614
|
|
615
|
+
function find_first_execute(node) {
|
616
|
+
if (!node)
|
617
|
+
return false;
|
618
|
+
|
619
|
+
switch (node[0]) {
|
620
|
+
case "num":
|
621
|
+
case "string":
|
622
|
+
case "name":
|
623
|
+
return node;
|
624
|
+
case "call":
|
625
|
+
case "conditional":
|
626
|
+
case "for":
|
627
|
+
case "if":
|
628
|
+
case "new":
|
629
|
+
case "return":
|
630
|
+
case "stat":
|
631
|
+
case "switch":
|
632
|
+
case "throw":
|
633
|
+
return find_first_execute(node[1]);
|
634
|
+
case "binary":
|
635
|
+
return find_first_execute(node[2]);
|
636
|
+
case "assign":
|
637
|
+
if (node[1] === true)
|
638
|
+
return find_first_execute(node[3]);
|
639
|
+
break;
|
640
|
+
case "var":
|
641
|
+
if (node[1][0].length > 1)
|
642
|
+
return find_first_execute(node[1][0][1]);
|
643
|
+
break;
|
644
|
+
}
|
645
|
+
return null;
|
646
|
+
}
|
647
|
+
|
648
|
+
function find_assign_recursive(p, v) {
|
649
|
+
if (p[0] == "assign" && p[1] != true || p[0] == "unary-prefix") {
|
650
|
+
if (p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1])
|
651
|
+
return true;
|
652
|
+
return false;
|
653
|
+
}
|
654
|
+
|
655
|
+
if (p[0] != "assign" || p[1] !== true)
|
656
|
+
return false;
|
657
|
+
|
658
|
+
if ((is_constant(p[3]) && p[3][0] == v[0] && p[3][1] == v[1]) ||
|
659
|
+
(p[3][0] == "name" && v[0] == "name" && p[3][1] == v[1]) ||
|
660
|
+
(p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1]))
|
661
|
+
return true;
|
662
|
+
|
663
|
+
return find_assign_recursive(p[3], v);
|
664
|
+
};
|
665
|
+
|
588
666
|
function rmblock(block) {
|
589
667
|
if (block != null && block[0] == "block" && block[1] && block[1].length == 1)
|
590
668
|
block = block[1][0];
|
591
669
|
return block;
|
592
670
|
};
|
593
671
|
|
672
|
+
function clone(obj) {
|
673
|
+
if (obj && obj.constructor == Array)
|
674
|
+
return obj.map(clone);
|
675
|
+
return obj;
|
676
|
+
};
|
677
|
+
|
678
|
+
function make_seq_to_statements(node) {
|
679
|
+
if (node[0] != "seq") {
|
680
|
+
switch (node[0]) {
|
681
|
+
case "var":
|
682
|
+
case "const":
|
683
|
+
return [ node ];
|
684
|
+
default:
|
685
|
+
return [ [ "stat", node ] ];
|
686
|
+
}
|
687
|
+
}
|
688
|
+
|
689
|
+
var ret = [];
|
690
|
+
for (var i = 1; i < node.length; i++)
|
691
|
+
ret.push.apply(ret, make_seq_to_statements(node[i]));
|
692
|
+
|
693
|
+
return ret;
|
694
|
+
};
|
695
|
+
|
594
696
|
function _lambda(name, args, body) {
|
595
697
|
return [ this[0], name, args, tighten(body.map(walk), "lambda") ];
|
596
698
|
};
|
597
699
|
|
598
700
|
// we get here for blocks that have been already transformed.
|
599
|
-
// this function does
|
701
|
+
// this function does a few things:
|
600
702
|
// 1. discard useless blocks
|
601
703
|
// 2. join consecutive var declarations
|
602
704
|
// 3. remove obviously dead code
|
603
705
|
// 4. transform consecutive statements using the comma operator
|
706
|
+
// 5. if block_type == "lambda" and it detects constructs like if(foo) return ... - rewrite like if (!foo) { ... }
|
604
707
|
function tighten(statements, block_type) {
|
605
708
|
statements = statements.reduce(function(a, stat){
|
606
709
|
if (stat[0] == "block") {
|
@@ -613,6 +716,64 @@ function ast_squeeze(ast, options) {
|
|
613
716
|
return a;
|
614
717
|
}, []);
|
615
718
|
|
719
|
+
if (options.extra) {
|
720
|
+
// Detightening things. We do this because then we can assume that the
|
721
|
+
// statements are structured in a specific way.
|
722
|
+
statements = (function(a, prev) {
|
723
|
+
statements.forEach(function(cur) {
|
724
|
+
switch (cur[0]) {
|
725
|
+
case "for":
|
726
|
+
if (cur[1] != null) {
|
727
|
+
a.push.apply(a, make_seq_to_statements(cur[1]));
|
728
|
+
cur[1] = null;
|
729
|
+
}
|
730
|
+
a.push(cur);
|
731
|
+
break;
|
732
|
+
case "stat":
|
733
|
+
var stats = make_seq_to_statements(cur[1]);
|
734
|
+
stats.forEach(function(s) {
|
735
|
+
if (s[1][0] == "unary-postfix")
|
736
|
+
s[1][0] = "unary-prefix";
|
737
|
+
});
|
738
|
+
a.push.apply(a, stats);
|
739
|
+
break;
|
740
|
+
default:
|
741
|
+
a.push(cur);
|
742
|
+
}
|
743
|
+
});
|
744
|
+
return a;
|
745
|
+
})([]);
|
746
|
+
|
747
|
+
statements = (function(a, prev) {
|
748
|
+
statements.forEach(function(cur) {
|
749
|
+
if (!(prev && prev[0] == "stat")) {
|
750
|
+
a.push(cur);
|
751
|
+
prev = cur;
|
752
|
+
return;
|
753
|
+
}
|
754
|
+
|
755
|
+
var p = prev[1];
|
756
|
+
var c = find_first_execute(cur);
|
757
|
+
if (c && find_assign_recursive(p, c)) {
|
758
|
+
var old_cur = clone(cur);
|
759
|
+
c.splice(0, c.length);
|
760
|
+
c.push.apply(c, p);
|
761
|
+
var tmp_cur = best_of(cur, [ "toplevel", [ prev, old_cur ] ]);
|
762
|
+
if (tmp_cur == cur) {
|
763
|
+
a[a.length -1] = cur;
|
764
|
+
} else {
|
765
|
+
cur = old_cur;
|
766
|
+
a.push(cur);
|
767
|
+
}
|
768
|
+
} else {
|
769
|
+
a.push(cur);
|
770
|
+
}
|
771
|
+
prev = cur;
|
772
|
+
});
|
773
|
+
return a;
|
774
|
+
})([]);
|
775
|
+
}
|
776
|
+
|
616
777
|
statements = (function(a, prev){
|
617
778
|
statements.forEach(function(cur){
|
618
779
|
if (prev && ((cur[0] == "var" && prev[0] == "var") ||
|
@@ -646,28 +807,47 @@ function ast_squeeze(ast, options) {
|
|
646
807
|
|
647
808
|
if (options.make_seqs) statements = (function(a, prev) {
|
648
809
|
statements.forEach(function(cur){
|
649
|
-
if (
|
650
|
-
a.push(cur);
|
651
|
-
if (cur[0] == "stat") prev = cur;
|
652
|
-
} else if (cur[0] == "stat" && prev[0] == "stat") {
|
810
|
+
if (prev && prev[0] == "stat" && cur[0] == "stat") {
|
653
811
|
prev[1] = [ "seq", prev[1], cur[1] ];
|
654
812
|
} else {
|
655
813
|
a.push(cur);
|
656
|
-
prev =
|
814
|
+
prev = cur;
|
657
815
|
}
|
658
816
|
});
|
659
817
|
return a;
|
660
818
|
})([]);
|
661
819
|
|
820
|
+
if (options.extra) {
|
821
|
+
statements = (function(a, prev){
|
822
|
+
statements.forEach(function(cur){
|
823
|
+
var replaced = false;
|
824
|
+
if (prev && cur[0] == "for" && cur[1] == null && (prev[0] == "var" || prev[0] == "const" || prev[0] == "stat")) {
|
825
|
+
cur[1] = prev;
|
826
|
+
a[a.length - 1] = cur;
|
827
|
+
} else {
|
828
|
+
a.push(cur);
|
829
|
+
}
|
830
|
+
prev = cur;
|
831
|
+
});
|
832
|
+
return a;
|
833
|
+
})([]);
|
834
|
+
}
|
835
|
+
|
662
836
|
if (block_type == "lambda") statements = (function(i, a, stat){
|
663
837
|
while (i < statements.length) {
|
664
838
|
stat = statements[i++];
|
665
|
-
if (stat[0] == "if" &&
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
839
|
+
if (stat[0] == "if" && !stat[3]) {
|
840
|
+
if (stat[2][0] == "return" && stat[2][1] == null) {
|
841
|
+
a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ]));
|
842
|
+
break;
|
843
|
+
}
|
844
|
+
var last = last_stat(stat[2]);
|
845
|
+
if (last[0] == "return" && last[1] == null) {
|
846
|
+
a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ]));
|
847
|
+
break;
|
848
|
+
}
|
670
849
|
}
|
850
|
+
a.push(stat);
|
671
851
|
}
|
672
852
|
return a;
|
673
853
|
})(0, []);
|
@@ -675,52 +855,30 @@ function ast_squeeze(ast, options) {
|
|
675
855
|
return statements;
|
676
856
|
};
|
677
857
|
|
678
|
-
function best_of(ast1, ast2) {
|
679
|
-
return gen_code(ast1).length > gen_code(ast2[0] == "stat" ? ast2[1] : ast2).length ? ast2 : ast1;
|
680
|
-
};
|
681
|
-
|
682
|
-
function aborts(t) {
|
683
|
-
if (t[0] == "block" && t[1] && t[1].length > 0)
|
684
|
-
t = t[1][t[1].length - 1]; // interested in last statement
|
685
|
-
if (t[0] == "return" || t[0] == "break" || t[0] == "continue" || t[0] == "throw")
|
686
|
-
return true;
|
687
|
-
};
|
688
|
-
|
689
|
-
function negate(c) {
|
690
|
-
if (c[0] == "unary-prefix" && c[1] == "!") return c[2];
|
691
|
-
else return [ "unary-prefix", "!", c ];
|
692
|
-
};
|
693
|
-
|
694
|
-
function make_conditional(c, t, e) {
|
695
|
-
if (c[0] == "unary-prefix" && c[1] == "!") {
|
696
|
-
return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ];
|
697
|
-
} else {
|
698
|
-
return e ? [ "conditional", c, t, e ] : [ "binary", "&&", c, t ];
|
699
|
-
}
|
700
|
-
};
|
701
|
-
|
702
|
-
function empty(b) {
|
703
|
-
return !b || (b[0] == "block" && (!b[1] || b[1].length == 0));
|
704
|
-
};
|
705
|
-
|
706
858
|
function make_if(c, t, e) {
|
707
859
|
c = walk(c);
|
708
860
|
t = walk(t);
|
709
861
|
e = walk(e);
|
710
|
-
|
862
|
+
|
711
863
|
if (empty(t)) {
|
712
|
-
|
713
|
-
else c = [ "unary-prefix", "!", c ];
|
864
|
+
c = negate(c);
|
714
865
|
t = e;
|
715
866
|
e = null;
|
716
|
-
}
|
717
|
-
if (empty(e)) {
|
867
|
+
} else if (empty(e)) {
|
718
868
|
e = null;
|
719
869
|
} else {
|
720
|
-
if
|
721
|
-
|
722
|
-
var
|
723
|
-
|
870
|
+
// if we have both else and then, maybe it makes sense to switch them?
|
871
|
+
(function(){
|
872
|
+
var a = gen_code(c);
|
873
|
+
var n = negate(c);
|
874
|
+
var b = gen_code(n);
|
875
|
+
if (b.length < a.length) {
|
876
|
+
var tmp = t;
|
877
|
+
t = e;
|
878
|
+
e = tmp;
|
879
|
+
c = n;
|
880
|
+
}
|
881
|
+
})();
|
724
882
|
}
|
725
883
|
if (empty(e) && empty(t))
|
726
884
|
return [ "stat", c ];
|
@@ -748,6 +906,15 @@ function ast_squeeze(ast, options) {
|
|
748
906
|
}
|
749
907
|
ret = walk([ "block", ret ]);
|
750
908
|
}
|
909
|
+
else if (t && aborts(e)) {
|
910
|
+
ret = [ [ "if", negate(c), e ] ];
|
911
|
+
if (t[0] == "block") {
|
912
|
+
if (t[1]) ret = ret.concat(t[1]);
|
913
|
+
} else {
|
914
|
+
ret.push(t);
|
915
|
+
}
|
916
|
+
ret = walk([ "block", ret ]);
|
917
|
+
}
|
751
918
|
return ret;
|
752
919
|
};
|
753
920
|
|
@@ -785,19 +952,23 @@ function ast_squeeze(ast, options) {
|
|
785
952
|
left = walk(left);
|
786
953
|
right = walk(right);
|
787
954
|
var best = [ "binary", op, left, right ];
|
788
|
-
if (is_constant(
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
955
|
+
if (is_constant(right)) {
|
956
|
+
if (is_constant(left)) {
|
957
|
+
var val = null;
|
958
|
+
switch (op) {
|
959
|
+
case "+": val = left[1] + right[1]; break;
|
960
|
+
case "*": val = left[1] * right[1]; break;
|
961
|
+
case "/": val = left[1] / right[1]; break;
|
962
|
+
case "-": val = left[1] - right[1]; break;
|
963
|
+
case "<<": val = left[1] << right[1]; break;
|
964
|
+
case ">>": val = left[1] >> right[1]; break;
|
965
|
+
case ">>>": val = left[1] >>> right[1]; break;
|
966
|
+
}
|
967
|
+
if (val != null) {
|
968
|
+
best = best_of(best, [ typeof val == "string" ? "string" : "num", val ]);
|
969
|
+
}
|
970
|
+
} else if (left[0] == "binary" && left[1] == "+" && left[3][0] == "string") {
|
971
|
+
best = best_of(best, [ "binary", "+", left[2], [ "string", left[3][1] + right[1] ] ]);
|
801
972
|
}
|
802
973
|
}
|
803
974
|
return best;
|
@@ -812,6 +983,16 @@ function ast_squeeze(ast, options) {
|
|
812
983
|
c != null ? [ c[0], tighten(c[1].map(walk)) ] : null,
|
813
984
|
f != null ? tighten(f.map(walk)) : null
|
814
985
|
];
|
986
|
+
},
|
987
|
+
"unary-prefix": function(op, cond) {
|
988
|
+
if (op == "!")
|
989
|
+
return best_of(this, negate(cond));
|
990
|
+
},
|
991
|
+
"call": function(expr, args) {
|
992
|
+
if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) {
|
993
|
+
// foo.toString() ==> foo+""
|
994
|
+
return [ "binary", "+", expr[1], [ "string", "" ]];
|
995
|
+
}
|
815
996
|
}
|
816
997
|
}, function() {
|
817
998
|
return walk(ast);
|
@@ -1005,7 +1186,7 @@ function gen_code(ast, beautify) {
|
|
1005
1186
|
"assign": function(op, lvalue, rvalue) {
|
1006
1187
|
if (op && op !== true) op += "=";
|
1007
1188
|
else op = "=";
|
1008
|
-
return add_spaces([ make(lvalue), op,
|
1189
|
+
return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]);
|
1009
1190
|
},
|
1010
1191
|
"dot": function(expr) {
|
1011
1192
|
var out = make(expr), i = 1;
|
@@ -1193,6 +1374,10 @@ function gen_code(ast, beautify) {
|
|
1193
1374
|
};
|
1194
1375
|
|
1195
1376
|
function make_name(name) {
|
1377
|
+
switch (name) {
|
1378
|
+
case "true": return beautify ? "true" : "!0";
|
1379
|
+
case "false": return beautify ? "false" : "!1";
|
1380
|
+
}
|
1196
1381
|
return name.toString();
|
1197
1382
|
};
|
1198
1383
|
|
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: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ville Lautanala
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-18 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -197,6 +197,7 @@ files:
|
|
197
197
|
- lib/uglifier.rb
|
198
198
|
- spec/spec_helper.rb
|
199
199
|
- spec/uglifier_spec.rb
|
200
|
+
- uglifier.gemspec
|
200
201
|
- vendor/uglifyjs/lib/parse-js.js
|
201
202
|
- vendor/uglifyjs/lib/process.js
|
202
203
|
has_rdoc: true
|