ruby2js 3.3.3 → 3.5.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.
@@ -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