ruby2js 3.5.2 → 4.0.1
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 +5 -665
- data/lib/ruby2js.rb +47 -13
- data/lib/ruby2js/converter.rb +9 -3
- data/lib/ruby2js/converter/args.rb +6 -1
- 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 +80 -21
- data/lib/ruby2js/converter/class2.rb +107 -33
- data/lib/ruby2js/converter/def.rb +7 -3
- data/lib/ruby2js/converter/dstr.rb +8 -3
- data/lib/ruby2js/converter/hash.rb +28 -6
- data/lib/ruby2js/converter/hide.rb +13 -0
- data/lib/ruby2js/converter/if.rb +10 -2
- data/lib/ruby2js/converter/import.rb +19 -4
- data/lib/ruby2js/converter/kwbegin.rb +9 -2
- data/lib/ruby2js/converter/literal.rb +14 -2
- data/lib/ruby2js/converter/logical.rb +1 -1
- data/lib/ruby2js/converter/module.rb +41 -4
- data/lib/ruby2js/converter/opasgn.rb +8 -0
- data/lib/ruby2js/converter/return.rb +2 -1
- data/lib/ruby2js/converter/send.rb +73 -8
- data/lib/ruby2js/converter/vasgn.rb +5 -0
- data/lib/ruby2js/converter/xstr.rb +2 -3
- 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 +6 -3
- data/lib/ruby2js/filter/cjs.rb +2 -0
- data/lib/ruby2js/filter/esm.rb +118 -26
- data/lib/ruby2js/filter/functions.rb +104 -106
- data/lib/ruby2js/filter/{wunderbar.rb → jsx.rb} +29 -7
- data/lib/ruby2js/filter/node.rb +58 -14
- data/lib/ruby2js/filter/nokogiri.rb +12 -12
- data/lib/ruby2js/filter/react.rb +192 -57
- data/lib/ruby2js/filter/require.rb +102 -11
- data/lib/ruby2js/filter/return.rb +13 -1
- data/lib/ruby2js/filter/stimulus.rb +185 -0
- data/lib/ruby2js/jsx.rb +309 -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 +2 -2
- metadata +17 -9
- data/lib/ruby2js/filter/esm_migration.rb +0 -72
- data/lib/ruby2js/filter/fast-deep-equal.rb +0 -23
data/lib/ruby2js.rb
CHANGED
@@ -10,9 +10,15 @@ end
|
|
10
10
|
|
11
11
|
require 'ruby2js/converter'
|
12
12
|
require 'ruby2js/filter'
|
13
|
+
require 'ruby2js/namespace'
|
13
14
|
|
14
15
|
module Ruby2JS
|
15
16
|
class SyntaxError < RuntimeError
|
17
|
+
attr_reader :diagnostic
|
18
|
+
def initialize(message, diagnostic=nil)
|
19
|
+
super(message)
|
20
|
+
@diagnostic = diagnostic
|
21
|
+
end
|
16
22
|
end
|
17
23
|
|
18
24
|
@@eslevel_default = 2009 # ecmascript 5
|
@@ -61,21 +67,26 @@ module Ruby2JS
|
|
61
67
|
include Ruby2JS::Filter
|
62
68
|
BINARY_OPERATORS = Converter::OPERATORS[2..-1].flatten
|
63
69
|
|
64
|
-
attr_accessor :prepend_list
|
70
|
+
attr_accessor :prepend_list, :disable_autoimports, :namespace
|
65
71
|
|
66
72
|
def initialize(comments)
|
67
73
|
@comments = comments
|
74
|
+
|
75
|
+
# check if magic comment is present:
|
76
|
+
first_comment = @comments.values.first&.map(&:text)&.first
|
77
|
+
@disable_autoimports = first_comment&.include?(" autoimports: false")
|
78
|
+
@disable_autoexports = first_comment&.include?(" autoexports: false")
|
79
|
+
|
68
80
|
@ast = nil
|
69
81
|
@exclude_methods = []
|
70
|
-
@esm = false
|
71
82
|
@prepend_list = Set.new
|
72
83
|
end
|
73
84
|
|
74
85
|
def options=(options)
|
75
86
|
@options = options
|
76
87
|
|
77
|
-
@included =
|
78
|
-
@excluded =
|
88
|
+
@included = Filter.included_methods
|
89
|
+
@excluded = Filter.excluded_methods
|
79
90
|
|
80
91
|
include_all if options[:include_all]
|
81
92
|
include_only(options[:include_only]) if options[:include_only]
|
@@ -111,6 +122,10 @@ module Ruby2JS
|
|
111
122
|
@options[:eslevel] >= 2021
|
112
123
|
end
|
113
124
|
|
125
|
+
def es2022
|
126
|
+
@options[:eslevel] >= 2022
|
127
|
+
end
|
128
|
+
|
114
129
|
def process(node)
|
115
130
|
ast, @ast = @ast, node
|
116
131
|
replacement = super
|
@@ -125,6 +140,7 @@ module Ruby2JS
|
|
125
140
|
end
|
126
141
|
|
127
142
|
# handle all of the 'invented/synthetic' ast types
|
143
|
+
def on_assign(node); end
|
128
144
|
def on_async(node); on_def(node); end
|
129
145
|
def on_asyncs(node); on_defs(node); end
|
130
146
|
def on_attr(node); on_send(node); end
|
@@ -132,17 +148,23 @@ module Ruby2JS
|
|
132
148
|
def on_await(node); on_send(node); end
|
133
149
|
def on_call(node); on_send(node); end
|
134
150
|
def on_class_extend(node); on_send(node); end
|
151
|
+
def on_class_hash(node); on_class(node); end
|
135
152
|
def on_class_module(node); on_send(node); end
|
136
153
|
def on_constructor(node); on_def(node); end
|
154
|
+
def on_deff(node); on_def(node); end
|
137
155
|
def on_defm(node); on_defs(node); end
|
138
156
|
def on_defp(node); on_defs(node); end
|
139
157
|
def on_for_of(node); on_for(node); end
|
140
158
|
def on_in?(node); on_send(node); end
|
141
159
|
def on_method(node); on_send(node); end
|
160
|
+
def on_module_hash(node); on_module(node); end
|
142
161
|
def on_prop(node); on_array(node); end
|
143
162
|
def on_prototype(node); on_begin(node); end
|
163
|
+
def on_send!(node); on_send(node); end
|
144
164
|
def on_sendw(node); on_send(node); end
|
145
165
|
def on_undefined?(node); on_defined?(node); end
|
166
|
+
def on_defineProps(node); end
|
167
|
+
def on_hide(node); on_begin(node); end
|
146
168
|
def on_nil(node); end
|
147
169
|
def on_xnode(node); end
|
148
170
|
def on_export(node); end
|
@@ -160,10 +182,12 @@ module Ruby2JS
|
|
160
182
|
return on_block s(:block, s(:send, *node.children[0..-2]),
|
161
183
|
s(:args, s(:arg, :a), s(:arg, :b)), s(:return,
|
162
184
|
process(s(:send, s(:lvar, :a), method, s(:lvar, :b)))))
|
163
|
-
|
185
|
+
elsif node.children.last.children.first.type == :sym
|
164
186
|
return on_block s(:block, s(:send, *node.children[0..-2]),
|
165
187
|
s(:args, s(:arg, :item)), s(:return,
|
166
188
|
process(s(:attr, s(:lvar, :item), method))))
|
189
|
+
else
|
190
|
+
super
|
167
191
|
end
|
168
192
|
end
|
169
193
|
super
|
@@ -172,6 +196,7 @@ module Ruby2JS
|
|
172
196
|
end
|
173
197
|
|
174
198
|
def self.convert(source, options={})
|
199
|
+
options = options.dup
|
175
200
|
options[:eslevel] ||= @@eslevel_default
|
176
201
|
options[:strict] = @@strict_default if options[:strict] == nil
|
177
202
|
options[:module] ||= @@module_default || :esm
|
@@ -188,9 +213,11 @@ module Ruby2JS
|
|
188
213
|
source = ast.loc.expression.source_buffer.source
|
189
214
|
else
|
190
215
|
ast, comments = parse( source, options[:file] )
|
191
|
-
comments = Parser::Source::Comment.associate(ast, comments)
|
216
|
+
comments = ast ? Parser::Source::Comment.associate(ast, comments) : {}
|
192
217
|
end
|
193
218
|
|
219
|
+
namespace = Namespace.new
|
220
|
+
|
194
221
|
filters = (options[:filters] || Filter::DEFAULTS)
|
195
222
|
|
196
223
|
unless filters.empty?
|
@@ -205,10 +232,12 @@ module Ruby2JS
|
|
205
232
|
filter = filter.new(comments)
|
206
233
|
|
207
234
|
filter.options = options
|
235
|
+
filter.namespace = namespace
|
208
236
|
ast = filter.process(ast)
|
209
237
|
|
210
|
-
|
238
|
+
unless filter.prepend_list.empty?
|
211
239
|
prepend = filter.prepend_list.sort_by {|ast| ast.type == :import ? 0 : 1}
|
240
|
+
prepend.reject! {|ast| ast.type == :import} if filter.disable_autoimports
|
212
241
|
ast = Parser::AST::Node.new(:begin, [*prepend, ast])
|
213
242
|
end
|
214
243
|
end
|
@@ -222,7 +251,10 @@ module Ruby2JS
|
|
222
251
|
ruby2js.comparison = options[:comparison] || :equality
|
223
252
|
ruby2js.or = options[:or] || :logical
|
224
253
|
ruby2js.module_type = options[:module] || :esm
|
225
|
-
ruby2js.underscored_private = (options[:eslevel] <
|
254
|
+
ruby2js.underscored_private = (options[:eslevel] < 2022) || options[:underscored_private]
|
255
|
+
|
256
|
+
ruby2js.namespace = namespace
|
257
|
+
|
226
258
|
if ruby2js.binding and not ruby2js.ivars
|
227
259
|
ruby2js.ivars = ruby2js.binding.eval \
|
228
260
|
'Hash[instance_variables.map {|var| [var, instance_variable_get(var)]}]'
|
@@ -240,6 +272,8 @@ module Ruby2JS
|
|
240
272
|
|
241
273
|
ruby2js.timestamp options[:file]
|
242
274
|
|
275
|
+
ruby2js.file_name = options[:file] || ast&.loc&.expression&.source_buffer&.name || ''
|
276
|
+
|
243
277
|
ruby2js
|
244
278
|
end
|
245
279
|
|
@@ -247,16 +281,16 @@ module Ruby2JS
|
|
247
281
|
buffer = Parser::Source::Buffer.new(file, line)
|
248
282
|
buffer.source = source.encode('utf-8')
|
249
283
|
parser = Parser::CurrentRuby.new
|
250
|
-
parser.
|
251
|
-
|
252
|
-
|
253
|
-
|
284
|
+
parser.diagnostics.all_errors_are_fatal = true
|
285
|
+
parser.diagnostics.consumer = lambda {|diagnostic| nil}
|
286
|
+
parser.builder.emit_file_line_as_literals = false
|
287
|
+
parser.parse_with_comments(buffer)
|
254
288
|
rescue Parser::SyntaxError => e
|
255
289
|
split = source[0..e.diagnostic.location.begin_pos].split("\n")
|
256
290
|
line, col = split.length, split.last.length
|
257
291
|
message = "line #{line}, column #{col}: #{e.diagnostic.message}"
|
258
292
|
message += "\n in file #{file}" if file
|
259
|
-
raise Ruby2JS::SyntaxError.new(message)
|
293
|
+
raise Ruby2JS::SyntaxError.new(message, e.diagnostic)
|
260
294
|
end
|
261
295
|
|
262
296
|
def self.find_block(ast, line)
|
data/lib/ruby2js/converter.rb
CHANGED
@@ -14,7 +14,7 @@ module Ruby2JS
|
|
14
14
|
|
15
15
|
class Converter < Serializer
|
16
16
|
attr_accessor :ast
|
17
|
-
|
17
|
+
|
18
18
|
LOGICAL = :and, :not, :or
|
19
19
|
OPERATORS = [:[], :[]=], [:not, :!], [:**], [:*, :/, :%], [:+, :-],
|
20
20
|
[:>>, :<<], [:&], [:^, :|], [:<=, :<, :>, :>=], [:==, :!=, :===, :"!=="],
|
@@ -34,7 +34,7 @@ module Ruby2JS
|
|
34
34
|
|
35
35
|
VASGN = [:cvasgn, :ivasgn, :gvasgn, :lvasgn]
|
36
36
|
|
37
|
-
attr_accessor :binding, :ivars
|
37
|
+
attr_accessor :binding, :ivars, :namespace
|
38
38
|
|
39
39
|
def initialize( ast, comments, vars = {} )
|
40
40
|
super()
|
@@ -160,6 +160,10 @@ module Ruby2JS
|
|
160
160
|
@eslevel >= 2021
|
161
161
|
end
|
162
162
|
|
163
|
+
def es2022
|
164
|
+
@eslevel >= 2022
|
165
|
+
end
|
166
|
+
|
163
167
|
@@handlers = []
|
164
168
|
def self.handle(*types, &block)
|
165
169
|
types.each do |type|
|
@@ -248,7 +252,7 @@ module Ruby2JS
|
|
248
252
|
if ast.loc and ast.loc.expression
|
249
253
|
filename = ast.loc.expression.source_buffer.name
|
250
254
|
if filename and not filename.empty?
|
251
|
-
@timestamps[filename] ||= File.mtime(filename)
|
255
|
+
@timestamps[filename] ||= File.mtime(filename) rescue nil
|
252
256
|
end
|
253
257
|
end
|
254
258
|
|
@@ -295,6 +299,7 @@ end
|
|
295
299
|
require 'ruby2js/converter/arg'
|
296
300
|
require 'ruby2js/converter/args'
|
297
301
|
require 'ruby2js/converter/array'
|
302
|
+
require 'ruby2js/converter/assign'
|
298
303
|
require 'ruby2js/converter/begin'
|
299
304
|
require 'ruby2js/converter/block'
|
300
305
|
require 'ruby2js/converter/blockpass'
|
@@ -314,6 +319,7 @@ require 'ruby2js/converter/dstr'
|
|
314
319
|
require 'ruby2js/converter/fileline'
|
315
320
|
require 'ruby2js/converter/for'
|
316
321
|
require 'ruby2js/converter/hash'
|
322
|
+
require 'ruby2js/converter/hide'
|
317
323
|
require 'ruby2js/converter/if'
|
318
324
|
require 'ruby2js/converter/in'
|
319
325
|
require 'ruby2js/converter/import'
|
@@ -30,13 +30,18 @@ module Ruby2JS
|
|
30
30
|
if kw.type == :kwarg
|
31
31
|
put kw.children.first
|
32
32
|
elsif kw.type == :kwoptarg
|
33
|
-
put kw.children.first
|
33
|
+
put kw.children.first
|
34
|
+
unless kw.children.last == s(:send, nil, :undefined)
|
35
|
+
put ' = '; parse kw.children.last
|
36
|
+
end
|
34
37
|
elsif kw.type == :kwrestarg
|
35
38
|
raise 'Rest arg requires ES2018' unless es2018
|
36
39
|
put '...'; put kw.children.first
|
37
40
|
end
|
38
41
|
end
|
39
42
|
put ' }'
|
43
|
+
|
44
|
+
put ' = {}' unless kwargs.any? {|kw| kw.type == :kwarg}
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# Kinda like Object.assign, except it handles properties
|
2
|
+
#
|
3
|
+
# Note: Object.defineProperties, Object.getOwnPropertyNames, etc. technically
|
4
|
+
# were not part of ES5, but were implemented by IE prior to ES6, and are
|
5
|
+
# the only way to implement getters and setters.
|
6
|
+
|
7
|
+
module Ruby2JS
|
8
|
+
class Converter
|
9
|
+
|
10
|
+
# (assign
|
11
|
+
# target
|
12
|
+
# (hash)
|
13
|
+
# ...
|
14
|
+
|
15
|
+
handle :assign do |target, *args|
|
16
|
+
collapsible = false
|
17
|
+
|
18
|
+
nonprop = proc do |node|
|
19
|
+
next false unless node.is_a? Parser::AST::Node
|
20
|
+
next false if node.type == :pair and node.children.first.type == :prop and es2015
|
21
|
+
next true unless node.type == :def
|
22
|
+
next false if node.children.first.to_s.end_with? '='
|
23
|
+
node.is_method?
|
24
|
+
end
|
25
|
+
|
26
|
+
collapsible = true if args.length == 1 and args.first.type == :hash and
|
27
|
+
args.first.children.length == 1
|
28
|
+
|
29
|
+
collapsible = true if args.length == 1 and args.first.type == :class_module and
|
30
|
+
args.first.children.length == 3 and nonprop[args.first.children.last]
|
31
|
+
|
32
|
+
if es2015 and not collapsible and args.all? {|arg|
|
33
|
+
case arg.type
|
34
|
+
when :pair, :hash, :class_module
|
35
|
+
arg.children.all? {|child| nonprop[child]}
|
36
|
+
when :const
|
37
|
+
false
|
38
|
+
else
|
39
|
+
true
|
40
|
+
end
|
41
|
+
}
|
42
|
+
parse s(:send, s(:const, nil, :Object), :assign, target, *args)
|
43
|
+
else
|
44
|
+
|
45
|
+
if target == s(:hash)
|
46
|
+
copy = [s(:gvasgn, :$$, target)]
|
47
|
+
target = s(:gvar, :$$)
|
48
|
+
shadow = [s(:shadowarg, :$$)]
|
49
|
+
elsif collapsible or es2015 or
|
50
|
+
(%i(send const).include? target.type and
|
51
|
+
target.children.length == 2 and target.children[0] == nil)
|
52
|
+
then
|
53
|
+
copy = []
|
54
|
+
shadow = []
|
55
|
+
else
|
56
|
+
copy = [s(:gvasgn, :$0, target)]
|
57
|
+
target = s(:gvar, :$0)
|
58
|
+
shadow = [s(:shadowarg, :$0)]
|
59
|
+
end
|
60
|
+
|
61
|
+
body = [*copy,
|
62
|
+
*args.map {|modname|
|
63
|
+
if modname.type == :hash and
|
64
|
+
modname.children.all? {|pair| pair.children.first.type == :prop}
|
65
|
+
|
66
|
+
if modname.children.length == 1
|
67
|
+
pair = modname.children.first
|
68
|
+
s(:send, s(:const, nil, :Object), :defineProperty, target,
|
69
|
+
s(:sym, pair.children.first.children.last),
|
70
|
+
s(:hash, *pair.children.last.map {|name, value| s(:pair,
|
71
|
+
s(:sym, name), value)}))
|
72
|
+
else
|
73
|
+
pair = modname.children.first
|
74
|
+
s(:send, s(:const, nil, :Object), :defineProperties, target,
|
75
|
+
s(:hash, *modname.children.map {|pair| s(:pair,
|
76
|
+
s(:sym, pair.children.first.children.last),
|
77
|
+
s(:hash, *pair.children.last.map {|name, value| s(:pair,
|
78
|
+
s(:sym, name), value)})
|
79
|
+
)}))
|
80
|
+
end
|
81
|
+
|
82
|
+
elsif modname.type == :hash and
|
83
|
+
modname.children.all? {|child| nonprop[child]}
|
84
|
+
|
85
|
+
s(:begin, *modname.children.map {|pair|
|
86
|
+
if pair.children.first.type == :prop
|
87
|
+
s(:send, s(:const, nil, :Object), :defineProperty, target,
|
88
|
+
s(:sym, pair.children.first.children.last),
|
89
|
+
s(:hash, *pair.children.last.map {|name, value| s(:pair,
|
90
|
+
s(:sym, name), value)}))
|
91
|
+
else
|
92
|
+
s(:send, target, :[]=, *pair.children)
|
93
|
+
end
|
94
|
+
})
|
95
|
+
|
96
|
+
elsif modname.type == :class_module and
|
97
|
+
modname.children[2..-1].all? {|child| nonprop[child]}
|
98
|
+
|
99
|
+
s(:begin, *modname.children[2..-1].map {|pair|
|
100
|
+
s(:send, target, :[]=, s(:sym, pair.children.first),
|
101
|
+
pair.updated(:defm, [nil, *pair.children[1..-1]]))
|
102
|
+
})
|
103
|
+
|
104
|
+
elsif modname.type == :lvar and not es2015
|
105
|
+
s(:for, s(:lvasgn, :$_), modname,
|
106
|
+
s(:send, target, :[]=,
|
107
|
+
s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
|
108
|
+
|
109
|
+
else
|
110
|
+
if es2017
|
111
|
+
s(:send, s(:const, nil, :Object), :defineProperties, target,
|
112
|
+
s(:send, s(:const, nil, :Object), :getOwnPropertyDescriptors, modname))
|
113
|
+
else
|
114
|
+
if modname.type == :lvar or (%i(send const).include? modname.type and
|
115
|
+
modname.children.length == 2 and modname.children[0] == nil)
|
116
|
+
|
117
|
+
object = modname
|
118
|
+
else
|
119
|
+
shadow += [s(:shadowarg, :$1)]
|
120
|
+
object = s(:gvar, :$1)
|
121
|
+
end
|
122
|
+
|
123
|
+
copy = s(:send,
|
124
|
+
s(:const, nil, :Object), :defineProperties, target,
|
125
|
+
s(:send,
|
126
|
+
s(:send, s(:const, nil, :Object), :getOwnPropertyNames, object),
|
127
|
+
:reduce,
|
128
|
+
s(:block,
|
129
|
+
s(:send, nil, :lambda),
|
130
|
+
s(:args, s(:arg, :$2), s(:arg, :$3)),
|
131
|
+
s(:begin,
|
132
|
+
s(:send,
|
133
|
+
s(:lvar, :$2), :[]=, s(:lvar, :$3),
|
134
|
+
s(:send, s(:const, nil, :Object), :getOwnPropertyDescriptor,
|
135
|
+
object, s(:lvar, :$3))),
|
136
|
+
s(:return, s(:lvar, :$2)))),
|
137
|
+
s(:hash)))
|
138
|
+
|
139
|
+
|
140
|
+
if object.type == :gvar
|
141
|
+
s(:begin, s(:gvasgn, object.children.last, modname), copy)
|
142
|
+
else
|
143
|
+
copy
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
}]
|
148
|
+
|
149
|
+
if @state == :statement and shadow.empty?
|
150
|
+
parse s(:begin, *body)
|
151
|
+
else
|
152
|
+
body.push s(:return, target) if @state == :expression
|
153
|
+
parse s(:send, s(:block, s(:send, nil, :lambda), s(:args, *shadow),
|
154
|
+
s(:begin, *body)), :[])
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -9,6 +9,11 @@ module Ruby2JS
|
|
9
9
|
state = @state
|
10
10
|
props = false
|
11
11
|
|
12
|
+
if state == :expression and statements.empty?
|
13
|
+
puts 'null'
|
14
|
+
return
|
15
|
+
end
|
16
|
+
|
12
17
|
statements.map! do |statement|
|
13
18
|
case statement and statement.type
|
14
19
|
when :defs, :defp
|
@@ -32,9 +37,9 @@ module Ruby2JS
|
|
32
37
|
end
|
33
38
|
|
34
39
|
def combine_properties(body)
|
35
|
-
|
40
|
+
(0...body.length-1).each do |i|
|
36
41
|
next unless body[i] and body[i].type == :prop
|
37
|
-
|
42
|
+
(i+1...body.length).each do |j|
|
38
43
|
break unless body[j] and body[j].type == :prop
|
39
44
|
|
40
45
|
if body[i].children[0] == body[j].children[0]
|
@@ -10,10 +10,15 @@ module Ruby2JS
|
|
10
10
|
|
11
11
|
handle :case do |expr, *whens, other|
|
12
12
|
begin
|
13
|
+
if @state == :expression
|
14
|
+
parse s(:kwbegin, @ast), @state
|
15
|
+
return
|
16
|
+
end
|
17
|
+
|
13
18
|
inner, @inner = @inner, @ast
|
14
19
|
|
15
20
|
has_range = whens.any? do |node|
|
16
|
-
node.children.any? {|child| [:irange, :erange].include? child
|
21
|
+
node.children.any? {|child| [:irange, :erange].include? child&.type}
|
17
22
|
end
|
18
23
|
|
19
24
|
if has_range
|
@@ -47,7 +52,7 @@ module Ruby2JS
|
|
47
52
|
|
48
53
|
parse code, :statement
|
49
54
|
last = code
|
50
|
-
while last
|
55
|
+
while last&.type == :begin
|
51
56
|
last = last.children.last
|
52
57
|
end
|
53
58
|
|