ruby2js 3.5.2 → 4.0.1
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 -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
|
|