ruby2js 4.0.0 → 4.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -1
  3. data/lib/ruby2js.rb +16 -3
  4. data/lib/ruby2js/converter.rb +31 -0
  5. data/lib/ruby2js/converter/args.rb +6 -1
  6. data/lib/ruby2js/converter/class.rb +3 -0
  7. data/lib/ruby2js/converter/class2.rb +8 -5
  8. data/lib/ruby2js/converter/def.rb +8 -2
  9. data/lib/ruby2js/converter/dstr.rb +3 -1
  10. data/lib/ruby2js/converter/for.rb +1 -1
  11. data/lib/ruby2js/converter/hash.rb +19 -1
  12. data/lib/ruby2js/converter/logical.rb +1 -1
  13. data/lib/ruby2js/converter/next.rb +10 -2
  14. data/lib/ruby2js/converter/redo.rb +14 -0
  15. data/lib/ruby2js/converter/return.rb +2 -1
  16. data/lib/ruby2js/converter/send.rb +30 -4
  17. data/lib/ruby2js/converter/taglit.rb +9 -2
  18. data/lib/ruby2js/converter/while.rb +1 -1
  19. data/lib/ruby2js/converter/whilepost.rb +1 -1
  20. data/lib/ruby2js/converter/xstr.rb +1 -2
  21. data/lib/ruby2js/filter/camelCase.rb +2 -0
  22. data/lib/ruby2js/filter/functions.rb +39 -11
  23. data/lib/ruby2js/filter/lit-element.rb +202 -0
  24. data/lib/ruby2js/filter/react.rb +6 -16
  25. data/lib/ruby2js/filter/require.rb +2 -6
  26. data/lib/ruby2js/filter/stimulus.rb +4 -2
  27. data/lib/ruby2js/filter/tagged_templates.rb +4 -2
  28. data/lib/ruby2js/jsx.rb +19 -1
  29. data/lib/ruby2js/rails.rb +6 -59
  30. data/lib/ruby2js/serializer.rb +16 -11
  31. data/lib/ruby2js/sprockets.rb +40 -0
  32. data/lib/ruby2js/version.rb +1 -1
  33. data/lib/tasks/README.md +4 -0
  34. data/lib/tasks/install/app/javascript/elements/index.js +2 -0
  35. data/lib/tasks/install/litelement.rb +9 -0
  36. data/lib/tasks/install/react.rb +2 -0
  37. data/lib/tasks/install/stimulus-sprockets.rb +32 -0
  38. data/lib/tasks/install/stimulus-webpacker.rb +5 -0
  39. data/lib/tasks/install/webpacker.rb +97 -0
  40. data/lib/tasks/nodetest.js +47 -0
  41. data/lib/tasks/ruby2js_tasks.rake +42 -0
  42. data/ruby2js.gemspec +1 -1
  43. metadata +18 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 064d9dc5d65f6e2456e91d951e2f4311b776221422a77d59a8cfd466ceb5056d
4
- data.tar.gz: ffc274a55ceb9a1280f776c00da8c296dc10672150174135931547cd056a3520
3
+ metadata.gz: 6728e4201e77b477a9203551b57de3f23b36077f6012061233d4b072d92886b9
4
+ data.tar.gz: 7d5e6ef7aa5b9add1477b3cc642cc55714a657f7f962dbb6dd7af6688d45cfb0
5
5
  SHA512:
6
- metadata.gz: 8fe9775803716fce25697adaf59a8afb57f4de499052a66847f18dfdd59c1f73b52d77be473adf762a57693a0896a6c90ed275a2b9152b5b6b548ca454e6d9ae
7
- data.tar.gz: aa901eab47bba051a69a0ee132b69e7754aa5da49ff2e7e22560303a4c0fd02cdb727d4297c13098f3a6f82cf20788f4657c7ec21d145e66533875933d1a5154
6
+ metadata.gz: 321dc88308946ff626914ceb87fa93f93bec4f5cde0b660cab75d7df46b52f9ca63da830e7fab4f070b989586ef468b3cdf9d8f682f64b44ee06fef9df5230f7
7
+ data.tar.gz: 22f5161f0bc03c294fbfd3f32be407030fea293985e1eff4c7d0fc464bd57aaa6a3cfc70e1bf9ed13e9bbb0dbbac9f394b860e76df52ae236b494accd86c840b
data/README.md CHANGED
@@ -3,7 +3,6 @@ Ruby2JS
3
3
 
4
4
  Minimal yet extensible Ruby to JavaScript conversion.
5
5
 
6
- [![Build Status](https://travis-ci.org/rubys/ruby2js.svg)](https://travis-ci.org/rubys/ruby2js)
7
6
  [![Gem Version](https://badge.fury.io/rb/ruby2js.svg)](https://badge.fury.io/rb/ruby2js)
8
7
  [![Gitter](https://badges.gitter.im/ruby2js/community.svg)](https://gitter.im/ruby2js/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
9
8
 
data/lib/ruby2js.rb CHANGED
@@ -92,6 +92,17 @@ module Ruby2JS
92
92
  include_only(options[:include_only]) if options[:include_only]
93
93
  include(options[:include]) if options[:include]
94
94
  exclude(options[:exclude]) if options[:exclude]
95
+
96
+ filters = options[:filters] || DEFAULTS
97
+ @modules_enabled =
98
+ (defined? Ruby2JS::Filter::ESM and
99
+ filters.include? Ruby2JS::Filter::ESM) or
100
+ (defined? Ruby2JS::Filter::CJS and
101
+ filters.include? Ruby2JS::Filter::CJS)
102
+ end
103
+
104
+ def modules_enabled?
105
+ @modules_enabled
95
106
  end
96
107
 
97
108
  def es2015
@@ -169,7 +180,7 @@ module Ruby2JS
169
180
  def on_xnode(node); end
170
181
  def on_export(node); end
171
182
  def on_import(node); end
172
- def on_taglit(node); end
183
+ def on_taglit(node); on_pair(node); end
173
184
 
174
185
  # provide a method so filters can call 'super'
175
186
  def on_sym(node); node; end
@@ -182,10 +193,12 @@ module Ruby2JS
182
193
  return on_block s(:block, s(:send, *node.children[0..-2]),
183
194
  s(:args, s(:arg, :a), s(:arg, :b)), s(:return,
184
195
  process(s(:send, s(:lvar, :a), method, s(:lvar, :b)))))
185
- else
196
+ elsif node.children.last.children.first.type == :sym
186
197
  return on_block s(:block, s(:send, *node.children[0..-2]),
187
198
  s(:args, s(:arg, :item)), s(:return,
188
199
  process(s(:attr, s(:lvar, :item), method))))
200
+ else
201
+ super
189
202
  end
190
203
  end
191
204
  super
@@ -277,7 +290,7 @@ module Ruby2JS
277
290
 
278
291
  def self.parse(source, file=nil, line=1)
279
292
  buffer = Parser::Source::Buffer.new(file, line)
280
- buffer.source = source.encode('utf-8')
293
+ buffer.source = source.encode('UTF-8')
281
294
  parser = Parser::CurrentRuby.new
282
295
  parser.diagnostics.all_errors_are_fatal = true
283
296
  parser.diagnostics.consumer = lambda {|diagnostic| nil}
@@ -60,12 +60,14 @@ module Ruby2JS
60
60
  @class_parent = nil
61
61
  @class_name = nil
62
62
  @jsx = false
63
+ @autobind = true
63
64
 
64
65
  @eslevel = :es5
65
66
  @strict = false
66
67
  @comparison = :equality
67
68
  @or = :logical
68
69
  @underscored_private = true
70
+ @redoable = false
69
71
  end
70
72
 
71
73
  def width=(width)
@@ -243,6 +245,34 @@ module Ruby2JS
243
245
  end
244
246
  end
245
247
 
248
+ def redoable(block)
249
+ save_redoable = @redoable
250
+
251
+ has_redo = proc do |node|
252
+ node.children.any? do |child|
253
+ next false unless child.is_a? Parser::AST::Node
254
+ next true if child.type == :redo
255
+ next false if %i[for while while_post until until_post].include? child.type
256
+ has_redo[child]
257
+ end
258
+ end
259
+
260
+ @redoable = has_redo[@ast]
261
+
262
+ if @redoable
263
+ put es2015 ? 'let ' : 'var '
264
+ put "redo$#@sep"
265
+ puts 'do {'
266
+ put "redo$ = false#@sep"
267
+ scope block
268
+ put "#@nl} while(redo$)"
269
+ else
270
+ scope block
271
+ end
272
+ ensure
273
+ @redoable = save_redoable
274
+ end
275
+
246
276
  def timestamp(file)
247
277
  super
248
278
 
@@ -335,6 +365,7 @@ require 'ruby2js/converter/nil'
335
365
  require 'ruby2js/converter/nthref'
336
366
  require 'ruby2js/converter/opasgn'
337
367
  require 'ruby2js/converter/prototype'
368
+ require 'ruby2js/converter/redo'
338
369
  require 'ruby2js/converter/regexp'
339
370
  require 'ruby2js/converter/return'
340
371
  require 'ruby2js/converter/self'
@@ -30,13 +30,18 @@ module Ruby2JS
30
30
  if kw.type == :kwarg
31
31
  put kw.children.first
32
32
  elsif kw.type == :kwoptarg
33
- put kw.children.first; put ' = '; parse kw.children.last
33
+ put kw.children.first
34
+ unless kw.children.last == s(:send, nil, :undefined)
35
+ put '='; parse kw.children.last
36
+ end
34
37
  elsif kw.type == :kwrestarg
35
38
  raise 'Rest arg requires ES2018' unless es2018
36
39
  put '...'; put kw.children.first
37
40
  end
38
41
  end
39
42
  put ' }'
43
+
44
+ put ' = {}' unless kwargs.any? {|kw| kw.type == :kwarg}
40
45
  end
41
46
  end
42
47
 
@@ -114,6 +114,7 @@ module Ruby2JS
114
114
  if m.children[1] == :attr_accessor
115
115
  m.children[2..-1].map do |child_sym|
116
116
  var = child_sym.children.first
117
+ visible[var] = s(:self)
117
118
  s(:prop, s(:attr, name, :prototype), var =>
118
119
  {enumerable: s(:true), configurable: s(:true),
119
120
  get: s(:block, s(:send, nil, :proc), s(:args),
@@ -124,6 +125,7 @@ module Ruby2JS
124
125
  elsif m.children[1] == :attr_reader
125
126
  m.children[2..-1].map do |child_sym|
126
127
  var = child_sym.children.first
128
+ visible[var] = s(:self)
127
129
  s(:prop, s(:attr, name, :prototype), var =>
128
130
  {get: s(:block, s(:send, nil, :proc), s(:args),
129
131
  s(:return, s(:ivar, :"@#{var}"))),
@@ -133,6 +135,7 @@ module Ruby2JS
133
135
  elsif m.children[1] == :attr_writer
134
136
  m.children[2..-1].map do |child_sym|
135
137
  var = child_sym.children.first
138
+ visible[var] = s(:self)
136
139
  s(:prop, s(:attr, name, :prototype), var =>
137
140
  {set: s(:block, s(:send, nil, :proc), s(:args, s(:arg, var)),
138
141
  s(:ivasgn, :"@#{var}", s(:lvar, var))),
@@ -156,7 +156,7 @@ module Ruby2JS
156
156
  end
157
157
  end
158
158
 
159
- if m.type == :def || m.type == :defm || m.type == :async
159
+ if %i[def defm deff async].include? m.type
160
160
  @prop = m.children.first
161
161
 
162
162
  if @prop == :initialize and !@rbstack.last[:initialize]
@@ -190,11 +190,11 @@ module Ruby2JS
190
190
  end
191
191
 
192
192
  elsif \
193
- [:defs, :asyncs].include? m.type and m.children.first.type == :self
193
+ [:defs, :defp, :asyncs].include? m.type and m.children.first.type == :self
194
194
  then
195
195
 
196
196
  @prop = "static #{m.children[1]}"
197
- if not m.is_method?
197
+ if m.type == :defp or not m.is_method?
198
198
  @prop = "static get #{m.children[1]}"
199
199
  m = m.updated(m.type, [*m.children[0..2],
200
200
  s(:autoreturn, m.children[3])])
@@ -206,7 +206,7 @@ module Ruby2JS
206
206
  @prop = "static #{m.children[1]}"
207
207
  end
208
208
 
209
- @prop.sub! 'static', 'static async' if m.type == :asyncs
209
+ @prop = @prop.sub('static', 'static async') if m.type == :asyncs
210
210
 
211
211
  m = m.updated(:def, m.children[1..3])
212
212
  begin
@@ -224,6 +224,7 @@ module Ruby2JS
224
224
  m.children[2..-1].each_with_index do |child_sym, index2|
225
225
  put @sep unless index2 == 0
226
226
  var = child_sym.children.first
227
+ @rbstack.last[var] = s(:self)
227
228
  put "get #{var}() {#{@nl}return this.#{p}#{var}#@nl}#@sep"
228
229
  put "set #{var}(#{var}) {#{@nl}this.#{p}#{var} = #{var}#@nl}"
229
230
  end
@@ -231,12 +232,14 @@ module Ruby2JS
231
232
  m.children[2..-1].each_with_index do |child_sym, index2|
232
233
  put @sep unless index2 == 0
233
234
  var = child_sym.children.first
235
+ @rbstack.last[var] = s(:self)
234
236
  put "get #{var}() {#{@nl}return this.#{p}#{var}#@nl}"
235
237
  end
236
238
  elsif m.children[1] == :attr_writer
237
239
  m.children[2..-1].each_with_index do |child_sym, index2|
238
240
  put @sep unless index2 == 0
239
241
  var = child_sym.children.first
242
+ @rbstack.last[var] = s(:self)
240
243
  put "set #{var}(#{var}) {#{@nl}this.#{p}#{var} = #{var}#@nl}"
241
244
  end
242
245
  elsif [:private, :protected, :public].include? m.children[1]
@@ -276,7 +279,7 @@ module Ruby2JS
276
279
  if m.type == :casgn and m.children[0] == nil
277
280
  @rbstack.last[m.children[1]] = name
278
281
 
279
- if es2020
282
+ if es2022
280
283
  put 'static '; put m.children[1].to_s; put ' = '
281
284
  parse m.children[2]
282
285
  skipped = false
@@ -135,14 +135,20 @@ module Ruby2JS
135
135
  style = :statement
136
136
  end
137
137
 
138
- if args.children.length == 1 and args.children.first.type != :restarg and style == :expression
138
+ if args.children.length == 1 and args.children.first.type == :arg and style == :expression
139
139
  parse args; put ' => '
140
140
  else
141
141
  put '('; parse args; put ') => '
142
142
  end
143
143
 
144
144
  if style == :expression
145
- expr.type == :hash ? group(expr) : wrap('(', ')') { parse(expr) }
145
+ if expr.type == :taglit
146
+ parse expr
147
+ elsif expr.type == :hash
148
+ group(expr)
149
+ else
150
+ wrap('(', ')') { parse(expr) }
151
+ end
146
152
  elsif body.type == :begin and body.children.length == 0
147
153
  put "{}"
148
154
  else
@@ -25,7 +25,9 @@ module Ruby2JS
25
25
  put '`'
26
26
  children.each do |child|
27
27
  if child.type == :str
28
- str = child.children.first.inspect[1..-2].gsub('${', '$\{').gsub('`', '\\\`')
28
+ str = child.children.first.inspect[1..-2].
29
+ gsub('${', '$\{').gsub('`', '\\\`')
30
+ str = str.gsub(/\\"/, '"') unless str.include? '\\\\'
29
31
  if heredoc
30
32
  put! str.gsub("\\n", "\n")
31
33
  else
@@ -28,7 +28,7 @@ module Ruby2JS
28
28
  else
29
29
  put (@ast.type==:for_of ? ' of ' : ' in '); parse expression;
30
30
  end
31
- puts ') {'; scope block; sput '}'
31
+ puts ') {'; redoable block; sput '}'
32
32
  ensure
33
33
  @next_token = next_token
34
34
  @vars = vars if es2015
@@ -7,6 +7,24 @@ module Ruby2JS
7
7
  # (str "value")))
8
8
 
9
9
  handle :hash do |*pairs|
10
+ if not es2018 and pairs.any? {|pair| pair.type == :kwsplat}
11
+ groups = []
12
+ pending = []
13
+ while not pairs.empty?
14
+ pair = pairs.shift
15
+ if pair.type != :kwsplat
16
+ pending << pair
17
+ else
18
+ groups << s(:hash, *pending) unless pending.empty?
19
+ groups << pair.children.first
20
+ pending = []
21
+ end
22
+ end
23
+ groups << s(:hash, *pending) unless pending.empty?
24
+ parse s(:assign, s(:hash), *groups)
25
+ return
26
+ end
27
+
10
28
  compact do
11
29
  singleton = pairs.length <= 1
12
30
 
@@ -24,7 +42,7 @@ module Ruby2JS
24
42
  pairs.unshift(*node.children.first.children)
25
43
  index = 0
26
44
  else
27
- puts '...'; parse node.children.first
45
+ put '...'; parse node.children.first
28
46
  end
29
47
 
30
48
  next
@@ -57,7 +57,7 @@ module Ruby2JS
57
57
  else
58
58
  group = LOGICAL.include?( expr.type ) &&
59
59
  operator_index( :not ) < operator_index( expr.type )
60
- group = true if expr and expr.type == :begin
60
+ group = true if expr and %i[begin in?].include? expr.type
61
61
 
62
62
  put '!'; put '(' if group; parse expr; put ')' if group
63
63
  end
@@ -5,8 +5,16 @@ module Ruby2JS
5
5
  # (int 1))
6
6
 
7
7
  handle :next do |n=nil|
8
- raise Error.new("next argument #{ n.inspect }", @ast) if n
9
- put @next_token.to_s
8
+ if @next_token == :return
9
+ put 'return'
10
+ if n
11
+ put ' '
12
+ parse n
13
+ end
14
+ else
15
+ raise Error.new("next argument #{ n.inspect }", @ast) if n
16
+ put @next_token.to_s
17
+ end
10
18
  end
11
19
  end
12
20
  end
@@ -0,0 +1,14 @@
1
+ module Ruby2JS
2
+ class Converter
3
+
4
+ # (redo)
5
+
6
+ handle :redo do
7
+ unless @redoable and @next_token == :continue
8
+ raise Error.new("redo outside of loop", @ast)
9
+ end
10
+
11
+ put "redo$ = true#{@sep}continue"
12
+ end
13
+ end
14
+ end
@@ -14,7 +14,8 @@ module Ruby2JS
14
14
 
15
15
  EXPRESSIONS = [ :array, :float, :hash, :int, :lvar, :nil, :send, :attr,
16
16
  :str, :sym, :dstr, :dsym, :cvar, :ivar, :zsuper, :super, :or, :and,
17
- :block, :const, :true, :false, :xnode, :taglit, :self ]
17
+ :block, :const, :true, :false, :xnode, :taglit, :self,
18
+ :op_asgn, :and_asgn, :or_asgn, :taglit, :gvar ]
18
19
 
19
20
  handle :autoreturn do |*statements|
20
21
  return if statements == [nil]
@@ -60,7 +60,7 @@ module Ruby2JS
60
60
  return parse args.first, @state
61
61
 
62
62
  elsif not receiver and [:lambda, :proc].include? method
63
- if method == :lambda
63
+ if method == :lambda and @state != :statement
64
64
  return parse s(args.first.type, *args.first.children[0..-2],
65
65
  s(:autoreturn, args.first.children[-1])), @state
66
66
  else
@@ -75,10 +75,17 @@ module Ruby2JS
75
75
  (es2015 || @state == :statement ? group(receiver) : parse(receiver))
76
76
  put '('; parse_all(*args, join: ', '); put ')'
77
77
  return
78
+ elsif not t2 and m2 == :async and args2.length == 0
79
+ put '('; parse receiver; put ')()'
80
+ return
78
81
  end
79
82
  end
80
83
 
81
84
  # async/await support
85
+ # map "await x do...end" to "await x {...}" due to precedence rules
86
+ if method == :await and es2017 and receiver == nil and args.length == 2 and args[1].type == :def
87
+ args = [s(:block, args.first, *args.last.children[1..-1])]
88
+ end
82
89
  if es2017 and receiver == nil and args.length == 1
83
90
  if method == :async
84
91
  if args.first.type == :def
@@ -89,6 +96,15 @@ module Ruby2JS
89
96
  # async def o.m(x) {...}
90
97
  return parse args.first.updated :asyncs
91
98
 
99
+ elsif args.first.type == :send and
100
+ args.first.children.first.type == :block and
101
+ args.first.children.last == :[]
102
+
103
+ put '(async '
104
+ parse args.first.children.first, :statement
105
+ put ')()'
106
+ return
107
+
92
108
  elsif args.first.type == :block
93
109
  block = args.first
94
110
 
@@ -137,6 +153,7 @@ module Ruby2JS
137
153
  if receiver
138
154
  if receiver.type == :autobind
139
155
  autobind = receiver = receiver.children.first
156
+ autobind = nil unless @autobind
140
157
  end
141
158
 
142
159
  group_receiver = receiver.type == :send &&
@@ -157,6 +174,8 @@ module Ruby2JS
157
174
  group_target ||= GROUP_OPERATORS.include? target.type
158
175
  end
159
176
 
177
+ put 'await ' if @ast.type == :await
178
+
160
179
  if method == :!
161
180
  parse s(:not, receiver)
162
181
 
@@ -172,7 +191,7 @@ module Ruby2JS
172
191
  end
173
192
 
174
193
  elsif method == :[]=
175
- parse receiver
194
+ (group_receiver ? group(receiver) : parse(receiver))
176
195
  if \
177
196
  args.length == 2 and [:str, :sym].include? args.first.type and
178
197
  args.first.children.first.to_s =~ /^[a-zA-Z]\w*$/
@@ -303,9 +322,16 @@ module Ruby2JS
303
322
  elsif method == :typeof and receiver == nil
304
323
  put 'typeof '; parse args.first
305
324
 
306
- else
307
- put 'await ' if @ast.type == :await
325
+ elsif ast.children[1] == :is_a? and receiver and args.length == 1
326
+ parse receiver; put ' instanceof '; parse args.first
327
+
328
+ elsif ast.children[1] == :kind_of? and receiver and args.length == 1
329
+ parse receiver; put ' instanceof '; parse args.first
308
330
 
331
+ elsif ast.children[1] == :instance_of? and receiver and args.length == 1
332
+ parse s(:send, s(:attr, receiver, :constructor), :==, args.first)
333
+
334
+ else
309
335
  if method == :bind and receiver&.type == :send
310
336
  if receiver.children.length == 2 and receiver.children.first == nil
311
337
  receiver = receiver.updated(:attr) # prevent autobind