ruby2js 3.5.3 → 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 +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
|