ruby2js 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
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,