ruby2js 4.0.0 → 4.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +0 -1
- data/lib/ruby2js.rb +16 -3
- data/lib/ruby2js/converter.rb +31 -0
- data/lib/ruby2js/converter/args.rb +6 -1
- data/lib/ruby2js/converter/class.rb +3 -0
- data/lib/ruby2js/converter/class2.rb +8 -5
- data/lib/ruby2js/converter/def.rb +8 -2
- data/lib/ruby2js/converter/dstr.rb +3 -1
- data/lib/ruby2js/converter/for.rb +1 -1
- data/lib/ruby2js/converter/hash.rb +19 -1
- data/lib/ruby2js/converter/logical.rb +1 -1
- data/lib/ruby2js/converter/next.rb +10 -2
- data/lib/ruby2js/converter/redo.rb +14 -0
- data/lib/ruby2js/converter/return.rb +2 -1
- data/lib/ruby2js/converter/send.rb +30 -4
- data/lib/ruby2js/converter/taglit.rb +9 -2
- data/lib/ruby2js/converter/while.rb +1 -1
- data/lib/ruby2js/converter/whilepost.rb +1 -1
- data/lib/ruby2js/converter/xstr.rb +1 -2
- data/lib/ruby2js/filter/camelCase.rb +2 -0
- data/lib/ruby2js/filter/functions.rb +39 -11
- data/lib/ruby2js/filter/lit-element.rb +202 -0
- data/lib/ruby2js/filter/react.rb +6 -16
- data/lib/ruby2js/filter/require.rb +2 -6
- data/lib/ruby2js/filter/stimulus.rb +4 -2
- data/lib/ruby2js/filter/tagged_templates.rb +4 -2
- data/lib/ruby2js/jsx.rb +19 -1
- data/lib/ruby2js/rails.rb +6 -59
- data/lib/ruby2js/serializer.rb +16 -11
- data/lib/ruby2js/sprockets.rb +40 -0
- data/lib/ruby2js/version.rb +1 -1
- data/lib/tasks/README.md +4 -0
- data/lib/tasks/install/app/javascript/elements/index.js +2 -0
- data/lib/tasks/install/litelement.rb +9 -0
- data/lib/tasks/install/react.rb +2 -0
- data/lib/tasks/install/stimulus-sprockets.rb +32 -0
- data/lib/tasks/install/stimulus-webpacker.rb +5 -0
- data/lib/tasks/install/webpacker.rb +97 -0
- data/lib/tasks/nodetest.js +47 -0
- data/lib/tasks/ruby2js_tasks.rake +42 -0
- data/ruby2js.gemspec +1 -1
- metadata +18 -6
@@ -6,8 +6,15 @@ module Ruby2JS
|
|
6
6
|
# (dstr)
|
7
7
|
|
8
8
|
handle :taglit do |tag, *children|
|
9
|
-
|
10
|
-
|
9
|
+
begin
|
10
|
+
# disable autobinding in tag literals
|
11
|
+
save_autobind, @autobind = @autobind, false
|
12
|
+
|
13
|
+
put tag.children.first
|
14
|
+
parse_all(*children, join: '')
|
15
|
+
ensure
|
16
|
+
@autobind = save_autobind
|
17
|
+
end
|
11
18
|
end
|
12
19
|
end
|
13
20
|
end
|
@@ -11,7 +11,7 @@ module Ruby2JS
|
|
11
11
|
begin
|
12
12
|
next_token, @next_token = @next_token, :continue
|
13
13
|
|
14
|
-
puts 'do {';
|
14
|
+
puts 'do {'; redoable block; sput '} while ('; parse condition; put ')'
|
15
15
|
ensure
|
16
16
|
@next_token = next_token
|
17
17
|
end
|
@@ -5,9 +5,8 @@ module Ruby2JS
|
|
5
5
|
# (str 'a'))
|
6
6
|
|
7
7
|
handle :xstr do |*children|
|
8
|
-
str = eval capture { parse_all(*children) }
|
9
|
-
|
10
8
|
if @binding
|
9
|
+
str = eval capture { parse_all(*children) }
|
11
10
|
puts @binding.eval(str).to_s
|
12
11
|
else
|
13
12
|
raise SecurityError.new('Insecure operation, eval without binding option')
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'ruby2js'
|
2
|
+
|
2
3
|
require 'regexp_parser/scanner'
|
3
4
|
|
4
5
|
module Ruby2JS
|
@@ -7,7 +8,7 @@ module Ruby2JS
|
|
7
8
|
include SEXP
|
8
9
|
|
9
10
|
# require explicit opt-in to to class => constructor mapping
|
10
|
-
Filter.exclude :class
|
11
|
+
Filter.exclude :class, :call
|
11
12
|
|
12
13
|
VAR_TO_ASSIGN = {
|
13
14
|
lvar: :lvasgn,
|
@@ -23,7 +24,7 @@ module Ruby2JS
|
|
23
24
|
|
24
25
|
def on_send(node)
|
25
26
|
target, method, *args = node.children
|
26
|
-
return super if excluded?(method)
|
27
|
+
return super if excluded?(method) and method != :call
|
27
28
|
|
28
29
|
if [:max, :min].include? method and args.length == 0
|
29
30
|
if target.type == :array
|
@@ -36,13 +37,10 @@ module Ruby2JS
|
|
36
37
|
return super
|
37
38
|
end
|
38
39
|
|
39
|
-
elsif method == :call and target and
|
40
|
-
|
41
|
-
*args)
|
40
|
+
elsif method == :call and target and
|
41
|
+
(%i[ivar cvar].include?(target.type) or not excluded?(:call))
|
42
42
|
|
43
|
-
|
44
|
-
process S(:send, s(:attr, s(:self), :constructor),
|
45
|
-
"_#{target.children.first.to_s[2..-1]}", *args)
|
43
|
+
S(:call, process(target), nil, *process_all(args))
|
46
44
|
|
47
45
|
elsif method == :keys and args.length == 0 and node.is_method?
|
48
46
|
process S(:send, s(:const, nil, :Object), :keys, target)
|
@@ -212,10 +210,10 @@ module Ruby2JS
|
|
212
210
|
s(:block, s(:send, nil, :proc), s(:args, s(:arg, :s)),
|
213
211
|
s(:send, s(:lvar, :s), :slice, s(:int, 1))))
|
214
212
|
else
|
215
|
-
# str.match(/.../g).map(s => s.match(/.../).slice(1))
|
213
|
+
# (str.match(/.../g) || []).map(s => s.match(/.../).slice(1))
|
216
214
|
s(:block, s(:send,
|
217
|
-
s(:send, process(target), :match, gpattern), :
|
218
|
-
s(:args, s(:arg, :s)),
|
215
|
+
s(:or, s(:send, process(target), :match, gpattern), s(:array)),
|
216
|
+
:map), s(:args, s(:arg, :s)),
|
219
217
|
s(:return, s(:send, s(:send, s(:lvar, :s), :match, arg),
|
220
218
|
:slice, s(:int, 1))))
|
221
219
|
end
|
@@ -510,6 +508,36 @@ module Ruby2JS
|
|
510
508
|
elsif method == :floor and args.length == 0
|
511
509
|
process S(:send, s(:const, nil, :Math), :floor, target)
|
512
510
|
|
511
|
+
elsif method == :rand and target == nil
|
512
|
+
if args.length == 0
|
513
|
+
process S(:send!, s(:const, nil, :Math), :random)
|
514
|
+
elsif %i[irange erange].include? args.first.type
|
515
|
+
range = args.first
|
516
|
+
multiplier = s(:send, range.children.last, :-, range.children.first)
|
517
|
+
if range.children.all? {|child| child.type == :int}
|
518
|
+
multiplier = s(:int, range.children.last.children.last - range.children.first.children.last)
|
519
|
+
multiplier = s(:int, multiplier.children.first + 1) if range.type == :irange
|
520
|
+
elsif range.type == :irange
|
521
|
+
if multiplier.children.last.type == :int
|
522
|
+
diff = multiplier.children.last.children.last - 1
|
523
|
+
multiplier = s(:send, *multiplier.children[0..1], s(:int, diff))
|
524
|
+
multiplier = multiplier.children.first if diff == 0
|
525
|
+
multiplier = s(:send, multiplier.children[0], :+, s(:int, -diff)) if diff < 0
|
526
|
+
else
|
527
|
+
multiplier = s(:send, multiplier, :+, s(:int, 1))
|
528
|
+
end
|
529
|
+
end
|
530
|
+
raw = s(:send, s(:send, s(:const, nil, :Math), :random), :*, multiplier)
|
531
|
+
if range.children.first != s(:int, 0)
|
532
|
+
raw = s(:send, raw, :+, range.children.first)
|
533
|
+
end
|
534
|
+
process S(:send, nil, :parseInt, raw)
|
535
|
+
else
|
536
|
+
process S(:send, nil, :parseInt,
|
537
|
+
s(:send, s(:send, s(:const, nil, :Math), :random),
|
538
|
+
:*, args.first))
|
539
|
+
end
|
540
|
+
|
513
541
|
elsif method == :sum and args.length == 0
|
514
542
|
process S(:send, target, :reduce, s(:block, s(:send, nil, :proc),
|
515
543
|
s(:args, s(:arg, :a), s(:arg, :b)),
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'ruby2js'
|
2
|
+
|
3
|
+
module Ruby2JS
|
4
|
+
module Filter
|
5
|
+
module LitElement
|
6
|
+
include SEXP
|
7
|
+
extend SEXP
|
8
|
+
|
9
|
+
LITELEMENT_IMPORT = s(:import,
|
10
|
+
[s(:pair, s(:sym, :from), s(:str, "lit-element"))],
|
11
|
+
[s(:const, nil, :LitElement), s(:attr, nil, :css), s(:attr, nil, :html)])
|
12
|
+
|
13
|
+
def initialize(node)
|
14
|
+
super
|
15
|
+
@le_props = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def on_ivar(node)
|
19
|
+
return super unless @le_props&.include?(node.children.first)
|
20
|
+
s(:attr, s(:self), node.children.first.to_s[1..-1])
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_ivasgn(node)
|
24
|
+
return super unless @le_props&.include?(node.children.first)
|
25
|
+
s(:send, s(:self), node.children.first.to_s[1..-1]+'=',
|
26
|
+
process(node.children[1]))
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_class(node)
|
30
|
+
cname, inheritance, *body = node.children
|
31
|
+
return super unless inheritance == s(:const, nil, :LitElement)
|
32
|
+
|
33
|
+
@le_props = {}
|
34
|
+
le_walk(node)
|
35
|
+
|
36
|
+
prepend_list << LITELEMENT_IMPORT if modules_enabled?
|
37
|
+
|
38
|
+
nodes = body.dup
|
39
|
+
if nodes.length == 1 and nodes.first&.type == :begin
|
40
|
+
nodes = nodes.first.children.dup
|
41
|
+
end
|
42
|
+
|
43
|
+
# insert/update static get properties() {}
|
44
|
+
unless @le_props.empty?
|
45
|
+
values = nodes.find_index {|child|
|
46
|
+
child.type == :defs and child.children[0..1] == [s(:self), :properties]
|
47
|
+
}
|
48
|
+
|
49
|
+
if values == nil
|
50
|
+
nodes.unshift s(:defp, s(:self), :properties, s(:args), s(:return,
|
51
|
+
s(:hash, *@le_props.map {|name, type| s(:pair, s(:str, name.to_s[1..-1]),
|
52
|
+
s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String))))})))
|
53
|
+
elsif nodes[values].children[3].type == :hash
|
54
|
+
le_props = @le_props.map {|name, type|
|
55
|
+
[s(:sym, name.to_s[1..-1].to_sym),
|
56
|
+
s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String)))]
|
57
|
+
}.to_h.merge(
|
58
|
+
nodes[values].children[3].children.map {|pair| pair.children}.to_h
|
59
|
+
)
|
60
|
+
|
61
|
+
nodes[values] = nodes[values].updated(nil,
|
62
|
+
[*nodes[values].children[0..2], s(:hash,
|
63
|
+
*le_props.map{|name, value| s(:pair, name, value)})])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# render of a string is converted to a taglit :html
|
68
|
+
render = nodes.find_index {|child|
|
69
|
+
child.type == :def and child.children.first == :render
|
70
|
+
}
|
71
|
+
if render and %i[str dstr].include?(nodes[render].children[2].type)
|
72
|
+
nodes[render] = nodes[render].updated(:deff,
|
73
|
+
[*nodes[render].children[0..1],
|
74
|
+
s(:autoreturn, html_wrap(nodes[render].children[2]))])
|
75
|
+
end
|
76
|
+
|
77
|
+
# self.styles returning string is converted to a taglit :css
|
78
|
+
styles = nodes.find_index {|child|
|
79
|
+
child.type == :defs and child.children[0..1] == [s(:self), :styles]
|
80
|
+
}
|
81
|
+
if styles and %i[str dstr].include?(nodes[styles].children[3].type)
|
82
|
+
string = nodes[styles].children[3]
|
83
|
+
string = s(:dstr, string) if string.type == :str
|
84
|
+
children = string.children.dup
|
85
|
+
|
86
|
+
while children.length > 1 and children.last.type == :str and
|
87
|
+
children.last.children.last.strip == ''
|
88
|
+
children.pop
|
89
|
+
end
|
90
|
+
|
91
|
+
if children.last.type == :str
|
92
|
+
children << s(:str, children.pop.children.first.chomp)
|
93
|
+
end
|
94
|
+
|
95
|
+
nodes[styles] = nodes[styles].updated(nil,
|
96
|
+
[*nodes[styles].children[0..2],
|
97
|
+
s(:autoreturn, s(:taglit, s(:sym, :css),
|
98
|
+
s(:dstr, *children)))])
|
99
|
+
end
|
100
|
+
|
101
|
+
# insert super calls into initializer
|
102
|
+
initialize = nodes.find_index {|child|
|
103
|
+
child.type == :def and child.children.first == :initialize
|
104
|
+
}
|
105
|
+
if initialize and nodes[initialize].children.length == 3
|
106
|
+
statements = nodes[initialize].children[2].children
|
107
|
+
|
108
|
+
if statements.length == 1 and statements.children.first.type == :begin
|
109
|
+
statements = statements.children
|
110
|
+
end
|
111
|
+
|
112
|
+
unless statements.any? {|statement| %i[super zuper].include? statement.type}
|
113
|
+
nodes[initialize] = nodes[initialize].updated(nil,
|
114
|
+
[*nodes[initialize].children[0..1],
|
115
|
+
s(:begin, s(:zsuper), *statements)])
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
props = @le_props.keys.map {|prop| [prop.to_sym, s(:self)]}.to_h
|
120
|
+
|
121
|
+
nodes.unshift s(:defineProps, props)
|
122
|
+
|
123
|
+
nodes.pop unless nodes.last
|
124
|
+
|
125
|
+
node.updated(nil, [*node.children[0..1], s(:begin, *process_all(nodes))])
|
126
|
+
ensure
|
127
|
+
@le_props = nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def html_wrap(node)
|
131
|
+
if node.type == :str and node.children.first.strip.start_with? '<'
|
132
|
+
s(:taglit, s(:sym, :html), s(:dstr, node))
|
133
|
+
elsif node.type == :dstr
|
134
|
+
prefix = ''
|
135
|
+
node.children.each do |child|
|
136
|
+
break unless child.type == :str
|
137
|
+
prefix += child.children.first
|
138
|
+
end
|
139
|
+
|
140
|
+
return node unless prefix.strip.start_with? '<'
|
141
|
+
|
142
|
+
children = node.children.map do |child|
|
143
|
+
if child.type == :str
|
144
|
+
child
|
145
|
+
else
|
146
|
+
html_wrap(child)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
while children.length > 1 and children.last.type == :str and
|
151
|
+
children.last.children.last.strip == ''
|
152
|
+
children.pop
|
153
|
+
end
|
154
|
+
|
155
|
+
if children.last.type == :str
|
156
|
+
children << s(:str, children.pop.children.first.chomp)
|
157
|
+
end
|
158
|
+
|
159
|
+
s(:taglit, s(:sym, :html), node.updated(nil, children))
|
160
|
+
elsif node.type == :begin
|
161
|
+
node.updated(nil, node.children.map {|child| html_wrap(child)})
|
162
|
+
elsif node.type == :if
|
163
|
+
node.updated(nil, [node.children.first,
|
164
|
+
*node.children[1..2].map {|child| html_wrap(child)}])
|
165
|
+
elsif node.type == :block and
|
166
|
+
node.children.first.children[1] == :map
|
167
|
+
node.updated(nil, [*node.children[0..1],
|
168
|
+
html_wrap(node.children[2])])
|
169
|
+
else
|
170
|
+
node
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# analyze ivar usage
|
175
|
+
def le_walk(node)
|
176
|
+
node.children.each do |child|
|
177
|
+
next unless Parser::AST::Node === child
|
178
|
+
le_walk(child)
|
179
|
+
|
180
|
+
if child.type == :ivar
|
181
|
+
@le_props[child.children.first] ||= nil
|
182
|
+
elsif child.type == :ivasgn
|
183
|
+
@le_props[child.children.first] = case child.children.last.type
|
184
|
+
when :str, :dstr
|
185
|
+
:String
|
186
|
+
when :array
|
187
|
+
:Array
|
188
|
+
when :int, :float
|
189
|
+
:Number
|
190
|
+
when :true, :false
|
191
|
+
:Boolean
|
192
|
+
else
|
193
|
+
@le_props[child.children.first] || :Object
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
DEFAULTS.push LitElement
|
201
|
+
end
|
202
|
+
end
|
data/lib/ruby2js/filter/react.rb
CHANGED
@@ -26,8 +26,8 @@ module Ruby2JS
|
|
26
26
|
extend SEXP
|
27
27
|
|
28
28
|
REACT_IMPORTS = {
|
29
|
-
React: s(:import, ['
|
30
|
-
ReactDOM: s(:import, ['
|
29
|
+
React: s(:import, ['react'], s(:attr, nil, :React)),
|
30
|
+
ReactDOM: s(:import, ['react-dom'], s(:attr, nil, :ReactDOM))
|
31
31
|
}
|
32
32
|
|
33
33
|
# the following command can be used to generate ReactAttrs:
|
@@ -85,7 +85,6 @@ module Ruby2JS
|
|
85
85
|
@react_props = []
|
86
86
|
@react_methods = []
|
87
87
|
@react_filter_functions = false
|
88
|
-
@react_imports = false
|
89
88
|
@jsx = false
|
90
89
|
super
|
91
90
|
end
|
@@ -102,15 +101,6 @@ module Ruby2JS
|
|
102
101
|
@react_filter_functions = true
|
103
102
|
end
|
104
103
|
|
105
|
-
if \
|
106
|
-
(defined? Ruby2JS::Filter::ESM and
|
107
|
-
filters.include? Ruby2JS::Filter::ESM) or
|
108
|
-
(defined? Ruby2JS::Filter::CJS and
|
109
|
-
filters.include? Ruby2JS::Filter::CJS)
|
110
|
-
then
|
111
|
-
@react_imports = true
|
112
|
-
end
|
113
|
-
|
114
104
|
if \
|
115
105
|
defined? Ruby2JS::Filter::JSX and
|
116
106
|
filters.include? Ruby2JS::Filter::JSX
|
@@ -133,7 +123,7 @@ module Ruby2JS
|
|
133
123
|
inheritance == s(:const, s(:const, nil, :React), :Component) or
|
134
124
|
inheritance == s(:send, s(:const, nil, :React), :Component)
|
135
125
|
|
136
|
-
prepend_list << REACT_IMPORTS[:React] if
|
126
|
+
prepend_list << REACT_IMPORTS[:React] if modules_enabled?
|
137
127
|
|
138
128
|
# traverse down to actual list of class statements
|
139
129
|
if body.length == 1
|
@@ -222,7 +212,7 @@ module Ruby2JS
|
|
222
212
|
scan_events[node.children]
|
223
213
|
end
|
224
214
|
end
|
225
|
-
scan_events[body]
|
215
|
+
scan_events[body] unless es2015
|
226
216
|
|
227
217
|
# append statics (if any)
|
228
218
|
unless statics.empty?
|
@@ -323,7 +313,7 @@ module Ruby2JS
|
|
323
313
|
elsif mname == :render and not react_wunderbar_free(block, true)
|
324
314
|
if \
|
325
315
|
block.length != 1 or not block.last or
|
326
|
-
not [
|
316
|
+
not %i[send block xstr].include? block.last.type
|
327
317
|
then
|
328
318
|
if @jsx
|
329
319
|
while block.length == 1 and block.first.type == :begin
|
@@ -445,7 +435,7 @@ module Ruby2JS
|
|
445
435
|
node.children.first == s(:const, nil, :React) or
|
446
436
|
node.children.first == s(:const, nil, :ReactDOM)
|
447
437
|
then
|
448
|
-
if
|
438
|
+
if modules_enabled?
|
449
439
|
prepend_list << REACT_IMPORTS[node.children.first.children.last]
|
450
440
|
end
|
451
441
|
|
@@ -111,6 +111,7 @@ module Ruby2JS
|
|
111
111
|
|
112
112
|
importname = Pathname.new(filename).relative_path_from(Pathname.new(dirname)).to_s
|
113
113
|
importname = Pathname.new(@require_relative).join(importname).to_s
|
114
|
+
importname = "./#{importname}" unless importname.start_with? '.'
|
114
115
|
|
115
116
|
prepend_list << s(:import, importname, *imports)
|
116
117
|
|
@@ -152,12 +153,7 @@ module Ruby2JS
|
|
152
153
|
end
|
153
154
|
end
|
154
155
|
else
|
155
|
-
|
156
|
-
require_expr, @require_expr = @require_expr, true
|
157
|
-
super
|
158
|
-
ensure
|
159
|
-
@require_expr = require_expr
|
160
|
-
end
|
156
|
+
super
|
161
157
|
end
|
162
158
|
end
|
163
159
|
|
@@ -51,8 +51,10 @@ module Ruby2JS
|
|
51
51
|
@stim_classes = Set.new
|
52
52
|
stim_walk(node)
|
53
53
|
|
54
|
-
|
55
|
-
|
54
|
+
if modules_enabled?
|
55
|
+
prepend_list << (@options[:import_from_skypack] ?
|
56
|
+
STIMULUS_IMPORT_SKYPACK : STIMULUS_IMPORT)
|
57
|
+
end
|
56
58
|
|
57
59
|
nodes = body
|
58
60
|
if nodes.length == 1 and nodes.first&.type == :begin
|