ruby2js 3.6.1 → 4.0.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/README.md +1 -7
- data/lib/ruby2js.rb +32 -9
- data/lib/ruby2js/converter.rb +8 -2
- data/lib/ruby2js/converter/assign.rb +159 -0
- data/lib/ruby2js/converter/begin.rb +7 -2
- data/lib/ruby2js/converter/case.rb +7 -2
- data/lib/ruby2js/converter/class.rb +77 -21
- data/lib/ruby2js/converter/class2.rb +39 -11
- data/lib/ruby2js/converter/def.rb +6 -2
- data/lib/ruby2js/converter/dstr.rb +8 -3
- data/lib/ruby2js/converter/hash.rb +9 -5
- data/lib/ruby2js/converter/hide.rb +13 -0
- data/lib/ruby2js/converter/if.rb +10 -2
- data/lib/ruby2js/converter/import.rb +18 -3
- data/lib/ruby2js/converter/kwbegin.rb +9 -2
- data/lib/ruby2js/converter/literal.rb +2 -2
- data/lib/ruby2js/converter/module.rb +37 -5
- data/lib/ruby2js/converter/opasgn.rb +8 -0
- data/lib/ruby2js/converter/send.rb +41 -2
- data/lib/ruby2js/converter/vasgn.rb +5 -0
- data/lib/ruby2js/demo.rb +53 -0
- data/lib/ruby2js/es2022.rb +5 -0
- data/lib/ruby2js/es2022/strict.rb +3 -0
- data/lib/ruby2js/filter.rb +9 -1
- data/lib/ruby2js/filter/active_functions.rb +1 -0
- data/lib/ruby2js/filter/cjs.rb +2 -0
- data/lib/ruby2js/filter/esm.rb +44 -10
- data/lib/ruby2js/filter/functions.rb +84 -95
- data/lib/ruby2js/filter/{wunderbar.rb → jsx.rb} +29 -7
- data/lib/ruby2js/filter/react.rb +191 -56
- data/lib/ruby2js/filter/require.rb +100 -5
- data/lib/ruby2js/filter/return.rb +13 -1
- data/lib/ruby2js/filter/stimulus.rb +185 -0
- data/lib/ruby2js/jsx.rb +291 -0
- data/lib/ruby2js/namespace.rb +75 -0
- data/lib/ruby2js/version.rb +3 -3
- metadata +12 -4
@@ -1,17 +1,19 @@
|
|
1
1
|
require 'ruby2js'
|
2
2
|
|
3
|
+
# Convert Wunderbar syntax to JSX
|
4
|
+
|
3
5
|
module Ruby2JS
|
4
6
|
module Filter
|
5
|
-
module
|
7
|
+
module JSX
|
6
8
|
include SEXP
|
7
9
|
|
8
10
|
def on_send(node)
|
9
|
-
target, method, *
|
11
|
+
target, method, *args = node.children
|
10
12
|
|
11
13
|
if target == s(:const, nil, :Wunderbar)
|
12
14
|
if [:debug, :info, :warn, :error, :fatal].include? method
|
13
15
|
method = :error if method == :fatal
|
14
|
-
return node.updated(nil, [s(:const, nil, :console), method, *
|
16
|
+
return node.updated(nil, [s(:const, nil, :console), method, *args])
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
@@ -27,7 +29,17 @@ module Ruby2JS
|
|
27
29
|
end
|
28
30
|
|
29
31
|
if target == nil and method.to_s.start_with? "_"
|
30
|
-
S(:xnode,
|
32
|
+
S(:xnode, method.to_s[1..-1], *stack, *process_all(args))
|
33
|
+
|
34
|
+
elsif method == :createElement and target == s(:const, nil, :React)
|
35
|
+
if args.first.type == :str and \
|
36
|
+
(args.length == 1 or %i(nil hash).include? args[1].type)
|
37
|
+
attrs = (args[1]&.type != :nil && args[1]) || s(:hash)
|
38
|
+
S(:xnode, args[0].children.first, attrs, *process_all(args[2..-1]))
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
31
43
|
else
|
32
44
|
super
|
33
45
|
end
|
@@ -42,8 +54,18 @@ module Ruby2JS
|
|
42
54
|
|
43
55
|
if target == nil and method.to_s.start_with? "_"
|
44
56
|
if args.children.empty?
|
45
|
-
|
46
|
-
|
57
|
+
if method == :_
|
58
|
+
# Fragment
|
59
|
+
if send.children.length == 2
|
60
|
+
process send.updated(:xnode, ['', *process_all(block)])
|
61
|
+
else
|
62
|
+
process s(:xnode, 'React.Fragment', *send.children[2..-1],
|
63
|
+
*process_all(block))
|
64
|
+
end
|
65
|
+
else
|
66
|
+
# append block as a standalone proc
|
67
|
+
process send.updated(nil, [*send.children, *process_all(block)])
|
68
|
+
end
|
47
69
|
else
|
48
70
|
# iterate over Enumerable arguments if there are args present
|
49
71
|
send = send.children
|
@@ -58,6 +80,6 @@ module Ruby2JS
|
|
58
80
|
end
|
59
81
|
end
|
60
82
|
|
61
|
-
DEFAULTS.push
|
83
|
+
DEFAULTS.push JSX
|
62
84
|
end
|
63
85
|
end
|
data/lib/ruby2js/filter/react.rb
CHANGED
@@ -17,30 +17,39 @@
|
|
17
17
|
# * ~"x" becomes document.querySelector("x")
|
18
18
|
#
|
19
19
|
require 'ruby2js'
|
20
|
+
require 'ruby2js/jsx'
|
20
21
|
|
21
22
|
module Ruby2JS
|
22
23
|
module Filter
|
23
24
|
module React
|
24
25
|
include SEXP
|
26
|
+
extend SEXP
|
27
|
+
|
28
|
+
REACT_IMPORTS = {
|
29
|
+
React: s(:import, ['React'], s(:attr, nil, :React)),
|
30
|
+
ReactDOM: s(:import, ['ReactDOM'], s(:attr, nil, :ReactDOM))
|
31
|
+
}
|
25
32
|
|
26
33
|
# the following command can be used to generate ReactAttrs:
|
27
34
|
#
|
28
35
|
# ruby -r ruby2js/filter/react -e "Ruby2JS::Filter::React.genAttrs"
|
29
36
|
#
|
30
37
|
def self.genAttrs
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
unless RUBY_ENGINE == 'opal'
|
39
|
+
require 'nokogumbo'
|
40
|
+
page = 'https://facebook.github.io/react/docs/tags-and-attributes.html'
|
41
|
+
doc = Nokogiri::HTML5.get(page)
|
42
|
+
|
43
|
+
# delete contents of page prior to the list of supported attributes
|
44
|
+
attrs = doc.at('a[name=supported-attributes]')
|
45
|
+
attrs = attrs.parent while attrs and not attrs.name.start_with? 'h'
|
46
|
+
attrs.previous_sibling.remove while attrs and attrs.previous_sibling
|
47
|
+
|
48
|
+
# extract attribute names with uppercase chars from code and format
|
49
|
+
attrs = doc.search('code').map(&:text).join(' ')
|
50
|
+
attrs = attrs.split(/\s+/).grep(/[A-Z]/).sort.uniq.join(' ')
|
51
|
+
puts "ReactAttrs = %w(#{attrs})".gsub(/(.{1,72})(\s+|\Z)/, "\\1\n")
|
52
|
+
end
|
44
53
|
end
|
45
54
|
|
46
55
|
# list of react attributes that require special processing
|
@@ -60,8 +69,13 @@ module Ruby2JS
|
|
60
69
|
xlinkActuate xlinkArcrole xlinkHref xlinkRole xlinkShow xlinkTitle
|
61
70
|
xlinkType xmlBase xmlLang xmlSpace)
|
62
71
|
|
72
|
+
ReactLifecycle = %w(render componentDidMount shouldComponentUpdate
|
73
|
+
getShapshotBeforeUpdate componentDidUpdate componentWillUnmount
|
74
|
+
componentDidCatch)
|
75
|
+
|
63
76
|
ReactAttrMap = Hash[ReactAttrs.map {|name| [name.downcase, name]}]
|
64
77
|
ReactAttrMap['for'] = 'htmlFor'
|
78
|
+
ReactFragment = :'_React.Fragment'
|
65
79
|
|
66
80
|
def initialize(*args)
|
67
81
|
@react = nil
|
@@ -71,6 +85,7 @@ module Ruby2JS
|
|
71
85
|
@react_props = []
|
72
86
|
@react_methods = []
|
73
87
|
@react_filter_functions = false
|
88
|
+
@react_imports = false
|
74
89
|
@jsx = false
|
75
90
|
super
|
76
91
|
end
|
@@ -88,8 +103,17 @@ module Ruby2JS
|
|
88
103
|
end
|
89
104
|
|
90
105
|
if \
|
91
|
-
defined? Ruby2JS::Filter::
|
92
|
-
filters.include? Ruby2JS::Filter::
|
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
|
+
if \
|
115
|
+
defined? Ruby2JS::Filter::JSX and
|
116
|
+
filters.include? Ruby2JS::Filter::JSX
|
93
117
|
then
|
94
118
|
@jsx = true
|
95
119
|
end
|
@@ -106,8 +130,11 @@ module Ruby2JS
|
|
106
130
|
return super unless cname.children.first == nil
|
107
131
|
return super unless inheritance == s(:const, nil, :React) or
|
108
132
|
inheritance == s(:const, nil, :Vue) or
|
133
|
+
inheritance == s(:const, s(:const, nil, :React), :Component) or
|
109
134
|
inheritance == s(:send, s(:const, nil, :React), :Component)
|
110
135
|
|
136
|
+
prepend_list << REACT_IMPORTS[:React] if @react_imports
|
137
|
+
|
111
138
|
# traverse down to actual list of class statements
|
112
139
|
if body.length == 1
|
113
140
|
if not body.first
|
@@ -156,24 +183,46 @@ module Ruby2JS
|
|
156
183
|
end
|
157
184
|
end
|
158
185
|
|
159
|
-
|
186
|
+
# collect instance methods (including getters and setters)
|
160
187
|
@react_props = []
|
161
188
|
@react_methods = []
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
189
|
+
body.each do |statement|
|
190
|
+
if statement.type == :def
|
191
|
+
method = statement.children.first
|
192
|
+
unless method == :initialize
|
193
|
+
if method.to_s.end_with? '='
|
194
|
+
method = method.to_s[0..-2].to_sym
|
195
|
+
@react_props << method unless @react_props.include? method
|
196
|
+
elsif statement.is_method?
|
197
|
+
@react_methods << method unless @react_methods.include? method
|
198
|
+
else
|
199
|
+
@react_props << method unless @react_props.include? method
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# determine which instance methods need binding
|
206
|
+
needs_binding = []
|
207
|
+
scan_events = lambda do |list|
|
208
|
+
list.each do |node|
|
209
|
+
next unless Parser::AST::Node === node
|
210
|
+
node = process node if node.type == :xstr
|
211
|
+
if node.type == :hash
|
212
|
+
node.children.each do |pair|
|
213
|
+
value = pair.children.last
|
214
|
+
if value.type == :send and \
|
215
|
+
@react_methods.include? value.children[1] and \
|
216
|
+
[nil, s(:self), s(:send, nil, :this)].include? value.children[0]
|
217
|
+
|
218
|
+
needs_binding << value.children[1]
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
scan_events[node.children]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
scan_events[body]
|
177
226
|
|
178
227
|
# append statics (if any)
|
179
228
|
unless statics.empty?
|
@@ -181,9 +230,9 @@ module Ruby2JS
|
|
181
230
|
end
|
182
231
|
|
183
232
|
# create a default getInitialState method if there is no such method
|
184
|
-
# and there are references to instance variables
|
233
|
+
# and there are either references to instance variables or there are
|
234
|
+
# methods that need to be bound.
|
185
235
|
if \
|
186
|
-
not es2015 and
|
187
236
|
not body.any? do |child|
|
188
237
|
child.type == :def and
|
189
238
|
[:getInitialState, :initialize].include? child.children.first
|
@@ -191,9 +240,11 @@ module Ruby2JS
|
|
191
240
|
then
|
192
241
|
@reactIvars = {pre: [], post: [], asgn: [], ref: [], cond: []}
|
193
242
|
react_walk(node)
|
194
|
-
|
243
|
+
if not es2015 and not @reactIvars.values.flatten.empty?
|
195
244
|
body = [s(:def, :getInitialState, s(:args),
|
196
245
|
s(:return, s(:hash))), *body]
|
246
|
+
elsif not needs_binding.empty? or not @reactIvars.values.flatten.empty?
|
247
|
+
body = [s(:def, :initialize, s(:args)), *body]
|
197
248
|
end
|
198
249
|
end
|
199
250
|
|
@@ -221,9 +272,22 @@ module Ruby2JS
|
|
221
272
|
end
|
222
273
|
end
|
223
274
|
|
275
|
+
# add props argument if there is a reference to a prop
|
276
|
+
if args.children.length == 0
|
277
|
+
has_cvar = lambda {|list|
|
278
|
+
list.any? {|node|
|
279
|
+
next unless Parser::AST::Node === node
|
280
|
+
return true if node.type == :cvar
|
281
|
+
has_cvar.call(node.children)
|
282
|
+
}
|
283
|
+
}
|
284
|
+
args = s(:args, s(:arg, 'prop$')) if has_cvar[block]
|
285
|
+
end
|
286
|
+
|
224
287
|
# peel off the initial set of instance variable assignment stmts
|
225
288
|
assigns = []
|
226
289
|
block = block.dup
|
290
|
+
block.shift if block.first == s(:zsuper)
|
227
291
|
while not block.empty? and block.first.type == :ivasgn
|
228
292
|
node = block.shift
|
229
293
|
vars = [node.children.first]
|
@@ -240,9 +304,15 @@ module Ruby2JS
|
|
240
304
|
state = s(:hash, *assigns.map {|anode| s(:pair, s(:str,
|
241
305
|
anode.children.first.to_s[1..-1]), anode.children.last)})
|
242
306
|
|
307
|
+
# bind methods as needed
|
308
|
+
needs_binding.each do |method|
|
309
|
+
block.push(s(:send, s(:self), "#{method}=",
|
310
|
+
s(:send, s(:attr, s(:self), method), :bind, s(:self))))
|
311
|
+
end
|
312
|
+
|
243
313
|
# modify block to build and/or return state
|
244
314
|
if mname == :initialize
|
245
|
-
block.unshift(s(:send, s(:self), :state=, state))
|
315
|
+
block.unshift(s(:zsuper), s(:send, s(:self), :state=, state))
|
246
316
|
elsif block.empty?
|
247
317
|
block = [s(:return, state)]
|
248
318
|
else
|
@@ -250,7 +320,7 @@ module Ruby2JS
|
|
250
320
|
block.push(s(:return, s(:attr, s(:self), :state)))
|
251
321
|
end
|
252
322
|
|
253
|
-
elsif mname == :render
|
323
|
+
elsif mname == :render and not react_wunderbar_free(block, true)
|
254
324
|
if \
|
255
325
|
block.length != 1 or not block.last or
|
256
326
|
not [:send, :block].include? block.last.type
|
@@ -271,9 +341,9 @@ module Ruby2JS
|
|
271
341
|
block = [*prolog, s(:return,
|
272
342
|
s(:xnode, '', *process_all(block)))]
|
273
343
|
else
|
274
|
-
# wrap multi-line blocks with a
|
344
|
+
# wrap multi-line blocks with a React Fragment
|
275
345
|
block = [s(:return,
|
276
|
-
s(:block, s(:send, nil,
|
346
|
+
s(:block, s(:send, nil, ReactFragment), s(:args), *block))]
|
277
347
|
end
|
278
348
|
end
|
279
349
|
|
@@ -300,7 +370,10 @@ module Ruby2JS
|
|
300
370
|
end
|
301
371
|
|
302
372
|
if es2015
|
303
|
-
pairs <<
|
373
|
+
pairs << child.updated(
|
374
|
+
ReactLifecycle.include?(mname.to_s) ? :defm : :def,
|
375
|
+
[mname, args, process(s(type, *block))]
|
376
|
+
)
|
304
377
|
else
|
305
378
|
pairs << s(:pair, s(:sym, mname), child.updated(:block,
|
306
379
|
[s(:send, nil, :proc), args, process(s(type, *block))]))
|
@@ -369,8 +442,12 @@ module Ruby2JS
|
|
369
442
|
# enable React filtering within React class method calls or
|
370
443
|
# React component calls
|
371
444
|
if \
|
372
|
-
node.children.first == s(:const, nil, :React)
|
445
|
+
node.children.first == s(:const, nil, :React) or
|
446
|
+
node.children.first == s(:const, nil, :ReactDOM)
|
373
447
|
then
|
448
|
+
if @react_imports
|
449
|
+
prepend_list << REACT_IMPORTS[node.children.first.children.last]
|
450
|
+
end
|
374
451
|
|
375
452
|
begin
|
376
453
|
react, @react = @react, true
|
@@ -429,6 +506,10 @@ module Ruby2JS
|
|
429
506
|
# :block arguments are inserted by on_block logic below
|
430
507
|
block = child
|
431
508
|
|
509
|
+
elsif child.type == :splat
|
510
|
+
# arrays need not be expanded
|
511
|
+
text = child.children.first
|
512
|
+
|
432
513
|
else
|
433
514
|
# everything else added as text
|
434
515
|
text = child
|
@@ -586,6 +667,9 @@ module Ruby2JS
|
|
586
667
|
next true if arg.children[1] == :createElement and
|
587
668
|
arg.children[0] == s(:const, nil, :Vue)
|
588
669
|
|
670
|
+
# JSX
|
671
|
+
next true if arg.type == :xstr
|
672
|
+
|
589
673
|
# wunderbar style call
|
590
674
|
arg = arg.children.first if arg.type == :block
|
591
675
|
while arg.type == :send and arg.children.first != nil
|
@@ -598,7 +682,19 @@ module Ruby2JS
|
|
598
682
|
if simple
|
599
683
|
# in the normal case, process each argument
|
600
684
|
reactApply, @reactApply = @reactApply, false
|
601
|
-
|
685
|
+
args.each do |arg|
|
686
|
+
arg = process(arg)
|
687
|
+
if arg.type == :send and
|
688
|
+
arg.children[0] == s(:const, nil, :React) and
|
689
|
+
arg.children[1] == :createElement and
|
690
|
+
arg.children[2] == s(:const, nil, "React.Fragment") and
|
691
|
+
arg.children[3] == s(:nil)
|
692
|
+
then
|
693
|
+
params += arg.children[4..-1]
|
694
|
+
else
|
695
|
+
params << arg
|
696
|
+
end
|
697
|
+
end
|
602
698
|
else
|
603
699
|
reactApply, @reactApply = @reactApply, true
|
604
700
|
|
@@ -860,7 +956,15 @@ module Ruby2JS
|
|
860
956
|
end
|
861
957
|
|
862
958
|
# wunderbar style calls
|
863
|
-
if
|
959
|
+
if child.children[0] == nil and child.children[1] == :_ and \
|
960
|
+
node.children[1].children.empty? and !@jsx
|
961
|
+
|
962
|
+
block = s(:block, s(:send, nil, :proc), s(:args),
|
963
|
+
*node.children[2..-1])
|
964
|
+
return on_send node.children.first.updated(:send,
|
965
|
+
[nil, ReactFragment, block])
|
966
|
+
|
967
|
+
elsif !@jsx and child.children[0] == nil and child.children[1] =~ /^_\w/
|
864
968
|
if node.children[1].children.empty?
|
865
969
|
# append block as a standalone proc
|
866
970
|
block = s(:block, s(:send, nil, :proc), s(:args),
|
@@ -871,9 +975,18 @@ module Ruby2JS
|
|
871
975
|
# iterate over Enumerable arguments if there are args present
|
872
976
|
send = node.children.first.children
|
873
977
|
return super if send.length < 3
|
874
|
-
|
875
|
-
|
876
|
-
|
978
|
+
if node.children.length == 3 and
|
979
|
+
node.children.last.respond_to? :type and
|
980
|
+
node.children.last.type == :send
|
981
|
+
|
982
|
+
return process s(:send, *send[0..1], *send[3..-1],
|
983
|
+
s(:splat, s(:block, s(:send, send[2], :map),
|
984
|
+
node.children[1], s(:return, node.children[2]))))
|
985
|
+
else
|
986
|
+
return process s(:block, s(:send, *send[0..1], *send[3..-1]),
|
987
|
+
s(:args), s(:block, s(:send, send[2], :forEach),
|
988
|
+
*node.children[1..-1]))
|
989
|
+
end
|
877
990
|
end
|
878
991
|
end
|
879
992
|
|
@@ -885,6 +998,13 @@ module Ruby2JS
|
|
885
998
|
end
|
886
999
|
end
|
887
1000
|
|
1001
|
+
def on_lvasgn(node)
|
1002
|
+
return super unless @reactClass
|
1003
|
+
return super unless @react_props.include? node.children.first
|
1004
|
+
node.updated(:send, [s(:self), "#{node.children.first}=",
|
1005
|
+
node.children.last])
|
1006
|
+
end
|
1007
|
+
|
888
1008
|
# convert global variables to refs
|
889
1009
|
def on_gvar(node)
|
890
1010
|
return super unless @reactClass
|
@@ -993,7 +1113,7 @@ module Ruby2JS
|
|
993
1113
|
end
|
994
1114
|
|
995
1115
|
# is this a "wunderbar" style call or createElement?
|
996
|
-
def react_element?(node)
|
1116
|
+
def react_element?(node, wunderbar_only=false)
|
997
1117
|
return false unless node
|
998
1118
|
|
999
1119
|
forEach = [:forEach]
|
@@ -1001,15 +1121,17 @@ module Ruby2JS
|
|
1001
1121
|
|
1002
1122
|
return true if node.type == :block and
|
1003
1123
|
forEach.include? node.children.first.children.last and
|
1004
|
-
react_element?(node.children.last)
|
1124
|
+
react_element?(node.children.last, wunderbar_only)
|
1005
1125
|
|
1006
|
-
|
1007
|
-
|
1008
|
-
node.children[
|
1126
|
+
unless wunderbar_only
|
1127
|
+
# explicit call to React.createElement
|
1128
|
+
return true if node.children[1] == :createElement and
|
1129
|
+
node.children[0] == s(:const, nil, :React)
|
1009
1130
|
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1131
|
+
# explicit call to Vue.createElement
|
1132
|
+
return true if node.children[1] == :createElement and
|
1133
|
+
node.children[0] == s(:const, nil, :Vue)
|
1134
|
+
end
|
1013
1135
|
|
1014
1136
|
# wunderbar style call
|
1015
1137
|
node = node.children.first if node.type == :block
|
@@ -1021,13 +1143,14 @@ module Ruby2JS
|
|
1021
1143
|
|
1022
1144
|
# ensure that there are no "wunderbar" or "createElement" calls in
|
1023
1145
|
# a set of statements.
|
1024
|
-
def react_wunderbar_free(nodes)
|
1146
|
+
def react_wunderbar_free(nodes, wunderbar_only=false)
|
1025
1147
|
nodes.each do |node|
|
1026
1148
|
if Parser::AST::Node === node
|
1027
|
-
return false if
|
1149
|
+
return false if node.type == :xstr
|
1150
|
+
return false if react_element?(node, wunderbar_only)
|
1028
1151
|
|
1029
1152
|
# recurse
|
1030
|
-
return false unless react_wunderbar_free(node.children)
|
1153
|
+
return false unless react_wunderbar_free(node.children, wunderbar_only)
|
1031
1154
|
end
|
1032
1155
|
end
|
1033
1156
|
|
@@ -1181,6 +1304,18 @@ module Ruby2JS
|
|
1181
1304
|
|
1182
1305
|
block
|
1183
1306
|
end
|
1307
|
+
|
1308
|
+
def on_xstr(node)
|
1309
|
+
loc = node.loc
|
1310
|
+
return super unless loc
|
1311
|
+
source = loc.begin.source_buffer.source
|
1312
|
+
source = source[loc.begin.end_pos...loc.end.begin_pos].strip
|
1313
|
+
return super unless @reactClass or source.start_with? '<'
|
1314
|
+
source = Ruby2JS.jsx2_rb(source)
|
1315
|
+
ast = Ruby2JS.parse(source).first
|
1316
|
+
ast = s(:block, s(:send, nil, :_), s(:args), ast) if ast.type == :begin
|
1317
|
+
process ast
|
1318
|
+
end
|
1184
1319
|
end
|
1185
1320
|
|
1186
1321
|
DEFAULTS.push React
|