ruby2js 3.1.1 → 3.3.2
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 +52 -11
- data/lib/ruby2js.rb +14 -2
- data/lib/ruby2js/converter.rb +11 -3
- data/lib/ruby2js/converter/args.rb +1 -1
- data/lib/ruby2js/converter/block.rb +2 -2
- data/lib/ruby2js/converter/class.rb +4 -3
- data/lib/ruby2js/converter/class2.rb +38 -9
- data/lib/ruby2js/converter/cvar.rb +1 -1
- data/lib/ruby2js/converter/cvasgn.rb +1 -1
- data/lib/ruby2js/converter/def.rb +2 -2
- data/lib/ruby2js/converter/for.rb +7 -0
- data/lib/ruby2js/converter/hash.rb +3 -3
- data/lib/ruby2js/converter/if.rb +13 -2
- data/lib/ruby2js/converter/import.rb +38 -0
- data/lib/ruby2js/converter/logical.rb +46 -1
- data/lib/ruby2js/converter/opasgn.rb +5 -2
- data/lib/ruby2js/converter/regexp.rb +27 -2
- data/lib/ruby2js/converter/return.rb +1 -1
- data/lib/ruby2js/converter/send.rb +53 -27
- data/lib/ruby2js/converter/super.rb +15 -9
- data/lib/ruby2js/converter/xnode.rb +89 -0
- data/lib/ruby2js/es2021.rb +5 -0
- data/lib/ruby2js/es2021/strict.rb +3 -0
- data/lib/ruby2js/filter/cjs.rb +2 -2
- data/lib/ruby2js/filter/esm.rb +72 -0
- data/lib/ruby2js/filter/functions.rb +191 -41
- data/lib/ruby2js/filter/matchAll.rb +49 -0
- data/lib/ruby2js/filter/node.rb +18 -10
- data/lib/ruby2js/filter/nokogiri.rb +13 -13
- data/lib/ruby2js/filter/react.rb +190 -30
- data/lib/ruby2js/filter/require.rb +1 -4
- data/lib/ruby2js/filter/rubyjs.rb +4 -4
- data/lib/ruby2js/filter/vue.rb +40 -15
- data/lib/ruby2js/filter/wunderbar.rb +63 -0
- data/lib/ruby2js/serializer.rb +25 -11
- data/lib/ruby2js/version.rb +2 -2
- data/ruby2js.gemspec +2 -11
- metadata +24 -4
@@ -88,7 +88,7 @@ module Ruby2JS
|
|
88
88
|
put 'async ' if @ast.type == :async
|
89
89
|
|
90
90
|
# es2015 fat arrow support
|
91
|
-
if
|
91
|
+
if \
|
92
92
|
not name and es2015 and @state != :method and @ast.type != :defm and
|
93
93
|
not @prop
|
94
94
|
then
|
@@ -105,7 +105,7 @@ module Ruby2JS
|
|
105
105
|
else
|
106
106
|
style = :expression
|
107
107
|
end
|
108
|
-
elsif
|
108
|
+
elsif \
|
109
109
|
expr.type == :if and expr.children[1] and expr.children[2] and
|
110
110
|
EXPRESSIONS.include? expr.children[1].type and
|
111
111
|
EXPRESSIONS.include? expr.children[2].type
|
@@ -10,6 +10,13 @@ module Ruby2JS
|
|
10
10
|
# (...)
|
11
11
|
|
12
12
|
handle :for, :for_of do |var, expression, block|
|
13
|
+
if @jsx and @ast.type == :for_of
|
14
|
+
parse s(:block, s(:send, expression, :map),
|
15
|
+
s(:args, s(:arg, var.children[0])),
|
16
|
+
s(:autoreturn, block))
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
13
20
|
begin
|
14
21
|
vars = @vars.dup
|
15
22
|
next_token, @next_token = @next_token, :continue
|
@@ -97,13 +97,13 @@ module Ruby2JS
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
-
if
|
100
|
+
if \
|
101
101
|
anonfn and
|
102
102
|
left.children.first.to_s =~ /\A[a-zA-Z_$][a-zA-Z_$0-9]*\Z/
|
103
103
|
then
|
104
104
|
@prop = left.children.first
|
105
105
|
parse right, :method
|
106
|
-
elsif
|
106
|
+
elsif \
|
107
107
|
es2015 and left.type == :sym and right.type == :lvar and
|
108
108
|
left.children == right.children
|
109
109
|
then
|
@@ -113,7 +113,7 @@ module Ruby2JS
|
|
113
113
|
put '['
|
114
114
|
parse left
|
115
115
|
put ']'
|
116
|
-
elsif
|
116
|
+
elsif \
|
117
117
|
left.children.first.to_s =~ /\A[a-zA-Z_$][a-zA-Z_$0-9]*\Z/
|
118
118
|
then
|
119
119
|
put left.children.first
|
data/lib/ruby2js/converter/if.rb
CHANGED
@@ -55,8 +55,19 @@ module Ruby2JS
|
|
55
55
|
end
|
56
56
|
else
|
57
57
|
else_block ||= s(:nil)
|
58
|
-
|
59
|
-
|
58
|
+
|
59
|
+
if @jsx
|
60
|
+
if then_block.type == :begin
|
61
|
+
then_block = s(:xnode, '', *then_block.children)
|
62
|
+
end
|
63
|
+
|
64
|
+
if else_block.type == :begin
|
65
|
+
else_block = s(:xnode, '', *else_block.children)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
parse condition; put ' ? '; parse then_block
|
70
|
+
put ' : '; parse else_block
|
60
71
|
end
|
61
72
|
end
|
62
73
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Ruby2JS
|
2
|
+
class Converter
|
3
|
+
|
4
|
+
# (import str const)
|
5
|
+
|
6
|
+
# NOTE: import is a synthetic
|
7
|
+
|
8
|
+
handle :import do |path, *args|
|
9
|
+
put 'import '
|
10
|
+
|
11
|
+
args.each_with_index do |arg, index|
|
12
|
+
put ', ' unless index == 0
|
13
|
+
parse arg
|
14
|
+
end
|
15
|
+
|
16
|
+
put ' from '
|
17
|
+
put path.inspect
|
18
|
+
end
|
19
|
+
|
20
|
+
# (export const)
|
21
|
+
|
22
|
+
# NOTE: export is a synthetic
|
23
|
+
|
24
|
+
handle :export do |*args|
|
25
|
+
put 'export '
|
26
|
+
|
27
|
+
if args.first == :default
|
28
|
+
put 'default '
|
29
|
+
args.shift
|
30
|
+
end
|
31
|
+
|
32
|
+
args.each_with_index do |arg, index|
|
33
|
+
put ', ' unless index == 0
|
34
|
+
parse arg
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -14,6 +14,17 @@ module Ruby2JS
|
|
14
14
|
|
15
15
|
handle :and, :or do |left, right|
|
16
16
|
type = @ast.type
|
17
|
+
|
18
|
+
|
19
|
+
if es2020 and type == :and
|
20
|
+
node = rewrite(left, right)
|
21
|
+
if node.type == :csend
|
22
|
+
return parse right.updated(node.type, node.children)
|
23
|
+
else
|
24
|
+
left, right = node.children
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
17
28
|
op_index = operator_index type
|
18
29
|
|
19
30
|
lgroup = LOGICAL.include?( left.type ) &&
|
@@ -25,7 +36,7 @@ module Ruby2JS
|
|
25
36
|
rgroup = true if right.type == :begin
|
26
37
|
|
27
38
|
put '(' if lgroup; parse left; put ')' if lgroup
|
28
|
-
put (type==:and ? ' && ' : ' || ')
|
39
|
+
put (type==:and ? ' && ' : ((@or == :nullish and es2020) ? ' ?? ' : ' || '))
|
29
40
|
put '(' if rgroup; parse right; put ')' if rgroup
|
30
41
|
end
|
31
42
|
|
@@ -51,5 +62,39 @@ module Ruby2JS
|
|
51
62
|
put '!'; put '(' if group; parse expr; put ')' if group
|
52
63
|
end
|
53
64
|
end
|
65
|
+
|
66
|
+
# rewrite a && a.b to a&.b
|
67
|
+
def rewrite(left, right)
|
68
|
+
if left && left.type == :and
|
69
|
+
left = rewrite(*left.children)
|
70
|
+
end
|
71
|
+
|
72
|
+
if right.type != :send
|
73
|
+
s(:and, left, right)
|
74
|
+
elsif conditionally_equals(left, right.children.first)
|
75
|
+
# a && a.b => a&.b
|
76
|
+
right.updated(:csend, [left, right.children.last])
|
77
|
+
elsif conditionally_equals(left.children.last, right.children.first)
|
78
|
+
# a && b && b.c => a && b&.c
|
79
|
+
left.updated(:and, [left.children.first,
|
80
|
+
left.children.last.updated(:csend,
|
81
|
+
[left.children.last, right.children.last])])
|
82
|
+
else
|
83
|
+
s(:and, left, right)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# determine if two trees are identical, modulo conditionalilties
|
88
|
+
# in other words a.b == a&.b
|
89
|
+
def conditionally_equals(left, right)
|
90
|
+
if left == right
|
91
|
+
true
|
92
|
+
elsif !left or !right or left.type != :csend or right.type != :send
|
93
|
+
false
|
94
|
+
else
|
95
|
+
conditionally_equals(left.children.first, right.children.first) &&
|
96
|
+
conditionally_equals(left.children.last, right.children.last)
|
97
|
+
end
|
98
|
+
end
|
54
99
|
end
|
55
100
|
end
|
@@ -12,7 +12,7 @@ module Ruby2JS
|
|
12
12
|
var = s(:lvar, var.children.first) if var.type == :lvasgn
|
13
13
|
var = s(:cvar, var.children.first) if var.type == :cvasgn
|
14
14
|
|
15
|
-
if
|
15
|
+
if \
|
16
16
|
[:+, :-].include?(op) and value.type==:int and
|
17
17
|
(value.children==[1] or value.children==[-1])
|
18
18
|
then
|
@@ -46,7 +46,10 @@ module Ruby2JS
|
|
46
46
|
vtype = :ivar if asgn.type == :ivasgn
|
47
47
|
vtype = :cvar if asgn.type == :cvasgn
|
48
48
|
|
49
|
-
if
|
49
|
+
if es2021
|
50
|
+
op = type == :and ? '&&' : (@or == :nullish ? '??' : '||')
|
51
|
+
parse s(:op_asgn, asgn, op, value);
|
52
|
+
elsif vtype
|
50
53
|
parse s(asgn.type, asgn.children.first, s(type,
|
51
54
|
s(vtype, asgn.children.first), value))
|
52
55
|
elsif asgn.type == :send and asgn.children[1] == :[]
|
@@ -27,10 +27,35 @@ module Ruby2JS
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
# in Ruby regular expressions, ^ and $ apply to each line
|
30
31
|
if parts.first.type == :str and parts.first.children[0].start_with?('^')
|
31
|
-
|
32
|
+
if opts.include? :m or opts.include? 'm'
|
33
|
+
if parts.first.children[0].gsub(/\\./, '').gsub(/\[.*?\]/, '').include? '.'
|
34
|
+
opts = opts + [:s] unless opts.include? :s or opts.include? 's'
|
35
|
+
end
|
36
|
+
else
|
37
|
+
opts = opts + [:m]
|
38
|
+
end
|
32
39
|
elsif parts.last.type == :str and parts.last.children[0].end_with?('$')
|
33
|
-
|
40
|
+
if opts.include? :m or opts.include? 'm'
|
41
|
+
if parts.last.children[0].gsub(/\\./, '').gsub(/\[.*?\]/, '').include? '.'
|
42
|
+
opts = opts + [:s] unless opts.include? :s or opts.include? 's'
|
43
|
+
end
|
44
|
+
else
|
45
|
+
opts = opts + [:m]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# in Ruby regular expressions, /A is the start of the string
|
50
|
+
if parts.first.type == :str and parts.first.children[0].start_with?('\A')
|
51
|
+
parts = [s(:str, parts.first.children[0].sub('\A', '^'))] +
|
52
|
+
parts[1..-1]
|
53
|
+
end
|
54
|
+
|
55
|
+
# in Ruby regular expressions, /z is the end of the string
|
56
|
+
if parts.last.type == :str and parts.last.children[0].end_with?('\z')
|
57
|
+
parts = parts[0..-2] +
|
58
|
+
[s(:str, parts.first.children[0].sub('\z', '$'))]
|
34
59
|
end
|
35
60
|
|
36
61
|
# use slash syntax if there are few embedded slashes in the regexp
|
@@ -14,7 +14,7 @@ module Ruby2JS
|
|
14
14
|
|
15
15
|
EXPRESSIONS = [ :array, :float, :hash, :int, :lvar, :nil, :send, :attr,
|
16
16
|
:str, :sym, :dstr, :dsym, :cvar, :ivar, :zsuper, :super, :or, :and,
|
17
|
-
:block, :const, :true, :false ]
|
17
|
+
:block, :const, :true, :false, :xnode ]
|
18
18
|
|
19
19
|
handle :autoreturn do |*statements|
|
20
20
|
return if statements == [nil]
|
@@ -16,7 +16,7 @@ module Ruby2JS
|
|
16
16
|
handle :send, :sendw, :await, :attr, :call do |receiver, method, *args|
|
17
17
|
ast = @ast
|
18
18
|
|
19
|
-
if
|
19
|
+
if \
|
20
20
|
args.length == 1 and method == :+
|
21
21
|
then
|
22
22
|
node = collapse_strings(ast)
|
@@ -25,7 +25,7 @@ module Ruby2JS
|
|
25
25
|
|
26
26
|
# :irange support
|
27
27
|
# - currently only .to_a
|
28
|
-
if
|
28
|
+
if \
|
29
29
|
receiver and
|
30
30
|
receiver.type == :begin and
|
31
31
|
[:irange, :erange].include? receiver.children.first.type
|
@@ -43,6 +43,7 @@ module Ruby2JS
|
|
43
43
|
# three ways to define anonymous functions
|
44
44
|
if method == :new and receiver and receiver.children == [nil, :Proc]
|
45
45
|
return parse args.first, @state
|
46
|
+
|
46
47
|
elsif not receiver and [:lambda, :proc].include? method
|
47
48
|
if method == :lambda
|
48
49
|
return parse s(args.first.type, *args.first.children[0..-2],
|
@@ -86,7 +87,7 @@ module Ruby2JS
|
|
86
87
|
# async proc {|x| ... }
|
87
88
|
return parse block.updated(:async, [nil, *block.children[1..-1]])
|
88
89
|
|
89
|
-
elsif
|
90
|
+
elsif \
|
90
91
|
block.children[0].children[1] == :new and
|
91
92
|
block.children[0].children[0] == s(:const, nil, :Proc)
|
92
93
|
then
|
@@ -141,7 +142,7 @@ module Ruby2JS
|
|
141
142
|
|
142
143
|
elsif method == :[]
|
143
144
|
(group_receiver ? group(receiver) : parse(receiver))
|
144
|
-
if
|
145
|
+
if \
|
145
146
|
args.length == 1 and [:str, :sym].include? args.first.type and
|
146
147
|
args.first.children.first.to_s =~ /^[a-zA-Z]\w*$/
|
147
148
|
then
|
@@ -152,7 +153,7 @@ module Ruby2JS
|
|
152
153
|
|
153
154
|
elsif method == :[]=
|
154
155
|
parse receiver
|
155
|
-
if
|
156
|
+
if \
|
156
157
|
args.length == 2 and [:str, :sym].include? args.first.type and
|
157
158
|
args.first.children.first.to_s =~ /^[a-zA-Z]\w*$/
|
158
159
|
then
|
@@ -170,7 +171,7 @@ module Ruby2JS
|
|
170
171
|
put ')'
|
171
172
|
|
172
173
|
elsif [:-@, :+@, :~, '~'].include? method
|
173
|
-
if
|
174
|
+
if \
|
174
175
|
receiver.type == :send and
|
175
176
|
receiver.children[1] == :+@ and
|
176
177
|
Parser::AST::Node === receiver.children[0] and
|
@@ -196,7 +197,13 @@ module Ruby2JS
|
|
196
197
|
|
197
198
|
elsif OPERATORS.flatten.include?(method) and not LOGICAL.include?(method)
|
198
199
|
(group_receiver ? group(receiver) : parse(receiver))
|
199
|
-
|
200
|
+
|
201
|
+
if @comparison == :identity and [:==, :!=].include? method
|
202
|
+
put " #{ method }= "
|
203
|
+
else
|
204
|
+
put " #{ method } "
|
205
|
+
end
|
206
|
+
|
200
207
|
(group_target ? group(target) : parse(target))
|
201
208
|
|
202
209
|
elsif method =~ /=$/
|
@@ -249,7 +256,7 @@ module Ruby2JS
|
|
249
256
|
elsif args.length == 1 and args.first.type == :const
|
250
257
|
# accommodation for JavaScript like new syntax w/o argument list
|
251
258
|
parse s(:attr, args.first, :new), @state
|
252
|
-
elsif
|
259
|
+
elsif \
|
253
260
|
args.length == 2 and [:send, :const].include? args.first.type and
|
254
261
|
args.last.type == :def and args.last.children.first == nil
|
255
262
|
then
|
@@ -299,27 +306,46 @@ module Ruby2JS
|
|
299
306
|
end
|
300
307
|
|
301
308
|
handle :csend do |receiver, method, *args|
|
302
|
-
|
309
|
+
if es2020
|
303
310
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
311
|
+
# optional chaining
|
312
|
+
parse receiver
|
313
|
+
put "?."
|
314
|
+
if method == :[]
|
315
|
+
put '['
|
316
|
+
args.each {|arg| parse arg}
|
317
|
+
put ']'
|
318
|
+
else
|
319
|
+
put method.to_s
|
320
|
+
put '(' if @ast.is_method?
|
321
|
+
args.each {|arg| parse arg}
|
322
|
+
put ')' if @ast.is_method?
|
323
|
+
end
|
310
324
|
|
311
|
-
|
312
|
-
expr = node.updated(:send)
|
313
|
-
result = s(:and, node.children.first, expr)
|
325
|
+
else
|
314
326
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
327
|
+
node = @ast
|
328
|
+
|
329
|
+
# collect up chain of conditional sends
|
330
|
+
stack = []
|
331
|
+
while node.children.first.type == :csend
|
332
|
+
stack << node
|
333
|
+
node = node.children.first
|
334
|
+
end
|
321
335
|
|
322
|
-
|
336
|
+
# conditionally evaluate most nested expression
|
337
|
+
expr = node.updated(:send)
|
338
|
+
result = s(:and, node.children.first, expr)
|
339
|
+
|
340
|
+
# build up chain of conditional evaluations
|
341
|
+
until stack.empty?
|
342
|
+
node = stack.pop
|
343
|
+
expr = node.updated(:send, [expr, *node.children[1..-1]])
|
344
|
+
result = s(:and, result, expr)
|
345
|
+
end
|
346
|
+
|
347
|
+
parse result
|
348
|
+
end
|
323
349
|
end
|
324
350
|
|
325
351
|
handle :splat do |expr|
|
@@ -334,7 +360,7 @@ module Ruby2JS
|
|
334
360
|
right = node.children[2]
|
335
361
|
|
336
362
|
# recursively evaluate left hand side
|
337
|
-
if
|
363
|
+
if \
|
338
364
|
left.type == :send and left.children.length == 3 and
|
339
365
|
left.children[1] == :+
|
340
366
|
then
|
@@ -342,7 +368,7 @@ module Ruby2JS
|
|
342
368
|
end
|
343
369
|
|
344
370
|
# recursively evaluate right hand side
|
345
|
-
if
|
371
|
+
if \
|
346
372
|
right.type == :send and right.children.length == 3 and
|
347
373
|
right.children[1] == :+
|
348
374
|
then
|
@@ -6,27 +6,33 @@ module Ruby2JS
|
|
6
6
|
# (super ...)
|
7
7
|
|
8
8
|
handle :super, :zsuper do |*args|
|
9
|
-
|
9
|
+
method = @instance_method || @class_method
|
10
|
+
|
11
|
+
unless method and @class_parent
|
10
12
|
raise Error.new("super outside of a method", @ast)
|
11
13
|
end
|
12
14
|
|
13
15
|
# what to pass
|
14
16
|
if @ast.type == :zsuper
|
15
|
-
if
|
16
|
-
args =
|
17
|
-
elsif
|
17
|
+
if method.type == :method
|
18
|
+
args = method.children[2].children[1].children
|
19
|
+
elsif method.type == :prop
|
18
20
|
args = nil
|
19
21
|
else
|
20
|
-
args =
|
22
|
+
args = method.children[1].children
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
26
|
if es2015
|
25
|
-
if @
|
27
|
+
if @class_method
|
28
|
+
parse @class_parent
|
29
|
+
put '.'
|
30
|
+
put method.children[0]
|
31
|
+
elsif method.children[0] == :constructor
|
26
32
|
put 'super'
|
27
33
|
else
|
28
34
|
put 'super.'
|
29
|
-
put
|
35
|
+
put method.children[0]
|
30
36
|
end
|
31
37
|
|
32
38
|
put '('
|
@@ -36,8 +42,8 @@ module Ruby2JS
|
|
36
42
|
parse @class_parent
|
37
43
|
|
38
44
|
# what to call
|
39
|
-
if
|
40
|
-
puts ".prototype.#{
|
45
|
+
if method.type != :constructor
|
46
|
+
puts ".prototype.#{ method.children[1].to_s.chomp('=') }"
|
41
47
|
end
|
42
48
|
|
43
49
|
if args
|