ruby2js 2.1.24 → 3.0.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 +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
|