ruby2js 3.2.0 → 3.3.0
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 +4 -4
- data/README.md +44 -4
- data/lib/ruby2js.rb +14 -2
- data/lib/ruby2js/converter.rb +11 -3
- data/lib/ruby2js/converter/args.rb +1 -1
- data/lib/ruby2js/converter/block.rb +2 -2
- data/lib/ruby2js/converter/class.rb +2 -2
- data/lib/ruby2js/converter/class2.rb +38 -9
- data/lib/ruby2js/converter/cvar.rb +1 -1
- data/lib/ruby2js/converter/cvasgn.rb +1 -1
- data/lib/ruby2js/converter/def.rb +2 -2
- data/lib/ruby2js/converter/for.rb +7 -0
- data/lib/ruby2js/converter/hash.rb +3 -3
- data/lib/ruby2js/converter/if.rb +13 -2
- data/lib/ruby2js/converter/import.rb +38 -0
- data/lib/ruby2js/converter/logical.rb +46 -1
- data/lib/ruby2js/converter/opasgn.rb +5 -2
- data/lib/ruby2js/converter/regexp.rb +27 -2
- data/lib/ruby2js/converter/return.rb +1 -1
- data/lib/ruby2js/converter/send.rb +53 -27
- data/lib/ruby2js/converter/super.rb +15 -9
- data/lib/ruby2js/converter/xnode.rb +89 -0
- data/lib/ruby2js/es2021.rb +5 -0
- data/lib/ruby2js/es2021/strict.rb +3 -0
- data/lib/ruby2js/filter/cjs.rb +2 -2
- data/lib/ruby2js/filter/esm.rb +72 -0
- data/lib/ruby2js/filter/functions.rb +142 -26
- data/lib/ruby2js/filter/matchAll.rb +49 -0
- data/lib/ruby2js/filter/node.rb +18 -10
- data/lib/ruby2js/filter/nokogiri.rb +13 -13
- data/lib/ruby2js/filter/react.rb +190 -30
- data/lib/ruby2js/filter/require.rb +1 -4
- data/lib/ruby2js/filter/rubyjs.rb +4 -4
- data/lib/ruby2js/filter/vue.rb +15 -15
- data/lib/ruby2js/filter/wunderbar.rb +63 -0
- data/lib/ruby2js/serializer.rb +25 -11
- data/lib/ruby2js/version.rb +1 -1
- metadata +10 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b2ad87139fac25c7b097f2ee32c59b141936bb8424cf93a4a20c2d9393495528
|
4
|
+
data.tar.gz: 4de6a0b69d4d496faae496b37c21c66caee4f3793b1241baf134b5a05c85c7f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e359e299801b09bc428a93fdf95d4ac1128fbb19266636034fad929d3fa3759f504e59bbd70eb923733b0656770309f845e23aeb0e4e24424ab0161f6fe528a
|
7
|
+
data.tar.gz: '0874df3f8606f65be7cbae4114c2d384938f7827391020ee0f85d0d99340e4e905010dbe7216ebab17f0adf72fa7793525c95a6e083273abc08cae3dd076d849'
|
data/README.md
CHANGED
@@ -92,6 +92,18 @@ Enable strict support:
|
|
92
92
|
puts Ruby2JS.convert('a=1', strict: true)
|
93
93
|
```
|
94
94
|
|
95
|
+
Emit strict equality comparisons:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
puts Ruby2JS.convert('a==1', comparison: :identity)
|
99
|
+
```
|
100
|
+
|
101
|
+
Emit nullish coalescing operators:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
puts Ruby2JS.convert('a || 1', or: :nullish)
|
105
|
+
```
|
106
|
+
|
95
107
|
With [ExecJS](https://github.com/sstephenson/execjs):
|
96
108
|
```ruby
|
97
109
|
require 'ruby2js/execjs'
|
@@ -233,9 +245,10 @@ the script.
|
|
233
245
|
* `.gsub` becomes `replace(//g)`
|
234
246
|
* `.include?` becomes `.indexOf() != -1`
|
235
247
|
* `.inspect` becomes `JSON.stringify()`
|
236
|
-
* `.keys` becomes `Object.keys()`
|
248
|
+
* `.keys()` becomes `Object.keys()`
|
237
249
|
* `.last` becomes `[*.length-1]`
|
238
250
|
* `.last(n)` becomes `.slice(*.length-1, *.length)`
|
251
|
+
* `.lstrip` becomes `.replace(/^\s+/, "")`
|
239
252
|
* `.max` becomes `Math.max.apply(Math)`
|
240
253
|
* `.merge` becomes `Object.assign({}, ...)`
|
241
254
|
* `.merge!` becomes `Object.assign()`
|
@@ -245,6 +258,7 @@ the script.
|
|
245
258
|
* `puts` becomes `console.log`
|
246
259
|
* `.replace` becomes `.length = 0; ...push.apply(*)`
|
247
260
|
* `.respond_to?` becomes `right in left`
|
261
|
+
* `.rstrip` becomes `.replace(/s+$/, "")`
|
248
262
|
* `.scan` becomes `.match(//g)`
|
249
263
|
* `.start_with?` becomes `.substring(0, arg.length) == arg`
|
250
264
|
* `.upto(lim)` becomes `for (var i=num; i<=lim; i+=1)`
|
@@ -264,6 +278,7 @@ the script.
|
|
264
278
|
* `[n...m]` becomes `.slice(n,m)`
|
265
279
|
* `[n..m]` becomes `.slice(n,m+1)`
|
266
280
|
* `[/r/, n]` becomes `.match(/r/)[n]`
|
281
|
+
* `[/r/, n]=` becomes `.replace(/r/, ...)`
|
267
282
|
* `(1..2).each {|i| ...}` becomes `for (var i=1 i<=2; i+=1)`
|
268
283
|
* `"string" * length` becomes `new Array(length + 1).join("string")`
|
269
284
|
* `.sub!` and `.gsub!` become equivalent `x = x.replace` statements
|
@@ -281,6 +296,7 @@ the script.
|
|
281
296
|
* New classes subclassed off of `Exception` will become subclassed off
|
282
297
|
of `Error` instead; and default constructors will be provided
|
283
298
|
* `loop do...end` will be replaced with `while (true) {...}`
|
299
|
+
* `raise Exception.new(...)` will be replaced with `throw new Error(...)`
|
284
300
|
|
285
301
|
Additionally, there is one mapping that will only be done if explicitly
|
286
302
|
<a href="https://github.com/rubys/ruby2js/blob/master/lib/ruby2js/filter.rb">included</a>:
|
@@ -516,6 +532,16 @@ the script.
|
|
516
532
|
* maps `export default async proc` to `module.exports = async`
|
517
533
|
* maps `export default` to `module.exports =`
|
518
534
|
|
535
|
+
* <a id="matchAll" href="https://github.com/rubys/ruby2js/blob/master/spec/matchAll">matchAll</a>
|
536
|
+
|
537
|
+
For ES level < 2020:
|
538
|
+
|
539
|
+
* maps `str.matchAll(pattern).forEach {}` to
|
540
|
+
`while (match = pattern.exec(str)) {}`
|
541
|
+
|
542
|
+
Note `pattern` must be a simple variable with a value of a regular
|
543
|
+
expression with the `g` flag set at runtime.
|
544
|
+
|
519
545
|
[Wunderbar](https://github.com/rubys/wunderbar) includes additional demos:
|
520
546
|
|
521
547
|
* [chat](https://github.com/rubys/wunderbar/blob/master/demo/chat.rb),
|
@@ -573,9 +599,11 @@ ES2017 support
|
|
573
599
|
---
|
574
600
|
|
575
601
|
When option `eslevel: 2017` is provided, the following additional
|
576
|
-
|
602
|
+
conversions are made by the `functions` filter:
|
577
603
|
|
578
|
-
* `.
|
604
|
+
* `.values()` becomes `Object.values()`
|
605
|
+
* `.entries()` becomes `Object.entries()`
|
606
|
+
* `.each_pair {}` becomes `for (let [key, value] of Object.entries()) {}'
|
579
607
|
|
580
608
|
ES2018 support
|
581
609
|
---
|
@@ -598,6 +626,7 @@ conversion is made by the `functions` filter:
|
|
598
626
|
* `.lstrip` becomes `.trimEnd
|
599
627
|
* `.rstrip` becomes `.trimStart
|
600
628
|
* `a.to_h` becomes `Object.fromEntries(a)`
|
629
|
+
* `Hash[a]` becomes `Object.fromEntries(a)`
|
601
630
|
|
602
631
|
Additionally, `rescue` without a variable will map to `catch` without a
|
603
632
|
variable.
|
@@ -606,10 +635,21 @@ ES2020 support
|
|
606
635
|
---
|
607
636
|
|
608
637
|
When option `eslevel: 2020` is provided, the following additional
|
609
|
-
|
638
|
+
conversions are made:
|
610
639
|
|
611
640
|
* `@x` becomes `this.#x`
|
612
641
|
* `@@x` becomes `ClassName.#x`
|
642
|
+
* `a&.b` becomes `a?.b`
|
643
|
+
* `.scan` becomes `Array.from(str.matchAll(/.../g), s => s.slice(1))`
|
644
|
+
|
645
|
+
ES2021 support
|
646
|
+
---
|
647
|
+
|
648
|
+
When option `eslevel: 2021` is provided, the following additional
|
649
|
+
conversions are made:
|
650
|
+
|
651
|
+
* `x ||= 1` becomes `x ||= 1`
|
652
|
+
* `x &&= 1` becomes `x &&= 1`
|
613
653
|
|
614
654
|
Picking a Ruby to JS mapping tool
|
615
655
|
---
|
data/lib/ruby2js.rb
CHANGED
@@ -94,6 +94,10 @@ module Ruby2JS
|
|
94
94
|
@options[:eslevel] >= 2020
|
95
95
|
end
|
96
96
|
|
97
|
+
def es2021
|
98
|
+
@options[:eslevel] >= 2021
|
99
|
+
end
|
100
|
+
|
97
101
|
def process(node)
|
98
102
|
ast, @ast = @ast, node
|
99
103
|
replacement = super
|
@@ -127,6 +131,9 @@ module Ruby2JS
|
|
127
131
|
def on_sendw(node); on_send(node); end
|
128
132
|
def on_undefined?(node); on_defined?(node); end
|
129
133
|
def on_nil(node); end
|
134
|
+
def on_xnode(node); end
|
135
|
+
def on_export(node); end
|
136
|
+
def on_import(node); end
|
130
137
|
|
131
138
|
# provide a method so filters can call 'super'
|
132
139
|
def on_sym(node); node; end
|
@@ -156,7 +163,7 @@ module Ruby2JS
|
|
156
163
|
|
157
164
|
if Proc === source
|
158
165
|
file,line = source.source_location
|
159
|
-
source =
|
166
|
+
source = IO.read(file)
|
160
167
|
ast, comments = parse(source)
|
161
168
|
comments = Parser::Source::Comment.associate(ast, comments) if ast
|
162
169
|
ast = find_block( ast, line )
|
@@ -169,9 +176,12 @@ module Ruby2JS
|
|
169
176
|
comments = Parser::Source::Comment.associate(ast, comments) if ast
|
170
177
|
end
|
171
178
|
|
172
|
-
filters = options[:filters] || Filter::DEFAULTS
|
179
|
+
filters = (options[:filters] || Filter::DEFAULTS)
|
173
180
|
|
174
181
|
unless filters.empty?
|
182
|
+
filters.dup.each do |filter|
|
183
|
+
filters = filter.reorder(filters) if filter.respond_to? :reorder
|
184
|
+
end
|
175
185
|
|
176
186
|
filter = Filter::Processor
|
177
187
|
filters.reverse.each do |mod|
|
@@ -189,6 +199,8 @@ module Ruby2JS
|
|
189
199
|
ruby2js.ivars = options[:ivars]
|
190
200
|
ruby2js.eslevel = options[:eslevel]
|
191
201
|
ruby2js.strict = options[:strict]
|
202
|
+
ruby2js.comparison = options[:comparison] || :equality
|
203
|
+
ruby2js.or = options[:or] || :logical
|
192
204
|
if ruby2js.binding and not ruby2js.ivars
|
193
205
|
ruby2js.ivars = ruby2js.binding.eval \
|
194
206
|
'Hash[instance_variables.map {|var| [var, instance_variable_get(var)]}]'
|
data/lib/ruby2js/converter.rb
CHANGED
@@ -28,7 +28,7 @@ module Ruby2JS
|
|
28
28
|
:=== => :'!=='
|
29
29
|
}
|
30
30
|
|
31
|
-
GROUP_OPERATORS = [:begin, :dstr, :dsym, :and, :or, :casgn]
|
31
|
+
GROUP_OPERATORS = [:begin, :dstr, :dsym, :and, :or, :casgn, :if]
|
32
32
|
|
33
33
|
VASGN = [:cvasgn, :ivasgn, :gvasgn, :lvasgn]
|
34
34
|
|
@@ -57,9 +57,12 @@ module Ruby2JS
|
|
57
57
|
@prototype = nil
|
58
58
|
@class_parent = nil
|
59
59
|
@class_name = nil
|
60
|
+
@jsx = false
|
60
61
|
|
61
62
|
@eslevel = :es5
|
62
63
|
@strict = false
|
64
|
+
@comparison = :equality
|
65
|
+
@or = :logical
|
63
66
|
end
|
64
67
|
|
65
68
|
def width=(width)
|
@@ -124,7 +127,7 @@ module Ruby2JS
|
|
124
127
|
Parser::AST::Node.new(type, args)
|
125
128
|
end
|
126
129
|
|
127
|
-
attr_accessor :strict, :eslevel
|
130
|
+
attr_accessor :strict, :eslevel, :comparison, :or
|
128
131
|
|
129
132
|
def es2015
|
130
133
|
@eslevel >= 2015
|
@@ -150,6 +153,10 @@ module Ruby2JS
|
|
150
153
|
@eslevel >= 2020
|
151
154
|
end
|
152
155
|
|
156
|
+
def es2021
|
157
|
+
@eslevel >= 2021
|
158
|
+
end
|
159
|
+
|
153
160
|
@@handlers = []
|
154
161
|
def self.handle(*types, &block)
|
155
162
|
types.each do |type|
|
@@ -238,7 +245,6 @@ module Ruby2JS
|
|
238
245
|
if ast.loc and ast.loc.expression
|
239
246
|
filename = ast.loc.expression.source_buffer.name
|
240
247
|
if filename and not filename.empty?
|
241
|
-
filename = filename.dup.untaint
|
242
248
|
@timestamps[filename] ||= File.mtime(filename)
|
243
249
|
end
|
244
250
|
end
|
@@ -307,6 +313,7 @@ require 'ruby2js/converter/for'
|
|
307
313
|
require 'ruby2js/converter/hash'
|
308
314
|
require 'ruby2js/converter/if'
|
309
315
|
require 'ruby2js/converter/in'
|
316
|
+
require 'ruby2js/converter/import'
|
310
317
|
require 'ruby2js/converter/ivar'
|
311
318
|
require 'ruby2js/converter/ivasgn'
|
312
319
|
require 'ruby2js/converter/kwbegin'
|
@@ -333,3 +340,4 @@ require 'ruby2js/converter/vasgn'
|
|
333
340
|
require 'ruby2js/converter/while'
|
334
341
|
require 'ruby2js/converter/whilepost'
|
335
342
|
require 'ruby2js/converter/xstr'
|
343
|
+
require 'ruby2js/converter/xnode'
|
@@ -9,7 +9,7 @@ module Ruby2JS
|
|
9
9
|
|
10
10
|
handle :block do |call, args, block|
|
11
11
|
|
12
|
-
if
|
12
|
+
if \
|
13
13
|
@state == :statement and args.children.length == 1 and
|
14
14
|
call.children.first and call.children.first.type == :begin and
|
15
15
|
call.children[1] == :step and
|
@@ -42,7 +42,7 @@ module Ruby2JS
|
|
42
42
|
@vars = vars if es2015
|
43
43
|
end
|
44
44
|
|
45
|
-
elsif
|
45
|
+
elsif \
|
46
46
|
call.children[0] == nil and call.children[1] == :function and
|
47
47
|
call.children[2..-1].all? do |child|
|
48
48
|
child.type == :lvar or (child.type == :send and
|
@@ -37,7 +37,7 @@ module Ruby2JS
|
|
37
37
|
body.compact!
|
38
38
|
visible = {}
|
39
39
|
body.map! do |m|
|
40
|
-
if
|
40
|
+
if \
|
41
41
|
@ast.type == :class_module and m.type == :defs and
|
42
42
|
m.children.first == s(:self)
|
43
43
|
then
|
@@ -217,7 +217,7 @@ module Ruby2JS
|
|
217
217
|
end
|
218
218
|
|
219
219
|
# collapse sequence to a single assignment
|
220
|
-
if
|
220
|
+
if \
|
221
221
|
@ast.type != :class_extend and
|
222
222
|
(methods > 1 or (methods == 1 and body[start].type == :prop))
|
223
223
|
then
|
@@ -56,10 +56,30 @@ module Ruby2JS
|
|
56
56
|
# find ivars and cvars
|
57
57
|
walk = proc do |ast|
|
58
58
|
ivars << ast.children.first if ast.type === :ivar
|
59
|
+
ivars << ast.children.first if ast.type === :ivasgn
|
59
60
|
cvars << ast.children.first if ast.type === :cvar
|
61
|
+
cvars << ast.children.first if ast.type === :cvasgn
|
62
|
+
|
60
63
|
ast.children.each do |child|
|
61
64
|
walk[child] if child.is_a? Parser::AST::Node
|
62
65
|
end
|
66
|
+
|
67
|
+
if ast.type == :send and ast.children.first == nil
|
68
|
+
if ast.children[1] == :attr_accessor
|
69
|
+
ast.children[2..-1].each_with_index do |child_sym, index2|
|
70
|
+
ivars << :"@#{child_sym.children.first}"
|
71
|
+
end
|
72
|
+
elsif ast.children[1] == :attr_reader
|
73
|
+
ast.children[2..-1].each_with_index do |child_sym, index2|
|
74
|
+
ivars << :"@#{child_sym.children.first}"
|
75
|
+
end
|
76
|
+
elsif ast.children[1] == :attr_writer
|
77
|
+
ast.children[2..-1].each_with_index do |child_sym, index2|
|
78
|
+
ivars << :"@#{child_sym.children.first}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
63
83
|
end
|
64
84
|
walk[@ast]
|
65
85
|
|
@@ -77,7 +97,7 @@ module Ruby2JS
|
|
77
97
|
cvars.to_a.sort.each do |cvar|
|
78
98
|
put(index == 0 ? @nl : @sep)
|
79
99
|
index += 1
|
80
|
-
put 'static
|
100
|
+
put 'static #$' + cvar.to_s[2..-1]
|
81
101
|
end
|
82
102
|
|
83
103
|
while constructor.length > 0 and constructor.first.type == :ivasgn
|
@@ -131,7 +151,7 @@ module Ruby2JS
|
|
131
151
|
next
|
132
152
|
end
|
133
153
|
|
134
|
-
m = m.updated(m.type, [@prop, m.children[1], *constructor])
|
154
|
+
m = m.updated(m.type, [@prop, m.children[1], s(:begin, *constructor)])
|
135
155
|
elsif not m.is_method?
|
136
156
|
@prop = "get #{@prop}"
|
137
157
|
m = m.updated(m.type, [*m.children[0..1],
|
@@ -147,12 +167,13 @@ module Ruby2JS
|
|
147
167
|
|
148
168
|
begin
|
149
169
|
@instance_method = m
|
170
|
+
@class_method = nil
|
150
171
|
parse m # unless skipped
|
151
172
|
ensure
|
152
173
|
@instance_method = nil
|
153
174
|
end
|
154
175
|
|
155
|
-
elsif
|
176
|
+
elsif \
|
156
177
|
[:defs, :asyncs].include? m.type and m.children.first.type == :self
|
157
178
|
then
|
158
179
|
|
@@ -172,27 +193,35 @@ module Ruby2JS
|
|
172
193
|
@prop.sub! 'static', 'static async' if m.type == :asyncs
|
173
194
|
|
174
195
|
m = m.updated(:def, m.children[1..3])
|
175
|
-
|
196
|
+
begin
|
197
|
+
@instance_method = nil
|
198
|
+
@class_method = m
|
199
|
+
parse m # unless skipped
|
200
|
+
ensure
|
201
|
+
@instance_method = nil
|
202
|
+
end
|
176
203
|
|
177
204
|
elsif m.type == :send and m.children.first == nil
|
205
|
+
p = es2020 ? '#' : '_'
|
206
|
+
|
178
207
|
if m.children[1] == :attr_accessor
|
179
208
|
m.children[2..-1].each_with_index do |child_sym, index2|
|
180
209
|
put @sep unless index2 == 0
|
181
210
|
var = child_sym.children.first
|
182
|
-
put "get #{var}() {#{@nl}return this
|
183
|
-
put "set #{var}(#{var}) {#{@nl}this
|
211
|
+
put "get #{var}() {#{@nl}return this.#{p}#{var}#@nl}#@sep"
|
212
|
+
put "set #{var}(#{var}) {#{@nl}this.#{p}#{var} = #{var}#@nl}"
|
184
213
|
end
|
185
214
|
elsif m.children[1] == :attr_reader
|
186
215
|
m.children[2..-1].each_with_index do |child_sym, index2|
|
187
216
|
put @sep unless index2 == 0
|
188
217
|
var = child_sym.children.first
|
189
|
-
put "get #{var}() {#{@nl}return this
|
218
|
+
put "get #{var}() {#{@nl}return this.#{p}#{var}#@nl}"
|
190
219
|
end
|
191
220
|
elsif m.children[1] == :attr_writer
|
192
221
|
m.children[2..-1].each_with_index do |child_sym, index2|
|
193
222
|
put @sep unless index2 == 0
|
194
223
|
var = child_sym.children.first
|
195
|
-
put "set #{var}(#{var}) {#{@nl}this
|
224
|
+
put "set #{var}(#{var}) {#{@nl}this.#{p}#{var} = #{var}#@nl}"
|
196
225
|
end
|
197
226
|
elsif [:private, :protected, :public].include? m.children[1]
|
198
227
|
raise Error.new("class #{m.children[1]} is not supported", @ast)
|
@@ -208,7 +237,7 @@ module Ruby2JS
|
|
208
237
|
|
209
238
|
else
|
210
239
|
if m.type == :cvasgn and es2020
|
211
|
-
put 'static
|
240
|
+
put 'static #$'; put m.children[0].to_s[2..-1]; put ' = '
|
212
241
|
parse m.children[1]
|
213
242
|
else
|
214
243
|
skipped = true
|
@@ -88,7 +88,7 @@ module Ruby2JS
|
|
88
88
|
put 'async ' if @ast.type == :async
|
89
89
|
|
90
90
|
# es2015 fat arrow support
|
91
|
-
if
|
91
|
+
if \
|
92
92
|
not name and es2015 and @state != :method and @ast.type != :defm and
|
93
93
|
not @prop
|
94
94
|
then
|
@@ -105,7 +105,7 @@ module Ruby2JS
|
|
105
105
|
else
|
106
106
|
style = :expression
|
107
107
|
end
|
108
|
-
elsif
|
108
|
+
elsif \
|
109
109
|
expr.type == :if and expr.children[1] and expr.children[2] and
|
110
110
|
EXPRESSIONS.include? expr.children[1].type and
|
111
111
|
EXPRESSIONS.include? expr.children[2].type
|
@@ -10,6 +10,13 @@ module Ruby2JS
|
|
10
10
|
# (...)
|
11
11
|
|
12
12
|
handle :for, :for_of do |var, expression, block|
|
13
|
+
if @jsx and @ast.type == :for_of
|
14
|
+
parse s(:block, s(:send, expression, :map),
|
15
|
+
s(:args, s(:arg, var.children[0])),
|
16
|
+
s(:autoreturn, block))
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
13
20
|
begin
|
14
21
|
vars = @vars.dup
|
15
22
|
next_token, @next_token = @next_token, :continue
|