ruby2js 2.1.24 → 3.0.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 +91 -50
- data/lib/ruby2js/converter/args.rb +10 -0
- data/lib/ruby2js/converter/block.rb +1 -1
- data/lib/ruby2js/converter/case.rb +1 -1
- data/lib/ruby2js/converter/casgn.rb +6 -1
- data/lib/ruby2js/converter/class.rb +7 -2
- data/lib/ruby2js/converter/class2.rb +167 -0
- data/lib/ruby2js/converter/def.rb +54 -6
- data/lib/ruby2js/converter/defs.rb +11 -5
- data/lib/ruby2js/converter/dstr.rb +26 -0
- data/lib/ruby2js/converter/for.rb +3 -3
- data/lib/ruby2js/converter/hash.rb +31 -6
- data/lib/ruby2js/converter/if.rb +1 -1
- data/lib/ruby2js/converter/ivasgn.rb +5 -2
- data/lib/ruby2js/converter/masgn.rb +41 -4
- data/lib/ruby2js/converter/send.rb +71 -10
- data/lib/ruby2js/converter/super.rb +21 -8
- data/lib/ruby2js/converter/vasgn.rb +5 -1
- data/lib/ruby2js/converter/while.rb +13 -0
- data/lib/ruby2js/converter.rb +32 -5
- data/lib/ruby2js/es2015/strict.rb +3 -0
- data/lib/ruby2js/es2015.rb +5 -0
- data/lib/ruby2js/es2016/strict.rb +3 -0
- data/lib/ruby2js/es2016.rb +5 -0
- data/lib/ruby2js/es2017/strict.rb +3 -0
- data/lib/ruby2js/es2017.rb +5 -0
- data/lib/ruby2js/execjs.rb +1 -1
- data/lib/ruby2js/filter/camelCase.rb +1 -1
- data/lib/ruby2js/filter/functions.rb +49 -2
- data/lib/ruby2js/filter/vue.rb +66 -45
- data/lib/ruby2js/strict.rb +3 -0
- data/lib/ruby2js/version.rb +3 -3
- data/lib/ruby2js.rb +41 -0
- data/ruby2js.gemspec +3 -1
- metadata +10 -6
- data/lib/ruby2js/filter/angular-resource.rb +0 -25
- data/lib/ruby2js/filter/angular-route.rb +0 -44
- data/lib/ruby2js/filter/angularrb.rb +0 -604
- data/lib/ruby2js/filter/strict.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz: '
|
3
|
+
metadata.gz: 0b1bcb8158bb81cdfafcf70eb22f84ad5dc195b1
|
4
|
+
data.tar.gz: '08d8a3e28b785aa35c52317b86f5749cebce31de'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c4946688aa439dd57d84de8115f1fbee1155a7d42227acf6ab2633ce6e6eb8c6e7f0fc7c7e322badd831642e856cc1991439c97beda892cd212f99e3cc8aa51
|
7
|
+
data.tar.gz: d8e945b65e77e4aacd05e36864f505c7cd454f8b00f788d37e7254f642df860cde0c9a6ebee44d854ba6c706a1c768d3c4dbe5c3e65ec86df660648b5ccf5ccd
|
data/README.md
CHANGED
@@ -9,12 +9,35 @@ Minimal yet extensible Ruby to JavaScript conversion.
|
|
9
9
|
Description
|
10
10
|
---
|
11
11
|
|
12
|
-
The base package maps Ruby syntax to JavaScript semantics.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
The base package maps Ruby syntax to JavaScript semantics.
|
13
|
+
For example:
|
14
|
+
|
15
|
+
* a Ruby Hash literal becomes a JavaScript Object literal
|
16
|
+
* Ruby symbols become JavaScript strings.
|
17
|
+
* Ruby method calls become JavaScript function calls IF
|
18
|
+
there are either one or more arguments passed OR
|
19
|
+
parenthesis are used
|
20
|
+
* otherwise Ruby method calls become JavaScript property accesses.
|
21
|
+
* by default, methods and procs return `undefined`
|
22
|
+
* splats are handled (may need to try around or read transliteration_spec)
|
23
|
+
* ruby string interpolation is expanded into string + operations
|
24
|
+
* `and` and `or` become `&&` and `||`
|
25
|
+
* `a ** b` becomes `Math.pow(a,b)`
|
26
|
+
* `<< a` becomes `.push(a)`
|
27
|
+
* `unless` becomes `if !`
|
28
|
+
* `until` becomes `while !`
|
29
|
+
* `case` and `when` becomes `switch` and `case`
|
30
|
+
* ruby for loops become js for loops
|
31
|
+
* `(1...4).step(2){` becomes `for (var i = 1; i < 4; i += 2) {`
|
32
|
+
* `x.forEach { next }` becomes `x.forEach(function() {return})`
|
33
|
+
* `lambda {}` and `proc {}` becomes `function() {}`
|
34
|
+
* `class Person; end` becomes `function Person() {}`
|
35
|
+
* instance methods become prototype methods
|
36
|
+
* instance variables become underscored, `@name` becomes `this._name`
|
37
|
+
* self is assigned to this is if used
|
38
|
+
* Any block becomes and explicit argument `new Promise do; y(); end` becomes `new Promise(function() {y()})`
|
39
|
+
* regular expressions are mapped to js
|
40
|
+
* `raise` becomes `throw`
|
18
41
|
|
19
42
|
Ruby attribute accessors, methods defined with no parameters and no
|
20
43
|
parenthesis, as well as setter method definitions, are
|
@@ -47,6 +70,18 @@ require 'ruby2js/filter/functions'
|
|
47
70
|
puts Ruby2JS.convert('"2A".to_i(16)')
|
48
71
|
```
|
49
72
|
|
73
|
+
Enable ES2015 support:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
puts Ruby2JS.convert('"#{a}"', eslevel: 2015)
|
77
|
+
```
|
78
|
+
|
79
|
+
Enable strict support:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
puts Ruby2JS.convert('a=1', strict: true)
|
83
|
+
```
|
84
|
+
|
50
85
|
With [ExecJS](https://github.com/sstephenson/execjs):
|
51
86
|
```ruby
|
52
87
|
require 'ruby2js/execjs'
|
@@ -140,9 +175,6 @@ In general, making use of a filter is as simple as requiring it. If multiple
|
|
140
175
|
filters are selected, they will all be applied in parallel in one pass through
|
141
176
|
the script.
|
142
177
|
|
143
|
-
* <a id="strict" href="https://github.com/rubys/ruby2js/blob/master/lib/ruby2js/filter/strict.rb">strict</a>
|
144
|
-
adds `'use strict';` to the output.
|
145
|
-
|
146
178
|
* <a id="return" href="https://github.com/rubys/ruby2js/blob/master/lib/ruby2js/filter/return.rb">return</a>
|
147
179
|
adds `return` to the last expression in functions.
|
148
180
|
|
@@ -164,7 +196,9 @@ the script.
|
|
164
196
|
* `.clear` becomes `.length = 0`
|
165
197
|
* `.delete` becomes `delete target[arg]`
|
166
198
|
* `.downcase` becomes `.toLowerCase`
|
167
|
-
* `.each` becomes `
|
199
|
+
* `.each` becomes `for (i in ...) {}`
|
200
|
+
* `.each_key` becomes `Object.keys().forEach`
|
201
|
+
* `.each_value` becomes `for (i in ...) {}`
|
168
202
|
* `.each_with_index` becomes `.forEach`
|
169
203
|
* `.end_with?` becomes `.slice(-arg.length) == arg`
|
170
204
|
* `.empty?` becomes `.length == 0`
|
@@ -200,6 +234,7 @@ the script.
|
|
200
234
|
* `[n...m]` becomes `.slice(n,m)`
|
201
235
|
* `[n..m]` becomes `.slice(n,m+1)`
|
202
236
|
* `[/r/, n]` becomes `.match(/r/)[n]`
|
237
|
+
* `(1..2).each {|i| ...}` becomes `for (var i=1 i<=2; i+=1)`
|
203
238
|
* `"string" * length` becomes `new Array(length + 1).join("string")`
|
204
239
|
* `.sub!` and `.gsub!` become equivalent `x = x.replace` statements
|
205
240
|
* `.map!`, `.reverse!`, and `.select` become equivalent
|
@@ -332,39 +367,6 @@ the script.
|
|
332
367
|
* defaults the fourth parameter of $$.post to `"json"`, allowing Ruby block
|
333
368
|
syntax to be used for the success function.
|
334
369
|
|
335
|
-
* <a id="angularrb" href="https://github.com/rubys/ruby2js/blob/master/spec/angularrb.rb">angularrb</a>
|
336
|
-
|
337
|
-
* maps Ruby `module` to `angular.module`
|
338
|
-
* maps `filter`, `controller`, `factory`, and `directive` to calls to
|
339
|
-
angular module functions.
|
340
|
-
* maps `use` statements to formal arguments or array values (as
|
341
|
-
appropriate) depending on the module function.
|
342
|
-
* maps `watch` statements to calls to `$scope.$watch`.
|
343
|
-
* tracks globals variable and constant references and adds additional
|
344
|
-
implicit `use` statements
|
345
|
-
* maps constant assignments in an angular module to a filter
|
346
|
-
* maps class definitions in an angular module to a filter
|
347
|
-
* within a controller or within a `link` method in a directive:
|
348
|
-
* maps `apply`, `broadcast`, `digest`, `emit`, `eval`, `evalAsync`, and
|
349
|
-
`parent` calls to `$scope` functions.
|
350
|
-
* maps `apply!`, `broadcast!`, `digest!`, `eval!`, and `evalAsync!`
|
351
|
-
calls to `$rootScope` functions.
|
352
|
-
* maps `filter` calls to '$filter` calls.
|
353
|
-
* maps `timeout` and `interval` calls with a block to `$timeout` and
|
354
|
-
`$interval` calls where the block is passed as the first parameter.
|
355
|
-
|
356
|
-
* <a id="angular-route" href="https://github.com/rubys/ruby2js/blob/master/lib/ruby2js/filter/angular-routerb.rb">angular-route</a>
|
357
|
-
|
358
|
-
* maps `case` statements on `$routeProvider` to angular.js module
|
359
|
-
configuration.
|
360
|
-
* adds implicit module `use` of `ngRoute` when such a `case` statement
|
361
|
-
is encountered
|
362
|
-
|
363
|
-
* <a id="angular-resource" href="https://github.com/rubys/ruby2js/blob/master/lib/ruby2js/filter/angular-resource.rb">angular-resource</a>
|
364
|
-
* maps `$resource.new` statements on `$resource` function calls.
|
365
|
-
* adds implicit module `use` of `ngResource` when `$resource.new` calls
|
366
|
-
are encountered
|
367
|
-
|
368
370
|
* <a id="minitest-jasmine" href="https://github.com/rubys/ruby2js/blob/master/spec/minitest-jasmine.rb">minitest-jasmine</a>
|
369
371
|
* maps subclasses of `Minitest::Test` to `describe` calls
|
370
372
|
* maps `test_` methods inside subclasses of `Minitest::Test` to `it` calls
|
@@ -393,13 +395,52 @@ the script.
|
|
393
395
|
and [wiki](https://github.com/rubys/wunderbar/blob/master/demo/wiki.rb) make
|
394
396
|
use of the jquery filter.
|
395
397
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
398
|
+
ES2015 support
|
399
|
+
---
|
400
|
+
|
401
|
+
When option `eslevel: 2015` is provided, the following additional
|
402
|
+
conversions are made:
|
403
|
+
|
404
|
+
* `"#{a}"` becomes <code>\`${a}\`</code>
|
405
|
+
* `a = 1` becomes `let a = 1`
|
406
|
+
* `A = 1` becomes `const A = 1`
|
407
|
+
* `a, b = b, a` becomes `[a, b] = [b, a]`
|
408
|
+
* `a, (foo, *bar) = x` becomes `let [a, [foo, ...bar]] = x`
|
409
|
+
* `def f(a, (foo, *bar))` becomes `function f(a, [foo, ...bar])`
|
410
|
+
* `def a(b=1)` becomes `function a(b=1)`
|
411
|
+
* `def a(*b)` becomes `function a(...b)`
|
412
|
+
* `.each_key` becomes `for (i of ...) {}`
|
413
|
+
* `a(*b)` becomes `a(...b)`
|
414
|
+
* `"#{a}"` becomes <code>\`${a}\`</code>
|
415
|
+
* `lambda {|x| x}` becomes `(x) => {return x}`
|
416
|
+
* `proc {|x| x}` becomes `(x) => {x}`
|
417
|
+
* `a {|x|}` becomes `a((x) => {})`
|
418
|
+
* `class Person; end` becomes `class Person {}`
|
419
|
+
|
420
|
+
ES2015 class support includes constructors, super, methods, class methods,
|
421
|
+
instance methods, instance variables, class variables, getters, setters,
|
422
|
+
attr_accessor, attr_reader, attr_writer, etc.
|
423
|
+
|
424
|
+
Additionally, the `functions` filter will provide the following conversion:
|
425
|
+
|
426
|
+
* `Array(x)` becomes `Array.from(x)`
|
427
|
+
* `.inject(n) {}` becomes `.reduce(() => {}, n)`
|
428
|
+
|
429
|
+
ES2016 support
|
430
|
+
---
|
431
|
+
|
432
|
+
When option `eslevel: 2016` is provided, the following additional
|
433
|
+
conversion is made:
|
434
|
+
|
435
|
+
* `a ** b` becomes `a ** b`
|
436
|
+
|
437
|
+
ES2017 support
|
438
|
+
---
|
439
|
+
|
440
|
+
When option `eslevel: 2017` is provided, the following additional
|
441
|
+
conversion is made by the `functions` filter:
|
442
|
+
|
443
|
+
* `.each_entry` becomes `Object.entries().forEach`
|
403
444
|
|
404
445
|
Picking a Ruby to JS mapping tool
|
405
446
|
---
|
@@ -9,5 +9,15 @@ module Ruby2JS
|
|
9
9
|
handle :args do |*args|
|
10
10
|
parse_all(*args, join: ', ')
|
11
11
|
end
|
12
|
+
|
13
|
+
handle :mlhs do |*args|
|
14
|
+
if es2015
|
15
|
+
put '['
|
16
|
+
parse_all(*args, join: ', ')
|
17
|
+
put ']'
|
18
|
+
else
|
19
|
+
raise NotImplementedError, "destructuring requires ES2015"
|
20
|
+
end
|
21
|
+
end
|
12
22
|
end
|
13
23
|
end
|
@@ -58,7 +58,7 @@ module Ruby2JS
|
|
58
58
|
# consisting of an anonymous function
|
59
59
|
block ||= s(:begin)
|
60
60
|
function = @ast.updated(:def, [nil, args, block])
|
61
|
-
parse s(
|
61
|
+
parse s(@ast.children[0].type, *call.children, function), @state
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
@@ -31,7 +31,7 @@ module Ruby2JS
|
|
31
31
|
if scope
|
32
32
|
vars = @vars.select {|key, value| value == :pending}.keys
|
33
33
|
unless vars.empty?
|
34
|
-
insert mark, "var #{vars.join(', ')}#{@sep}"
|
34
|
+
insert mark, "#{es2015 ? 'let' : 'var'} #{vars.join(', ')}#{@sep}"
|
35
35
|
vars.each {|var| @vars[var] = true}
|
36
36
|
end
|
37
37
|
end
|
@@ -6,8 +6,13 @@ module Ruby2JS
|
|
6
6
|
|
7
7
|
handle :casgn do |cbase, var, value|
|
8
8
|
begin
|
9
|
-
|
9
|
+
if es2015
|
10
|
+
put "const "
|
11
|
+
else
|
12
|
+
put "var "
|
13
|
+
end
|
10
14
|
|
15
|
+
cbase ||= @rbstack.map {|rb| rb[var]}.compact.last
|
11
16
|
(parse cbase; put '.') if cbase
|
12
17
|
|
13
18
|
put "#{ var } = "; parse value
|
@@ -9,6 +9,11 @@ module Ruby2JS
|
|
9
9
|
# NOTE: :prop and :method macros are defined at the bottom of this file
|
10
10
|
|
11
11
|
handle :class do |name, inheritance, *body|
|
12
|
+
if es2015
|
13
|
+
parse @ast.updated(:class2)
|
14
|
+
return
|
15
|
+
end
|
16
|
+
|
12
17
|
if inheritance
|
13
18
|
init = s(:def, :initialize, s(:args), s(:super))
|
14
19
|
else
|
@@ -48,7 +53,7 @@ module Ruby2JS
|
|
48
53
|
# method: add to prototype
|
49
54
|
s(:method, s(:attr, name, :prototype),
|
50
55
|
:"#{m.children[0].to_s.chomp('!')}=",
|
51
|
-
s(:
|
56
|
+
s(:def, nil, *m.children[1..-1]))
|
52
57
|
end
|
53
58
|
end
|
54
59
|
|
@@ -57,7 +62,7 @@ module Ruby2JS
|
|
57
62
|
# class property setter
|
58
63
|
s(:prop, name, m.children[1].to_s[0..-2] =>
|
59
64
|
{enumerable: s(:true), configurable: s(:true),
|
60
|
-
set: s(:
|
65
|
+
set: s(:def, nil, *m.children[2..-1])})
|
61
66
|
elsif m.children[2].children.length == 0 and
|
62
67
|
m.children[1] !~ /!/ and m.loc and m.loc.name and
|
63
68
|
m.loc.name.source_buffer.source[m.loc.name.end_pos] != '('
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Ruby2JS
|
2
|
+
class Converter
|
3
|
+
|
4
|
+
# (class2
|
5
|
+
# (const nil :A)
|
6
|
+
# (const nil :B)
|
7
|
+
# (...)
|
8
|
+
|
9
|
+
# NOTE: this is the es2015 version of class
|
10
|
+
|
11
|
+
handle :class2 do |name, inheritance, *body|
|
12
|
+
if name.type == :const and name.children.first == nil
|
13
|
+
put 'class '
|
14
|
+
parse name
|
15
|
+
else
|
16
|
+
parse name
|
17
|
+
put ' = class'
|
18
|
+
end
|
19
|
+
|
20
|
+
if inheritance
|
21
|
+
put ' extends '
|
22
|
+
parse inheritance
|
23
|
+
end
|
24
|
+
|
25
|
+
put " {"
|
26
|
+
|
27
|
+
body.compact!
|
28
|
+
while body.length == 1 and body.first.type == :begin
|
29
|
+
body = body.first.children
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
class_name, @class_name = @class_name, name
|
34
|
+
class_parent, @class_parent = @class_parent, inheritance
|
35
|
+
@rbstack.push({})
|
36
|
+
|
37
|
+
post = []
|
38
|
+
skipped = false
|
39
|
+
body.each_with_index do |m, index|
|
40
|
+
put(index == 0 ? @nl : @sep) unless skipped
|
41
|
+
skipped = false
|
42
|
+
|
43
|
+
# intercept async definitions
|
44
|
+
if es2017 and m.type == :send and m.children[0..1] == [nil, :async]
|
45
|
+
child = m.children[2]
|
46
|
+
if child.type == :def
|
47
|
+
m = child.updated(:async)
|
48
|
+
elsif child.type == :defs and child.children[0].type == :self
|
49
|
+
m = child.updated(:asyncs)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if m.type == :def || m.type == :async
|
54
|
+
@prop = m.children.first
|
55
|
+
|
56
|
+
if @prop == :initialize
|
57
|
+
@prop = :constructor
|
58
|
+
m = m.updated(m.type, [@prop, *m.children[1..2]])
|
59
|
+
elsif not m.is_method?
|
60
|
+
@rbstack.last[@prop] = s(:self)
|
61
|
+
@prop = "get #{@prop}"
|
62
|
+
m = m.updated(m.type, [*m.children[0..1],
|
63
|
+
s(:autoreturn, m.children[2])])
|
64
|
+
elsif @prop.to_s.end_with? '='
|
65
|
+
@prop = @prop.to_s.sub('=', '').to_sym
|
66
|
+
@rbstack.last[@prop] = s(:self)
|
67
|
+
m = m.updated(m.type, [@prop, *m.children[1..2]])
|
68
|
+
@prop = "set #{@prop}"
|
69
|
+
elsif @prop.to_s.end_with? '!'
|
70
|
+
@prop = @prop.to_s.sub('!', '')
|
71
|
+
m = m.updated(m.type, [@prop, *m.children[1..2]])
|
72
|
+
else
|
73
|
+
@rbstack.last[@prop] = s(:self)
|
74
|
+
end
|
75
|
+
|
76
|
+
begin
|
77
|
+
@instance_method = m
|
78
|
+
parse m
|
79
|
+
ensure
|
80
|
+
@instance_method = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
elsif
|
84
|
+
[:defs, :asyncs].include? m.type and m.children.first.type == :self
|
85
|
+
then
|
86
|
+
|
87
|
+
@prop = "static #{m.children[1]}"
|
88
|
+
if not m.is_method?
|
89
|
+
@prop = "static get #{m.children[1]}"
|
90
|
+
m = m.updated(m.type, [*m.children[0..2],
|
91
|
+
s(:autoreturn, m.children[3])])
|
92
|
+
elsif @prop.to_s.end_with? '='
|
93
|
+
@prop = "static set #{m.children[1].to_s.sub('=', '')}"
|
94
|
+
elsif @prop.to_s.end_with? '!'
|
95
|
+
m = m.updated(m.type, [m.children[0],
|
96
|
+
m.children[1].to_s.sub('!', ''), *m.children[2..3]])
|
97
|
+
@prop = "static #{m.children[1]}"
|
98
|
+
end
|
99
|
+
|
100
|
+
@prop.sub! 'static', 'static async' if m.type == :asyncs
|
101
|
+
|
102
|
+
m = m.updated(:def, m.children[1..3])
|
103
|
+
parse m
|
104
|
+
|
105
|
+
elsif m.type == :send and m.children.first == nil
|
106
|
+
if m.children[1] == :attr_accessor
|
107
|
+
m.children[2..-1].each_with_index do |child_sym, index2|
|
108
|
+
put @sep unless index2 == 0
|
109
|
+
var = child_sym.children.first
|
110
|
+
put "get #{var}() {#{@nl}return this._#{var}#@nl}#@sep"
|
111
|
+
put "set #{var}(#{var}) {#{@nl}this._#{var} = #{var}#@nl}"
|
112
|
+
end
|
113
|
+
elsif m.children[1] == :attr_reader
|
114
|
+
m.children[2..-1].each_with_index do |child_sym, index2|
|
115
|
+
put @sep unless index2 == 0
|
116
|
+
var = child_sym.children.first
|
117
|
+
put "get #{var}() {#{@nl}return this._#{var}#@nl}"
|
118
|
+
end
|
119
|
+
elsif m.children[1] == :attr_writer
|
120
|
+
m.children[2..-1].each_with_index do |child_sym, index2|
|
121
|
+
put @sep unless index2 == 0
|
122
|
+
var = child_sym.children.first
|
123
|
+
put "set #{var}(#{var}) {#{@nl}this._#{var} = #{var}#@nl}"
|
124
|
+
end
|
125
|
+
else
|
126
|
+
skipped = true
|
127
|
+
end
|
128
|
+
|
129
|
+
else
|
130
|
+
skipped = true
|
131
|
+
|
132
|
+
if m.type == :casgn and m.children[0] == nil
|
133
|
+
@rbstack.last[m.children[1]] = name
|
134
|
+
elsif m.type == :alias
|
135
|
+
@rbstack.last[m.children[0]] = name
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
post << m if skipped
|
140
|
+
end
|
141
|
+
|
142
|
+
put @nl unless skipped
|
143
|
+
put '}'
|
144
|
+
|
145
|
+
post.each do |m|
|
146
|
+
put @sep
|
147
|
+
if m.type == :alias
|
148
|
+
parse name
|
149
|
+
put '.prototype.'
|
150
|
+
put m.children[0].children[0]
|
151
|
+
put ' = '
|
152
|
+
parse name
|
153
|
+
put '.prototype.'
|
154
|
+
put m.children[1].children[0]
|
155
|
+
else
|
156
|
+
parse m, :statement
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
ensure
|
161
|
+
@class_name = class_name
|
162
|
+
@class_parent = class_parent
|
163
|
+
@rbstack.pop
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -6,7 +6,7 @@ module Ruby2JS
|
|
6
6
|
# (arg :x)
|
7
7
|
# (...)
|
8
8
|
|
9
|
-
handle :def do |name, args, body=nil|
|
9
|
+
handle :def, :async do |name, args, body=nil|
|
10
10
|
body ||= s(:begin)
|
11
11
|
if name =~ /[!?]$/
|
12
12
|
raise NotImplementedError, "invalid method name #{ name }"
|
@@ -16,7 +16,7 @@ module Ruby2JS
|
|
16
16
|
vars.merge! @vars unless name
|
17
17
|
if args and !args.children.empty?
|
18
18
|
# splats
|
19
|
-
if args.children.last.type == :restarg
|
19
|
+
if args.children.last.type == :restarg and not es2015
|
20
20
|
if args.children[-1].children.first
|
21
21
|
body = s(:begin, body) unless body.type == :begin
|
22
22
|
assign = s(:lvasgn, args.children[-1].children.first,
|
@@ -68,7 +68,7 @@ module Ruby2JS
|
|
68
68
|
|
69
69
|
# optional arguments
|
70
70
|
args.children.each_with_index do |arg, i|
|
71
|
-
if arg.type == :optarg
|
71
|
+
if arg.type == :optarg and not es2015
|
72
72
|
body = s(:begin, body) unless body.type == :begin
|
73
73
|
argname, value = arg.children
|
74
74
|
children = args.children.dup
|
@@ -88,13 +88,50 @@ module Ruby2JS
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
+
put 'async ' if @ast.type == :async
|
92
|
+
|
93
|
+
# es2015 fat arrow support
|
94
|
+
if not name and es2015 and @state != :method
|
95
|
+
put '('; parse args; put ') => '
|
96
|
+
|
97
|
+
expr = body
|
98
|
+
expr = expr.children.first if expr.type == :autoreturn
|
99
|
+
while expr.type == :begin and expr.children.length == 1
|
100
|
+
expr = expr.children.first
|
101
|
+
end
|
102
|
+
|
103
|
+
if EXPRESSIONS.include? expr.type
|
104
|
+
if expr.type == :send and expr.children[0..1] == [nil, :raise]
|
105
|
+
style = :statement
|
106
|
+
else
|
107
|
+
style = :expression
|
108
|
+
end
|
109
|
+
elsif
|
110
|
+
expr.type == :if and expr.children[1] and expr.children[2] and
|
111
|
+
EXPRESSIONS.include? expr.children[1].type and
|
112
|
+
EXPRESSIONS.include? expr.children[2].type
|
113
|
+
then
|
114
|
+
style = :expression
|
115
|
+
else
|
116
|
+
style = :statement
|
117
|
+
end
|
118
|
+
|
119
|
+
if style == :expression
|
120
|
+
expr.type == :hash ? group(expr) : parse(expr)
|
121
|
+
else
|
122
|
+
put "{#{@nl}"; scope body, vars; put "#{@nl}}"
|
123
|
+
end
|
124
|
+
|
125
|
+
return
|
126
|
+
end
|
127
|
+
|
91
128
|
nl = @nl unless body == s(:begin)
|
92
129
|
begin
|
93
|
-
if
|
94
|
-
put "function #{name}"
|
95
|
-
elsif @prop
|
130
|
+
if @prop
|
96
131
|
put @prop
|
97
132
|
@prop = nil
|
133
|
+
elsif name
|
134
|
+
put "function #{name}"
|
98
135
|
else
|
99
136
|
put 'function'
|
100
137
|
end
|
@@ -116,5 +153,16 @@ module Ruby2JS
|
|
116
153
|
@block_depth -= 1 if @block_depth
|
117
154
|
end
|
118
155
|
end
|
156
|
+
|
157
|
+
handle :optarg do |name, value|
|
158
|
+
put name
|
159
|
+
put '='
|
160
|
+
parse value
|
161
|
+
end
|
162
|
+
|
163
|
+
handle :restarg do |name|
|
164
|
+
put '...'
|
165
|
+
put name
|
166
|
+
end
|
119
167
|
end
|
120
168
|
end
|
@@ -5,10 +5,17 @@ module Ruby2JS
|
|
5
5
|
# (args)
|
6
6
|
# (...)
|
7
7
|
|
8
|
-
# NOTE: defp
|
8
|
+
# NOTE: defp and asyncs are only produced by filters
|
9
9
|
|
10
|
-
handle :defs, :defp do |target, method, args, body|
|
11
|
-
|
10
|
+
handle :defs, :defp, :asyncs do |target, method, args, body|
|
11
|
+
node = transform_defs(target, method, args, body)
|
12
|
+
|
13
|
+
if node.type == :send and @ast.type == :asyncs
|
14
|
+
node = node.updated(nil, [*node.children[0..1],
|
15
|
+
node.children[2].updated(:async)])
|
16
|
+
end
|
17
|
+
|
18
|
+
parse node, :method
|
12
19
|
end
|
13
20
|
|
14
21
|
def transform_defs(target, method, args, body)
|
@@ -23,8 +30,7 @@ module Ruby2JS
|
|
23
30
|
set: s(:block, s(:send, nil, :proc), args,
|
24
31
|
body)})
|
25
32
|
else
|
26
|
-
node = s(:send, target, "#{method}=",
|
27
|
-
s(:block, s(:send, nil, :proc), args, body))
|
33
|
+
node = s(:send, target, "#{method}=", s(:def, nil, args, body))
|
28
34
|
end
|
29
35
|
|
30
36
|
@comments[node] = @comments[@ast] if @comments[@ast]
|
@@ -10,6 +10,32 @@ module Ruby2JS
|
|
10
10
|
# (...))
|
11
11
|
|
12
12
|
handle :dstr, :dsym do |*children|
|
13
|
+
if es2015
|
14
|
+
put '`'
|
15
|
+
|
16
|
+
# gather length of string parts; if long enough, newlines will
|
17
|
+
# not be escaped
|
18
|
+
length = children.select {|child| child.type==:str}.
|
19
|
+
map {|child| child.children.last.length}.inject(:+)
|
20
|
+
|
21
|
+
children.each do |child|
|
22
|
+
if child.type == :str
|
23
|
+
str = child.children.first.inspect[1..-2].gsub('${', '$\{')
|
24
|
+
if length > 40
|
25
|
+
put str.gsub("\\n", "\n")
|
26
|
+
else
|
27
|
+
put str
|
28
|
+
end
|
29
|
+
else
|
30
|
+
put '${'
|
31
|
+
parse child
|
32
|
+
put '}'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
put '`'
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
13
39
|
children.each_with_index do |child, index|
|
14
40
|
put ' + ' unless index == 0
|
15
41
|
|
@@ -9,16 +9,16 @@ module Ruby2JS
|
|
9
9
|
# (int 1))
|
10
10
|
# (...)
|
11
11
|
|
12
|
-
handle :for do |var, expression, block|
|
12
|
+
handle :for, :for_of do |var, expression, block|
|
13
13
|
begin
|
14
14
|
next_token, @next_token = @next_token, :continue
|
15
|
-
put "for (var "; parse var
|
15
|
+
put "for (#{es2015 ? 'let' : 'var'} "; parse var
|
16
16
|
if [:irange, :erange].include? expression.type
|
17
17
|
put ' = '; parse expression.children.first; put '; '; parse var
|
18
18
|
(expression.type == :erange ? put(' < ') : put(' <= '))
|
19
19
|
parse expression.children.last; put '; '; parse var; put '++'
|
20
20
|
else
|
21
|
-
put ' in '; parse expression;
|
21
|
+
put (@ast.type==:for_of ? ' of ' : ' in '); parse expression;
|
22
22
|
end
|
23
23
|
puts ') {'; scope block; sput '}'
|
24
24
|
ensure
|