Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[New] ES2018+: Add CreateAsyncFromSyncIterator #105

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@
2019/CanonicalNumericIndexString.js spackled linguist-generated=true
2019/CompletePropertyDescriptor.js spackled linguist-generated=true
2019/CopyDataProperties.js spackled linguist-generated=true
2019/CreateAsyncFromSyncIterator.js spackled linguist-generated=true
2019/CreateDataProperty.js spackled linguist-generated=true
2019/CreateDataPropertyOrThrow.js spackled linguist-generated=true
2019/CreateHTML.js spackled linguist-generated=true
Expand Down Expand Up @@ -482,4 +483,4 @@
2019/thisBooleanValue.js spackled linguist-generated=true
2019/thisNumberValue.js spackled linguist-generated=true
2019/thisStringValue.js spackled linguist-generated=true
2019/thisSymbolValue.js spackled linguist-generated=true
2019/thisSymbolValue.js spackled linguist-generated=true
20 changes: 20 additions & 0 deletions 2018/CreateAsyncFromSyncIterator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

var AsyncFromSyncIterator = require('../helpers/AsyncFromSyncIterator');
var Get = require('./Get');

// https://www.ecma-international.org/ecma-262/9.0/#sec-createasyncfromsynciterator

module.exports = function CreateAsyncFromSyncIterator(syncIteratorRecord) {
if (!AsyncFromSyncIterator) {
throw new SyntaxError('This environment does not support Promises.');
}

var asyncIterator = new AsyncFromSyncIterator(syncIteratorRecord);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var asyncIterator = new AsyncFromSyncIterator(syncIteratorRecord);
var asyncIterator = AsyncFromSyncIterator(syncIteratorRecord);

i'm very confused why we'd want a constructor, or to encourage use of new.

var nextMethod = Get(asyncIterator, 'next');
return {
'[[Iterator]]': asyncIterator,
'[[NextMethod]]': nextMethod,
'[[Done]]': false
};
};
20 changes: 20 additions & 0 deletions 2019/CreateAsyncFromSyncIterator.js

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

1 change: 1 addition & 0 deletions es2018.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var ES2018 = {
CanonicalNumericIndexString: require('./2018/CanonicalNumericIndexString'),
CompletePropertyDescriptor: require('./2018/CompletePropertyDescriptor'),
CopyDataProperties: require('./2018/CopyDataProperties'),
CreateAsyncFromSyncIterator: require('./2018/CreateAsyncFromSyncIterator'),
CreateDataProperty: require('./2018/CreateDataProperty'),
CreateDataPropertyOrThrow: require('./2018/CreateDataPropertyOrThrow'),
CreateHTML: require('./2018/CreateHTML'),
Expand Down
1 change: 1 addition & 0 deletions es2019.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var ES2019 = {
CanonicalNumericIndexString: require('./2019/CanonicalNumericIndexString'),
CompletePropertyDescriptor: require('./2019/CompletePropertyDescriptor'),
CopyDataProperties: require('./2019/CopyDataProperties'),
CreateAsyncFromSyncIterator: require('./2019/CreateAsyncFromSyncIterator'),
CreateDataProperty: require('./2019/CreateDataProperty'),
CreateDataPropertyOrThrow: require('./2019/CreateDataPropertyOrThrow'),
CreateHTML: require('./2019/CreateHTML'),
Expand Down
230 changes: 230 additions & 0 deletions helpers/AsyncFromSyncIterator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
'use strict';

var internalSlot = require('internal-slot');
var isCallable = require('is-callable');

var callBind = require('./callBind');
var callBound = require('./callBound');
var GetIntrinsic = require('../GetIntrinsic');
var $isNaN = require('./isNaN');

var $apply = GetIntrinsic('%Reflect.apply%', true) || callBound('%Function.prototype.apply%');
var $asyncIterator = GetIntrinsic('%Symbol.asyncIterator%', true);
var $toStringTag = GetIntrinsic('%Symbol.toStringTag%', true);
var $TypeError = GetIntrinsic('%TypeError%');

var undefined;

// TODO: Use %AsyncIterator.from% once it's in ECMA-262

/** @type {(o: object, p: string | symbol, Desc: import('es-abstract').PropertyDescriptor) => boolean} */
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** @type {(o: object, p: string | symbol, Desc: import('es-abstract').PropertyDescriptor) => boolean} */

i'm not interested in jsdoc comments at this time

var DefineOwnProperty = callBind(
require('./DefineOwnProperty'),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be required at module level and used here

undefined,
function IsDataDescriptor(Desc) {
return !('[[Get]]' in Desc) && !('[[Set]]' in Desc);
},
Comment on lines +24 to +26
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should use require('./IsDataDescriptor').

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do realise that this is now in the helpers directory, right?

As such, there is no IsDataDescriptor file that can be imported.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, it should take IsDataDescriptor as a function argument.

GetIntrinsic('%Object.is%', true) || function SameValue(x, y) {
if (x === y) {
// 0 === -0, but they are not identical.
if (x === 0) {
return 1 / x === 1 / y;
}
return true;
}
return $isNaN(x) && $isNaN(y);
},
Comment on lines +27 to +36
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should just use require('./SameValue') directly (required at module level)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also be passed as a function argument.

function FromPropertyDescriptor(Desc) {
var obj = {};
if ('[[Value]]' in Desc) {
obj.value = Desc['[[Value]]'];
}
if ('[[Writable]]' in Desc) {
obj.writable = Desc['[[Writable]]'];
}
if ('[[Get]]' in Desc) {
obj.get = Desc['[[Get]]'];
}
if ('[[Set]]' in Desc) {
obj.set = Desc['[[Set]]'];
}
if ('[[Enumerable]]' in Desc) {
obj.enumerable = Desc['[[Enumerable]]'];
}
if ('[[Configurable]]' in Desc) {
obj.configurable = Desc['[[Configurable]]'];
}
return obj;
}
Comment on lines +37 to +58
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function FromPropertyDescriptor(Desc) {
var obj = {};
if ('[[Value]]' in Desc) {
obj.value = Desc['[[Value]]'];
}
if ('[[Writable]]' in Desc) {
obj.writable = Desc['[[Writable]]'];
}
if ('[[Get]]' in Desc) {
obj.get = Desc['[[Get]]'];
}
if ('[[Set]]' in Desc) {
obj.set = Desc['[[Set]]'];
}
if ('[[Enumerable]]' in Desc) {
obj.enumerable = Desc['[[Enumerable]]'];
}
if ('[[Configurable]]' in Desc) {
obj.configurable = Desc['[[Configurable]]'];
}
return obj;
}
FromPropertyDescriptor,

where FromPropertyDescriptor is require('./FromPropertyDescriptor') at module level

);

var CreateMethodProperty = function CreateMethodProperty(O, P, V) {
return DefineOwnProperty(O, P, {
'[[Configurable]]': true,
'[[Enumerable]]': false,
'[[Writable]]': true,
'[[Value]]': V
});
};
Comment on lines +61 to +68
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should also be require('./CreateMethodProperty')


var isObject = function (target) {
return target !== null && (typeof target === 'object' || typeof target === 'function');
};
Comment on lines +70 to +72
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use the inverse of helpers/isPrimitive for this.


var AsyncIteratorPrototype
= GetIntrinsic('%AsyncIteratorPrototype%', true)
|| (function () {
var result = {};
if ($toStringTag) {
DefineOwnProperty(result, $toStringTag, {
'[[Writable]]': false,
'[[Enumerable]]': false,
'[[Configurable]]': true,
'[[Value]]': 'AsyncIterator'
});
}
if ($asyncIterator) {
CreateMethodProperty(
result,
$asyncIterator,
{
'[Symbol.asyncIterator]': function () {
return this;
}
}['[Symbol.asyncIterator]']
);
}
return result;
}());
Comment on lines +76 to +98
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be moved to a separate helpers file, that's tested independently.


var AsyncFromSyncIteratorPrototype
= GetIntrinsic('%AsyncFromSyncIteratorPrototype%', true)
// eslint-disable-next-line max-lines-per-function
|| (function () {
var $Promise = GetIntrinsic('%Promise%', true);
if (!$Promise) {
return;
}

var PromiseResolve = callBind(GetIntrinsic('%Promise.resolve%'));
var promiseProtoThen = callBound('%Promise.prototype.then%');
var AsyncFromSyncIteratorContinuation = function AsyncFromSyncIteratorContinuation(result, promiseCapability) {
var done = !!result.done;
var value = result.value;
var valueWrapper = PromiseResolve($Promise, value);

promiseProtoThen(
valueWrapper,
function onFulfilled(unwrappedValue) {
$apply(
promiseCapability['[[Resolve]]'],
undefined,
[{ value: unwrappedValue, done: done }]
);
},
promiseCapability['[[Reject]]']
);
};

var T = function T() {};
T.prototype = AsyncIteratorPrototype;
// eslint-disable-next-line no-shadow
var AsyncFromSyncIteratorPrototype = new T();

CreateMethodProperty(AsyncFromSyncIteratorPrototype, 'next', function next(value) {
// eslint-disable-next-line no-invalid-this
var O = this;
return new Promise(function (resolve, reject) {
internalSlot.assert(O, '[[SyncIteratorRecord]]');

var syncIteratorRecord = internalSlot.get(O, '[[SyncIteratorRecord]]');
var result = $apply(
syncIteratorRecord['[[NextMethod]]'],
syncIteratorRecord['[[Iterator]]'],
[value]
);

if (!isObject(result)) {
throw new $TypeError('iterator next must return an object');
}

return AsyncFromSyncIteratorContinuation(result, {
'[[Resolve]]': resolve,
'[[Reject]]': reject
});
});
});

CreateMethodProperty(AsyncFromSyncIteratorPrototype, 'return', {
'return': function (value) {
var O = this;
return new Promise(function (resolve, reject) {
internalSlot.assert(O, '[[SyncIteratorRecord]]');

var syncIterator = internalSlot.get(O, '[[SyncIteratorRecord]]')['[[Iterator]]'];
var returnMethod = syncIterator['return'];
if (returnMethod != null) {
if (!isCallable(returnMethod)) {
throw new $TypeError('iterator return is not a function');
}

return resolve({
value: value,
done: true
});
}

var result = $apply(returnMethod, syncIterator, [value]);
if (!isObject(result)) {
throw new $TypeError('iterator return must return an object');
}

return AsyncFromSyncIteratorContinuation(result, {
'[[Resolve]]': resolve,
'[[Reject]]': reject
});
});
}
}['return']);

CreateMethodProperty(AsyncFromSyncIteratorPrototype, 'throw', {
'throw': function (value) {
var O = this;
return new Promise(function (resolve, reject) {
internalSlot.assert(O, '[[SyncIteratorRecord]]');

var syncIterator = internalSlot.get(O, '[[SyncIteratorRecord]]')['[[Iterator]]'];
var throwMethod = syncIterator['return'];
if (throwMethod != null) {
if (!isCallable(throwMethod)) {
throw new $TypeError('iterator throw is not a function');
}
throw value;
}

var result = $apply(throwMethod, syncIterator, [value]);
if (!isObject(result)) {
throw new $TypeError('iterator throw must return an object');
}

return AsyncFromSyncIteratorContinuation(result, {
'[[Resolve]]': resolve,
'[[Reject]]': reject
});
});
}
}['throw']);

// eslint-disable-next-line consistent-return
return AsyncFromSyncIteratorPrototype;
}());
Comment on lines +103 to +220
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as should this.


var AsyncFromSyncIteratorConstructor;
if (AsyncFromSyncIteratorPrototype) {
AsyncFromSyncIteratorConstructor = function AsyncFromSyncIterator(syncIteratorRecord) {
internalSlot.set(this, '[[SyncIteratorRecord]]', syncIteratorRecord);
};
AsyncFromSyncIteratorConstructor.prototype = AsyncFromSyncIteratorPrototype;
}

module.exports = AsyncFromSyncIteratorConstructor;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"internal-slot": "^1.0.2",
"is-callable": "^1.2.0",
"is-negative-zero": "^2.0.0",
"is-regex": "^1.1.0",
Expand Down
1 change: 0 additions & 1 deletion test/es2018.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ var expectedMissing = [
'CopyDataBlockBytes',
'CreateArrayFromList',
'CreateArrayIterator',
'CreateAsyncFromSyncIterator',
'CreateBuiltinFunction',
'CreateByteDataBlock',
'CreateDynamicFunction',
Expand Down
1 change: 0 additions & 1 deletion test/es2019.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ var expectedMissing = [
'CopyDataBlockBytes',
'CreateArrayFromList',
'CreateArrayIterator',
'CreateAsyncFromSyncIterator',
'CreateBuiltinFunction',
'CreateByteDataBlock',
'CreateDynamicFunction',
Expand Down