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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +52 -11
  3. data/lib/ruby2js.rb +14 -2
  4. data/lib/ruby2js/converter.rb +11 -3
  5. data/lib/ruby2js/converter/args.rb +1 -1
  6. data/lib/ruby2js/converter/block.rb +2 -2
  7. data/lib/ruby2js/converter/class.rb +4 -3
  8. data/lib/ruby2js/converter/class2.rb +38 -9
  9. data/lib/ruby2js/converter/cvar.rb +1 -1
  10. data/lib/ruby2js/converter/cvasgn.rb +1 -1
  11. data/lib/ruby2js/converter/def.rb +2 -2
  12. data/lib/ruby2js/converter/for.rb +7 -0
  13. data/lib/ruby2js/converter/hash.rb +3 -3
  14. data/lib/ruby2js/converter/if.rb +13 -2
  15. data/lib/ruby2js/converter/import.rb +38 -0
  16. data/lib/ruby2js/converter/logical.rb +46 -1
  17. data/lib/ruby2js/converter/opasgn.rb +5 -2
  18. data/lib/ruby2js/converter/regexp.rb +27 -2
  19. data/lib/ruby2js/converter/return.rb +1 -1
  20. data/lib/ruby2js/converter/send.rb +53 -27
  21. data/lib/ruby2js/converter/super.rb +15 -9
  22. data/lib/ruby2js/converter/xnode.rb +89 -0
  23. data/lib/ruby2js/es2021.rb +5 -0
  24. data/lib/ruby2js/es2021/strict.rb +3 -0
  25. data/lib/ruby2js/filter/cjs.rb +2 -2
  26. data/lib/ruby2js/filter/esm.rb +72 -0
  27. data/lib/ruby2js/filter/functions.rb +191 -41
  28. data/lib/ruby2js/filter/matchAll.rb +49 -0
  29. data/lib/ruby2js/filter/node.rb +18 -10
  30. data/lib/ruby2js/filter/nokogiri.rb +13 -13
  31. data/lib/ruby2js/filter/react.rb +190 -30
  32. data/lib/ruby2js/filter/require.rb +1 -4
  33. data/lib/ruby2js/filter/rubyjs.rb +4 -4
  34. data/lib/ruby2js/filter/vue.rb +40 -15
  35. data/lib/ruby2js/filter/wunderbar.rb +63 -0
  36. data/lib/ruby2js/serializer.rb +25 -11
  37. data/lib/ruby2js/version.rb +2 -2
  38. data/ruby2js.gemspec +2 -11
  39. metadata +24 -4
@@ -0,0 +1,89 @@
1
+ module Ruby2JS
2
+ class Converter
3
+
4
+ # (xnode str hash)
5
+
6
+ # NOTE: xnode is a synthetic
7
+
8
+ handle :xnode do |nodename, *args|
9
+ attrs = {}
10
+ children = []
11
+
12
+ args.each do |arg|
13
+ if arg.type == :hash
14
+ arg.children.each do |pair|
15
+ name = pair.children[0].children[0]
16
+
17
+ if defined? Ruby2JS::Filter::React
18
+ name = :className if name == :class
19
+ name = :htmlFor if name == :for
20
+ end
21
+
22
+ if [:class, :className].include? name and attrs[name]
23
+ if attrs[name].type == :str and pair.children[1].type == :str
24
+ attrs[name] = s(:str, pair.children[1].children[0] + ' ' +
25
+ attrs[name].children[0])
26
+ else
27
+ attrs[name] = s(:send, s(:send, attrs[name], :+,
28
+ s(:str, ' ')), :+, pair.children[1])
29
+ end
30
+ else
31
+ attrs[name] = pair.children[1]
32
+ end
33
+ end
34
+ elsif arg.type == :begin
35
+ children += arg.children
36
+ else
37
+ children << arg
38
+ end
39
+ end
40
+
41
+ put '<'
42
+ put nodename
43
+
44
+ attrs.each do |name, value|
45
+ put ' '
46
+ put name
47
+ put '='
48
+ if value.type == :str
49
+ parse value
50
+ else
51
+ put '{'
52
+ parse value
53
+ put '}'
54
+ end
55
+ end
56
+
57
+ if children.empty?
58
+ put '/>'
59
+ else
60
+ put '>'
61
+ put @nl unless children.length == 1 and children.first.type != :xnode
62
+
63
+ children.each_with_index do |child, index|
64
+ put @nl unless index == 0
65
+ if child.type == :str
66
+ put child.children.first
67
+ elsif child.type == :xnode
68
+ parse child
69
+ else
70
+ begin
71
+ jsx, @jsx = @jsx, true
72
+ put '{'
73
+ parse child
74
+ put '}'
75
+ ensure
76
+ @jsx = jsx
77
+ end
78
+ end
79
+ end
80
+
81
+ put @nl unless children.length == 1 and children.first.type != :xnode
82
+
83
+ put '</'
84
+ put nodename
85
+ put ">"
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,5 @@
1
+ require 'ruby2js'
2
+
3
+ if Ruby2JS.eslevel_default < 2021
4
+ Ruby2JS.eslevel_default = 2021
5
+ end
@@ -0,0 +1,3 @@
1
+ require 'ruby2js/es2021'
2
+
3
+ Ruby2JS.strict_default = true
@@ -24,7 +24,7 @@ module Ruby2JS
24
24
  *assign.children[1..-1]
25
25
  ])
26
26
 
27
- elsif
27
+ elsif \
28
28
  node.children[2].type == :send and
29
29
  node.children[2].children[0..1] == [nil, :async] and
30
30
  node.children[2].children[2].type == :def
@@ -38,7 +38,7 @@ module Ruby2JS
38
38
  *process_all(fn.children[1..-1])))
39
39
  ])
40
40
 
41
- elsif
41
+ elsif \
42
42
  node.children[2].type == :send and
43
43
  node.children[2].children[0..1] == [nil, :default]
44
44
  then
@@ -0,0 +1,72 @@
1
+ require 'ruby2js'
2
+
3
+ module Ruby2JS
4
+ module Filter
5
+ module ESM
6
+ include SEXP
7
+
8
+ def initialize(*args)
9
+ @esm_include = nil
10
+ super
11
+ end
12
+
13
+ def process(node)
14
+ return super if @esm_include
15
+ @esm_include = Set.new
16
+ @esm_exclude = Set.new
17
+ @esm_export = nil
18
+ result = super
19
+
20
+ esm_walk(result)
21
+
22
+ inventory = (@esm_include - @esm_exclude).to_a.sort
23
+
24
+ if inventory.empty? and not @esm_export
25
+ result
26
+ else
27
+ list = inventory.map do |name|
28
+ if name == "React" and defined? Ruby2JS::Filter::React
29
+ s(:import, "#{name.downcase}", s(:const, nil, name))
30
+ elsif not %w(JSON Object).include? name
31
+ s(:import, "./#{name.downcase}.js", s(:const, nil, name))
32
+ end
33
+ end
34
+
35
+ list.push result
36
+
37
+ if @esm_export
38
+ list.push s(:export, :default, s(:const, nil, @esm_export))
39
+ end
40
+
41
+ s(:begin, *list.compact)
42
+ end
43
+ end
44
+
45
+ # gather constants
46
+ def esm_walk(node)
47
+ # extract ivars and cvars
48
+ if node.type == :const and node.children.first == nil
49
+ @esm_include << node.children.last.to_s
50
+ elsif node.type == :xnode
51
+ name = node.children.first
52
+ @esm_include << name unless name.empty? or name =~ /^[a-z]/
53
+ elsif node.type == :casgn and node.children.first == nil
54
+ @esm_exclude << node.children[1].to_s
55
+ elsif node.type == :class and node.children.first.type == :const
56
+ if node.children.first.children.first == nil
57
+ name = node.children.first.children.last.to_s
58
+ @esm_exclude << name
59
+ @esm_export ||= name
60
+ end
61
+ end
62
+
63
+ # recurse
64
+ node.children.each do |child|
65
+ esm_walk(child) if Parser::AST::Node === child
66
+ end
67
+ end
68
+ end
69
+
70
+ DEFAULTS.push ESM
71
+ end
72
+ end
@@ -1,4 +1,5 @@
1
1
  require 'ruby2js'
2
+ require 'regexp_parser'
2
3
 
3
4
  module Ruby2JS
4
5
  module Filter
@@ -15,6 +16,11 @@ module Ruby2JS
15
16
  gvar: :gvasgn
16
17
  }
17
18
 
19
+ def initialize(*args)
20
+ @jsx = false
21
+ super
22
+ end
23
+
18
24
  def on_send(node)
19
25
  target, method, *args = node.children
20
26
  return super if excluded?(method)
@@ -35,6 +41,78 @@ module Ruby2JS
35
41
  elsif method == :keys and args.length == 0 and node.is_method?
36
42
  process S(:send, s(:const, nil, :Object), :keys, target)
37
43
 
44
+ elsif method == :[]= and args.length == 3 and
45
+ args[0].type == :regexp and args[1].type == :int
46
+ index = args[1].children.first
47
+
48
+ parts = Regexp::Parser.parse(args[0].children.first.children.first)
49
+ split = parts.index do |part|
50
+ part.type == :group and part.number == index
51
+ end
52
+
53
+ return super unless split
54
+
55
+ rewritten = parts[split].to_s
56
+
57
+ dstr = [args.last]
58
+ if rewritten == '()'
59
+ index -= 1
60
+ rewritten = ''
61
+ end
62
+
63
+ parts = parts.to_a
64
+
65
+ pre = ''
66
+ if parts.first.type == :anchor
67
+ pre = parts.shift.to_s
68
+ split -= 1
69
+ end
70
+
71
+ if split > 0
72
+ if split == 1 and parts.first.type == :group
73
+ rewritten = parts.first.to_s + rewritten
74
+ else
75
+ rewritten = '(' + parts[0 .. split - 1].join + ')' + rewritten
76
+ index += 1
77
+ end
78
+ dstr.unshift s(:send, s(:lvar, :match), :[], s(:int, 0))
79
+ end
80
+
81
+
82
+ post = ''
83
+ if parts.last.type == :anchor
84
+ post = parts.pop.to_s
85
+ end
86
+
87
+ if split + 1 < parts.length
88
+ if split + 2 == parts.length and parts.last.type == :group
89
+ rewritten += parts.last.to_s
90
+ else
91
+ rewritten += '(' + parts[split + 1 .. -1].join + ')'
92
+ end
93
+ dstr << s(:send, s(:lvar, :match), :[], s(:int, index))
94
+ end
95
+
96
+ rewritten = pre + rewritten + post
97
+
98
+ regex = process s(:regexp, s(:str, rewritten), args[0].children.last)
99
+ block = s(:block,
100
+ s(:send, target, :replace, regex),
101
+ s(:args, s(:arg, :match)),
102
+ process(s(:dstr, *dstr)))
103
+
104
+ if VAR_TO_ASSIGN.keys.include? target.type
105
+ S(VAR_TO_ASSIGN[target.type], target.children.first, block)
106
+ elsif target.type == :send
107
+ if target.children[0] == nil
108
+ S(:lvasgn, target.children[1], block)
109
+ else
110
+ S(:send, target.children[0], :"#{target.children[1]}=", block)
111
+ end
112
+ else
113
+ super
114
+ end
115
+
38
116
  elsif method == :merge
39
117
  args.unshift target
40
118
 
@@ -50,9 +128,15 @@ module Ruby2JS
50
128
 
51
129
  s(:send, s(:block, s(:send, nil, :lambda), s(:args),
52
130
  s(:begin, *copy, *args.map {|modname|
53
- s(:for, s(:lvasgn, :$_), modname,
54
- s(:send, s(:gvar, :$$), :[]=,
55
- s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
131
+ if modname.type == :hash
132
+ s(:begin, *modname.children.map {|pair|
133
+ s(:send, s(:gvar, :$$), :[]=, *pair.children)
134
+ })
135
+ else
136
+ s(:for, s(:lvasgn, :$_), modname,
137
+ s(:send, s(:gvar, :$$), :[]=,
138
+ s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
139
+ end
56
140
  }, s(:return, s(:gvar, :$$)))), :[])
57
141
  end
58
142
 
@@ -72,9 +156,15 @@ module Ruby2JS
72
156
 
73
157
  s(:send, s(:block, s(:send, nil, :lambda), s(:args),
74
158
  s(:begin, *copy, *args.map {|modname|
75
- s(:for, s(:lvasgn, :$_), modname,
76
- s(:send, target, :[]=,
77
- s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
159
+ if modname.type == :hash
160
+ s(:begin, *modname.children.map {|pair|
161
+ s(:send, target, :[]=, *pair.children)
162
+ })
163
+ else
164
+ s(:for, s(:lvasgn, :$_), modname,
165
+ s(:send, target, :[]=,
166
+ s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
167
+ end
78
168
  }, s(:return, target))), :[])
79
169
  end
80
170
 
@@ -134,23 +224,33 @@ module Ruby2JS
134
224
  [s(:str, Regexp.escape(arg.children.first)), s(:regopt)])
135
225
  end
136
226
 
137
- pattern = arg.children.first.children.first
138
- pattern = pattern.gsub(/\\./, '').gsub(/\[.*\]/, '')
139
-
140
227
  if arg.type == :regexp
228
+ pattern = arg.children.first.children.first
229
+ pattern = pattern.gsub(/\\./, '').gsub(/\[.*\]/, '')
230
+
141
231
  gpattern = arg.updated(:regexp, [*arg.children[0...-1],
142
232
  s(:regopt, :g, *arg.children.last)])
143
233
  else
144
- super
234
+ gpattern = s(:send, s(:const, nil, :RegExp), :new, arg, s(:str, 'g'))
145
235
  end
146
236
 
147
- if pattern.include? '('
148
- s(:block, s(:send,
149
- s(:send, process(target), :match, gpattern), :map),
150
- s(:args, s(:arg, :s)),
151
- s(:return, s(:send, s(:send, s(:lvar, :s), :match, arg),
152
- :slice, s(:int, 1))))
237
+ if arg.type != :regexp or pattern.include? '('
238
+ if es2020
239
+ # Array.from(str.matchAll(/.../g), s => s.slice(1))
240
+ s(:send, s(:const, nil, :Array), :from,
241
+ s(:send, process(target), :matchAll, gpattern),
242
+ s(:block, s(:send, nil, :proc), s(:args, s(:arg, :s)),
243
+ s(:send, s(:lvar, :s), :slice, s(:int, 1))))
244
+ else
245
+ # str.match(/.../g).map(s => s.match(/.../).slice(1))
246
+ s(:block, s(:send,
247
+ s(:send, process(target), :match, gpattern), :map),
248
+ s(:args, s(:arg, :s)),
249
+ s(:return, s(:send, s(:send, s(:lvar, :s), :match, arg),
250
+ :slice, s(:int, 1))))
251
+ end
153
252
  else
253
+ # str.match(/.../g)
154
254
  S(:send, process(target), :match, gpattern)
155
255
  end
156
256
 
@@ -278,6 +378,9 @@ module Ruby2JS
278
378
  end
279
379
 
280
380
 
381
+ elsif method == :[] and target == s(:const, nil, :Hash)
382
+ s(:send, s(:const, nil, :Object), :fromEntries, *process_all(args))
383
+
281
384
  elsif method == :[]
282
385
  # resolve negative literal indexes
283
386
  i = proc do |index|
@@ -295,9 +398,15 @@ module Ruby2JS
295
398
  super
296
399
 
297
400
  elsif index.type == :regexp
298
- process S(:send,
299
- s(:or, S(:send, process(target), :match, index), s(:array)),
300
- :[], args[1] || s(:int, 0))
401
+ if es2020
402
+ process S(:csend,
403
+ S(:send, process(target), :match, index),
404
+ :[], args[1] || s(:int, 0))
405
+ else
406
+ process S(:send,
407
+ s(:or, S(:send, process(target), :match, index), s(:array)),
408
+ :[], args[1] || s(:int, 0))
409
+ end
301
410
 
302
411
  elsif node.children.length != 3
303
412
  super
@@ -307,7 +416,9 @@ module Ruby2JS
307
416
 
308
417
  elsif index.type == :erange
309
418
  start, finish = index.children
310
- if finish.type == :int
419
+ if not finish
420
+ process S(:send, target, :slice, start)
421
+ elsif finish.type == :int
311
422
  process S(:send, target, :slice, i.(start), finish)
312
423
  else
313
424
  process S(:send, target, :slice, i.(start), i.(finish))
@@ -315,7 +426,7 @@ module Ruby2JS
315
426
 
316
427
  elsif index.type == :irange
317
428
  start, finish = index.children
318
- if finish.type == :int
429
+ if finish and finish.type == :int
319
430
  final = S(:int, finish.children.first+1)
320
431
  else
321
432
  final = S(:send, finish, :+, s(:int, 1))
@@ -323,7 +434,7 @@ module Ruby2JS
323
434
 
324
435
  # No need for the last argument if it's -1
325
436
  # This means take all to the end of array
326
- if finish.children.first == -1
437
+ if not finish or finish.children.first == -1
327
438
  process S(:send, target, :slice, start)
328
439
  else
329
440
  process S(:send, target, :slice, start, final)
@@ -395,15 +506,28 @@ module Ruby2JS
395
506
  process node.updated(nil, [s(:const, nil, :Object), :fromEntries,
396
507
  target])
397
508
 
398
- elsif es2019 and method==:rstrip
399
- process node.updated(nil, [target, :trimStart, *args])
509
+ elsif method==:rstrip
510
+ if es2019
511
+ process node.updated(nil, [target, :trimEnd, *args])
512
+ else
513
+ node.updated(nil, [process(target), :replace,
514
+ s(:regexp, s(:str, '\s+\z') , s(:regopt)), s(:str, '')])
515
+ end
400
516
 
401
- elsif es2019 and method==:lstrip
402
- process node.updated(nil, [target, :trimEnd, *args])
517
+ elsif method==:lstrip and args.length == 0
518
+ if es2019
519
+ process s(:send, target, :trimStart)
520
+ else
521
+ node.updated(nil, [process(target), :replace,
522
+ s(:regexp, s(:str, '\A\s+') , s(:regopt)), s(:str, '')])
523
+ end
403
524
 
404
525
  elsif method == :class and args.length==0 and not node.is_method?
405
526
  process node.updated(:attr, [target, :constructor])
406
527
 
528
+ elsif method == :new and target == s(:const, nil, :Exception)
529
+ process S(:send, s(:const, nil, :Error), :new, *args)
530
+
407
531
  else
408
532
  super
409
533
  end
@@ -498,7 +622,7 @@ module Ruby2JS
498
622
  call = call.updated(nil, [s(:begin, range), :step, s(:int, 1)])
499
623
  process node.updated(nil, [call, *node.children[1..-1]])
500
624
 
501
- elsif
625
+ elsif \
502
626
  method == :each and call.children[0].type == :send and
503
627
  call.children[0].children[1] == :step
504
628
  then
@@ -510,7 +634,7 @@ module Ruby2JS
510
634
  :step, step])
511
635
  process node.updated(nil, [call, *node.children[1..-1]])
512
636
 
513
- elsif
637
+ elsif \
514
638
  # (a..b).each {|v| ...}
515
639
  method == :each and
516
640
  call.children[0].type == :begin and
@@ -518,23 +642,34 @@ module Ruby2JS
518
642
  [:irange, :erange].include? call.children[0].children[0].type and
519
643
  node.children[1].children.length == 1
520
644
  then
521
- s(:for, s(:lvasgn, node.children[1].children[0].children[0]),
645
+ process s(:for, s(:lvasgn, node.children[1].children[0].children[0]),
522
646
  call.children[0].children[0], node.children[2])
523
647
 
524
- elsif
525
- [:each, :each_value].include? method and
526
- node.children[1].children.length == 1
648
+ elsif \
649
+ [:each, :each_value].include? method
527
650
  then
528
- if es2015
529
- process node.updated(:for_of,
530
- [s(:lvasgn, node.children[1].children[0].children[0]),
531
- node.children[0].children[0], node.children[2]])
651
+ if es2015 or @jsx
652
+ if node.children[1].children.length > 1
653
+ process node.updated(:for_of,
654
+ [s(:mlhs, *node.children[1].children.map {|child|
655
+ s(:lvasgn, child.children[0])}),
656
+ node.children[0].children[0], node.children[2]])
657
+ elsif node.children[1].children[0].type == :mlhs
658
+ process node.updated(:for_of,
659
+ [s(:mlhs, *node.children[1].children[0].children.map {|child|
660
+ s(:lvasgn, child.children[0])}),
661
+ node.children[0].children[0], node.children[2]])
662
+ else
663
+ process node.updated(:for_of,
664
+ [s(:lvasgn, node.children[1].children[0].children[0]),
665
+ node.children[0].children[0], node.children[2]])
666
+ end
532
667
  else
533
668
  process node.updated(nil, [s(:send, call.children[0],
534
669
  :forEach), *node.children[1..2]])
535
670
  end
536
671
 
537
- elsif
672
+ elsif \
538
673
  method == :each_key and
539
674
  [:each, :each_key].include? method and
540
675
  node.children[1].children.length == 1
@@ -548,10 +683,25 @@ module Ruby2JS
548
683
  s(:block, s(:send, nil, :lambda), *node.children[1..2]),
549
684
  *call.children[2..-1]])
550
685
 
551
- elsif es2017 and method == :each_pair
552
- process node.updated(nil, [s(:send, s(:send, s(:const, nil, :Object),
553
- :entries, call.children[0]), :forEach), s(:args, s(:mlhs,
554
- *node.children[1].children)), node.children[2]])
686
+ elsif method == :each_pair and node.children[1].children.length == 2
687
+ if es2017
688
+ # Object.entries(a).forEach(([key, value]) => {})
689
+ process node.updated(nil, [s(:send, s(:send,
690
+ s(:const, nil, :Object), :entries, call.children[0]), :each),
691
+ node.children[1], node.children[2]])
692
+ else
693
+ # for (key in a). {var value = a[key]; ...}
694
+ process node.updated(:for, [s(:lvasgn,
695
+ node.children[1].children[0].children[0]), call.children[0],
696
+ s(:begin, s(:lvasgn, node.children[1].children[1].children[0],
697
+ s(:send, call.children[0], :[],
698
+ s(:lvar, node.children[1].children[0].children[0]))),
699
+ node.children[2])])
700
+ end
701
+
702
+ elsif method == :scan and call.children.length == 3
703
+ process call.updated(nil, [*call.children, s(:block,
704
+ s(:send, nil, :proc), *node.children[1..-1])])
555
705
 
556
706
  else
557
707
  super