Skip to content

Commit ede4dc1

Browse files
authored
Merge pull request #4967 from DanielMoss/symbol-asynciterable
Add js.Symbol.asyncIterator.
2 parents 76e3292 + 4a1e347 commit ede4dc1

File tree

2 files changed

+74
-11
lines changed

2 files changed

+74
-11
lines changed

library/src/main/scala/scala/scalajs/js/Symbol.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ object Symbol extends js.Object {
6767
*/
6868
def keyFor(sym: js.Symbol): js.UndefOr[String] = js.native
6969

70+
/** <span class="badge badge-ecma2018" style="float: right;">ECMAScript 2018</span>
71+
* The well-known symbol `@@asyncIterator`.
72+
*
73+
* @group wellknownsyms
74+
*/
75+
val asyncIterator: js.Symbol = js.native
76+
7077
/** The well-known symbol `@@hasInstance`.
7178
*
7279
* @group wellknownsyms

test-suite/js/src/test/scala/org/scalajs/testsuite/jsinterop/JSSymbolTest.scala

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package org.scalajs.testsuite.jsinterop
1414

1515
import scala.scalajs.js
16+
import scala.scalajs.js.|
1617
import scala.scalajs.js.annotation._
1718

1819
import org.junit.Assert._
@@ -251,6 +252,17 @@ class JSSymbolTest {
251252
assertArrayEquals(Array(532), content.result())
252253
}
253254

255+
@Test def sjsdefinedAsyncIterable(): Unit = {
256+
PromiseMock.withMockedPromise { processQueue =>
257+
val obj = new SJSDefinedAsyncIterable
258+
259+
val content = Array.newBuilder[Int]
260+
iterateAsyncIterable(obj)(content += _)
261+
processQueue()
262+
assertArrayEquals(Array(278), content.result())
263+
}
264+
}
265+
254266
@Test def inOperatorWithSymbols(): Unit = {
255267
val obj = mkObject(sym1 -> "foo")
256268

@@ -304,26 +316,40 @@ object JSSymbolTest {
304316
def callSymbol(sym: js.Symbol)(args: js.Any*): Any = js.native
305317
}
306318

307-
def singletonIterator(singleton: Any): js.Dynamic = {
308-
var first = true
319+
def singletonIterator(singleton: Any): js.Dynamic =
320+
js.Dynamic.literal(next = singletonIteratorLogic(singleton))
321+
322+
def singletonAsyncIterator(singleton: Any): js.Dynamic = {
323+
val logic = singletonIteratorLogic(singleton)
309324
js.Dynamic.literal(
310-
next = { () =>
311-
if (first) {
312-
first = false
313-
js.Dynamic.literal(value = singleton.asInstanceOf[js.Any],
314-
done = false)
315-
} else {
316-
js.Dynamic.literal(value = (), done = true)
317-
}
318-
}
325+
next = { () =>
326+
new js.Promise[js.Dynamic]({
327+
(resolve: js.Function1[js.Dynamic | js.Thenable[js.Dynamic], _], reject: js.Function1[Any, _]) =>
328+
resolve(logic())
329+
})
330+
}
319331
)
320332
}
321333

334+
def singletonIteratorLogic(singleton: Any): () => js.Dynamic = {
335+
var first = true
336+
337+
{ () =>
338+
if (first) {
339+
first = false
340+
js.Dynamic.literal(value = singleton.asInstanceOf[js.Any], done = false)
341+
} else {
342+
js.Dynamic.literal(value = (), done = true)
343+
}
344+
}
345+
}
346+
322347
def iterableToArray[A](iterable: JSIterable[A]): js.Array[A] =
323348
js.constructorOf[js.Array[_]].from(iterable).asInstanceOf[js.Array[A]]
324349

325350
def iterateIterable[A](iterable: JSIterable[A])(f: A => Any): Unit = {
326351
val iterator = iterable.iterator()
352+
327353
def loop(): Unit = {
328354
import js.DynamicImplicits.truthValue
329355

@@ -333,6 +359,26 @@ object JSSymbolTest {
333359
loop()
334360
}
335361
}
362+
363+
loop()
364+
}
365+
366+
def iterateAsyncIterable[A](
367+
iterable: JSAsyncIterable[A])(f: A => Any): Unit = {
368+
val iterator = iterable.asyncIterator()
369+
370+
def loop(): Unit = {
371+
import js.DynamicImplicits.truthValue
372+
373+
val pEntry = iterator.next().asInstanceOf[js.Promise[js.Dynamic]]
374+
pEntry.`then`[Unit] { (entry: js.Dynamic) =>
375+
if (!entry.done) {
376+
f(entry.value.asInstanceOf[A])
377+
loop()
378+
}
379+
}
380+
}
381+
336382
loop()
337383
}
338384

@@ -512,4 +558,14 @@ object JSSymbolTest {
512558
@JSName(js.Symbol.iterator)
513559
def iterator(): js.Dynamic = singletonIterator(532)
514560
}
561+
562+
trait JSAsyncIterable[+A] extends js.Object {
563+
@JSName(js.Symbol.asyncIterator)
564+
def asyncIterator(): js.Dynamic
565+
}
566+
567+
class SJSDefinedAsyncIterable extends JSAsyncIterable[Int] {
568+
@JSName(js.Symbol.asyncIterator)
569+
def asyncIterator(): js.Dynamic = singletonAsyncIterator(278)
570+
}
515571
}

0 commit comments

Comments
 (0)