ruby2js 4.1.5 → 4.2.1
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.
- checksums.yaml +4 -4
- data/bin/ruby2js +4 -0
- data/demo/ruby2js.rb +679 -0
- data/lib/ruby2js/converter/block.rb +14 -0
- data/lib/ruby2js/converter/logical.rb +2 -2
- data/lib/ruby2js/converter/return.rb +1 -1
- data/lib/ruby2js/converter.rb +2 -2
- data/lib/ruby2js/demo.rb +28 -0
- data/lib/ruby2js/filter/esm.rb +28 -14
- data/lib/ruby2js/filter/functions.rb +24 -0
- data/lib/ruby2js/filter/lit-element.rb +2 -218
- data/lib/ruby2js/filter/lit.rb +290 -0
- data/lib/ruby2js/filter/react.rb +11 -4
- data/lib/ruby2js/filter/stimulus.rb +2 -2
- data/lib/ruby2js/filter/underscore.rb +23 -17
- data/lib/ruby2js/version.rb +2 -2
- data/lib/ruby2js.rb +11 -0
- data/lib/tasks/install/{litelement.rb → lit-webpacker.rb} +2 -2
- data/lib/tasks/install/stimulus-rollup.rb +44 -0
- data/lib/tasks/install/stimulus-sprockets.rb +16 -23
- data/lib/tasks/install/stimulus-webpacker.rb +3 -0
- data/lib/tasks/ruby2js_tasks.rake +19 -5
- data/ruby2js.gemspec +3 -1
- metadata +10 -5
@@ -69,5 +69,19 @@ module Ruby2JS
|
|
69
69
|
parse s(@ast.children[0].type, *call.children, function), @state
|
70
70
|
end
|
71
71
|
end
|
72
|
+
|
73
|
+
# (numblock
|
74
|
+
# (send nil :x)
|
75
|
+
# 1
|
76
|
+
# (lvar :_1))
|
77
|
+
|
78
|
+
handle :numblock do |call, count, block|
|
79
|
+
parse s(:block,
|
80
|
+
call,
|
81
|
+
s(:args, *((1..count).map {|i| s(:arg, "_#{i}")})),
|
82
|
+
block
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
72
86
|
end
|
73
87
|
end
|
@@ -73,12 +73,12 @@ module Ruby2JS
|
|
73
73
|
s(:and, left, right)
|
74
74
|
elsif conditionally_equals(left, right.children.first)
|
75
75
|
# a && a.b => a&.b
|
76
|
-
right.updated(:csend, [left, right.children
|
76
|
+
right.updated(:csend, [left, *right.children[1..-1]])
|
77
77
|
elsif conditionally_equals(left.children.last, right.children.first)
|
78
78
|
# a && b && b.c => a && b&.c
|
79
79
|
left.updated(:and, [left.children.first,
|
80
80
|
left.children.last.updated(:csend,
|
81
|
-
[left.children.last, right.children
|
81
|
+
[left.children.last, *right.children[1..-1]])])
|
82
82
|
else
|
83
83
|
s(:and, left, right)
|
84
84
|
end
|
@@ -15,7 +15,7 @@ module Ruby2JS
|
|
15
15
|
EXPRESSIONS = [ :array, :float, :hash, :int, :lvar, :nil, :send, :attr,
|
16
16
|
:str, :sym, :dstr, :dsym, :cvar, :ivar, :zsuper, :super, :or, :and,
|
17
17
|
:block, :const, :true, :false, :xnode, :taglit, :self,
|
18
|
-
:op_asgn, :and_asgn, :or_asgn, :taglit, :gvar ]
|
18
|
+
:op_asgn, :and_asgn, :or_asgn, :taglit, :gvar, :csend ]
|
19
19
|
|
20
20
|
handle :autoreturn do |*statements|
|
21
21
|
return if statements == [nil]
|
data/lib/ruby2js/converter.rb
CHANGED
@@ -17,8 +17,8 @@ module Ruby2JS
|
|
17
17
|
|
18
18
|
LOGICAL = :and, :not, :or
|
19
19
|
OPERATORS = [:[], :[]=], [:not, :!], [:**], [:*, :/, :%], [:+, :-],
|
20
|
-
[:>>, :<<], [:&], [:^, :|], [:<=, :<, :>, :>=],
|
21
|
-
[:and, :or]
|
20
|
+
[:>>, :<<], [:&], [:^, :|], [:<=, :<, :>, :>=],
|
21
|
+
[:==, :!=, :===, :"!==", :=~, :!~], [:and, :or]
|
22
22
|
|
23
23
|
INVERT_OP = {
|
24
24
|
:< => :>=,
|
data/lib/ruby2js/demo.rb
CHANGED
@@ -3,6 +3,34 @@ require 'ruby2js'
|
|
3
3
|
|
4
4
|
module Ruby2JS
|
5
5
|
module Demo
|
6
|
+
# convert {"[:foo, :Bar]" => "wee"} to {[:foo, :Bar] => "wee"}
|
7
|
+
def self.parse_stringified_symbol_keys(mapping_hash)
|
8
|
+
updated_mappings = {}
|
9
|
+
|
10
|
+
mapping_hash.each do |k, v|
|
11
|
+
next updated_mappings[k] = v unless k.is_a?(String) && k.start_with?("[:")
|
12
|
+
|
13
|
+
new_k = k.tr("[]", "").split(",").map! {|str| str.strip.delete_prefix(":").to_sym }.map(&:to_sym)
|
14
|
+
updated_mappings[new_k] = v
|
15
|
+
end
|
16
|
+
|
17
|
+
updated_mappings
|
18
|
+
end
|
19
|
+
|
20
|
+
# convert {"Foo" => "[:bar, :Baz]"} to {"Foo" => [:bar, :Baz]}
|
21
|
+
def self.parse_stringified_symbol_values(mapping_hash)
|
22
|
+
updated_mappings = {}
|
23
|
+
|
24
|
+
mapping_hash.each do |k, v|
|
25
|
+
next updated_mappings[k] = v unless v.is_a?(String) && v.start_with?("[:")
|
26
|
+
|
27
|
+
new_v = v.tr("[]", "").split(",").map! {|str| str.strip.delete_prefix(":").to_sym }.map(&:to_sym)
|
28
|
+
updated_mappings[k] = new_v
|
29
|
+
end
|
30
|
+
|
31
|
+
updated_mappings
|
32
|
+
end
|
33
|
+
|
6
34
|
def self.parse_autoimports(mappings)
|
7
35
|
autoimports = {}
|
8
36
|
|
data/lib/ruby2js/filter/esm.rb
CHANGED
@@ -13,16 +13,30 @@ module Ruby2JS
|
|
13
13
|
@esm_autoimports = options[:autoimports]
|
14
14
|
@esm_defs = options[:defs] || {}
|
15
15
|
@esm_explicit_tokens = Set.new
|
16
|
+
@esm_top = nil
|
17
|
+
|
18
|
+
# don't convert requires if Require filter is included
|
19
|
+
filters = options[:filters] || Filter::DEFAULTS
|
20
|
+
if \
|
21
|
+
defined? Ruby2JS::Filter::Require and
|
22
|
+
filters.include? Ruby2JS::Filter::Require
|
23
|
+
then
|
24
|
+
@esm_top = []
|
25
|
+
end
|
16
26
|
end
|
17
27
|
|
18
28
|
def process(node)
|
19
|
-
return super
|
29
|
+
return super if @esm_top
|
20
30
|
|
21
31
|
list = [node]
|
22
32
|
while list.length == 1 and list.first.type == :begin
|
23
33
|
list = list.first.children.dup
|
24
34
|
end
|
25
35
|
|
36
|
+
@esm_top = list
|
37
|
+
|
38
|
+
return super unless @esm_autoexports
|
39
|
+
|
26
40
|
replaced = []
|
27
41
|
list.map! do |child|
|
28
42
|
replacement = child
|
@@ -84,7 +98,7 @@ module Ruby2JS
|
|
84
98
|
target, method, *args = node.children
|
85
99
|
return super unless target.nil?
|
86
100
|
|
87
|
-
if method == :import
|
101
|
+
if method == :import or (method == :require and @esm_top&.include? @ast)
|
88
102
|
# don't do the conversion if the word import is followed by a paren
|
89
103
|
if node.loc.respond_to? :selector
|
90
104
|
selector = node.loc.selector
|
@@ -98,7 +112,7 @@ module Ruby2JS
|
|
98
112
|
# => import "file.css"
|
99
113
|
s(:import, args[0].children[0])
|
100
114
|
elsif args.length == 1 and \
|
101
|
-
|
115
|
+
args[0].type == :send and \
|
102
116
|
args[0].children[0].nil? and \
|
103
117
|
args[0].children[2].type == :send and \
|
104
118
|
args[0].children[2].children[0].nil? and \
|
@@ -152,17 +166,17 @@ module Ruby2JS
|
|
152
166
|
|
153
167
|
values = @esm_defs[node.children.last]
|
154
168
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
169
|
+
if values
|
170
|
+
values = values.map {|value|
|
171
|
+
if value.to_s.start_with? "@"
|
172
|
+
[value.to_s[1..-1].to_sym, s(:self)]
|
173
|
+
else
|
174
|
+
[value.to_sym, s(:autobind, s(:self))]
|
175
|
+
end
|
176
|
+
}.to_h
|
177
|
+
|
178
|
+
@namespace.defineProps values, [node.children.last]
|
179
|
+
end
|
166
180
|
end
|
167
181
|
|
168
182
|
super
|
@@ -162,6 +162,9 @@ module Ruby2JS
|
|
162
162
|
elsif method == :to_f
|
163
163
|
process node.updated :send, [nil, :parseFloat, target, *args]
|
164
164
|
|
165
|
+
elsif method == :to_json
|
166
|
+
process node.updated :send, [s(:const, nil, :JSON), :stringify, target, *args]
|
167
|
+
|
165
168
|
elsif method == :sub and args.length == 2
|
166
169
|
if args[1].type == :str
|
167
170
|
args[1] = s(:str, args[1].children.first.gsub(/\\(\d)/, "$\\1"))
|
@@ -503,6 +506,12 @@ module Ruby2JS
|
|
503
506
|
s(:regexp, s(:str, '\A\s+') , s(:regopt)), s(:str, '')])
|
504
507
|
end
|
505
508
|
|
509
|
+
elsif method == :index
|
510
|
+
process node.updated(nil, [target, :indexOf, *args])
|
511
|
+
|
512
|
+
elsif method == :rindex
|
513
|
+
process node.updated(nil, [target, :lastIndexOf, *args])
|
514
|
+
|
506
515
|
elsif method == :class and args.length==0 and not node.is_method?
|
507
516
|
process node.updated(:attr, [target, :constructor])
|
508
517
|
|
@@ -515,6 +524,9 @@ module Ruby2JS
|
|
515
524
|
elsif method == :abs and args.length == 0
|
516
525
|
process S(:send, s(:const, nil, :Math), :abs, target)
|
517
526
|
|
527
|
+
elsif method == :round and args.length == 0
|
528
|
+
process S(:send, s(:const, nil, :Math), :round, target)
|
529
|
+
|
518
530
|
elsif method == :ceil and args.length == 0
|
519
531
|
process S(:send, s(:const, nil, :Math), :ceil, target)
|
520
532
|
|
@@ -570,6 +582,13 @@ module Ruby2JS
|
|
570
582
|
process S(:send, s(:attr, target, :prototype), :[]=, args[0],
|
571
583
|
s(:attr, s(:attr, target, :prototype), args[1].children[0]))
|
572
584
|
|
585
|
+
elsif method == :new and args.length == 2 and target == s(:const, nil, :Array)
|
586
|
+
if es2015
|
587
|
+
s(:send, S(:send, target, :new, args.first), :fill, args.last)
|
588
|
+
else
|
589
|
+
super
|
590
|
+
end
|
591
|
+
|
573
592
|
else
|
574
593
|
super
|
575
594
|
end
|
@@ -616,6 +635,11 @@ module Ruby2JS
|
|
616
635
|
node.updated nil, [process(call), process(node.children[1]),
|
617
636
|
s(:autoreturn, *process_all(node.children[2..-1]))]
|
618
637
|
|
638
|
+
elsif method == :index and call.children.length == 2
|
639
|
+
call = call.updated nil, [call.children.first, :findIndex]
|
640
|
+
node.updated nil, [process(call), process(node.children[1]),
|
641
|
+
s(:autoreturn, *process_all(node.children[2..-1]))]
|
642
|
+
|
619
643
|
elsif method == :map and call.children.length == 2
|
620
644
|
node.updated nil, [process(call), process(node.children[1]),
|
621
645
|
s(:autoreturn, *process_all(node.children[2..-1]))]
|
@@ -1,218 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module Ruby2JS
|
4
|
-
module Filter
|
5
|
-
module LitElement
|
6
|
-
include SEXP
|
7
|
-
extend SEXP
|
8
|
-
|
9
|
-
LITELEMENT_IMPORT = s(:import,
|
10
|
-
[s(:pair, s(:sym, :from), s(:str, "lit-element"))],
|
11
|
-
[s(:const, nil, :LitElement), s(:attr, nil, :css), s(:attr, nil, :html)])
|
12
|
-
|
13
|
-
def initialize(node)
|
14
|
-
super
|
15
|
-
@le_props = nil
|
16
|
-
end
|
17
|
-
|
18
|
-
def on_ivar(node)
|
19
|
-
return super unless @le_props&.include?(node.children.first)
|
20
|
-
s(:attr, s(:self), node.children.first.to_s[1..-1])
|
21
|
-
end
|
22
|
-
|
23
|
-
def on_ivasgn(node)
|
24
|
-
return super unless @le_props&.include?(node.children.first)
|
25
|
-
return super unless node.children.length > 1
|
26
|
-
s(:send, s(:self), node.children.first.to_s[1..-1]+'=',
|
27
|
-
process(node.children[1]))
|
28
|
-
end
|
29
|
-
|
30
|
-
def on_op_asgn(node)
|
31
|
-
return super unless node.children.first.type == :ivasgn
|
32
|
-
var = node.children.first.children.first
|
33
|
-
return super unless @le_props&.include?(var)
|
34
|
-
super node.updated(nil, [s(:attr, s(:attr, nil, :this),
|
35
|
-
var.to_s[1..-1]), *node.children[1..-1]])
|
36
|
-
end
|
37
|
-
|
38
|
-
def on_class(node)
|
39
|
-
_, inheritance, *body = node.children
|
40
|
-
return super unless inheritance == s(:const, nil, :LitElement)
|
41
|
-
|
42
|
-
@le_props = {}
|
43
|
-
le_walk(node)
|
44
|
-
|
45
|
-
prepend_list << LITELEMENT_IMPORT if modules_enabled?
|
46
|
-
|
47
|
-
nodes = body.dup
|
48
|
-
if nodes.length == 1 and nodes.first&.type == :begin
|
49
|
-
nodes = nodes.first.children.dup
|
50
|
-
end
|
51
|
-
|
52
|
-
# insert/update static get properties() {}
|
53
|
-
unless @le_props.empty?
|
54
|
-
values = nodes.find_index {|child|
|
55
|
-
child.type == :defs and child.children[0..1] == [s(:self), :properties]
|
56
|
-
}
|
57
|
-
|
58
|
-
if values == nil
|
59
|
-
nodes.unshift s(:defp, s(:self), :properties, s(:args), s(:return,
|
60
|
-
s(:hash, *@le_props.map {|name, type| s(:pair, s(:str, name.to_s[1..-1]),
|
61
|
-
s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String))))})))
|
62
|
-
elsif nodes[values].children[3].type == :hash
|
63
|
-
le_props = @le_props.map {|name, type|
|
64
|
-
[s(:sym, name.to_s[1..-1].to_sym),
|
65
|
-
s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String)))]
|
66
|
-
}.to_h.merge(
|
67
|
-
nodes[values].children[3].children.map {|pair| pair.children}.to_h
|
68
|
-
)
|
69
|
-
|
70
|
-
nodes[values] = nodes[values].updated(nil,
|
71
|
-
[*nodes[values].children[0..2], s(:hash,
|
72
|
-
*le_props.map{|name, value| s(:pair, name, value)})])
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# render of a string is converted to a taglit :html
|
77
|
-
render = nodes.find_index {|child|
|
78
|
-
child&.type == :def and child.children.first == :render
|
79
|
-
}
|
80
|
-
if render and %i[str dstr].include?(nodes[render].children[2]&.type)
|
81
|
-
nodes[render] = nodes[render].updated(:deff,
|
82
|
-
[*nodes[render].children[0..1],
|
83
|
-
s(:autoreturn, html_wrap(nodes[render].children[2]))])
|
84
|
-
end
|
85
|
-
|
86
|
-
# self.styles returning string is converted to a taglit :css
|
87
|
-
styles = nodes.find_index {|child|
|
88
|
-
child&.type == :defs and child.children[0..1] == [s(:self), :styles]
|
89
|
-
}
|
90
|
-
if styles and %i[str dstr].include?(nodes[styles].children[3]&.type)
|
91
|
-
string = nodes[styles].children[3]
|
92
|
-
string = s(:dstr, string) if string.type == :str
|
93
|
-
children = string.children.dup
|
94
|
-
|
95
|
-
while children.length > 1 and children.last.type == :str and
|
96
|
-
children.last.children.last.strip == ''
|
97
|
-
children.pop
|
98
|
-
end
|
99
|
-
|
100
|
-
if children.last.type == :str
|
101
|
-
children << s(:str, children.pop.children.first.chomp)
|
102
|
-
end
|
103
|
-
|
104
|
-
nodes[styles] = nodes[styles].updated(nil,
|
105
|
-
[*nodes[styles].children[0..2],
|
106
|
-
s(:autoreturn, s(:taglit, s(:sym, :css),
|
107
|
-
s(:dstr, *children)))])
|
108
|
-
end
|
109
|
-
|
110
|
-
# insert super calls into initializer
|
111
|
-
initialize = nodes.find_index {|child|
|
112
|
-
child&.type == :def and child.children.first == :initialize
|
113
|
-
}
|
114
|
-
if initialize and nodes[initialize].children.length == 3
|
115
|
-
statements = nodes[initialize].children[2..-1]
|
116
|
-
|
117
|
-
if statements.length == 1 and statements.first.type == :begin
|
118
|
-
statements = statements.first.children
|
119
|
-
end
|
120
|
-
|
121
|
-
unless statements.any? {|statement| %i[super zuper].include? statement.type}
|
122
|
-
nodes[initialize] = nodes[initialize].updated(nil,
|
123
|
-
[*nodes[initialize].children[0..1],
|
124
|
-
s(:begin, s(:zsuper), *statements)])
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
props = @le_props.keys.map {|prop| [prop.to_sym, s(:self)]}.to_h
|
129
|
-
|
130
|
-
nodes.unshift s(:defineProps, props)
|
131
|
-
|
132
|
-
nodes.pop unless nodes.last
|
133
|
-
|
134
|
-
node.updated(nil, [*node.children[0..1], s(:begin, *process_all(nodes))])
|
135
|
-
ensure
|
136
|
-
@le_props = nil
|
137
|
-
end
|
138
|
-
|
139
|
-
def html_wrap(node)
|
140
|
-
if node.type == :str and node.children.first.strip.start_with? '<'
|
141
|
-
s(:taglit, s(:sym, :html), s(:dstr, node))
|
142
|
-
elsif node.type == :dstr
|
143
|
-
prefix = ''
|
144
|
-
node.children.each do |child|
|
145
|
-
break unless child.type == :str
|
146
|
-
prefix += child.children.first
|
147
|
-
end
|
148
|
-
|
149
|
-
return node unless prefix.strip.start_with? '<'
|
150
|
-
|
151
|
-
children = node.children.map do |child|
|
152
|
-
if child.type == :str
|
153
|
-
child
|
154
|
-
else
|
155
|
-
html_wrap(child)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
while children.length > 1 and children.last.type == :str and
|
160
|
-
children.last.children.last.strip == ''
|
161
|
-
children.pop
|
162
|
-
end
|
163
|
-
|
164
|
-
if children.last.type == :str
|
165
|
-
children << s(:str, children.pop.children.first.chomp)
|
166
|
-
end
|
167
|
-
|
168
|
-
s(:taglit, s(:sym, :html), node.updated(nil, children))
|
169
|
-
elsif node.type == :begin
|
170
|
-
node.updated(nil, node.children.map {|child| html_wrap(child)})
|
171
|
-
elsif node.type == :if
|
172
|
-
node.updated(nil, [node.children.first,
|
173
|
-
*node.children[1..2].map {|child| html_wrap(child)}])
|
174
|
-
elsif node.type == :block and
|
175
|
-
node.children.first.children[1] == :map
|
176
|
-
node.updated(nil, [*node.children[0..1],
|
177
|
-
html_wrap(node.children[2])])
|
178
|
-
else
|
179
|
-
node
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
# analyze ivar usage
|
184
|
-
def le_walk(node)
|
185
|
-
node.children.each do |child|
|
186
|
-
next unless child.is_a? Parser::AST::Node
|
187
|
-
|
188
|
-
if child.type == :ivar
|
189
|
-
@le_props[child.children.first] ||= nil
|
190
|
-
elsif child.type == :ivasgn || child.type == :op_asgn
|
191
|
-
prop = child.children.first
|
192
|
-
unless prop.is_a? Symbol
|
193
|
-
prop = prop.children.first if prop.type == :ivasgn
|
194
|
-
next unless prop.is_a? Symbol
|
195
|
-
end
|
196
|
-
|
197
|
-
@le_props[prop] = case child.children.last.type
|
198
|
-
when :str, :dstr
|
199
|
-
:String
|
200
|
-
when :array
|
201
|
-
:Array
|
202
|
-
when :int, :float
|
203
|
-
:Number
|
204
|
-
when :true, :false
|
205
|
-
:Boolean
|
206
|
-
else
|
207
|
-
@le_props[prop] || :Object
|
208
|
-
end
|
209
|
-
else
|
210
|
-
le_walk(child)
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
DEFAULTS.push LitElement
|
217
|
-
end
|
218
|
-
end
|
1
|
+
# for backwards compatibility
|
2
|
+
require_relative './lit'
|