ruby2js 3.2.0 → 3.3.4

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 +45 -5
  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 +17 -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 +142 -26
  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 +15 -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 +3 -12
  39. metadata +25 -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
 
@@ -146,23 +224,33 @@ module Ruby2JS
146
224
  [s(:str, Regexp.escape(arg.children.first)), s(:regopt)])
147
225
  end
148
226
 
149
- pattern = arg.children.first.children.first
150
- pattern = pattern.gsub(/\\./, '').gsub(/\[.*\]/, '')
151
-
152
227
  if arg.type == :regexp
228
+ pattern = arg.children.first.children.first
229
+ pattern = pattern.gsub(/\\./, '').gsub(/\[.*\]/, '')
230
+
153
231
  gpattern = arg.updated(:regexp, [*arg.children[0...-1],
154
232
  s(:regopt, :g, *arg.children.last)])
155
233
  else
156
- super
234
+ gpattern = s(:send, s(:const, nil, :RegExp), :new, arg, s(:str, 'g'))
157
235
  end
158
236
 
159
- if pattern.include? '('
160
- s(:block, s(:send,
161
- s(:send, process(target), :match, gpattern), :map),
162
- s(:args, s(:arg, :s)),
163
- s(:return, s(:send, s(:send, s(:lvar, :s), :match, arg),
164
- :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
165
252
  else
253
+ # str.match(/.../g)
166
254
  S(:send, process(target), :match, gpattern)
167
255
  end
168
256
 
@@ -290,6 +378,9 @@ module Ruby2JS
290
378
  end
291
379
 
292
380
 
381
+ elsif method == :[] and target == s(:const, nil, :Hash)
382
+ s(:send, s(:const, nil, :Object), :fromEntries, *process_all(args))
383
+
293
384
  elsif method == :[]
294
385
  # resolve negative literal indexes
295
386
  i = proc do |index|
@@ -307,9 +398,15 @@ module Ruby2JS
307
398
  super
308
399
 
309
400
  elsif index.type == :regexp
310
- process S(:send,
311
- s(:or, S(:send, process(target), :match, index), s(:array)),
312
- :[], 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
313
410
 
314
411
  elsif node.children.length != 3
315
412
  super
@@ -319,7 +416,9 @@ module Ruby2JS
319
416
 
320
417
  elsif index.type == :erange
321
418
  start, finish = index.children
322
- if finish.type == :int
419
+ if not finish
420
+ process S(:send, target, :slice, start)
421
+ elsif finish.type == :int
323
422
  process S(:send, target, :slice, i.(start), finish)
324
423
  else
325
424
  process S(:send, target, :slice, i.(start), i.(finish))
@@ -327,7 +426,7 @@ module Ruby2JS
327
426
 
328
427
  elsif index.type == :irange
329
428
  start, finish = index.children
330
- if finish.type == :int
429
+ if finish and finish.type == :int
331
430
  final = S(:int, finish.children.first+1)
332
431
  else
333
432
  final = S(:send, finish, :+, s(:int, 1))
@@ -335,7 +434,7 @@ module Ruby2JS
335
434
 
336
435
  # No need for the last argument if it's -1
337
436
  # This means take all to the end of array
338
- if finish.children.first == -1
437
+ if not finish or finish.children.first == -1
339
438
  process S(:send, target, :slice, start)
340
439
  else
341
440
  process S(:send, target, :slice, start, final)
@@ -407,15 +506,28 @@ module Ruby2JS
407
506
  process node.updated(nil, [s(:const, nil, :Object), :fromEntries,
408
507
  target])
409
508
 
410
- elsif es2019 and method==:rstrip
411
- 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
412
516
 
413
- elsif es2019 and method==:lstrip
414
- 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
415
524
 
416
525
  elsif method == :class and args.length==0 and not node.is_method?
417
526
  process node.updated(:attr, [target, :constructor])
418
527
 
528
+ elsif method == :new and target == s(:const, nil, :Exception)
529
+ process S(:send, s(:const, nil, :Error), :new, *args)
530
+
419
531
  else
420
532
  super
421
533
  end
@@ -510,7 +622,7 @@ module Ruby2JS
510
622
  call = call.updated(nil, [s(:begin, range), :step, s(:int, 1)])
511
623
  process node.updated(nil, [call, *node.children[1..-1]])
512
624
 
513
- elsif
625
+ elsif \
514
626
  method == :each and call.children[0].type == :send and
515
627
  call.children[0].children[1] == :step
516
628
  then
@@ -522,7 +634,7 @@ module Ruby2JS
522
634
  :step, step])
523
635
  process node.updated(nil, [call, *node.children[1..-1]])
524
636
 
525
- elsif
637
+ elsif \
526
638
  # (a..b).each {|v| ...}
527
639
  method == :each and
528
640
  call.children[0].type == :begin and
@@ -530,13 +642,13 @@ module Ruby2JS
530
642
  [:irange, :erange].include? call.children[0].children[0].type and
531
643
  node.children[1].children.length == 1
532
644
  then
533
- s(:for, s(:lvasgn, node.children[1].children[0].children[0]),
645
+ process s(:for, s(:lvasgn, node.children[1].children[0].children[0]),
534
646
  call.children[0].children[0], node.children[2])
535
647
 
536
- elsif
648
+ elsif \
537
649
  [:each, :each_value].include? method
538
650
  then
539
- if es2015
651
+ if es2015 or @jsx
540
652
  if node.children[1].children.length > 1
541
653
  process node.updated(:for_of,
542
654
  [s(:mlhs, *node.children[1].children.map {|child|
@@ -557,7 +669,7 @@ module Ruby2JS
557
669
  :forEach), *node.children[1..2]])
558
670
  end
559
671
 
560
- elsif
672
+ elsif \
561
673
  method == :each_key and
562
674
  [:each, :each_key].include? method and
563
675
  node.children[1].children.length == 1
@@ -587,6 +699,10 @@ module Ruby2JS
587
699
  node.children[2])])
588
700
  end
589
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])])
705
+
590
706
  else
591
707
  super
592
708
  end