ruby2js 3.4.0 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +128 -20
- data/lib/ruby2js.rb +30 -2
- data/lib/ruby2js/converter.rb +7 -5
- data/lib/ruby2js/converter/block.rb +5 -0
- data/lib/ruby2js/converter/class2.rb +63 -20
- data/lib/ruby2js/converter/def.rb +1 -1
- data/lib/ruby2js/converter/import.rb +17 -1
- data/lib/ruby2js/converter/ivar.rb +10 -2
- data/lib/ruby2js/converter/literal.rb +14 -2
- data/lib/ruby2js/converter/send.rb +4 -3
- data/lib/ruby2js/converter/xstr.rb +1 -1
- data/lib/ruby2js/filter/active_functions.rb +43 -0
- data/lib/ruby2js/filter/camelCase.rb +4 -3
- data/lib/ruby2js/filter/esm.rb +96 -4
- data/lib/ruby2js/filter/functions.rb +14 -0
- data/lib/ruby2js/filter/node.rb +95 -74
- data/lib/ruby2js/filter/nokogiri.rb +3 -29
- data/lib/ruby2js/filter/return.rb +2 -0
- data/lib/ruby2js/filter/securerandom.rb +33 -0
- data/lib/ruby2js/filter/vue.rb +9 -0
- data/lib/ruby2js/rails.rb +15 -9
- data/lib/ruby2js/serializer.rb +4 -2
- data/lib/ruby2js/version.rb +1 -1
- data/ruby2js.gemspec +1 -1
- metadata +9 -7
- data/lib/ruby2js/filter/esm_migration.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fa9e6949c8d7d1f3f5cb549dc234a2b559d032bc9b5b236d123f68b62ecd763
|
4
|
+
data.tar.gz: e89542553f4db3caa7ceda112542a3a7fceb468d23d8a15cb9b416954c054d1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a46d662b6be3a5e7a7242c1249705dcc5b705bfa984443ebedbb766c241aff365ce6f45fbea6b774f6646ce807c6d7f595becb841866f1a878ae65f69b409430
|
7
|
+
data.tar.gz: 27091e81578f5cebad30132ef54c3e08a1a32516233a0cab084c15dca5b361c7a2c7602dd3ba886d57db23301bb5a7d54d106cabba7a5a71d5989fc0b959533d
|
data/README.md
CHANGED
@@ -40,9 +40,6 @@ For example:
|
|
40
40
|
* Any block becomes and explicit argument `new Promise do; y(); end` becomes `new Promise(function() {y()})`
|
41
41
|
* regular expressions are mapped to js
|
42
42
|
* `raise` becomes `throw`
|
43
|
-
* expressions enclosed in backtick operators (\`\`) and `%x{}` literals are
|
44
|
-
evaluated in the context of the caller and the results are inserted
|
45
|
-
into the generated JavaScript.
|
46
43
|
|
47
44
|
Ruby attribute accessors, methods defined with no parameters and no
|
48
45
|
parenthesis, as well as setter method definitions, are
|
@@ -81,6 +78,18 @@ require 'ruby2js/filter/functions'
|
|
81
78
|
puts Ruby2JS.convert('"2A".to_i(16)')
|
82
79
|
```
|
83
80
|
|
81
|
+
Host variable substitution:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
puts Ruby2JS.convert("@name", ivars: {:@name => "Joe"})
|
85
|
+
```
|
86
|
+
|
87
|
+
Host expression evalution -- potentially unsafe, use only if you trust
|
88
|
+
the source being converted::
|
89
|
+
```ruby
|
90
|
+
i = 7; puts Ruby2JS.convert("i = `i`", binding: binding)
|
91
|
+
```
|
92
|
+
|
84
93
|
Enable ES2015 support:
|
85
94
|
|
86
95
|
```ruby
|
@@ -129,7 +138,7 @@ Introduction
|
|
129
138
|
|
130
139
|
JavaScript is a language where `0` is considered `false`, strings are
|
131
140
|
immutable, and the behaviors for operators like `==` are, at best,
|
132
|
-
[convoluted](
|
141
|
+
[convoluted](https://zero.milosz.ca/).
|
133
142
|
|
134
143
|
Any attempt to bridge the semantics of Ruby and JavaScript will involve
|
135
144
|
trade-offs. Consider the following expression:
|
@@ -144,10 +153,10 @@ quite different if `a` is a Hash.
|
|
144
153
|
|
145
154
|
One way to resolve this is to change the way indexing operators are evaluated,
|
146
155
|
and to provide a runtime library that adds properties to global JavaScript
|
147
|
-
objects to handle this. This is the approach that [Opal](
|
156
|
+
objects to handle this. This is the approach that [Opal](https://opalrb.com/)
|
148
157
|
takes. It is a fine approach, with a number of benefits. It also has some
|
149
158
|
notable drawbacks. For example,
|
150
|
-
[readability](
|
159
|
+
[readability](https://opalrb.com/try/#code:a%20%3D%20%22abc%22%3B%20puts%20a[-1])
|
151
160
|
and
|
152
161
|
[compatibility with other frameworks](https://github.com/opal/opal/issues/400).
|
153
162
|
|
@@ -169,7 +178,7 @@ negative at runtime.
|
|
169
178
|
This quickly gets into gray areas. `each` in Ruby is a common method that
|
170
179
|
facilitates iteration over arrays. `forEach` is the JavaScript equivalent.
|
171
180
|
Mapping this is fine until you start using a framework like jQuery which
|
172
|
-
provides a function named [each](
|
181
|
+
provides a function named [each](https://api.jquery.com/jQuery.each/).
|
173
182
|
|
174
183
|
Fortunately, Ruby provides `?` and `!` as legal suffixes for method names,
|
175
184
|
Ruby2js filters do an exact match, so if you select a filter that maps `each`
|
@@ -192,9 +201,7 @@ Ruby2JS::Filter.exclude :each
|
|
192
201
|
```
|
193
202
|
|
194
203
|
Static transformations and runtime libraries aren't aren’t mutually exclusive.
|
195
|
-
With enough of each, one could reproduce any functionality desired.
|
196
|
-
forewarned, that implementing a function like `method_missing` would require a
|
197
|
-
_lot_ of work.
|
204
|
+
With enough of each, one could reproduce any functionality desired.
|
198
205
|
|
199
206
|
Integrations
|
200
207
|
---
|
@@ -237,8 +244,10 @@ the script.
|
|
237
244
|
|
238
245
|
* <a id="functions" href="https://github.com/rubys/ruby2js/blob/master/lib/ruby2js/filter/functions.rb">functions</a>
|
239
246
|
|
247
|
+
* `.abs` becomes `Math.abs()`
|
240
248
|
* `.all?` becomes `.every`
|
241
249
|
* `.any?` becomes `.some`
|
250
|
+
* `.ceil` becomes `Math.ceil()`
|
242
251
|
* `.chr` becomes `fromCharCode`
|
243
252
|
* `.clear` becomes `.length = 0`
|
244
253
|
* `.delete` becomes `delete target[arg]`
|
@@ -253,6 +262,7 @@ the script.
|
|
253
262
|
* `.find_index` becomes `findIndex`
|
254
263
|
* `.first` becomes `[0]`
|
255
264
|
* `.first(n)` becomes `.slice(0, n)`
|
265
|
+
* `.floor` becomes `Math.floor()`
|
256
266
|
* `.gsub` becomes `replace(//g)`
|
257
267
|
* `.include?` becomes `.indexOf() != -1`
|
258
268
|
* `.inspect` becomes `JSON.stringify()`
|
@@ -271,6 +281,7 @@ the script.
|
|
271
281
|
* `.respond_to?` becomes `right in left`
|
272
282
|
* `.rstrip` becomes `.replace(/s+$/, "")`
|
273
283
|
* `.scan` becomes `.match(//g)`
|
284
|
+
* `.sum` becomes `.reduce(function(a, b) {a + b}, 0)`
|
274
285
|
* `.start_with?` becomes `.substring(0, arg.length) == arg`
|
275
286
|
* `.upto(lim)` becomes `for (var i=num; i<=lim; i+=1)`
|
276
287
|
* `.downto(lim)` becomes `for (var i=num; i>=lim; i-=1)`
|
@@ -317,6 +328,20 @@ the script.
|
|
317
328
|
|
318
329
|
* `.class` becomes `.constructor`
|
319
330
|
|
331
|
+
* <a id="active_functions" href="https://github.com/rubys/ruby2js/blob/master/lib/ruby2js/filter/active_functions.rb">active_functions</a>
|
332
|
+
|
333
|
+
Provides functionality inspired by Rails' ActiveSupport. Works in conjunction
|
334
|
+
with the tiny NPM dependency `@ruby2js/active-functions` which must be added to
|
335
|
+
your application.
|
336
|
+
|
337
|
+
* `value.blank?` becomes `blank$(value)`
|
338
|
+
* `value.present?` becomes `present$(value)`
|
339
|
+
* `value.presence` becomes `presence$(value)`
|
340
|
+
|
341
|
+
Note: these conversions are only done if eslevel >= 2015. Import statements
|
342
|
+
will be added to the top of the code output automatically. By default they
|
343
|
+
will be `@ruby2js/active-functions`, but you can pass an `import_from_skypack: true` option to `convert` to use the Skypack CDN instead.
|
344
|
+
|
320
345
|
* <a id="tagged_templates" href="https://github.com/rubys/ruby2js/blob/master/lib/ruby2js/filter/tagged_templates.rb">tagged_templates</a>
|
321
346
|
|
322
347
|
Allows you to turn certain method calls with a string argument into tagged
|
@@ -382,6 +407,59 @@ the script.
|
|
382
407
|
# => export { one, two, three as default }
|
383
408
|
```
|
384
409
|
|
410
|
+
If the "autoexports" option is `true`, all top level modules, classes,
|
411
|
+
methods and constants will automatically be exported.
|
412
|
+
|
413
|
+
The esm filter also provides a way to specify "autoimports" when you run the
|
414
|
+
conversion. It will add the relevant import statements automatically whenever
|
415
|
+
a particular class or function name is referenced. These can be either default
|
416
|
+
or named exports. Simply provide an `autoimports` hash with one or more keys
|
417
|
+
to the `Ruby2JS.convert` method. Examples:
|
418
|
+
|
419
|
+
```ruby
|
420
|
+
require "ruby2js/filter/esm"
|
421
|
+
puts Ruby2JS.convert('class MyElement < LitElement; end',
|
422
|
+
eslevel: 2020, autoimports: {[:LitElement] => "lit-element"})
|
423
|
+
```
|
424
|
+
|
425
|
+
```js
|
426
|
+
// JavaScript output:
|
427
|
+
import { LitElement } from "lit-element"
|
428
|
+
class MyElement extends LitElement {}
|
429
|
+
```
|
430
|
+
|
431
|
+
```ruby
|
432
|
+
require "ruby2js/filter/esm"
|
433
|
+
puts Ruby2JS.convert('AWN.new({position: "top-right"}).success("Hello World")',
|
434
|
+
eslevel: 2020, autoimports: {:AWN => "awesome-notifications"})
|
435
|
+
```
|
436
|
+
|
437
|
+
```js
|
438
|
+
// JavaScript output:
|
439
|
+
import AWN from "awesome-notifications"
|
440
|
+
new AWN({position: "top-right"}).success("Hello World")
|
441
|
+
```
|
442
|
+
|
443
|
+
The esm filter is able to recognize if you are defining a class or function
|
444
|
+
within the code itself and it won't add that import statement accordingly.
|
445
|
+
If for some reason you wish to disable autoimports entirely on a file-by-file
|
446
|
+
basis (for instance when using the Webpack loader), you can add a magic comment
|
447
|
+
to the top of the code:
|
448
|
+
|
449
|
+
```ruby
|
450
|
+
require "ruby2js/filter/esm"
|
451
|
+
puts Ruby2JS.convert(
|
452
|
+
"# autoimports: false\n" +
|
453
|
+
'AWN.new({position: "top-right"}).success("Hello World")',
|
454
|
+
eslevel: 2020, autoimports: {:AWN => "awesome-notifications"}
|
455
|
+
)
|
456
|
+
```
|
457
|
+
|
458
|
+
```js
|
459
|
+
// autoimports: false
|
460
|
+
new AWN({position: "top-right"}).success("Hello World")
|
461
|
+
```
|
462
|
+
|
385
463
|
* <a id="node" href="https://github.com/rubys/ruby2js/blob/master/spec/node_spec.rb">node</a>
|
386
464
|
|
387
465
|
* `` `command` `` becomes `child_process.execSync("command", {encoding: "utf8"})`
|
@@ -389,24 +467,34 @@ the script.
|
|
389
467
|
* `__dir__` becomes `__dirname`
|
390
468
|
* `Dir.chdir` becomes `process.chdir`
|
391
469
|
* `Dir.entries` becomes `fs.readdirSync`
|
470
|
+
* `Dir.home` becomes `os.homedir()`
|
392
471
|
* `Dir.mkdir` becomes `fs.mkdirSync`
|
393
472
|
* `Dir.mktmpdir` becomes `fs.mkdtempSync`
|
394
473
|
* `Dir.pwd` becomes `process.cwd`
|
395
474
|
* `Dir.rmdir` becomes `fs.rmdirSync`
|
475
|
+
* `Dir.tmpdir` becomes `os.tmpdir()`
|
396
476
|
* `ENV` becomes `process.env`
|
397
477
|
* `__FILE__` becomes `__filename`
|
478
|
+
* `File.absolute_path` becomes `path.resolve`
|
479
|
+
* `File.absolute_path?` becomes `path.isAbsolute`
|
480
|
+
* `File.basename` becomes `path.basename`
|
398
481
|
* `File.chmod` becomes `fs.chmodSync`
|
399
482
|
* `File.chown` becomes `fs.chownSync`
|
400
483
|
* `File.cp` becomes `fs.copyFileSync`
|
484
|
+
* `File.dirname` becomes `path.dirname`
|
401
485
|
* `File.exist?` becomes `fs.existsSync`
|
486
|
+
* `File.extname` becomes `path.extname`
|
487
|
+
* `File.join` becomes `path.join`
|
402
488
|
* `File.lchmod` becomes `fs.lchmodSync`
|
403
489
|
* `File.link` becomes `fs.linkSync`
|
404
490
|
* `File.ln` becomes `fs.linkSync`
|
405
491
|
* `File.lstat` becomes `fs.lstatSync`
|
492
|
+
* `File::PATH_SEPARATOR` becomes `path.delimiter`
|
406
493
|
* `File.read` becomes `fs.readFileSync`
|
407
494
|
* `File.readlink` becomes `fs.readlinkSync`
|
408
495
|
* `File.realpath` becomes `fs.realpathSync`
|
409
496
|
* `File.rename` becomes `fs.renameSync`
|
497
|
+
* `File::SEPARATOR` becomes `path.sep`
|
410
498
|
* `File.stat` becomes `fs.statSync`
|
411
499
|
* `File.symlink` becomes `fs.symlinkSync`
|
412
500
|
* `File.truncate` becomes `fs.truncateSync`
|
@@ -600,8 +688,16 @@ Additionally, the `functions` filter will provide the following conversion:
|
|
600
688
|
* `Array(x)` becomes `Array.from(x)`
|
601
689
|
* `.inject(n) {}` becomes `.reduce(() => {}, n)`
|
602
690
|
|
603
|
-
|
604
|
-
parameter
|
691
|
+
Keyword arguments and optional keyword arguments will be mapped to
|
692
|
+
parameter destructuring.
|
693
|
+
|
694
|
+
Classes defined with a `method_missing` method will emit a `Proxy` object
|
695
|
+
for each instance that will forward calls. Note that in order to forward
|
696
|
+
arguments, this proxy will return a function that will need to be called,
|
697
|
+
making it impossible to proxy attributes/getters. As a special accommodation,
|
698
|
+
if the `method_missing` method is defined to only accept a single parameter
|
699
|
+
it will be called with only the method name, and it is free to return
|
700
|
+
either values or functions.
|
605
701
|
|
606
702
|
ES2016 support
|
607
703
|
---
|
@@ -610,6 +706,9 @@ When option `eslevel: 2016` is provided, the following additional
|
|
610
706
|
conversion is made:
|
611
707
|
|
612
708
|
* `a ** b` becomes `a ** b`
|
709
|
+
|
710
|
+
Additionally the following conversions is added to the `functions` filter:
|
711
|
+
|
613
712
|
* `.include?` becomes `.includes`
|
614
713
|
|
615
714
|
ES2017 support
|
@@ -620,7 +719,15 @@ conversions are made by the `functions` filter:
|
|
620
719
|
|
621
720
|
* `.values()` becomes `Object.values()`
|
622
721
|
* `.entries()` becomes `Object.entries()`
|
623
|
-
* `.each_pair {}` becomes `for (let [key, value] of Object.entries()) {}
|
722
|
+
* `.each_pair {}` becomes `for (let [key, value] of Object.entries()) {}`
|
723
|
+
|
724
|
+
async support:
|
725
|
+
|
726
|
+
* `async def` becomes `async function`
|
727
|
+
* `async lambda` becomes `async =>`
|
728
|
+
* `async proc` becomes `async =>`
|
729
|
+
* `async ->` becomes `async =>`
|
730
|
+
* `foo bar, async do...end` becomes `foo(bar, async () => {})`
|
624
731
|
|
625
732
|
ES2018 support
|
626
733
|
---
|
@@ -640,8 +747,8 @@ When option `eslevel: 2019` is provided, the following additional
|
|
640
747
|
conversion is made by the `functions` filter:
|
641
748
|
|
642
749
|
* `.flatten` becomes `.flat(Infinity)`
|
643
|
-
* `.lstrip` becomes `.trimEnd
|
644
|
-
* `.rstrip` becomes `.trimStart
|
750
|
+
* `.lstrip` becomes `.trimEnd`
|
751
|
+
* `.rstrip` becomes `.trimStart`
|
645
752
|
* `a.to_h` becomes `Object.fromEntries(a)`
|
646
753
|
* `Hash[a]` becomes `Object.fromEntries(a)`
|
647
754
|
|
@@ -667,27 +774,28 @@ conversions are made:
|
|
667
774
|
|
668
775
|
* `x ||= 1` becomes `x ||= 1`
|
669
776
|
* `x &&= 1` becomes `x &&= 1`
|
777
|
+
* `1000000.000001` becomes `1_000_000.000_001`
|
670
778
|
|
671
779
|
Picking a Ruby to JS mapping tool
|
672
780
|
---
|
673
781
|
|
674
782
|
> dsl — A domain specific language, where code is written in one language and
|
675
783
|
> errors are given in another.
|
676
|
-
> -- [Devil’s Dictionary of Programming](
|
784
|
+
> -- [Devil’s Dictionary of Programming](https://programmingisterrible.com/post/65781074112/devils-dictionary-of-programming)
|
677
785
|
|
678
786
|
If you simply want to get a job done, and would like a mature and tested
|
679
787
|
framework, and only use one of the many integrations that
|
680
|
-
[Opal](
|
788
|
+
[Opal](https://opalrb.com/) provides, then Opal is the way to go right now.
|
681
789
|
|
682
790
|
ruby2js is for those that want to produce JavaScript that looks like it
|
683
791
|
wasn’t machine generated, and want the absolute bare minimum in terms of
|
684
792
|
limitations as to what JavaScript can be produced.
|
685
793
|
|
686
|
-
[Try](
|
687
|
-
[Compare](
|
794
|
+
[Try](https://intertwingly.net/projects/ruby2js) for yourself.
|
795
|
+
[Compare](https://opalrb.com/try/#code:).
|
688
796
|
|
689
797
|
And, of course, the right solution might be to use
|
690
|
-
[CoffeeScript](
|
798
|
+
[CoffeeScript](https://coffeescript.org/) instead.
|
691
799
|
|
692
800
|
License
|
693
801
|
---
|
data/lib/ruby2js.rb
CHANGED
@@ -17,6 +17,7 @@ module Ruby2JS
|
|
17
17
|
|
18
18
|
@@eslevel_default = 2009 # ecmascript 5
|
19
19
|
@@strict_default = false
|
20
|
+
@@module_default = nil
|
20
21
|
|
21
22
|
def self.eslevel_default
|
22
23
|
@@eslevel_default
|
@@ -34,6 +35,14 @@ module Ruby2JS
|
|
34
35
|
@@strict_default = level
|
35
36
|
end
|
36
37
|
|
38
|
+
def self.module_default
|
39
|
+
@@module_default
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.module_default=(module_type)
|
43
|
+
@@module_default = module_type
|
44
|
+
end
|
45
|
+
|
37
46
|
module Filter
|
38
47
|
DEFAULTS = []
|
39
48
|
|
@@ -52,11 +61,19 @@ module Ruby2JS
|
|
52
61
|
include Ruby2JS::Filter
|
53
62
|
BINARY_OPERATORS = Converter::OPERATORS[2..-1].flatten
|
54
63
|
|
64
|
+
attr_accessor :prepend_list, :disable_autoimports
|
65
|
+
|
55
66
|
def initialize(comments)
|
56
67
|
@comments = comments
|
68
|
+
|
69
|
+
# check if magic comment is present:
|
70
|
+
first_comment = @comments.values.first&.map(&:text)&.first
|
71
|
+
@disable_autoimports = first_comment&.include?(" autoimports: false")
|
72
|
+
@disable_autoexports = first_comment&.include?(" autoexports: false")
|
73
|
+
|
57
74
|
@ast = nil
|
58
75
|
@exclude_methods = []
|
59
|
-
@
|
76
|
+
@prepend_list = Set.new
|
60
77
|
end
|
61
78
|
|
62
79
|
def options=(options)
|
@@ -129,6 +146,7 @@ module Ruby2JS
|
|
129
146
|
def on_method(node); on_send(node); end
|
130
147
|
def on_prop(node); on_array(node); end
|
131
148
|
def on_prototype(node); on_begin(node); end
|
149
|
+
def on_send!(node); on_send(node); end
|
132
150
|
def on_sendw(node); on_send(node); end
|
133
151
|
def on_undefined?(node); on_defined?(node); end
|
134
152
|
def on_nil(node); end
|
@@ -162,6 +180,7 @@ module Ruby2JS
|
|
162
180
|
def self.convert(source, options={})
|
163
181
|
options[:eslevel] ||= @@eslevel_default
|
164
182
|
options[:strict] = @@strict_default if options[:strict] == nil
|
183
|
+
options[:module] ||= @@module_default || :esm
|
165
184
|
|
166
185
|
if Proc === source
|
167
186
|
file,line = source.source_location
|
@@ -175,7 +194,7 @@ module Ruby2JS
|
|
175
194
|
source = ast.loc.expression.source_buffer.source
|
176
195
|
else
|
177
196
|
ast, comments = parse( source, options[:file] )
|
178
|
-
comments = Parser::Source::Comment.associate(ast, comments)
|
197
|
+
comments = ast ? Parser::Source::Comment.associate(ast, comments) : {}
|
179
198
|
end
|
180
199
|
|
181
200
|
filters = (options[:filters] || Filter::DEFAULTS)
|
@@ -193,6 +212,12 @@ module Ruby2JS
|
|
193
212
|
|
194
213
|
filter.options = options
|
195
214
|
ast = filter.process(ast)
|
215
|
+
|
216
|
+
unless filter.prepend_list.empty?
|
217
|
+
prepend = filter.prepend_list.sort_by {|ast| ast.type == :import ? 0 : 1}
|
218
|
+
prepend.reject! {|ast| ast.type == :import} if filter.disable_autoimports
|
219
|
+
ast = Parser::AST::Node.new(:begin, [*prepend, ast])
|
220
|
+
end
|
196
221
|
end
|
197
222
|
|
198
223
|
ruby2js = Ruby2JS::Converter.new(ast, comments)
|
@@ -203,6 +228,7 @@ module Ruby2JS
|
|
203
228
|
ruby2js.strict = options[:strict]
|
204
229
|
ruby2js.comparison = options[:comparison] || :equality
|
205
230
|
ruby2js.or = options[:or] || :logical
|
231
|
+
ruby2js.module_type = options[:module] || :esm
|
206
232
|
ruby2js.underscored_private = (options[:eslevel] < 2020) || options[:underscored_private]
|
207
233
|
if ruby2js.binding and not ruby2js.ivars
|
208
234
|
ruby2js.ivars = ruby2js.binding.eval \
|
@@ -221,6 +247,8 @@ module Ruby2JS
|
|
221
247
|
|
222
248
|
ruby2js.timestamp options[:file]
|
223
249
|
|
250
|
+
ruby2js.file_name = options[:file] || ast&.loc&.expression&.source_buffer&.name || ''
|
251
|
+
|
224
252
|
ruby2js
|
225
253
|
end
|
226
254
|
|
data/lib/ruby2js/converter.rb
CHANGED
@@ -3,9 +3,11 @@ require 'ruby2js/serializer'
|
|
3
3
|
module Ruby2JS
|
4
4
|
class Error < NotImplementedError
|
5
5
|
def initialize(message, ast)
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
if ast.loc
|
7
|
+
message += ' at ' + ast.loc.expression.source_buffer.name.to_s
|
8
|
+
message += ':' + ast.loc.expression.line.inspect
|
9
|
+
message += ':' + ast.loc.expression.column.to_s
|
10
|
+
end
|
9
11
|
super(message)
|
10
12
|
end
|
11
13
|
end
|
@@ -128,7 +130,7 @@ module Ruby2JS
|
|
128
130
|
Parser::AST::Node.new(type, args)
|
129
131
|
end
|
130
132
|
|
131
|
-
attr_accessor :strict, :eslevel, :comparison, :or, :underscored_private
|
133
|
+
attr_accessor :strict, :eslevel, :module_type, :comparison, :or, :underscored_private
|
132
134
|
|
133
135
|
def es2015
|
134
136
|
@eslevel >= 2015
|
@@ -246,7 +248,7 @@ module Ruby2JS
|
|
246
248
|
if ast.loc and ast.loc.expression
|
247
249
|
filename = ast.loc.expression.source_buffer.name
|
248
250
|
if filename and not filename.empty?
|
249
|
-
@timestamps[filename] ||= File.mtime(filename)
|
251
|
+
@timestamps[filename] ||= File.mtime(filename) rescue nil
|
250
252
|
end
|
251
253
|
end
|
252
254
|
|
@@ -9,6 +9,11 @@ module Ruby2JS
|
|
9
9
|
|
10
10
|
handle :block do |call, args, block|
|
11
11
|
|
12
|
+
if es2017 and call.children.last == s(:send, nil, :async)
|
13
|
+
return parse call.updated(nil, [*call.children[0..-2],
|
14
|
+
s(:send, nil, :async, s(:block, s(:send, nil, :proc), args, block))])
|
15
|
+
end
|
16
|
+
|
12
17
|
if \
|
13
18
|
@state == :statement and args.children.length == 1 and
|
14
19
|
call.children.first and call.children.first.type == :begin and
|