ruby2js 3.5.1 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -662
- data/lib/ruby2js.rb +61 -10
- data/lib/ruby2js/converter.rb +10 -4
- 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 +102 -31
- data/lib/ruby2js/converter/def.rb +7 -3
- 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 +35 -4
- data/lib/ruby2js/converter/kwbegin.rb +9 -2
- data/lib/ruby2js/converter/literal.rb +14 -2
- data/lib/ruby2js/converter/module.rb +41 -4
- data/lib/ruby2js/converter/opasgn.rb +8 -0
- data/lib/ruby2js/converter/send.rb +45 -5
- data/lib/ruby2js/converter/vasgn.rb +5 -0
- data/lib/ruby2js/converter/xstr.rb +1 -1
- 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 +44 -0
- data/lib/ruby2js/filter/camelCase.rb +4 -3
- data/lib/ruby2js/filter/cjs.rb +2 -0
- data/lib/ruby2js/filter/esm.rb +133 -7
- data/lib/ruby2js/filter/functions.rb +107 -98
- data/lib/ruby2js/filter/{wunderbar.rb → jsx.rb} +29 -7
- data/lib/ruby2js/filter/node.rb +95 -74
- data/lib/ruby2js/filter/nokogiri.rb +15 -41
- data/lib/ruby2js/filter/react.rb +191 -56
- data/lib/ruby2js/filter/require.rb +100 -5
- data/lib/ruby2js/filter/return.rb +15 -1
- data/lib/ruby2js/filter/securerandom.rb +33 -0
- data/lib/ruby2js/filter/stimulus.rb +185 -0
- data/lib/ruby2js/filter/vue.rb +9 -0
- data/lib/ruby2js/jsx.rb +291 -0
- data/lib/ruby2js/namespace.rb +75 -0
- data/lib/ruby2js/rails.rb +15 -9
- data/lib/ruby2js/serializer.rb +3 -1
- data/lib/ruby2js/version.rb +3 -3
- data/ruby2js.gemspec +1 -1
- metadata +14 -5
- data/lib/ruby2js/filter/esm_migration.rb +0 -72
- data/lib/ruby2js/filter/fast-deep-equal.rb +0 -23
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
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'ruby2js'
|
2
|
+
require 'pathname'
|
2
3
|
|
3
4
|
module Ruby2JS
|
4
5
|
module Filter
|
@@ -13,9 +14,17 @@ module Ruby2JS
|
|
13
14
|
|
14
15
|
def initialize(*args)
|
15
16
|
@require_expr = nil
|
17
|
+
@require_seen = {}
|
18
|
+
@require_relative = '.'
|
16
19
|
super
|
17
20
|
end
|
18
21
|
|
22
|
+
def options=(options)
|
23
|
+
super
|
24
|
+
@require_autoexports = !@disable_autoexports && options[:autoexports]
|
25
|
+
@require_recursive = options[:require_recursive]
|
26
|
+
end
|
27
|
+
|
19
28
|
def on_send(node)
|
20
29
|
if \
|
21
30
|
not @require_expr and # only statements
|
@@ -44,11 +53,97 @@ module Ruby2JS
|
|
44
53
|
filename += '.js.rb'
|
45
54
|
end
|
46
55
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
56
|
+
realpath = File.realpath(filename)
|
57
|
+
if @require_seen[realpath]
|
58
|
+
ast = s(:hide)
|
59
|
+
else
|
60
|
+
@require_seen[realpath] = []
|
61
|
+
|
62
|
+
@options[:file2] = filename
|
63
|
+
ast, comments = Ruby2JS.parse(File.read(filename), filename)
|
64
|
+
@comments.merge! Parser::Source::Comment.associate(ast, comments)
|
65
|
+
@comments[node] += @comments[ast]
|
66
|
+
end
|
67
|
+
|
68
|
+
children = ast.type == :begin ? ast.children : [ast]
|
69
|
+
|
70
|
+
named_exports = []
|
71
|
+
auto_exports = []
|
72
|
+
default_exports = []
|
73
|
+
children.each do |child|
|
74
|
+
if child&.type == :send and child.children[0..1] == [nil, :export]
|
75
|
+
child = child.children[2]
|
76
|
+
if child&.type == :send and child.children[0..1] == [nil, :default]
|
77
|
+
child = child.children[2]
|
78
|
+
target = default_exports
|
79
|
+
else
|
80
|
+
target = named_exports
|
81
|
+
end
|
82
|
+
elsif @require_autoexports
|
83
|
+
target = auto_exports
|
84
|
+
else
|
85
|
+
next
|
86
|
+
end
|
87
|
+
|
88
|
+
if %i[class module].include? child.type and child.children[0].children[0] == nil
|
89
|
+
target << child.children[0].children[1]
|
90
|
+
elsif child.type == :casgn and child.children[0] == nil
|
91
|
+
target << child.children[1]
|
92
|
+
elsif child.type == :def
|
93
|
+
target << child.children[0]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
if @require_autoexports == :default and auto_exports.length == 1
|
98
|
+
default_exports += auto_exports
|
99
|
+
else
|
100
|
+
named_exports += auto_exports
|
101
|
+
end
|
102
|
+
|
103
|
+
imports = @require_seen[realpath]
|
104
|
+
imports << s(:const, nil, default_exports.first) unless default_exports.empty?
|
105
|
+
imports << named_exports.map {|id| s(:const, nil, id)} unless named_exports.empty?
|
106
|
+
|
107
|
+
if imports.empty?
|
108
|
+
process ast
|
109
|
+
else
|
110
|
+
@require_seen[realpath] = imports
|
111
|
+
|
112
|
+
importname = Pathname.new(filename).relative_path_from(Pathname.new(dirname)).to_s
|
113
|
+
importname = Pathname.new(@require_relative).join(importname).to_s
|
114
|
+
|
115
|
+
prepend_list << s(:import, importname, *imports)
|
116
|
+
|
117
|
+
save_prepend_list = prepend_list.dup
|
118
|
+
|
119
|
+
begin
|
120
|
+
require_relative = @require_relative
|
121
|
+
@require_relative = Pathname.new(@require_relative).join(basename).parent.to_s
|
122
|
+
node = process s(:hide, ast)
|
123
|
+
ensure
|
124
|
+
@require_relative = require_relative
|
125
|
+
end
|
126
|
+
|
127
|
+
if @require_recursive
|
128
|
+
block = node.children
|
129
|
+
while block.length == 1 and block.first.type == :begin
|
130
|
+
block = block.first.children
|
131
|
+
end
|
132
|
+
|
133
|
+
block.each do |child|
|
134
|
+
if child&.type == :import
|
135
|
+
puts ['rr', basename, child.inspect]
|
136
|
+
prepend_list << child
|
137
|
+
end
|
138
|
+
end
|
139
|
+
else
|
140
|
+
prepend_list.keep_if do |import|
|
141
|
+
save_prepend_list.include? import
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
node
|
146
|
+
end
|
52
147
|
ensure
|
53
148
|
if file2
|
54
149
|
@options[:file2] = file2
|