diff --git a/crates/swc/tests/exec/git-keep/js/exec.js b/crates/swc/tests/exec/git-keep/js/exec.js deleted file mode 100644 index b2c376c6559..00000000000 --- a/crates/swc/tests/exec/git-keep/js/exec.js +++ /dev/null @@ -1 +0,0 @@ -console.log("Ensure that the directory is tracked by git"); diff --git a/crates/swc/tests/exec/git-keep/ts/exec.ts b/crates/swc/tests/exec/git-keep/ts/exec.ts deleted file mode 100644 index b2c376c6559..00000000000 --- a/crates/swc/tests/exec/git-keep/ts/exec.ts +++ /dev/null @@ -1 +0,0 @@ -console.log("Ensure that the directory is tracked by git"); diff --git a/crates/swc/tests/exec/issues-5xxx/5383/exec.js b/crates/swc/tests/exec/issues-5xxx/5383/exec.js new file mode 100644 index 00000000000..42c0bf8d81d --- /dev/null +++ b/crates/swc/tests/exec/issues-5xxx/5383/exec.js @@ -0,0 +1,10 @@ +const a1 = [1, 2, 3]; +const a2 = a1.map((x) => Promise.resolve(x)); + +async function f() { + for await (const v of a2) { + console.log(v); + } +} + +f(); \ No newline at end of file diff --git a/crates/swc_ecma_transforms_base/src/helpers/_async_iterator.js b/crates/swc_ecma_transforms_base/src/helpers/_async_iterator.js index 5a27a83f290..52ed87b9acb 100644 --- a/crates/swc_ecma_transforms_base/src/helpers/_async_iterator.js +++ b/crates/swc_ecma_transforms_base/src/helpers/_async_iterator.js @@ -1,17 +1,42 @@ function _asyncIterator(iterable) { - var method; - - if (typeof Symbol === "function") { - if (Symbol.asyncIterator) { - method = iterable[Symbol.asyncIterator]; - if (method != null) return method.call(iterable); - } - - if (Symbol.iterator) { - method = iterable[Symbol.iterator]; - if (method != null) return method.call(iterable); - } + var method, async, sync, retry = 2; + for ("undefined" != typeof Symbol && (async = Symbol.asyncIterator, sync = Symbol.iterator); retry--;) { + if (async && null != (method = iterable[async])) return method.call(iterable); + if (sync && null != (method = iterable[sync])) return new AsyncFromSyncIterator(method.call(iterable)); + async = "@@asyncIterator", sync = "@@iterator"; } - throw new TypeError("Object is not async iterable"); } + +function AsyncFromSyncIterator(s) { + function AsyncFromSyncIteratorContinuation(r) { + if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object.")); + var done = r.done; + return Promise.resolve(r.value).then(function (value) { + return { + value: value, + done: done + }; + }); + } + return AsyncFromSyncIterator = function (s) { + this.s = s, this.n = s.next; + }, AsyncFromSyncIterator.prototype = { + s: null, + n: null, + next: function () { + return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments)); + }, + return: function (value) { + var ret = this.s.return; + return void 0 === ret ? Promise.resolve({ + value: value, + done: !0 + }) : AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments)); + }, + throw: function (value) { + var thr = this.s.return; + return void 0 === thr ? Promise.reject(value) : AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments)); + } + }, new AsyncFromSyncIterator(s); +} \ No newline at end of file diff --git a/crates/swc_ecma_transforms_compat/tests/async-to-generator/issue-5383/1/exec.js b/crates/swc_ecma_transforms_compat/tests/async-to-generator/issue-5383/1/exec.js new file mode 100644 index 00000000000..30786880f73 --- /dev/null +++ b/crates/swc_ecma_transforms_compat/tests/async-to-generator/issue-5383/1/exec.js @@ -0,0 +1,10 @@ +const a1 = [1, 2, 3]; +const a2 = a1.map((x) => Promise.resolve(x)); + +async function f() { + for await (const v of a2) { + console.log(v); + } +} + +f(); \ No newline at end of file diff --git a/packages/swc-helpers/src/_async_iterator.mjs b/packages/swc-helpers/src/_async_iterator.mjs index 9f67652fb04..764a961da7b 100644 --- a/packages/swc-helpers/src/_async_iterator.mjs +++ b/packages/swc-helpers/src/_async_iterator.mjs @@ -1,17 +1,44 @@ export default function _asyncIterator(iterable) { - var method; - - if (typeof Symbol === "function") { - if (Symbol.asyncIterator) { - method = iterable[Symbol.asyncIterator]; - if (method != null) return method.call(iterable); - } - - if (Symbol.iterator) { - method = iterable[Symbol.iterator]; - if (method != null) return method.call(iterable); - } + var method, async, sync, retry = 2; + for ("undefined" != typeof Symbol && (async = Symbol.asyncIterator, sync = Symbol.iterator); retry--;) { + if (async && null != (method = iterable[async])) return method.call(iterable); + if (sync && null != (method = iterable[sync])) return new AsyncFromSyncIterator(method.call(iterable)); + async = "@@asyncIterator", sync = "@@iterator"; } - throw new TypeError("Object is not async iterable"); } + + + +function AsyncFromSyncIterator(s) { + function AsyncFromSyncIteratorContinuation(r) { + if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object.")); + var done = r.done; + return Promise.resolve(r.value).then(function (value) { + return { + value: value, + done: done + }; + }); + } + return AsyncFromSyncIterator = function (s) { + this.s = s, this.n = s.next; + }, AsyncFromSyncIterator.prototype = { + s: null, + n: null, + next: function () { + return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments)); + }, + return: function (value) { + var ret = this.s.return; + return void 0 === ret ? Promise.resolve({ + value: value, + done: !0 + }) : AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments)); + }, + throw: function (value) { + var thr = this.s.return; + return void 0 === thr ? Promise.reject(value) : AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments)); + } + }, new AsyncFromSyncIterator(s); +} \ No newline at end of file