ruby2js 3.5.3 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +111 -20
- data/lib/ruby2js.rb +14 -5
- data/lib/ruby2js/converter.rb +1 -1
- data/lib/ruby2js/converter/class2.rb +63 -20
- data/lib/ruby2js/converter/def.rb +1 -1
- data/lib/ruby2js/converter/import.rb +1 -1
- 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 +81 -23
- data/lib/ruby2js/filter/functions.rb +5 -0
- data/lib/ruby2js/filter/node.rb +58 -14
- data/lib/ruby2js/serializer.rb +3 -1
- data/lib/ruby2js/version.rb +2 -2
- data/ruby2js.gemspec +1 -1
- metadata +8 -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
|
@@ -87,6 +84,12 @@ Host variable substitution:
|
|
87
84
|
puts Ruby2JS.convert("@name", ivars: {:@name => "Joe"})
|
88
85
|
```
|
89
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
|
+
|
90
93
|
Enable ES2015 support:
|
91
94
|
|
92
95
|
```ruby
|
@@ -135,7 +138,7 @@ Introduction
|
|
135
138
|
|
136
139
|
JavaScript is a language where `0` is considered `false`, strings are
|
137
140
|
immutable, and the behaviors for operators like `==` are, at best,
|
138
|
-
[convoluted](
|
141
|
+
[convoluted](https://zero.milosz.ca/).
|
139
142
|
|
140
143
|
Any attempt to bridge the semantics of Ruby and JavaScript will involve
|
141
144
|
trade-offs. Consider the following expression:
|
@@ -150,10 +153,10 @@ quite different if `a` is a Hash.
|
|
150
153
|
|
151
154
|
One way to resolve this is to change the way indexing operators are evaluated,
|
152
155
|
and to provide a runtime library that adds properties to global JavaScript
|
153
|
-
objects to handle this. This is the approach that [Opal](
|
156
|
+
objects to handle this. This is the approach that [Opal](https://opalrb.com/)
|
154
157
|
takes. It is a fine approach, with a number of benefits. It also has some
|
155
158
|
notable drawbacks. For example,
|
156
|
-
[readability](
|
159
|
+
[readability](https://opalrb.com/try/#code:a%20%3D%20%22abc%22%3B%20puts%20a[-1])
|
157
160
|
and
|
158
161
|
[compatibility with other frameworks](https://github.com/opal/opal/issues/400).
|
159
162
|
|
@@ -175,7 +178,7 @@ negative at runtime.
|
|
175
178
|
This quickly gets into gray areas. `each` in Ruby is a common method that
|
176
179
|
facilitates iteration over arrays. `forEach` is the JavaScript equivalent.
|
177
180
|
Mapping this is fine until you start using a framework like jQuery which
|
178
|
-
provides a function named [each](
|
181
|
+
provides a function named [each](https://api.jquery.com/jQuery.each/).
|
179
182
|
|
180
183
|
Fortunately, Ruby provides `?` and `!` as legal suffixes for method names,
|
181
184
|
Ruby2js filters do an exact match, so if you select a filter that maps `each`
|
@@ -198,9 +201,7 @@ Ruby2JS::Filter.exclude :each
|
|
198
201
|
```
|
199
202
|
|
200
203
|
Static transformations and runtime libraries aren't aren’t mutually exclusive.
|
201
|
-
With enough of each, one could reproduce any functionality desired.
|
202
|
-
forewarned, that implementing a function like `method_missing` would require a
|
203
|
-
_lot_ of work.
|
204
|
+
With enough of each, one could reproduce any functionality desired.
|
204
205
|
|
205
206
|
Integrations
|
206
207
|
---
|
@@ -280,6 +281,7 @@ the script.
|
|
280
281
|
* `.respond_to?` becomes `right in left`
|
281
282
|
* `.rstrip` becomes `.replace(/s+$/, "")`
|
282
283
|
* `.scan` becomes `.match(//g)`
|
284
|
+
* `.sum` becomes `.reduce(function(a, b) {a + b}, 0)`
|
283
285
|
* `.start_with?` becomes `.substring(0, arg.length) == arg`
|
284
286
|
* `.upto(lim)` becomes `for (var i=num; i<=lim; i+=1)`
|
285
287
|
* `.downto(lim)` becomes `for (var i=num; i>=lim; i-=1)`
|
@@ -326,6 +328,20 @@ the script.
|
|
326
328
|
|
327
329
|
* `.class` becomes `.constructor`
|
328
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
|
+
|
329
345
|
* <a id="tagged_templates" href="https://github.com/rubys/ruby2js/blob/master/lib/ruby2js/filter/tagged_templates.rb">tagged_templates</a>
|
330
346
|
|
331
347
|
Allows you to turn certain method calls with a string argument into tagged
|
@@ -391,6 +407,59 @@ the script.
|
|
391
407
|
# => export { one, two, three as default }
|
392
408
|
```
|
393
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
|
+
|
394
463
|
* <a id="node" href="https://github.com/rubys/ruby2js/blob/master/spec/node_spec.rb">node</a>
|
395
464
|
|
396
465
|
* `` `command` `` becomes `child_process.execSync("command", {encoding: "utf8"})`
|
@@ -398,24 +467,34 @@ the script.
|
|
398
467
|
* `__dir__` becomes `__dirname`
|
399
468
|
* `Dir.chdir` becomes `process.chdir`
|
400
469
|
* `Dir.entries` becomes `fs.readdirSync`
|
470
|
+
* `Dir.home` becomes `os.homedir()`
|
401
471
|
* `Dir.mkdir` becomes `fs.mkdirSync`
|
402
472
|
* `Dir.mktmpdir` becomes `fs.mkdtempSync`
|
403
473
|
* `Dir.pwd` becomes `process.cwd`
|
404
474
|
* `Dir.rmdir` becomes `fs.rmdirSync`
|
475
|
+
* `Dir.tmpdir` becomes `os.tmpdir()`
|
405
476
|
* `ENV` becomes `process.env`
|
406
477
|
* `__FILE__` becomes `__filename`
|
478
|
+
* `File.absolute_path` becomes `path.resolve`
|
479
|
+
* `File.absolute_path?` becomes `path.isAbsolute`
|
480
|
+
* `File.basename` becomes `path.basename`
|
407
481
|
* `File.chmod` becomes `fs.chmodSync`
|
408
482
|
* `File.chown` becomes `fs.chownSync`
|
409
483
|
* `File.cp` becomes `fs.copyFileSync`
|
484
|
+
* `File.dirname` becomes `path.dirname`
|
410
485
|
* `File.exist?` becomes `fs.existsSync`
|
486
|
+
* `File.extname` becomes `path.extname`
|
487
|
+
* `File.join` becomes `path.join`
|
411
488
|
* `File.lchmod` becomes `fs.lchmodSync`
|
412
489
|
* `File.link` becomes `fs.linkSync`
|
413
490
|
* `File.ln` becomes `fs.linkSync`
|
414
491
|
* `File.lstat` becomes `fs.lstatSync`
|
492
|
+
* `File::PATH_SEPARATOR` becomes `path.delimiter`
|
415
493
|
* `File.read` becomes `fs.readFileSync`
|
416
494
|
* `File.readlink` becomes `fs.readlinkSync`
|
417
495
|
* `File.realpath` becomes `fs.realpathSync`
|
418
496
|
* `File.rename` becomes `fs.renameSync`
|
497
|
+
* `File::SEPARATOR` becomes `path.sep`
|
419
498
|
* `File.stat` becomes `fs.statSync`
|
420
499
|
* `File.symlink` becomes `fs.symlinkSync`
|
421
500
|
* `File.truncate` becomes `fs.truncateSync`
|
@@ -609,8 +688,16 @@ Additionally, the `functions` filter will provide the following conversion:
|
|
609
688
|
* `Array(x)` becomes `Array.from(x)`
|
610
689
|
* `.inject(n) {}` becomes `.reduce(() => {}, n)`
|
611
690
|
|
612
|
-
|
613
|
-
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.
|
614
701
|
|
615
702
|
ES2016 support
|
616
703
|
---
|
@@ -619,6 +706,9 @@ When option `eslevel: 2016` is provided, the following additional
|
|
619
706
|
conversion is made:
|
620
707
|
|
621
708
|
* `a ** b` becomes `a ** b`
|
709
|
+
|
710
|
+
Additionally the following conversions is added to the `functions` filter:
|
711
|
+
|
622
712
|
* `.include?` becomes `.includes`
|
623
713
|
|
624
714
|
ES2017 support
|
@@ -629,7 +719,7 @@ conversions are made by the `functions` filter:
|
|
629
719
|
|
630
720
|
* `.values()` becomes `Object.values()`
|
631
721
|
* `.entries()` becomes `Object.entries()`
|
632
|
-
* `.each_pair {}` becomes `for (let [key, value] of Object.entries()) {}
|
722
|
+
* `.each_pair {}` becomes `for (let [key, value] of Object.entries()) {}`
|
633
723
|
|
634
724
|
async support:
|
635
725
|
|
@@ -657,8 +747,8 @@ When option `eslevel: 2019` is provided, the following additional
|
|
657
747
|
conversion is made by the `functions` filter:
|
658
748
|
|
659
749
|
* `.flatten` becomes `.flat(Infinity)`
|
660
|
-
* `.lstrip` becomes `.trimEnd
|
661
|
-
* `.rstrip` becomes `.trimStart
|
750
|
+
* `.lstrip` becomes `.trimEnd`
|
751
|
+
* `.rstrip` becomes `.trimStart`
|
662
752
|
* `a.to_h` becomes `Object.fromEntries(a)`
|
663
753
|
* `Hash[a]` becomes `Object.fromEntries(a)`
|
664
754
|
|
@@ -684,27 +774,28 @@ conversions are made:
|
|
684
774
|
|
685
775
|
* `x ||= 1` becomes `x ||= 1`
|
686
776
|
* `x &&= 1` becomes `x &&= 1`
|
777
|
+
* `1000000.000001` becomes `1_000_000.000_001`
|
687
778
|
|
688
779
|
Picking a Ruby to JS mapping tool
|
689
780
|
---
|
690
781
|
|
691
782
|
> dsl — A domain specific language, where code is written in one language and
|
692
783
|
> errors are given in another.
|
693
|
-
> -- [Devil’s Dictionary of Programming](
|
784
|
+
> -- [Devil’s Dictionary of Programming](https://programmingisterrible.com/post/65781074112/devils-dictionary-of-programming)
|
694
785
|
|
695
786
|
If you simply want to get a job done, and would like a mature and tested
|
696
787
|
framework, and only use one of the many integrations that
|
697
|
-
[Opal](
|
788
|
+
[Opal](https://opalrb.com/) provides, then Opal is the way to go right now.
|
698
789
|
|
699
790
|
ruby2js is for those that want to produce JavaScript that looks like it
|
700
791
|
wasn’t machine generated, and want the absolute bare minimum in terms of
|
701
792
|
limitations as to what JavaScript can be produced.
|
702
793
|
|
703
|
-
[Try](
|
704
|
-
[Compare](
|
794
|
+
[Try](https://intertwingly.net/projects/ruby2js) for yourself.
|
795
|
+
[Compare](https://opalrb.com/try/#code:).
|
705
796
|
|
706
797
|
And, of course, the right solution might be to use
|
707
|
-
[CoffeeScript](
|
798
|
+
[CoffeeScript](https://coffeescript.org/) instead.
|
708
799
|
|
709
800
|
License
|
710
801
|
---
|
data/lib/ruby2js.rb
CHANGED
@@ -61,13 +61,18 @@ module Ruby2JS
|
|
61
61
|
include Ruby2JS::Filter
|
62
62
|
BINARY_OPERATORS = Converter::OPERATORS[2..-1].flatten
|
63
63
|
|
64
|
-
attr_accessor :prepend_list
|
64
|
+
attr_accessor :prepend_list, :disable_autoimports
|
65
65
|
|
66
66
|
def initialize(comments)
|
67
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
|
+
|
68
74
|
@ast = nil
|
69
75
|
@exclude_methods = []
|
70
|
-
@esm = false
|
71
76
|
@prepend_list = Set.new
|
72
77
|
end
|
73
78
|
|
@@ -141,6 +146,7 @@ module Ruby2JS
|
|
141
146
|
def on_method(node); on_send(node); end
|
142
147
|
def on_prop(node); on_array(node); end
|
143
148
|
def on_prototype(node); on_begin(node); end
|
149
|
+
def on_send!(node); on_send(node); end
|
144
150
|
def on_sendw(node); on_send(node); end
|
145
151
|
def on_undefined?(node); on_defined?(node); end
|
146
152
|
def on_nil(node); end
|
@@ -188,7 +194,7 @@ module Ruby2JS
|
|
188
194
|
source = ast.loc.expression.source_buffer.source
|
189
195
|
else
|
190
196
|
ast, comments = parse( source, options[:file] )
|
191
|
-
comments = Parser::Source::Comment.associate(ast, comments)
|
197
|
+
comments = ast ? Parser::Source::Comment.associate(ast, comments) : {}
|
192
198
|
end
|
193
199
|
|
194
200
|
filters = (options[:filters] || Filter::DEFAULTS)
|
@@ -207,9 +213,10 @@ module Ruby2JS
|
|
207
213
|
filter.options = options
|
208
214
|
ast = filter.process(ast)
|
209
215
|
|
210
|
-
|
216
|
+
unless filter.prepend_list.empty?
|
211
217
|
prepend = filter.prepend_list.sort_by {|ast| ast.type == :import ? 0 : 1}
|
212
|
-
ast
|
218
|
+
prepend.reject! {|ast| ast.type == :import} if filter.disable_autoimports
|
219
|
+
ast = Parser::AST::Node.new(:begin, [*prepend, ast])
|
213
220
|
end
|
214
221
|
end
|
215
222
|
|
@@ -240,6 +247,8 @@ module Ruby2JS
|
|
240
247
|
|
241
248
|
ruby2js.timestamp options[:file]
|
242
249
|
|
250
|
+
ruby2js.file_name = options[:file] || ast&.loc&.expression&.source_buffer&.name || ''
|
251
|
+
|
243
252
|
ruby2js
|
244
253
|
end
|
245
254
|
|
data/lib/ruby2js/converter.rb
CHANGED
@@ -248,7 +248,7 @@ module Ruby2JS
|
|
248
248
|
if ast.loc and ast.loc.expression
|
249
249
|
filename = ast.loc.expression.source_buffer.name
|
250
250
|
if filename and not filename.empty?
|
251
|
-
@timestamps[filename] ||= File.mtime(filename)
|
251
|
+
@timestamps[filename] ||= File.mtime(filename) rescue nil
|
252
252
|
end
|
253
253
|
end
|
254
254
|
|
@@ -9,11 +9,22 @@ module Ruby2JS
|
|
9
9
|
# NOTE: this is the es2015 version of class
|
10
10
|
|
11
11
|
handle :class2 do |name, inheritance, *body|
|
12
|
+
body.compact!
|
13
|
+
while body.length == 1 and body.first.type == :begin
|
14
|
+
body = body.first.children
|
15
|
+
end
|
16
|
+
|
17
|
+
proxied = body.find do |node|
|
18
|
+
node.type == :def and node.children.first == :method_missing
|
19
|
+
end
|
20
|
+
|
12
21
|
if name.type == :const and name.children.first == nil
|
13
22
|
put 'class '
|
14
23
|
parse name
|
24
|
+
put '$' if proxied
|
15
25
|
else
|
16
26
|
parse name
|
27
|
+
put '$' if proxied
|
17
28
|
put ' = class'
|
18
29
|
end
|
19
30
|
|
@@ -24,11 +35,6 @@ module Ruby2JS
|
|
24
35
|
|
25
36
|
put " {"
|
26
37
|
|
27
|
-
body.compact!
|
28
|
-
while body.length == 1 and body.first.type == :begin
|
29
|
-
body = body.first.children
|
30
|
-
end
|
31
|
-
|
32
38
|
begin
|
33
39
|
class_name, @class_name = @class_name, name
|
34
40
|
class_parent, @class_parent = @class_parent, inheritance
|
@@ -64,21 +70,21 @@ module Ruby2JS
|
|
64
70
|
walk[child] if child.is_a? Parser::AST::Node
|
65
71
|
end
|
66
72
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
73
|
+
if ast.type == :send and ast.children.first == nil
|
74
|
+
if ast.children[1] == :attr_accessor
|
75
|
+
ast.children[2..-1].each_with_index do |child_sym, index2|
|
76
|
+
ivars << :"@#{child_sym.children.first}"
|
77
|
+
end
|
78
|
+
elsif ast.children[1] == :attr_reader
|
79
|
+
ast.children[2..-1].each_with_index do |child_sym, index2|
|
80
|
+
ivars << :"@#{child_sym.children.first}"
|
81
|
+
end
|
82
|
+
elsif ast.children[1] == :attr_writer
|
83
|
+
ast.children[2..-1].each_with_index do |child_sym, index2|
|
84
|
+
ivars << :"@#{child_sym.children.first}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
82
88
|
|
83
89
|
end
|
84
90
|
walk[@ast]
|
@@ -299,6 +305,43 @@ module Ruby2JS
|
|
299
305
|
end
|
300
306
|
end
|
301
307
|
|
308
|
+
if proxied
|
309
|
+
put @sep
|
310
|
+
|
311
|
+
rename = name.updated(nil, [name.children.first, name.children.last.to_s + '$'])
|
312
|
+
|
313
|
+
if proxied.children[1].children.length == 1
|
314
|
+
# special case: if method_missing only has on argument, call it
|
315
|
+
# directly (i.e., don't pass arguments). This enables
|
316
|
+
# method_missing to return instance attributes (getters) as well
|
317
|
+
# as bound functions (methods).
|
318
|
+
forward = s(:send, s(:lvar, :obj), :method_missing, s(:lvar, :prop))
|
319
|
+
else
|
320
|
+
# normal case: return a function which, when called, will call
|
321
|
+
# method_missing with method name and arguments.
|
322
|
+
forward = s(:block, s(:send, nil, :proc), s(:args, s(:restarg, :args)),
|
323
|
+
s(:send, s(:lvar, :obj), :method_missing, s(:lvar, :prop),
|
324
|
+
s(:splat, s(:lvar, :args))))
|
325
|
+
end
|
326
|
+
|
327
|
+
proxy = s(:return, s(:send, s(:const, nil, :Proxy), :new,
|
328
|
+
s(:send, rename, :new, s(:splat, s(:lvar, :args))),
|
329
|
+
s(:hash, s(:pair, s(:sym, :get), s(:block, s(:send, nil, :proc),
|
330
|
+
s(:args, s(:arg, :obj), s(:arg, :prop)),
|
331
|
+
s(:if, s(:in?, s(:lvar, :prop), s(:lvar, :obj)),
|
332
|
+
s(:return, s(:send, s(:lvar, :obj), :[], s(:lvar, :prop))),
|
333
|
+
s(:return, forward))))))
|
334
|
+
)
|
335
|
+
|
336
|
+
if name.children.first == nil
|
337
|
+
proxy = s(:def, name.children.last, s(:args, s(:restarg, :args)), proxy)
|
338
|
+
else
|
339
|
+
proxy = s(:defs, *name.children, s(:args, s(:restarg, :args)), proxy)
|
340
|
+
end
|
341
|
+
|
342
|
+
parse proxy
|
343
|
+
end
|
344
|
+
|
302
345
|
ensure
|
303
346
|
@class_name = class_name
|
304
347
|
@class_parent = class_parent
|
@@ -131,7 +131,7 @@ module Ruby2JS
|
|
131
131
|
style = :statement
|
132
132
|
end
|
133
133
|
|
134
|
-
if args.children.length == 1 and style == :expression
|
134
|
+
if args.children.length == 1 and args.children.first.type != :restarg and style == :expression
|
135
135
|
parse args; put ' => '
|
136
136
|
else
|
137
137
|
put '('; parse args; put ') => '
|
@@ -82,7 +82,7 @@ module Ruby2JS
|
|
82
82
|
elsif node.respond_to?(:type) && node.children[1] == :default
|
83
83
|
put 'default '
|
84
84
|
args[0] = node.children[2]
|
85
|
-
elsif node.respond_to?(:type) && node.type
|
85
|
+
elsif node.respond_to?(:type) && [:lvasgn, :casgn].include?(node.type)
|
86
86
|
if node.children[0] == :default
|
87
87
|
put 'default '
|
88
88
|
args[0] = node.children[1]
|
@@ -5,12 +5,24 @@ module Ruby2JS
|
|
5
5
|
# (float 1.1)
|
6
6
|
# (str "1"))
|
7
7
|
|
8
|
-
handle :
|
8
|
+
handle :str do |value|
|
9
9
|
put value.inspect
|
10
10
|
end
|
11
11
|
|
12
|
+
handle :int, :float do |value|
|
13
|
+
put number_format(value)
|
14
|
+
end
|
15
|
+
|
12
16
|
handle :octal do |value|
|
13
|
-
put '0' + value.to_s(8)
|
17
|
+
put '0' + number_format(value.to_s(8))
|
18
|
+
end
|
19
|
+
|
20
|
+
def number_format(number)
|
21
|
+
return number.to_s unless es2021
|
22
|
+
parts = number.to_s.split('.')
|
23
|
+
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1_")
|
24
|
+
parts[1].gsub!(/(\d\d\d)(?=\d)/, "\\1_") if parts[1]
|
25
|
+
parts.join('.')
|
14
26
|
end
|
15
27
|
end
|
16
28
|
end
|
@@ -9,11 +9,12 @@ module Ruby2JS
|
|
9
9
|
# (sendw nil :puts
|
10
10
|
# (int 1))
|
11
11
|
|
12
|
-
# Note: attr, sendw, and await are only generated by filters. Attr forces
|
12
|
+
# Note: attr, sendw, send!, and await are only generated by filters. Attr forces
|
13
13
|
# interpretation as an attribute vs a function call with zero parameters.
|
14
|
+
# send! forces interpretation as a method call even with zero parameters.
|
14
15
|
# Sendw forces parameters to be placed on separate lines.
|
15
16
|
|
16
|
-
handle :send, :sendw, :await, :attr, :call do |receiver, method, *args|
|
17
|
+
handle :send, :sendw, :send!, :await, :attr, :call do |receiver, method, *args|
|
17
18
|
ast = @ast
|
18
19
|
|
19
20
|
if \
|
@@ -280,7 +281,7 @@ module Ruby2JS
|
|
280
281
|
else
|
281
282
|
put 'await ' if @ast.type == :await
|
282
283
|
|
283
|
-
if not ast.is_method?
|
284
|
+
if not ast.is_method? and ast.type != :send!
|
284
285
|
if receiver
|
285
286
|
(group_receiver ? group(receiver) : parse(receiver))
|
286
287
|
put ".#{ method }"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'ruby2js'
|
2
|
+
|
3
|
+
module Ruby2JS
|
4
|
+
module Filter
|
5
|
+
module ActiveFunctions
|
6
|
+
include SEXP
|
7
|
+
|
8
|
+
def on_send(node)
|
9
|
+
target, method, *args = node.children
|
10
|
+
|
11
|
+
if es2015 and method == :blank?
|
12
|
+
create_or_update_import("blank$")
|
13
|
+
process node.updated :send, [nil, "blank$", target]
|
14
|
+
elsif es2015 and method == :present?
|
15
|
+
create_or_update_import("present$")
|
16
|
+
process node.updated :send, [nil, "present$", target]
|
17
|
+
elsif es2015 and method == :presence
|
18
|
+
create_or_update_import("presence$")
|
19
|
+
process node.updated :send, [nil, "presence$", target]
|
20
|
+
else
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def create_or_update_import(token)
|
28
|
+
af_import = @options[:import_from_skypack] ? "https://cdn.skypack.dev/@ruby2js/active-functions" : "@ruby2js/active-functions"
|
29
|
+
|
30
|
+
if found_node = prepend_list.find {|ast| ast.type == :import && ast.children.first == af_import}
|
31
|
+
unless found_node.children.find {|child| child == token}
|
32
|
+
prepend_list.delete found_node
|
33
|
+
prepend_list << s(:import, found_node.children.first, found_node.children.last.push(s(:const, nil, token)))
|
34
|
+
end
|
35
|
+
else
|
36
|
+
prepend_list << s(:import, af_import, [s(:const, nil, token)])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
DEFAULTS.push ActiveFunctions
|
42
|
+
end
|
43
|
+
end
|
@@ -9,8 +9,9 @@ module Ruby2JS
|
|
9
9
|
module CamelCase
|
10
10
|
include SEXP
|
11
11
|
|
12
|
-
|
12
|
+
ALLOWLIST = %w{
|
13
13
|
attr_accessor
|
14
|
+
method_missing
|
14
15
|
}
|
15
16
|
|
16
17
|
CAPS_EXCEPTIONS = {
|
@@ -37,7 +38,7 @@ module Ruby2JS
|
|
37
38
|
node = super
|
38
39
|
return node unless [:send, :csend, :attr].include? node.type
|
39
40
|
|
40
|
-
if node.children[0] == nil and
|
41
|
+
if node.children[0] == nil and ALLOWLIST.include? node.children[1].to_s
|
41
42
|
node
|
42
43
|
elsif node.children[0] && [:ivar, :cvar].include?(node.children[0].type)
|
43
44
|
S(node.type, s(node.children[0].type, camelCase(node.children[0].children[0])),
|
@@ -61,7 +62,7 @@ module Ruby2JS
|
|
61
62
|
def handle_generic_node(node, node_type)
|
62
63
|
return node if node.type != node_type
|
63
64
|
|
64
|
-
if node.children[0] =~ /_.*\w$/
|
65
|
+
if node.children[0] =~ /_.*\w$/ and !ALLOWLIST.include?(node.children[0].to_s)
|
65
66
|
S(node_type , camelCase(node.children[0]), *node.children[1..-1])
|
66
67
|
else
|
67
68
|
node
|
data/lib/ruby2js/filter/esm.rb
CHANGED
@@ -7,30 +7,62 @@ module Ruby2JS
|
|
7
7
|
module ESM
|
8
8
|
include SEXP
|
9
9
|
|
10
|
-
def initialize(*args)
|
11
|
-
super
|
12
|
-
@esm = true # signal for other filters
|
13
|
-
@esm_imports = nil
|
14
|
-
end
|
15
|
-
|
16
10
|
def options=(options)
|
17
11
|
super
|
12
|
+
@esm_autoexports = options[:autoexports] && !@disable_autoexports
|
18
13
|
@esm_autoimports = options[:autoimports]
|
19
|
-
|
14
|
+
@esm_explicit_tokens = Set.new
|
20
15
|
end
|
21
16
|
|
22
17
|
def process(node)
|
23
|
-
return super
|
24
|
-
@
|
25
|
-
result = super
|
18
|
+
return super unless @esm_autoexports
|
19
|
+
@esm_autoexports = false
|
26
20
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
21
|
+
list = [node]
|
22
|
+
while list.length == 1 and list.first.type == :begin
|
23
|
+
list = list.first.children.dup
|
24
|
+
end
|
25
|
+
|
26
|
+
list.map! do |child|
|
27
|
+
replacement = child
|
28
|
+
|
29
|
+
if [:module, :class].include? child.type and
|
30
|
+
child.children.first.type == :const and
|
31
|
+
child.children.first.children.first == nil \
|
32
|
+
then
|
33
|
+
replacement = s(:export, child)
|
34
|
+
elsif child.type == :casgn and child.children.first == nil
|
35
|
+
replacement = s(:export, child)
|
36
|
+
elsif child.type == :def
|
37
|
+
replacement = s(:export, child)
|
38
|
+
end
|
39
|
+
|
40
|
+
if replacement != child and @comments[child]
|
41
|
+
@comments[replacement] = @comments[child]
|
42
|
+
end
|
43
|
+
|
44
|
+
replacement
|
33
45
|
end
|
46
|
+
|
47
|
+
process s(:begin, *list)
|
48
|
+
end
|
49
|
+
|
50
|
+
def on_class(node)
|
51
|
+
@esm_explicit_tokens << node.children.first.children.last
|
52
|
+
|
53
|
+
super
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_def(node)
|
57
|
+
@esm_explicit_tokens << node.children.first
|
58
|
+
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
62
|
+
def on_lvasgn(node)
|
63
|
+
@esm_explicit_tokens << node.children.first
|
64
|
+
|
65
|
+
super
|
34
66
|
end
|
35
67
|
|
36
68
|
def on_send(node)
|
@@ -59,6 +91,8 @@ module Ruby2JS
|
|
59
91
|
args[0].children[2].children[2].type == :str
|
60
92
|
# import name from "file.js"
|
61
93
|
# => import name from "file.js"
|
94
|
+
@esm_explicit_tokens << args[0].children[1]
|
95
|
+
|
62
96
|
s(:import,
|
63
97
|
[args[0].children[2].children[2].children[0]],
|
64
98
|
process(s(:attr, nil, args[0].children[1])))
|
@@ -72,15 +106,20 @@ module Ruby2JS
|
|
72
106
|
# => import Stuff as * from "file.js"
|
73
107
|
# import [ Some, Stuff ], from: "file.js"
|
74
108
|
# => import { Some, Stuff } from "file.js"
|
75
|
-
imports =
|
76
|
-
|
109
|
+
imports = if args[0].type == :const || args[0].type == :send
|
110
|
+
@esm_explicit_tokens << args[0].children.last
|
111
|
+
process(args[0])
|
112
|
+
else
|
113
|
+
args[0].children.each {|i| @esm_explicit_tokens << i.children.last}
|
77
114
|
process_all(args[0].children)
|
115
|
+
end
|
116
|
+
|
78
117
|
s(:import, args[1].children, imports) unless args[1].nil?
|
79
118
|
end
|
80
119
|
elsif method == :export
|
81
120
|
s(:export, *process_all(args))
|
82
|
-
elsif
|
83
|
-
|
121
|
+
elsif target.nil? and found_import = find_autoimport(method)
|
122
|
+
prepend_list << s(:import, found_import[0], found_import[1])
|
84
123
|
super
|
85
124
|
else
|
86
125
|
super
|
@@ -88,12 +127,31 @@ module Ruby2JS
|
|
88
127
|
end
|
89
128
|
|
90
129
|
def on_const(node)
|
91
|
-
|
92
|
-
|
93
|
-
@esm_imports.add(node.children.last)
|
130
|
+
if node.children.first == nil and found_import = find_autoimport(node.children.last)
|
131
|
+
prepend_list << s(:import, found_import[0], found_import[1])
|
94
132
|
end
|
133
|
+
|
95
134
|
super
|
96
135
|
end
|
136
|
+
|
137
|
+
def on_export(node)
|
138
|
+
s(:export, *process_all(node.children))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def find_autoimport(token)
|
145
|
+
return nil if @esm_autoimports.nil?
|
146
|
+
return nil if @esm_explicit_tokens.include?(token)
|
147
|
+
|
148
|
+
token = camelCase(token) if respond_to?(:camelCase)
|
149
|
+
|
150
|
+
if @esm_autoimports[token]
|
151
|
+
[@esm_autoimports[token], s(:const, nil, token)]
|
152
|
+
elsif found_key = @esm_autoimports.keys.find {|key| key.is_a?(Array) && key.include?(token)}
|
153
|
+
[@esm_autoimports[found_key], found_key.map {|key| s(:const, nil, key)}]
|
154
|
+
end
|
97
155
|
end
|
98
156
|
|
99
157
|
DEFAULTS.push ESM
|
@@ -540,6 +540,11 @@ module Ruby2JS
|
|
540
540
|
elsif method == :floor and args.length == 0
|
541
541
|
process S(:send, s(:const, nil, :Math), :floor, target)
|
542
542
|
|
543
|
+
elsif method == :sum and args.length == 0
|
544
|
+
process S(:send, target, :reduce, s(:block, s(:send, nil, :proc),
|
545
|
+
s(:args, s(:arg, :a), s(:arg, :b)),
|
546
|
+
s(:send, s(:lvar, :a), :+, s(:lvar, :b))), s(:int, 0))
|
547
|
+
|
543
548
|
else
|
544
549
|
super
|
545
550
|
end
|
data/lib/ruby2js/filter/node.rb
CHANGED
@@ -14,6 +14,10 @@ module Ruby2JS
|
|
14
14
|
|
15
15
|
IMPORT_FS = s(:import, ['fs'], s(:attr, nil, :fs))
|
16
16
|
|
17
|
+
IMPORT_OS = s(:import, ['os'], s(:attr, nil, :os))
|
18
|
+
|
19
|
+
IMPORT_PATH = s(:import, ['path'], s(:attr, nil, :path))
|
20
|
+
|
17
21
|
SETUP_ARGV = s(:lvasgn, :ARGV, s(:send, s(:attr,
|
18
22
|
s(:attr, nil, :process), :argv), :slice, s(:int, 2)))
|
19
23
|
|
@@ -31,11 +35,11 @@ module Ruby2JS
|
|
31
35
|
prepend_list << IMPORT_CHILD_PROCESS
|
32
36
|
|
33
37
|
if args.length == 1
|
34
|
-
|
38
|
+
S(:send, s(:attr, nil, :child_process), :execSync,
|
35
39
|
process(args.first),
|
36
40
|
s(:hash, s(:pair, s(:sym, :stdio), s(:str, 'inherit'))))
|
37
41
|
else
|
38
|
-
|
42
|
+
S(:send, s(:attr, nil, :child_process), :execFileSync,
|
39
43
|
process(args.first), s(:array, *process_all(args[1..-1])),
|
40
44
|
s(:hash, s(:pair, s(:sym, :stdio), s(:str, 'inherit'))))
|
41
45
|
end
|
@@ -57,7 +61,7 @@ module Ruby2JS
|
|
57
61
|
then
|
58
62
|
if method == :read and args.length == 1
|
59
63
|
prepend_list << IMPORT_FS
|
60
|
-
|
64
|
+
S(:send, s(:attr, nil, :fs), :readFileSync, *process_all(args),
|
61
65
|
s(:str, 'utf8'))
|
62
66
|
|
63
67
|
elsif method == :write and args.length == 2
|
@@ -111,15 +115,15 @@ module Ruby2JS
|
|
111
115
|
|
112
116
|
elsif method == :symlink and args.length == 2
|
113
117
|
prepend_list << IMPORT_FS
|
114
|
-
|
118
|
+
S(:send, s(:attr, nil, :fs), :symlinkSync, *process_all(args))
|
115
119
|
|
116
120
|
elsif method == :truncate and args.length == 2
|
117
121
|
prepend_list << IMPORT_FS
|
118
|
-
|
122
|
+
S(:send, s(:attr, nil, :fs), :truncateSync, *process_all(args))
|
119
123
|
|
120
124
|
elsif [:stat, :lstat].include? method and args.length == 1
|
121
125
|
prepend_list << IMPORT_FS
|
122
|
-
|
126
|
+
S(:send, s(:attr, nil, :fs), method.to_s + 'Sync',
|
123
127
|
process(args.first))
|
124
128
|
|
125
129
|
elsif method == :unlink and args.length == 1
|
@@ -128,6 +132,29 @@ module Ruby2JS
|
|
128
132
|
S(:send, s(:attr, nil, :fs), :unlinkSync, process(file))
|
129
133
|
})
|
130
134
|
|
135
|
+
elsif target.children.last == :File
|
136
|
+
if method == :absolute_path
|
137
|
+
prepend_list << IMPORT_PATH
|
138
|
+
S(:send, s(:attr, nil, :path), :resolve,
|
139
|
+
*process_all(args.reverse))
|
140
|
+
elsif method == :absolute_path?
|
141
|
+
prepend_list << IMPORT_PATH
|
142
|
+
S(:send, s(:attr, nil, :path), :isAbsolute, *process_all(args))
|
143
|
+
elsif method == :basename
|
144
|
+
prepend_list << IMPORT_PATH
|
145
|
+
S(:send, s(:attr, nil, :path), :basename, *process_all(args))
|
146
|
+
elsif method == :dirname
|
147
|
+
prepend_list << IMPORT_PATH
|
148
|
+
S(:send, s(:attr, nil, :path), :dirname, *process_all(args))
|
149
|
+
elsif method == :extname
|
150
|
+
prepend_list << IMPORT_PATH
|
151
|
+
S(:send, s(:attr, nil, :path), :extname, *process_all(args))
|
152
|
+
elsif method == :join
|
153
|
+
prepend_list << IMPORT_PATH
|
154
|
+
S(:send, s(:attr, nil, :path), :join, *process_all(args))
|
155
|
+
else
|
156
|
+
super
|
157
|
+
end
|
131
158
|
else
|
132
159
|
super
|
133
160
|
end
|
@@ -163,7 +190,7 @@ module Ruby2JS
|
|
163
190
|
S(:send, s(:attr, nil, :process), :chdir, *process_all(args))
|
164
191
|
|
165
192
|
elsif method == :pwd and args.length == 0
|
166
|
-
|
193
|
+
S(:send!, s(:attr, nil, :process), :cwd)
|
167
194
|
|
168
195
|
elsif method == :rmdir and args.length == 1
|
169
196
|
prepend_list << IMPORT_FS
|
@@ -173,11 +200,11 @@ module Ruby2JS
|
|
173
200
|
|
174
201
|
elsif method == :ln and args.length == 2
|
175
202
|
prepend_list << IMPORT_FS
|
176
|
-
|
203
|
+
S(:send, s(:attr, nil, :fs), :linkSync, *process_all(args))
|
177
204
|
|
178
205
|
elsif method == :ln_s and args.length == 2
|
179
206
|
prepend_list << IMPORT_FS
|
180
|
-
|
207
|
+
S(:send, s(:attr, nil, :fs), :symlinkSync, *process_all(args))
|
181
208
|
|
182
209
|
elsif method == :rm and args.length == 1
|
183
210
|
prepend_list << IMPORT_FS
|
@@ -224,16 +251,16 @@ module Ruby2JS
|
|
224
251
|
if method == :chdir and args.length == 1
|
225
252
|
S(:send, s(:attr, nil, :process), :chdir, *process_all(args))
|
226
253
|
elsif method == :pwd and args.length == 0
|
227
|
-
|
254
|
+
S(:send!, s(:attr, nil, :process), :cwd)
|
228
255
|
elsif method == :entries
|
229
256
|
prepend_list << IMPORT_FS
|
230
|
-
|
257
|
+
S(:send, s(:attr, nil, :fs), :readdirSync, *process_all(args))
|
231
258
|
elsif method == :mkdir and args.length == 1
|
232
259
|
prepend_list << IMPORT_FS
|
233
|
-
|
260
|
+
S(:send, s(:attr, nil, :fs), :mkdirSync, process(args.first))
|
234
261
|
elsif method == :rmdir and args.length == 1
|
235
262
|
prepend_list << IMPORT_FS
|
236
|
-
|
263
|
+
S(:send, s(:attr, nil, :fs), :rmdirSync, process(args.first))
|
237
264
|
elsif method == :mktmpdir and args.length <=1
|
238
265
|
prepend_list << IMPORT_FS
|
239
266
|
if args.length == 0
|
@@ -244,7 +271,14 @@ module Ruby2JS
|
|
244
271
|
prefix = args.first
|
245
272
|
end
|
246
273
|
|
247
|
-
|
274
|
+
S(:send, s(:attr, nil, :fs), :mkdtempSync, process(prefix))
|
275
|
+
elsif method == :home and args.length == 0
|
276
|
+
prepend_list << IMPORT_OS
|
277
|
+
S(:send!, s(:attr, nil, :os), :homedir)
|
278
|
+
elsif method == :tmpdir and args.length == 0
|
279
|
+
prepend_list << IMPORT_OS
|
280
|
+
S(:send!, s(:attr, nil, :os), :tmpdir)
|
281
|
+
|
248
282
|
else
|
249
283
|
super
|
250
284
|
end
|
@@ -285,6 +319,16 @@ module Ruby2JS
|
|
285
319
|
S(:attr, s(:attr, nil, :process), :stdout)
|
286
320
|
elsif node.children == [nil, :STDERR]
|
287
321
|
S(:attr, s(:attr, nil, :process), :stderr)
|
322
|
+
elsif node.children.first == s(:const, nil, :File)
|
323
|
+
if node.children.last == :SEPARATOR
|
324
|
+
prepend_list << IMPORT_PATH
|
325
|
+
S(:attr, s(:attr, nil, :path), :sep)
|
326
|
+
elsif node.children.last == :PATH_SEPARATOR
|
327
|
+
prepend_list << IMPORT_PATH
|
328
|
+
S(:attr, s(:attr, nil, :path), :delimiter)
|
329
|
+
else
|
330
|
+
super
|
331
|
+
end
|
288
332
|
else
|
289
333
|
super
|
290
334
|
end
|
data/lib/ruby2js/serializer.rb
CHANGED
@@ -42,6 +42,7 @@ module Ruby2JS
|
|
42
42
|
|
43
43
|
class Serializer
|
44
44
|
attr_reader :timestamps
|
45
|
+
attr_accessor :file_name
|
45
46
|
|
46
47
|
def initialize
|
47
48
|
@sep = '; '
|
@@ -56,6 +57,7 @@ module Ruby2JS
|
|
56
57
|
@timestamps = {}
|
57
58
|
|
58
59
|
@ast = nil
|
60
|
+
@file_name = ''
|
59
61
|
end
|
60
62
|
|
61
63
|
def timestamp(file)
|
@@ -363,7 +365,7 @@ module Ruby2JS
|
|
363
365
|
|
364
366
|
@sourcemap = {
|
365
367
|
version: 3,
|
366
|
-
file: @
|
368
|
+
file: @file_name,
|
367
369
|
sources: sources.map(&:name),
|
368
370
|
mappings: @mappings
|
369
371
|
}
|
data/lib/ruby2js/version.rb
CHANGED
data/ruby2js.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
11
11
|
s.require_paths = ["lib".freeze]
|
12
|
-
s.authors = ["Sam Ruby".freeze]
|
12
|
+
s.authors = ["Sam Ruby".freeze, "Jared White".freeze]
|
13
13
|
s.description = " The base package maps Ruby syntax to JavaScript semantics.\n Filters may be provided to add Ruby-specific or framework specific\n behavior.\n".freeze
|
14
14
|
s.email = "rubys@intertwingly.net".freeze
|
15
15
|
s.files = %w(ruby2js.gemspec README.md) + Dir.glob("{lib}/**/*")
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby2js
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Ruby
|
8
|
-
|
8
|
+
- Jared White
|
9
|
+
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2020-
|
12
|
+
date: 2020-12-26 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: parser
|
@@ -121,10 +122,10 @@ files:
|
|
121
122
|
- lib/ruby2js/es2021/strict.rb
|
122
123
|
- lib/ruby2js/execjs.rb
|
123
124
|
- lib/ruby2js/filter.rb
|
125
|
+
- lib/ruby2js/filter/active_functions.rb
|
124
126
|
- lib/ruby2js/filter/camelCase.rb
|
125
127
|
- lib/ruby2js/filter/cjs.rb
|
126
128
|
- lib/ruby2js/filter/esm.rb
|
127
|
-
- lib/ruby2js/filter/esm_migration.rb
|
128
129
|
- lib/ruby2js/filter/functions.rb
|
129
130
|
- lib/ruby2js/filter/jquery.rb
|
130
131
|
- lib/ruby2js/filter/matchAll.rb
|
@@ -150,7 +151,7 @@ homepage: http://github.com/rubys/ruby2js
|
|
150
151
|
licenses:
|
151
152
|
- MIT
|
152
153
|
metadata: {}
|
153
|
-
post_install_message:
|
154
|
+
post_install_message:
|
154
155
|
rdoc_options: []
|
155
156
|
require_paths:
|
156
157
|
- lib
|
@@ -165,8 +166,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
166
|
- !ruby/object:Gem::Version
|
166
167
|
version: '0'
|
167
168
|
requirements: []
|
168
|
-
rubygems_version: 3.
|
169
|
-
signing_key:
|
169
|
+
rubygems_version: 3.1.4
|
170
|
+
signing_key:
|
170
171
|
specification_version: 4
|
171
172
|
summary: Minimal yet extensible Ruby to JavaScript conversion.
|
172
173
|
test_files: []
|
@@ -1,72 +0,0 @@
|
|
1
|
-
require 'ruby2js'
|
2
|
-
|
3
|
-
module Ruby2JS
|
4
|
-
module Filter
|
5
|
-
module ESMMigration
|
6
|
-
include SEXP
|
7
|
-
|
8
|
-
def initialize(*args)
|
9
|
-
@esm_include = nil
|
10
|
-
super
|
11
|
-
end
|
12
|
-
|
13
|
-
def process(node)
|
14
|
-
return super if @esm_include
|
15
|
-
@esm_include = Set.new
|
16
|
-
@esm_exclude = Set.new
|
17
|
-
@esm_export = nil
|
18
|
-
result = super
|
19
|
-
|
20
|
-
esm_walk(result)
|
21
|
-
|
22
|
-
inventory = (@esm_include - @esm_exclude).to_a.sort
|
23
|
-
|
24
|
-
if inventory.empty? and not @esm_export
|
25
|
-
result
|
26
|
-
else
|
27
|
-
list = inventory.map do |name|
|
28
|
-
if name == "React" and defined? Ruby2JS::Filter::React
|
29
|
-
s(:import, "#{name.downcase}", s(:const, nil, name))
|
30
|
-
elsif not %w(JSON Object).include? name
|
31
|
-
s(:import, "./#{name.downcase}.js", s(:const, nil, name))
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
list.push result
|
36
|
-
|
37
|
-
if @esm_export
|
38
|
-
list.push s(:export, :default, s(:const, nil, @esm_export))
|
39
|
-
end
|
40
|
-
|
41
|
-
s(:begin, *list.compact)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# gather constants
|
46
|
-
def esm_walk(node)
|
47
|
-
# extract ivars and cvars
|
48
|
-
if node.type == :const and node.children.first == nil
|
49
|
-
@esm_include << node.children.last.to_s
|
50
|
-
elsif node.type == :xnode
|
51
|
-
name = node.children.first
|
52
|
-
@esm_include << name unless name.empty? or name =~ /^[a-z]/
|
53
|
-
elsif node.type == :casgn and node.children.first == nil
|
54
|
-
@esm_exclude << node.children[1].to_s
|
55
|
-
elsif node.type == :class and node.children.first.type == :const
|
56
|
-
if node.children.first.children.first == nil
|
57
|
-
name = node.children.first.children.last.to_s
|
58
|
-
@esm_exclude << name
|
59
|
-
@esm_export ||= name
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# recurse
|
64
|
-
node.children.each do |child|
|
65
|
-
esm_walk(child) if Parser::AST::Node === child
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
DEFAULTS.push ESMMigration
|
71
|
-
end
|
72
|
-
end
|