ruby2js 4.1.7 → 4.2.0
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/bin/ruby2js +4 -0
- data/demo/ruby2js.rb +677 -0
- data/lib/ruby2js/converter/return.rb +1 -1
- data/lib/ruby2js/demo.rb +28 -0
- data/lib/ruby2js/filter/esm.rb +28 -14
- data/lib/ruby2js/filter/lit-element.rb +2 -218
- data/lib/ruby2js/filter/lit.rb +290 -0
- data/lib/ruby2js/filter/react.rb +11 -4
- data/lib/ruby2js/version.rb +2 -2
- data/lib/tasks/install/{litelement.rb → lit-webpacker.rb} +2 -2
- data/lib/tasks/install/stimulus-rollup.rb +2 -1
- data/lib/tasks/ruby2js_tasks.rake +13 -1
- data/ruby2js.gemspec +3 -1
- metadata +9 -5
data/lib/ruby2js/demo.rb
CHANGED
@@ -3,6 +3,34 @@ require 'ruby2js'
|
|
3
3
|
|
4
4
|
module Ruby2JS
|
5
5
|
module Demo
|
6
|
+
# convert {"[:foo, :Bar]" => "wee"} to {[:foo, :Bar] => "wee"}
|
7
|
+
def self.parse_stringified_symbol_keys(mapping_hash)
|
8
|
+
updated_mappings = {}
|
9
|
+
|
10
|
+
mapping_hash.each do |k, v|
|
11
|
+
next updated_mappings[k] = v unless k.is_a?(String) && k.start_with?("[:")
|
12
|
+
|
13
|
+
new_k = k.tr("[]", "").split(",").map! {|str| str.strip.delete_prefix(":").to_sym }.map(&:to_sym)
|
14
|
+
updated_mappings[new_k] = v
|
15
|
+
end
|
16
|
+
|
17
|
+
updated_mappings
|
18
|
+
end
|
19
|
+
|
20
|
+
# convert {"Foo" => "[:bar, :Baz]"} to {"Foo" => [:bar, :Baz]}
|
21
|
+
def self.parse_stringified_symbol_values(mapping_hash)
|
22
|
+
updated_mappings = {}
|
23
|
+
|
24
|
+
mapping_hash.each do |k, v|
|
25
|
+
next updated_mappings[k] = v unless v.is_a?(String) && v.start_with?("[:")
|
26
|
+
|
27
|
+
new_v = v.tr("[]", "").split(",").map! {|str| str.strip.delete_prefix(":").to_sym }.map(&:to_sym)
|
28
|
+
updated_mappings[k] = new_v
|
29
|
+
end
|
30
|
+
|
31
|
+
updated_mappings
|
32
|
+
end
|
33
|
+
|
6
34
|
def self.parse_autoimports(mappings)
|
7
35
|
autoimports = {}
|
8
36
|
|
data/lib/ruby2js/filter/esm.rb
CHANGED
@@ -13,16 +13,30 @@ module Ruby2JS
|
|
13
13
|
@esm_autoimports = options[:autoimports]
|
14
14
|
@esm_defs = options[:defs] || {}
|
15
15
|
@esm_explicit_tokens = Set.new
|
16
|
+
@esm_top = nil
|
17
|
+
|
18
|
+
# don't convert requires if Require filter is included
|
19
|
+
filters = options[:filters] || Filter::DEFAULTS
|
20
|
+
if \
|
21
|
+
defined? Ruby2JS::Filter::Require and
|
22
|
+
filters.include? Ruby2JS::Filter::Require
|
23
|
+
then
|
24
|
+
@esm_top = []
|
25
|
+
end
|
16
26
|
end
|
17
27
|
|
18
28
|
def process(node)
|
19
|
-
return super
|
29
|
+
return super if @esm_top
|
20
30
|
|
21
31
|
list = [node]
|
22
32
|
while list.length == 1 and list.first.type == :begin
|
23
33
|
list = list.first.children.dup
|
24
34
|
end
|
25
35
|
|
36
|
+
@esm_top = list
|
37
|
+
|
38
|
+
return super unless @esm_autoexports
|
39
|
+
|
26
40
|
replaced = []
|
27
41
|
list.map! do |child|
|
28
42
|
replacement = child
|
@@ -84,7 +98,7 @@ module Ruby2JS
|
|
84
98
|
target, method, *args = node.children
|
85
99
|
return super unless target.nil?
|
86
100
|
|
87
|
-
if method == :import
|
101
|
+
if method == :import or (method == :require and @esm_top&.include? @ast)
|
88
102
|
# don't do the conversion if the word import is followed by a paren
|
89
103
|
if node.loc.respond_to? :selector
|
90
104
|
selector = node.loc.selector
|
@@ -98,7 +112,7 @@ module Ruby2JS
|
|
98
112
|
# => import "file.css"
|
99
113
|
s(:import, args[0].children[0])
|
100
114
|
elsif args.length == 1 and \
|
101
|
-
|
115
|
+
args[0].type == :send and \
|
102
116
|
args[0].children[0].nil? and \
|
103
117
|
args[0].children[2].type == :send and \
|
104
118
|
args[0].children[2].children[0].nil? and \
|
@@ -152,17 +166,17 @@ module Ruby2JS
|
|
152
166
|
|
153
167
|
values = @esm_defs[node.children.last]
|
154
168
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
169
|
+
if values
|
170
|
+
values = values.map {|value|
|
171
|
+
if value.to_s.start_with? "@"
|
172
|
+
[value.to_s[1..-1].to_sym, s(:self)]
|
173
|
+
else
|
174
|
+
[value.to_sym, s(:autobind, s(:self))]
|
175
|
+
end
|
176
|
+
}.to_h
|
177
|
+
|
178
|
+
@namespace.defineProps values, [node.children.last]
|
179
|
+
end
|
166
180
|
end
|
167
181
|
|
168
182
|
super
|
@@ -1,218 +1,2 @@
|
|
1
|
-
|
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
|
-
return super unless node.children.length > 1
|
26
|
-
s(:send, s(:self), node.children.first.to_s[1..-1]+'=',
|
27
|
-
process(node.children[1]))
|
28
|
-
end
|
29
|
-
|
30
|
-
def on_op_asgn(node)
|
31
|
-
return super unless node.children.first.type == :ivasgn
|
32
|
-
var = node.children.first.children.first
|
33
|
-
return super unless @le_props&.include?(var)
|
34
|
-
super node.updated(nil, [s(:attr, s(:attr, nil, :this),
|
35
|
-
var.to_s[1..-1]), *node.children[1..-1]])
|
36
|
-
end
|
37
|
-
|
38
|
-
def on_class(node)
|
39
|
-
_, inheritance, *body = node.children
|
40
|
-
return super unless inheritance == s(:const, nil, :LitElement)
|
41
|
-
|
42
|
-
@le_props = {}
|
43
|
-
le_walk(node)
|
44
|
-
|
45
|
-
prepend_list << LITELEMENT_IMPORT if modules_enabled?
|
46
|
-
|
47
|
-
nodes = body.dup
|
48
|
-
if nodes.length == 1 and nodes.first&.type == :begin
|
49
|
-
nodes = nodes.first.children.dup
|
50
|
-
end
|
51
|
-
|
52
|
-
# insert/update static get properties() {}
|
53
|
-
unless @le_props.empty?
|
54
|
-
values = nodes.find_index {|child|
|
55
|
-
child.type == :defs and child.children[0..1] == [s(:self), :properties]
|
56
|
-
}
|
57
|
-
|
58
|
-
if values == nil
|
59
|
-
nodes.unshift s(:defp, s(:self), :properties, s(:args), s(:return,
|
60
|
-
s(:hash, *@le_props.map {|name, type| s(:pair, s(:str, name.to_s[1..-1]),
|
61
|
-
s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String))))})))
|
62
|
-
elsif nodes[values].children[3].type == :hash
|
63
|
-
le_props = @le_props.map {|name, type|
|
64
|
-
[s(:sym, name.to_s[1..-1].to_sym),
|
65
|
-
s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String)))]
|
66
|
-
}.to_h.merge(
|
67
|
-
nodes[values].children[3].children.map {|pair| pair.children}.to_h
|
68
|
-
)
|
69
|
-
|
70
|
-
nodes[values] = nodes[values].updated(nil,
|
71
|
-
[*nodes[values].children[0..2], s(:hash,
|
72
|
-
*le_props.map{|name, value| s(:pair, name, value)})])
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# render of a string is converted to a taglit :html
|
77
|
-
render = nodes.find_index {|child|
|
78
|
-
child&.type == :def and child.children.first == :render
|
79
|
-
}
|
80
|
-
if render and %i[str dstr].include?(nodes[render].children[2]&.type)
|
81
|
-
nodes[render] = nodes[render].updated(:deff,
|
82
|
-
[*nodes[render].children[0..1],
|
83
|
-
s(:autoreturn, html_wrap(nodes[render].children[2]))])
|
84
|
-
end
|
85
|
-
|
86
|
-
# self.styles returning string is converted to a taglit :css
|
87
|
-
styles = nodes.find_index {|child|
|
88
|
-
child&.type == :defs and child.children[0..1] == [s(:self), :styles]
|
89
|
-
}
|
90
|
-
if styles and %i[str dstr].include?(nodes[styles].children[3]&.type)
|
91
|
-
string = nodes[styles].children[3]
|
92
|
-
string = s(:dstr, string) if string.type == :str
|
93
|
-
children = string.children.dup
|
94
|
-
|
95
|
-
while children.length > 1 and children.last.type == :str and
|
96
|
-
children.last.children.last.strip == ''
|
97
|
-
children.pop
|
98
|
-
end
|
99
|
-
|
100
|
-
if children.last.type == :str
|
101
|
-
children << s(:str, children.pop.children.first.chomp)
|
102
|
-
end
|
103
|
-
|
104
|
-
nodes[styles] = nodes[styles].updated(nil,
|
105
|
-
[*nodes[styles].children[0..2],
|
106
|
-
s(:autoreturn, s(:taglit, s(:sym, :css),
|
107
|
-
s(:dstr, *children)))])
|
108
|
-
end
|
109
|
-
|
110
|
-
# insert super calls into initializer
|
111
|
-
initialize = nodes.find_index {|child|
|
112
|
-
child&.type == :def and child.children.first == :initialize
|
113
|
-
}
|
114
|
-
if initialize and nodes[initialize].children.length == 3
|
115
|
-
statements = nodes[initialize].children[2..-1]
|
116
|
-
|
117
|
-
if statements.length == 1 and statements.first.type == :begin
|
118
|
-
statements = statements.first.children
|
119
|
-
end
|
120
|
-
|
121
|
-
unless statements.any? {|statement| %i[super zuper].include? statement.type}
|
122
|
-
nodes[initialize] = nodes[initialize].updated(nil,
|
123
|
-
[*nodes[initialize].children[0..1],
|
124
|
-
s(:begin, s(:zsuper), *statements)])
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
props = @le_props.keys.map {|prop| [prop.to_sym, s(:self)]}.to_h
|
129
|
-
|
130
|
-
nodes.unshift s(:defineProps, props)
|
131
|
-
|
132
|
-
nodes.pop unless nodes.last
|
133
|
-
|
134
|
-
node.updated(nil, [*node.children[0..1], s(:begin, *process_all(nodes))])
|
135
|
-
ensure
|
136
|
-
@le_props = nil
|
137
|
-
end
|
138
|
-
|
139
|
-
def html_wrap(node)
|
140
|
-
if node.type == :str and node.children.first.strip.start_with? '<'
|
141
|
-
s(:taglit, s(:sym, :html), s(:dstr, node))
|
142
|
-
elsif node.type == :dstr
|
143
|
-
prefix = ''
|
144
|
-
node.children.each do |child|
|
145
|
-
break unless child.type == :str
|
146
|
-
prefix += child.children.first
|
147
|
-
end
|
148
|
-
|
149
|
-
return node unless prefix.strip.start_with? '<'
|
150
|
-
|
151
|
-
children = node.children.map do |child|
|
152
|
-
if child.type == :str
|
153
|
-
child
|
154
|
-
else
|
155
|
-
html_wrap(child)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
while children.length > 1 and children.last.type == :str and
|
160
|
-
children.last.children.last.strip == ''
|
161
|
-
children.pop
|
162
|
-
end
|
163
|
-
|
164
|
-
if children.last.type == :str
|
165
|
-
children << s(:str, children.pop.children.first.chomp)
|
166
|
-
end
|
167
|
-
|
168
|
-
s(:taglit, s(:sym, :html), node.updated(nil, children))
|
169
|
-
elsif node.type == :begin
|
170
|
-
node.updated(nil, node.children.map {|child| html_wrap(child)})
|
171
|
-
elsif node.type == :if
|
172
|
-
node.updated(nil, [node.children.first,
|
173
|
-
*node.children[1..2].map {|child| html_wrap(child)}])
|
174
|
-
elsif node.type == :block and
|
175
|
-
node.children.first.children[1] == :map
|
176
|
-
node.updated(nil, [*node.children[0..1],
|
177
|
-
html_wrap(node.children[2])])
|
178
|
-
else
|
179
|
-
node
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
# analyze ivar usage
|
184
|
-
def le_walk(node)
|
185
|
-
node.children.each do |child|
|
186
|
-
next unless child.is_a? Parser::AST::Node
|
187
|
-
|
188
|
-
if child.type == :ivar
|
189
|
-
@le_props[child.children.first] ||= nil
|
190
|
-
elsif child.type == :ivasgn || child.type == :op_asgn
|
191
|
-
prop = child.children.first
|
192
|
-
unless prop.is_a? Symbol
|
193
|
-
prop = prop.children.first if prop.type == :ivasgn
|
194
|
-
next unless prop.is_a? Symbol
|
195
|
-
end
|
196
|
-
|
197
|
-
@le_props[prop] = case child.children.last.type
|
198
|
-
when :str, :dstr
|
199
|
-
:String
|
200
|
-
when :array
|
201
|
-
:Array
|
202
|
-
when :int, :float
|
203
|
-
:Number
|
204
|
-
when :true, :false
|
205
|
-
:Boolean
|
206
|
-
else
|
207
|
-
@le_props[prop] || :Object
|
208
|
-
end
|
209
|
-
else
|
210
|
-
le_walk(child)
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
DEFAULTS.push LitElement
|
217
|
-
end
|
218
|
-
end
|
1
|
+
# for backwards compatibility
|
2
|
+
require_relative './lit'
|
@@ -0,0 +1,290 @@
|
|
1
|
+
require 'ruby2js'
|
2
|
+
|
3
|
+
module Ruby2JS
|
4
|
+
module Filter
|
5
|
+
module Lit
|
6
|
+
include SEXP
|
7
|
+
extend SEXP
|
8
|
+
|
9
|
+
LITELEMENT_IMPORT = s(:import,
|
10
|
+
[s(:pair, s(:sym, :from), s(:str, "lit"))],
|
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
|
+
process 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
|
+
return super unless node.children.length > 1
|
26
|
+
|
27
|
+
process s(:send, s(:self), node.children.first.to_s[1..-1]+'=',
|
28
|
+
process(node.children[1]))
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_op_asgn(node)
|
32
|
+
return super unless node.children.first.type == :ivasgn
|
33
|
+
var = node.children.first.children.first
|
34
|
+
return super unless @le_props&.include?(var)
|
35
|
+
super node.updated(nil, [s(:attr, s(:attr, nil, :this),
|
36
|
+
var.to_s[1..-1]), *node.children[1..-1]])
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_class(node)
|
40
|
+
class_name, inheritance, *body = node.children
|
41
|
+
return super unless inheritance == s(:const, nil, :LitElement)
|
42
|
+
|
43
|
+
@le_props = {}
|
44
|
+
le_walk(node)
|
45
|
+
|
46
|
+
prepend_list << LITELEMENT_IMPORT if modules_enabled?
|
47
|
+
|
48
|
+
nodes = body.dup
|
49
|
+
if nodes.length == 1 and nodes.first&.type == :begin
|
50
|
+
nodes = nodes.first.children.dup
|
51
|
+
end
|
52
|
+
|
53
|
+
# insert/update static get properties() {}
|
54
|
+
unless @le_props.empty?
|
55
|
+
values = nodes.find_index {|child|
|
56
|
+
(child.type == :defs and child.children[0..1] == [s(:self), :properties]) or
|
57
|
+
(child.type == :send and child.children[0..1] == [s(:self), :properties=])
|
58
|
+
}
|
59
|
+
|
60
|
+
if values == nil
|
61
|
+
if es2022
|
62
|
+
nodes.unshift process(s(:casgn, nil, :properties,
|
63
|
+
s(:hash, *@le_props.map {|name, type| s(:pair, s(:sym, name.to_s[1..-1]),
|
64
|
+
s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String))))})))
|
65
|
+
else
|
66
|
+
nodes.unshift process(s(:defp, s(:self), :properties, s(:args), s(:return,
|
67
|
+
s(:hash, *@le_props.map {|name, type| s(:pair, s(:sym, name.to_s[1..-1]),
|
68
|
+
s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String))))}))))
|
69
|
+
end
|
70
|
+
elsif nodes[values].children.last.type == :hash
|
71
|
+
le_props = @le_props.map {|name, type|
|
72
|
+
[s(:sym, name.to_s[1..-1].to_sym),
|
73
|
+
s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String)))]
|
74
|
+
}.to_h.merge(
|
75
|
+
nodes[values].children.last.children.map {|pair| pair.children}.to_h
|
76
|
+
)
|
77
|
+
|
78
|
+
nodes[values] = nodes[values].updated(nil,
|
79
|
+
[*nodes[values].children[0..-2], s(:hash,
|
80
|
+
*le_props.map{|name, value| s(:pair, name, value)})])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# customElement is converted to customElements.define
|
85
|
+
customElement = nodes.find_index {|child|
|
86
|
+
child&.type == :send and (child.children[0..1] == [nil, :customElement] || child.children[0..1] == [nil, :custom_element])
|
87
|
+
}
|
88
|
+
if customElement and nodes[customElement].children.length == 3
|
89
|
+
nodes[customElement] = nodes[customElement].updated(nil,
|
90
|
+
[s(:attr, nil, :customElements), :define,
|
91
|
+
nodes[customElement].children.last, class_name])
|
92
|
+
end
|
93
|
+
|
94
|
+
# render of a string is converted to a taglit :html
|
95
|
+
render = nodes.find_index {|child|
|
96
|
+
child&.type == :def and child.children.first == :render
|
97
|
+
}
|
98
|
+
if render and %i[str dstr begin if block].include?(nodes[render].children[2]&.type)
|
99
|
+
nodes[render] = nodes[render].updated(:deff,
|
100
|
+
[*nodes[render].children[0..1],
|
101
|
+
s(:autoreturn, html_wrap(nodes[render].children[2]))])
|
102
|
+
end
|
103
|
+
|
104
|
+
# self.styles returning string is converted to a taglit :css
|
105
|
+
styles = nodes.find_index {|child|
|
106
|
+
(child&.type == :ivasgn and child.children[0] == :@styles) or
|
107
|
+
(child&.type == :defs and child.children[0..1] == [s(:self), :styles]) or
|
108
|
+
(child&.type == :send and child.children[0..1] == [s(:self), :styles=])
|
109
|
+
}
|
110
|
+
if styles and %i[str dstr].include?(nodes[styles].children.last&.type)
|
111
|
+
string = nodes[styles].children.last
|
112
|
+
string = s(:dstr, string) if string.type == :str
|
113
|
+
children = string.children.dup
|
114
|
+
|
115
|
+
while children.length > 1 and children.last.type == :str and
|
116
|
+
children.last.children.last.strip == ''
|
117
|
+
children.pop
|
118
|
+
end
|
119
|
+
|
120
|
+
if children.last.type == :str
|
121
|
+
children << s(:str, children.pop.children.first.chomp)
|
122
|
+
end
|
123
|
+
|
124
|
+
if es2022
|
125
|
+
nodes[styles] = nodes[styles].updated(:casgn,
|
126
|
+
[nil, :styles, s(:taglit, s(:sym, :css),
|
127
|
+
s(:dstr, *children))])
|
128
|
+
else
|
129
|
+
nodes[styles] = nodes[styles].updated(:defp,
|
130
|
+
[s(:self), :styles, s(:args),
|
131
|
+
s(:autoreturn, s(:taglit, s(:sym, :css),
|
132
|
+
s(:dstr, *children)))])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# insert super calls into initializer
|
137
|
+
initialize = nodes.find_index {|child|
|
138
|
+
child&.type == :def and child.children.first == :initialize
|
139
|
+
}
|
140
|
+
if initialize and nodes[initialize].children.length == 3
|
141
|
+
statements = nodes[initialize].children[2..-1]
|
142
|
+
|
143
|
+
if statements.length == 1 and statements.first.type == :begin
|
144
|
+
statements = statements.first.children
|
145
|
+
end
|
146
|
+
|
147
|
+
unless statements.any? {|statement| %i[super zuper].include? statement.type}
|
148
|
+
nodes[initialize] = nodes[initialize].updated(nil,
|
149
|
+
[*nodes[initialize].children[0..1],
|
150
|
+
s(:begin, s(:zsuper), *statements)])
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# props/methods inherited from LitElement
|
155
|
+
props = {
|
156
|
+
hasUpdated: s(:self),
|
157
|
+
performUpdate: s(:autobind, s(:self)),
|
158
|
+
renderRoot: s(:self),
|
159
|
+
requestUpdate: s(:autobind, s(:self)),
|
160
|
+
shadowRoot: s(:self),
|
161
|
+
updateComplete: s(:self),
|
162
|
+
}
|
163
|
+
|
164
|
+
# local props
|
165
|
+
props.merge! @le_props.keys.map {|prop| [prop.to_sym, s(:self)]}.to_h
|
166
|
+
|
167
|
+
nodes.unshift s(:defineProps, props)
|
168
|
+
|
169
|
+
nodes.pop unless nodes.last
|
170
|
+
|
171
|
+
node.updated(nil, [*node.children[0..1], s(:begin, *process_all(nodes))])
|
172
|
+
ensure
|
173
|
+
@le_props = nil
|
174
|
+
end
|
175
|
+
|
176
|
+
def html_wrap(node)
|
177
|
+
return node unless node.is_a?(Parser::AST::Node)
|
178
|
+
|
179
|
+
if node.type == :str and node.children.first.strip.start_with? '<'
|
180
|
+
s(:taglit, s(:sym, :html), s(:dstr, node))
|
181
|
+
elsif node.type == :dstr
|
182
|
+
prefix = ''
|
183
|
+
node.children.each do |child|
|
184
|
+
break unless child.type == :str
|
185
|
+
prefix += child.children.first
|
186
|
+
end
|
187
|
+
|
188
|
+
return node unless prefix.strip.start_with? '<'
|
189
|
+
|
190
|
+
children = node.children.map do |child|
|
191
|
+
if child.type == :str
|
192
|
+
child
|
193
|
+
else
|
194
|
+
html_wrap(child)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
while children.length > 1 and children.last.type == :str and
|
199
|
+
children.last.children.last.strip == ''
|
200
|
+
children.pop
|
201
|
+
end
|
202
|
+
|
203
|
+
if children.last.type == :str
|
204
|
+
children << s(:str, children.pop.children.first.chomp)
|
205
|
+
end
|
206
|
+
|
207
|
+
s(:taglit, s(:sym, :html), node.updated(nil, children))
|
208
|
+
elsif node.type == :begin
|
209
|
+
node.updated(nil, node.children.map {|child| html_wrap(child)})
|
210
|
+
elsif node.type == :if
|
211
|
+
node.updated(nil, [node.children.first,
|
212
|
+
*node.children[1..2].map {|child| html_wrap(child)}])
|
213
|
+
elsif node.type == :block and
|
214
|
+
node.children.first.children[1] == :map
|
215
|
+
node.updated(nil, [*node.children[0..1],
|
216
|
+
html_wrap(node.children[2])])
|
217
|
+
else
|
218
|
+
node
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def on_def(node)
|
223
|
+
node = super
|
224
|
+
return node if [:constructor, :initialize].include?(node.children.first)
|
225
|
+
|
226
|
+
children = node.children[1..-1]
|
227
|
+
|
228
|
+
node.updated nil, [node.children[0], children.first,
|
229
|
+
*(children[1..-1].map {|child| html_wrap(child) })]
|
230
|
+
end
|
231
|
+
|
232
|
+
# analyze ivar usage
|
233
|
+
def le_walk(node)
|
234
|
+
node.children.each do |child|
|
235
|
+
next unless child.is_a? Parser::AST::Node
|
236
|
+
|
237
|
+
if child.type == :ivar
|
238
|
+
next if child.children.first.to_s.start_with?("@_")
|
239
|
+
|
240
|
+
@le_props[child.children.first] ||= nil
|
241
|
+
elsif child.type == :ivasgn || child.type == :op_asgn
|
242
|
+
prop = child.children.first
|
243
|
+
unless prop.is_a? Symbol
|
244
|
+
prop = prop.children.first if prop.type == :ivasgn
|
245
|
+
next unless prop.is_a? Symbol
|
246
|
+
end
|
247
|
+
|
248
|
+
next if prop.to_s.start_with?("@_")
|
249
|
+
|
250
|
+
@le_props[prop] = case child.children.last.type
|
251
|
+
when :str, :dstr
|
252
|
+
:String
|
253
|
+
when :array
|
254
|
+
:Array
|
255
|
+
when :int, :float
|
256
|
+
:Number
|
257
|
+
when :true, :false
|
258
|
+
:Boolean
|
259
|
+
else
|
260
|
+
@le_props[prop] || :Object
|
261
|
+
end
|
262
|
+
else
|
263
|
+
le_walk(child)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def on_send(node)
|
269
|
+
target, method, *args = node.children
|
270
|
+
|
271
|
+
return super if target
|
272
|
+
return super unless %i{query queryAll queryAsync}.include? method
|
273
|
+
return super unless args.length == 1
|
274
|
+
|
275
|
+
result = s(:csend, s(:attr, s(:self), :renderRoot),
|
276
|
+
(method == :query ? 'querySelector' : 'querySelectorAll'),
|
277
|
+
args.first)
|
278
|
+
|
279
|
+
if method == :queryAsync
|
280
|
+
result = s(:block, s(:send, s(:attr, s(:self), :updateComplete),
|
281
|
+
:then), s(:args), result)
|
282
|
+
end
|
283
|
+
|
284
|
+
result
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
DEFAULTS.push Lit
|
289
|
+
end
|
290
|
+
end
|
data/lib/ruby2js/filter/react.rb
CHANGED
@@ -41,9 +41,16 @@ module Ruby2JS
|
|
41
41
|
#
|
42
42
|
def self.genAttrs
|
43
43
|
unless RUBY_ENGINE == 'opal'
|
44
|
-
require '
|
45
|
-
|
46
|
-
|
44
|
+
require 'nokogiri'
|
45
|
+
require 'uri'
|
46
|
+
require 'net/http'
|
47
|
+
|
48
|
+
page = 'https://reactjs.org/docs/dom-elements.html'
|
49
|
+
uri = URI.parse(page)
|
50
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
51
|
+
http.use_ssl = true
|
52
|
+
data = http.get(uri.request_uri).body
|
53
|
+
doc = Nokogiri::HTML5::Document.parse(data)
|
47
54
|
|
48
55
|
# delete contents of page prior to the list of supported attributes
|
49
56
|
attrs = doc.at('a[name=supported-attributes]')
|
@@ -51,7 +58,7 @@ module Ruby2JS
|
|
51
58
|
attrs.previous_sibling.remove while attrs and attrs.previous_sibling
|
52
59
|
|
53
60
|
# extract attribute names with uppercase chars from code and format
|
54
|
-
attrs = doc.search('code').map(&:text).join(' ')
|
61
|
+
attrs = doc.search('div[data-language=text] pre code').map(&:text).join(' ')
|
55
62
|
attrs = attrs.split(/\s+/).grep(/[A-Z]/).sort.uniq.join(' ')
|
56
63
|
puts "ReactAttrs = %w(#{attrs})".gsub(/(.{1,72})(\s+|\Z)/, "\\1\n")
|
57
64
|
end
|
data/lib/ruby2js/version.rb
CHANGED
@@ -15,7 +15,8 @@ insert_into_file Rails.root.join("rollup.config.js").to_s,
|
|
15
15
|
})
|
16
16
|
CONFIG
|
17
17
|
|
18
|
-
# monkey patch stimulus:manifest:update to find .rb.js controllers too
|
18
|
+
# monkey patch stimulus:manifest:update to find .rb.js controllers too.
|
19
|
+
# See https://github.com/hotwired/stimulus-rails/issues/76
|
19
20
|
append_to_file Rails.root.join('config/application.rb').to_s,
|
20
21
|
"\n" + <<~'CONFIG'
|
21
22
|
require 'stimulus/manifest'
|