ruby2js 4.1.0 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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