ruby2js 3.5.3 → 4.0.2
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/README.md +5 -665
- data/lib/ruby2js.rb +60 -15
- data/lib/ruby2js/converter.rb +39 -3
- data/lib/ruby2js/converter/args.rb +6 -1
- data/lib/ruby2js/converter/assign.rb +159 -0
- data/lib/ruby2js/converter/begin.rb +7 -2
- data/lib/ruby2js/converter/case.rb +7 -2
- data/lib/ruby2js/converter/class.rb +80 -21
- data/lib/ruby2js/converter/class2.rb +107 -33
- data/lib/ruby2js/converter/def.rb +7 -3
- data/lib/ruby2js/converter/dstr.rb +8 -3
- data/lib/ruby2js/converter/for.rb +1 -1
- data/lib/ruby2js/converter/hash.rb +28 -6
- data/lib/ruby2js/converter/hide.rb +13 -0
- data/lib/ruby2js/converter/if.rb +10 -2
- data/lib/ruby2js/converter/import.rb +19 -4
- data/lib/ruby2js/converter/kwbegin.rb +9 -2
- data/lib/ruby2js/converter/literal.rb +14 -2
- data/lib/ruby2js/converter/logical.rb +1 -1
- data/lib/ruby2js/converter/module.rb +41 -4
- data/lib/ruby2js/converter/next.rb +10 -2
- data/lib/ruby2js/converter/opasgn.rb +8 -0
- data/lib/ruby2js/converter/redo.rb +14 -0
- data/lib/ruby2js/converter/return.rb +2 -1
- data/lib/ruby2js/converter/send.rb +73 -8
- data/lib/ruby2js/converter/vasgn.rb +5 -0
- data/lib/ruby2js/converter/while.rb +1 -1
- data/lib/ruby2js/converter/whilepost.rb +1 -1
- data/lib/ruby2js/converter/xstr.rb +2 -3
- data/lib/ruby2js/demo.rb +53 -0
- data/lib/ruby2js/es2022.rb +5 -0
- data/lib/ruby2js/es2022/strict.rb +3 -0
- data/lib/ruby2js/filter.rb +9 -1
- data/lib/ruby2js/filter/active_functions.rb +44 -0
- data/lib/ruby2js/filter/camelCase.rb +6 -3
- data/lib/ruby2js/filter/cjs.rb +2 -0
- data/lib/ruby2js/filter/esm.rb +118 -26
- data/lib/ruby2js/filter/functions.rb +137 -109
- data/lib/ruby2js/filter/{wunderbar.rb → jsx.rb} +29 -7
- data/lib/ruby2js/filter/node.rb +58 -14
- data/lib/ruby2js/filter/nokogiri.rb +12 -12
- data/lib/ruby2js/filter/react.rb +182 -57
- data/lib/ruby2js/filter/require.rb +102 -11
- data/lib/ruby2js/filter/return.rb +13 -1
- data/lib/ruby2js/filter/stimulus.rb +187 -0
- data/lib/ruby2js/jsx.rb +309 -0
- data/lib/ruby2js/namespace.rb +75 -0
- data/lib/ruby2js/serializer.rb +19 -12
- data/lib/ruby2js/sprockets.rb +40 -0
- data/lib/ruby2js/version.rb +3 -3
- data/ruby2js.gemspec +2 -2
- metadata +23 -13
- data/lib/ruby2js/filter/esm_migration.rb +0 -72
- data/lib/ruby2js/rails.rb +0 -63
@@ -8,6 +8,11 @@ module Ruby2JS
|
|
8
8
|
# (int 1))
|
9
9
|
|
10
10
|
handle :lvasgn, :gvasgn do |name, value=nil|
|
11
|
+
if @ast.type == :lvasgn and value
|
12
|
+
receiver = @rbstack.map {|rb| rb[name]}.compact.last
|
13
|
+
return parse s(:attr, receiver, "#{name}=", value) if receiver
|
14
|
+
end
|
15
|
+
|
11
16
|
state = @state
|
12
17
|
begin
|
13
18
|
if value and value.type == :lvasgn and @state == :statement
|
@@ -11,7 +11,7 @@ module Ruby2JS
|
|
11
11
|
begin
|
12
12
|
next_token, @next_token = @next_token, :continue
|
13
13
|
|
14
|
-
puts 'do {';
|
14
|
+
puts 'do {'; redoable block; sput '} while ('; parse condition; put ')'
|
15
15
|
ensure
|
16
16
|
@next_token = next_token
|
17
17
|
end
|
@@ -5,12 +5,11 @@ module Ruby2JS
|
|
5
5
|
# (str 'a'))
|
6
6
|
|
7
7
|
handle :xstr do |*children|
|
8
|
-
str = eval capture { parse_all(*children) }
|
9
|
-
|
10
8
|
if @binding
|
9
|
+
str = eval capture { parse_all(*children) }
|
11
10
|
puts @binding.eval(str).to_s
|
12
11
|
else
|
13
|
-
|
12
|
+
raise SecurityError.new('Insecure operation, eval without binding option')
|
14
13
|
end
|
15
14
|
end
|
16
15
|
end
|
data/lib/ruby2js/demo.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# helper methods shared between MRI CGI/server and Opal implementations
|
2
|
+
require 'ruby2js'
|
3
|
+
|
4
|
+
module Ruby2JS
|
5
|
+
module Demo
|
6
|
+
def self.parse_autoimports(mappings)
|
7
|
+
autoimports = {}
|
8
|
+
|
9
|
+
mappings = mappings.gsub(/\s+|"|'/, '')
|
10
|
+
|
11
|
+
while mappings and not mappings.empty?
|
12
|
+
if mappings =~ /^(\w+):([^,]+)(,(.*))?$/
|
13
|
+
# symbol: module
|
14
|
+
autoimports[$1.to_sym] = $2
|
15
|
+
mappings = $4
|
16
|
+
elsif mappings =~ /^\[([\w,]+)\]:([^,]+)(,(.*))?$/
|
17
|
+
# [symbol, symbol]: module
|
18
|
+
mname, mappings = $2, $4
|
19
|
+
autoimports[$1.split(/,/).map(&:to_sym)] = mname
|
20
|
+
elsif mappings =~ /^(\w+)(,(.*))?$/
|
21
|
+
# symbol
|
22
|
+
autoimports[$1.to_sym] = $1
|
23
|
+
mappings = $3
|
24
|
+
elsif not mappings.empty?
|
25
|
+
$load_error = "unsupported autoimports mapping: #{mappings}"
|
26
|
+
mappings = ''
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# if nothing is listed, provide a mapping for everything
|
31
|
+
autoimports = proc {|name| name.to_s} if autoimports.empty?
|
32
|
+
|
33
|
+
autoimports
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.parse_defs(mappings)
|
37
|
+
defs = {}
|
38
|
+
|
39
|
+
mappings = mappings.gsub(/\s+|"|'/, '')
|
40
|
+
|
41
|
+
while mappings =~ /^(\w+):\[(:?@?\w+(,:?@?\w+)*)\](,(.*))?$/
|
42
|
+
mappings = $5
|
43
|
+
defs[$1.to_sym] = $2.gsub(':', '').split(',').map(&:to_sym)
|
44
|
+
end
|
45
|
+
|
46
|
+
if mappings and not mappings.empty?
|
47
|
+
$load_error = "unsupported defs: #{mappings}"
|
48
|
+
end
|
49
|
+
|
50
|
+
defs
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/ruby2js/filter.rb
CHANGED
@@ -13,6 +13,14 @@ module Ruby2JS
|
|
13
13
|
@@included = nil
|
14
14
|
@@excluded = []
|
15
15
|
|
16
|
+
def self.included_methods
|
17
|
+
@@included&.dup
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.excluded_methods
|
21
|
+
@@excluded&.dup
|
22
|
+
end
|
23
|
+
|
16
24
|
# indicate that the specified methods are not to be processed
|
17
25
|
def self.exclude(*methods)
|
18
26
|
if @@included
|
@@ -52,7 +60,7 @@ module Ruby2JS
|
|
52
60
|
not @included.include? method
|
53
61
|
else
|
54
62
|
return true if @exclude_methods.flatten.include? method
|
55
|
-
@excluded
|
63
|
+
@excluded&.include? method
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'ruby2js'
|
2
|
+
|
3
|
+
module Ruby2JS
|
4
|
+
module Filter
|
5
|
+
module ActiveFunctions
|
6
|
+
include SEXP
|
7
|
+
|
8
|
+
def on_send(node)
|
9
|
+
target, method, *args = node.children
|
10
|
+
return super unless args.empty?
|
11
|
+
|
12
|
+
if es2015 and method == :blank?
|
13
|
+
create_or_update_import("blank$")
|
14
|
+
process node.updated :send, [nil, "blank$", target]
|
15
|
+
elsif es2015 and method == :present?
|
16
|
+
create_or_update_import("present$")
|
17
|
+
process node.updated :send, [nil, "present$", target]
|
18
|
+
elsif es2015 and method == :presence
|
19
|
+
create_or_update_import("presence$")
|
20
|
+
process node.updated :send, [nil, "presence$", target]
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def create_or_update_import(token)
|
29
|
+
af_import = @options[:import_from_skypack] ? "https://cdn.skypack.dev/@ruby2js/active-functions" : "@ruby2js/active-functions"
|
30
|
+
|
31
|
+
if found_node = prepend_list.find {|ast| ast.type == :import && ast.children.first == af_import}
|
32
|
+
unless found_node.children.last.find {|const| const.children.last == token}
|
33
|
+
prepend_list.delete found_node
|
34
|
+
prepend_list << s(:import, found_node.children.first, found_node.children.last.push(s(:const, nil, token)))
|
35
|
+
end
|
36
|
+
else
|
37
|
+
prepend_list << s(:import, af_import, [s(:const, nil, token)])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
DEFAULTS.push ActiveFunctions
|
43
|
+
end
|
44
|
+
end
|
@@ -9,8 +9,11 @@ module Ruby2JS
|
|
9
9
|
module CamelCase
|
10
10
|
include SEXP
|
11
11
|
|
12
|
-
|
12
|
+
ALLOWLIST = %w{
|
13
13
|
attr_accessor
|
14
|
+
attr_reader
|
15
|
+
attr_writer
|
16
|
+
method_missing
|
14
17
|
}
|
15
18
|
|
16
19
|
CAPS_EXCEPTIONS = {
|
@@ -37,7 +40,7 @@ module Ruby2JS
|
|
37
40
|
node = super
|
38
41
|
return node unless [:send, :csend, :attr].include? node.type
|
39
42
|
|
40
|
-
if node.children[0] == nil and
|
43
|
+
if node.children[0] == nil and ALLOWLIST.include? node.children[1].to_s
|
41
44
|
node
|
42
45
|
elsif node.children[0] && [:ivar, :cvar].include?(node.children[0].type)
|
43
46
|
S(node.type, s(node.children[0].type, camelCase(node.children[0].children[0])),
|
@@ -61,7 +64,7 @@ module Ruby2JS
|
|
61
64
|
def handle_generic_node(node, node_type)
|
62
65
|
return node if node.type != node_type
|
63
66
|
|
64
|
-
if node.children[0] =~ /_.*\w$/
|
67
|
+
if node.children[0] =~ /_.*\w$/ and !ALLOWLIST.include?(node.children[0].to_s)
|
65
68
|
S(node_type , camelCase(node.children[0]), *node.children[1..-1])
|
66
69
|
else
|
67
70
|
node
|
data/lib/ruby2js/filter/cjs.rb
CHANGED
data/lib/ruby2js/filter/esm.rb
CHANGED
@@ -7,30 +7,77 @@ module Ruby2JS
|
|
7
7
|
module ESM
|
8
8
|
include SEXP
|
9
9
|
|
10
|
-
def initialize(*args)
|
11
|
-
super
|
12
|
-
@esm = true # signal for other filters
|
13
|
-
@esm_imports = nil
|
14
|
-
end
|
15
|
-
|
16
10
|
def options=(options)
|
17
11
|
super
|
12
|
+
@esm_autoexports = !@disable_autoexports && options[:autoexports]
|
18
13
|
@esm_autoimports = options[:autoimports]
|
19
|
-
|
14
|
+
@esm_defs = options[:defs] || {}
|
15
|
+
@esm_explicit_tokens = Set.new
|
20
16
|
end
|
21
17
|
|
22
18
|
def process(node)
|
23
|
-
return super
|
24
|
-
@esm_imports = Set.new
|
25
|
-
result = super
|
19
|
+
return super unless @esm_autoexports
|
26
20
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
21
|
+
list = [node]
|
22
|
+
while list.length == 1 and list.first.type == :begin
|
23
|
+
list = list.first.children.dup
|
24
|
+
end
|
25
|
+
|
26
|
+
replaced = []
|
27
|
+
list.map! do |child|
|
28
|
+
replacement = child
|
29
|
+
|
30
|
+
if [:module, :class].include? child.type and
|
31
|
+
child.children.first.type == :const and
|
32
|
+
child.children.first.children.first == nil \
|
33
|
+
then
|
34
|
+
replacement = s(:export, child)
|
35
|
+
elsif child.type == :casgn and child.children.first == nil
|
36
|
+
replacement = s(:export, child)
|
37
|
+
elsif child.type == :def
|
38
|
+
replacement = s(:export, child)
|
39
|
+
end
|
40
|
+
|
41
|
+
if replacement != child
|
42
|
+
replaced << replacement
|
43
|
+
@comments[replacement] = @comments[child] if @comments[child]
|
44
|
+
end
|
45
|
+
|
46
|
+
replacement
|
33
47
|
end
|
48
|
+
|
49
|
+
if replaced.length == 1 and @esm_autoexports == :default
|
50
|
+
list.map! do |child|
|
51
|
+
if child == replaced.first
|
52
|
+
replacement = s(:export, s(:send, nil, :default, *child.children))
|
53
|
+
@comments[replacement] = @comments[child] if @comments[child]
|
54
|
+
replacement
|
55
|
+
else
|
56
|
+
child
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
@esm_autoexports = false
|
62
|
+
process s(:begin, *list)
|
63
|
+
end
|
64
|
+
|
65
|
+
def on_class(node)
|
66
|
+
@esm_explicit_tokens << node.children.first.children.last
|
67
|
+
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
def on_def(node)
|
72
|
+
@esm_explicit_tokens << node.children.first
|
73
|
+
|
74
|
+
super
|
75
|
+
end
|
76
|
+
|
77
|
+
def on_lvasgn(node)
|
78
|
+
@esm_explicit_tokens << node.children.first
|
79
|
+
|
80
|
+
super
|
34
81
|
end
|
35
82
|
|
36
83
|
def on_send(node)
|
@@ -46,7 +93,7 @@ module Ruby2JS
|
|
46
93
|
end
|
47
94
|
end
|
48
95
|
|
49
|
-
if args[0].type == :str
|
96
|
+
if args[0].type == :str and args.length == 1
|
50
97
|
# import "file.css"
|
51
98
|
# => import "file.css"
|
52
99
|
s(:import, args[0].children[0])
|
@@ -59,6 +106,8 @@ module Ruby2JS
|
|
59
106
|
args[0].children[2].children[2].type == :str
|
60
107
|
# import name from "file.js"
|
61
108
|
# => import name from "file.js"
|
109
|
+
@esm_explicit_tokens << args[0].children[1]
|
110
|
+
|
62
111
|
s(:import,
|
63
112
|
[args[0].children[2].children[2].children[0]],
|
64
113
|
process(s(:attr, nil, args[0].children[1])))
|
@@ -72,15 +121,25 @@ module Ruby2JS
|
|
72
121
|
# => import Stuff as * from "file.js"
|
73
122
|
# import [ Some, Stuff ], from: "file.js"
|
74
123
|
# => import { Some, Stuff } from "file.js"
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
124
|
+
# import Some, [ More, Stuff ], from: "file.js"
|
125
|
+
# => import Some, { More, Stuff } from "file.js"
|
126
|
+
imports = []
|
127
|
+
if %i(const send str).include? args[0].type
|
128
|
+
@esm_explicit_tokens << args[0].children.last
|
129
|
+
imports << process(args.shift)
|
130
|
+
end
|
131
|
+
|
132
|
+
if args[0].type == :array
|
133
|
+
args[0].children.each {|i| @esm_explicit_tokens << i.children.last}
|
134
|
+
imports << process_all(args.shift.children)
|
135
|
+
end
|
136
|
+
|
137
|
+
s(:import, args[0].children, *imports) unless args[0].nil?
|
79
138
|
end
|
80
139
|
elsif method == :export
|
81
140
|
s(:export, *process_all(args))
|
82
|
-
elsif
|
83
|
-
|
141
|
+
elsif target.nil? and found_import = find_autoimport(method)
|
142
|
+
prepend_list << s(:import, found_import[0], found_import[1])
|
84
143
|
super
|
85
144
|
else
|
86
145
|
super
|
@@ -88,12 +147,45 @@ module Ruby2JS
|
|
88
147
|
end
|
89
148
|
|
90
149
|
def on_const(node)
|
91
|
-
|
92
|
-
|
93
|
-
|
150
|
+
if node.children.first == nil and found_import = find_autoimport(node.children.last)
|
151
|
+
prepend_list << s(:import, found_import[0], found_import[1])
|
152
|
+
|
153
|
+
values = @esm_defs[node.children.last]
|
154
|
+
|
155
|
+
if values
|
156
|
+
values = values.map {|value|
|
157
|
+
if value.to_s.start_with? "@"
|
158
|
+
[value.to_s[1..-1].to_sym, s(:self)]
|
159
|
+
else
|
160
|
+
[value.to_sym, s(:autobind, s(:self))]
|
161
|
+
end
|
162
|
+
}.to_h
|
163
|
+
|
164
|
+
@namespace.defineProps values, [node.children.last]
|
165
|
+
end
|
94
166
|
end
|
167
|
+
|
95
168
|
super
|
96
169
|
end
|
170
|
+
|
171
|
+
def on_export(node)
|
172
|
+
s(:export, *process_all(node.children))
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
def find_autoimport(token)
|
179
|
+
return nil if @esm_autoimports.nil?
|
180
|
+
return nil if @esm_explicit_tokens.include?(token)
|
181
|
+
|
182
|
+
token = camelCase(token) if respond_to?(:camelCase)
|
183
|
+
|
184
|
+
if @esm_autoimports[token]
|
185
|
+
[@esm_autoimports[token], s(:const, nil, token)]
|
186
|
+
elsif found_key = @esm_autoimports.keys.find {|key| key.is_a?(Array) && key.include?(token)}
|
187
|
+
[@esm_autoimports[found_key], found_key.map {|key| s(:const, nil, key)}]
|
188
|
+
end
|
97
189
|
end
|
98
190
|
|
99
191
|
DEFAULTS.push ESM
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'ruby2js'
|
2
|
-
|
2
|
+
|
3
|
+
require 'regexp_parser/scanner'
|
3
4
|
|
4
5
|
module Ruby2JS
|
5
6
|
module Filter
|
@@ -7,7 +8,7 @@ module Ruby2JS
|
|
7
8
|
include SEXP
|
8
9
|
|
9
10
|
# require explicit opt-in to to class => constructor mapping
|
10
|
-
Filter.exclude :class
|
11
|
+
Filter.exclude :class, :call
|
11
12
|
|
12
13
|
VAR_TO_ASSIGN = {
|
13
14
|
lvar: :lvasgn,
|
@@ -23,91 +24,101 @@ module Ruby2JS
|
|
23
24
|
|
24
25
|
def on_send(node)
|
25
26
|
target, method, *args = node.children
|
26
|
-
return super if excluded?(method)
|
27
|
+
return super if excluded?(method) and method != :call
|
27
28
|
|
28
29
|
if [:max, :min].include? method and args.length == 0
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
if target.type == :array
|
31
|
+
process S(:send, s(:const, nil, :Math), node.children[1],
|
32
|
+
*target.children)
|
33
|
+
elsif node.is_method?
|
34
|
+
process S(:send, s(:const, nil, :Math), node.children[1],
|
35
|
+
s(:splat, target))
|
36
|
+
else
|
37
|
+
return super
|
38
|
+
end
|
32
39
|
|
33
|
-
elsif method == :call and target and
|
34
|
-
|
35
|
-
*args)
|
40
|
+
elsif method == :call and target and
|
41
|
+
(%i[ivar cvar].include?(target.type) or not excluded?(:call))
|
36
42
|
|
37
|
-
|
38
|
-
process S(:send, s(:attr, s(:self), :constructor),
|
39
|
-
"_#{target.children.first.to_s[2..-1]}", *args)
|
43
|
+
S(:call, process(target), nil, *process_all(args))
|
40
44
|
|
41
45
|
elsif method == :keys and args.length == 0 and node.is_method?
|
42
46
|
process S(:send, s(:const, nil, :Object), :keys, target)
|
43
47
|
|
44
48
|
elsif method == :[]= and args.length == 3 and
|
45
49
|
args[0].type == :regexp and args[1].type == :int
|
50
|
+
|
46
51
|
index = args[1].children.first
|
47
52
|
|
48
|
-
|
49
|
-
|
50
|
-
|
53
|
+
# identify groups
|
54
|
+
regex = args[0].children.first.children.first
|
55
|
+
tokens = Regexp::Scanner.scan(regex)
|
56
|
+
groups = []
|
57
|
+
stack = []
|
58
|
+
tokens.each do |token|
|
59
|
+
next unless token[0] == :group
|
60
|
+
if token[1] == :capture
|
61
|
+
groups.push token.dup
|
62
|
+
return super if groups.length == index and not stack.empty?
|
63
|
+
stack.push groups.last
|
64
|
+
elsif token[1] == :close
|
65
|
+
stack.pop[-1]=token.last
|
66
|
+
end
|
51
67
|
end
|
68
|
+
group = groups[index-1]
|
52
69
|
|
53
|
-
|
70
|
+
# rewrite regex
|
71
|
+
prepend = nil
|
72
|
+
append = nil
|
54
73
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
index -= 1
|
60
|
-
rewritten = ''
|
74
|
+
if group[4] < regex.length
|
75
|
+
regex = (regex[0...group[4]] + '(' + regex[group[4]..-1] + ')').
|
76
|
+
sub(/\$\)$/, ')$')
|
77
|
+
append = 2
|
61
78
|
end
|
62
79
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
if parts.first.type == :anchor
|
67
|
-
pre = parts.shift.to_s
|
68
|
-
split -= 1
|
80
|
+
if group[4] - group[3] == 2
|
81
|
+
regex = regex[0...group[3]] + regex[group[4]..-1]
|
82
|
+
append = 1 if append
|
69
83
|
end
|
70
84
|
|
71
|
-
if
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
index += 1
|
77
|
-
end
|
78
|
-
dstr.unshift s(:send, s(:lvar, :match), :[], s(:int, 0))
|
85
|
+
if group[3] > 0
|
86
|
+
regex = ('(' + regex[0...group[3]] + ')' + regex[group[3]..-1]).
|
87
|
+
sub(/^\(\^/, '^(')
|
88
|
+
prepend = 1
|
89
|
+
append += 1 if append
|
79
90
|
end
|
80
91
|
|
92
|
+
regex = process s(:regexp, s(:str, regex), args[0].children.last)
|
81
93
|
|
82
|
-
|
83
|
-
if
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
94
|
+
#
|
95
|
+
if args.last.type == :str
|
96
|
+
str = args.last.children.first.gsub('$', '$$')
|
97
|
+
str = "$#{prepend}#{str}" if prepend
|
98
|
+
str = "#{str}$#{append}" if append
|
99
|
+
expr = s(:send, target, :replace, regex, s(:str, str))
|
100
|
+
else
|
101
|
+
dstr = args.last.type == :dstr ? args.last.children.dup : [args.last]
|
102
|
+
if prepend
|
103
|
+
dstr.unshift s(:send, s(:lvar, :match), :[], s(:int, prepend-1))
|
104
|
+
end
|
105
|
+
if append
|
106
|
+
dstr << s(:send, s(:lvar, :match), :[], s(:int, append-1))
|
92
107
|
end
|
93
|
-
dstr << s(:send, s(:lvar, :match), :[], s(:int, index))
|
94
|
-
end
|
95
|
-
|
96
|
-
rewritten = pre + rewritten + post
|
97
108
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
109
|
+
expr = s(:block,
|
110
|
+
s(:send, target, :replace, regex),
|
111
|
+
s(:args, s(:arg, :match)),
|
112
|
+
process(s(:dstr, *dstr)))
|
113
|
+
end
|
103
114
|
|
104
115
|
if VAR_TO_ASSIGN.keys.include? target.type
|
105
|
-
S(VAR_TO_ASSIGN[target.type], target.children.first,
|
116
|
+
S(VAR_TO_ASSIGN[target.type], target.children.first, expr)
|
106
117
|
elsif target.type == :send
|
107
118
|
if target.children[0] == nil
|
108
|
-
S(:lvasgn, target.children[1],
|
119
|
+
S(:lvasgn, target.children[1], expr)
|
109
120
|
else
|
110
|
-
S(:send, target.children[0], :"#{target.children[1]}=",
|
121
|
+
S(:send, target.children[0], :"#{target.children[1]}=", expr)
|
111
122
|
end
|
112
123
|
else
|
113
124
|
super
|
@@ -116,57 +127,14 @@ module Ruby2JS
|
|
116
127
|
elsif method == :merge
|
117
128
|
args.unshift target
|
118
129
|
|
119
|
-
if
|
120
|
-
|
121
|
-
process S(:hash, *args.map {|arg| s(:kwsplat, arg)})
|
122
|
-
else
|
123
|
-
process S(:send, s(:const, nil, :Object), :assign, s(:hash),
|
124
|
-
*args)
|
125
|
-
end
|
130
|
+
if es2018
|
131
|
+
process S(:hash, *args.map {|arg| s(:kwsplat, arg)})
|
126
132
|
else
|
127
|
-
|
128
|
-
|
129
|
-
s(:send, s(:block, s(:send, nil, :lambda), s(:args),
|
130
|
-
s(:begin, *copy, *args.map {|modname|
|
131
|
-
if modname.type == :hash
|
132
|
-
s(:begin, *modname.children.map {|pair|
|
133
|
-
s(:send, s(:gvar, :$$), :[]=, *pair.children)
|
134
|
-
})
|
135
|
-
else
|
136
|
-
s(:for, s(:lvasgn, :$_), modname,
|
137
|
-
s(:send, s(:gvar, :$$), :[]=,
|
138
|
-
s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
|
139
|
-
end
|
140
|
-
}, s(:return, s(:gvar, :$$)))), :[])
|
133
|
+
process S(:assign, s(:hash), *args)
|
141
134
|
end
|
142
135
|
|
143
136
|
elsif method == :merge!
|
144
|
-
|
145
|
-
process S(:send, s(:const, nil, :Object), :assign, target, *args)
|
146
|
-
else
|
147
|
-
copy = []
|
148
|
-
|
149
|
-
unless
|
150
|
-
target.type == :send and target.children.length == 2 and
|
151
|
-
target.children[0] == nil
|
152
|
-
then
|
153
|
-
copy << s(:gvasgn, :$0, target)
|
154
|
-
target = s(:gvar, :$0)
|
155
|
-
end
|
156
|
-
|
157
|
-
s(:send, s(:block, s(:send, nil, :lambda), s(:args),
|
158
|
-
s(:begin, *copy, *args.map {|modname|
|
159
|
-
if modname.type == :hash
|
160
|
-
s(:begin, *modname.children.map {|pair|
|
161
|
-
s(:send, target, :[]=, *pair.children)
|
162
|
-
})
|
163
|
-
else
|
164
|
-
s(:for, s(:lvasgn, :$_), modname,
|
165
|
-
s(:send, target, :[]=,
|
166
|
-
s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
|
167
|
-
end
|
168
|
-
}, s(:return, target))), :[])
|
169
|
-
end
|
137
|
+
process S(:assign, target, *args)
|
170
138
|
|
171
139
|
elsif method == :delete and args.length == 1
|
172
140
|
if not target
|
@@ -242,10 +210,10 @@ module Ruby2JS
|
|
242
210
|
s(:block, s(:send, nil, :proc), s(:args, s(:arg, :s)),
|
243
211
|
s(:send, s(:lvar, :s), :slice, s(:int, 1))))
|
244
212
|
else
|
245
|
-
# str.match(/.../g).map(s => s.match(/.../).slice(1))
|
213
|
+
# (str.match(/.../g) || []).map(s => s.match(/.../).slice(1))
|
246
214
|
s(:block, s(:send,
|
247
|
-
s(:send, process(target), :match, gpattern), :
|
248
|
-
s(:args, s(:arg, :s)),
|
215
|
+
s(:or, s(:send, process(target), :match, gpattern), s(:array)),
|
216
|
+
:map), s(:args, s(:arg, :s)),
|
249
217
|
s(:return, s(:send, s(:send, s(:lvar, :s), :match, arg),
|
250
218
|
:slice, s(:int, 1))))
|
251
219
|
end
|
@@ -540,6 +508,55 @@ module Ruby2JS
|
|
540
508
|
elsif method == :floor and args.length == 0
|
541
509
|
process S(:send, s(:const, nil, :Math), :floor, target)
|
542
510
|
|
511
|
+
elsif method == :rand and target == nil
|
512
|
+
if args.length == 0
|
513
|
+
process S(:send!, s(:const, nil, :Math), :random)
|
514
|
+
elsif %i[irange erange].include? args.first.type
|
515
|
+
range = args.first
|
516
|
+
multiplier = s(:send, range.children.last, :-, range.children.first)
|
517
|
+
if range.children.all? {|child| child.type == :int}
|
518
|
+
multiplier = s(:int, range.children.last.children.last - range.children.first.children.last)
|
519
|
+
multiplier = s(:int, multiplier.children.first + 1) if range.type == :irange
|
520
|
+
elsif range.type == :irange
|
521
|
+
if multiplier.children.last.type == :int
|
522
|
+
diff = multiplier.children.last.children.last - 1
|
523
|
+
multiplier = s(:send, *multiplier.children[0..1], s(:int, diff))
|
524
|
+
multiplier = multiplier.children.first if diff == 0
|
525
|
+
multiplier = s(:send, multiplier.children[0], :+, s(:int, -diff)) if diff < 0
|
526
|
+
else
|
527
|
+
multiplier = s(:send, multiplier, :+, s(:int, 1))
|
528
|
+
end
|
529
|
+
end
|
530
|
+
raw = s(:send, s(:send, s(:const, nil, :Math), :random), :*, multiplier)
|
531
|
+
if range.children.first != s(:int, 0)
|
532
|
+
raw = s(:send, raw, :+, range.children.first)
|
533
|
+
end
|
534
|
+
process S(:send, nil, :parseInt, raw)
|
535
|
+
else
|
536
|
+
process S(:send, nil, :parseInt,
|
537
|
+
s(:send, s(:send, s(:const, nil, :Math), :random),
|
538
|
+
:*, args.first))
|
539
|
+
end
|
540
|
+
|
541
|
+
elsif method == :sum and args.length == 0
|
542
|
+
process S(:send, target, :reduce, s(:block, s(:send, nil, :proc),
|
543
|
+
s(:args, s(:arg, :a), s(:arg, :b)),
|
544
|
+
s(:send, s(:lvar, :a), :+, s(:lvar, :b))), s(:int, 0))
|
545
|
+
|
546
|
+
elsif method == :method_defined? and args.length >= 1
|
547
|
+
if args[1] == s(:false)
|
548
|
+
process S(:send, s(:attr, target, :prototype), :hasOwnProperty, args[0])
|
549
|
+
elsif args.length == 1 or args[1] == s(:true)
|
550
|
+
process S(:in?, args[0], s(:attr, target, :prototype))
|
551
|
+
else
|
552
|
+
process S(:if, args[1], s(:in?, args[0], s(:attr, target, :prototype)),
|
553
|
+
s(:send, s(:attr, target, :prototype), :hasOwnProperty, args[0]))
|
554
|
+
end
|
555
|
+
|
556
|
+
elsif method == :alias_method and args.length == 2
|
557
|
+
process S(:send, s(:attr, target, :prototype), :[]=, args[0],
|
558
|
+
s(:attr, s(:attr, target, :prototype), args[1].children[0]))
|
559
|
+
|
543
560
|
else
|
544
561
|
super
|
545
562
|
end
|
@@ -726,6 +743,10 @@ module Ruby2JS
|
|
726
743
|
s(:return, s(:lvar, node.children[1].children[0].children[0])))),
|
727
744
|
:[], call.children[0]])
|
728
745
|
|
746
|
+
elsif method == :define_method and call.children.length == 3
|
747
|
+
process node.updated(:send, [s(:attr, call.children[0], :prototype), :[]=,
|
748
|
+
call.children[2], s(:deff, nil, *node.children[1..-1])])
|
749
|
+
|
729
750
|
else
|
730
751
|
super
|
731
752
|
end
|
@@ -735,6 +756,12 @@ module Ruby2JS
|
|
735
756
|
name, inheritance, *body = node.children
|
736
757
|
body.compact!
|
737
758
|
|
759
|
+
body.each_with_index do |node, i|
|
760
|
+
if node.type == :send and node.children[0..1] == [nil, :alias_method]
|
761
|
+
body[i] = node.updated(:send, [name, *node.children[1..-1]])
|
762
|
+
end
|
763
|
+
end
|
764
|
+
|
738
765
|
if inheritance == s(:const, nil, :Exception)
|
739
766
|
unless
|
740
767
|
body.any? {|statement| statement.type == :def and
|
@@ -750,7 +777,8 @@ module Ruby2JS
|
|
750
777
|
body = [s(:begin, *body)] if body.length > 1
|
751
778
|
S(:class, name, s(:const, nil, :Error), *body)
|
752
779
|
else
|
753
|
-
|
780
|
+
body = [s(:begin, *body)] if body.length > 1
|
781
|
+
super S(:class, name, inheritance, *body)
|
754
782
|
end
|
755
783
|
end
|
756
784
|
end
|