ruby2js 3.0.15 → 3.1.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 +45 -1
- data/lib/ruby2js.rb +15 -1
- data/lib/ruby2js/converter.rb +12 -0
- data/lib/ruby2js/converter/args.rb +30 -0
- data/lib/ruby2js/converter/casgn.rb +3 -2
- data/lib/ruby2js/converter/class2.rb +82 -7
- data/lib/ruby2js/converter/cvar.rb +5 -3
- data/lib/ruby2js/converter/cvasgn.rb +5 -3
- data/lib/ruby2js/converter/hash.rb +19 -3
- data/lib/ruby2js/converter/ivar.rb +2 -0
- data/lib/ruby2js/converter/ivasgn.rb +1 -1
- data/lib/ruby2js/converter/kwbegin.rb +16 -2
- data/lib/ruby2js/converter/send.rb +113 -48
- data/lib/ruby2js/es2018.rb +5 -0
- data/lib/ruby2js/es2018/strict.rb +3 -0
- data/lib/ruby2js/es2019.rb +5 -0
- data/lib/ruby2js/es2019/strict.rb +3 -0
- data/lib/ruby2js/es2020.rb +5 -0
- data/lib/ruby2js/es2020/strict.rb +3 -0
- data/lib/ruby2js/filter/functions.rb +34 -0
- data/lib/ruby2js/version.rb +2 -2
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0d87e8dda198550df6b79aa5a14e033ff6180f6057998d63252a41011d04735
|
4
|
+
data.tar.gz: 1869aa7759c6b40137258b3a87c0c250944940753cc5d0814a0e027bd88068dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75b7232fbc65271e6b200f6283f04605de370d6e38b127e6c51a481931a41076e055a3141fe643094c67e9b73988b0e7ccf576d0d6c36e3f44cbdb56face4362
|
7
|
+
data.tar.gz: c60b7631d17f12cafe859cfc06e7551f3158f1d6f4643f2fd2faf12a4cbd85cb8496c453d8c43d6244e73516726251f438f964a2312fd87deb8c690dc098b208
|
data/README.md
CHANGED
@@ -236,6 +236,7 @@ the script.
|
|
236
236
|
* `.last` becomes `[*.length-1]`
|
237
237
|
* `.last(n)` becomes `.slice(*.length-1, *.length)`
|
238
238
|
* `.max` becomes `Math.max.apply(Math)`
|
239
|
+
* `.merge` becomes `Object.assign({}, ...)`
|
239
240
|
* `.merge!` becomes `Object.assign()`
|
240
241
|
* `.min` becomes `Math.min.apply(Math)`
|
241
242
|
* `.nil?` becomes `== null`
|
@@ -249,6 +250,9 @@ the script.
|
|
249
250
|
* `.downto(lim)` becomes `for (var i=num; i>=lim; i-=1)`
|
250
251
|
* `.step(lim, n).each` becomes `for (var i=num; i<=lim; i+=n)`
|
251
252
|
* `.step(lim, -n).each` becomes `for (var i=num; i>=lim; i-=n)`
|
253
|
+
* `(0..a).to_a` becomes `Array.apply(null, {length: a}).map(Function.call, Number)`
|
254
|
+
* `(b..a).to_a` becomes `Array.apply(null, {length: (a-b+1)}).map(Function.call, Number).map(function (idx) { return idx+b })`
|
255
|
+
* `(b...a).to_a` becomes `Array.apply(null, {length: (a-b)}).map(Function.call, Number).map(function (idx) { return idx+b })`
|
252
256
|
* `.strip` becomes `.trim`
|
253
257
|
* `.sub` becomes `.replace`
|
254
258
|
* `.to_f` becomes `parseFloat`
|
@@ -282,7 +286,7 @@ the script.
|
|
282
286
|
|
283
287
|
* `.class` becomes `.constructor`
|
284
288
|
|
285
|
-
* <a id="node"
|
289
|
+
* <a id="node" href="https://github.com/rubys/ruby2js/blob/master/spec/node_spec.rb">node</a>
|
286
290
|
|
287
291
|
* `` `command` `` becomes `child_process.execSync("command", {encoding: "utf8"})`
|
288
292
|
* `ARGV` becomes `process.argv.slice(2)`
|
@@ -539,6 +543,9 @@ conversions are made:
|
|
539
543
|
* `proc {|x| x}` becomes `(x) => {x}`
|
540
544
|
* `a {|x|}` becomes `a((x) => {})`
|
541
545
|
* `class Person; end` becomes `class Person {}`
|
546
|
+
* `(0...a).to_a` becomes `[...Array(a).keys()]`
|
547
|
+
* `(0..a).to_a` becomes `[...Array(a+1).keys()]`
|
548
|
+
* `(b..a).to_a` becomes `Array.from({length: (a-b+1)}, (_, idx) => idx+b)`
|
542
549
|
|
543
550
|
ES2015 class support includes constructors, super, methods, class methods,
|
544
551
|
instance methods, instance variables, class variables, getters, setters,
|
@@ -549,6 +556,9 @@ Additionally, the `functions` filter will provide the following conversion:
|
|
549
556
|
* `Array(x)` becomes `Array.from(x)`
|
550
557
|
* `.inject(n) {}` becomes `.reduce(() => {}, n)`
|
551
558
|
|
559
|
+
Finally, keyword arguments and optional keyword arguments will be mapped to
|
560
|
+
parameter detructuring.
|
561
|
+
|
552
562
|
ES2016 support
|
553
563
|
---
|
554
564
|
|
@@ -566,6 +576,40 @@ conversion is made by the `functions` filter:
|
|
566
576
|
|
567
577
|
* `.each_entry` becomes `Object.entries().forEach`
|
568
578
|
|
579
|
+
ES2018 support
|
580
|
+
---
|
581
|
+
|
582
|
+
When option `eslevel: 2018` is provided, the following additional
|
583
|
+
conversion is made by the `functions` filter:
|
584
|
+
|
585
|
+
* `.merge` becomes `{...a, ...b}`
|
586
|
+
|
587
|
+
Additionally, rest arguments can now be used with keyword arguments and
|
588
|
+
optional keyword arguments.
|
589
|
+
|
590
|
+
ES2019 support
|
591
|
+
---
|
592
|
+
|
593
|
+
When option `eslevel: 2018` is provided, the following additional
|
594
|
+
conversion is made by the `functions` filter:
|
595
|
+
|
596
|
+
* `.flatten` becomes `.flat(Infinity)`
|
597
|
+
* `.lstrip` becomes `.trimEnd
|
598
|
+
* `.rstrip` becomes `.trimStart
|
599
|
+
* `a.to_h` becomes `Object.fromEntries(a)`
|
600
|
+
|
601
|
+
Additionally, `rescue` without a variable will map to `catch` without a
|
602
|
+
variable.
|
603
|
+
|
604
|
+
ES2020 support
|
605
|
+
---
|
606
|
+
|
607
|
+
When option `eslevel: 2018` is provided, the following additional
|
608
|
+
conversion is made:
|
609
|
+
|
610
|
+
* `@x` becomes `this.#x`
|
611
|
+
* `@@x` becomes `ClassName.#x`
|
612
|
+
|
569
613
|
Picking a Ruby to JS mapping tool
|
570
614
|
---
|
571
615
|
|
data/lib/ruby2js.rb
CHANGED
@@ -81,6 +81,18 @@ module Ruby2JS
|
|
81
81
|
@options[:eslevel] >= 2017
|
82
82
|
end
|
83
83
|
|
84
|
+
def es2018
|
85
|
+
@options[:eslevel] >= 2018
|
86
|
+
end
|
87
|
+
|
88
|
+
def es2019
|
89
|
+
@options[:eslevel] >= 2019
|
90
|
+
end
|
91
|
+
|
92
|
+
def es2020
|
93
|
+
@options[:eslevel] >= 2020
|
94
|
+
end
|
95
|
+
|
84
96
|
def process(node)
|
85
97
|
ast, @ast = @ast, node
|
86
98
|
replacement = super
|
@@ -201,7 +213,9 @@ module Ruby2JS
|
|
201
213
|
buffer.source = source.encode('utf-8')
|
202
214
|
parser = Parser::CurrentRuby.new
|
203
215
|
parser.builder.emit_file_line_as_literals=false
|
204
|
-
parser.parse_with_comments(buffer)
|
216
|
+
ast, comments = parser.parse_with_comments(buffer)
|
217
|
+
Parser::CurrentRuby.parse(source.encode('utf-8')) unless ast
|
218
|
+
[ast, comments]
|
205
219
|
rescue Parser::SyntaxError => e
|
206
220
|
split = source[0..e.diagnostic.location.begin_pos].split("\n")
|
207
221
|
line, col = split.length, split.last.length
|
data/lib/ruby2js/converter.rb
CHANGED
@@ -138,6 +138,18 @@ module Ruby2JS
|
|
138
138
|
@eslevel >= 2017
|
139
139
|
end
|
140
140
|
|
141
|
+
def es2018
|
142
|
+
@eslevel >= 2018
|
143
|
+
end
|
144
|
+
|
145
|
+
def es2019
|
146
|
+
@eslevel >= 2019
|
147
|
+
end
|
148
|
+
|
149
|
+
def es2020
|
150
|
+
@eslevel >= 2020
|
151
|
+
end
|
152
|
+
|
141
153
|
@@handlers = []
|
142
154
|
def self.handle(*types, &block)
|
143
155
|
types.each do |type|
|
@@ -7,7 +7,37 @@ module Ruby2JS
|
|
7
7
|
# (blockarg :c))
|
8
8
|
|
9
9
|
handle :args do |*args|
|
10
|
+
kwargs = []
|
11
|
+
while args.last and
|
12
|
+
[:kwarg, :kwoptarg, :kwrestarg].include? args.last.type
|
13
|
+
kwargs.unshift args.pop
|
14
|
+
end
|
15
|
+
|
16
|
+
if kwargs.length == 1 and kwargs.last.type == :kwrestarg
|
17
|
+
args.push s(:arg, *kwargs.last.children)
|
18
|
+
end
|
19
|
+
|
20
|
+
unless kwargs.empty? or es2015
|
21
|
+
raise NotImplementedError.new('Keyword args require ES2015')
|
22
|
+
end
|
23
|
+
|
10
24
|
parse_all(*args, join: ', ')
|
25
|
+
if not kwargs.empty?
|
26
|
+
put ', ' unless args.empty?
|
27
|
+
put '{ '
|
28
|
+
kwargs.each_with_index do |kw, index|
|
29
|
+
put ', ' unless index == 0
|
30
|
+
if kw.type == :kwarg
|
31
|
+
put kw.children.first
|
32
|
+
elsif kw.type == :kwoptarg
|
33
|
+
put kw.children.first; put ' = '; parse kw.children.last
|
34
|
+
elsif kw.type == :kwrestarg
|
35
|
+
raise 'Rest arg requires ES2018' unless es2018
|
36
|
+
put '...'; put kw.children.first
|
37
|
+
end
|
38
|
+
end
|
39
|
+
put ' }'
|
40
|
+
end
|
11
41
|
end
|
12
42
|
|
13
43
|
handle :mlhs do |*args|
|
@@ -8,7 +8,9 @@ module Ruby2JS
|
|
8
8
|
multi_assign_declarations if @state == :statement
|
9
9
|
|
10
10
|
begin
|
11
|
-
|
11
|
+
cbase ||= @rbstack.map {|rb| rb[var]}.compact.last
|
12
|
+
|
13
|
+
if @state == :statement and not cbase
|
12
14
|
if es2015
|
13
15
|
put "const "
|
14
16
|
else
|
@@ -16,7 +18,6 @@ module Ruby2JS
|
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
|
-
cbase ||= @rbstack.map {|rb| rb[var]}.compact.last
|
20
21
|
(parse cbase; put '.') if cbase
|
21
22
|
|
22
23
|
put "#{ var } = "; parse value
|
@@ -33,21 +33,79 @@ module Ruby2JS
|
|
33
33
|
class_name, @class_name = @class_name, name
|
34
34
|
class_parent, @class_parent = @class_parent, inheritance
|
35
35
|
@rbstack.push({})
|
36
|
+
constructor = []
|
37
|
+
index = 0
|
36
38
|
|
37
|
-
# capture method names for automatic self referencing
|
38
|
-
body.
|
39
|
+
# capture constructor, method names for automatic self referencing
|
40
|
+
body.each do |m|
|
39
41
|
if m.type == :def
|
40
42
|
prop = m.children.first
|
41
|
-
|
43
|
+
if prop == :initialize
|
44
|
+
constructor = m.children[2..-1]
|
45
|
+
elsif not prop.to_s.end_with? '='
|
42
46
|
@rbstack.last[prop] = s(:self)
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
51
|
+
# private variable declarations
|
52
|
+
if es2020
|
53
|
+
ivars = Set.new
|
54
|
+
cvars = Set.new
|
55
|
+
|
56
|
+
# find ivars and cvars
|
57
|
+
walk = proc do |ast|
|
58
|
+
ivars << ast.children.first if ast.type === :ivar
|
59
|
+
cvars << ast.children.first if ast.type === :cvar
|
60
|
+
ast.children.each do |child|
|
61
|
+
walk[child] if child.is_a? Parser::AST::Node
|
62
|
+
end
|
63
|
+
end
|
64
|
+
walk[@ast]
|
65
|
+
|
66
|
+
# process leading initializers in constructor
|
67
|
+
while constructor.length == 1 and constructor.first.type == :begin
|
68
|
+
constructor = constructor.first.children.dup
|
69
|
+
end
|
70
|
+
|
71
|
+
# emit additional class declarations
|
72
|
+
unless cvars.empty?
|
73
|
+
body.each do |m|
|
74
|
+
cvars.delete m.children.first if m.type == :cvasgn
|
75
|
+
end
|
76
|
+
end
|
77
|
+
cvars.to_a.sort.each do |cvar|
|
78
|
+
put(index == 0 ? @nl : @sep)
|
79
|
+
index += 1
|
80
|
+
put 'static #' + cvar.to_s[2..-1]
|
81
|
+
end
|
82
|
+
|
83
|
+
while constructor.length > 0 and constructor.first.type == :ivasgn
|
84
|
+
put(index == 0 ? @nl : @sep)
|
85
|
+
index += 1
|
86
|
+
statement = constructor.shift
|
87
|
+
put '#'
|
88
|
+
put statement.children.first.to_s[1..-1]
|
89
|
+
put ' = '
|
90
|
+
parse statement.children.last
|
91
|
+
|
92
|
+
ivars.delete statement.children.first
|
93
|
+
end
|
94
|
+
|
95
|
+
# emit additional instance declarations
|
96
|
+
ivars.to_a.sort.each do |ivar|
|
97
|
+
put(index == 0 ? @nl : @sep)
|
98
|
+
index += 1
|
99
|
+
put '#' + ivar.to_s[1..-1]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# process class definition
|
47
104
|
post = []
|
48
105
|
skipped = false
|
49
|
-
body.
|
106
|
+
body.each do |m|
|
50
107
|
put(index == 0 ? @nl : @sep) unless skipped
|
108
|
+
index += 1
|
51
109
|
comments = comments(m)
|
52
110
|
location = output_location
|
53
111
|
skipped = false
|
@@ -67,7 +125,13 @@ module Ruby2JS
|
|
67
125
|
|
68
126
|
if @prop == :initialize
|
69
127
|
@prop = :constructor
|
70
|
-
|
128
|
+
|
129
|
+
if constructor == [] or constructor == [(:super)]
|
130
|
+
skipped = true
|
131
|
+
next
|
132
|
+
end
|
133
|
+
|
134
|
+
m = m.updated(m.type, [@prop, m.children[1], *constructor])
|
71
135
|
elsif not m.is_method?
|
72
136
|
@prop = "get #{@prop}"
|
73
137
|
m = m.updated(m.type, [*m.children[0..1],
|
@@ -83,7 +147,7 @@ module Ruby2JS
|
|
83
147
|
|
84
148
|
begin
|
85
149
|
@instance_method = m
|
86
|
-
parse m
|
150
|
+
parse m # unless skipped
|
87
151
|
ensure
|
88
152
|
@instance_method = nil
|
89
153
|
end
|
@@ -143,10 +207,21 @@ module Ruby2JS
|
|
143
207
|
end
|
144
208
|
|
145
209
|
else
|
146
|
-
|
210
|
+
if m.type == :cvasgn and es2020
|
211
|
+
put 'static #'; put m.children[0].to_s[2..-1]; put ' = '
|
212
|
+
parse m.children[1]
|
213
|
+
else
|
214
|
+
skipped = true
|
215
|
+
end
|
147
216
|
|
148
217
|
if m.type == :casgn and m.children[0] == nil
|
149
218
|
@rbstack.last[m.children[1]] = name
|
219
|
+
|
220
|
+
if es2020
|
221
|
+
put 'static '; put m.children[1].to_s; put ' = '
|
222
|
+
parse m.children[2]
|
223
|
+
skipped = false
|
224
|
+
end
|
150
225
|
elsif m.type == :alias
|
151
226
|
@rbstack.last[m.children[0]] = name
|
152
227
|
end
|
@@ -4,14 +4,16 @@ module Ruby2JS
|
|
4
4
|
# (cvar :@@a)
|
5
5
|
|
6
6
|
handle :cvar do |var|
|
7
|
+
prefix = es2020 ? '#' : '_'
|
8
|
+
|
7
9
|
@class_name ||= nil
|
8
10
|
if @class_name
|
9
11
|
parse @class_name
|
10
|
-
put var.to_s.sub('@@', "
|
12
|
+
put var.to_s.sub('@@', ".#{prefix}")
|
11
13
|
elsif @prototype
|
12
|
-
put var.to_s.sub('@@',
|
14
|
+
put var.to_s.sub('@@', "this.#{prefix}")
|
13
15
|
else
|
14
|
-
put var.to_s.sub('@@',
|
16
|
+
put var.to_s.sub('@@', "this.constructor.#{prefix}")
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end
|
@@ -7,13 +7,15 @@ module Ruby2JS
|
|
7
7
|
handle :cvasgn do |var, expression=nil|
|
8
8
|
multi_assign_declarations if @state == :statement
|
9
9
|
|
10
|
+
prefix = es2020 ? '#' : '_'
|
11
|
+
|
10
12
|
if @class_name
|
11
13
|
parse @class_name
|
12
|
-
put var.to_s.sub('@@', "
|
14
|
+
put var.to_s.sub('@@', ".#{prefix}")
|
13
15
|
elsif @prototype
|
14
|
-
put var.to_s.sub('@@',
|
16
|
+
put var.to_s.sub('@@', "this.#{prefix}")
|
15
17
|
else
|
16
|
-
put var.to_s.sub('@@',
|
18
|
+
put var.to_s.sub('@@', "this.constructor.#{prefix}")
|
17
19
|
end
|
18
20
|
|
19
21
|
if expression
|
@@ -12,10 +12,26 @@ module Ruby2JS
|
|
12
12
|
|
13
13
|
(singleton ? put('{') : puts('{'))
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
index = 0
|
16
|
+
while pairs.length > 0
|
17
|
+
node = pairs.shift
|
18
18
|
(singleton ? put(', ') : put(",#@ws")) unless index == 0
|
19
|
+
index += 1
|
20
|
+
|
21
|
+
if node.type == :kwsplat
|
22
|
+
if es2018
|
23
|
+
if node.children.first.type == :hash
|
24
|
+
pairs.unshift(*node.children.first.children)
|
25
|
+
index = 0
|
26
|
+
else
|
27
|
+
puts '...'; parse node.children.first
|
28
|
+
end
|
29
|
+
|
30
|
+
next
|
31
|
+
else
|
32
|
+
raise Error.new("kwsplat", @ast)
|
33
|
+
end
|
34
|
+
end
|
19
35
|
|
20
36
|
if not @comments[node].empty?
|
21
37
|
(puts ''; singleton = false) if singleton
|
@@ -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._') }"
|
10
|
+
put "#{ var.to_s.sub('@', 'this.' + (es2020 ? '#' : '_')) }"
|
11
11
|
if expression
|
12
12
|
put " = "; parse expression
|
13
13
|
end
|
@@ -51,13 +51,27 @@ module Ruby2JS
|
|
51
51
|
puts "try {"; scope body; sput '}'
|
52
52
|
|
53
53
|
if recovers
|
54
|
-
var ||= s(:gvar, :$EXCEPTION)
|
55
54
|
|
56
55
|
if recovers.length == 1 and not recovers.first.children.first
|
56
|
+
# find reference to exception ($!)
|
57
|
+
walk = proc do |ast|
|
58
|
+
result = ast if ast.type === :gvar and ast.children.first == :$!
|
59
|
+
ast.children.each do |child|
|
60
|
+
result ||= walk[child] if child.is_a? Parser::AST::Node
|
61
|
+
end
|
62
|
+
result
|
63
|
+
end
|
64
|
+
|
57
65
|
# single catch with no exception named
|
58
|
-
|
66
|
+
if es2019 and not var and not walk[@ast]
|
67
|
+
puts " catch {"
|
68
|
+
else
|
69
|
+
var ||= s(:gvar, :$EXCEPTION)
|
70
|
+
put " catch ("; parse var; puts ") {"
|
71
|
+
end
|
59
72
|
scope recovers.first.children.last; sput '}'
|
60
73
|
else
|
74
|
+
var ||= s(:gvar, :$EXCEPTION)
|
61
75
|
put " catch ("; parse var; puts ') {'
|
62
76
|
|
63
77
|
first = true
|
@@ -16,12 +16,26 @@ module Ruby2JS
|
|
16
16
|
handle :send, :sendw, :await, :attr, :call do |receiver, method, *args|
|
17
17
|
ast = @ast
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
if
|
20
|
+
args.length == 1 and method == :+
|
21
|
+
then
|
22
|
+
node = collapse_strings(ast)
|
23
|
+
return parse node if node != ast
|
24
|
+
end
|
25
|
+
|
26
|
+
# :irange support
|
27
|
+
# - currently only .to_a
|
28
|
+
if
|
29
|
+
receiver and
|
30
|
+
receiver.type == :begin and
|
31
|
+
[:irange, :erange].include? receiver.children.first.type
|
32
|
+
then
|
33
|
+
unless method == :to_a
|
34
|
+
raise Error.new("#{receiver.children.first.type} can only be converted to array currently", receiver.children.first)
|
35
|
+
else
|
36
|
+
return range_to_array(receiver.children.first)
|
37
|
+
end
|
38
|
+
end
|
25
39
|
|
26
40
|
# strip '!' and '?' decorations
|
27
41
|
method = method.to_s[0..-2] if method =~ /\w[!?]$/
|
@@ -39,7 +53,7 @@ module Ruby2JS
|
|
39
53
|
end
|
40
54
|
|
41
55
|
# call anonymous function
|
42
|
-
if [:call, :[]].include? method and receiver and receiver.type == :block
|
56
|
+
if [:call, :[]].include? method and receiver and receiver.type == :block
|
43
57
|
t2,m2,*args2 = receiver.children.first.children
|
44
58
|
if not t2 and [:lambda, :proc].include? m2 and args2.length == 0
|
45
59
|
(es2015 || @state == :statement ? group(receiver) : parse(receiver))
|
@@ -97,7 +111,7 @@ module Ruby2JS
|
|
97
111
|
|
98
112
|
op_index = operator_index method
|
99
113
|
if op_index != -1
|
100
|
-
target = args.first
|
114
|
+
target = args.first
|
101
115
|
end
|
102
116
|
|
103
117
|
# resolve anonymous receivers against rbstack
|
@@ -109,7 +123,7 @@ module Ruby2JS
|
|
109
123
|
group_receiver ||= GROUP_OPERATORS.include? receiver.type
|
110
124
|
group_receiver = false if receiver.children[1] == :[]
|
111
125
|
if receiver.type == :int and !OPERATORS.flatten.include?(method)
|
112
|
-
group_receiver = true
|
126
|
+
group_receiver = true
|
113
127
|
end
|
114
128
|
if not receiver.is_method? and receiver.children.last == :new
|
115
129
|
group_receiver = true
|
@@ -117,7 +131,7 @@ module Ruby2JS
|
|
117
131
|
end
|
118
132
|
|
119
133
|
if target
|
120
|
-
group_target = target.type == :send &&
|
134
|
+
group_target = target.type == :send &&
|
121
135
|
op_index < operator_index( target.children[1] )
|
122
136
|
group_target ||= GROUP_OPERATORS.include? target.type
|
123
137
|
end
|
@@ -156,7 +170,7 @@ module Ruby2JS
|
|
156
170
|
put ')'
|
157
171
|
|
158
172
|
elsif [:-@, :+@, :~, '~'].include? method
|
159
|
-
if
|
173
|
+
if
|
160
174
|
receiver.type == :send and
|
161
175
|
receiver.children[1] == :+@ and
|
162
176
|
Parser::AST::Node === receiver.children[0] and
|
@@ -235,7 +249,7 @@ module Ruby2JS
|
|
235
249
|
elsif args.length == 1 and args.first.type == :const
|
236
250
|
# accommodation for JavaScript like new syntax w/o argument list
|
237
251
|
parse s(:attr, args.first, :new), @state
|
238
|
-
elsif
|
252
|
+
elsif
|
239
253
|
args.length == 2 and [:send, :const].include? args.first.type and
|
240
254
|
args.last.type == :def and args.last.children.first == nil
|
241
255
|
then
|
@@ -269,7 +283,7 @@ module Ruby2JS
|
|
269
283
|
parse ast.updated(:lvasgn, [method]), @state
|
270
284
|
end
|
271
285
|
elsif args.any? {|arg| arg.type == :splat} and not es2015
|
272
|
-
parse s(:send, s(:attr, receiver, method), :apply,
|
286
|
+
parse s(:send, s(:attr, receiver, method), :apply,
|
273
287
|
(receiver || s(:nil)), s(:array, *args))
|
274
288
|
else
|
275
289
|
(group_receiver ? group(receiver) : parse(receiver))
|
@@ -313,47 +327,98 @@ module Ruby2JS
|
|
313
327
|
parse expr
|
314
328
|
end
|
315
329
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
330
|
+
# do string concatenation when possible
|
331
|
+
def collapse_strings(node)
|
332
|
+
left = node.children[0]
|
333
|
+
return node unless left
|
334
|
+
right = node.children[2]
|
335
|
+
|
336
|
+
# recursively evaluate left hand side
|
337
|
+
if
|
338
|
+
left.type == :send and left.children.length == 3 and
|
339
|
+
left.children[1] == :+
|
340
|
+
then
|
341
|
+
left = collapse_strings(left)
|
342
|
+
end
|
329
343
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
344
|
+
# recursively evaluate right hand side
|
345
|
+
if
|
346
|
+
right.type == :send and right.children.length == 3 and
|
347
|
+
right.children[1] == :+
|
348
|
+
then
|
349
|
+
right = collapse_strings(right)
|
350
|
+
end
|
337
351
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
352
|
+
# if left and right are both strings, perform concatenation
|
353
|
+
if [:dstr, :str].include? left.type and [:dstr, :str].include? right.type
|
354
|
+
if left.type == :str and right.type == :str
|
355
|
+
return left.updated nil,
|
356
|
+
[left.children.first + right.children.first]
|
357
|
+
else
|
358
|
+
left = s(:dstr, left) if left.type == :str
|
359
|
+
right = s(:dstr, right) if right.type == :str
|
360
|
+
return left.updated(nil, left.children + right.children)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
# if left and right are unchanged, return original node; otherwise
|
365
|
+
# return node modified to include new left and/or right hand sides.
|
366
|
+
if left == node.children[0] and right == node.children[2]
|
367
|
+
return node
|
343
368
|
else
|
344
|
-
|
345
|
-
right = s(:dstr, right) if right.type == :str
|
346
|
-
return left.updated(nil, left.children + right.children)
|
369
|
+
return node.updated(nil, [left, :+, right])
|
347
370
|
end
|
348
371
|
end
|
349
372
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
373
|
+
def range_to_array(node)
|
374
|
+
start, finish = node.children
|
375
|
+
if start.type == :int and start.children.first == 0
|
376
|
+
# Ranges which start from 0 can be achieved with more simpler code
|
377
|
+
if finish.type == :int
|
378
|
+
# output cleaner code if we know the value already
|
379
|
+
length = finish.children.first + (node.type == :irange ? 1 : 0)
|
380
|
+
else
|
381
|
+
# If this is variable we need to fix indexing by 1 in js
|
382
|
+
length = "#{finish.children.last}" + (node.type == :irange ? "+1" : "")
|
383
|
+
end
|
384
|
+
|
385
|
+
if es2015
|
386
|
+
return put "[...Array(#{length}).keys()]"
|
387
|
+
else
|
388
|
+
return put "Array.apply(null, {length: #{length}}).map(Function.call, Number)"
|
389
|
+
end
|
390
|
+
else
|
391
|
+
# Use .compact because the first argument is nil with variables
|
392
|
+
# This way the first value is always set
|
393
|
+
start_value = start.children.compact.first
|
394
|
+
finish_value = finish.children.compact.first
|
395
|
+
if start.type == :int and finish.type == :int
|
396
|
+
length = finish_value - start_value + (node.type == :irange ? 1 : 0)
|
397
|
+
else
|
398
|
+
length = "(#{finish_value}-#{start_value}" + (node.type == :irange ? "+1" : "") + ")"
|
399
|
+
end
|
400
|
+
|
401
|
+
# Avoid of using same variables in the map as used in the irange or elsewhere in this code
|
402
|
+
# Ruby2js only allows dollar sign in beginning of variable so i$ is safe
|
403
|
+
if @vars.include? :idx or start_value == :idx or finish_value == :idx
|
404
|
+
index_var = 'i$'
|
405
|
+
else
|
406
|
+
index_var = 'idx'
|
407
|
+
end
|
408
|
+
|
409
|
+
if es2015
|
410
|
+
# Use _ because it's normal convention in JS for variable which is not used at all
|
411
|
+
if @vars.include? :_ or start_value == :_ or finish_value == :_
|
412
|
+
blank = '_$'
|
413
|
+
else
|
414
|
+
blank = '_'
|
415
|
+
end
|
416
|
+
|
417
|
+
return put "Array.from({length: #{length}}, (#{blank}, #{index_var}) => #{index_var}+#{start_value})"
|
418
|
+
else
|
419
|
+
return put "Array.apply(null, {length: #{length}}).map(Function.call, Number).map(function (#{index_var}) { return #{index_var}+#{start_value} })"
|
420
|
+
end
|
421
|
+
end
|
356
422
|
end
|
357
423
|
end
|
358
|
-
end
|
359
424
|
end
|
@@ -35,6 +35,27 @@ module Ruby2JS
|
|
35
35
|
elsif method == :keys and args.length == 0 and node.is_method?
|
36
36
|
process S(:send, s(:const, nil, :Object), :keys, target)
|
37
37
|
|
38
|
+
elsif method == :merge
|
39
|
+
args.unshift target
|
40
|
+
|
41
|
+
if es2015
|
42
|
+
if es2018
|
43
|
+
process S(:hash, *args.map {|arg| s(:kwsplat, arg)})
|
44
|
+
else
|
45
|
+
process S(:send, s(:const, nil, :Object), :assign, s(:hash),
|
46
|
+
*args)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
copy = [s(:gvasgn, :$$, s(:hash))]
|
50
|
+
|
51
|
+
s(:send, s(:block, s(:send, nil, :lambda), s(:args),
|
52
|
+
s(:begin, *copy, *args.map {|modname|
|
53
|
+
s(:for, s(:lvasgn, :$_), modname,
|
54
|
+
s(:send, s(:gvar, :$$), :[]=,
|
55
|
+
s(:lvar, :$_), s(:send, modname, :[], s(:lvar, :$_))))
|
56
|
+
}, s(:return, s(:gvar, :$$)))), :[])
|
57
|
+
end
|
58
|
+
|
38
59
|
elsif method == :merge!
|
39
60
|
if es2015
|
40
61
|
process S(:send, s(:const, nil, :Object), :assign, target, *args)
|
@@ -367,6 +388,19 @@ module Ruby2JS
|
|
367
388
|
elsif es2017 and method==:ljust
|
368
389
|
process node.updated(nil, [target, :padEnd, *args])
|
369
390
|
|
391
|
+
elsif es2019 and method==:flatten and args.length == 0
|
392
|
+
process node.updated(nil, [target, :flat, s(:lvar, :Infinity)])
|
393
|
+
|
394
|
+
elsif es2019 and method==:to_h and args.length==0
|
395
|
+
process node.updated(nil, [s(:const, nil, :Object), :fromEntries,
|
396
|
+
target])
|
397
|
+
|
398
|
+
elsif es2019 and method==:rstrip
|
399
|
+
process node.updated(nil, [target, :trimStart, *args])
|
400
|
+
|
401
|
+
elsif es2019 and method==:lstrip
|
402
|
+
process node.updated(nil, [target, :trimEnd, *args])
|
403
|
+
|
370
404
|
elsif method == :class and args.length==0 and not node.is_method?
|
371
405
|
process node.updated(:attr, [target, :constructor])
|
372
406
|
|
data/lib/ruby2js/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby2js
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Ruby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -93,6 +93,12 @@ files:
|
|
93
93
|
- lib/ruby2js/es2016/strict.rb
|
94
94
|
- lib/ruby2js/es2017.rb
|
95
95
|
- lib/ruby2js/es2017/strict.rb
|
96
|
+
- lib/ruby2js/es2018.rb
|
97
|
+
- lib/ruby2js/es2018/strict.rb
|
98
|
+
- lib/ruby2js/es2019.rb
|
99
|
+
- lib/ruby2js/es2019/strict.rb
|
100
|
+
- lib/ruby2js/es2020.rb
|
101
|
+
- lib/ruby2js/es2020/strict.rb
|
96
102
|
- lib/ruby2js/execjs.rb
|
97
103
|
- lib/ruby2js/filter.rb
|
98
104
|
- lib/ruby2js/filter/camelCase.rb
|