ruby2js 4.1.0 → 4.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 46b6cba0b33ebf62cb966def9b680eda35f5e84ff0c3adaea058fc2aae242269
4
- data.tar.gz: 6c5843992eccd24e8460b16f805eab16701d70d85e8ef4dcaffee948243666c0
3
+ metadata.gz: 6b96695d82101133b8d791e19d0f04fa5c6c56c16bb6504b447cf26e0e1291db
4
+ data.tar.gz: 9a7711f281076e14e354bcab9fd8f96de5b884153360a9b5fdb57b6fa9c5a792
5
5
  SHA512:
6
- metadata.gz: 6910f39474f2c22c321b91ad742ab10f7fff08bc5408e53f9b4d0cdee4f4fead414519a1b31bf7e6f781dc31da71fbda55bc747132c0d78e8eeb62a8693ca419
7
- data.tar.gz: 07b1ddbff32682c2ea3fa65570e40f97907eea4765d00ea4b7921bca5156f83f8f855178ab13ed3fc70b9edb8035fc801cdb4031c6f8176e044699099ac7dccd
6
+ metadata.gz: f64daa6dad4b3ed8d475654e588a8f921782fc11aceecb01886b8c039139bdc716f863eb25f57c119410da1a180273cbf9f66992da0555ce66b1131c31deab44
7
+ data.tar.gz: f5ffccf5acc15710797fc566ba89730f34d5884492892d4972fa9d4ad6ef785e1875bd4e3ffb25a9cb0148d77c4501aed8ea21e3f1171c55c5ca13104c274f56
@@ -59,7 +59,7 @@ module Ruby2JS
59
59
  m = m.updated(:def, m.children[1..-1])
60
60
  end
61
61
 
62
- node = if m.type == :def or m.type == :defm
62
+ node = if %i(def defm deff).include? m.type
63
63
  if m.children.first == :initialize and !visible[:initialize]
64
64
  # constructor: remove from body and overwrite init function
65
65
  init = m
@@ -90,7 +90,7 @@ module Ruby2JS
90
90
  end
91
91
  end
92
92
 
93
- elsif m.type == :defs and m.children.first == s(:self)
93
+ elsif %i(defs defp).include? m.type and m.children.first == s(:self)
94
94
  if m.children[1] =~ /=$/
95
95
  # class property setter
96
96
  s(:prop, name, m.children[1].to_s[0..-2] =>
@@ -10,8 +10,12 @@ module Ruby2JS
10
10
  # disable autobinding in tag literals
11
11
  save_autobind, @autobind = @autobind, false
12
12
 
13
- put tag.children.first
14
- parse_all(*children, join: '')
13
+ if es2015
14
+ put tag.children.first
15
+ parse_all(*children, join: '')
16
+ else
17
+ parse @ast.updated(:send, [nil, tag.children.last, *children])
18
+ end
15
19
  ensure
16
20
  @autobind = save_autobind
17
21
  end
@@ -7,6 +7,59 @@ module Ruby2JS
7
7
  module CJS
8
8
  include SEXP
9
9
 
10
+ def options=(options)
11
+ super
12
+ @cjs_autoexports = !@disable_autoexports && options[:autoexports]
13
+ end
14
+
15
+ def process(node)
16
+ return super unless @cjs_autoexports
17
+
18
+ list = [node]
19
+ while list.length == 1 and list.first.type == :begin
20
+ list = list.first.children.dup
21
+ end
22
+
23
+ replaced = []
24
+ list.map! do |child|
25
+ replacement = child
26
+
27
+ if [:module, :class].include? child.type and
28
+ child.children.first.type == :const and
29
+ child.children.first.children.first == nil \
30
+ then
31
+ replacement = s(:send, nil, :export, child)
32
+ elsif child.type == :casgn and child.children.first == nil
33
+ replacement = s(:send, nil, :export, child)
34
+ elsif child.type == :def
35
+ replacement = s(:send, nil, :export, child)
36
+ end
37
+
38
+ if replacement != child
39
+ replaced << replacement
40
+ @comments[replacement] = @comments[child] if @comments[child]
41
+ end
42
+
43
+ replacement
44
+ end
45
+
46
+ if replaced.length == 1 and @cjs_autoexports == :default
47
+ list.map! do |child|
48
+ if child == replaced.first
49
+ replacement = s(:send, nil, :export, s(:send, nil, :default,
50
+ *child.children[2..-1]))
51
+ @comments[replacement] = @comments[child] if @comments[child]
52
+ replacement
53
+ else
54
+ child
55
+ end
56
+ end
57
+ end
58
+
59
+ @cjs_autoexports = false
60
+ process s(:begin, *list)
61
+ end
62
+
10
63
  def on_send(node)
11
64
  return super unless node.children[1] == :export
12
65
 
@@ -23,9 +76,54 @@ module Ruby2JS
23
76
  node.updated(nil, [
24
77
  s(:attr, nil, :exports),
25
78
  assign.children[0].to_s + '=',
26
- *assign.children[1..-1]
79
+ *process_all(assign.children[1..-1])
27
80
  ])
28
81
 
82
+ elsif node.children[2].type == :casgn
83
+ assign = node.children[2]
84
+ if assign.children[0] == nil
85
+ node.updated(nil, [
86
+ s(:attr, nil, :exports),
87
+ assign.children[1].to_s + '=',
88
+ *process_all(assign.children[2..-1])
89
+ ])
90
+ else
91
+ node
92
+ end
93
+
94
+ elsif node.children[2].type == :class
95
+ assign = node.children[2]
96
+ if assign.children[0].children[0] != nil
97
+ node
98
+ elsif assign.children[1] == nil
99
+ node.updated(nil, [
100
+ s(:attr, nil, :exports),
101
+ assign.children[0].children[1].to_s + '=',
102
+ s(:block, s(:send, s(:const, nil, :Class), :new),
103
+ s(:args), *process_all(assign.children[2..-1]))
104
+ ])
105
+ else
106
+ node.updated(nil, [
107
+ s(:attr, nil, :exports),
108
+ assign.children[0].children[1].to_s + '=',
109
+ s(:block, s(:send, s(:const, nil, :Class), :new,
110
+ assign.children[1]), s(:args),
111
+ *process_all(assign.children[2..-1]))
112
+ ])
113
+ end
114
+
115
+ elsif node.children[2].type == :module
116
+ assign = node.children[2]
117
+ if assign.children[0].children[0] != nil
118
+ node
119
+ else
120
+ node.updated(nil, [
121
+ s(:attr, nil, :exports),
122
+ assign.children[0].children[1].to_s + '=',
123
+ s(:class_module, nil, nil, *process_all(assign.children[1..-1]))
124
+ ])
125
+ end
126
+
29
127
  elsif \
30
128
  node.children[2].type == :send and
31
129
  node.children[2].children[0..1] == [nil, :async] and
@@ -49,7 +147,7 @@ module Ruby2JS
49
147
  node.updated(nil, [
50
148
  s(:attr, nil, :module),
51
149
  :exports=,
52
- node.children[2]
150
+ process(node.children[2])
53
151
  ])
54
152
 
55
153
  else
@@ -22,10 +22,19 @@ module Ruby2JS
22
22
 
23
23
  def on_ivasgn(node)
24
24
  return super unless @le_props&.include?(node.children.first)
25
+ return super unless node.children.length > 1
25
26
  s(:send, s(:self), node.children.first.to_s[1..-1]+'=',
26
27
  process(node.children[1]))
27
28
  end
28
29
 
30
+ def on_op_asgn(node)
31
+ return super unless node.children.first.type == :ivasgn
32
+ var = node.children.first.children.first
33
+ return super unless @le_props&.include?(var)
34
+ super node.updated(nil, [s(:attr, s(:attr, nil, :this),
35
+ var.to_s[1..-1]), *node.children[1..-1]])
36
+ end
37
+
29
38
  def on_class(node)
30
39
  cname, inheritance, *body = node.children
31
40
  return super unless inheritance == s(:const, nil, :LitElement)
@@ -66,9 +75,9 @@ module Ruby2JS
66
75
 
67
76
  # render of a string is converted to a taglit :html
68
77
  render = nodes.find_index {|child|
69
- child.type == :def and child.children.first == :render
78
+ child&.type == :def and child.children.first == :render
70
79
  }
71
- if render and %i[str dstr].include?(nodes[render].children[2].type)
80
+ if render and %i[str dstr].include?(nodes[render].children[2]&.type)
72
81
  nodes[render] = nodes[render].updated(:deff,
73
82
  [*nodes[render].children[0..1],
74
83
  s(:autoreturn, html_wrap(nodes[render].children[2]))])
@@ -76,9 +85,9 @@ module Ruby2JS
76
85
 
77
86
  # self.styles returning string is converted to a taglit :css
78
87
  styles = nodes.find_index {|child|
79
- child.type == :defs and child.children[0..1] == [s(:self), :styles]
88
+ child&.type == :defs and child.children[0..1] == [s(:self), :styles]
80
89
  }
81
- if styles and %i[str dstr].include?(nodes[styles].children[3].type)
90
+ if styles and %i[str dstr].include?(nodes[styles].children[3]&.type)
82
91
  string = nodes[styles].children[3]
83
92
  string = s(:dstr, string) if string.type == :str
84
93
  children = string.children.dup
@@ -100,13 +109,13 @@ module Ruby2JS
100
109
 
101
110
  # insert super calls into initializer
102
111
  initialize = nodes.find_index {|child|
103
- child.type == :def and child.children.first == :initialize
112
+ child&.type == :def and child.children.first == :initialize
104
113
  }
105
114
  if initialize and nodes[initialize].children.length == 3
106
- statements = nodes[initialize].children[2].children
115
+ statements = nodes[initialize].children[2..-1]
107
116
 
108
- if statements.length == 1 and statements.children.first.type == :begin
109
- statements = statements.children
117
+ if statements.length == 1 and statements.first.type == :begin
118
+ statements = statements.first.children
110
119
  end
111
120
 
112
121
  unless statements.any? {|statement| %i[super zuper].include? statement.type}
@@ -174,13 +183,18 @@ module Ruby2JS
174
183
  # analyze ivar usage
175
184
  def le_walk(node)
176
185
  node.children.each do |child|
177
- next unless Parser::AST::Node === child
178
- le_walk(child)
186
+ next unless child.is_a? Parser::AST::Node
179
187
 
180
188
  if child.type == :ivar
181
189
  @le_props[child.children.first] ||= nil
182
- elsif child.type == :ivasgn
183
- @le_props[child.children.first] = case child.children.last.type
190
+ elsif child.type == :ivasgn || child.type == :op_asgn
191
+ prop = child.children.first
192
+ unless prop.is_a? Symbol
193
+ prop = prop.children.first if prop.type == :ivasgn
194
+ next unless prop.is_a? Symbol
195
+ end
196
+
197
+ @le_props[prop] = case child.children.last.type
184
198
  when :str, :dstr
185
199
  :String
186
200
  when :array
@@ -190,8 +204,10 @@ module Ruby2JS
190
204
  when :true, :false
191
205
  :Boolean
192
206
  else
193
- @le_props[child.children.first] || :Object
207
+ @le_props[prop] || :Object
194
208
  end
209
+ else
210
+ le_walk(child)
195
211
  end
196
212
  end
197
213
  end
@@ -31,7 +31,8 @@ module Ruby2JS
31
31
  Preact: s(:import,
32
32
  [s(:pair, s(:sym, :as), s(:const, nil, :Preact)),
33
33
  s(:pair, s(:sym, :from), s(:str, "preact"))],
34
- s(:str, '*'))
34
+ s(:str, '*')),
35
+ PreactHook: s(:import, ["preact/hooks"], [s(:attr, nil, :useState)])
35
36
  }
36
37
 
37
38
  # the following command can be used to generate ReactAttrs:
@@ -75,7 +76,7 @@ module Ruby2JS
75
76
 
76
77
  ReactLifecycle = %w(render componentDidMount shouldComponentUpdate
77
78
  getShapshotBeforeUpdate componentDidUpdate componentWillUnmount
78
- componentDidCatch)
79
+ componentDidCatch componentWillReceiveProps)
79
80
 
80
81
  ReactAttrMap = Hash[ReactAttrs.map {|name| [name.downcase, name]}]
81
82
  ReactAttrMap['for'] = 'htmlFor'
@@ -91,6 +92,7 @@ module Ruby2JS
91
92
  @reactApply = nil
92
93
  @reactBlock = nil
93
94
  @reactClass = nil
95
+ @reactMethod = nil
94
96
  @react_props = []
95
97
  @react_methods = []
96
98
  @react_filter_functions = false
@@ -181,8 +183,8 @@ module Ruby2JS
181
183
  if not createClass
182
184
  pairs << child
183
185
  elsif child.is_method?
184
- statics << s(:pair, s(:sym, mname), process(child.updated(:block,
185
- [s(:send, nil, :proc), args, s(:autoreturn, *block)])))
186
+ statics << s(:pair, s(:sym, mname), child.updated(:block,
187
+ [s(:send, nil, :proc), args, s(:autoreturn, *block)]))
186
188
  elsif \
187
189
  block.length == 1 and
188
190
  Converter::EXPRESSIONS.include? block.first.type
@@ -240,6 +242,46 @@ module Ruby2JS
240
242
  pairs << s(:pair, s(:sym, :statics), s(:hash, *statics))
241
243
  end
242
244
 
245
+ # determine if this class can be emitted as a hook
246
+ hook = (es2015 and inheritance.children.first == nil)
247
+ hookinit = nil
248
+ useState = []
249
+ body.each_with_index do |statement, index|
250
+ if statement.type == :def
251
+ method = statement.children.first
252
+ if method == :initialize
253
+ children = statement.children[2..-1]
254
+ children.pop unless children.last
255
+ while children.length == 1 and children.first.type == :begin
256
+ children = children.first.children
257
+ end
258
+ hookinit = index if children.any? {|child| child.type != :ivasgn}
259
+ elsif method == :render
260
+ nil
261
+ elsif ReactLifecycle.include? method.to_s
262
+ hook = false
263
+ elsif not statement.is_method?
264
+ hook = false
265
+ elsif method.to_s.end_with? '='
266
+ hook = false
267
+ end
268
+ elsif statement.type == :defs
269
+ hook = false
270
+ end
271
+ end
272
+
273
+ if hook
274
+ @reactClass = :hook
275
+ @react_props = []
276
+ @react_methods = []
277
+
278
+ if hookinit
279
+ body = body.dup
280
+ hookinit = body.delete_at(hookinit)
281
+ pairs.unshift process hookinit.children[2]
282
+ end
283
+ end
284
+
243
285
  # create a default getInitialState method if there is no such method
244
286
  # and there are either references to instance variables or there are
245
287
  # methods that need to be bound.
@@ -251,6 +293,12 @@ module Ruby2JS
251
293
  then
252
294
  @reactIvars = {pre: [], post: [], asgn: [], ref: [], cond: []}
253
295
  react_walk(node)
296
+
297
+ if hook
298
+ react_walk(hookinit) if hookinit
299
+ useState = (@reactIvars[:asgn] + @reactIvars[:ref]).uniq
300
+ end
301
+
254
302
  if createClass and not @reactIvars.values.flatten.empty?
255
303
  body = [s(:def, :getInitialState, s(:args),
256
304
  s(:return, s(:hash))), *body]
@@ -263,13 +311,18 @@ module Ruby2JS
263
311
  body.select {|child| child.type == :def}.each do |child|
264
312
  mname, args, *block = child.children
265
313
  @reactMethod = mname
266
- @reactProps = child.updated(:attr, [s(:self), :props])
314
+
315
+ if @reactClass == :hook
316
+ @reactProps = s(:lvar, :"prop$")
317
+ else
318
+ @reactProps = child.updated(:attr, [s(:self), :props])
319
+ end
267
320
 
268
321
  # analyze ivar usage
269
322
  @reactIvars = {pre: [], post: [], asgn: [], ref: [], cond: []}
270
323
  react_walk(child) unless mname == :initialize
271
- @reactIvars[:capture] =
272
- (@reactIvars[:pre] + @reactIvars[:post]).uniq
324
+ @reactIvars[:capture] = (@reactIvars[:pre] + @reactIvars[:post]).uniq
325
+ @reactIvars[:pre] = @reactIvars[:post] = [] if @reactClass == :hook
273
326
 
274
327
  if mname == :initialize
275
328
  mname = createClass ? :getInitialState : :initialize
@@ -400,6 +453,52 @@ module Ruby2JS
400
453
  # emit a createClass statement
401
454
  node.updated(:casgn, [nil, cname.children.last,
402
455
  s(:send, s(:const, nil, :React), :createClass, s(:hash, *pairs))])
456
+ elsif hook
457
+ initialize = pairs.find_index {|node| node.type == :def and node.children.first == :initialize}
458
+
459
+ hash = {}
460
+ if initialize
461
+ hash = pairs.delete_at(initialize)
462
+ hash = hash.children.last while %i(def begin send).include? hash&.type
463
+ hash = s(:hash) unless hash&.type == :hash
464
+ hash = hash.children.map {|pair|
465
+ [pair.children.first.children.first, pair.children.last]
466
+ }.to_h
467
+ end
468
+
469
+ useState.each do |symbol|
470
+ hash[symbol.to_s[1..-1]] ||= s(:nil)
471
+ end
472
+
473
+ hash.sort.reverse.each do |var, value|
474
+ if @react == :Preact
475
+ hooker = nil
476
+ prepend_list << REACT_IMPORTS[:PreactHook] if modules_enabled?
477
+ else
478
+ hooker = s(:const, nil, :React)
479
+ end
480
+
481
+ setter = 'set' + var[0].upcase + var[1..-1]
482
+ pairs.unshift(s(:masgn, s(:mlhs, s(:lvasgn, var),
483
+ s(:lvasgn, setter)), s(:send, hooker, :useState, value)))
484
+ end
485
+
486
+ render = pairs.find_index {|node| node.type == :defm and node.children.first == :render}
487
+ if render
488
+ render = pairs.delete_at(render)
489
+ pairs.push s(:autoreturn, render.children.last)
490
+ end
491
+
492
+ has_cvar = lambda {|list|
493
+ list.any? {|node|
494
+ next unless Parser::AST::Node === node
495
+ return true if node.type == :cvar
496
+ has_cvar.call(node.children)
497
+ }
498
+ }
499
+ args = has_cvar[node.children] ? s(:args, s(:arg, 'prop$')) : s(:args)
500
+
501
+ node.updated(:def, [cname.children.last, args, s(:begin, *pairs)])
403
502
  else
404
503
  # emit a class that extends React.Component
405
504
  node.updated(:class, [s(:const, nil, cname.children.last),
@@ -1068,13 +1167,17 @@ module Ruby2JS
1068
1167
  # convert global variables to refs
1069
1168
  def on_gvar(node)
1070
1169
  return super unless @reactClass
1170
+ return super if @reactClass == :hook
1071
1171
  s(:attr, s(:attr, s(:self), :refs), node.children.first.to_s[1..-1])
1072
1172
  end
1073
1173
 
1074
1174
  # convert instance variables to state
1075
1175
  def on_ivar(node)
1076
1176
  return super unless @reactClass
1077
- if @reactMethod and @reactIvars[:capture].include? node.children.first
1177
+
1178
+ if @reactClass == :hook
1179
+ node.updated(:lvar, [node.children.first.to_s[1..-1]])
1180
+ elsif @reactMethod and @reactIvars[:capture].include? node.children.first
1078
1181
  node.updated(:lvar, ["$#{node.children.first[1..-1]}"])
1079
1182
  else
1080
1183
  node.updated(:attr, [s(:attr, s(:self), :state),
@@ -1086,6 +1189,12 @@ module Ruby2JS
1086
1189
  def on_ivasgn(node)
1087
1190
  return super unless @react
1088
1191
 
1192
+ if @reactClass == :hook
1193
+ var = node.children.first.to_s[1..-1]
1194
+ return node.updated(:send, [nil, 'set' + var[0].upcase + var[1..-1],
1195
+ process(node.children.last)])
1196
+ end
1197
+
1089
1198
  if @reactMethod and @reactIvars[:capture].include? node.children.first
1090
1199
  ivar = node.children.first.to_s
1091
1200
  if @reactBlock
@@ -1142,7 +1251,11 @@ module Ruby2JS
1142
1251
  return super unless @react
1143
1252
  return super unless node.children.first.type == :ivasgn
1144
1253
  var = node.children.first.children.first
1145
- if @reactMethod and @reactIvars[:capture].include? var
1254
+ if @reactClass == :hook
1255
+ var = node.children.first.children.first.to_s[1..-1]
1256
+ node.updated(:send, [nil, 'set' + var[0].upcase + var[1..-1],
1257
+ s(:send, s(:lvar, var), *node.children[1..-1])])
1258
+ elsif @reactMethod and @reactIvars[:capture].include? var
1146
1259
  if @reactBlock
1147
1260
  s(:send, s(:self), :setState, s(:hash, s(:pair,
1148
1261
  s(:str, var[1..-1]), process(s(node.type,
@@ -1330,6 +1443,7 @@ module Ruby2JS
1330
1443
  @reactIvars = {pre: [], post: [], asgn: [], ref: [], cond: []}
1331
1444
  react_walk(node.children.last)
1332
1445
  @reactIvars[:capture] = (@reactIvars[:pre] + @reactIvars[:post]).uniq
1446
+ @reactIvars[:pre] = @reactIvars[:post] = [] if @reactClass == :hook
1333
1447
  node = super
1334
1448
  block = react_process_ivars([node.children.last.dup])
1335
1449
  node.updated(nil, [*node.children[0..-2], s(:begin, *block)])
@@ -2,7 +2,7 @@ module Ruby2JS
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 4
4
4
  MINOR = 1
5
- TINY = 0
5
+ TINY = 1
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby2js
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Ruby
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-03-17 00:00:00.000000000 Z
12
+ date: 2021-03-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: parser