js2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,123 @@
1
+
2
+ # ------------------------------------------------------------------------------
3
+ # AKA Tokens
4
+ # Hooks into Ragel
5
+ # this system could be more elegant, but we choose iteration over OO for
6
+ # efficiency
7
+ # HOOKS:
8
+ # << # to simulate <<
9
+ # ------------------------------------------------------------------------------
10
+ class JS2::AST::Nodes < Array
11
+ CLOSE_CLASS_LEVEL = 0
12
+ CLOSE_METHOD_LEVEL = 1
13
+
14
+ STATE_IDX = 0
15
+ STRING_IDX = 1
16
+ METHODS_IDX = 2
17
+
18
+ attr_accessor :stack, :filename, :line_number
19
+
20
+ def initialize (filename, str)
21
+ @cleanser = JS2::Decorator::Cleanser.new
22
+ @str = str
23
+ @filename = filename
24
+ @line_number = 0
25
+ @mems = []
26
+ @static_mems = []
27
+ @includes = []
28
+ @foreach = []
29
+ @comments = []
30
+ @curries = []
31
+ @in_class = false
32
+
33
+ @static = false
34
+ end
35
+
36
+
37
+ def do_next (type, begin_index, end_index, line)
38
+ val = @str[begin_index..end_index]
39
+
40
+ if type == :FOREACH
41
+ @foreach.push([begin_index, end_index, val])
42
+
43
+ elsif type == :CURRY
44
+ @curries.push([begin_index, end_index, val])
45
+
46
+ elsif type != :COMMENT
47
+ offset = 0
48
+ @foreach.reverse.each do |f|
49
+ s = f[0] - begin_index
50
+ e = f[1] - begin_index
51
+ before = val[s..e]
52
+ after = @cleanser.do_foreach(val[s..e])
53
+ offset += after.length - before.length
54
+
55
+ val[s..e] = after
56
+ end
57
+
58
+ @curries.reverse.each do |f|
59
+ s = f[0] - begin_index + offset
60
+ e = f[1] - begin_index + offset
61
+ val[s..e] = @cleanser.do_curry(val[s..e])
62
+ end
63
+
64
+ @foreach = []
65
+ @curries = []
66
+ end
67
+
68
+ if type == :METHOD
69
+ mems << JS2::AST::MethodNode.new(@filename, line, val)
70
+ reset_static
71
+
72
+ elsif type == :MEMBER
73
+ mems << JS2::AST::MemberNode.new(@filename, line, val)
74
+ reset_static
75
+
76
+ elsif type == :PROPERTY
77
+ @mems += JS2::AST::MethodNode.properties(@filename, line, val)
78
+ reset_static
79
+
80
+ elsif type == :CLASS
81
+ self << JS2::AST::ClassNode.new(@filename, line, val, @mems, @includes, @static_mems)
82
+
83
+ @static_mems = []
84
+ @mems = []
85
+ @includes = []
86
+
87
+ elsif type == :STUFF
88
+ self << JS2::AST::StuffNode.new(@filename, line, val)
89
+ @mems = []
90
+
91
+ elsif type == :COMMENT
92
+ mems << JS2::AST::CommentNode.new(@filename, line, val)
93
+
94
+ elsif type == :INCLUDE
95
+ @includes << JS2::AST::IncludeNode.new(@filename, line, val)
96
+
97
+ elsif type == :MODULE
98
+ self << JS2::AST::ModuleNode.new(@filename, line, val, @mems, [], @static_mems)
99
+
100
+ @static_mems = []
101
+ @mems = []
102
+ @includes = []
103
+ end
104
+
105
+ end
106
+
107
+ def mems
108
+ if @static
109
+ return @static_mems
110
+ else
111
+ return @mems
112
+ end
113
+ end
114
+
115
+ def set_static
116
+ @static = true
117
+ end
118
+
119
+ def reset_static
120
+ @static = false
121
+ end
122
+
123
+ end
@@ -0,0 +1,6 @@
1
+ class JS2::AST::StuffNode < JS2::AST::Node
2
+
3
+ def type
4
+ return :STUFF
5
+ end
6
+ end
data/lib/js2/config.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'yaml'
2
+
3
+ class JS2::Config
4
+ DEFAULTS = {
5
+ :framework => 'jquery',
6
+ :highlight => true,
7
+ :js2_dir => './js2',
8
+ :haml_engine_class => false,
9
+ :reference_dir => nil,
10
+ :write_dir => './public/javascripts',
11
+ :test_mode => false,
12
+ :js2_haml_dir => './js2',
13
+ :haml_dir => './app/views',
14
+ :selenium => { }
15
+ }
16
+
17
+ attr_accessor *DEFAULTS.keys
18
+
19
+ def initialize (hash = nil)
20
+ DEFAULTS.each_pair do |k,v|
21
+ self.send(k.to_s + '=', v)
22
+ end
23
+
24
+ load_hash(hash) if hash
25
+ end
26
+
27
+ def load_hash(hash)
28
+ DEFAULTS.keys.each do |k|
29
+ k = k.to_s
30
+ self.send(k + '=', hash[k]) if hash.has_key?(k)
31
+ end
32
+ end
33
+ end
34
+
data/lib/js2/daemon.rb ADDED
@@ -0,0 +1,35 @@
1
+ class JS2::Daemon
2
+ attr_accessor :haml_parser, :decorator, :parser, :universe, :haml_engine
3
+ INTERVAL = 1
4
+
5
+ def initialize (processor)
6
+ @processor = processor
7
+ end
8
+
9
+ def run (n=nil)
10
+ n ||= -1
11
+ i = 0
12
+ while i != n
13
+ i += 1
14
+
15
+ if check_files
16
+ yield if block_given?
17
+ else
18
+ sleep INTERVAL
19
+ end
20
+ end
21
+ end
22
+
23
+
24
+ private
25
+
26
+ def check_files
27
+ unless @processor.fh.need_update!
28
+ return false
29
+ end
30
+ @processor.write_files
31
+ rescue Exception => e
32
+ print e.to_s
33
+ print "Error in processing files"
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ class JS2::Decorator::App
2
+ def initialize (yaml_file)
3
+ @yaml = YAML.load_file(yaml_file)
4
+ end
5
+
6
+ end
7
+
@@ -0,0 +1,54 @@
1
+ class JS2::Decorator::Cleanser
2
+ @@enum = 0
3
+
4
+ def cleanse (str)
5
+ do_foreach(str)
6
+ end
7
+
8
+ def do_foreach (str)
9
+ # TODO support types
10
+ # TODO foreach:pair (var key,item in itemHash)
11
+ # TODO foreach:time (var i in 25)
12
+ # TODO foreach:key (var key in hash)
13
+ #
14
+ # SUPPORTED foreach (var item:i in items)
15
+ if m = str.match(%r|foreach\s*(:([^\s]))?\s*\(\s*var\s+([^\s\:]+)\s*(:?([^\s]))?\s+in\s+([^\s]+)\s*\)|)
16
+ type = m[2]
17
+ decl = m[3]
18
+ it = m[5] || ('it_' + (@@enum += 1).to_s)
19
+ arr = m[6]
20
+ len = it + '_len'
21
+
22
+ return "for (var #{decl},#{it}=0,#{len}=#{arr}.length; (#{decl}=#{arr}[#{it}]) || #{it}<#{len}; #{it}++)"
23
+ else
24
+ return str
25
+ end
26
+ end
27
+
28
+ def do_curry (str)
29
+
30
+ # decl code
31
+ if m = str.match(%r|^curry\s*([^\{]*)?(\{.*)$|m)
32
+ decl = m[1].strip
33
+ code = m[2]
34
+
35
+ scoped_vars = ''
36
+ args = ''
37
+
38
+ if m = decl.match(%r|with\s+\(([^)]*)\)|)
39
+ vars = m[1].split(',').collect { |v| v.strip }
40
+ scoped_vars = vars.collect { |v| v == 'this' ? 'self' : v }.join(', ')
41
+ in_scoped_vars = vars.join(', ')
42
+ end
43
+
44
+ if m = decl.match(%r|^\s*\(([^)]*)\)|)
45
+ args = m[1].strip
46
+ end
47
+
48
+
49
+ return %{(function (#{scoped_vars}) { return function (#{args}) #{code} })(#{in_scoped_vars})}
50
+ else
51
+ return str
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,127 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+
4
+ class JS2::Decorator::Standard
5
+ def draw_nodes (nodes)
6
+ str = ''
7
+ nodes.each do |node|
8
+ if node.is_a? JS2::AST::StuffNode
9
+ str << draw_stuff(node)
10
+ elsif node.is_a? JS2::AST::ClassNode
11
+ str << draw_class(node)
12
+ end
13
+ end
14
+ return str
15
+ end
16
+
17
+ def draw_classes (nodes)
18
+ ret = []
19
+ visited = Hash.new
20
+ funct = "function () { if (this.initialize) this.initialize.apply(this, arguments); }"
21
+ nodes.select { |n| n.is_a? JS2::AST::ClassNode }.sort { |a,b| a.name <=> b.name }.each do |n|
22
+ splitted = n.name.split(/\./)
23
+ running_name = []
24
+
25
+ splitted.each_with_index do |sub_name, i|
26
+ running_name << sub_name
27
+ name = running_name.join('.')
28
+ next if visited[name]
29
+ visited[name] = true
30
+
31
+ if i == 0
32
+ ret << "var #{name}=#{funct};"
33
+ else
34
+ ret << " #{name}=#{funct};"
35
+ end
36
+
37
+ end
38
+ end
39
+ return ret.join("\n")
40
+ end
41
+
42
+ private
43
+
44
+ def draw_method (node)
45
+ return %{ // #{node.filename}:#{node.line_number}
46
+ #{node.name}:function #{node.text}}
47
+ end
48
+
49
+ def draw_inherited (node)
50
+ return " #{node.name}: #{node.extends}.prototype.#{node.name}"
51
+ end
52
+
53
+ def draw_haml (node)
54
+ text = node.attrs.collect do |attr|
55
+ %{#{attr[0]}:#{attr[1]}}
56
+ end.join(',')
57
+ return %{ htmlCache: {#{text}}}
58
+ end
59
+
60
+ def draw_comment (node)
61
+ return ' ' + node.text
62
+ end
63
+
64
+ def draw_member (node)
65
+ if node.is_a? JS2::AST::MethodNode
66
+ return draw_method(node)
67
+ elsif node.is_a? JS2::AST::InheritedNode
68
+ return draw_inherited(node)
69
+ elsif node.is_a? JS2::AST::HamlNode
70
+ return draw_haml(node)
71
+ elsif node.is_a? JS2::AST::CommentNode
72
+ return draw_comment(node)
73
+ end
74
+
75
+ return %{ // #{node.filename}:#{node.line_number}
76
+ #{node.name}:#{node.text}}
77
+ end
78
+
79
+ def draw_class (node)
80
+ meta = ''
81
+ if node.extends
82
+ meta << "_parent:#{node.extends},"
83
+ end
84
+
85
+ members = node.members
86
+
87
+ meta << "_klass:'#{node.name}'"
88
+ meta << ',' unless members.empty?
89
+
90
+ handle_super = ''
91
+ node.super_hash.each_pair do |k,v|
92
+ handle_super << "#{node.name}.prototype.#{k}._super=#{v}.prototype.#{k};\n"
93
+ end
94
+
95
+ handle_static =
96
+ node.statics.collect do |s|
97
+ handle_static = "#{node.name}.#{s.name}=function #{s.text};"
98
+ end.join("\n")
99
+
100
+ member_js = [ ]
101
+ member_str = ''
102
+ members.each do |m|
103
+ member_str << draw_member(m)
104
+ if m.is_a? JS2::AST::CommentNode
105
+ member_str << "\n"
106
+ else
107
+ member_js.push(member_str)
108
+ member_str = ''
109
+ end
110
+ end
111
+
112
+ return <<-END
113
+ // #{node.filename}:#{node.line_number}
114
+ #{node.name}.prototype={#{meta}
115
+ #{member_js.join(",\n") }
116
+ };
117
+ // adding super
118
+ #{handle_super}
119
+ #{handle_static}
120
+ #{node.name}.prototype['class']=#{node.name};
121
+ END
122
+ end
123
+
124
+ def draw_stuff (node)
125
+ return node.text
126
+ end
127
+ end
@@ -0,0 +1,148 @@
1
+ require 'json'
2
+
3
+ class JS2::Decorator::Test < JS2::Decorator::Standard
4
+
5
+ def initialize ()
6
+ super()
7
+ @references = Hash.new
8
+ @in_class = false
9
+ end
10
+
11
+
12
+ def draw_class (node)
13
+ str = super(node)
14
+ @scope = node.name
15
+ @in_class = true
16
+ str = process_str(str)
17
+ @in_class = false
18
+ return str
19
+ end
20
+
21
+ def draw_stuff (node)
22
+ str = super(node)
23
+ @scope = nil
24
+ return process_str(str)
25
+ end
26
+
27
+ def write_references (dir)
28
+ @references.each_pair do |klass, val|
29
+ File.open(dir + '/' + klass + '.yml', 'w') do |out|
30
+ YAML.dump(val, out)
31
+ end
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def process_str (str)
38
+ lines = str.split(/\r?\n/)
39
+ processed = []
40
+
41
+ lines.each do |line|
42
+ # release comment and put it back in the queue
43
+ line.sub!(%r|\s*//@=\s*.*|) do |str|
44
+ if m = str.match(%r|(\s*)//@=\s*(.*)|)
45
+ m[1] + m[2]
46
+ else
47
+ str
48
+ end
49
+ end
50
+ end
51
+
52
+ while line = lines.shift
53
+
54
+ # scope is defined
55
+ if m = line.match(%r|^\s*//@\s*Scope\(([\w\.]+)\)|)
56
+ @scope = "Page.#{m[1]}"
57
+ processed.push(line)
58
+
59
+ elsif @scope
60
+ # if its a marker, reverse the next 2 lines
61
+ if new_line = process_marker(line, lines.first)
62
+ processed.push(lines.shift)
63
+ processed.push(new_line)
64
+
65
+ # var button = $('.button'); //@ Button
66
+ elsif new_lines = process_tailing_marker(line)
67
+
68
+ # reorder this and send it back through the loop
69
+ # but with the marker on top
70
+ lines.unshift(new_lines[1])
71
+ lines.unshift(new_lines[0])
72
+ next
73
+
74
+ # proceed as normal
75
+ else
76
+ processed.push(line)
77
+ end
78
+ else
79
+ processed.push(line)
80
+ end
81
+ end
82
+
83
+ return processed.join("\n")
84
+ end
85
+
86
+ def process_marker (line, next_line)
87
+ return false unless @scope && next_line
88
+
89
+ # //@ Foo // Bar
90
+ # //@+ Foo // Bar
91
+ # pad type marker comment
92
+ if m = line.match(%r|^(\s*)//@(\+)?\s+([^/]+)\s*(//(.*))?$|)
93
+
94
+ padding = m[1]
95
+ type = m[2]
96
+ marker = m[3].strip
97
+
98
+ whole_comment = m[4]
99
+ comment = (m[5] || '').strip
100
+
101
+ # get lval
102
+ lval_match = next_line.match(/^\s*(var)?\s*([^\s=;]+)\s*/)
103
+
104
+ return false unless lval_match
105
+ lval = lval_match[2]
106
+
107
+ # figure out what the lval should be
108
+ # Button(<jquery selector>)
109
+ key, find = parse_marker(marker)
110
+ finder = find ? find.to_json : "null"
111
+
112
+ # method to use for JS2.TEST.<addEle>(...)
113
+ insert = type == "+" ? 'appendVal' : 'addVal'
114
+
115
+ (@references[@scope] ||= {})[key] = comment
116
+ scope =
117
+ if @in_class
118
+ "this._klass"
119
+ else
120
+ @scope.to_json
121
+ end
122
+
123
+ return padding + %{TMP_SEL_MARKER = this.SEL_MARKER || JS2.SEL_MARKER; TMP_SEL_MARKER.#{insert}(#{scope}, #{key.to_json}, #{lval}, #{finder});}
124
+ else
125
+ return false
126
+ end
127
+ end
128
+
129
+ # split a trailing marker into 2 lines
130
+ def process_tailing_marker (line)
131
+ if m = line.match(%r|^(\s*)([^\s]+.*)(//@.*)$|)
132
+ new_line = m[1] + m[2]
133
+ marker = m[1] + m[3]
134
+ return [ marker, new_line ]
135
+ else
136
+ return false
137
+ end
138
+ end
139
+
140
+ def parse_marker (marker)
141
+ # key find
142
+ if m = marker.match(/^([^\(]+)\(([^\)]*)\)?/)
143
+ return [ m[1], m[2] ]
144
+ else
145
+ return [ marker, nil ]
146
+ end
147
+ end
148
+ end