ruby2js 4.0.0 → 4.0.5

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.
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