From 05a0a12d7ca76daf95be399aa58f422d2de403c1 Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Wed, 10 Nov 2021 18:57:01 +0200 Subject: [PATCH 01/13] WIP --- .../org/scalajs/dom/ReadableStream.scala | 7 ++- .../dom/ReadableStreamController.scala | 6 +- .../dom/ReadableStreamQueuingStrategy.scala | 23 +++++++ .../scalajs/dom/ReadableStreamReader.scala | 5 +- .../org/scalajs/dom/ReadableStreamType.scala | 11 ++++ .../dom/ReadableStreamUnderlyingSource.scala | 60 +++++++++++++++++++ .../main/scala/org/scalajs/dom/package.scala | 4 +- .../dom/tests/shared/SharedTests.scala | 46 +++++++++++++- 8 files changed, 150 insertions(+), 12 deletions(-) create mode 100644 dom/src/main/scala/org/scalajs/dom/ReadableStreamQueuingStrategy.scala create mode 100644 dom/src/main/scala/org/scalajs/dom/ReadableStreamType.scala create mode 100644 dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala index df6ffeb54..6d6abee7e 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala @@ -1,6 +1,7 @@ package org.scalajs.dom import scala.scalajs.js +import scala.scalajs.js.annotation.JSGlobal /** defined at [[https://streams.spec.whatwg.org/#readable-stream ¶2.1. Readable Streams]] of whatwg Streams spec. * @@ -8,7 +9,11 @@ import scala.scalajs.js * Type of the Chunks returned by the Stream. Can't make it coveriant, due to T */ @js.native -trait ReadableStream[+T] extends js.Object { +@JSGlobal +class ReadableStream[+T]( + underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]], + queuingStrategy: js.UndefOr[ReadableStreamQueuingStrategy[T]] = js.undefined +) extends js.Object { /** The locked getter returns whether or not the readable stream is locked to a reader. * diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala index 55e7106d5..6994ceb75 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala @@ -1,7 +1,6 @@ package org.scalajs.dom import scala.scalajs.js -import scala.scalajs.js.annotation._ /** [[https://streams.spec.whatwg.org/#rs-controller-class ¶3.3 Class ReadableStreamController]] of whatwg spec * @@ -14,8 +13,7 @@ import scala.scalajs.js.annotation._ * Type of the Chunks to be enqueued to the Stream */ @js.native -@JSGlobal -class ReadableStreamController[-T](stream: ReadableStream[T] = null) extends js.Object { +trait ReadableStreamController[-T] extends js.Object { /** The desiredSize getter returns the desired size to fill the controlled stream’s internal queue. It can be * negative, if the queue is over-full. An underlying source should use this information to determine when and how to @@ -39,7 +37,7 @@ class ReadableStreamController[-T](stream: ReadableStream[T] = null) extends js. * @return * seems like its an undefOr[Int] of the size */ - def enqueue(chunk: Chunk[T]): js.UndefOr[Int] = js.native + def enqueue(chunk: T): js.UndefOr[Int] = js.native /** The error method will error the readable stream, making all future interactions with it fail with the given error * e. diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamQueuingStrategy.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamQueuingStrategy.scala new file mode 100644 index 000000000..7957935fc --- /dev/null +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamQueuingStrategy.scala @@ -0,0 +1,23 @@ +package org.scalajs.dom + +import scala.scalajs.js + +/** See [[https://streams.spec.whatwg.org/#qs-api ¶7.1. The queuing strategy API]] + * + * @tparam T + * Type of the Chunks returned by the Stream + */ +trait ReadableStreamQueuingStrategy[T] extends js.Object { + + /** A non-negative number indicating the high water mark of the stream using this queuing strategy. */ + var highWaterMark: Double + + /** (non-byte streams only) + * + * The result is used to determine backpressure, manifesting via the appropriate desiredSize property. For readable + * streams, it also governs when the underlying source's [[ReadableStreamUnderlyingSource.pull]] method is called. + * + * A function that computes and returns the finite non-negative size of the given chunk value. + */ + var size: js.Function1[Chunk[T], Unit] +} diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala index adf996e55..7de143bb8 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala @@ -30,11 +30,8 @@ class ReadableStreamReader[+T](stream: ReadableStream[T]) extends js.Object { * * If the reader is active, the cancel method behaves the same as that for the associated stream. When done, it * automatically releases the lock. - * - * //todo determine type of reason */ - // not actually sure what the return type is here - def cancel(reason: Any): js.Promise[Any] = js.native + def cancel[U](reason: js.UndefOr[U]): js.Promise[U] = js.native /** See [[https://streams.spec.whatwg.org/#reader-read 3.4.4.3. read()]] of whatwg Stream spec. * diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamType.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamType.scala new file mode 100644 index 000000000..6578fbc82 --- /dev/null +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamType.scala @@ -0,0 +1,11 @@ +package org.scalajs.dom + +import scala.scalajs.js + +/** [[https://streams.spec.whatwg.org/#enumdef-readablestreamtype ReadableStreamType enum]] */ +@js.native +sealed trait ReadableStreamType extends js.Any + +object ReadableStreamType { + val bytes: ReadableStreamType = "bytes".asInstanceOf[ReadableStreamType] +} diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala new file mode 100644 index 000000000..6961594f5 --- /dev/null +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala @@ -0,0 +1,60 @@ +package org.scalajs.dom + +import scala.scalajs.js +import scala.scalajs.js.| + +/** See [[https://streams.spec.whatwg.org/#underlying-source-api ¶4.2.3. The underlying source API]] of whatwg streams + * spec. + * + * @tparam T + * Type of the Chunks returned by the Stream + */ +trait ReadableStreamUnderlyingSource[T] extends js.Object { + + /** A function that is called immediately during creation of the ReadableStream. + * + * If this setup process is asynchronous, it can return a promise to signal success or failure; a rejected promise + * will error the stream. Any thrown exceptions will be re-thrown by the [[ReadableStream]] constructor. + */ + var start: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] = js.undefined + + /** A function that is called whenever the stream’s internal queue of chunks becomes not full, i.e. whenever the + * queue’s desired size becomes positive. Generally, it will be called repeatedly until the queue reaches its high + * water mark (i.e. until the desired size becomes non-positive). + * + * This function will not be called until [[start]] successfully completes. Additionally, it will only be called + * repeatedly if it enqueues at least one chunk or fulfills a BYOB request; a no-op [[pull]] implementation will not + * be continually called. + * + * If the function returns a promise, then it will not be called again until that promise fulfills. (If the promise + * rejects, the stream will become errored.) This is mainly used in the case of pull sources, where the promise + * returned represents the process of acquiring a new chunk. Throwing an exception is treated the same as returning a + * rejected promise. + */ + var pull: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] = js.undefined + + /** A function that is called whenever the consumer cancels the stream, via [[ReadableStream.cancel]] or + * [[ReadableStreamReader.cancel]]. It takes as its argument the same value as was passed to those methods by the + * consumer. + * + * If the shutdown process is asynchronous, it can return a promise to signal success or failure; the result will be + * communicated via the return value of the [[cancel]] method that was called. Additionally, a rejected promise will + * error the stream, instead of letting it close. Throwing an exception is treated the same as returning a rejected + * promise. + */ + var cancel: js.UndefOr[js.Function1[js.Any, Unit | js.Promise[Unit]]] = js.undefined + + /** Can be set to "bytes" to signal that the constructed [[ReadableStream]] is a readable byte stream. + * + * Setting any value other than "bytes" or undefined will cause the ReadableStream() constructor to throw an + * exception. + */ + var `type`: js.UndefOr[ReadableStreamType] = js.undefined + + /** (byte streams only) + * + * Can be set to a positive integer to cause the implementation to automatically allocate buffers for the underlying + * source code to write into. + */ + var autoAllocateChunkSize: js.UndefOr[Double] = js.undefined +} diff --git a/dom/src/main/scala/org/scalajs/dom/package.scala b/dom/src/main/scala/org/scalajs/dom/package.scala index 6ed863024..caeea520b 100644 --- a/dom/src/main/scala/org/scalajs/dom/package.scala +++ b/dom/src/main/scala/org/scalajs/dom/package.scala @@ -2,7 +2,7 @@ package org.scalajs import scala.scalajs.js import scala.scalajs.js.annotation._ -import scala.scalajs.js.typedarray.{ArrayBuffer, ArrayBufferView} +import scala.scalajs.js.typedarray.{ArrayBuffer, ArrayBufferView, Uint8Array} import scala.scalajs.js.| package object dom { @@ -32,7 +32,7 @@ package object dom { /** defined at [[https://fetch.spec.whatwg.org/#body-mixin ¶6.2 Body mixin]] in whatwg Fetch spec */ type BodyInit = - Blob | BufferSource | FormData | String // todo: add URLSearchParams + Blob | BufferSource | FormData | String | ReadableStream[Uint8Array] // todo: add URLSearchParams /** WebIDL sequence is js.Array[T] | JSIterable[T]. However @mseddon knows at least Blink's IDL compiler treats * these as simply js.Array[T] for now. We keep this type as a reminder to check in more detail diff --git a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala index 3a02babea..4578d0349 100644 --- a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala +++ b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala @@ -1,7 +1,13 @@ package org.scalajs.dom.tests.shared -import org.scalajs.dom.tests.shared.AsyncTesting._ +import org.junit.Assert.assertEquals import org.junit.Test +import org.scalajs.dom.tests.shared.AsyncTesting._ + +import scala.concurrent.Future +import scala.scalajs.js +import scala.scalajs.js.Thenable.Implicits._ +import scala.scalajs.js.| trait SharedTests { @@ -36,4 +42,42 @@ trait SharedTests { @Test final def WindowIdbTest(): AsyncResult = IdbTest(window.indexedDB) + + @Test + final def ReadableStreamTest: AsyncResult = async { + case class Tuna(color: String) + + val expectedTunas = Seq( + Tuna("blue"), + Tuna("red") + ) + + val stream = new ReadableStream[Tuna]( + new ReadableStreamUnderlyingSource[Tuna] { + start = { controller: ReadableStreamController[Tuna] => + controller.enqueue(Tuna("blue")) + controller.enqueue(Tuna("red")) + controller.close() + }.asInstanceOf[js.UndefOr[js.Function1[ReadableStreamController[Tuna], Unit | js.Promise[Unit]]]] + } + ) + + val reader = stream.getReader() + + def read(tunas: Seq[Tuna]): Future[Seq[Tuna]] = { + reader + .read() + .flatMap { chunk => + if (chunk.done) { + Future.successful(tunas) + } else { + read(tunas :+ chunk.value) + } + } + } + read(Seq.empty) + .map { receivedTunas => + assertEquals(receivedTunas, expectedTunas) + } + } } From 6c5a02fc2c46935c13e32e896988ae25a9a2e590 Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Thu, 11 Nov 2021 17:17:49 +0200 Subject: [PATCH 02/13] Fix ReadableStream binary compatibility and test compilation. --- .../org/scalajs/dom/ReadableStream.scala | 22 ++++++++++++++----- .../dom/tests/shared/SharedTests.scala | 7 +++--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala index 6d6abee7e..8d280e97f 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala @@ -1,7 +1,6 @@ package org.scalajs.dom import scala.scalajs.js -import scala.scalajs.js.annotation.JSGlobal /** defined at [[https://streams.spec.whatwg.org/#readable-stream ¶2.1. Readable Streams]] of whatwg Streams spec. * @@ -9,11 +8,7 @@ import scala.scalajs.js.annotation.JSGlobal * Type of the Chunks returned by the Stream. Can't make it coveriant, due to T */ @js.native -@JSGlobal -class ReadableStream[+T]( - underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]], - queuingStrategy: js.UndefOr[ReadableStreamQueuingStrategy[T]] = js.undefined -) extends js.Object { +trait ReadableStream[+T] extends js.Object { /** The locked getter returns whether or not the readable stream is locked to a reader. * @@ -97,3 +92,18 @@ class ReadableStream[+T]( */ def tee(): js.Array[_ <: ReadableStream[T]] = js.native // TODO js.Tuple2[ReadableStream[T], ReadableStream[T]] } + +object ReadableStream { + + def apply[T]( + underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]], + queuingStrategy: js.UndefOr[ReadableStreamQueuingStrategy[T]] = js.undefined + ): ReadableStream[T] = { + js.Dynamic + .newInstance(js.Dynamic.global.selectDynamic("ReadableStream"))( + underlyingSource.asInstanceOf[js.Any], + queuingStrategy.asInstanceOf[js.Any] + ) + .asInstanceOf[ReadableStream[T]] + } +} diff --git a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala index 4578d0349..ffdd5f8a2 100644 --- a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala +++ b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala @@ -7,7 +7,6 @@ import org.scalajs.dom.tests.shared.AsyncTesting._ import scala.concurrent.Future import scala.scalajs.js import scala.scalajs.js.Thenable.Implicits._ -import scala.scalajs.js.| trait SharedTests { @@ -52,13 +51,13 @@ trait SharedTests { Tuna("red") ) - val stream = new ReadableStream[Tuna]( + val stream = ReadableStream[Tuna]( new ReadableStreamUnderlyingSource[Tuna] { - start = { controller: ReadableStreamController[Tuna] => + start = { (controller: ReadableStreamController[Tuna]) => controller.enqueue(Tuna("blue")) controller.enqueue(Tuna("red")) controller.close() - }.asInstanceOf[js.UndefOr[js.Function1[ReadableStreamController[Tuna], Unit | js.Promise[Unit]]]] + }: js.Function1[ReadableStreamController[Tuna], Unit] } ) From 7c149c87b2afd37489b1176ba5f37194a42ea637 Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Thu, 11 Nov 2021 20:12:28 +0200 Subject: [PATCH 03/13] WIP --- .../org/scalajs/dom/ReadableStreamType.scala | 2 +- .../org/scalajs/dom/ReadableStreamType.scala | 7 +++ .../dom/ReadableStreamController.scala | 4 +- .../scalajs/dom/ReadableStreamReader.scala | 3 +- .../dom/tests/chrome/ChromeTests.scala | 2 +- .../dom/tests/firefox/FirefoxTests.scala | 2 +- .../dom/tests/shared/BrowserTests.scala | 55 +++++++++++++++++++ .../dom/tests/shared/SharedTests.scala | 45 +-------------- 8 files changed, 71 insertions(+), 49 deletions(-) rename dom/src/main/{scala => scala-2}/org/scalajs/dom/ReadableStreamType.scala (99%) create mode 100644 dom/src/main/scala-3/org/scalajs/dom/ReadableStreamType.scala create mode 100644 tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamType.scala b/dom/src/main/scala-2/org/scalajs/dom/ReadableStreamType.scala similarity index 99% rename from dom/src/main/scala/org/scalajs/dom/ReadableStreamType.scala rename to dom/src/main/scala-2/org/scalajs/dom/ReadableStreamType.scala index 6578fbc82..0f622a271 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamType.scala +++ b/dom/src/main/scala-2/org/scalajs/dom/ReadableStreamType.scala @@ -8,4 +8,4 @@ sealed trait ReadableStreamType extends js.Any object ReadableStreamType { val bytes: ReadableStreamType = "bytes".asInstanceOf[ReadableStreamType] -} +} \ No newline at end of file diff --git a/dom/src/main/scala-3/org/scalajs/dom/ReadableStreamType.scala b/dom/src/main/scala-3/org/scalajs/dom/ReadableStreamType.scala new file mode 100644 index 000000000..c19fb3d14 --- /dev/null +++ b/dom/src/main/scala-3/org/scalajs/dom/ReadableStreamType.scala @@ -0,0 +1,7 @@ +package org.scalajs.dom + +opaque type ReadableStreamType <: String = String + +object ReadableStreamType { + val bytes: ReadableStreamType = "bytes" +} diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala index 6994ceb75..6f451317a 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala @@ -1,6 +1,7 @@ package org.scalajs.dom import scala.scalajs.js +import scala.scalajs.js.annotation.JSGlobal /** [[https://streams.spec.whatwg.org/#rs-controller-class ¶3.3 Class ReadableStreamController]] of whatwg spec * @@ -13,7 +14,8 @@ import scala.scalajs.js * Type of the Chunks to be enqueued to the Stream */ @js.native -trait ReadableStreamController[-T] extends js.Object { +@JSGlobal +class ReadableStreamController[-T] private[this] (stream: ReadableStream[T] = null) extends js.Object { /** The desiredSize getter returns the desired size to fill the controlled stream’s internal queue. It can be * negative, if the queue is over-full. An underlying source should use this information to determine when and how to diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala index 7de143bb8..2e02599bb 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala @@ -31,7 +31,8 @@ class ReadableStreamReader[+T](stream: ReadableStream[T]) extends js.Object { * If the reader is active, the cancel method behaves the same as that for the associated stream. When done, it * automatically releases the lock. */ - def cancel[U](reason: js.UndefOr[U]): js.Promise[U] = js.native + def cancel[U](reason: U): js.Promise[U] = js.native + def cancel(): js.Promise[Unit] = js.native /** See [[https://streams.spec.whatwg.org/#reader-read 3.4.4.3. read()]] of whatwg Stream spec. * diff --git a/tests-chrome/src/test/scala/org/scalajs/dom/tests/chrome/ChromeTests.scala b/tests-chrome/src/test/scala/org/scalajs/dom/tests/chrome/ChromeTests.scala index 9a4e5e267..b91a6cff8 100644 --- a/tests-chrome/src/test/scala/org/scalajs/dom/tests/chrome/ChromeTests.scala +++ b/tests-chrome/src/test/scala/org/scalajs/dom/tests/chrome/ChromeTests.scala @@ -3,4 +3,4 @@ package org.scalajs.dom.tests.chrome import org.scalajs.dom.tests.shared._ import org.scalajs.dom.tests.webworker._ -class ChromeTests extends SharedTests with WebWorkerTests \ No newline at end of file +class ChromeTests extends SharedTests with WebWorkerTests with BrowserTests \ No newline at end of file diff --git a/tests-firefox/src/test/scala/org/scalajs/dom/tests/firefox/FirefoxTests.scala b/tests-firefox/src/test/scala/org/scalajs/dom/tests/firefox/FirefoxTests.scala index 1a8735389..d877f8b79 100644 --- a/tests-firefox/src/test/scala/org/scalajs/dom/tests/firefox/FirefoxTests.scala +++ b/tests-firefox/src/test/scala/org/scalajs/dom/tests/firefox/FirefoxTests.scala @@ -3,4 +3,4 @@ package org.scalajs.dom.tests.firefox import org.scalajs.dom.tests.shared._ import org.scalajs.dom.tests.webworker._ -class FirefoxTests extends SharedTests with WebWorkerTests \ No newline at end of file +class FirefoxTests extends SharedTests with WebWorkerTests with BrowserTests \ No newline at end of file diff --git a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala new file mode 100644 index 000000000..0e0c67e75 --- /dev/null +++ b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala @@ -0,0 +1,55 @@ +package org.scalajs.dom.tests.shared + +import org.junit.Assert.assertEquals +import org.junit.Test +import org.scalajs.dom.ReadableStream +import org.scalajs.dom.ReadableStreamController +import org.scalajs.dom.ReadableStreamUnderlyingSource +import org.scalajs.dom.tests.shared.AsyncTesting.AsyncResult +import org.scalajs.dom.tests.shared.AsyncTesting._ +import org.scalajs.dom.tests.shared.AsyncTesting.async + +import scala.concurrent.Future +import scala.scalajs.js +import scala.scalajs.js.Thenable.Implicits._ + +trait BrowserTests { + + @Test + final def ReadableStreamTest: AsyncResult = async { + case class Tuna(color: String) + + val expectedTunas = Seq( + Tuna("blue"), + Tuna("red") + ) + + val stream = ReadableStream[Tuna]( + new ReadableStreamUnderlyingSource[Tuna] { + start = { (controller: ReadableStreamController[Tuna]) => + controller.enqueue(Tuna("blue")) + controller.enqueue(Tuna("red")) + controller.close() + }: js.Function1[ReadableStreamController[Tuna], Unit] + } + ) + + val reader = stream.getReader() + + def read(tunas: Seq[Tuna]): Future[Seq[Tuna]] = { + reader + .read() + .flatMap { chunk => + if (chunk.done) { + Future.successful(tunas) + } else { + read(tunas :+ chunk.value) + } + } + } + read(Seq.empty) + .map { receivedTunas => + assertEquals(receivedTunas, expectedTunas) + } + } +} diff --git a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala index ffdd5f8a2..3a02babea 100644 --- a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala +++ b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/SharedTests.scala @@ -1,12 +1,7 @@ package org.scalajs.dom.tests.shared -import org.junit.Assert.assertEquals -import org.junit.Test import org.scalajs.dom.tests.shared.AsyncTesting._ - -import scala.concurrent.Future -import scala.scalajs.js -import scala.scalajs.js.Thenable.Implicits._ +import org.junit.Test trait SharedTests { @@ -41,42 +36,4 @@ trait SharedTests { @Test final def WindowIdbTest(): AsyncResult = IdbTest(window.indexedDB) - - @Test - final def ReadableStreamTest: AsyncResult = async { - case class Tuna(color: String) - - val expectedTunas = Seq( - Tuna("blue"), - Tuna("red") - ) - - val stream = ReadableStream[Tuna]( - new ReadableStreamUnderlyingSource[Tuna] { - start = { (controller: ReadableStreamController[Tuna]) => - controller.enqueue(Tuna("blue")) - controller.enqueue(Tuna("red")) - controller.close() - }: js.Function1[ReadableStreamController[Tuna], Unit] - } - ) - - val reader = stream.getReader() - - def read(tunas: Seq[Tuna]): Future[Seq[Tuna]] = { - reader - .read() - .flatMap { chunk => - if (chunk.done) { - Future.successful(tunas) - } else { - read(tunas :+ chunk.value) - } - } - } - read(Seq.empty) - .map { receivedTunas => - assertEquals(receivedTunas, expectedTunas) - } - } } From d3b38eda21af3603494e85e36ec8a1a57ba473a9 Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Thu, 11 Nov 2021 20:28:43 +0200 Subject: [PATCH 04/13] Fix casts in ReadableStream tests for Scala 2.12. --- .../scala/org/scalajs/dom/tests/shared/BrowserTests.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala index 0e0c67e75..b748178a8 100644 --- a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala +++ b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala @@ -12,6 +12,7 @@ import org.scalajs.dom.tests.shared.AsyncTesting.async import scala.concurrent.Future import scala.scalajs.js import scala.scalajs.js.Thenable.Implicits._ +import scala.scalajs.js.| trait BrowserTests { @@ -26,11 +27,11 @@ trait BrowserTests { val stream = ReadableStream[Tuna]( new ReadableStreamUnderlyingSource[Tuna] { - start = { (controller: ReadableStreamController[Tuna]) => + start = js.defined({ (controller: ReadableStreamController[Tuna]) => controller.enqueue(Tuna("blue")) controller.enqueue(Tuna("red")) controller.close() - }: js.Function1[ReadableStreamController[Tuna], Unit] + }): js.UndefOr[js.Function1[ReadableStreamController[Tuna], Unit | js.Promise[Unit]]] } ) From 5d11d2cd16addfd8d341ccf410bdffc5af00aa7d Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Thu, 11 Nov 2021 23:13:27 +0200 Subject: [PATCH 05/13] Fix scaladoc for ReadableStreamReader.cancel overloads. --- .../scalajs/dom/ReadableStreamUnderlyingSource.scala | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala index 6961594f5..b0f7410b5 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala @@ -34,13 +34,11 @@ trait ReadableStreamUnderlyingSource[T] extends js.Object { var pull: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] = js.undefined /** A function that is called whenever the consumer cancels the stream, via [[ReadableStream.cancel]] or - * [[ReadableStreamReader.cancel]]. It takes as its argument the same value as was passed to those methods by the - * consumer. - * - * If the shutdown process is asynchronous, it can return a promise to signal success or failure; the result will be - * communicated via the return value of the [[cancel]] method that was called. Additionally, a rejected promise will - * error the stream, instead of letting it close. Throwing an exception is treated the same as returning a rejected - * promise. + * [[ReadableStreamReader.cancel():scala\.scalajs\.js\.Promise[Unit]*]]. It takes as its argument the same value as + * was passed to those methods by the consumer. If the shutdown process is asynchronous, it can return a promise to + * signal success or failure; the result will be communicated via the return value of the [[cancel]] method that was + * called. Additionally, a rejected promise will error the stream, instead of letting it close. Throwing an exception + * is treated the same as returning a rejected promise. */ var cancel: js.UndefOr[js.Function1[js.Any, Unit | js.Promise[Unit]]] = js.undefined From 6b7ab22d76fb03e90408bef5b3baaa8d37b04049 Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Thu, 11 Nov 2021 23:22:05 +0200 Subject: [PATCH 06/13] Fix type casts for Scala 2.11. --- .../main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala index b748178a8..2843b9ec7 100644 --- a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala +++ b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala @@ -30,7 +30,7 @@ trait BrowserTests { start = js.defined({ (controller: ReadableStreamController[Tuna]) => controller.enqueue(Tuna("blue")) controller.enqueue(Tuna("red")) - controller.close() + controller.close(): Unit | js.Promise[Unit] }): js.UndefOr[js.Function1[ReadableStreamController[Tuna], Unit | js.Promise[Unit]]] } ) From 2c54ad61f87d9ae706af27799998585b64753e4a Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Thu, 11 Nov 2021 23:36:14 +0200 Subject: [PATCH 07/13] Generate api-reports. --- api-reports/2_12.txt | 17 ++++++++++++++--- api-reports/2_13.txt | 17 ++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/api-reports/2_12.txt b/api-reports/2_12.txt index c2887d6c2..b53ecdde1 100644 --- a/api-reports/2_12.txt +++ b/api-reports/2_12.txt @@ -15851,14 +15851,25 @@ ReadableStream[JT] def locked: Boolean ReadableStream[JT] def pipeThrough[U](pair: Any, options: Any?): ReadableStream[U] ReadableStream[JT] def pipeTo(dest: WriteableStream[T], options: Any?): Unit ReadableStream[JT] def tee(): js.Array[_ <: ReadableStream[T]] +ReadableStream[SO] def apply[T](underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]], queuingStrategy: js.UndefOr[ReadableStreamQueuingStrategy[T]]?): ReadableStream[T] ReadableStreamController[JC] def close(): Unit ReadableStreamController[JC] def desiredSize: Int -ReadableStreamController[JC] def enqueue(chunk: Chunk[T]): js.UndefOr[Int] +ReadableStreamController[JC] def enqueue(chunk: T): js.UndefOr[Int] ReadableStreamController[JC] def error(e: Any): Unit -ReadableStreamReader[JC] def cancel(reason: Any): js.Promise[Any] +ReadableStreamQueuingStrategy[JT] var highWaterMark: Double +ReadableStreamQueuingStrategy[JT] var size: js.Function1[Chunk[T], Unit] +ReadableStreamReader[JC] def cancel(): js.Promise[Unit] +ReadableStreamReader[JC] def cancel[U](reason: U): js.Promise[U] ReadableStreamReader[JC] def closed: js.Promise[ReadableStreamReader[T]] ReadableStreamReader[JC] def read(): js.Promise[Chunk[T]] ReadableStreamReader[JC] def releaseLock(): Unit +ReadableStreamType[JT] +ReadableStreamType[SO] val bytes: ReadableStreamType +ReadableStreamUnderlyingSource[JT] var autoAllocateChunkSize: js.UndefOr[Double] +ReadableStreamUnderlyingSource[JT] var cancel: js.UndefOr[js.Function1[js.Any, Unit | js.Promise[Unit]]] +ReadableStreamUnderlyingSource[JT] var pull: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] +ReadableStreamUnderlyingSource[JT] var start: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] +ReadableStreamUnderlyingSource[JT] var `type`: js.UndefOr[ReadableStreamType] ReferrerPolicy[JT] ReferrerPolicy[SO] val empty: ReferrerPolicy ReferrerPolicy[SO] val `no-referrer` = "no-referrer".asInstanceOf[ReferrerPolicy] @@ -25958,7 +25969,7 @@ intl/NumberFormatOptions[JT] var useGrouping: js.UndefOr[Boolean] intl/NumberFormatOptions[SO] def apply(localeMatcher: js.UndefOr[String]?, style: js.UndefOr[String]?, currency: js.UndefOr[String]?, currencyDisplay: js.UndefOr[String]?, useGrouping: js.UndefOr[Boolean]?, minimumIntegerDigits: js.UndefOr[Double]?, minimumFractionDigits: js.UndefOr[Double]?, maximumFractionDigits: js.UndefOr[Double]?, minimumSignificantDigits: js.UndefOr[Double]?, maximumSignificantDigits: js.UndefOr[Double]?): NumberFormatOptions (@deprecated in 2.0.0) package[SO] type AlgorithmIdentifier = Algorithm | String package[SO] type BigInteger = js.typedarray.Uint8Array -package[SO] type BodyInit = Blob | BufferSource | FormData | String +package[SO] type BodyInit = Blob | BufferSource | FormData | String | ReadableStream[Uint8Array] package[SO] type BufferSource = ArrayBufferView | ArrayBuffer package[SO] type ByteString = String package[SO] type ClientRect = DOMRect (@deprecated in 2.0.0) diff --git a/api-reports/2_13.txt b/api-reports/2_13.txt index c2887d6c2..b53ecdde1 100644 --- a/api-reports/2_13.txt +++ b/api-reports/2_13.txt @@ -15851,14 +15851,25 @@ ReadableStream[JT] def locked: Boolean ReadableStream[JT] def pipeThrough[U](pair: Any, options: Any?): ReadableStream[U] ReadableStream[JT] def pipeTo(dest: WriteableStream[T], options: Any?): Unit ReadableStream[JT] def tee(): js.Array[_ <: ReadableStream[T]] +ReadableStream[SO] def apply[T](underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]], queuingStrategy: js.UndefOr[ReadableStreamQueuingStrategy[T]]?): ReadableStream[T] ReadableStreamController[JC] def close(): Unit ReadableStreamController[JC] def desiredSize: Int -ReadableStreamController[JC] def enqueue(chunk: Chunk[T]): js.UndefOr[Int] +ReadableStreamController[JC] def enqueue(chunk: T): js.UndefOr[Int] ReadableStreamController[JC] def error(e: Any): Unit -ReadableStreamReader[JC] def cancel(reason: Any): js.Promise[Any] +ReadableStreamQueuingStrategy[JT] var highWaterMark: Double +ReadableStreamQueuingStrategy[JT] var size: js.Function1[Chunk[T], Unit] +ReadableStreamReader[JC] def cancel(): js.Promise[Unit] +ReadableStreamReader[JC] def cancel[U](reason: U): js.Promise[U] ReadableStreamReader[JC] def closed: js.Promise[ReadableStreamReader[T]] ReadableStreamReader[JC] def read(): js.Promise[Chunk[T]] ReadableStreamReader[JC] def releaseLock(): Unit +ReadableStreamType[JT] +ReadableStreamType[SO] val bytes: ReadableStreamType +ReadableStreamUnderlyingSource[JT] var autoAllocateChunkSize: js.UndefOr[Double] +ReadableStreamUnderlyingSource[JT] var cancel: js.UndefOr[js.Function1[js.Any, Unit | js.Promise[Unit]]] +ReadableStreamUnderlyingSource[JT] var pull: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] +ReadableStreamUnderlyingSource[JT] var start: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] +ReadableStreamUnderlyingSource[JT] var `type`: js.UndefOr[ReadableStreamType] ReferrerPolicy[JT] ReferrerPolicy[SO] val empty: ReferrerPolicy ReferrerPolicy[SO] val `no-referrer` = "no-referrer".asInstanceOf[ReferrerPolicy] @@ -25958,7 +25969,7 @@ intl/NumberFormatOptions[JT] var useGrouping: js.UndefOr[Boolean] intl/NumberFormatOptions[SO] def apply(localeMatcher: js.UndefOr[String]?, style: js.UndefOr[String]?, currency: js.UndefOr[String]?, currencyDisplay: js.UndefOr[String]?, useGrouping: js.UndefOr[Boolean]?, minimumIntegerDigits: js.UndefOr[Double]?, minimumFractionDigits: js.UndefOr[Double]?, maximumFractionDigits: js.UndefOr[Double]?, minimumSignificantDigits: js.UndefOr[Double]?, maximumSignificantDigits: js.UndefOr[Double]?): NumberFormatOptions (@deprecated in 2.0.0) package[SO] type AlgorithmIdentifier = Algorithm | String package[SO] type BigInteger = js.typedarray.Uint8Array -package[SO] type BodyInit = Blob | BufferSource | FormData | String +package[SO] type BodyInit = Blob | BufferSource | FormData | String | ReadableStream[Uint8Array] package[SO] type BufferSource = ArrayBufferView | ArrayBuffer package[SO] type ByteString = String package[SO] type ClientRect = DOMRect (@deprecated in 2.0.0) From 1620172be49b412d21a3cc03b010310b81b93c4a Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Fri, 12 Nov 2021 13:18:04 +0200 Subject: [PATCH 08/13] WIP --- api-reports/2_12.txt | 12 ++--- api-reports/2_13.txt | 12 ++--- ...ngStrategy.scala => QueuingStrategy.scala} | 6 +-- .../org/scalajs/dom/ReadableStream.scala | 4 +- .../dom/ReadableStreamController.scala | 2 +- .../dom/ReadableStreamUnderlyingSource.scala | 7 ++- .../dom/tests/shared/BrowserTests.scala | 50 +++++++++++++++++-- 7 files changed, 67 insertions(+), 26 deletions(-) rename dom/src/main/scala/org/scalajs/dom/{ReadableStreamQueuingStrategy.scala => QueuingStrategy.scala} (84%) diff --git a/api-reports/2_12.txt b/api-reports/2_12.txt index b53ecdde1..f2e96cc8a 100644 --- a/api-reports/2_12.txt +++ b/api-reports/2_12.txt @@ -15625,6 +15625,8 @@ PushSubscriptionJSON[JT] val expirationTime: java.lang.Double PushSubscriptionJSON[JT] val keys: js.Dictionary[String] PushSubscriptionOptions[JT] var applicationServerKey: js.UndefOr[Uint8Array] PushSubscriptionOptions[JT] var userVisibleOnly: js.UndefOr[Boolean] +QueuingStrategy[JT] var highWaterMark: Int +QueuingStrategy[JT] var size: js.Function1[T, Int] RTCBundlePolicy[JT] RTCBundlePolicy[SO] val balanced: RTCBundlePolicy RTCBundlePolicy[SO] val `max-bundle` = "max-bundle".asInstanceOf[RTCBundlePolicy] @@ -15851,13 +15853,11 @@ ReadableStream[JT] def locked: Boolean ReadableStream[JT] def pipeThrough[U](pair: Any, options: Any?): ReadableStream[U] ReadableStream[JT] def pipeTo(dest: WriteableStream[T], options: Any?): Unit ReadableStream[JT] def tee(): js.Array[_ <: ReadableStream[T]] -ReadableStream[SO] def apply[T](underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]], queuingStrategy: js.UndefOr[ReadableStreamQueuingStrategy[T]]?): ReadableStream[T] +ReadableStream[SO] def apply[T](underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]]?, queuingStrategy: js.UndefOr[QueuingStrategy[T]]?): ReadableStream[T] ReadableStreamController[JC] def close(): Unit ReadableStreamController[JC] def desiredSize: Int ReadableStreamController[JC] def enqueue(chunk: T): js.UndefOr[Int] ReadableStreamController[JC] def error(e: Any): Unit -ReadableStreamQueuingStrategy[JT] var highWaterMark: Double -ReadableStreamQueuingStrategy[JT] var size: js.Function1[Chunk[T], Unit] ReadableStreamReader[JC] def cancel(): js.Promise[Unit] ReadableStreamReader[JC] def cancel[U](reason: U): js.Promise[U] ReadableStreamReader[JC] def closed: js.Promise[ReadableStreamReader[T]] @@ -15866,9 +15866,9 @@ ReadableStreamReader[JC] def releaseLock(): Unit ReadableStreamType[JT] ReadableStreamType[SO] val bytes: ReadableStreamType ReadableStreamUnderlyingSource[JT] var autoAllocateChunkSize: js.UndefOr[Double] -ReadableStreamUnderlyingSource[JT] var cancel: js.UndefOr[js.Function1[js.Any, Unit | js.Promise[Unit]]] -ReadableStreamUnderlyingSource[JT] var pull: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] -ReadableStreamUnderlyingSource[JT] var start: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] +ReadableStreamUnderlyingSource[JT] var cancel: js.UndefOr[js.Function1[js.Any, js.UndefOr[js.Promise[Unit]]]] +ReadableStreamUnderlyingSource[JT] var pull: js.UndefOr[js.Function1[ReadableStreamController[T], js.UndefOr[js.Promise[Unit]]]] +ReadableStreamUnderlyingSource[JT] var start: js.UndefOr[js.Function1[ReadableStreamController[T], js.UndefOr[js.Promise[Unit]]]] ReadableStreamUnderlyingSource[JT] var `type`: js.UndefOr[ReadableStreamType] ReferrerPolicy[JT] ReferrerPolicy[SO] val empty: ReferrerPolicy diff --git a/api-reports/2_13.txt b/api-reports/2_13.txt index b53ecdde1..f2e96cc8a 100644 --- a/api-reports/2_13.txt +++ b/api-reports/2_13.txt @@ -15625,6 +15625,8 @@ PushSubscriptionJSON[JT] val expirationTime: java.lang.Double PushSubscriptionJSON[JT] val keys: js.Dictionary[String] PushSubscriptionOptions[JT] var applicationServerKey: js.UndefOr[Uint8Array] PushSubscriptionOptions[JT] var userVisibleOnly: js.UndefOr[Boolean] +QueuingStrategy[JT] var highWaterMark: Int +QueuingStrategy[JT] var size: js.Function1[T, Int] RTCBundlePolicy[JT] RTCBundlePolicy[SO] val balanced: RTCBundlePolicy RTCBundlePolicy[SO] val `max-bundle` = "max-bundle".asInstanceOf[RTCBundlePolicy] @@ -15851,13 +15853,11 @@ ReadableStream[JT] def locked: Boolean ReadableStream[JT] def pipeThrough[U](pair: Any, options: Any?): ReadableStream[U] ReadableStream[JT] def pipeTo(dest: WriteableStream[T], options: Any?): Unit ReadableStream[JT] def tee(): js.Array[_ <: ReadableStream[T]] -ReadableStream[SO] def apply[T](underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]], queuingStrategy: js.UndefOr[ReadableStreamQueuingStrategy[T]]?): ReadableStream[T] +ReadableStream[SO] def apply[T](underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]]?, queuingStrategy: js.UndefOr[QueuingStrategy[T]]?): ReadableStream[T] ReadableStreamController[JC] def close(): Unit ReadableStreamController[JC] def desiredSize: Int ReadableStreamController[JC] def enqueue(chunk: T): js.UndefOr[Int] ReadableStreamController[JC] def error(e: Any): Unit -ReadableStreamQueuingStrategy[JT] var highWaterMark: Double -ReadableStreamQueuingStrategy[JT] var size: js.Function1[Chunk[T], Unit] ReadableStreamReader[JC] def cancel(): js.Promise[Unit] ReadableStreamReader[JC] def cancel[U](reason: U): js.Promise[U] ReadableStreamReader[JC] def closed: js.Promise[ReadableStreamReader[T]] @@ -15866,9 +15866,9 @@ ReadableStreamReader[JC] def releaseLock(): Unit ReadableStreamType[JT] ReadableStreamType[SO] val bytes: ReadableStreamType ReadableStreamUnderlyingSource[JT] var autoAllocateChunkSize: js.UndefOr[Double] -ReadableStreamUnderlyingSource[JT] var cancel: js.UndefOr[js.Function1[js.Any, Unit | js.Promise[Unit]]] -ReadableStreamUnderlyingSource[JT] var pull: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] -ReadableStreamUnderlyingSource[JT] var start: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] +ReadableStreamUnderlyingSource[JT] var cancel: js.UndefOr[js.Function1[js.Any, js.UndefOr[js.Promise[Unit]]]] +ReadableStreamUnderlyingSource[JT] var pull: js.UndefOr[js.Function1[ReadableStreamController[T], js.UndefOr[js.Promise[Unit]]]] +ReadableStreamUnderlyingSource[JT] var start: js.UndefOr[js.Function1[ReadableStreamController[T], js.UndefOr[js.Promise[Unit]]]] ReadableStreamUnderlyingSource[JT] var `type`: js.UndefOr[ReadableStreamType] ReferrerPolicy[JT] ReferrerPolicy[SO] val empty: ReferrerPolicy diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamQueuingStrategy.scala b/dom/src/main/scala/org/scalajs/dom/QueuingStrategy.scala similarity index 84% rename from dom/src/main/scala/org/scalajs/dom/ReadableStreamQueuingStrategy.scala rename to dom/src/main/scala/org/scalajs/dom/QueuingStrategy.scala index 7957935fc..bf5e8845a 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamQueuingStrategy.scala +++ b/dom/src/main/scala/org/scalajs/dom/QueuingStrategy.scala @@ -7,10 +7,10 @@ import scala.scalajs.js * @tparam T * Type of the Chunks returned by the Stream */ -trait ReadableStreamQueuingStrategy[T] extends js.Object { +trait QueuingStrategy[T] extends js.Object { /** A non-negative number indicating the high water mark of the stream using this queuing strategy. */ - var highWaterMark: Double + var highWaterMark: Int /** (non-byte streams only) * @@ -19,5 +19,5 @@ trait ReadableStreamQueuingStrategy[T] extends js.Object { * * A function that computes and returns the finite non-negative size of the given chunk value. */ - var size: js.Function1[Chunk[T], Unit] + var size: js.Function1[T, Int] } diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala index 8d280e97f..6182d2916 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala @@ -96,8 +96,8 @@ trait ReadableStream[+T] extends js.Object { object ReadableStream { def apply[T]( - underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]], - queuingStrategy: js.UndefOr[ReadableStreamQueuingStrategy[T]] = js.undefined + underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]] = js.undefined, + queuingStrategy: js.UndefOr[QueuingStrategy[T]] = js.undefined ): ReadableStream[T] = { js.Dynamic .newInstance(js.Dynamic.global.selectDynamic("ReadableStream"))( diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala index 6f451317a..13398badb 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala @@ -15,7 +15,7 @@ import scala.scalajs.js.annotation.JSGlobal */ @js.native @JSGlobal -class ReadableStreamController[-T] private[this] (stream: ReadableStream[T] = null) extends js.Object { +class ReadableStreamController[-T] private[this] () extends js.Object { /** The desiredSize getter returns the desired size to fill the controlled stream’s internal queue. It can be * negative, if the queue is over-full. An underlying source should use this information to determine when and how to diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala index b0f7410b5..35fe4e3a9 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala @@ -1,7 +1,6 @@ package org.scalajs.dom import scala.scalajs.js -import scala.scalajs.js.| /** See [[https://streams.spec.whatwg.org/#underlying-source-api ¶4.2.3. The underlying source API]] of whatwg streams * spec. @@ -16,7 +15,7 @@ trait ReadableStreamUnderlyingSource[T] extends js.Object { * If this setup process is asynchronous, it can return a promise to signal success or failure; a rejected promise * will error the stream. Any thrown exceptions will be re-thrown by the [[ReadableStream]] constructor. */ - var start: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] = js.undefined + var start: js.UndefOr[js.Function1[ReadableStreamController[T], js.UndefOr[js.Promise[Unit]]]] = js.undefined /** A function that is called whenever the stream’s internal queue of chunks becomes not full, i.e. whenever the * queue’s desired size becomes positive. Generally, it will be called repeatedly until the queue reaches its high @@ -31,7 +30,7 @@ trait ReadableStreamUnderlyingSource[T] extends js.Object { * returned represents the process of acquiring a new chunk. Throwing an exception is treated the same as returning a * rejected promise. */ - var pull: js.UndefOr[js.Function1[ReadableStreamController[T], Unit | js.Promise[Unit]]] = js.undefined + var pull: js.UndefOr[js.Function1[ReadableStreamController[T], js.UndefOr[js.Promise[Unit]]]] = js.undefined /** A function that is called whenever the consumer cancels the stream, via [[ReadableStream.cancel]] or * [[ReadableStreamReader.cancel():scala\.scalajs\.js\.Promise[Unit]*]]. It takes as its argument the same value as @@ -40,7 +39,7 @@ trait ReadableStreamUnderlyingSource[T] extends js.Object { * called. Additionally, a rejected promise will error the stream, instead of letting it close. Throwing an exception * is treated the same as returning a rejected promise. */ - var cancel: js.UndefOr[js.Function1[js.Any, Unit | js.Promise[Unit]]] = js.undefined + var cancel: js.UndefOr[js.Function1[js.Any, js.UndefOr[js.Promise[Unit]]]] = js.undefined /** Can be set to "bytes" to signal that the constructed [[ReadableStream]] is a readable byte stream. * diff --git a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala index 2843b9ec7..0b5ff03a9 100644 --- a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala +++ b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala @@ -2,6 +2,7 @@ package org.scalajs.dom.tests.shared import org.junit.Assert.assertEquals import org.junit.Test +import org.scalajs.dom.QueuingStrategy import org.scalajs.dom.ReadableStream import org.scalajs.dom.ReadableStreamController import org.scalajs.dom.ReadableStreamUnderlyingSource @@ -12,12 +13,11 @@ import org.scalajs.dom.tests.shared.AsyncTesting.async import scala.concurrent.Future import scala.scalajs.js import scala.scalajs.js.Thenable.Implicits._ -import scala.scalajs.js.| trait BrowserTests { @Test - final def ReadableStreamTest: AsyncResult = async { + final def ReadableStreamConstructionAndConsumptionTest: AsyncResult = async { case class Tuna(color: String) val expectedTunas = Seq( @@ -30,8 +30,8 @@ trait BrowserTests { start = js.defined({ (controller: ReadableStreamController[Tuna]) => controller.enqueue(Tuna("blue")) controller.enqueue(Tuna("red")) - controller.close(): Unit | js.Promise[Unit] - }): js.UndefOr[js.Function1[ReadableStreamController[Tuna], Unit | js.Promise[Unit]]] + controller.close(): js.UndefOr[js.Promise[Unit]] + }): js.UndefOr[js.Function1[ReadableStreamController[Tuna], js.UndefOr[js.Promise[Unit]]]] } ) @@ -53,4 +53,46 @@ trait BrowserTests { assertEquals(receivedTunas, expectedTunas) } } + + @Test + final def ReadableStreamQueueingStrategyTest: AsyncResult = async { + val expectedStrings = Seq( + "short one", + "definitely a longer one" + ) + + val stream = ReadableStream[String]( + new ReadableStreamUnderlyingSource[String] { + start = js.defined({ (controller: ReadableStreamController[String]) => + controller.enqueue("short one") + controller.enqueue("definitely a longer one") + controller.close(): js.UndefOr[js.Promise[Unit]] + }): js.UndefOr[js.Function1[ReadableStreamController[String], js.UndefOr[js.Promise[Unit]]]] + }, + new QueuingStrategy[String] { + var highWaterMark = 1 + var size: js.Function1[String, Int] = { (chunk: String) => + chunk.length + } + } + ) + + val reader = stream.getReader() + + def read(strings: Seq[String]): Future[Seq[String]] = { + reader + .read() + .flatMap { chunk => + if (chunk.done) { + Future.successful(strings) + } else { + read(strings :+ chunk.value) + } + } + } + read(Seq.empty) + .map { receivedStrings => + assertEquals(receivedStrings, expectedStrings) + } + } } From fadb50ba5d594f58b51d39b5532976e038780fcc Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Sun, 14 Nov 2021 21:47:47 +0200 Subject: [PATCH 09/13] WIP --- api-reports/2_12.txt | 7 +- api-reports/2_13.txt | 7 +- .../dom/ReadableStreamController.scala | 3 +- .../scalajs/dom/ReadableStreamReader.scala | 2 +- .../dom/ReadableStreamUnderlyingSource.scala | 2 +- .../dom/tests/shared/BrowserTests.scala | 89 +++++++++++++------ 6 files changed, 73 insertions(+), 37 deletions(-) diff --git a/api-reports/2_12.txt b/api-reports/2_12.txt index f2e96cc8a..f3cdfc0b7 100644 --- a/api-reports/2_12.txt +++ b/api-reports/2_12.txt @@ -15856,16 +15856,17 @@ ReadableStream[JT] def tee(): js.Array[_ <: ReadableStream[T]] ReadableStream[SO] def apply[T](underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]]?, queuingStrategy: js.UndefOr[QueuingStrategy[T]]?): ReadableStream[T] ReadableStreamController[JC] def close(): Unit ReadableStreamController[JC] def desiredSize: Int -ReadableStreamController[JC] def enqueue(chunk: T): js.UndefOr[Int] +ReadableStreamController[JC] def enqueue(): Unit +ReadableStreamController[JC] def enqueue(chunk: T): Unit ReadableStreamController[JC] def error(e: Any): Unit ReadableStreamReader[JC] def cancel(): js.Promise[Unit] -ReadableStreamReader[JC] def cancel[U](reason: U): js.Promise[U] +ReadableStreamReader[JC] def cancel[U](reason: U): js.Promise[Unit] ReadableStreamReader[JC] def closed: js.Promise[ReadableStreamReader[T]] ReadableStreamReader[JC] def read(): js.Promise[Chunk[T]] ReadableStreamReader[JC] def releaseLock(): Unit ReadableStreamType[JT] ReadableStreamType[SO] val bytes: ReadableStreamType -ReadableStreamUnderlyingSource[JT] var autoAllocateChunkSize: js.UndefOr[Double] +ReadableStreamUnderlyingSource[JT] var autoAllocateChunkSize: js.UndefOr[Int] ReadableStreamUnderlyingSource[JT] var cancel: js.UndefOr[js.Function1[js.Any, js.UndefOr[js.Promise[Unit]]]] ReadableStreamUnderlyingSource[JT] var pull: js.UndefOr[js.Function1[ReadableStreamController[T], js.UndefOr[js.Promise[Unit]]]] ReadableStreamUnderlyingSource[JT] var start: js.UndefOr[js.Function1[ReadableStreamController[T], js.UndefOr[js.Promise[Unit]]]] diff --git a/api-reports/2_13.txt b/api-reports/2_13.txt index f2e96cc8a..f3cdfc0b7 100644 --- a/api-reports/2_13.txt +++ b/api-reports/2_13.txt @@ -15856,16 +15856,17 @@ ReadableStream[JT] def tee(): js.Array[_ <: ReadableStream[T]] ReadableStream[SO] def apply[T](underlyingSource: js.UndefOr[ReadableStreamUnderlyingSource[T]]?, queuingStrategy: js.UndefOr[QueuingStrategy[T]]?): ReadableStream[T] ReadableStreamController[JC] def close(): Unit ReadableStreamController[JC] def desiredSize: Int -ReadableStreamController[JC] def enqueue(chunk: T): js.UndefOr[Int] +ReadableStreamController[JC] def enqueue(): Unit +ReadableStreamController[JC] def enqueue(chunk: T): Unit ReadableStreamController[JC] def error(e: Any): Unit ReadableStreamReader[JC] def cancel(): js.Promise[Unit] -ReadableStreamReader[JC] def cancel[U](reason: U): js.Promise[U] +ReadableStreamReader[JC] def cancel[U](reason: U): js.Promise[Unit] ReadableStreamReader[JC] def closed: js.Promise[ReadableStreamReader[T]] ReadableStreamReader[JC] def read(): js.Promise[Chunk[T]] ReadableStreamReader[JC] def releaseLock(): Unit ReadableStreamType[JT] ReadableStreamType[SO] val bytes: ReadableStreamType -ReadableStreamUnderlyingSource[JT] var autoAllocateChunkSize: js.UndefOr[Double] +ReadableStreamUnderlyingSource[JT] var autoAllocateChunkSize: js.UndefOr[Int] ReadableStreamUnderlyingSource[JT] var cancel: js.UndefOr[js.Function1[js.Any, js.UndefOr[js.Promise[Unit]]]] ReadableStreamUnderlyingSource[JT] var pull: js.UndefOr[js.Function1[ReadableStreamController[T], js.UndefOr[js.Promise[Unit]]]] ReadableStreamUnderlyingSource[JT] var start: js.UndefOr[js.Function1[ReadableStreamController[T], js.UndefOr[js.Promise[Unit]]]] diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala index 13398badb..ee40db34b 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamController.scala @@ -39,7 +39,8 @@ class ReadableStreamController[-T] private[this] () extends js.Object { * @return * seems like its an undefOr[Int] of the size */ - def enqueue(chunk: T): js.UndefOr[Int] = js.native + def enqueue(chunk: T): Unit = js.native + def enqueue(): Unit = js.native /** The error method will error the readable stream, making all future interactions with it fail with the given error * e. diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala index 2e02599bb..49ab25bac 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala @@ -31,7 +31,7 @@ class ReadableStreamReader[+T](stream: ReadableStream[T]) extends js.Object { * If the reader is active, the cancel method behaves the same as that for the associated stream. When done, it * automatically releases the lock. */ - def cancel[U](reason: U): js.Promise[U] = js.native + def cancel[U](reason: U): js.Promise[Unit] = js.native def cancel(): js.Promise[Unit] = js.native /** See [[https://streams.spec.whatwg.org/#reader-read 3.4.4.3. read()]] of whatwg Stream spec. diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala index 35fe4e3a9..0d7712bc4 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamUnderlyingSource.scala @@ -53,5 +53,5 @@ trait ReadableStreamUnderlyingSource[T] extends js.Object { * Can be set to a positive integer to cause the implementation to automatically allocate buffers for the underlying * source code to write into. */ - var autoAllocateChunkSize: js.UndefOr[Double] = js.undefined + var autoAllocateChunkSize: js.UndefOr[Int] = js.undefined } diff --git a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala index 0b5ff03a9..8ac074b23 100644 --- a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala +++ b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala @@ -5,17 +5,32 @@ import org.junit.Test import org.scalajs.dom.QueuingStrategy import org.scalajs.dom.ReadableStream import org.scalajs.dom.ReadableStreamController +import org.scalajs.dom.ReadableStreamReader import org.scalajs.dom.ReadableStreamUnderlyingSource import org.scalajs.dom.tests.shared.AsyncTesting.AsyncResult import org.scalajs.dom.tests.shared.AsyncTesting._ import org.scalajs.dom.tests.shared.AsyncTesting.async import scala.concurrent.Future +import scala.concurrent.Promise import scala.scalajs.js import scala.scalajs.js.Thenable.Implicits._ +import scala.util.Try trait BrowserTests { + def read[T](reader: ReadableStreamReader[T])(tunas: Seq[T]): Future[Seq[T]] = { + reader + .read() + .flatMap { chunk => + if (chunk.done) { + Future.successful(tunas) + } else { + read(reader)(tunas :+ chunk.value) + } + } + } + @Test final def ReadableStreamConstructionAndConsumptionTest: AsyncResult = async { case class Tuna(color: String) @@ -35,20 +50,7 @@ trait BrowserTests { } ) - val reader = stream.getReader() - - def read(tunas: Seq[Tuna]): Future[Seq[Tuna]] = { - reader - .read() - .flatMap { chunk => - if (chunk.done) { - Future.successful(tunas) - } else { - read(tunas :+ chunk.value) - } - } - } - read(Seq.empty) + read(stream.getReader())(Seq.empty) .map { receivedTunas => assertEquals(receivedTunas, expectedTunas) } @@ -77,22 +79,53 @@ trait BrowserTests { } ) - val reader = stream.getReader() - - def read(strings: Seq[String]): Future[Seq[String]] = { - reader - .read() - .flatMap { chunk => - if (chunk.done) { - Future.successful(strings) - } else { - read(strings :+ chunk.value) - } - } - } - read(Seq.empty) + read(stream.getReader())(Seq.empty) .map { receivedStrings => assertEquals(receivedStrings, expectedStrings) } } + + @Test + final def ReadableStreamReaderCancelUnitTest: AsyncResult = async { + val reasonPromise = Promise[Unit]() + val stream = ReadableStream[Unit]( + new ReadableStreamUnderlyingSource[Unit] { + cancel = js.defined({ (reason: Any) => + reasonPromise.tryComplete(Try(reason.asInstanceOf[Unit])) + (): js.UndefOr[js.Promise[Unit]] + }): js.UndefOr[js.Function1[Any, js.UndefOr[js.Promise[Unit]]]] + } + ) + + for { + _ <- stream + .getReader() + .cancel() + .map(assertEquals((), _)) + _ <- reasonPromise.future.map(assertEquals((), _)) + } yield () + } + + @Test + final def ReadableStreamReaderCancelPromiseTest: AsyncResult = async { + val expectedReason = "probably a good one" + + val reasonPromise = Promise[String]() + val stream = ReadableStream[Unit]( + new ReadableStreamUnderlyingSource[Unit] { + cancel = js.defined({ (reason: Any) => + reasonPromise.tryComplete(Try(reason.asInstanceOf[String])) + (): js.UndefOr[js.Promise[Unit]] + }): js.UndefOr[js.Function1[Any, js.UndefOr[js.Promise[Unit]]]] + } + ) + + for { + _ <- stream + .getReader() + .cancel(expectedReason) + .map(assertEquals((), _)) + _ <- reasonPromise.future.map(assertEquals(expectedReason, _)) + } yield () + } } From 86cd967fed79e0bf01e873c364a683af38e0950f Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Sun, 14 Nov 2021 21:51:30 +0200 Subject: [PATCH 10/13] WIP --- .../scala/org/scalajs/dom/tests/shared/BrowserTests.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala index 8ac074b23..10d8c26a8 100644 --- a/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala +++ b/tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala @@ -19,14 +19,14 @@ import scala.util.Try trait BrowserTests { - def read[T](reader: ReadableStreamReader[T])(tunas: Seq[T]): Future[Seq[T]] = { + def read[T](reader: ReadableStreamReader[T])(values: Seq[T]): Future[Seq[T]] = { reader .read() .flatMap { chunk => if (chunk.done) { - Future.successful(tunas) + Future.successful(values) } else { - read(reader)(tunas :+ chunk.value) + read(reader)(values :+ chunk.value) } } } From 775bb394a933c2d1e85c97016e5fce3d26ef94ae Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Sun, 14 Nov 2021 22:58:44 +0200 Subject: [PATCH 11/13] WIP Co-authored-by: Arman Bilge --- dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala index 49ab25bac..1953b2688 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStreamReader.scala @@ -31,7 +31,7 @@ class ReadableStreamReader[+T](stream: ReadableStream[T]) extends js.Object { * If the reader is active, the cancel method behaves the same as that for the associated stream. When done, it * automatically releases the lock. */ - def cancel[U](reason: U): js.Promise[Unit] = js.native + def cancel(reason: Any): js.Promise[Unit] = js.native def cancel(): js.Promise[Unit] = js.native /** See [[https://streams.spec.whatwg.org/#reader-read 3.4.4.3. read()]] of whatwg Stream spec. From 345ae043ba53abb7a7ceca29f1e8a42753c23a6e Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Sun, 14 Nov 2021 23:05:22 +0200 Subject: [PATCH 12/13] Regenerate api-reports. --- api-reports/2_12.txt | 2 +- api-reports/2_13.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api-reports/2_12.txt b/api-reports/2_12.txt index f3cdfc0b7..bcf31dc83 100644 --- a/api-reports/2_12.txt +++ b/api-reports/2_12.txt @@ -15860,7 +15860,7 @@ ReadableStreamController[JC] def enqueue(): Unit ReadableStreamController[JC] def enqueue(chunk: T): Unit ReadableStreamController[JC] def error(e: Any): Unit ReadableStreamReader[JC] def cancel(): js.Promise[Unit] -ReadableStreamReader[JC] def cancel[U](reason: U): js.Promise[Unit] +ReadableStreamReader[JC] def cancel(reason: Any): js.Promise[Unit] ReadableStreamReader[JC] def closed: js.Promise[ReadableStreamReader[T]] ReadableStreamReader[JC] def read(): js.Promise[Chunk[T]] ReadableStreamReader[JC] def releaseLock(): Unit diff --git a/api-reports/2_13.txt b/api-reports/2_13.txt index f3cdfc0b7..bcf31dc83 100644 --- a/api-reports/2_13.txt +++ b/api-reports/2_13.txt @@ -15860,7 +15860,7 @@ ReadableStreamController[JC] def enqueue(): Unit ReadableStreamController[JC] def enqueue(chunk: T): Unit ReadableStreamController[JC] def error(e: Any): Unit ReadableStreamReader[JC] def cancel(): js.Promise[Unit] -ReadableStreamReader[JC] def cancel[U](reason: U): js.Promise[Unit] +ReadableStreamReader[JC] def cancel(reason: Any): js.Promise[Unit] ReadableStreamReader[JC] def closed: js.Promise[ReadableStreamReader[T]] ReadableStreamReader[JC] def read(): js.Promise[Chunk[T]] ReadableStreamReader[JC] def releaseLock(): Unit From eabf4b0680503954f939338fa59abb209a892856 Mon Sep 17 00:00:00 2001 From: Domantas Petrauskas Date: Mon, 15 Nov 2021 17:15:05 +0200 Subject: [PATCH 13/13] WIP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sébastien Doeraene --- dom/src/main/scala/org/scalajs/dom/ReadableStream.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala b/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala index 6182d2916..cc6cd9973 100644 --- a/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala +++ b/dom/src/main/scala/org/scalajs/dom/ReadableStream.scala @@ -100,7 +100,7 @@ object ReadableStream { queuingStrategy: js.UndefOr[QueuingStrategy[T]] = js.undefined ): ReadableStream[T] = { js.Dynamic - .newInstance(js.Dynamic.global.selectDynamic("ReadableStream"))( + .newInstance(js.Dynamic.global.ReadableStream)( underlyingSource.asInstanceOf[js.Any], queuingStrategy.asInstanceOf[js.Any] )