ruby2js 4.0.2 → 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: 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