js2 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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