ruby2js 3.4.0 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +128 -20
- data/lib/ruby2js.rb +30 -2
- data/lib/ruby2js/converter.rb +7 -5
- data/lib/ruby2js/converter/block.rb +5 -0
- data/lib/ruby2js/converter/class2.rb +63 -20
- data/lib/ruby2js/converter/def.rb +1 -1
- data/lib/ruby2js/converter/import.rb +17 -1
- data/lib/ruby2js/converter/ivar.rb +10 -2
- data/lib/ruby2js/converter/literal.rb +14 -2
- data/lib/ruby2js/converter/send.rb +4 -3
- data/lib/ruby2js/converter/xstr.rb +1 -1
- data/lib/ruby2js/filter/active_functions.rb +43 -0
- data/lib/ruby2js/filter/camelCase.rb +4 -3
- data/lib/ruby2js/filter/esm.rb +96 -4
- data/lib/ruby2js/filter/functions.rb +14 -0
- data/lib/ruby2js/filter/node.rb +95 -74
- data/lib/ruby2js/filter/nokogiri.rb +3 -29
- data/lib/ruby2js/filter/return.rb +2 -0
- data/lib/ruby2js/filter/securerandom.rb +33 -0
- data/lib/ruby2js/filter/vue.rb +9 -0
- data/lib/ruby2js/rails.rb +15 -9
- data/lib/ruby2js/serializer.rb +4 -2
- data/lib/ruby2js/version.rb +1 -1
- data/ruby2js.gemspec +1 -1
- metadata +9 -7
- data/lib/ruby2js/filter/esm_migration.rb +0 -72
@@ -9,11 +9,22 @@ module Ruby2JS
|
|
9
9
|
# NOTE: this is the es2015 version of class
|
10
10
|
|
11
11
|
handle :class2 do |name, inheritance, *body|
|
12
|
+
body.compact!
|
13
|
+
while body.length == 1 and body.first.type == :begin
|
14
|
+
body = body.first.children
|
15
|
+
end
|
16
|
+
|
17
|
+
proxied = body.find do |node|
|
18
|
+
node.type == :def and node.children.first == :method_missing
|
19
|
+
end
|
20
|
+
|
12
21
|
if name.type == :const and name.children.first == nil
|
13
22
|
put 'class '
|
14
23
|
parse name
|
24
|
+
put '$' if proxied
|
15
25
|
else
|
16
26
|
parse name
|
27
|
+
put '$' if proxied
|
17
28
|
put ' = class'
|
18
29
|
end
|
19
30
|
|
@@ -24,11 +35,6 @@ module Ruby2JS
|
|
24
35
|
|
25
36
|
put " {"
|
26
37
|
|
27
|
-
body.compact!
|
28
|
-
while body.length == 1 and body.first.type == :begin
|
29
|
-
body = body.first.children
|
30
|
-
end
|
31
|
-
|
32
38
|
begin
|
33
39
|
class_name, @class_name = @class_name, name
|
34
40
|
class_parent, @class_parent = @class_parent, inheritance
|
@@ -64,21 +70,21 @@ module Ruby2JS
|
|
64
70
|
walk[child] if child.is_a? Parser::AST::Node
|
65
71
|
end
|
66
72
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
73
|
+
if ast.type == :send and ast.children.first == nil
|
74
|
+
if ast.children[1] == :attr_accessor
|
75
|
+
ast.children[2..-1].each_with_index do |child_sym, index2|
|
76
|
+
ivars << :"@#{child_sym.children.first}"
|
77
|
+
end
|
78
|
+
elsif ast.children[1] == :attr_reader
|
79
|
+
ast.children[2..-1].each_with_index do |child_sym, index2|
|
80
|
+
ivars << :"@#{child_sym.children.first}"
|
81
|
+
end
|
82
|
+
elsif ast.children[1] == :attr_writer
|
83
|
+
ast.children[2..-1].each_with_index do |child_sym, index2|
|
84
|
+
ivars << :"@#{child_sym.children.first}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
82
88
|
|
83
89
|
end
|
84
90
|
walk[@ast]
|
@@ -299,6 +305,43 @@ module Ruby2JS
|
|
299
305
|
end
|
300
306
|
end
|
301
307
|
|
308
|
+
if proxied
|
309
|
+
put @sep
|
310
|
+
|
311
|
+
rename = name.updated(nil, [name.children.first, name.children.last.to_s + '$'])
|
312
|
+
|
313
|
+
if proxied.children[1].children.length == 1
|
314
|
+
# special case: if method_missing only has on argument, call it
|
315
|
+
# directly (i.e., don't pass arguments). This enables
|
316
|
+
# method_missing to return instance attributes (getters) as well
|
317
|
+
# as bound functions (methods).
|
318
|
+
forward = s(:send, s(:lvar, :obj), :method_missing, s(:lvar, :prop))
|
319
|
+
else
|
320
|
+
# normal case: return a function which, when called, will call
|
321
|
+
# method_missing with method name and arguments.
|
322
|
+
forward = s(:block, s(:send, nil, :proc), s(:args, s(:restarg, :args)),
|
323
|
+
s(:send, s(:lvar, :obj), :method_missing, s(:lvar, :prop),
|
324
|
+
s(:splat, s(:lvar, :args))))
|
325
|
+
end
|
326
|
+
|
327
|
+
proxy = s(:return, s(:send, s(:const, nil, :Proxy), :new,
|
328
|
+
s(:send, rename, :new, s(:splat, s(:lvar, :args))),
|
329
|
+
s(:hash, s(:pair, s(:sym, :get), s(:block, s(:send, nil, :proc),
|
330
|
+
s(:args, s(:arg, :obj), s(:arg, :prop)),
|
331
|
+
s(:if, s(:in?, s(:lvar, :prop), s(:lvar, :obj)),
|
332
|
+
s(:return, s(:send, s(:lvar, :obj), :[], s(:lvar, :prop))),
|
333
|
+
s(:return, forward))))))
|
334
|
+
)
|
335
|
+
|
336
|
+
if name.children.first == nil
|
337
|
+
proxy = s(:def, name.children.last, s(:args, s(:restarg, :args)), proxy)
|
338
|
+
else
|
339
|
+
proxy = s(:defs, *name.children, s(:args, s(:restarg, :args)), proxy)
|
340
|
+
end
|
341
|
+
|
342
|
+
parse proxy
|
343
|
+
end
|
344
|
+
|
302
345
|
ensure
|
303
346
|
@class_name = class_name
|
304
347
|
@class_parent = class_parent
|
@@ -131,7 +131,7 @@ module Ruby2JS
|
|
131
131
|
style = :statement
|
132
132
|
end
|
133
133
|
|
134
|
-
if args.children.length == 1 and style == :expression
|
134
|
+
if args.children.length == 1 and args.children.first.type != :restarg and style == :expression
|
135
135
|
parse args; put ' => '
|
136
136
|
else
|
137
137
|
put '('; parse args; put ') => '
|
@@ -6,7 +6,23 @@ module Ruby2JS
|
|
6
6
|
# NOTE: import is a synthetic
|
7
7
|
|
8
8
|
handle :import do |path, *args|
|
9
|
+
if module_type == :cjs
|
10
|
+
# only the subset of import syntaxes generated by filters are handled here
|
11
|
+
if Parser::AST::Node === args.first and args.first.type == :attr
|
12
|
+
return parse s(:casgn, *args.first.children,
|
13
|
+
s(:send, nil, :require, s(:str, Array(path).first))), :statement
|
14
|
+
elsif Array === args.first and args.first.length == 1
|
15
|
+
target = args.first.first
|
16
|
+
if Parser::AST::Node === target and target.type == :attr and target.children.first == nil
|
17
|
+
return parse s(:casgn, *target.children,
|
18
|
+
s(:attr, s(:send, nil, :require, s(:str, Array(path).first)), target.children.last)),
|
19
|
+
:statement
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
9
24
|
put 'import '
|
25
|
+
|
10
26
|
if args.length == 0
|
11
27
|
# import "file.css"
|
12
28
|
put path.inspect
|
@@ -66,7 +82,7 @@ module Ruby2JS
|
|
66
82
|
elsif node.respond_to?(:type) && node.children[1] == :default
|
67
83
|
put 'default '
|
68
84
|
args[0] = node.children[2]
|
69
|
-
elsif node.respond_to?(:type) && node.type
|
85
|
+
elsif node.respond_to?(:type) && [:lvasgn, :casgn].include?(node.type)
|
70
86
|
if node.children[0] == :default
|
71
87
|
put 'default '
|
72
88
|
args[0] = node.children[1]
|
@@ -16,8 +16,16 @@ module Ruby2JS
|
|
16
16
|
handle :hostvalue do |value|
|
17
17
|
case value
|
18
18
|
when Hash
|
19
|
-
parse s(:hash, *value.map {|key, hvalue|
|
20
|
-
|
19
|
+
parse s(:hash, *value.map {|key, hvalue|
|
20
|
+
case key
|
21
|
+
when String
|
22
|
+
s(:pair, s(:str, key), s(:hostvalue, hvalue))
|
23
|
+
when Symbol
|
24
|
+
s(:pair, s(:sym, key), s(:hostvalue, hvalue))
|
25
|
+
else
|
26
|
+
s(:pair, s(:hostvalue, key), s(:hostvalue, hvalue))
|
27
|
+
end
|
28
|
+
})
|
21
29
|
when Array
|
22
30
|
parse s(:array, *value.map {|hvalue| s(:hostvalue, hvalue)})
|
23
31
|
when String
|
@@ -5,12 +5,24 @@ module Ruby2JS
|
|
5
5
|
# (float 1.1)
|
6
6
|
# (str "1"))
|
7
7
|
|
8
|
-
handle :
|
8
|
+
handle :str do |value|
|
9
9
|
put value.inspect
|
10
10
|
end
|
11
11
|
|
12
|
+
handle :int, :float do |value|
|
13
|
+
put number_format(value)
|
14
|
+
end
|
15
|
+
|
12
16
|
handle :octal do |value|
|
13
|
-
put '0' + value.to_s(8)
|
17
|
+
put '0' + number_format(value.to_s(8))
|
18
|
+
end
|
19
|
+
|
20
|
+
def number_format(number)
|
21
|
+
return number.to_s unless es2021
|
22
|
+
parts = number.to_s.split('.')
|
23
|
+
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1_")
|
24
|
+
parts[1].gsub!(/(\d\d\d)(?=\d)/, "\\1_") if parts[1]
|
25
|
+
parts.join('.')
|
14
26
|
end
|
15
27
|
end
|
16
28
|
end
|
@@ -9,11 +9,12 @@ module Ruby2JS
|
|
9
9
|
# (sendw nil :puts
|
10
10
|
# (int 1))
|
11
11
|
|
12
|
-
# Note: attr, sendw, and await are only generated by filters. Attr forces
|
12
|
+
# Note: attr, sendw, send!, and await are only generated by filters. Attr forces
|
13
13
|
# interpretation as an attribute vs a function call with zero parameters.
|
14
|
+
# send! forces interpretation as a method call even with zero parameters.
|
14
15
|
# Sendw forces parameters to be placed on separate lines.
|
15
16
|
|
16
|
-
handle :send, :sendw, :await, :attr, :call do |receiver, method, *args|
|
17
|
+
handle :send, :sendw, :send!, :await, :attr, :call do |receiver, method, *args|
|
17
18
|
ast = @ast
|
18
19
|
|
19
20
|
if \
|
@@ -280,7 +281,7 @@ module Ruby2JS
|
|
280
281
|
else
|
281
282
|
put 'await ' if @ast.type == :await
|
282
283
|
|
283
|
-
if not ast.is_method?
|
284
|
+
if not ast.is_method? and ast.type != :send!
|
284
285
|
if receiver
|
285
286
|
(group_receiver ? group(receiver) : parse(receiver))
|
286
287
|
put ".#{ method }"
|
@@ -0,0 +1,43 @@
|
|
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
|
+
|
11
|
+
if es2015 and method == :blank?
|
12
|
+
create_or_update_import("blank$")
|
13
|
+
process node.updated :send, [nil, "blank$", target]
|
14
|
+
elsif es2015 and method == :present?
|
15
|
+
create_or_update_import("present$")
|
16
|
+
process node.updated :send, [nil, "present$", target]
|
17
|
+
elsif es2015 and method == :presence
|
18
|
+
create_or_update_import("presence$")
|
19
|
+
process node.updated :send, [nil, "presence$", target]
|
20
|
+
else
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def create_or_update_import(token)
|
28
|
+
af_import = @options[:import_from_skypack] ? "https://cdn.skypack.dev/@ruby2js/active-functions" : "@ruby2js/active-functions"
|
29
|
+
|
30
|
+
if found_node = prepend_list.find {|ast| ast.type == :import && ast.children.first == af_import}
|
31
|
+
unless found_node.children.find {|child| child == token}
|
32
|
+
prepend_list.delete found_node
|
33
|
+
prepend_list << s(:import, found_node.children.first, found_node.children.last.push(s(:const, nil, token)))
|
34
|
+
end
|
35
|
+
else
|
36
|
+
prepend_list << s(:import, af_import, [s(:const, nil, token)])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
DEFAULTS.push ActiveFunctions
|
42
|
+
end
|
43
|
+
end
|
@@ -9,8 +9,9 @@ module Ruby2JS
|
|
9
9
|
module CamelCase
|
10
10
|
include SEXP
|
11
11
|
|
12
|
-
|
12
|
+
ALLOWLIST = %w{
|
13
13
|
attr_accessor
|
14
|
+
method_missing
|
14
15
|
}
|
15
16
|
|
16
17
|
CAPS_EXCEPTIONS = {
|
@@ -37,7 +38,7 @@ module Ruby2JS
|
|
37
38
|
node = super
|
38
39
|
return node unless [:send, :csend, :attr].include? node.type
|
39
40
|
|
40
|
-
if node.children[0] == nil and
|
41
|
+
if node.children[0] == nil and ALLOWLIST.include? node.children[1].to_s
|
41
42
|
node
|
42
43
|
elsif node.children[0] && [:ivar, :cvar].include?(node.children[0].type)
|
43
44
|
S(node.type, s(node.children[0].type, camelCase(node.children[0].children[0])),
|
@@ -61,7 +62,7 @@ module Ruby2JS
|
|
61
62
|
def handle_generic_node(node, node_type)
|
62
63
|
return node if node.type != node_type
|
63
64
|
|
64
|
-
if node.children[0] =~ /_.*\w$/
|
65
|
+
if node.children[0] =~ /_.*\w$/ and !ALLOWLIST.include?(node.children[0].to_s)
|
65
66
|
S(node_type , camelCase(node.children[0]), *node.children[1..-1])
|
66
67
|
else
|
67
68
|
node
|
data/lib/ruby2js/filter/esm.rb
CHANGED
@@ -1,13 +1,68 @@
|
|
1
1
|
require 'ruby2js'
|
2
2
|
|
3
|
+
Ruby2JS.module_default = :esm
|
4
|
+
|
3
5
|
module Ruby2JS
|
4
6
|
module Filter
|
5
7
|
module ESM
|
6
8
|
include SEXP
|
7
9
|
|
8
|
-
def
|
10
|
+
def options=(options)
|
11
|
+
super
|
12
|
+
@esm_autoexports = options[:autoexports] && !@disable_autoexports
|
13
|
+
@esm_autoimports = options[:autoimports]
|
14
|
+
@esm_explicit_tokens = Set.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def process(node)
|
18
|
+
return super unless @esm_autoexports
|
19
|
+
@esm_autoexports = false
|
20
|
+
|
21
|
+
list = [node]
|
22
|
+
while list.length == 1 and list.first.type == :begin
|
23
|
+
list = list.first.children.dup
|
24
|
+
end
|
25
|
+
|
26
|
+
list.map! do |child|
|
27
|
+
replacement = child
|
28
|
+
|
29
|
+
if [:module, :class].include? child.type and
|
30
|
+
child.children.first.type == :const and
|
31
|
+
child.children.first.children.first == nil \
|
32
|
+
then
|
33
|
+
replacement = s(:export, child)
|
34
|
+
elsif child.type == :casgn and child.children.first == nil
|
35
|
+
replacement = s(:export, child)
|
36
|
+
elsif child.type == :def
|
37
|
+
replacement = s(:export, child)
|
38
|
+
end
|
39
|
+
|
40
|
+
if replacement != child and @comments[child]
|
41
|
+
@comments[replacement] = @comments[child]
|
42
|
+
end
|
43
|
+
|
44
|
+
replacement
|
45
|
+
end
|
46
|
+
|
47
|
+
process s(:begin, *list)
|
48
|
+
end
|
49
|
+
|
50
|
+
def on_class(node)
|
51
|
+
@esm_explicit_tokens << node.children.first.children.last
|
52
|
+
|
53
|
+
super
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_def(node)
|
57
|
+
@esm_explicit_tokens << node.children.first
|
58
|
+
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
62
|
+
def on_lvasgn(node)
|
63
|
+
@esm_explicit_tokens << node.children.first
|
64
|
+
|
9
65
|
super
|
10
|
-
@esm = true # signal for other filters
|
11
66
|
end
|
12
67
|
|
13
68
|
def on_send(node)
|
@@ -36,6 +91,8 @@ module Ruby2JS
|
|
36
91
|
args[0].children[2].children[2].type == :str
|
37
92
|
# import name from "file.js"
|
38
93
|
# => import name from "file.js"
|
94
|
+
@esm_explicit_tokens << args[0].children[1]
|
95
|
+
|
39
96
|
s(:import,
|
40
97
|
[args[0].children[2].children[2].children[0]],
|
41
98
|
process(s(:attr, nil, args[0].children[1])))
|
@@ -49,17 +106,52 @@ module Ruby2JS
|
|
49
106
|
# => import Stuff as * from "file.js"
|
50
107
|
# import [ Some, Stuff ], from: "file.js"
|
51
108
|
# => import { Some, Stuff } from "file.js"
|
52
|
-
imports =
|
53
|
-
|
109
|
+
imports = if args[0].type == :const || args[0].type == :send
|
110
|
+
@esm_explicit_tokens << args[0].children.last
|
111
|
+
process(args[0])
|
112
|
+
else
|
113
|
+
args[0].children.each {|i| @esm_explicit_tokens << i.children.last}
|
54
114
|
process_all(args[0].children)
|
115
|
+
end
|
116
|
+
|
55
117
|
s(:import, args[1].children, imports) unless args[1].nil?
|
56
118
|
end
|
57
119
|
elsif method == :export
|
58
120
|
s(:export, *process_all(args))
|
121
|
+
elsif target.nil? and found_import = find_autoimport(method)
|
122
|
+
prepend_list << s(:import, found_import[0], found_import[1])
|
123
|
+
super
|
59
124
|
else
|
60
125
|
super
|
61
126
|
end
|
62
127
|
end
|
128
|
+
|
129
|
+
def on_const(node)
|
130
|
+
if node.children.first == nil and found_import = find_autoimport(node.children.last)
|
131
|
+
prepend_list << s(:import, found_import[0], found_import[1])
|
132
|
+
end
|
133
|
+
|
134
|
+
super
|
135
|
+
end
|
136
|
+
|
137
|
+
def on_export(node)
|
138
|
+
s(:export, *process_all(node.children))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def find_autoimport(token)
|
145
|
+
return nil if @esm_autoimports.nil?
|
146
|
+
return nil if @esm_explicit_tokens.include?(token)
|
147
|
+
|
148
|
+
token = camelCase(token) if respond_to?(:camelCase)
|
149
|
+
|
150
|
+
if @esm_autoimports[token]
|
151
|
+
[@esm_autoimports[token], s(:const, nil, token)]
|
152
|
+
elsif found_key = @esm_autoimports.keys.find {|key| key.is_a?(Array) && key.include?(token)}
|
153
|
+
[@esm_autoimports[found_key], found_key.map {|key| s(:const, nil, key)}]
|
154
|
+
end
|
63
155
|
end
|
64
156
|
|
65
157
|
DEFAULTS.push ESM
|
@@ -531,6 +531,20 @@ module Ruby2JS
|
|
531
531
|
elsif method == :block_given? and target == nil and args.length == 0
|
532
532
|
process process s(:lvar, "_implicitBlockYield")
|
533
533
|
|
534
|
+
elsif method == :abs and args.length == 0
|
535
|
+
process S(:send, s(:const, nil, :Math), :abs, target)
|
536
|
+
|
537
|
+
elsif method == :ceil and args.length == 0
|
538
|
+
process S(:send, s(:const, nil, :Math), :ceil, target)
|
539
|
+
|
540
|
+
elsif method == :floor and args.length == 0
|
541
|
+
process S(:send, s(:const, nil, :Math), :floor, target)
|
542
|
+
|
543
|
+
elsif method == :sum and args.length == 0
|
544
|
+
process S(:send, target, :reduce, s(:block, s(:send, nil, :proc),
|
545
|
+
s(:args, s(:arg, :a), s(:arg, :b)),
|
546
|
+
s(:send, s(:lvar, :a), :+, s(:lvar, :b))), s(:int, 0))
|
547
|
+
|
534
548
|
else
|
535
549
|
super
|
536
550
|
end
|