ruby2js 4.0.0 → 4.0.5
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.
- 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
|