From 22a925972a6af8e2c1e2c5464a742f4f934da7d3 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Wed, 17 Jul 2024 17:17:34 +0200 Subject: [PATCH 01/18] feat(webidl): add async iterable converter --- ext/fetch/22_body.js | 7 +++ ext/web/06_streams.js | 26 +++------ ext/webidl/00_webidl.js | 112 ++++++++++++++++++++++++++++++++++++++- ext/webidl/internal.d.ts | 21 ++++++++ 4 files changed, 146 insertions(+), 20 deletions(-) diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index e9d493658698c6..d1123704c2ccc8 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -32,6 +32,7 @@ const { TypedArrayPrototypeSlice, TypeError, Uint8Array, + SymbolAsyncIterator, } = primordials; import * as webidl from "ext:deno_webidl/00_webidl.js"; @@ -58,6 +59,7 @@ import { readableStreamTee, readableStreamThrowIfErrored, } from "ext:deno_web/06_streams.js"; +import { converters, createAsyncIterableConverter } from "../webidl/00_webidl"; /** * @param {Uint8Array | string} chunk @@ -445,6 +447,8 @@ function extractBody(object) { if (object.locked || isReadableStreamDisturbed(object)) { throw new TypeError("ReadableStream is locked or disturbed"); } + } else if (object[SymbolAsyncIterator] !== undefined) { + stream = ReadableStream.from(object.value); } if (typeof source === "string") { // WARNING: this deviates from spec (expects length to be set) @@ -462,6 +466,8 @@ function extractBody(object) { return { body, contentType }; } +webidl.converters["async iterable"] = createAsyncIterableConverter(webidl.converters.Uint8Array); + webidl.converters["BodyInit_DOMString"] = (V, prefix, context, opts) => { // Union for (ReadableStream or Blob or ArrayBufferView or ArrayBuffer or FormData or URLSearchParams or USVString) if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, V)) { @@ -480,6 +486,7 @@ webidl.converters["BodyInit_DOMString"] = (V, prefix, context, opts) => { if (ArrayBufferIsView(V)) { return webidl.converters["ArrayBufferView"](V, prefix, context, opts); } + return webidl.converters["async iterable"](V, prefix, context, opts); } // BodyInit conversion is passed to extractBody(), which calls core.encode(). // core.encode() will UTF-8 encode strings with replacement, being equivalent to the USV normalization. diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index d3de24363798c4..050b136697f202 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -5196,21 +5196,17 @@ class ReadableStream { } static from(asyncIterable) { + const prefix = "Failed to execute 'ReadableStream.from'"; webidl.requiredArguments( arguments.length, 1, - "Failed to execute 'ReadableStream.from'", + prefix, ); - asyncIterable = webidl.converters.any(asyncIterable); - - const iterator = getAsyncOrSyncIterator(asyncIterable); + asyncIterable = webidl.converters["async iterable"](asyncIterable, prefix, "Argument 1"); const stream = createReadableStream(noop, async () => { // deno-lint-ignore prefer-primordials - const res = await iterator.next(); - if (!isObject(res)) { - throw new TypeError("iterator.next value is not an object"); - } + const res = await asyncIterable.next(); if (res.done) { readableStreamDefaultControllerClose(stream[_controller]); } else { @@ -5220,17 +5216,7 @@ class ReadableStream { ); } }, async (reason) => { - if (iterator.return == null) { - return undefined; - } else { - // deno-lint-ignore prefer-primordials - const res = await iterator.return(reason); - if (!isObject(res)) { - throw new TypeError("iterator.return value is not an object"); - } else { - return undefined; - } - } + await asyncIterable.return(reason); }, 0); return stream; } @@ -6890,6 +6876,8 @@ webidl.converters.StreamPipeOptions = webidl { key: "signal", converter: webidl.converters.AbortSignal }, ]); +webidl.converters["async iterable"] = webidl.createAsyncIterableConverter(webidl.converters.any); + internals.resourceForReadableStream = resourceForReadableStream; export { diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 9ea2200f333af7..79efbc2b155715 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -6,7 +6,7 @@ /// -import { core, primordials } from "ext:core/mod.js"; +import { core, primordials, internals } from "ext:core/mod.js"; const { isArrayBuffer, isDataView, @@ -26,6 +26,7 @@ const { Float32Array, Float64Array, FunctionPrototypeBind, + FunctionPrototypeCall, Int16Array, Int32Array, Int8Array, @@ -77,6 +78,7 @@ const { StringPrototypeToWellFormed, Symbol, SymbolIterator, + SymbolAsyncIterator, SymbolToStringTag, TypedArrayPrototypeGetBuffer, TypedArrayPrototypeGetSymbolToStringTag, @@ -919,6 +921,113 @@ function createSequenceConverter(converter) { }; } +// Ref: https://tc39.es/ecma262/#sec-getiterator, modified to not call the iterator +function getIteratorAsync(obj) { + const method = obj[SymbolAsyncIterator]; + if (method === undefined) { + const syncMethod = obj[SymbolIterator]; + if (syncMethod === undefined) { + throw new TypeError("No iterator found"); + } + return syncMethod; + } else { + return method; + } +} + +function CreateAsyncFromSyncIterator(iter) { + return { + async next() { + return iter.next(); + } + } +} + +function createAsyncIterableConverter(converter) { + return function ( + V, + prefix = undefined, + context = undefined, + opts = { __proto__: null }, + ) { + if (type(V) !== "Object") { + throw makeException( + TypeError, + "can not be converted to async iterable.", + prefix, + context, + ); + } + + const iter = getIteratorAsync(V); + + let iterator; + return { + async next() { + if (!iterator) { + if (V[SymbolIterator]) { + iterator = CreateAsyncFromSyncIterator(FunctionPrototypeCall(iter, V)); + } else { + iterator = FunctionPrototypeCall(iter, V); + } + } + + const iterResult = await iterator.next(); + if (type(iterResult) !== "Object") { + throw makeException( + TypeError, + "can not be converted to async iterable.", + prefix, + context, + ); + } + + if (iterResult.done) { + return { done: true }; + } + + const iterValue = converter( + iterResult.value, + prefix, + context, + opts, + ); + + return { done: false, value: iterValue }; + }, + async return(reason) { + if (!iterator) { + if (V[SymbolIterator]) { + iterator = CreateAsyncFromSyncIterator(FunctionPrototypeCall(iter, V)); + } else { + iterator = FunctionPrototypeCall(iter, V); + } + } + + if (iterator.return === undefined) { + return undefined; + } + + const returnPromiseResult = await iterator.return(reason); + if (type(returnPromiseResult) !== "Object") { + throw makeException( + TypeError, + "can not be converted to async iterable.", + prefix, + context, + ); + } + + return undefined; + }, + [SymbolAsyncIterator]() { + return this; + }, + value: V, + }; + }; +} + function createRecordConverter(keyConverter, valueConverter) { return (V, prefix, context, opts) => { if (type(V) !== "Object") { @@ -1298,6 +1407,7 @@ export { createPromiseConverter, createRecordConverter, createSequenceConverter, + createAsyncIterableConverter, illegalConstructor, invokeCallbackFunction, makeException, diff --git a/ext/webidl/internal.d.ts b/ext/webidl/internal.d.ts index 1ce45463ecc37e..d9266f5f548a3c 100644 --- a/ext/webidl/internal.d.ts +++ b/ext/webidl/internal.d.ts @@ -438,6 +438,27 @@ declare module "ext:deno_webidl/00_webidl.js" { opts?: any, ) => T[]; + /** + * Create a converter that converts an async iterable of the inner type. + */ + function createAsyncIterableConverter( + converter: ( + v: V, + prefix?: string, + context?: string, + opts?: any, + ) => T, + ): ( + v: any, + prefix?: string, + context?: string, + opts?: any, + ) => ConvertedAsyncIterable; + + interface ConvertedAsyncIterable extends AsyncIterableIterator { + value: V; + } + /** * Create a converter that converts a Promise of the inner type. */ From 0f80a1c00576742b66d6462980132b0fa7407d06 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Wed, 17 Jul 2024 17:19:16 +0200 Subject: [PATCH 02/18] fmt --- ext/fetch/22_body.js | 11 ++++++++--- ext/web/06_streams.js | 10 ++++++++-- ext/webidl/00_webidl.js | 16 ++++++++++------ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index d1123704c2ccc8..9ae5862a284b94 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -59,7 +59,6 @@ import { readableStreamTee, readableStreamThrowIfErrored, } from "ext:deno_web/06_streams.js"; -import { converters, createAsyncIterableConverter } from "../webidl/00_webidl"; /** * @param {Uint8Array | string} chunk @@ -466,7 +465,8 @@ function extractBody(object) { return { body, contentType }; } -webidl.converters["async iterable"] = createAsyncIterableConverter(webidl.converters.Uint8Array); +webidl.converters["async iterable"] = webidl + .createAsyncIterableConverter(webidl.converters.Uint8Array); webidl.converters["BodyInit_DOMString"] = (V, prefix, context, opts) => { // Union for (ReadableStream or Blob or ArrayBufferView or ArrayBuffer or FormData or URLSearchParams or USVString) @@ -486,7 +486,12 @@ webidl.converters["BodyInit_DOMString"] = (V, prefix, context, opts) => { if (ArrayBufferIsView(V)) { return webidl.converters["ArrayBufferView"](V, prefix, context, opts); } - return webidl.converters["async iterable"](V, prefix, context, opts); + return webidl.converters["async iterable"]( + V, + prefix, + context, + opts, + ); } // BodyInit conversion is passed to extractBody(), which calls core.encode(). // core.encode() will UTF-8 encode strings with replacement, being equivalent to the USV normalization. diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 050b136697f202..2d0f776b5dc0f5 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -5202,7 +5202,11 @@ class ReadableStream { 1, prefix, ); - asyncIterable = webidl.converters["async iterable"](asyncIterable, prefix, "Argument 1"); + asyncIterable = webidl.converters["async iterable"]( + asyncIterable, + prefix, + "Argument 1", + ); const stream = createReadableStream(noop, async () => { // deno-lint-ignore prefer-primordials @@ -6876,7 +6880,9 @@ webidl.converters.StreamPipeOptions = webidl { key: "signal", converter: webidl.converters.AbortSignal }, ]); -webidl.converters["async iterable"] = webidl.createAsyncIterableConverter(webidl.converters.any); +webidl.converters["async iterable"] = webidl.createAsyncIterableConverter( + webidl.converters.any, +); internals.resourceForReadableStream = resourceForReadableStream; diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 79efbc2b155715..0adc4b96a58f1e 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -6,7 +6,7 @@ /// -import { core, primordials, internals } from "ext:core/mod.js"; +import { core, internals, primordials } from "ext:core/mod.js"; const { isArrayBuffer, isDataView, @@ -939,8 +939,8 @@ function CreateAsyncFromSyncIterator(iter) { return { async next() { return iter.next(); - } - } + }, + }; } function createAsyncIterableConverter(converter) { @@ -966,7 +966,9 @@ function createAsyncIterableConverter(converter) { async next() { if (!iterator) { if (V[SymbolIterator]) { - iterator = CreateAsyncFromSyncIterator(FunctionPrototypeCall(iter, V)); + iterator = CreateAsyncFromSyncIterator( + FunctionPrototypeCall(iter, V), + ); } else { iterator = FunctionPrototypeCall(iter, V); } @@ -998,7 +1000,9 @@ function createAsyncIterableConverter(converter) { async return(reason) { if (!iterator) { if (V[SymbolIterator]) { - iterator = CreateAsyncFromSyncIterator(FunctionPrototypeCall(iter, V)); + iterator = CreateAsyncFromSyncIterator( + FunctionPrototypeCall(iter, V), + ); } else { iterator = FunctionPrototypeCall(iter, V); } @@ -1399,6 +1403,7 @@ export { brand, configureInterface, converters, + createAsyncIterableConverter, createBranded, createDictionaryConverter, createEnumConverter, @@ -1407,7 +1412,6 @@ export { createPromiseConverter, createRecordConverter, createSequenceConverter, - createAsyncIterableConverter, illegalConstructor, invokeCallbackFunction, makeException, From d746a44b26a862c906532a0bf233ff5d504c41ef Mon Sep 17 00:00:00 2001 From: crowlkats Date: Wed, 17 Jul 2024 17:27:51 +0200 Subject: [PATCH 03/18] fix --- ext/fetch/22_body.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index 9ae5862a284b94..8771b80bd8ebed 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -447,7 +447,7 @@ function extractBody(object) { throw new TypeError("ReadableStream is locked or disturbed"); } } else if (object[SymbolAsyncIterator] !== undefined) { - stream = ReadableStream.from(object.value); + stream = ReadableStream.from(object); } if (typeof source === "string") { // WARNING: this deviates from spec (expects length to be set) From 3055ec23b252145116ec9de75e5bd70ac43a6bb4 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Wed, 17 Jul 2024 17:31:14 +0200 Subject: [PATCH 04/18] fix --- ext/fetch/22_body.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index 8771b80bd8ebed..c660942e413900 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -441,13 +441,15 @@ function extractBody(object) { // deno-lint-ignore prefer-primordials source = object.toString(); contentType = "application/x-www-form-urlencoded;charset=UTF-8"; - } else if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, object)) { - stream = object; - if (object.locked || isReadableStreamDisturbed(object)) { - throw new TypeError("ReadableStream is locked or disturbed"); - } } else if (object[SymbolAsyncIterator] !== undefined) { - stream = ReadableStream.from(object); + if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, object)) { + stream = object; + if (object.locked || isReadableStreamDisturbed(object)) { + throw new TypeError("ReadableStream is locked or disturbed"); + } + } else { + stream = ReadableStream.from(object); + } } if (typeof source === "string") { // WARNING: this deviates from spec (expects length to be set) From 0c352e4945c025fa510d7cddd23d76780796e67d Mon Sep 17 00:00:00 2001 From: crowlkats Date: Wed, 17 Jul 2024 17:31:46 +0200 Subject: [PATCH 05/18] fix --- ext/fetch/22_body.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index c660942e413900..9cb251de622aa0 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -442,9 +442,9 @@ function extractBody(object) { source = object.toString(); contentType = "application/x-www-form-urlencoded;charset=UTF-8"; } else if (object[SymbolAsyncIterator] !== undefined) { - if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, object)) { - stream = object; - if (object.locked || isReadableStreamDisturbed(object)) { + if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, object.value)) { + stream = object.value; + if (object.value.locked || isReadableStreamDisturbed(object.value)) { throw new TypeError("ReadableStream is locked or disturbed"); } } else { From 075baead6b0e5fcf3b635b3725da8f39eae758de Mon Sep 17 00:00:00 2001 From: crowlkats Date: Wed, 17 Jul 2024 17:46:52 +0200 Subject: [PATCH 06/18] lint --- ext/web/06_streams.js | 30 +----------------------------- ext/webidl/00_webidl.js | 6 +++++- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 2d0f776b5dc0f5..6b24221a35ba12 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -70,7 +70,6 @@ const { String, Symbol, SymbolAsyncIterator, - SymbolIterator, SymbolFor, TypeError, TypedArrayPrototypeGetBuffer, @@ -5083,34 +5082,6 @@ function initializeCountSizeFunction(globalObject) { WeakMapPrototypeSet(countSizeFunctionWeakMap, globalObject, size); } -// Ref: https://tc39.es/ecma262/#sec-getiterator -function getAsyncOrSyncIterator(obj) { - let iterator; - if (obj[SymbolAsyncIterator] != null) { - iterator = obj[SymbolAsyncIterator](); - if (!isObject(iterator)) { - throw new TypeError( - "[Symbol.asyncIterator] returned a non-object value", - ); - } - } else if (obj[SymbolIterator] != null) { - iterator = obj[SymbolIterator](); - if (!isObject(iterator)) { - throw new TypeError("[Symbol.iterator] returned a non-object value"); - } - } else { - throw new TypeError("No iterator found"); - } - if (typeof iterator.next !== "function") { - throw new TypeError("iterator.next is not a function"); - } - return iterator; -} - -function isObject(x) { - return (typeof x === "object" && x != null) || typeof x === "function"; -} - const _resourceBacking = Symbol("[[resourceBacking]]"); // This distinction exists to prevent unrefable streams being used in // regular fast streams that are unaware of refability @@ -5220,6 +5191,7 @@ class ReadableStream { ); } }, async (reason) => { + // deno-lint-ignore prefer-primordials await asyncIterable.return(reason); }, 0); return stream; diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 0adc4b96a58f1e..e6dbf950194d40 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -6,7 +6,7 @@ /// -import { core, internals, primordials } from "ext:core/mod.js"; +import { core, primordials } from "ext:core/mod.js"; const { isArrayBuffer, isDataView, @@ -937,7 +937,9 @@ function getIteratorAsync(obj) { function CreateAsyncFromSyncIterator(iter) { return { + // deno-lint-ignore require-await async next() { + // deno-lint-ignore prefer-primordials return iter.next(); }, }; @@ -974,6 +976,7 @@ function createAsyncIterableConverter(converter) { } } + // deno-lint-ignore prefer-primordials const iterResult = await iterator.next(); if (type(iterResult) !== "Object") { throw makeException( @@ -1012,6 +1015,7 @@ function createAsyncIterableConverter(converter) { return undefined; } + // deno-lint-ignore prefer-primordials const returnPromiseResult = await iterator.return(reason); if (type(returnPromiseResult) !== "Object") { throw makeException( From 201ad3abfd7b066ce156e4b8a9ea56f2ba919ffb Mon Sep 17 00:00:00 2001 From: crowlkats Date: Thu, 18 Jul 2024 00:21:52 +0200 Subject: [PATCH 07/18] fix --- ext/fetch/22_body.js | 5 ++--- ext/webidl/00_webidl.js | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index 9cb251de622aa0..19d7f6be28d2fa 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -472,9 +472,7 @@ webidl.converters["async iterable"] = webidl webidl.converters["BodyInit_DOMString"] = (V, prefix, context, opts) => { // Union for (ReadableStream or Blob or ArrayBufferView or ArrayBuffer or FormData or URLSearchParams or USVString) - if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, V)) { - return webidl.converters["ReadableStream"](V, prefix, context, opts); - } else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) { + if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) { return webidl.converters["Blob"](V, prefix, context, opts); } else if (ObjectPrototypeIsPrototypeOf(FormDataPrototype, V)) { return webidl.converters["FormData"](V, prefix, context, opts); @@ -488,6 +486,7 @@ webidl.converters["BodyInit_DOMString"] = (V, prefix, context, opts) => { if (ArrayBufferIsView(V)) { return webidl.converters["ArrayBufferView"](V, prefix, context, opts); } + return webidl.converters["async iterable"]( V, prefix, diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index e6dbf950194d40..27ad1f3561c232 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -966,6 +966,7 @@ function createAsyncIterableConverter(converter) { let iterator; return { async next() { + console.error("foo", this); if (!iterator) { if (V[SymbolIterator]) { iterator = CreateAsyncFromSyncIterator( From 494e88e5227d11ffcfc987a8dbdcd153fc5effdd Mon Sep 17 00:00:00 2001 From: crowlkats Date: Thu, 18 Jul 2024 16:17:32 +0200 Subject: [PATCH 08/18] fix and tests --- ext/fetch/22_body.js | 18 ++++----- ext/webidl/00_webidl.js | 55 ++++++++++++++-------------- tests/integration/node_unit_tests.rs | 1 + tests/unit/streams_test.ts | 15 +++++++- tests/unit_node/fetch_test.ts | 18 +++++++++ tests/wpt/runner/expectation.json | 10 ++++- 6 files changed, 78 insertions(+), 39 deletions(-) create mode 100644 tests/unit_node/fetch_test.ts diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index 19d7f6be28d2fa..6e0e7276695b1d 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -441,15 +441,13 @@ function extractBody(object) { // deno-lint-ignore prefer-primordials source = object.toString(); contentType = "application/x-www-form-urlencoded;charset=UTF-8"; - } else if (object[SymbolAsyncIterator] !== undefined) { - if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, object.value)) { - stream = object.value; - if (object.value.locked || isReadableStreamDisturbed(object.value)) { - throw new TypeError("ReadableStream is locked or disturbed"); - } - } else { - stream = ReadableStream.from(object); + } else if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, object)) { + stream = object; + if (object.locked || isReadableStreamDisturbed(object)) { + throw new TypeError("ReadableStream is locked or disturbed"); } + } else if (object[SymbolAsyncIterator] !== undefined) { + stream = ReadableStream.from(object); } if (typeof source === "string") { // WARNING: this deviates from spec (expects length to be set) @@ -472,7 +470,9 @@ webidl.converters["async iterable"] = webidl webidl.converters["BodyInit_DOMString"] = (V, prefix, context, opts) => { // Union for (ReadableStream or Blob or ArrayBufferView or ArrayBuffer or FormData or URLSearchParams or USVString) - if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) { + if (ObjectPrototypeIsPrototypeOf(ReadableStreamPrototype, V)) { + return webidl.converters["ReadableStream"](V, prefix, context, opts); + } else if (ObjectPrototypeIsPrototypeOf(BlobPrototype, V)) { return webidl.converters["Blob"](V, prefix, context, opts); } else if (ObjectPrototypeIsPrototypeOf(FormDataPrototype, V)) { return webidl.converters["FormData"](V, prefix, context, opts); diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 27ad1f3561c232..f370a9a99f9ba6 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -921,17 +921,40 @@ function createSequenceConverter(converter) { }; } -// Ref: https://tc39.es/ecma262/#sec-getiterator, modified to not call the iterator -function getIteratorAsync(obj) { +// Ref: https://tc39.es/ecma262/#sec-getiterator +function getIteratorAsync(obj, prefix, context) { const method = obj[SymbolAsyncIterator]; if (method === undefined) { const syncMethod = obj[SymbolIterator]; + if (syncMethod === undefined) { throw new TypeError("No iterator found"); } - return syncMethod; + + const iter = FunctionPrototypeCall(syncMethod, obj); + + if (type(iter) !== "Object") { + throw makeException( + TypeError, + "can not be converted to async iterable.", + prefix, + context, + ); + } + + return CreateAsyncFromSyncIterator(iter); } else { - return method; + const iter = FunctionPrototypeCall(method, obj); + if (type(iter) !== "Object") { + throw makeException( + TypeError, + "can not be converted to async iterable.", + prefix, + context, + ); + } + + return iter; } } @@ -961,22 +984,10 @@ function createAsyncIterableConverter(converter) { ); } - const iter = getIteratorAsync(V); + const iterator = getIteratorAsync(V, prefix, context); - let iterator; return { async next() { - console.error("foo", this); - if (!iterator) { - if (V[SymbolIterator]) { - iterator = CreateAsyncFromSyncIterator( - FunctionPrototypeCall(iter, V), - ); - } else { - iterator = FunctionPrototypeCall(iter, V); - } - } - // deno-lint-ignore prefer-primordials const iterResult = await iterator.next(); if (type(iterResult) !== "Object") { @@ -1002,16 +1013,6 @@ function createAsyncIterableConverter(converter) { return { done: false, value: iterValue }; }, async return(reason) { - if (!iterator) { - if (V[SymbolIterator]) { - iterator = CreateAsyncFromSyncIterator( - FunctionPrototypeCall(iter, V), - ); - } else { - iterator = FunctionPrototypeCall(iter, V); - } - } - if (iterator.return === undefined) { return undefined; } diff --git a/tests/integration/node_unit_tests.rs b/tests/integration/node_unit_tests.rs index 4f0b613788fa5e..e87f1cd2f8d3c1 100644 --- a/tests/integration/node_unit_tests.rs +++ b/tests/integration/node_unit_tests.rs @@ -71,6 +71,7 @@ util::unit_test_factory!( dgram_test, domain_test, fs_test, + fetch_test, http_test, http2_test, _randomBytes_test = internal / _randomBytes_test, diff --git a/tests/unit/streams_test.ts b/tests/unit/streams_test.ts index 80b45e6024af4b..c0adbda07c1ded 100644 --- a/tests/unit/streams_test.ts +++ b/tests/unit/streams_test.ts @@ -1,5 +1,10 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { assertEquals, assertRejects, fail } from "./test_util.ts"; +import { + assertEquals, + assertRejects, + assertThrows, + fail, +} from "./test_util.ts"; const { core, @@ -533,3 +538,11 @@ Deno.test(async function decompressionStreamInvalidGzipStillReported() { "corrupt gzip stream does not have a matching checksum", ); }); + +Deno.test(function readableStreamFromWithStringThrows() { + assertThrows( + () => ReadableStream.from("string"), + TypeError, + "Failed to execute 'ReadableStream.from': Argument 1 can not be converted to async iterable.", + ); +}); diff --git a/tests/unit_node/fetch_test.ts b/tests/unit_node/fetch_test.ts new file mode 100644 index 00000000000000..cccfded695bb3d --- /dev/null +++ b/tests/unit_node/fetch_test.ts @@ -0,0 +1,18 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +import { assertEquals } from "@std/assert/mod.ts"; +import { createReadStream } from "node:fs"; + +Deno.test("fetch node stream", async () => { + const file = createReadStream("tests/testdata/assets/fixture.json"); + + const response = await fetch("http://localhost:4545/echo_server", { + method: "POST", + body: file, + }); + + assertEquals( + response.text(), + await Deno.readTextFile("tests/testdata/assets/fixture.json"), + ); +}); diff --git a/tests/wpt/runner/expectation.json b/tests/wpt/runner/expectation.json index cd212f9c4ea64c..8ab6ada6fe913a 100644 --- a/tests/wpt/runner/expectation.json +++ b/tests/wpt/runner/expectation.json @@ -4007,8 +4007,14 @@ "owning-type-message-port.any.worker.html": false, "owning-type.any.html": false, "owning-type.any.worker.html": false, - "from.any.html": true, - "from.any.worker.html": true + "from.any.html": [ + "ReadableStream.from ignores a null @@asyncIterator", + "ReadableStream.from accepts a string" + ], + "from.any.worker.html": [ + "ReadableStream.from ignores a null @@asyncIterator", + "ReadableStream.from accepts a string" + ] }, "transform-streams": { "backpressure.any.html": true, From a106413cbd66827f942a3747bf5618dd27be5390 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Thu, 18 Jul 2024 16:39:02 +0200 Subject: [PATCH 09/18] update typings --- ext/fetch/lib.deno_fetch.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/fetch/lib.deno_fetch.d.ts b/ext/fetch/lib.deno_fetch.d.ts index c27313903d4eb5..3bf608cdb439b0 100644 --- a/ext/fetch/lib.deno_fetch.d.ts +++ b/ext/fetch/lib.deno_fetch.d.ts @@ -163,6 +163,7 @@ declare type BodyInit = | FormData | URLSearchParams | ReadableStream + | AsyncIterable | string; /** @category Fetch */ declare type RequestDestination = From b3542c416b79732385250534d27868bb8578b894 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Thu, 18 Jul 2024 17:32:27 +0200 Subject: [PATCH 10/18] fix --- tests/unit_node/fetch_test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_node/fetch_test.ts b/tests/unit_node/fetch_test.ts index cccfded695bb3d..e4aca2ce5120ae 100644 --- a/tests/unit_node/fetch_test.ts +++ b/tests/unit_node/fetch_test.ts @@ -12,7 +12,7 @@ Deno.test("fetch node stream", async () => { }); assertEquals( - response.text(), + await response.text(), await Deno.readTextFile("tests/testdata/assets/fixture.json"), ); }); From 23dc7a55dee7486d7e114f3fe01bb096ff4e8684 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Fri, 19 Jul 2024 01:00:06 +0200 Subject: [PATCH 11/18] fixes --- ext/fetch/22_body.js | 15 ++++++++------- ext/webidl/00_webidl.js | 32 ++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index 6e0e7276695b1d..28eb6c7ec9d7e0 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -486,13 +486,14 @@ webidl.converters["BodyInit_DOMString"] = (V, prefix, context, opts) => { if (ArrayBufferIsView(V)) { return webidl.converters["ArrayBufferView"](V, prefix, context, opts); } - - return webidl.converters["async iterable"]( - V, - prefix, - context, - opts, - ); + if (webidl.isIterator(V)) { + return webidl.converters["async iterable"]( + V, + prefix, + context, + opts, + ); + } } // BodyInit conversion is passed to extractBody(), which calls core.encode(). // core.encode() will UTF-8 encode strings with replacement, being equivalent to the USV normalization. diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index f370a9a99f9ba6..18f1b3438203b9 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -921,6 +921,16 @@ function createSequenceConverter(converter) { }; } +function isIterator(obj) { + if (obj[SymbolAsyncIterator] === undefined) { + if (obj[SymbolIterator] === undefined) { + return false; + } + } + + return true; +} + // Ref: https://tc39.es/ecma262/#sec-getiterator function getIteratorAsync(obj, prefix, context) { const method = obj[SymbolAsyncIterator]; @@ -928,7 +938,7 @@ function getIteratorAsync(obj, prefix, context) { const syncMethod = obj[SymbolIterator]; if (syncMethod === undefined) { - throw new TypeError("No iterator found"); + throw new TypeError("No iterator found."); } const iter = FunctionPrototypeCall(syncMethod, obj); @@ -942,7 +952,14 @@ function getIteratorAsync(obj, prefix, context) { ); } - return CreateAsyncFromSyncIterator(iter); + return { + // deno-lint-ignore require-await + async next() { + // deno-lint-ignore prefer-primordials + return iter.next(); + }, + }; + ; } else { const iter = FunctionPrototypeCall(method, obj); if (type(iter) !== "Object") { @@ -958,16 +975,6 @@ function getIteratorAsync(obj, prefix, context) { } } -function CreateAsyncFromSyncIterator(iter) { - return { - // deno-lint-ignore require-await - async next() { - // deno-lint-ignore prefer-primordials - return iter.next(); - }, - }; -} - function createAsyncIterableConverter(converter) { return function ( V, @@ -1420,6 +1427,7 @@ export { createSequenceConverter, illegalConstructor, invokeCallbackFunction, + isIterator, makeException, mixinPairIterable, requiredArguments, From 0265eda0ad99f68df84e2e66ddbca30c99c88330 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Fri, 19 Jul 2024 01:00:26 +0200 Subject: [PATCH 12/18] fmt --- ext/webidl/00_webidl.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 18f1b3438203b9..398a5a97034ba4 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -959,7 +959,6 @@ function getIteratorAsync(obj, prefix, context) { return iter.next(); }, }; - ; } else { const iter = FunctionPrototypeCall(method, obj); if (type(iter) !== "Object") { From d3a943f703632df649fedcb3479557c5888fd8f5 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Sun, 21 Jul 2024 23:16:15 +0200 Subject: [PATCH 13/18] rework --- ext/fetch/22_body.js | 4 +- ext/web/06_streams.js | 5 +- ext/webidl/00_webidl.js | 138 ++++++++++++++++++++-------------------- 3 files changed, 75 insertions(+), 72 deletions(-) diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index 28eb6c7ec9d7e0..a0318d7aad4a36 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -446,8 +446,8 @@ function extractBody(object) { if (object.locked || isReadableStreamDisturbed(object)) { throw new TypeError("ReadableStream is locked or disturbed"); } - } else if (object[SymbolAsyncIterator] !== undefined) { - stream = ReadableStream.from(object); + } else if (object[webidl.AsyncIterable] === webidl.AsyncIterable) { + stream = ReadableStream.from(object.open()); } if (typeof source === "string") { // WARNING: this deviates from spec (expects length to be set) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 6b24221a35ba12..ea3a3110f63bba 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -5178,10 +5178,11 @@ class ReadableStream { prefix, "Argument 1", ); + const iter = asyncIterable.open(); const stream = createReadableStream(noop, async () => { // deno-lint-ignore prefer-primordials - const res = await asyncIterable.next(); + const res = await iter.next(); if (res.done) { readableStreamDefaultControllerClose(stream[_controller]); } else { @@ -5192,7 +5193,7 @@ class ReadableStream { } }, async (reason) => { // deno-lint-ignore prefer-primordials - await asyncIterable.return(reason); + await iter.return(reason); }, 0); return stream; } diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 398a5a97034ba4..ea7f00002f5b46 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -931,8 +931,7 @@ function isIterator(obj) { return true; } -// Ref: https://tc39.es/ecma262/#sec-getiterator -function getIteratorAsync(obj, prefix, context) { +function getIteratorAsync(obj) { const method = obj[SymbolAsyncIterator]; if (method === undefined) { const syncMethod = obj[SymbolIterator]; @@ -941,39 +940,14 @@ function getIteratorAsync(obj, prefix, context) { throw new TypeError("No iterator found."); } - const iter = FunctionPrototypeCall(syncMethod, obj); - - if (type(iter) !== "Object") { - throw makeException( - TypeError, - "can not be converted to async iterable.", - prefix, - context, - ); - } - - return { - // deno-lint-ignore require-await - async next() { - // deno-lint-ignore prefer-primordials - return iter.next(); - }, - }; + return [syncMethod, false]; } else { - const iter = FunctionPrototypeCall(method, obj); - if (type(iter) !== "Object") { - throw makeException( - TypeError, - "can not be converted to async iterable.", - prefix, - context, - ); - } - - return iter; + return [method, true]; } } +const AsyncIterable = Symbol("[[asyncIterable]]"); + function createAsyncIterableConverter(converter) { return function ( V, @@ -990,56 +964,83 @@ function createAsyncIterableConverter(converter) { ); } - const iterator = getIteratorAsync(V, prefix, context); + const [iterator, isAsync] = getIteratorAsync(V); return { - async next() { - // deno-lint-ignore prefer-primordials - const iterResult = await iterator.next(); - if (type(iterResult) !== "Object") { + value: V, + [AsyncIterable]: AsyncIterable, + open() { + const iter = FunctionPrototypeCall(iterator, V); + if (type(iter) !== "Object") { throw makeException( TypeError, - "can not be converted to async iterable.", + "invalid iterator.", prefix, context, ); } - if (iterResult.done) { - return { done: true }; - } - - const iterValue = converter( - iterResult.value, - prefix, - context, - opts, - ); - - return { done: false, value: iterValue }; - }, - async return(reason) { - if (iterator.return === undefined) { - return undefined; - } + let asyncIterator = iter; - // deno-lint-ignore prefer-primordials - const returnPromiseResult = await iterator.return(reason); - if (type(returnPromiseResult) !== "Object") { - throw makeException( - TypeError, - "can not be converted to async iterable.", - prefix, - context, - ); + if (!isAsync) { + asyncIterator = { + // deno-lint-ignore require-await + async next() { + // deno-lint-ignore prefer-primordials + return iter.next(); + }, + }; } - return undefined; - }, - [SymbolAsyncIterator]() { - return this; + return { + async next() { + // deno-lint-ignore prefer-primordials + const iterResult = await asyncIterator.next(); + if (type(iterResult) !== "Object") { + throw makeException( + TypeError, + "can not be converted to async iterable.", + prefix, + context, + ); + } + + if (iterResult.done) { + return { done: true }; + } + + const iterValue = converter( + iterResult.value, + prefix, + context, + opts, + ); + + return { done: false, value: iterValue }; + }, + async return(reason) { + if (asyncIterator.return === undefined) { + return undefined; + } + + // deno-lint-ignore prefer-primordials + const returnPromiseResult = await iterator.return(reason); + if (type(returnPromiseResult) !== "Object") { + throw makeException( + TypeError, + "can not be converted to async iterable.", + prefix, + context, + ); + } + + return undefined; + }, + [SymbolAsyncIterator]() { + return this; + }, + }; }, - value: V, }; }; } @@ -1412,6 +1413,7 @@ function setlike(obj, objPrototype, readonly) { export { assertBranded, + AsyncIterable, brand, configureInterface, converters, From d7c6e32a2ac9ee132b416a655c40fba3c2702488 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Sun, 21 Jul 2024 23:57:54 +0200 Subject: [PATCH 14/18] fix --- ext/fetch/22_body.js | 1 - ext/webidl/00_webidl.js | 31 +++++++++++++------------------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index a0318d7aad4a36..b63d803e6cf7ad 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -32,7 +32,6 @@ const { TypedArrayPrototypeSlice, TypeError, Uint8Array, - SymbolAsyncIterator, } = primordials; import * as webidl from "ext:deno_webidl/00_webidl.js"; diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index ea7f00002f5b46..0d878178c07d70 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -931,21 +931,6 @@ function isIterator(obj) { return true; } -function getIteratorAsync(obj) { - const method = obj[SymbolAsyncIterator]; - if (method === undefined) { - const syncMethod = obj[SymbolIterator]; - - if (syncMethod === undefined) { - throw new TypeError("No iterator found."); - } - - return [syncMethod, false]; - } else { - return [method, true]; - } -} - const AsyncIterable = Symbol("[[asyncIterable]]"); function createAsyncIterableConverter(converter) { @@ -964,13 +949,23 @@ function createAsyncIterableConverter(converter) { ); } - const [iterator, isAsync] = getIteratorAsync(V); + let isAsync = true; + let method = V[SymbolAsyncIterator]; + if (method === undefined) { + method = V[SymbolIterator]; + + if (method === undefined) { + throw new TypeError("No iterator found."); + } + + isAsync = true; + } return { value: V, [AsyncIterable]: AsyncIterable, open() { - const iter = FunctionPrototypeCall(iterator, V); + const iter = FunctionPrototypeCall(method, V); if (type(iter) !== "Object") { throw makeException( TypeError, @@ -1024,7 +1019,7 @@ function createAsyncIterableConverter(converter) { } // deno-lint-ignore prefer-primordials - const returnPromiseResult = await iterator.return(reason); + const returnPromiseResult = await asyncIterator.return(reason); if (type(returnPromiseResult) !== "Object") { throw makeException( TypeError, From f130c1943a154edb8edbe4ca9a01e8e489523184 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Fri, 2 Aug 2024 16:05:33 +0200 Subject: [PATCH 15/18] address comments Co-authored-by: Luca Casonato --- ext/fetch/22_body.js | 2 +- ext/webidl/00_webidl.js | 38 ++++++++++++++------------------------ 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/ext/fetch/22_body.js b/ext/fetch/22_body.js index b63d803e6cf7ad..9a2573fc322c94 100644 --- a/ext/fetch/22_body.js +++ b/ext/fetch/22_body.js @@ -485,7 +485,7 @@ webidl.converters["BodyInit_DOMString"] = (V, prefix, context, opts) => { if (ArrayBufferIsView(V)) { return webidl.converters["ArrayBufferView"](V, prefix, context, opts); } - if (webidl.isIterator(V)) { + if (webidl.isAsyncIterator(V)) { return webidl.converters["async iterable"]( V, prefix, diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 0d878178c07d70..639ad125828a67 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -921,7 +921,7 @@ function createSequenceConverter(converter) { }; } -function isIterator(obj) { +function isAsyncIterator(obj) { if (obj[SymbolAsyncIterator] === undefined) { if (obj[SymbolIterator] === undefined) { return false; @@ -955,24 +955,24 @@ function createAsyncIterableConverter(converter) { method = V[SymbolIterator]; if (method === undefined) { - throw new TypeError("No iterator found."); + throw makeException( + TypeError, + "is not iterable.", + prefix, + context, + ); } - isAsync = true; + isAsync = false; } return { value: V, [AsyncIterable]: AsyncIterable, - open() { + open(context) { const iter = FunctionPrototypeCall(method, V); if (type(iter) !== "Object") { - throw makeException( - TypeError, - "invalid iterator.", - prefix, - context, - ); + throw new TypeError(`${context} could not be iterated because iterator method did not return object, but ${type(iter)}.`); } let asyncIterator = iter; @@ -992,12 +992,7 @@ function createAsyncIterableConverter(converter) { // deno-lint-ignore prefer-primordials const iterResult = await asyncIterator.next(); if (type(iterResult) !== "Object") { - throw makeException( - TypeError, - "can not be converted to async iterable.", - prefix, - context, - ); + throw TypeError(`${context} failed to iterate next value because the next() method did not return an object, but ${type(iterResult)}.`); } if (iterResult.done) { @@ -1006,8 +1001,8 @@ function createAsyncIterableConverter(converter) { const iterValue = converter( iterResult.value, - prefix, - context, + `${context} failed to iterate next value`, + `The value returned from the next() method`, opts, ); @@ -1021,12 +1016,7 @@ function createAsyncIterableConverter(converter) { // deno-lint-ignore prefer-primordials const returnPromiseResult = await asyncIterator.return(reason); if (type(returnPromiseResult) !== "Object") { - throw makeException( - TypeError, - "can not be converted to async iterable.", - prefix, - context, - ); + throw TypeError(`${context} failed to close iterator because the return() method did not return an object, but ${type(returnPromiseResult)}.`); } return undefined; From 0e5faf876d317685166e2d2d825b8cb5c2df9300 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Fri, 2 Aug 2024 16:06:19 +0200 Subject: [PATCH 16/18] fmt --- ext/webidl/00_webidl.js | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 639ad125828a67..4b8916f2cf3f93 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -955,12 +955,12 @@ function createAsyncIterableConverter(converter) { method = V[SymbolIterator]; if (method === undefined) { - throw makeException( - TypeError, - "is not iterable.", - prefix, - context, - ); + throw makeException( + TypeError, + "is not iterable.", + prefix, + context, + ); } isAsync = false; @@ -972,7 +972,11 @@ function createAsyncIterableConverter(converter) { open(context) { const iter = FunctionPrototypeCall(method, V); if (type(iter) !== "Object") { - throw new TypeError(`${context} could not be iterated because iterator method did not return object, but ${type(iter)}.`); + throw new TypeError( + `${context} could not be iterated because iterator method did not return object, but ${ + type(iter) + }.`, + ); } let asyncIterator = iter; @@ -992,7 +996,11 @@ function createAsyncIterableConverter(converter) { // deno-lint-ignore prefer-primordials const iterResult = await asyncIterator.next(); if (type(iterResult) !== "Object") { - throw TypeError(`${context} failed to iterate next value because the next() method did not return an object, but ${type(iterResult)}.`); + throw TypeError( + `${context} failed to iterate next value because the next() method did not return an object, but ${ + type(iterResult) + }.`, + ); } if (iterResult.done) { @@ -1016,7 +1024,11 @@ function createAsyncIterableConverter(converter) { // deno-lint-ignore prefer-primordials const returnPromiseResult = await asyncIterator.return(reason); if (type(returnPromiseResult) !== "Object") { - throw TypeError(`${context} failed to close iterator because the return() method did not return an object, but ${type(returnPromiseResult)}.`); + throw TypeError( + `${context} failed to close iterator because the return() method did not return an object, but ${ + type(returnPromiseResult) + }.`, + ); } return undefined; From e6176f63c7242b1ae945dcb46006bef9e52649b2 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Fri, 2 Aug 2024 16:40:47 +0200 Subject: [PATCH 17/18] fix --- ext/webidl/00_webidl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/webidl/00_webidl.js b/ext/webidl/00_webidl.js index 4b8916f2cf3f93..7440e47e7baf3a 100644 --- a/ext/webidl/00_webidl.js +++ b/ext/webidl/00_webidl.js @@ -1425,7 +1425,7 @@ export { createSequenceConverter, illegalConstructor, invokeCallbackFunction, - isIterator, + isAsyncIterator, makeException, mixinPairIterable, requiredArguments, From 81c30e8fc8929580a27b113d76877e00f7638350 Mon Sep 17 00:00:00 2001 From: crowlkats Date: Fri, 2 Aug 2024 20:42:29 +0200 Subject: [PATCH 18/18] fix test --- tests/unit_node/fetch_test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_node/fetch_test.ts b/tests/unit_node/fetch_test.ts index e4aca2ce5120ae..399d6052a56377 100644 --- a/tests/unit_node/fetch_test.ts +++ b/tests/unit_node/fetch_test.ts @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { assertEquals } from "@std/assert/mod.ts"; +import { assertEquals } from "@std/assert"; import { createReadStream } from "node:fs"; Deno.test("fetch node stream", async () => {