diff --git a/.eslintrc b/.eslintrc index 28a29f41..a188ef65 100644 --- a/.eslintrc +++ b/.eslintrc @@ -40,6 +40,12 @@ "max-lines": [2, 1500], }, }, + { + "files": "./es2018.js", + "rules": { + "max-lines": [2, 500], + }, + }, { "files": "operations/*", "rules": { diff --git a/es2018.js b/es2018.js index a8d789cc..dc23229b 100644 --- a/es2018.js +++ b/es2018.js @@ -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 {((value: T | PromiseLike) => Promise) & (() => Promise)} */ +var $NewPromise = $Promise.resolve.bind($Promise); var $isEnumerable = callBound('Object.prototype.propertyIsEnumerable'); var $pushApply = callBind.apply(GetIntrinsic('%Array.prototype.push%')); @@ -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, '[[NextMethod]]': AsyncIterator['next'], '[[Done]]': boolean}} iteratorRecord + * @param {() => T | PromiseLike} completion + * @return {Promise} + */ + 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); diff --git a/test/es2018.js b/test/es2018.js index 37c029a3..1b4d12db 100644 --- a/test/es2018.js +++ b/test/es2018.js @@ -4,6 +4,6 @@ var ES = require('../').ES2018; var ops = require('../operations/2018'); -var expectedMissing = ['abs', 'AddRestrictedFunctionProperties', 'AddWaiter', 'agent-order', 'AgentCanSuspend', 'AgentSignifier', 'AllocateArrayBuffer', 'AllocateSharedArrayBuffer', 'AllocateTypedArray', 'AllocateTypedArrayBuffer', 'AsyncFunctionStart', 'AsyncGeneratorEnqueue', 'AsyncGeneratorReject', 'AsyncGeneratorResolve', 'AsyncGeneratorResumeNext', 'AsyncGeneratorStart', 'AsyncGeneratorYield', 'AtomicLoad', 'AtomicReadModifyWrite', 'Await', 'BlockDeclarationInstantiation', 'BoundFunctionCreate', 'Canonicalize', 'CaseClauseIsSelected', 'CharacterRange', 'CharacterRangeOrUnion', 'CharacterSetMatcher', 'CloneArrayBuffer', 'Completion', 'ComposeWriteEventBytes', 'CopyDataBlockBytes', 'CreateArrayIterator', 'CreateAsyncFromSyncIterator', 'CreateBuiltinFunction', 'CreateByteDataBlock', 'CreateDynamicFunction', 'CreateIntrinsics', 'CreateMapIterator', 'CreateMappedArgumentsObject', 'CreatePerIterationEnvironment', 'CreateRealm', 'CreateResolvingFunctions', 'CreateSetIterator', 'CreateSharedByteDataBlock', 'CreateStringIterator', 'CreateUnmappedArgumentsObject', 'Decode', 'DetachArrayBuffer', 'Encode', 'EnqueueJob', 'EnterCriticalSection', 'EnumerateObjectProperties', 'EscapeRegExpPattern', 'EvalDeclarationInstantiation', 'EvaluateCall', 'EvaluateNew', 'EventSet', 'floor', 'ForBodyEvaluation', 'ForIn/OfBodyEvaluation', 'ForIn/OfHeadEvaluation', 'FulfillPromise', 'FunctionAllocate', 'FunctionCreate', 'FunctionDeclarationInstantiation', 'FunctionInitialize', 'GeneratorFunctionCreate', 'GeneratorResume', 'GeneratorResumeAbrupt', 'GeneratorStart', 'GeneratorValidate', 'GeneratorYield', 'GetActiveScriptOrModule', 'GetBase', 'GetFunctionRealm', 'GetGeneratorKind', 'GetGlobalObject', 'GetIdentifierReference', 'GetModifySetValueInBuffer', 'GetModuleNamespace', 'GetNewTarget', 'GetReferencedName', 'GetSuperConstructor', 'GetTemplateObject', 'GetThisEnvironment', 'GetThisValue', 'GetValue', 'GetValueFromBuffer', 'GetViewValue', 'GetWaiterList', 'GlobalDeclarationInstantiation', 'happens-before', 'HasPrimitiveBase', 'host-synchronizes-with', 'HostEnsureCanCompileStrings', 'HostEventSet', 'HostPromiseRejectionTracker', 'HostReportErrors', 'HostResolveImportedModule', 'IfAbruptRejectPromise', 'ImportedLocalNames', 'InitializeBoundName', 'InitializeHostDefinedRealm', 'InitializeReferencedBinding', 'InnerModuleEvaluation', 'InnerModuleInstantiation', 'IntegerIndexedElementGet', 'IntegerIndexedElementSet', 'IntegerIndexedObjectCreate', 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsCompatiblePropertyDescriptor', 'IsDetachedBuffer', 'IsInTailPosition', 'IsLabelledFunction', 'IsPropertyReference', 'IsSharedArrayBuffer', 'IsStrictReference', 'IsSuperReference', 'IsUnresolvableReference', 'IsWordChar', 'LeaveCriticalSection', 'LocalTime', 'LoopContinues', 'MakeArgGetter', 'MakeArgSetter', 'MakeClassConstructor', 'MakeConstructor', 'MakeMethod', 'MakeSuperPropertyReference', 'max', 'memory-order', 'min', 'ModuleDeclarationEnvironmentSetup', 'ModuleExecution', 'ModuleNamespaceCreate', 'NewDeclarativeEnvironment', 'NewFunctionEnvironment', 'NewGlobalEnvironment', 'NewModuleEnvironment', 'NewObjectEnvironment', 'NewPromiseCapability', 'NumberToRawBytes', 'ObjectDefineProperties', 'OrdinaryCallBindThis', 'OrdinaryCallEvaluateBody', 'OrdinaryCreateFromConstructor', 'OrdinaryDelete', 'OrdinaryGet', 'OrdinaryIsExtensible', 'OrdinaryOwnPropertyKeys', 'OrdinaryPreventExtensions', 'OrdinaryToPrimitive', 'ParseModule', 'ParseScript', 'PerformEval', 'PerformPromiseAll', 'PerformPromiseRace', 'PerformPromiseThen', 'PrepareForOrdinaryCall', 'PrepareForTailCall', 'PromiseReactionJob', 'PromiseResolveThenableJob', 'ProxyCreate', 'PutValue', 'QuoteJSONString', 'RawBytesToNumber', 'reads-bytes-from', 'reads-from', 'RegExpAlloc', 'RegExpCreate', 'RegExpInitialize', 'RejectPromise', 'RemoveWaiter', 'RemoveWaiters', 'RepeatMatcher', 'ResolveBinding', 'ResolveThisBinding', 'ReturnIfAbrupt', 'RunJobs', 'ScriptEvaluation', 'ScriptEvaluationJob', 'SerializeJSONArray', 'SerializeJSONObject', 'SerializeJSONProperty', 'SetDefaultGlobalBindings', 'SetImmutablePrototype', 'SetRealmGlobalObject', 'SetValueInBuffer', 'SetViewValue', 'SharedDataBlockEventSet', 'SortCompare', 'SplitMatch', 'StringCreate', 'StringGetOwnProperty', 'Suspend', 'synchronizes-with', 'TimeZoneString', 'TopLevelModuleEvaluationJob', 'TriggerPromiseReactions', 'TypedArrayCreate', 'TypedArraySpeciesCreate', 'UnicodeEscape', 'UpdateEmpty', 'UTC', 'UTF16Decode', 'UTF16Encoding', 'ValidateAtomicAccess', 'ValidateSharedIntegerTypedArray', 'ValidateTypedArray', 'ValueOfReadEvent', 'WakeWaiter', 'WordCharacters', 'AsyncFunctionCreate', 'AsyncGeneratorFunctionCreate', 'AsyncIteratorClose', 'BackreferenceMatcher', 'Construct', 'CreateArrayFromList', 'CreateListIteratorRecord', 'NormalCompletion', 'OrdinarySet', 'OrdinarySetWithOwnDescriptor', 'RegExpBuiltinExec', 'SetFunctionLength', 'ThrowCompletion', 'UnicodeMatchProperty', 'UnicodeMatchPropertyValue']; +var expectedMissing = ['abs', 'AddRestrictedFunctionProperties', 'AddWaiter', 'agent-order', 'AgentCanSuspend', 'AgentSignifier', 'AllocateArrayBuffer', 'AllocateSharedArrayBuffer', 'AllocateTypedArray', 'AllocateTypedArrayBuffer', 'AsyncFunctionStart', 'AsyncGeneratorEnqueue', 'AsyncGeneratorReject', 'AsyncGeneratorResolve', 'AsyncGeneratorResumeNext', 'AsyncGeneratorStart', 'AsyncGeneratorYield', 'AtomicLoad', 'AtomicReadModifyWrite', 'Await', 'BlockDeclarationInstantiation', 'BoundFunctionCreate', 'Canonicalize', 'CaseClauseIsSelected', 'CharacterRange', 'CharacterRangeOrUnion', 'CharacterSetMatcher', 'CloneArrayBuffer', 'Completion', 'ComposeWriteEventBytes', 'CopyDataBlockBytes', 'CreateArrayIterator', 'CreateAsyncFromSyncIterator', 'CreateBuiltinFunction', 'CreateByteDataBlock', 'CreateDynamicFunction', 'CreateIntrinsics', 'CreateMapIterator', 'CreateMappedArgumentsObject', 'CreatePerIterationEnvironment', 'CreateRealm', 'CreateResolvingFunctions', 'CreateSetIterator', 'CreateSharedByteDataBlock', 'CreateStringIterator', 'CreateUnmappedArgumentsObject', 'Decode', 'DetachArrayBuffer', 'Encode', 'EnqueueJob', 'EnterCriticalSection', 'EnumerateObjectProperties', 'EscapeRegExpPattern', 'EvalDeclarationInstantiation', 'EvaluateCall', 'EvaluateNew', 'EventSet', 'floor', 'ForBodyEvaluation', 'ForIn/OfBodyEvaluation', 'ForIn/OfHeadEvaluation', 'FulfillPromise', 'FunctionAllocate', 'FunctionCreate', 'FunctionDeclarationInstantiation', 'FunctionInitialize', 'GeneratorFunctionCreate', 'GeneratorResume', 'GeneratorResumeAbrupt', 'GeneratorStart', 'GeneratorValidate', 'GeneratorYield', 'GetActiveScriptOrModule', 'GetBase', 'GetFunctionRealm', 'GetGeneratorKind', 'GetGlobalObject', 'GetIdentifierReference', 'GetModifySetValueInBuffer', 'GetModuleNamespace', 'GetNewTarget', 'GetReferencedName', 'GetSuperConstructor', 'GetTemplateObject', 'GetThisEnvironment', 'GetThisValue', 'GetValue', 'GetValueFromBuffer', 'GetViewValue', 'GetWaiterList', 'GlobalDeclarationInstantiation', 'happens-before', 'HasPrimitiveBase', 'host-synchronizes-with', 'HostEnsureCanCompileStrings', 'HostEventSet', 'HostPromiseRejectionTracker', 'HostReportErrors', 'HostResolveImportedModule', 'IfAbruptRejectPromise', 'ImportedLocalNames', 'InitializeBoundName', 'InitializeHostDefinedRealm', 'InitializeReferencedBinding', 'InnerModuleEvaluation', 'InnerModuleInstantiation', 'IntegerIndexedElementGet', 'IntegerIndexedElementSet', 'IntegerIndexedObjectCreate', 'InternalizeJSONProperty', 'IsAnonymousFunctionDefinition', 'IsCompatiblePropertyDescriptor', 'IsDetachedBuffer', 'IsInTailPosition', 'IsLabelledFunction', 'IsPropertyReference', 'IsSharedArrayBuffer', 'IsStrictReference', 'IsSuperReference', 'IsUnresolvableReference', 'IsWordChar', 'LeaveCriticalSection', 'LocalTime', 'LoopContinues', 'MakeArgGetter', 'MakeArgSetter', 'MakeClassConstructor', 'MakeConstructor', 'MakeMethod', 'MakeSuperPropertyReference', 'max', 'memory-order', 'min', 'ModuleDeclarationEnvironmentSetup', 'ModuleExecution', 'ModuleNamespaceCreate', 'NewDeclarativeEnvironment', 'NewFunctionEnvironment', 'NewGlobalEnvironment', 'NewModuleEnvironment', 'NewObjectEnvironment', 'NewPromiseCapability', 'NumberToRawBytes', 'ObjectDefineProperties', 'OrdinaryCallBindThis', 'OrdinaryCallEvaluateBody', 'OrdinaryCreateFromConstructor', 'OrdinaryDelete', 'OrdinaryGet', 'OrdinaryIsExtensible', 'OrdinaryOwnPropertyKeys', 'OrdinaryPreventExtensions', 'OrdinaryToPrimitive', 'ParseModule', 'ParseScript', 'PerformEval', 'PerformPromiseAll', 'PerformPromiseRace', 'PerformPromiseThen', 'PrepareForOrdinaryCall', 'PrepareForTailCall', 'PromiseReactionJob', 'PromiseResolveThenableJob', 'ProxyCreate', 'PutValue', 'QuoteJSONString', 'RawBytesToNumber', 'reads-bytes-from', 'reads-from', 'RegExpAlloc', 'RegExpCreate', 'RegExpInitialize', 'RejectPromise', 'RemoveWaiter', 'RemoveWaiters', 'RepeatMatcher', 'ResolveBinding', 'ResolveThisBinding', 'ReturnIfAbrupt', 'RunJobs', 'ScriptEvaluation', 'ScriptEvaluationJob', 'SerializeJSONArray', 'SerializeJSONObject', 'SerializeJSONProperty', 'SetDefaultGlobalBindings', 'SetImmutablePrototype', 'SetRealmGlobalObject', 'SetValueInBuffer', 'SetViewValue', 'SharedDataBlockEventSet', 'SortCompare', 'SplitMatch', 'StringCreate', 'StringGetOwnProperty', 'Suspend', 'synchronizes-with', 'TimeZoneString', 'TopLevelModuleEvaluationJob', 'TriggerPromiseReactions', 'TypedArrayCreate', 'TypedArraySpeciesCreate', 'UnicodeEscape', 'UpdateEmpty', 'UTC', 'UTF16Decode', 'UTF16Encoding', 'ValidateAtomicAccess', 'ValidateSharedIntegerTypedArray', 'ValidateTypedArray', 'ValueOfReadEvent', 'WakeWaiter', 'WordCharacters', 'AsyncFunctionCreate', 'AsyncGeneratorFunctionCreate', 'BackreferenceMatcher', 'Construct', 'CreateArrayFromList', 'CreateListIteratorRecord', 'NormalCompletion', 'OrdinarySet', 'OrdinarySetWithOwnDescriptor', 'RegExpBuiltinExec', 'SetFunctionLength', 'ThrowCompletion', 'UnicodeMatchProperty', 'UnicodeMatchPropertyValue']; require('./tests').es2018(ES, ops, expectedMissing); diff --git a/test/tests.js b/test/tests.js index f624afd9..cabb6f0d 100644 --- a/test/tests.js +++ b/test/tests.js @@ -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'](