uglifier 0.2.0 → 0.3.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/Gemfile +3 -3
- data/VERSION +1 -1
- data/bin/uglify +6 -0
- data/lib/uglifier.rb +54 -42
- data/lib/uglifier/cli.rb +62 -0
- data/lib/uglifier/node.rb +24 -0
- data/spec/uglifier_spec.rb +49 -3
- data/uglifier.gemspec +17 -12
- data/vendor/uglifyjs/lib/parse-js.js +36 -23
- data/vendor/uglifyjs/lib/process.js +197 -118
- metadata +19 -17
data/Gemfile
CHANGED
@@ -3,13 +3,13 @@ source "http://rubygems.org"
|
|
3
3
|
# Example:
|
4
4
|
# gem "activesupport", ">= 2.3.5"
|
5
5
|
|
6
|
-
gem "therubyracer", ">= 0.
|
6
|
+
gem "therubyracer", ">= 0.8.0"
|
7
7
|
|
8
8
|
# Add dependencies to develop your gem here.
|
9
9
|
# Include everything needed to run rake, tests, features, etc.
|
10
10
|
group :development do
|
11
|
-
gem "rspec", "~> 2.
|
11
|
+
gem "rspec", "~> 2.3.0"
|
12
12
|
gem "bundler", "~> 1.0.0"
|
13
|
-
gem "jeweler", "~> 1.5.0
|
13
|
+
gem "jeweler", "~> 1.5.0"
|
14
14
|
gem "rcov", ">= 0"
|
15
15
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/bin/uglify
ADDED
data/lib/uglifier.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "
|
1
|
+
require "uglifier/node"
|
2
2
|
|
3
3
|
class Uglifier
|
4
4
|
# Raised when compilation fails
|
@@ -12,6 +12,7 @@ class Uglifier
|
|
12
12
|
:dead_code => true, # Remove dead code (e.g. after return)
|
13
13
|
:extra => false, # Additional and potentially unsafe optimizations
|
14
14
|
:unsafe => false, # Optimizations known to be unsafe in some situations
|
15
|
+
:copyright => true, # Show copyright message
|
15
16
|
:beautify => false, # Ouput indented code
|
16
17
|
:beautify_options => {
|
17
18
|
:indent_level => 4,
|
@@ -21,27 +22,26 @@ class Uglifier
|
|
21
22
|
}
|
22
23
|
}
|
23
24
|
|
25
|
+
# Create new instance of Uglifier with given options
|
24
26
|
def initialize(options = {})
|
25
27
|
@options = DEFAULTS.merge(options)
|
26
|
-
@
|
27
|
-
"
|
28
|
-
|
29
|
-
}
|
30
|
-
|
28
|
+
@node = Node.new do |cxt|
|
29
|
+
@tokenizer = cxt.require("parse-js")["tokenizer"]
|
30
|
+
process = cxt.require("process")
|
31
|
+
process["set_logger"].call(lambda {|m| $stderr.puts m })
|
32
|
+
end
|
31
33
|
end
|
32
34
|
|
33
35
|
def compile(source)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
36
|
+
str = stringify(source)
|
37
|
+
|
38
|
+
if @options[:copyright]
|
39
|
+
copyright(str)
|
40
|
+
else
|
41
|
+
""
|
42
|
+
end << generate_code(ast(str))
|
43
|
+
rescue V8::JSError => e
|
44
|
+
raise Error.new(e.message)
|
45
45
|
end
|
46
46
|
|
47
47
|
def self.compile(source, options = {})
|
@@ -50,46 +50,58 @@ class Uglifier
|
|
50
50
|
|
51
51
|
private
|
52
52
|
|
53
|
-
def
|
54
|
-
|
53
|
+
def stringify(source)
|
54
|
+
if source.respond_to? :read
|
55
|
+
source.read
|
56
|
+
else
|
57
|
+
source.to_s
|
58
|
+
end
|
55
59
|
end
|
56
60
|
|
57
|
-
def
|
58
|
-
|
61
|
+
def copyright(source)
|
62
|
+
comments = []
|
63
|
+
|
64
|
+
tokens = @tokenizer.call(source, false)
|
65
|
+
comment = tokens.call
|
66
|
+
prev = nil
|
67
|
+
|
68
|
+
while (comment["type"].match(/^comment/) && (!prev || prev == comment["type"]))
|
69
|
+
comments << if comment["type"] == "comment1"
|
70
|
+
"//#{comment["value"]}\n"
|
71
|
+
else
|
72
|
+
"/*#{comment["value"]}*/\n"
|
73
|
+
end
|
74
|
+
prev = comment["type"]
|
75
|
+
comment = tokens.call
|
76
|
+
end
|
77
|
+
comments.join
|
59
78
|
end
|
60
79
|
|
61
|
-
def
|
80
|
+
def generate_code(ast)
|
81
|
+
@node["gen_code"].call(ast, @options[:beautify] && @options[:beautify_options])
|
82
|
+
end
|
83
|
+
|
84
|
+
def ast(source)
|
85
|
+
squeeze_unsafe(squeeze(mangle(@node["parse"].call(source))))
|
86
|
+
end
|
87
|
+
|
88
|
+
def mangle(ast)
|
62
89
|
return ast unless @options[:mangle]
|
63
|
-
|
90
|
+
@node["ast_mangle"].call(ast, @options[:toplevel])
|
64
91
|
end
|
65
92
|
|
66
|
-
def squeeze(
|
93
|
+
def squeeze(ast)
|
67
94
|
return ast unless @options[:squeeze]
|
68
95
|
|
69
|
-
|
96
|
+
@node["ast_squeeze"].call(ast, {
|
70
97
|
"make_seqs" => @options[:seqs],
|
71
98
|
"dead_code" => @options[:dead_code],
|
72
99
|
"extra" => @options[:extra]
|
73
100
|
})
|
74
101
|
end
|
75
102
|
|
76
|
-
def squeeze_unsafe(
|
103
|
+
def squeeze_unsafe(ast)
|
77
104
|
return ast unless @options[:unsafe]
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
def load_file(cxt, file)
|
82
|
-
old = cxt["exports"]
|
83
|
-
cxt["exports"] = {}
|
84
|
-
cxt["require"] = lambda {|r|
|
85
|
-
@exports[File.basename(r, ".js")] || begin
|
86
|
-
@exports[file] = cxt["exports"] # Prevent circular dependencies
|
87
|
-
load_file(cxt, File.basename(r, ".js"))
|
88
|
-
end
|
89
|
-
}
|
90
|
-
cxt.load(File.join(File.dirname(__FILE__), "..", "vendor", "uglifyjs", "lib", File.basename(file, ".js") + ".js"))
|
91
|
-
@exports[file] = cxt["exports"]
|
92
|
-
cxt["exports"] = old
|
93
|
-
@exports[file]
|
105
|
+
@node["ast_squeeze_more"].call(ast)
|
94
106
|
end
|
95
107
|
end
|
data/lib/uglifier/cli.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
class Uglifier
|
4
|
+
module Cli
|
5
|
+
def self.run!
|
6
|
+
options = {}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = "Usage: uglifier [options] file1 file2 ..."
|
9
|
+
|
10
|
+
opts.on("-M", "--no-mangle", "Don't mangle variable names") do |m|
|
11
|
+
options[:mangle] = m
|
12
|
+
end
|
13
|
+
|
14
|
+
opts.on("-t", "--toplevel", "Mangle top-level variable names") do |m|
|
15
|
+
options[:toplevel] = m
|
16
|
+
end
|
17
|
+
|
18
|
+
opts.on("-S", "--no-squeeze", "Squeeze code resulting in smaller, but less-readable code") do |s|
|
19
|
+
options[:squeeze] = s
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on("-Q", "--no-seqs", "Reduce consecutive statements in blocks into single statement") do |q|
|
23
|
+
options[:seqs] = q
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on("-d", "--[no-]dead-code", "Remove dead code (e.g. after return)") do |d|
|
27
|
+
options[:dead_code] = d
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-x", "--extra-optimizations", "Additional and potentially unsafe optimizations") do |x|
|
31
|
+
options[:extra] = x
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("-u", "--unsafe-optimizations", "Optimizations known to be unsafe in some situations") do |d|
|
35
|
+
options[:unsafe] = d
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on("-C", "--no-copyright", "Omit copyright information") do |d|
|
39
|
+
options[:copyright] = d
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.on("-b", "--beautify", "Output indented code") do |d|
|
43
|
+
options[:beautify] = d
|
44
|
+
end
|
45
|
+
|
46
|
+
opts.on("-v", "--verbose", "Run verbosely") do |v|
|
47
|
+
options[:verbose] = v
|
48
|
+
end
|
49
|
+
end.parse!
|
50
|
+
|
51
|
+
uglifier = Uglifier.new(options)
|
52
|
+
if ARGV[0]
|
53
|
+
ARGV.each do |f|
|
54
|
+
puts uglifier.compile(File.open(f, 'r'))
|
55
|
+
end
|
56
|
+
else
|
57
|
+
puts uglifier.compile($stdin)
|
58
|
+
end
|
59
|
+
true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "v8"
|
2
|
+
|
3
|
+
class Uglifier
|
4
|
+
class Node < V8::Context
|
5
|
+
def initialize(*args, &blk)
|
6
|
+
@exports = {}
|
7
|
+
super(*args, &blk)
|
8
|
+
end
|
9
|
+
def require(file)
|
10
|
+
old = self["exports"]
|
11
|
+
self["exports"] = {}
|
12
|
+
self["require"] = lambda {|r|
|
13
|
+
@exports[File.basename(r, ".js")] || begin
|
14
|
+
@exports[file] = self["exports"] # Prevent circular dependencies
|
15
|
+
self.require(File.basename(r, ".js"))
|
16
|
+
end
|
17
|
+
}
|
18
|
+
load(File.join(File.dirname(__FILE__), "..", "..", "vendor", "uglifyjs", "lib", File.basename(file, ".js") + ".js"))
|
19
|
+
@exports[file] = self["exports"]
|
20
|
+
self["exports"] = old
|
21
|
+
@exports[file]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/spec/uglifier_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe "Uglifier" do
|
4
4
|
it "minifies JS" do
|
5
|
-
source = File.read("vendor/uglifyjs/lib/
|
5
|
+
source = File.read("vendor/uglifyjs/lib/process.js")
|
6
6
|
minified = Uglifier.new.compile(source)
|
7
7
|
minified.length.should < source.length
|
8
8
|
lambda {
|
@@ -16,8 +16,8 @@ describe "Uglifier" do
|
|
16
16
|
}.should raise_error(Uglifier::Error)
|
17
17
|
end
|
18
18
|
|
19
|
-
it "logs to
|
20
|
-
$
|
19
|
+
it "logs to stderr" do
|
20
|
+
$stderr.should_receive(:write).at_least(:once)
|
21
21
|
lambda {
|
22
22
|
Uglifier.new.compile("function uglifyThis() {
|
23
23
|
return;
|
@@ -26,6 +26,38 @@ describe "Uglifier" do
|
|
26
26
|
}.should_not raise_error(Uglifier::Error)
|
27
27
|
end
|
28
28
|
|
29
|
+
describe "Copyright Preservation" do
|
30
|
+
before :all do
|
31
|
+
@source = <<-EOS
|
32
|
+
/* Copyright Notice */
|
33
|
+
/* (c) 2011 */
|
34
|
+
// REMOVED
|
35
|
+
function identity(p) { return p; }
|
36
|
+
EOS
|
37
|
+
@minified = Uglifier.compile(@source, :copyright => true)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "preserves copyright notice" do
|
41
|
+
@minified.should match /Copyright Notice/
|
42
|
+
end
|
43
|
+
|
44
|
+
it "handles multiple copyright blocks" do
|
45
|
+
@minified.should match /\(c\) 2011/
|
46
|
+
end
|
47
|
+
|
48
|
+
it "doesn't include different comment types" do
|
49
|
+
@minified.should_not match /REMOVED/
|
50
|
+
end
|
51
|
+
|
52
|
+
it "puts comments on own lines" do
|
53
|
+
@minified.split("\n").should have(3).items
|
54
|
+
end
|
55
|
+
|
56
|
+
it "omits copyright notification if copyright parameter is set to false" do
|
57
|
+
Uglifier.compile(@source, :copyright => false).should_not match /Copyright/
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
29
61
|
it "does additional squeezing when unsafe options is true" do
|
30
62
|
unsafe_input = "function a(b){b.toString();}"
|
31
63
|
Uglifier.new(:unsafe => true).compile(unsafe_input).length.should < Uglifier.new(:unsafe => false).compile(unsafe_input).length
|
@@ -40,4 +72,18 @@ describe "Uglifier" do
|
|
40
72
|
code = "function a(a){if(a) { return 0; } else { return 1; }}"
|
41
73
|
Uglifier.compile(code, :squeeze => false).length.should > Uglifier.compile(code, :squeeze => true).length
|
42
74
|
end
|
75
|
+
|
76
|
+
describe "Input Formats" do
|
77
|
+
it "handles strings" do
|
78
|
+
lambda {
|
79
|
+
Uglifier.new.compile(File.read("vendor/uglifyjs/lib/process.js")).should_not be_empty
|
80
|
+
}.should_not raise_error
|
81
|
+
end
|
82
|
+
|
83
|
+
it "handles files" do
|
84
|
+
lambda {
|
85
|
+
Uglifier.new.compile(File.open("vendor/uglifyjs/lib/process.js", "r")).should_not be_empty
|
86
|
+
}.should_not raise_error
|
87
|
+
end
|
88
|
+
end
|
43
89
|
end
|
data/uglifier.gemspec
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{uglifier}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ville Lautanala"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-01-06}
|
13
|
+
s.default_executable = %q{uglify}
|
13
14
|
s.email = %q{lautis@gmail.com}
|
15
|
+
s.executables = ["uglify"]
|
14
16
|
s.extra_rdoc_files = [
|
15
17
|
"LICENSE.txt",
|
16
18
|
"README.rdoc"
|
@@ -24,7 +26,10 @@ Gem::Specification.new do |s|
|
|
24
26
|
"README.rdoc",
|
25
27
|
"Rakefile",
|
26
28
|
"VERSION",
|
29
|
+
"bin/uglify",
|
27
30
|
"lib/uglifier.rb",
|
31
|
+
"lib/uglifier/cli.rb",
|
32
|
+
"lib/uglifier/node.rb",
|
28
33
|
"spec/spec_helper.rb",
|
29
34
|
"spec/uglifier_spec.rb",
|
30
35
|
"uglifier.gemspec",
|
@@ -46,10 +51,10 @@ Gem::Specification.new do |s|
|
|
46
51
|
s.specification_version = 3
|
47
52
|
|
48
53
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
49
|
-
s.add_runtime_dependency(%q<therubyracer>, [">= 0.
|
50
|
-
s.add_development_dependency(%q<rspec>, ["~> 2.
|
54
|
+
s.add_runtime_dependency(%q<therubyracer>, [">= 0.8.0"])
|
55
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
|
51
56
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
52
|
-
s.add_development_dependency(%q<jeweler>, ["~> 1.5.0
|
57
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.0"])
|
53
58
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
54
59
|
s.add_development_dependency(%q<therubyracer>, [">= 0.7.5"])
|
55
60
|
s.add_development_dependency(%q<rspec>, ["~> 2.0.0"])
|
@@ -57,10 +62,10 @@ Gem::Specification.new do |s|
|
|
57
62
|
s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre5"])
|
58
63
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
59
64
|
else
|
60
|
-
s.add_dependency(%q<therubyracer>, [">= 0.
|
61
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
65
|
+
s.add_dependency(%q<therubyracer>, [">= 0.8.0"])
|
66
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
62
67
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
63
|
-
s.add_dependency(%q<jeweler>, ["~> 1.5.0
|
68
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0"])
|
64
69
|
s.add_dependency(%q<rcov>, [">= 0"])
|
65
70
|
s.add_dependency(%q<therubyracer>, [">= 0.7.5"])
|
66
71
|
s.add_dependency(%q<rspec>, ["~> 2.0.0"])
|
@@ -69,10 +74,10 @@ Gem::Specification.new do |s|
|
|
69
74
|
s.add_dependency(%q<rcov>, [">= 0"])
|
70
75
|
end
|
71
76
|
else
|
72
|
-
s.add_dependency(%q<therubyracer>, [">= 0.
|
73
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
77
|
+
s.add_dependency(%q<therubyracer>, [">= 0.8.0"])
|
78
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
74
79
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
75
|
-
s.add_dependency(%q<jeweler>, ["~> 1.5.0
|
80
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0"])
|
76
81
|
s.add_dependency(%q<rcov>, [">= 0"])
|
77
82
|
s.add_dependency(%q<therubyracer>, [">= 0.7.5"])
|
78
83
|
s.add_dependency(%q<rspec>, ["~> 2.0.0"])
|
@@ -24,29 +24,36 @@
|
|
24
24
|
<mihai.bazon@gmail.com>
|
25
25
|
http://mihai.bazon.net/blog
|
26
26
|
|
27
|
-
Distributed under the
|
27
|
+
Distributed under the BSD license:
|
28
28
|
|
29
29
|
Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
30
30
|
Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
32
|
+
Redistribution and use in source and binary forms, with or without
|
33
|
+
modification, are permitted provided that the following conditions
|
34
|
+
are met:
|
35
|
+
|
36
|
+
* Redistributions of source code must retain the above
|
37
|
+
copyright notice, this list of conditions and the following
|
38
|
+
disclaimer.
|
39
|
+
|
40
|
+
* Redistributions in binary form must reproduce the above
|
41
|
+
copyright notice, this list of conditions and the following
|
42
|
+
disclaimer in the documentation and/or other materials
|
43
|
+
provided with the distribution.
|
44
|
+
|
45
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
46
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
47
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
48
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
49
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
50
|
+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
51
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
52
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
53
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
54
|
+
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
55
|
+
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
56
|
+
SUCH DAMAGE.
|
50
57
|
|
51
58
|
***********************************************************************/
|
52
59
|
|
@@ -118,7 +125,8 @@ var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([
|
|
118
125
|
"new",
|
119
126
|
"delete",
|
120
127
|
"throw",
|
121
|
-
"else"
|
128
|
+
"else",
|
129
|
+
"case"
|
122
130
|
]);
|
123
131
|
|
124
132
|
var KEYWORDS_ATOM = array_to_hash([
|
@@ -414,6 +422,7 @@ function tokenizer($TEXT, skip_comments) {
|
|
414
422
|
text = S.text.substring(S.pos, i),
|
415
423
|
tok = token("comment2", text);
|
416
424
|
S.pos = i + 2;
|
425
|
+
S.line += text.split("\n").length - 1;
|
417
426
|
S.newline_before = text.indexOf("\n") >= 0;
|
418
427
|
return tok;
|
419
428
|
});
|
@@ -1031,10 +1040,14 @@ function parse($TEXT, strict_mode, embed_tokens) {
|
|
1031
1040
|
if (!strict_mode && is("punc", "}"))
|
1032
1041
|
// allow trailing comma
|
1033
1042
|
break;
|
1043
|
+
var type = S.token.type;
|
1034
1044
|
var name = as_property_name();
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1045
|
+
if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) {
|
1046
|
+
a.push([ as_name(), function_(false), name ]);
|
1047
|
+
} else {
|
1048
|
+
expect(":");
|
1049
|
+
a.push([ name, expression(false) ]);
|
1050
|
+
}
|
1038
1051
|
}
|
1039
1052
|
next();
|
1040
1053
|
return as("object", a);
|
@@ -27,28 +27,35 @@
|
|
27
27
|
<mihai.bazon@gmail.com>
|
28
28
|
http://mihai.bazon.net/blog
|
29
29
|
|
30
|
-
Distributed under
|
30
|
+
Distributed under the BSD license:
|
31
31
|
|
32
32
|
Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
34
|
+
Redistribution and use in source and binary forms, with or without
|
35
|
+
modification, are permitted provided that the following conditions
|
36
|
+
are met:
|
37
|
+
|
38
|
+
* Redistributions of source code must retain the above
|
39
|
+
copyright notice, this list of conditions and the following
|
40
|
+
disclaimer.
|
41
|
+
|
42
|
+
* Redistributions in binary form must reproduce the above
|
43
|
+
copyright notice, this list of conditions and the following
|
44
|
+
disclaimer in the documentation and/or other materials
|
45
|
+
provided with the distribution.
|
46
|
+
|
47
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
48
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
49
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
50
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
51
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
52
|
+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
53
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
54
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
55
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
56
|
+
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
57
|
+
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
58
|
+
SUCH DAMAGE.
|
52
59
|
|
53
60
|
***********************************************************************/
|
54
61
|
|
@@ -58,13 +65,11 @@ var jsp = require("./parse-js"),
|
|
58
65
|
PRECEDENCE = jsp.PRECEDENCE,
|
59
66
|
OPERATORS = jsp.OPERATORS;
|
60
67
|
|
61
|
-
var sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util");
|
62
|
-
|
63
68
|
/* -----[ helper for AST traversal ]----- */
|
64
69
|
|
65
70
|
function ast_walker(ast) {
|
66
71
|
function _vardefs(defs) {
|
67
|
-
return defs
|
72
|
+
return MAP(defs, function(def){
|
68
73
|
var a = [ def[0] ];
|
69
74
|
if (def.length > 1)
|
70
75
|
a[1] = walk(def[1]);
|
@@ -82,12 +87,12 @@ function ast_walker(ast) {
|
|
82
87
|
return [ "name", name ];
|
83
88
|
},
|
84
89
|
"toplevel": function(statements) {
|
85
|
-
return [ "toplevel", statements
|
90
|
+
return [ "toplevel", MAP(statements, walk) ];
|
86
91
|
},
|
87
92
|
"block": function(statements) {
|
88
93
|
var out = [ "block" ];
|
89
94
|
if (statements != null)
|
90
|
-
out.push(statements
|
95
|
+
out.push(MAP(statements, walk));
|
91
96
|
return out;
|
92
97
|
},
|
93
98
|
"var": function(defs) {
|
@@ -99,21 +104,21 @@ function ast_walker(ast) {
|
|
99
104
|
"try": function(t, c, f) {
|
100
105
|
return [
|
101
106
|
"try",
|
102
|
-
t
|
103
|
-
c != null ? [ c[0], c[1]
|
104
|
-
f != null ? f
|
107
|
+
MAP(t, walk),
|
108
|
+
c != null ? [ c[0], MAP(c[1], walk) ] : null,
|
109
|
+
f != null ? MAP(f, walk) : null
|
105
110
|
];
|
106
111
|
},
|
107
112
|
"throw": function(expr) {
|
108
113
|
return [ "throw", walk(expr) ];
|
109
114
|
},
|
110
115
|
"new": function(ctor, args) {
|
111
|
-
return [ "new", walk(ctor), args
|
116
|
+
return [ "new", walk(ctor), MAP(args, walk) ];
|
112
117
|
},
|
113
118
|
"switch": function(expr, body) {
|
114
|
-
return [ "switch", walk(expr), body
|
119
|
+
return [ "switch", walk(expr), MAP(body, function(branch){
|
115
120
|
return [ branch[0] ? walk(branch[0]) : null,
|
116
|
-
branch[1]
|
121
|
+
MAP(branch[1], walk) ];
|
117
122
|
}) ];
|
118
123
|
},
|
119
124
|
"break": function(label) {
|
@@ -132,13 +137,13 @@ function ast_walker(ast) {
|
|
132
137
|
return [ "dot", walk(expr) ].concat(slice(arguments, 1));
|
133
138
|
},
|
134
139
|
"call": function(expr, args) {
|
135
|
-
return [ "call", walk(expr), args
|
140
|
+
return [ "call", walk(expr), MAP(args, walk) ];
|
136
141
|
},
|
137
142
|
"function": function(name, args, body) {
|
138
|
-
return [ "function", name, args.slice(), body
|
143
|
+
return [ "function", name, args.slice(), MAP(body, walk) ];
|
139
144
|
},
|
140
145
|
"defun": function(name, args, body) {
|
141
|
-
return [ "defun", name, args.slice(), body
|
146
|
+
return [ "defun", name, args.slice(), MAP(body, walk) ];
|
142
147
|
},
|
143
148
|
"if": function(conditional, t, e) {
|
144
149
|
return [ "if", walk(conditional), walk(t), walk(e) ];
|
@@ -171,21 +176,23 @@ function ast_walker(ast) {
|
|
171
176
|
return [ "sub", walk(expr), walk(subscript) ];
|
172
177
|
},
|
173
178
|
"object": function(props) {
|
174
|
-
return [ "object", props
|
175
|
-
return
|
179
|
+
return [ "object", MAP(props, function(p){
|
180
|
+
return p.length == 2
|
181
|
+
? [ p[0], walk(p[1]) ]
|
182
|
+
: [ p[0], walk(p[1]), p[2] ]; // get/set-ter
|
176
183
|
}) ];
|
177
184
|
},
|
178
185
|
"regexp": function(rx, mods) {
|
179
186
|
return [ "regexp", rx, mods ];
|
180
187
|
},
|
181
188
|
"array": function(elements) {
|
182
|
-
return [ "array", elements
|
189
|
+
return [ "array", MAP(elements, walk) ];
|
183
190
|
},
|
184
191
|
"stat": function(stat) {
|
185
192
|
return [ "stat", walk(stat) ];
|
186
193
|
},
|
187
194
|
"seq": function() {
|
188
|
-
return [ "seq" ].concat(slice(arguments)
|
195
|
+
return [ "seq" ].concat(MAP(slice(arguments), walk));
|
189
196
|
},
|
190
197
|
"label": function(name, block) {
|
191
198
|
return [ "label", name, walk(block) ];
|
@@ -225,13 +232,12 @@ function ast_walker(ast) {
|
|
225
232
|
save[i] = user[i];
|
226
233
|
user[i] = walkers[i];
|
227
234
|
}
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
else user[i] = save[i];
|
233
|
-
}
|
235
|
+
var ret = cont();
|
236
|
+
for (i in save) if (HOP(save, i)) {
|
237
|
+
if (!save[i]) delete user[i];
|
238
|
+
else user[i] = save[i];
|
234
239
|
}
|
240
|
+
return ret;
|
235
241
|
};
|
236
242
|
|
237
243
|
return {
|
@@ -377,8 +383,8 @@ function ast_add_scope(ast) {
|
|
377
383
|
|
378
384
|
function _lambda(name, args, body) {
|
379
385
|
return [ this[0], define(name), args, with_new_scope(function(){
|
380
|
-
args
|
381
|
-
return body
|
386
|
+
MAP(args, define);
|
387
|
+
return MAP(body, walk);
|
382
388
|
})];
|
383
389
|
};
|
384
390
|
|
@@ -392,17 +398,17 @@ function ast_add_scope(ast) {
|
|
392
398
|
s.uses_with = true;
|
393
399
|
},
|
394
400
|
"var": function(defs) {
|
395
|
-
defs
|
401
|
+
MAP(defs, function(d){ define(d[0]) });
|
396
402
|
},
|
397
403
|
"const": function(defs) {
|
398
|
-
defs
|
404
|
+
MAP(defs, function(d){ define(d[0]) });
|
399
405
|
},
|
400
406
|
"try": function(t, c, f) {
|
401
407
|
if (c != null) return [
|
402
408
|
"try",
|
403
|
-
t
|
404
|
-
[ define(c[0]), c[1]
|
405
|
-
f != null ? f
|
409
|
+
MAP(t, walk),
|
410
|
+
[ define(c[0]), MAP(c[1], walk) ],
|
411
|
+
f != null ? MAP(f, walk) : null
|
406
412
|
];
|
407
413
|
},
|
408
414
|
"name": function(name) {
|
@@ -424,7 +430,7 @@ function ast_add_scope(ast) {
|
|
424
430
|
// scopes where eval was detected and their parents
|
425
431
|
// are marked with uses_eval, unless they define the
|
426
432
|
// "eval" name.
|
427
|
-
having_eval
|
433
|
+
MAP(having_eval, function(scope){
|
428
434
|
if (!scope.has("eval")) while (scope) {
|
429
435
|
scope.uses_eval = true;
|
430
436
|
scope = scope.parent;
|
@@ -466,8 +472,8 @@ function ast_mangle(ast, do_toplevel) {
|
|
466
472
|
function _lambda(name, args, body) {
|
467
473
|
if (name) name = get_mangled(name);
|
468
474
|
body = with_scope(body.scope, function(){
|
469
|
-
args = args
|
470
|
-
return body
|
475
|
+
args = MAP(args, function(name){ return get_mangled(name) });
|
476
|
+
return MAP(body, walk);
|
471
477
|
});
|
472
478
|
return [ this[0], name, args, body ];
|
473
479
|
};
|
@@ -478,19 +484,32 @@ function ast_mangle(ast, do_toplevel) {
|
|
478
484
|
for (var i in s.names) if (HOP(s.names, i)) {
|
479
485
|
get_mangled(i, true);
|
480
486
|
}
|
481
|
-
|
482
|
-
|
487
|
+
var ret = cont();
|
488
|
+
ret.scope = s;
|
489
|
+
scope = _scope;
|
490
|
+
return ret;
|
483
491
|
};
|
484
492
|
|
485
493
|
function _vardefs(defs) {
|
486
|
-
return defs
|
494
|
+
return MAP(defs, function(d){
|
487
495
|
return [ get_mangled(d[0]), walk(d[1]) ];
|
488
496
|
});
|
489
497
|
};
|
490
498
|
|
491
499
|
return w.with_walkers({
|
492
500
|
"function": _lambda,
|
493
|
-
"defun":
|
501
|
+
"defun": function() {
|
502
|
+
// move function declarations to the top when
|
503
|
+
// they are not in some block.
|
504
|
+
var ast = _lambda.apply(this, arguments);
|
505
|
+
switch (w.parent()[0]) {
|
506
|
+
case "toplevel":
|
507
|
+
case "function":
|
508
|
+
case "defun":
|
509
|
+
return MAP.at_top(ast);
|
510
|
+
}
|
511
|
+
return ast;
|
512
|
+
},
|
494
513
|
"var": function(defs) {
|
495
514
|
return [ "var", _vardefs(defs) ];
|
496
515
|
},
|
@@ -502,13 +521,13 @@ function ast_mangle(ast, do_toplevel) {
|
|
502
521
|
},
|
503
522
|
"try": function(t, c, f) {
|
504
523
|
return [ "try",
|
505
|
-
t
|
506
|
-
c != null ? [ get_mangled(c[0]), c[1]
|
507
|
-
f != null ? f
|
524
|
+
MAP(t, walk),
|
525
|
+
c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null,
|
526
|
+
f != null ? MAP(f, walk) : null ];
|
508
527
|
},
|
509
528
|
"toplevel": function(body) {
|
510
529
|
return with_scope(this.scope, function(){
|
511
|
-
return [ "toplevel", body
|
530
|
+
return [ "toplevel", MAP(body, walk) ];
|
512
531
|
});
|
513
532
|
},
|
514
533
|
"for-in": function(has_var, name, obj, stat) {
|
@@ -530,9 +549,7 @@ function ast_mangle(ast, do_toplevel) {
|
|
530
549
|
- if (foo) return bar(); else something(); ==> {if(foo)return bar();something()}
|
531
550
|
]----- */
|
532
551
|
|
533
|
-
|
534
|
-
sys.debug(msg);
|
535
|
-
};
|
552
|
+
var warn = function(){};
|
536
553
|
|
537
554
|
function best_of(ast1, ast2) {
|
538
555
|
return gen_code(ast1).length > gen_code(ast2[0] == "stat" ? ast2[1] : ast2).length ? ast2 : ast1;
|
@@ -556,13 +573,7 @@ function negate(c) {
|
|
556
573
|
var not_c = [ "unary-prefix", "!", c ];
|
557
574
|
switch (c[0]) {
|
558
575
|
case "unary-prefix":
|
559
|
-
return c[1] == "!" ? c[2] :
|
560
|
-
case "atom":
|
561
|
-
switch (c[1]) {
|
562
|
-
case "false": return [ "num", 0 ];
|
563
|
-
case "true": return [ "num", 1 ];
|
564
|
-
}
|
565
|
-
break;
|
576
|
+
return c[1] == "!" ? c[2] : not_c;
|
566
577
|
case "binary":
|
567
578
|
var op = c[1], left = c[2], right = c[3];
|
568
579
|
switch (op) {
|
@@ -602,7 +613,16 @@ function ast_squeeze(ast, options) {
|
|
602
613
|
extra : false
|
603
614
|
});
|
604
615
|
|
605
|
-
var w = ast_walker(), walk = w.walk;
|
616
|
+
var w = ast_walker(), walk = w.walk, scope;
|
617
|
+
|
618
|
+
function with_scope(s, cont) {
|
619
|
+
var _scope = scope;
|
620
|
+
scope = s;
|
621
|
+
var ret = cont();
|
622
|
+
ret.scope = s;
|
623
|
+
scope = _scope;
|
624
|
+
return ret;
|
625
|
+
};
|
606
626
|
|
607
627
|
function is_constant(node) {
|
608
628
|
return node[0] == "string" || node[0] == "num";
|
@@ -667,7 +687,7 @@ function ast_squeeze(ast, options) {
|
|
667
687
|
|
668
688
|
function clone(obj) {
|
669
689
|
if (obj && obj.constructor == Array)
|
670
|
-
return obj
|
690
|
+
return MAP(obj, clone);
|
671
691
|
return obj;
|
672
692
|
};
|
673
693
|
|
@@ -690,7 +710,9 @@ function ast_squeeze(ast, options) {
|
|
690
710
|
};
|
691
711
|
|
692
712
|
function _lambda(name, args, body) {
|
693
|
-
return [ this[0], name, args,
|
713
|
+
return [ this[0], name, args, with_scope(body.scope, function(){
|
714
|
+
return tighten(MAP(body, walk), "lambda");
|
715
|
+
}) ];
|
694
716
|
};
|
695
717
|
|
696
718
|
// we get here for blocks that have been already transformed.
|
@@ -925,12 +947,14 @@ function ast_squeeze(ast, options) {
|
|
925
947
|
},
|
926
948
|
"if": make_if,
|
927
949
|
"toplevel": function(body) {
|
928
|
-
return [ "toplevel",
|
950
|
+
return [ "toplevel", with_scope(this.scope, function(){
|
951
|
+
return tighten(MAP(body, walk));
|
952
|
+
}) ];
|
929
953
|
},
|
930
954
|
"switch": function(expr, body) {
|
931
955
|
var last = body.length - 1;
|
932
|
-
return [ "switch", walk(expr), body
|
933
|
-
var block = tighten(branch[1]
|
956
|
+
return [ "switch", walk(expr), MAP(body, function(branch, i){
|
957
|
+
var block = tighten(MAP(branch[1], walk));
|
934
958
|
if (i == last && block.length > 0) {
|
935
959
|
var node = block[block.length - 1];
|
936
960
|
if (node[0] == "break" && !node[1])
|
@@ -942,7 +966,7 @@ function ast_squeeze(ast, options) {
|
|
942
966
|
"function": _lambda,
|
943
967
|
"defun": _lambda,
|
944
968
|
"block": function(body) {
|
945
|
-
if (body) return rmblock([ "block", tighten(body
|
969
|
+
if (body) return rmblock([ "block", tighten(MAP(body, walk)) ]);
|
946
970
|
},
|
947
971
|
"binary": function(op, left, right) {
|
948
972
|
left = walk(left);
|
@@ -975,17 +999,45 @@ function ast_squeeze(ast, options) {
|
|
975
999
|
"try": function(t, c, f) {
|
976
1000
|
return [
|
977
1001
|
"try",
|
978
|
-
tighten(t
|
979
|
-
c != null ? [ c[0], tighten(c[1]
|
980
|
-
f != null ? tighten(f
|
1002
|
+
tighten(MAP(t, walk)),
|
1003
|
+
c != null ? [ c[0], tighten(MAP(c[1], walk)) ] : null,
|
1004
|
+
f != null ? tighten(MAP(f, walk)) : null
|
981
1005
|
];
|
982
1006
|
},
|
983
1007
|
"unary-prefix": function(op, cond) {
|
984
|
-
if (op == "!")
|
1008
|
+
if (op == "!") {
|
1009
|
+
cond = walk(cond);
|
1010
|
+
if (cond[0] == "unary-prefix" && cond[1] == "!") {
|
1011
|
+
var p = w.parent();
|
1012
|
+
if (p[0] == "unary-prefix" && p[1] == "!")
|
1013
|
+
return cond[2];
|
1014
|
+
return [ "unary-prefix", "!", cond ];
|
1015
|
+
}
|
985
1016
|
return best_of(this, negate(cond));
|
1017
|
+
}
|
1018
|
+
},
|
1019
|
+
"name": function(name) {
|
1020
|
+
switch (name) {
|
1021
|
+
case "true": return [ "unary-prefix", "!", [ "num", 0 ]];
|
1022
|
+
case "false": return [ "unary-prefix", "!", [ "num", 1 ]];
|
1023
|
+
}
|
1024
|
+
},
|
1025
|
+
"new": function(ctor, args) {
|
1026
|
+
if (ctor[0] == "name" && ctor[1] == "Array" && !scope.has("Array")) {
|
1027
|
+
if (args.length != 1) {
|
1028
|
+
return [ "array", args ];
|
1029
|
+
} else {
|
1030
|
+
return [ "call", [ "name", "Array" ], args ];
|
1031
|
+
}
|
1032
|
+
}
|
1033
|
+
},
|
1034
|
+
"call": function(expr, args) {
|
1035
|
+
if (expr[0] == "name" && expr[1] == "Array" && args.length != 1 && !scope.has("Array")) {
|
1036
|
+
return [ "array", args ];
|
1037
|
+
}
|
986
1038
|
}
|
987
1039
|
}, function() {
|
988
|
-
return walk(ast);
|
1040
|
+
return walk(ast_add_scope(ast));
|
989
1041
|
});
|
990
1042
|
};
|
991
1043
|
|
@@ -1001,6 +1053,28 @@ var DOT_CALL_NO_PARENS = jsp.array_to_hash([
|
|
1001
1053
|
"regexp"
|
1002
1054
|
]);
|
1003
1055
|
|
1056
|
+
function make_string(str) {
|
1057
|
+
var dq = 0, sq = 0;
|
1058
|
+
str = str.replace(/[\\\b\f\n\r\t\x22\x27]/g, function(s){
|
1059
|
+
switch (s) {
|
1060
|
+
case "\\": return "\\\\";
|
1061
|
+
case "\b": return "\\b";
|
1062
|
+
case "\f": return "\\f";
|
1063
|
+
case "\n": return "\\n";
|
1064
|
+
case "\r": return "\\r";
|
1065
|
+
case "\t": return "\\t";
|
1066
|
+
case '"': ++dq; return '"';
|
1067
|
+
case "'": ++sq; return "'";
|
1068
|
+
}
|
1069
|
+
return s;
|
1070
|
+
});
|
1071
|
+
if (dq > sq) {
|
1072
|
+
return "'" + str.replace(/\x27/g, "\\'") + "'";
|
1073
|
+
} else {
|
1074
|
+
return '"' + str.replace(/\x22/g, '\\"') + '"';
|
1075
|
+
}
|
1076
|
+
};
|
1077
|
+
|
1004
1078
|
function gen_code(ast, beautify) {
|
1005
1079
|
if (beautify) beautify = defaults(beautify, {
|
1006
1080
|
indent_start : 0,
|
@@ -1120,10 +1194,10 @@ function gen_code(ast, beautify) {
|
|
1120
1194
|
},
|
1121
1195
|
"block": make_block,
|
1122
1196
|
"var": function(defs) {
|
1123
|
-
return "var " + add_commas(defs
|
1197
|
+
return "var " + add_commas(MAP(defs, make_1vardef)) + ";";
|
1124
1198
|
},
|
1125
1199
|
"const": function(defs) {
|
1126
|
-
return "const " + add_commas(defs
|
1200
|
+
return "const " + add_commas(MAP(defs, make_1vardef)) + ";";
|
1127
1201
|
},
|
1128
1202
|
"try": function(tr, ca, fi) {
|
1129
1203
|
var out = [ "try", make_block(tr) ];
|
@@ -1135,7 +1209,7 @@ function gen_code(ast, beautify) {
|
|
1135
1209
|
return add_spaces([ "throw", make(expr) ]) + ";";
|
1136
1210
|
},
|
1137
1211
|
"new": function(ctor, args) {
|
1138
|
-
args = args.length > 0 ? "(" + add_commas(args
|
1212
|
+
args = args.length > 0 ? "(" + add_commas(MAP(args, make)) + ")" : "";
|
1139
1213
|
return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){
|
1140
1214
|
var w = ast_walker(), has_call = {};
|
1141
1215
|
try {
|
@@ -1189,7 +1263,9 @@ function gen_code(ast, beautify) {
|
|
1189
1263
|
var f = make(func);
|
1190
1264
|
if (needs_parens(func))
|
1191
1265
|
f = "(" + f + ")";
|
1192
|
-
return f + "(" + add_commas(args
|
1266
|
+
return f + "(" + add_commas(MAP(args, function(expr){
|
1267
|
+
return parenthesize(expr, "seq");
|
1268
|
+
})) + ")";
|
1193
1269
|
},
|
1194
1270
|
"function": make_function,
|
1195
1271
|
"defun": make_function,
|
@@ -1265,7 +1341,12 @@ function gen_code(ast, beautify) {
|
|
1265
1341
|
if (props.length == 0)
|
1266
1342
|
return "{}";
|
1267
1343
|
return "{" + newline + with_indent(function(){
|
1268
|
-
return props
|
1344
|
+
return MAP(props, function(p){
|
1345
|
+
if (p.length == 3) {
|
1346
|
+
// getter/setter. The name is in p[0], the arg.list in p[1][2], the
|
1347
|
+
// body in p[1][3] and type ("get" / "set") in p[2].
|
1348
|
+
return indent(make_function(p[0], p[1][2], p[1][3], p[2]));
|
1349
|
+
}
|
1269
1350
|
var key = p[0], val = make(p[1]);
|
1270
1351
|
if (beautify && beautify.quote_keys) {
|
1271
1352
|
key = make_string(key);
|
@@ -1285,13 +1366,15 @@ function gen_code(ast, beautify) {
|
|
1285
1366
|
},
|
1286
1367
|
"array": function(elements) {
|
1287
1368
|
if (elements.length == 0) return "[]";
|
1288
|
-
return add_spaces([ "[", add_commas(elements
|
1369
|
+
return add_spaces([ "[", add_commas(MAP(elements, function(el){
|
1370
|
+
return parenthesize(el, "seq");
|
1371
|
+
})), "]" ]);
|
1289
1372
|
},
|
1290
1373
|
"stat": function(stmt) {
|
1291
1374
|
return make(stmt).replace(/;*\s*$/, ";");
|
1292
1375
|
},
|
1293
1376
|
"seq": function() {
|
1294
|
-
return add_commas(slice(arguments)
|
1377
|
+
return add_commas(MAP(slice(arguments), make));
|
1295
1378
|
},
|
1296
1379
|
"label": function(name, block) {
|
1297
1380
|
return add_spaces([ make_name(name), ":", make(block) ]);
|
@@ -1341,39 +1424,16 @@ function gen_code(ast, beautify) {
|
|
1341
1424
|
return make(th);
|
1342
1425
|
};
|
1343
1426
|
|
1344
|
-
function make_function(name, args, body) {
|
1345
|
-
var out = "function";
|
1427
|
+
function make_function(name, args, body, keyword) {
|
1428
|
+
var out = keyword || "function";
|
1346
1429
|
if (name) {
|
1347
1430
|
out += " " + make_name(name);
|
1348
1431
|
}
|
1349
|
-
out += "(" + add_commas(args
|
1432
|
+
out += "(" + add_commas(MAP(args, make_name)) + ")";
|
1350
1433
|
return add_spaces([ out, make_block(body) ]);
|
1351
1434
|
};
|
1352
1435
|
|
1353
|
-
function make_string(str) {
|
1354
|
-
// return '"' +
|
1355
|
-
// str.replace(/\x5c/g, "\\\\")
|
1356
|
-
// .replace(/\r?\n/g, "\\n")
|
1357
|
-
// .replace(/\t/g, "\\t")
|
1358
|
-
// .replace(/\r/g, "\\r")
|
1359
|
-
// .replace(/\f/g, "\\f")
|
1360
|
-
// .replace(/[\b]/g, "\\b")
|
1361
|
-
// .replace(/\x22/g, "\\\"")
|
1362
|
-
// .replace(/[\x00-\x1f]|[\x80-\xff]/g, function(c){
|
1363
|
-
// var hex = c.charCodeAt(0).toString(16);
|
1364
|
-
// if (hex.length < 2)
|
1365
|
-
// hex = "0" + hex;
|
1366
|
-
// return "\\x" + hex;
|
1367
|
-
// })
|
1368
|
-
// + '"';
|
1369
|
-
return JSON.stringify(str); // STILL cheating.
|
1370
|
-
};
|
1371
|
-
|
1372
1436
|
function make_name(name) {
|
1373
|
-
switch (name) {
|
1374
|
-
case "true": return beautify ? "true" : "!0";
|
1375
|
-
case "false": return beautify ? "false" : "!1";
|
1376
|
-
}
|
1377
1437
|
return name.toString();
|
1378
1438
|
};
|
1379
1439
|
|
@@ -1387,13 +1447,13 @@ function gen_code(ast, beautify) {
|
|
1387
1447
|
a.push(code);
|
1388
1448
|
}
|
1389
1449
|
}
|
1390
|
-
return a
|
1450
|
+
return MAP(a, indent);
|
1391
1451
|
};
|
1392
1452
|
|
1393
1453
|
function make_switch_block(body) {
|
1394
1454
|
var n = body.length;
|
1395
1455
|
if (n == 0) return "{}";
|
1396
|
-
return "{" + newline + body
|
1456
|
+
return "{" + newline + MAP(body, function(branch, i){
|
1397
1457
|
var has_body = branch[1].length > 0, code = with_indent(function(){
|
1398
1458
|
return indent(branch[0]
|
1399
1459
|
? add_spaces([ "case", make(branch[0]) + ":" ])
|
@@ -1471,6 +1531,24 @@ function HOP(obj, prop) {
|
|
1471
1531
|
return Object.prototype.hasOwnProperty.call(obj, prop);
|
1472
1532
|
};
|
1473
1533
|
|
1534
|
+
// some utilities
|
1535
|
+
|
1536
|
+
var MAP;
|
1537
|
+
|
1538
|
+
(function(){
|
1539
|
+
MAP = function(a, f, o) {
|
1540
|
+
var ret = [];
|
1541
|
+
for (var i = 0; i < a.length; ++i) {
|
1542
|
+
var val = f.call(o, a[i], i);
|
1543
|
+
if (val instanceof AtTop) ret.unshift(val.v);
|
1544
|
+
else ret.push(val);
|
1545
|
+
}
|
1546
|
+
return ret;
|
1547
|
+
};
|
1548
|
+
MAP.at_top = function(val) { return new AtTop(val) };
|
1549
|
+
function AtTop(val) { this.v = val };
|
1550
|
+
})();
|
1551
|
+
|
1474
1552
|
/* -----[ Exports ]----- */
|
1475
1553
|
|
1476
1554
|
exports.ast_walker = ast_walker;
|
@@ -1479,3 +1557,4 @@ exports.ast_squeeze = ast_squeeze;
|
|
1479
1557
|
exports.gen_code = gen_code;
|
1480
1558
|
exports.ast_add_scope = ast_add_scope;
|
1481
1559
|
exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more;
|
1560
|
+
exports.set_logger = function(logger) { warn = logger };
|
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: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ville Lautanala
|
@@ -15,8 +15,8 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
19
|
-
default_executable:
|
18
|
+
date: 2011-01-06 00:00:00 +02:00
|
19
|
+
default_executable: uglify
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
requirement: &id001 !ruby/object:Gem::Requirement
|
@@ -24,12 +24,12 @@ dependencies:
|
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
hash:
|
27
|
+
hash: 63
|
28
28
|
segments:
|
29
29
|
- 0
|
30
|
-
-
|
31
|
-
-
|
32
|
-
version: 0.
|
30
|
+
- 8
|
31
|
+
- 0
|
32
|
+
version: 0.8.0
|
33
33
|
type: :runtime
|
34
34
|
name: therubyracer
|
35
35
|
prerelease: false
|
@@ -40,12 +40,12 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
hash:
|
43
|
+
hash: 3
|
44
44
|
segments:
|
45
45
|
- 2
|
46
|
+
- 3
|
46
47
|
- 0
|
47
|
-
|
48
|
-
version: 2.0.0
|
48
|
+
version: 2.3.0
|
49
49
|
type: :development
|
50
50
|
name: rspec
|
51
51
|
prerelease: false
|
@@ -72,13 +72,12 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - ~>
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
hash:
|
75
|
+
hash: 3
|
76
76
|
segments:
|
77
77
|
- 1
|
78
78
|
- 5
|
79
79
|
- 0
|
80
|
-
|
81
|
-
version: 1.5.0.pre5
|
80
|
+
version: 1.5.0
|
82
81
|
type: :development
|
83
82
|
name: jeweler
|
84
83
|
prerelease: false
|
@@ -178,8 +177,8 @@ dependencies:
|
|
178
177
|
version_requirements: *id010
|
179
178
|
description:
|
180
179
|
email: lautis@gmail.com
|
181
|
-
executables:
|
182
|
-
|
180
|
+
executables:
|
181
|
+
- uglify
|
183
182
|
extensions: []
|
184
183
|
|
185
184
|
extra_rdoc_files:
|
@@ -194,7 +193,10 @@ files:
|
|
194
193
|
- README.rdoc
|
195
194
|
- Rakefile
|
196
195
|
- VERSION
|
196
|
+
- bin/uglify
|
197
197
|
- lib/uglifier.rb
|
198
|
+
- lib/uglifier/cli.rb
|
199
|
+
- lib/uglifier/node.rb
|
198
200
|
- spec/spec_helper.rb
|
199
201
|
- spec/uglifier_spec.rb
|
200
202
|
- uglifier.gemspec
|