Await promises from sync iterators with for-await (#13824)
Co-authored-by: Mickey Rose <lightmare@users.noreply.github.com>
This commit is contained in:
parent
6029252bec
commit
b9ea196259
@ -5,6 +5,14 @@
|
||||
|
||||
import template from "@babel/template";
|
||||
|
||||
export const asyncIterator = {
|
||||
minVersion: "7.15.9",
|
||||
ast: () =>
|
||||
template.program.ast(
|
||||
'\nexport default function _asyncIterator(iterable) {\n var method, async, sync;\n if (typeof Symbol !== "undefined") {\n async = Symbol.asyncIterator;\n sync = Symbol.iterator;\n }\n do {\n if (!sync) {\n async = "@@asyncIterator";\n sync = "@@iterator";\n }\n if (async && (method = iterable[async]) != null) {\n return method.call(iterable);\n }\n if ((method = iterable[sync]) != null) {\n return new AsyncFromSyncIterator(method.call(iterable));\n }\n } while (!(sync === "@@iterator" || (sync = null)));\n throw new TypeError("Object is not async iterable");\n}\nfunction AsyncFromSyncIterator(s) {\n AsyncFromSyncIterator = function (s) {\n this.s = s;\n this.n = s.next;\n };\n AsyncFromSyncIterator.prototype = {\n s: null,\n n: null,\n next: function () {\n return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));\n },\n return: function (value) {\n var ret = this.s.return;\n if (ret === undefined) {\n return Promise.resolve({ value: value, done: true });\n }\n return AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments));\n },\n throw: function (value) {\n var thr = this.s.return;\n if (thr === undefined) return Promise.reject(value);\n return AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments));\n },\n };\n function AsyncFromSyncIteratorContinuation(r) {\n \n if (Object(r) !== r) {\n return Promise.reject(new TypeError(r + " is not an object."));\n }\n var done = r.done;\n return Promise.resolve(r.value).then(function (value) {\n return { value: value, done: done };\n });\n }\n return new AsyncFromSyncIterator(s);\n}\n',
|
||||
),
|
||||
};
|
||||
|
||||
export const jsx = {
|
||||
minVersion: "7.0.0-beta.0",
|
||||
ast: () =>
|
||||
|
||||
@ -16,20 +16,6 @@ const helper = (minVersion: string) => (tpl: TemplateStringsArray) => ({
|
||||
ast: () => template.program.ast(tpl),
|
||||
});
|
||||
|
||||
helpers.asyncIterator = helper("7.0.0-beta.0")`
|
||||
export default function _asyncIterator(iterable) {
|
||||
var method;
|
||||
if (typeof Symbol !== "undefined") {
|
||||
if (Symbol.asyncIterator) method = iterable[Symbol.asyncIterator];
|
||||
if (method == null && Symbol.iterator) method = iterable[Symbol.iterator];
|
||||
}
|
||||
if (method == null) method = iterable["@@asyncIterator"];
|
||||
if (method == null) method = iterable["@@iterator"]
|
||||
if (method == null) throw new TypeError("Object is not async iterable");
|
||||
return method.call(iterable);
|
||||
}
|
||||
`;
|
||||
|
||||
helpers.AwaitValue = helper("7.0.0-beta.0")`
|
||||
export default function _AwaitValue(value) {
|
||||
this.wrapped = value;
|
||||
|
||||
67
packages/babel-helpers/src/helpers/asyncIterator.js
Normal file
67
packages/babel-helpers/src/helpers/asyncIterator.js
Normal file
@ -0,0 +1,67 @@
|
||||
/* @minVersion 7.15.9 */
|
||||
|
||||
export default function _asyncIterator(iterable) {
|
||||
var method,
|
||||
async,
|
||||
sync,
|
||||
retry = 2;
|
||||
|
||||
if (typeof Symbol !== "undefined") {
|
||||
async = Symbol.asyncIterator;
|
||||
sync = Symbol.iterator;
|
||||
}
|
||||
|
||||
while (retry--) {
|
||||
if (async && (method = iterable[async]) != null) {
|
||||
return method.call(iterable);
|
||||
}
|
||||
if (sync && (method = iterable[sync]) != null) {
|
||||
return new AsyncFromSyncIterator(method.call(iterable));
|
||||
}
|
||||
|
||||
async = "@@asyncIterator";
|
||||
sync = "@@iterator";
|
||||
}
|
||||
|
||||
throw new TypeError("Object is not async iterable");
|
||||
}
|
||||
|
||||
function AsyncFromSyncIterator(s) {
|
||||
AsyncFromSyncIterator = function (s) {
|
||||
this.s = s;
|
||||
this.n = s.next;
|
||||
};
|
||||
AsyncFromSyncIterator.prototype = {
|
||||
/* SyncIterator */ s: null,
|
||||
/* SyncIterator.[[Next]] */ n: null,
|
||||
next: function () {
|
||||
return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));
|
||||
},
|
||||
return: function (value) {
|
||||
var ret = this.s.return;
|
||||
if (ret === undefined) {
|
||||
return Promise.resolve({ value: value, done: true });
|
||||
}
|
||||
return AsyncFromSyncIteratorContinuation(ret.apply(this.s, arguments));
|
||||
},
|
||||
throw: function (value) {
|
||||
var thr = this.s.return;
|
||||
if (thr === undefined) return Promise.reject(value);
|
||||
return AsyncFromSyncIteratorContinuation(thr.apply(this.s, arguments));
|
||||
},
|
||||
};
|
||||
|
||||
function AsyncFromSyncIteratorContinuation(r) {
|
||||
// This step is _before_ calling AsyncFromSyncIteratorContinuation in the spec.
|
||||
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 new AsyncFromSyncIterator(s);
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
async function* fn() {
|
||||
for await (const result of [Promise.resolve("ok")]) {
|
||||
return { result };
|
||||
}
|
||||
}
|
||||
|
||||
return fn().next().then(result => {
|
||||
expect(result).toEqual({
|
||||
done: true,
|
||||
value: { result: "ok" }
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,5 @@
|
||||
async function* fn() {
|
||||
for await (const result of [Promise.resolve("ok")]) {
|
||||
return { result };
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": ["proposal-async-generator-functions"],
|
||||
"parserOpts": {
|
||||
"allowReturnOutsideFunction": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
function fn() {
|
||||
return _fn.apply(this, arguments);
|
||||
}
|
||||
|
||||
function _fn() {
|
||||
_fn = babelHelpers.wrapAsyncGenerator(function* () {
|
||||
var _iteratorAbruptCompletion = false;
|
||||
var _didIteratorError = false;
|
||||
|
||||
var _iteratorError;
|
||||
|
||||
try {
|
||||
for (var _iterator = babelHelpers.asyncIterator([Promise.resolve("ok")]), _step; _iteratorAbruptCompletion = !(_step = yield babelHelpers.awaitAsyncGenerator(_iterator.next())).done; _iteratorAbruptCompletion = false) {
|
||||
const result = _step.value;
|
||||
return {
|
||||
result
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
_didIteratorError = true;
|
||||
_iteratorError = err;
|
||||
} finally {
|
||||
try {
|
||||
if (_iteratorAbruptCompletion && _iterator.return != null) {
|
||||
yield babelHelpers.awaitAsyncGenerator(_iterator.return());
|
||||
}
|
||||
} finally {
|
||||
if (_didIteratorError) {
|
||||
throw _iteratorError;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return _fn.apply(this, arguments);
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
async function* fn() {
|
||||
yield* [Promise.resolve("ok")] // CreateAsyncFromSyncIterator
|
||||
}
|
||||
|
||||
return fn().next().then(result => {
|
||||
expect(result).toEqual({ value: "ok", done: false });
|
||||
});
|
||||
@ -0,0 +1,3 @@
|
||||
async function* fn() {
|
||||
yield* [Promise.resolve("ok")] // CreateAsyncFromSyncIterator
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": ["proposal-async-generator-functions"],
|
||||
"parserOpts": {
|
||||
"allowReturnOutsideFunction": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
function fn() {
|
||||
return _fn.apply(this, arguments);
|
||||
}
|
||||
|
||||
function _fn() {
|
||||
_fn = babelHelpers.wrapAsyncGenerator(function* () {
|
||||
yield* babelHelpers.asyncGeneratorDelegate(babelHelpers.asyncIterator([Promise.resolve("ok")]), babelHelpers.awaitAsyncGenerator); // CreateAsyncFromSyncIterator
|
||||
});
|
||||
return _fn.apply(this, arguments);
|
||||
}
|
||||
@ -18,6 +18,15 @@
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
},
|
||||
"exports": {
|
||||
"./helpers/asyncIterator": [
|
||||
{
|
||||
"node": "./helpers/asyncIterator.js",
|
||||
"import": "./helpers/esm/asyncIterator.js",
|
||||
"default": "./helpers/asyncIterator.js"
|
||||
},
|
||||
"./helpers/asyncIterator.js"
|
||||
],
|
||||
"./helpers/esm/asyncIterator": "./helpers/esm/asyncIterator.js",
|
||||
"./helpers/jsx": [
|
||||
{
|
||||
"node": "./helpers/jsx.js",
|
||||
@ -54,15 +63,6 @@
|
||||
"./helpers/wrapRegExp.js"
|
||||
],
|
||||
"./helpers/esm/wrapRegExp": "./helpers/esm/wrapRegExp.js",
|
||||
"./helpers/asyncIterator": [
|
||||
{
|
||||
"node": "./helpers/asyncIterator.js",
|
||||
"import": "./helpers/esm/asyncIterator.js",
|
||||
"default": "./helpers/asyncIterator.js"
|
||||
},
|
||||
"./helpers/asyncIterator.js"
|
||||
],
|
||||
"./helpers/esm/asyncIterator": "./helpers/esm/asyncIterator.js",
|
||||
"./helpers/AwaitValue": [
|
||||
{
|
||||
"node": "./helpers/AwaitValue.js",
|
||||
|
||||
@ -17,6 +17,15 @@
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
},
|
||||
"exports": {
|
||||
"./helpers/asyncIterator": [
|
||||
{
|
||||
"node": "./helpers/asyncIterator.js",
|
||||
"import": "./helpers/esm/asyncIterator.js",
|
||||
"default": "./helpers/asyncIterator.js"
|
||||
},
|
||||
"./helpers/asyncIterator.js"
|
||||
],
|
||||
"./helpers/esm/asyncIterator": "./helpers/esm/asyncIterator.js",
|
||||
"./helpers/jsx": [
|
||||
{
|
||||
"node": "./helpers/jsx.js",
|
||||
@ -53,15 +62,6 @@
|
||||
"./helpers/wrapRegExp.js"
|
||||
],
|
||||
"./helpers/esm/wrapRegExp": "./helpers/esm/wrapRegExp.js",
|
||||
"./helpers/asyncIterator": [
|
||||
{
|
||||
"node": "./helpers/asyncIterator.js",
|
||||
"import": "./helpers/esm/asyncIterator.js",
|
||||
"default": "./helpers/asyncIterator.js"
|
||||
},
|
||||
"./helpers/asyncIterator.js"
|
||||
],
|
||||
"./helpers/esm/asyncIterator": "./helpers/esm/asyncIterator.js",
|
||||
"./helpers/AwaitValue": [
|
||||
{
|
||||
"node": "./helpers/AwaitValue.js",
|
||||
|
||||
@ -17,6 +17,15 @@
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
},
|
||||
"exports": {
|
||||
"./helpers/asyncIterator": [
|
||||
{
|
||||
"node": "./helpers/asyncIterator.js",
|
||||
"import": "./helpers/esm/asyncIterator.js",
|
||||
"default": "./helpers/asyncIterator.js"
|
||||
},
|
||||
"./helpers/asyncIterator.js"
|
||||
],
|
||||
"./helpers/esm/asyncIterator": "./helpers/esm/asyncIterator.js",
|
||||
"./helpers/jsx": [
|
||||
{
|
||||
"node": "./helpers/jsx.js",
|
||||
@ -53,15 +62,6 @@
|
||||
"./helpers/wrapRegExp.js"
|
||||
],
|
||||
"./helpers/esm/wrapRegExp": "./helpers/esm/wrapRegExp.js",
|
||||
"./helpers/asyncIterator": [
|
||||
{
|
||||
"node": "./helpers/asyncIterator.js",
|
||||
"import": "./helpers/esm/asyncIterator.js",
|
||||
"default": "./helpers/asyncIterator.js"
|
||||
},
|
||||
"./helpers/asyncIterator.js"
|
||||
],
|
||||
"./helpers/esm/asyncIterator": "./helpers/esm/asyncIterator.js",
|
||||
"./helpers/AwaitValue": [
|
||||
{
|
||||
"node": "./helpers/AwaitValue.js",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user