ruby2js 3.4.0 → 3.6.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.
- 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
|