ruby2js 3.2.0 → 3.3.0

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +44 -4
  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 +2 -2
  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 +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 +1 -1
  38. metadata +10 -3
@@ -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
@@ -0,0 +1,49 @@
1
+ require 'ruby2js'
2
+
3
+ module Ruby2JS
4
+ module Filter
5
+ module MatchAll
6
+ include SEXP
7
+
8
+ # ensure matchAll is before Functions in the filter list
9
+ def self.reorder(filters)
10
+ if \
11
+ defined? Ruby2JS::Filter::Functions and
12
+ filters.include? Ruby2JS::Filter::Functions
13
+ then
14
+ filters = filters.dup
15
+ matchAll = filters.delete(Ruby2JS::Filter::MatchAll)
16
+ filters.insert filters.index(Ruby2JS::Filter::Functions), matchAll
17
+ else
18
+ filters
19
+ end
20
+ end
21
+
22
+ def on_block(node)
23
+ return super if es2020
24
+
25
+ # only process each/forEach blocks
26
+ call = node.children.first
27
+ return super unless
28
+ [:each, :forEach].include? call.children[1] and
29
+ call.children.first.type == :send and
30
+ node.children[1].children.length == 1
31
+
32
+ # only process matchAll requests with simple expressions
33
+ call = call.children.first
34
+ return super unless
35
+ call.children[1] == :matchAll and
36
+ call.children[2].type == :send and
37
+ call.children[2].children.first == nil and
38
+ call.children[2].children.length == 2
39
+
40
+ process s(:while,
41
+ s(:lvasgn, node.children[1].children[0].children[0],
42
+ s(:send, call.children[2], :exec, call.children.first)),
43
+ node.children[2])
44
+ end
45
+ end
46
+
47
+ DEFAULTS.push MatchAll
48
+ end
49
+ end
@@ -56,7 +56,7 @@ module Ruby2JS
56
56
  s(:hash, s(:pair, s(:sym, :stdio), s(:str, 'inherit'))))
57
57
  end
58
58
 
59
- elsif
59
+ elsif \
60
60
  method == :require and args.length == 1 and
61
61
  args.first.type == :str and
62
62
  %w(fileutils tmpdir).include? args.first.children.first
@@ -67,7 +67,7 @@ module Ruby2JS
67
67
  super
68
68
  end
69
69
 
70
- elsif
70
+ elsif \
71
71
  [:File, :IO].include? target.children.last and
72
72
  target.type == :const and target.children.first == nil
73
73
  then
@@ -99,7 +99,7 @@ module Ruby2JS
99
99
  @node_setup << :fs
100
100
  S(:send, s(:attr, nil, :fs), :renameSync, *process_all(args))
101
101
 
102
- elsif
102
+ elsif \
103
103
  [:chmod, :lchmod].include? method and
104
104
  args.length > 1 and args.first.type == :int
105
105
  then
@@ -110,7 +110,7 @@ module Ruby2JS
110
110
  s(:octal, *args.first.children))
111
111
  })
112
112
 
113
- elsif
113
+ elsif \
114
114
  [:chown, :lchown].include? method and args.length > 2 and
115
115
  args[0].type == :int and args[1].type == :int
116
116
  then
@@ -148,7 +148,7 @@ module Ruby2JS
148
148
  super
149
149
  end
150
150
 
151
- elsif
151
+ elsif \
152
152
  target.children.last == :FileUtils and
153
153
  target.type == :const and target.children.first == nil
154
154
  then
@@ -201,7 +201,7 @@ module Ruby2JS
201
201
  s(:send, s(:attr, nil, :fs), :unlinkSync, process(file))
202
202
  })
203
203
 
204
- elsif
204
+ elsif \
205
205
  method == :chmod and args.length == 2 and args.first.type == :int
206
206
  then
207
207
  @node_setup << :fs
@@ -211,7 +211,7 @@ module Ruby2JS
211
211
  s(:octal, *args.first.children))
212
212
  })
213
213
 
214
- elsif
214
+ elsif \
215
215
  method == :chown and args.length == 3 and
216
216
  args[0].type == :int and args[1].type == :int
217
217
  then
@@ -233,7 +233,7 @@ module Ruby2JS
233
233
  super
234
234
  end
235
235
 
236
- elsif
236
+ elsif \
237
237
  target.type == :const and target.children.first == nil and
238
238
  target.children.last == :Dir
239
239
  then
@@ -274,7 +274,7 @@ module Ruby2JS
274
274
  call = node.children.first
275
275
  target, method, *args = call.children
276
276
 
277
- if
277
+ if \
278
278
  method == :chdir and args.length == 1 and
279
279
  target.children.last == :Dir and
280
280
  target.type == :const and target.children.first == nil
@@ -324,7 +324,15 @@ module Ruby2JS
324
324
  children = node.children.dup
325
325
  command = children.shift
326
326
  while children.length > 0
327
- command = s(:send, accumulator, :+, children.shift)
327
+ child = children.shift
328
+ if \
329
+ child.type == :begin and child.children.length == 1 and
330
+ child.children.first.type == :send and
331
+ child.children.first.children.first == nil
332
+ then
333
+ child = child.children.first
334
+ end
335
+ command = s(:send, command, :+, child)
328
336
  end
329
337
 
330
338
  s(:send, s(:attr, nil, :child_process), :execSync, command,