Skip to content

Commit

Permalink
feat(ES2018): Implement AsyncIteratorClose
Browse files Browse the repository at this point in the history
  • Loading branch information
ExE-Boss committed Nov 6, 2019
1 parent 4523a17 commit be5c161
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@
"max-lines": [2, 1500],
},
},
{
"files": "./es2018.js",
"rules": {
"max-lines": [2, 500],
},
},
{
"files": "operations/*",
"rules": {
Expand Down
60 changes: 59 additions & 1 deletion es2018.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ var $parseInt = parseInt;

var isDigit = regexTester(/^[0-9]$/);

var $PromiseResolve = callBound('Promise.resolve', true);
/** @type {typeof Promise} */
var $Promise = GetIntrinsic('%Promise%', true);
var $PromiseResolve = callBound('%Promise.resolve%', true);
/** @type {(<T>(value: T | PromiseLike<T>) => Promise<T>) & (() => Promise<void>)} */
var $NewPromise = $Promise.resolve.bind($Promise);

var $isEnumerable = callBound('Object.prototype.propertyIsEnumerable');
var $pushApply = callBind.apply(GetIntrinsic('%Array.prototype.push%'));
Expand Down Expand Up @@ -248,6 +252,60 @@ var ES2018 = assign(assign({}, ES2017), {
return completionRecord;
},

// https://ecma-international.org/ecma-262/9.0/#sec-asynciteratorclose
/**
* @template T
* @param {{'[[Iterator]]': AsyncIterator<any>, '[[NextMethod]]': AsyncIterator<any>['next'], '[[Done]]': boolean}} iteratorRecord
* @param {() => T | PromiseLike<T>} completion
* @return {Promise<T>}
*/
AsyncIteratorClose: function AsyncIteratorClose(iteratorRecord, completion) {
/** @type {typeof completion} */
var completionThunk, iterator, iteratorReturn, completionRecord;
var ES = this;

// Heavily modified from the output of https://www.npmjs.com/package/babel-plugin-async-to-promises
return $NewPromise().then(function () {
if (ES.Type(iteratorRecord['[[Iterator]]']) !== 'Object') {
throw new $TypeError('Assertion failed: Type(iteratorRecord.[[Iterator]]) is not Object');
}

if (!ES.IsCallable(completion)) {
throw new $TypeError('Assertion failed: completion is not a thunk for a Completion Record');
}

completionThunk = completion;
iterator = iteratorRecord['[[Iterator]]'];
iteratorReturn = ES.GetMethod(iterator, 'return');

if (typeof iteratorReturn === 'undefined') {
return completionThunk();
} else {
return $NewPromise().then(function () {
return ES.Call(iteratorReturn, iterator, []);
}).then(function (innerResult) {
completionRecord = completionThunk(); // if innerResult worked, then throw if the completion does
completionThunk = null; // ensure it's not called twice.

if (ES.Type(innerResult) !== 'Object') {
throw new $TypeError('iterator .return must return an object');
}

return completionRecord;
}, function (e) {
// if we hit here, then "e" is the innerResult completion that needs re-throwing

// if the completion is of type "throw", this will throw.
completionRecord = completionThunk();
completionThunk = null; // ensure it's not called twice.

// if not, then return the innerResult completion
throw e;
});
}
});
},

// https://www.ecma-international.org/ecma-262/9.0/#sec-iterabletolist
IterableToList: function IterableToList(items, method) {
var iterator = this.GetIterator(items, 'sync', method);
Expand Down
2 changes: 1 addition & 1 deletion test/es2018.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions test/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -3798,6 +3798,8 @@ var es2018 = function ES2018(ES, ops, expectedMissing, skips) {
t.end();
});

test('AsyncIteratorClose', { skip: true });

test('PromiseResolve', function (t) {
t.test('Promises unsupported', { skip: typeof Promise === 'function' }, function (st) {
st['throws'](
Expand Down

0 comments on commit be5c161

Please sign in to comment.