ruby2js 4.0.2 → 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: eada6454a1374751fa61b2522291a4f7c61023ec0218ba98d7fdcb19e0067f0e
4
- data.tar.gz: 4bef375ce47cef8733f0e08250dfbf4f6968e9a043aa53825d9198db3fafdd7f
3
+ metadata.gz: 6b96695d82101133b8d791e19d0f04fa5c6c56c16bb6504b447cf26e0e1291db
4
+ data.tar.gz: 9a7711f281076e14e354bcab9fd8f96de5b884153360a9b5fdb57b6fa9c5a792
5
5
  SHA512:
6
- metadata.gz: 511f8917dfac3baaa45f33147430d23ea0a41e3ed2b74147d9589e1385a6f07d36aab029f47ba05f07f974c3543a7823a7c943b190e30fee2a240ce604d25d87
7
- data.tar.gz: 61c8b8b5f3fbbecde1fb1bc0d23a35c13202a21467009665faba3b596607272fc1b1601f4f0156cf9d60ed80ff1e96ffa5204a1fa83b57430b729c6bc9b9b9d1
6
+ metadata.gz: f64daa6dad4b3ed8d475654e588a8f921782fc11aceecb01886b8c039139bdc716f863eb25f57c119410da1a180273cbf9f66992da0555ce66b1131c31deab44
7
+ data.tar.gz: f5ffccf5acc15710797fc566ba89730f34d5884492892d4972fa9d4ad6ef785e1875bd4e3ffb25a9cb0148d77c4501aed8ea21e3f1171c55c5ca13104c274f56
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
@@ -180,7 +180,7 @@ module Ruby2JS
180
180
  def on_xnode(node); end
181
181
  def on_export(node); end
182
182
  def on_import(node); end
183
- def on_taglit(node); end
183
+ def on_taglit(node); on_pair(node); end
184
184
 
185
185
  # provide a method so filters can call 'super'
186
186
  def on_sym(node); node; end
@@ -60,6 +60,7 @@ 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
@@ -36,7 +36,8 @@ module Ruby2JS
36
36
  end
37
37
 
38
38
  if inheritance
39
- init = s(:def, :initialize, s(:args), s(:super))
39
+ parent = @namespace.find(inheritance)&.[](:constructor)
40
+ init = s(:def, :initialize, parent || s(:args), s(:zsuper))
40
41
  else
41
42
  init = s(:def, :initialize, s(:args), nil)
42
43
  end
@@ -58,7 +59,7 @@ module Ruby2JS
58
59
  m = m.updated(:def, m.children[1..-1])
59
60
  end
60
61
 
61
- node = if m.type == :def
62
+ node = if %i(def defm deff).include? m.type
62
63
  if m.children.first == :initialize and !visible[:initialize]
63
64
  # constructor: remove from body and overwrite init function
64
65
  init = m
@@ -89,7 +90,7 @@ module Ruby2JS
89
90
  end
90
91
  end
91
92
 
92
- elsif m.type == :defs and m.children.first == s(:self)
93
+ elsif %i(defs defp).include? m.type and m.children.first == s(:self)
93
94
  if m.children[1] =~ /=$/
94
95
  # class property setter
95
96
  s(:prop, name, m.children[1].to_s[0..-2] =>
@@ -313,7 +314,7 @@ module Ruby2JS
313
314
  # prepend constructor
314
315
  if init
315
316
  constructor = init.updated(:constructor, [name, *init.children[1..-1]])
316
- @comments[constructor] = @comments[init] unless @comments[init].empty?
317
+ visible[:constructor] = init.children[1]
317
318
 
318
319
  if @ast.type == :class_extend or extend
319
320
  if es2015
@@ -329,6 +330,7 @@ module Ruby2JS
329
330
  end
330
331
  end
331
332
 
333
+ @comments[constructor] = @comments[init] unless @comments[init].empty?
332
334
  body.unshift constructor
333
335
  end
334
336
 
@@ -349,7 +351,7 @@ module Ruby2JS
349
351
  self.ivars = ivars
350
352
  @class_name = class_name
351
353
  @class_parent = class_parent
352
- @rbstack.pop
354
+ @namespace.defineProps @rbstack.pop
353
355
  @namespace.leave unless @ast.type == :class_module
354
356
  end
355
357
  end
@@ -99,7 +99,6 @@ module Ruby2JS
99
99
  end
100
100
  walk[@ast]
101
101
 
102
- # process leading initializers in constructor
103
102
  while constructor.length == 1 and constructor.first.type == :begin
104
103
  constructor = constructor.first.children.dup
105
104
  end
@@ -116,6 +115,7 @@ module Ruby2JS
116
115
  put 'static #$' + cvar.to_s[2..-1]
117
116
  end
118
117
 
118
+ # process leading initializers in constructor
119
119
  while constructor.length > 0 and constructor.first.type == :ivasgn
120
120
  put(index == 0 ? @nl : @sep)
121
121
  index += 1
@@ -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])])
@@ -142,7 +142,13 @@ module Ruby2JS
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
@@ -15,7 +15,7 @@ module Ruby2JS
15
15
  EXPRESSIONS = [ :array, :float, :hash, :int, :lvar, :nil, :send, :attr,
16
16
  :str, :sym, :dstr, :dsym, :cvar, :ivar, :zsuper, :super, :or, :and,
17
17
  :block, :const, :true, :false, :xnode, :taglit, :self,
18
- :op_asgn, :and_asgn, :or_asgn ]
18
+ :op_asgn, :and_asgn, :or_asgn, :taglit, :gvar ]
19
19
 
20
20
  handle :autoreturn do |*statements|
21
21
  return if statements == [nil]
@@ -153,6 +153,7 @@ module Ruby2JS
153
153
  if receiver
154
154
  if receiver.type == :autobind
155
155
  autobind = receiver = receiver.children.first
156
+ autobind = nil unless @autobind
156
157
  end
157
158
 
158
159
  group_receiver = receiver.type == :send &&
@@ -6,8 +6,19 @@ module Ruby2JS
6
6
  # (dstr)
7
7
 
8
8
  handle :taglit do |tag, *children|
9
- put tag.children.first
10
- parse_all(*children, join: '')
9
+ begin
10
+ # disable autobinding in tag literals
11
+ save_autobind, @autobind = @autobind, false
12
+
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
19
+ ensure
20
+ @autobind = save_autobind
21
+ end
11
22
  end
12
23
  end
13
24
  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
@@ -227,14 +227,19 @@ module Ruby2JS
227
227
  if before.type == :regexp
228
228
  before = before.updated(:regexp, [*before.children[0...-1],
229
229
  s(:regopt, :g, *before.children.last)])
230
- elsif before.type == :str
230
+ elsif before.type == :str and not es2021
231
231
  before = before.updated(:regexp,
232
232
  [s(:str, Regexp.escape(before.children.first)), s(:regopt, :g)])
233
233
  end
234
234
  if after.type == :str
235
235
  after = s(:str, after.children.first.gsub(/\\(\d)/, "$\\1"))
236
236
  end
237
- process node.updated nil, [target, :replace, before, after]
237
+
238
+ if es2021
239
+ process node.updated nil, [target, :replaceAll, before, after]
240
+ else
241
+ process node.updated nil, [target, :replace, before, after]
242
+ end
238
243
 
239
244
  elsif method == :ord and args.length == 0
240
245
  if target.type == :str
@@ -767,10 +772,10 @@ module Ruby2JS
767
772
  body.any? {|statement| statement.type == :def and
768
773
  statement.children.first == :initialize}
769
774
  then
770
- body.unshift S(:def, :initialize, s(:args, s(:arg, :message)),
771
- s(:begin, S(:send, s(:self), :message=, s(:lvar, :message)),
772
- S(:send, s(:self), :name=, s(:sym, name.children[1])),
773
- S(:send, s(:self), :stack=, s(:send, s(:send, nil, :Error,
775
+ body.unshift s(:def, :initialize, s(:args, s(:arg, :message)),
776
+ s(:begin, s(:send, s(:self), :message=, s(:lvar, :message)),
777
+ s(:send, s(:self), :name=, s(:sym, name.children[1])),
778
+ s(:send, s(:self), :stack=, s(:attr, s(:send, nil, :Error,
774
779
  s(:lvar, :message)), :stack))))
775
780
  end
776
781
 
@@ -0,0 +1,218 @@
1
+ require 'ruby2js'
2
+
3
+ module Ruby2JS
4
+ module Filter
5
+ module LitElement
6
+ include SEXP
7
+ extend SEXP
8
+
9
+ LITELEMENT_IMPORT = s(:import,
10
+ [s(:pair, s(:sym, :from), s(:str, "lit-element"))],
11
+ [s(:const, nil, :LitElement), s(:attr, nil, :css), s(:attr, nil, :html)])
12
+
13
+ def initialize(node)
14
+ super
15
+ @le_props = nil
16
+ end
17
+
18
+ def on_ivar(node)
19
+ return super unless @le_props&.include?(node.children.first)
20
+ s(:attr, s(:self), node.children.first.to_s[1..-1])
21
+ end
22
+
23
+ def on_ivasgn(node)
24
+ return super unless @le_props&.include?(node.children.first)
25
+ return super unless node.children.length > 1
26
+ s(:send, s(:self), node.children.first.to_s[1..-1]+'=',
27
+ process(node.children[1]))
28
+ end
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
+
38
+ def on_class(node)
39
+ cname, inheritance, *body = node.children
40
+ return super unless inheritance == s(:const, nil, :LitElement)
41
+
42
+ @le_props = {}
43
+ le_walk(node)
44
+
45
+ prepend_list << LITELEMENT_IMPORT if modules_enabled?
46
+
47
+ nodes = body.dup
48
+ if nodes.length == 1 and nodes.first&.type == :begin
49
+ nodes = nodes.first.children.dup
50
+ end
51
+
52
+ # insert/update static get properties() {}
53
+ unless @le_props.empty?
54
+ values = nodes.find_index {|child|
55
+ child.type == :defs and child.children[0..1] == [s(:self), :properties]
56
+ }
57
+
58
+ if values == nil
59
+ nodes.unshift s(:defp, s(:self), :properties, s(:args), s(:return,
60
+ s(:hash, *@le_props.map {|name, type| s(:pair, s(:str, name.to_s[1..-1]),
61
+ s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String))))})))
62
+ elsif nodes[values].children[3].type == :hash
63
+ le_props = @le_props.map {|name, type|
64
+ [s(:sym, name.to_s[1..-1].to_sym),
65
+ s(:hash, s(:pair, s(:sym, :type), s(:const, nil, type || :String)))]
66
+ }.to_h.merge(
67
+ nodes[values].children[3].children.map {|pair| pair.children}.to_h
68
+ )
69
+
70
+ nodes[values] = nodes[values].updated(nil,
71
+ [*nodes[values].children[0..2], s(:hash,
72
+ *le_props.map{|name, value| s(:pair, name, value)})])
73
+ end
74
+ end
75
+
76
+ # render of a string is converted to a taglit :html
77
+ render = nodes.find_index {|child|
78
+ child&.type == :def and child.children.first == :render
79
+ }
80
+ if render and %i[str dstr].include?(nodes[render].children[2]&.type)
81
+ nodes[render] = nodes[render].updated(:deff,
82
+ [*nodes[render].children[0..1],
83
+ s(:autoreturn, html_wrap(nodes[render].children[2]))])
84
+ end
85
+
86
+ # self.styles returning string is converted to a taglit :css
87
+ styles = nodes.find_index {|child|
88
+ child&.type == :defs and child.children[0..1] == [s(:self), :styles]
89
+ }
90
+ if styles and %i[str dstr].include?(nodes[styles].children[3]&.type)
91
+ string = nodes[styles].children[3]
92
+ string = s(:dstr, string) if string.type == :str
93
+ children = string.children.dup
94
+
95
+ while children.length > 1 and children.last.type == :str and
96
+ children.last.children.last.strip == ''
97
+ children.pop
98
+ end
99
+
100
+ if children.last.type == :str
101
+ children << s(:str, children.pop.children.first.chomp)
102
+ end
103
+
104
+ nodes[styles] = nodes[styles].updated(nil,
105
+ [*nodes[styles].children[0..2],
106
+ s(:autoreturn, s(:taglit, s(:sym, :css),
107
+ s(:dstr, *children)))])
108
+ end
109
+
110
+ # insert super calls into initializer
111
+ initialize = nodes.find_index {|child|
112
+ child&.type == :def and child.children.first == :initialize
113
+ }
114
+ if initialize and nodes[initialize].children.length == 3
115
+ statements = nodes[initialize].children[2..-1]
116
+
117
+ if statements.length == 1 and statements.first.type == :begin
118
+ statements = statements.first.children
119
+ end
120
+
121
+ unless statements.any? {|statement| %i[super zuper].include? statement.type}
122
+ nodes[initialize] = nodes[initialize].updated(nil,
123
+ [*nodes[initialize].children[0..1],
124
+ s(:begin, s(:zsuper), *statements)])
125
+ end
126
+ end
127
+
128
+ props = @le_props.keys.map {|prop| [prop.to_sym, s(:self)]}.to_h
129
+
130
+ nodes.unshift s(:defineProps, props)
131
+
132
+ nodes.pop unless nodes.last
133
+
134
+ node.updated(nil, [*node.children[0..1], s(:begin, *process_all(nodes))])
135
+ ensure
136
+ @le_props = nil
137
+ end
138
+
139
+ def html_wrap(node)
140
+ if node.type == :str and node.children.first.strip.start_with? '<'
141
+ s(:taglit, s(:sym, :html), s(:dstr, node))
142
+ elsif node.type == :dstr
143
+ prefix = ''
144
+ node.children.each do |child|
145
+ break unless child.type == :str
146
+ prefix += child.children.first
147
+ end
148
+
149
+ return node unless prefix.strip.start_with? '<'
150
+
151
+ children = node.children.map do |child|
152
+ if child.type == :str
153
+ child
154
+ else
155
+ html_wrap(child)
156
+ end
157
+ end
158
+
159
+ while children.length > 1 and children.last.type == :str and
160
+ children.last.children.last.strip == ''
161
+ children.pop
162
+ end
163
+
164
+ if children.last.type == :str
165
+ children << s(:str, children.pop.children.first.chomp)
166
+ end
167
+
168
+ s(:taglit, s(:sym, :html), node.updated(nil, children))
169
+ elsif node.type == :begin
170
+ node.updated(nil, node.children.map {|child| html_wrap(child)})
171
+ elsif node.type == :if
172
+ node.updated(nil, [node.children.first,
173
+ *node.children[1..2].map {|child| html_wrap(child)}])
174
+ elsif node.type == :block and
175
+ node.children.first.children[1] == :map
176
+ node.updated(nil, [*node.children[0..1],
177
+ html_wrap(node.children[2])])
178
+ else
179
+ node
180
+ end
181
+ end
182
+
183
+ # analyze ivar usage
184
+ def le_walk(node)
185
+ node.children.each do |child|
186
+ next unless child.is_a? Parser::AST::Node
187
+
188
+ if child.type == :ivar
189
+ @le_props[child.children.first] ||= nil
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
198
+ when :str, :dstr
199
+ :String
200
+ when :array
201
+ :Array
202
+ when :int, :float
203
+ :Number
204
+ when :true, :false
205
+ :Boolean
206
+ else
207
+ @le_props[prop] || :Object
208
+ end
209
+ else
210
+ le_walk(child)
211
+ end
212
+ end
213
+ end
214
+ end
215
+
216
+ DEFAULTS.push LitElement
217
+ end
218
+ end