ruby2js 3.3.6 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,10 +6,10 @@ module Ruby2JS
6
6
  handle :ivar do |var|
7
7
  if self.ivars and self.ivars.include? var
8
8
  parse s(:hostvalue, self.ivars[var])
9
- elsif es2020
10
- parse s(:attr, s(:self), var.to_s.sub('@', '#'))
11
- else
9
+ elsif underscored_private
12
10
  parse s(:attr, s(:self), var.to_s.sub('@', '_'))
11
+ else
12
+ parse s(:attr, s(:self), var.to_s.sub('@', '#'))
13
13
  end
14
14
  end
15
15
 
@@ -7,7 +7,7 @@ module Ruby2JS
7
7
  handle :ivasgn do |var, expression=nil|
8
8
  multi_assign_declarations if @state == :statement
9
9
 
10
- put "#{ var.to_s.sub('@', 'this.' + (es2020 ? '#' : '_')) }"
10
+ put "#{ var.to_s.sub('@', 'this.' + (underscored_private ? '_' : '#')) }"
11
11
  if expression
12
12
  put " = "; parse expression
13
13
  end
@@ -89,7 +89,7 @@ module Ruby2JS
89
89
  def conditionally_equals(left, right)
90
90
  if left == right
91
91
  true
92
- elsif !left or !right or left.type != :csend or right.type != :send
92
+ elsif !left.respond_to?(:type) or !left or !right or left.type != :csend or right.type != :send
93
93
  false
94
94
  else
95
95
  conditionally_equals(left.children.first, right.children.first) &&
@@ -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, :xnode ]
17
+ :block, :const, :true, :false, :xnode, :taglit, :self ]
18
18
 
19
19
  handle :autoreturn do |*statements|
20
20
  return if statements == [nil]
@@ -55,6 +55,8 @@ module Ruby2JS
55
55
  node = block.pop
56
56
  children = node.children.dup
57
57
  (1...children.length).each do |i|
58
+ next if children[i].nil? # case statements without else clause end with nil
59
+
58
60
  if children[i].type == :when
59
61
  gchildren = children[i].children.dup
60
62
  if !gchildren.empty? and EXPRESSIONS.include? gchildren.last.type
@@ -0,0 +1,13 @@
1
+ module Ruby2JS
2
+ class Converter
3
+
4
+ # (taglit
5
+ # (arg :tag)
6
+ # (dstr)
7
+
8
+ handle :taglit do |tag, *children|
9
+ put tag.children.first
10
+ parse_all(*children, join: '')
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Ruby2JS
2
+ class Converter
3
+
4
+ # (yield
5
+ # (arg 'a'))
6
+
7
+ handle :yield do |*args|
8
+ put '_implicitBlockYield'
9
+ put "("; parse_all(*args, join: ', '); put ')'
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,9 @@
1
1
  require 'ruby2js'
2
2
 
3
+ # Note care is taken to run all the filters first before camelCasing.
4
+ # This ensures that Ruby methods like each_pair can be mapped to
5
+ # JavaScript before camelcasing.
6
+
3
7
  module Ruby2JS
4
8
  module Filter
5
9
  module CamelCase
@@ -9,75 +13,114 @@ module Ruby2JS
9
13
  attr_accessor
10
14
  }
11
15
 
16
+ CAPS_EXCEPTIONS = {
17
+ "innerHtml" => "innerHTML",
18
+ "innerHtml=" => "innerHTML=",
19
+ "outerHtml" => "outerHTML",
20
+ "outerHtml=" => "outerHTML=",
21
+ "encodeUri" => "encodeURI",
22
+ "encodeUriComponent" => "encodeURIComponent",
23
+ "decodeUri" => "decodeURI",
24
+ "decodeUriComponent" => "decodeURIComponent"
25
+ }
26
+
12
27
  def camelCase(symbol)
13
- symbol.to_s.gsub(/_[a-z]/) {|match| match[1].upcase}
28
+ should_symbolize = symbol.is_a?(Symbol)
29
+ symbol = symbol
30
+ .to_s
31
+ .gsub(/(?!^)_[a-z0-9]/) {|match| match[1].upcase}
32
+ .gsub(/^(.*)$/) {|match| CAPS_EXCEPTIONS[match] || match }
33
+ should_symbolize ? symbol.to_sym : symbol
14
34
  end
15
35
 
16
36
  def on_send(node)
37
+ node = super
38
+ return node unless [:send, :csend, :attr].include? node.type
39
+
17
40
  if node.children[0] == nil and WHITELIST.include? node.children[1].to_s
18
- super
19
- elsif node.children[1] =~ /_.*\w$/
20
- super S(:send , node.children[0],
41
+ node
42
+ elsif node.children[0] && [:ivar, :cvar].include?(node.children[0].type)
43
+ S(node.type, s(node.children[0].type, camelCase(node.children[0].children[0])),
44
+ camelCase(node.children[1]), *node.children[2..-1])
45
+ elsif node.children[1] =~ /_.*\w[=!?]?$/
46
+ S(node.type, node.children[0],
21
47
  camelCase(node.children[1]), *node.children[2..-1])
22
48
  else
23
- super
49
+ node
24
50
  end
25
51
  end
52
+
53
+ def on_csend(node)
54
+ on_send(node)
55
+ end
56
+
57
+ def on_attr(node)
58
+ on_send(node)
59
+ end
60
+
61
+ def handle_generic_node(node, node_type)
62
+ return node if node.type != node_type
26
63
 
27
- def on_def(node)
28
64
  if node.children[0] =~ /_.*\w$/
29
- super S(:def , camelCase(node.children[0]), *node.children[1..-1])
65
+ S(node_type , camelCase(node.children[0]), *node.children[1..-1])
30
66
  else
31
- super
67
+ node
32
68
  end
33
69
  end
34
70
 
71
+ def on_def(node)
72
+ handle_generic_node(super, :def)
73
+ end
74
+
35
75
  def on_optarg(node)
36
- if node.children[0] =~ /_.*\w$/
37
- super S(:optarg , camelCase(node.children[0]), *node.children[1..-1])
38
- else
39
- super
40
- end
76
+ handle_generic_node(super, :optarg)
77
+ end
78
+
79
+ def on_kwoptarg(node)
80
+ handle_generic_node(super, :kwoptarg)
41
81
  end
42
82
 
43
83
  def on_lvar(node)
44
- if node.children[0] =~ /_.*\w$/
45
- super S(:lvar , camelCase(node.children[0]), *node.children[1..-1])
46
- else
47
- super
48
- end
84
+ handle_generic_node(super, :lvar)
85
+ end
86
+
87
+ def on_ivar(node)
88
+ handle_generic_node(super, :ivar)
89
+ end
90
+
91
+ def on_cvar(node)
92
+ handle_generic_node(super, :cvar)
49
93
  end
50
94
 
51
95
  def on_arg(node)
52
- if node.children[0] =~ /_.*\w$/
53
- super S(:arg , camelCase(node.children[0]), *node.children[1..-1])
54
- else
55
- super
56
- end
96
+ handle_generic_node(super, :arg)
57
97
  end
58
98
 
59
99
  def on_lvasgn(node)
60
- if node.children[0] =~ /_.*\w$/
61
- super S(:lvasgn , camelCase(node.children[0]), *node.children[1..-1])
62
- else
63
- super
64
- end
100
+ handle_generic_node(super, :lvasgn)
101
+ end
102
+
103
+ def on_ivasgn(node)
104
+ handle_generic_node(super, :ivasgn)
105
+ end
106
+
107
+ def on_cvasgn(node)
108
+ handle_generic_node(super, :cvasgn)
65
109
  end
66
110
 
67
111
  def on_sym(node)
68
- if node.children[0] =~ /_.*\w$/
69
- super S(:sym , camelCase(node.children[0]), *node.children[1..-1])
70
- else
71
- super
72
- end
112
+ handle_generic_node(super, :sym)
73
113
  end
74
114
 
75
115
  def on_defs(node)
116
+ node = super
117
+ return node if node.type != :defs
118
+
76
119
  if node.children[1] =~ /_.*\w$/
77
- super S(:defs , node.children[0],
120
+ S(:defs , node.children[0],
78
121
  camelCase(node.children[1]), *node.children[2..-1])
79
122
  else
80
- super
123
+ node
81
124
  end
82
125
  end
83
126
  end
@@ -6,63 +6,58 @@ module Ruby2JS
6
6
  include SEXP
7
7
 
8
8
  def initialize(*args)
9
- @esm_include = nil
10
9
  super
10
+ @esm = true # signal for other filters
11
11
  end
12
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
13
+ def on_send(node)
14
+ target, method, *args = node.children
15
+ return super unless target.nil?
19
16
 
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
17
+ if method == :import
18
+ # don't do the conversion if the word import is followed by a paren
19
+ if node.loc.respond_to? :selector
20
+ selector = node.loc.selector
21
+ if selector and selector.source_buffer
22
+ return super if selector.source_buffer.source[selector.end_pos] == '('
23
+ end
33
24
  end
34
25
 
35
- list.push result
26
+ if args[0].type == :str
27
+ # import "file.css"
28
+ # => import "file.css"
29
+ s(:import, args[0].children[0])
30
+ elsif args.length == 1 and \
31
+ args[0].type == :send and \
32
+ args[0].children[0].nil? and \
33
+ args[0].children[2].type == :send and \
34
+ args[0].children[2].children[0].nil? and \
35
+ args[0].children[2].children[1] == :from and \
36
+ args[0].children[2].children[2].type == :str
37
+ # import name from "file.js"
38
+ # => import name from "file.js"
39
+ s(:import,
40
+ [args[0].children[2].children[2].children[0]],
41
+ process(s(:attr, nil, args[0].children[1])))
36
42
 
37
- if @esm_export
38
- list.push s(:export, :default, s(:const, nil, @esm_export))
43
+ else
44
+ # import Stuff, "file.js"
45
+ # => import Stuff from "file.js"
46
+ # import Stuff, from: "file.js"
47
+ # => import Stuff from "file.js"
48
+ # import Stuff, as: "*", from: "file.js"
49
+ # => import Stuff as * from "file.js"
50
+ # import [ Some, Stuff ], from: "file.js"
51
+ # => import { Some, Stuff } from "file.js"
52
+ imports = (args[0].type == :const || args[0].type == :send) ?
53
+ process(args[0]) :
54
+ process_all(args[0].children)
55
+ s(:import, args[1].children, imports) unless args[1].nil?
39
56
  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
57
+ elsif method == :export
58
+ s(:export, *process_all(args))
59
+ else
60
+ super
66
61
  end
67
62
  end
68
63
  end
@@ -0,0 +1,72 @@
1
+ require 'ruby2js'
2
+
3
+ module Ruby2JS
4
+ module Filter
5
+ module ESMMigration
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 ESMMigration
71
+ end
72
+ end
@@ -528,6 +528,9 @@ module Ruby2JS
528
528
  elsif method == :new and target == s(:const, nil, :Exception)
529
529
  process S(:send, s(:const, nil, :Error), :new, *args)
530
530
 
531
+ elsif method == :block_given? and target == nil and args.length == 0
532
+ process process s(:lvar, "_implicitBlockYield")
533
+
531
534
  else
532
535
  super
533
536
  end
@@ -538,7 +541,7 @@ module Ruby2JS
538
541
  method = call.children[1]
539
542
  return super if excluded?(method)
540
543
 
541
- if [:setInterval, :setTimeout].include? method
544
+ if [:setInterval, :setTimeout, :set_interval, :set_timeout].include? method
542
545
  return super unless call.children.first == nil
543
546
  block = process s(:block, s(:send, nil, :proc), *node.children[1..-1])
544
547
  on_send call.updated nil, [*call.children[0..1], block,
@@ -703,6 +706,17 @@ module Ruby2JS
703
706
  process call.updated(nil, [*call.children, s(:block,
704
707
  s(:send, nil, :proc), *node.children[1..-1])])
705
708
 
709
+ elsif method == :yield_self and call.children.length == 2
710
+ process node.updated(:send, [s(:block, s(:send, nil, :proc),
711
+ node.children[1], s(:autoreturn, node.children[2])),
712
+ :[], call.children[0]])
713
+
714
+ elsif method == :tap and call.children.length == 2
715
+ process node.updated(:send, [s(:block, s(:send, nil, :proc),
716
+ node.children[1], s(:begin, node.children[2],
717
+ s(:return, s(:lvar, node.children[1].children[0].children[0])))),
718
+ :[], call.children[0]])
719
+
706
720
  else
707
721
  super
708
722
  end