-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Allow {{each-in}} to iterate ES6 Maps on browsers with support #15579
Conversation
tests seem reasonable, but I am not so sure about the implementation side |
There is two possibilities to implement this. The first one is to detect Map support, check if the iterable is a Map, and use The second one is to detect if the element is an iterable (has the I went with the first one, as IE11 still matters. If we want to support iterables, we might need three branches, one for Maps and Sets that supports IE11, another for Objects and Arrays and a third one that will only work on browsers with Symbol support that checks for Sounds reasonable? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left an inline suggestion for an alternative way to handle this (without requiring instanceof
checks for specific object types).
|
||
if (HAS_NATIVE_MAP) { | ||
BasicSyntaxTest.prototype['@test it repeats the given block for each item in the ES6 map'] = function(assert) { | ||
let map = new window.Map(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure you need window.
here?
let values = keys.map(key => iterable[key]); | ||
let keys = []; | ||
let values = []; | ||
if (HAS_NATIVE_MAP && iterable instanceof Map) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought was that we could simplify this a bit. Basically, use native symbol when possible then fallback to .forEach
if present, else do Object.keys
. And avoid directly doing instanceof checks here.
const HAS_NATIVE_SYMBOL = (function() {
let hasSymbol = typeof Symbol === 'function';
if (hasSymbol === false) { return false; }
let instance = Symbol('test-symbol');
// use `Object`'s `.toString` directly to prevent us from detecting
// polyfills as native
return Object.prototype.toString.call(instance) === '[object Symbol]';
})();
// ...snip...
if (iterable && (typeofIterable === 'object' || typeofIterable === 'function')) {
let keys;
let values;
if (HAS_NATIVE_SYMBOL && typeof iterable[Symbol.iterator]) {
keys = [];
values = [];
let iterator = iterable[Symbol.iterator]();
while(true) {
let result = iterator.next();
if (result.done) break;
let [key, value] = result.value;
keys.push(key);
values.push(value);
}
} else if (typeof iterable.forEach === 'function') {
keys = [];
values = [];
iterable.forEach((value, key) => {
keys.push(key);
values.push(value);
});
} else {
keys = Object.keys(iterable);
values = keys.map(key => iterable[key]);
}
}
// ...snip...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, its likely possible to create a custom iterator object that avoids eagerly iterating all the items (like I did in that snippet), but we would need to pester some folks to get some clarity on the "right" way to do it.
@rwjblue I've applied your feedback with very minor adjustments. It turns out that adding support for iterables added a features I wasn't counting with. That means that let iterable = {
[Symbol.iterator]: () => makeIterator([['one', 'foo'], ['two', 'bar']])
}; and it would be like iterating the object I added tests for that feature, but if that is not a behaviour we want to support I can remove the tests. |
After this I could add support for iterables in |
The feature was added in #16399, but we still need to add the tests, update the docs and add a CHANGELOG (see #15592 (comment)). Ideally, we should refactor the test similar to how we test If you couldn't figure out a good way to do that refactor, we can land the test you have now and I can refactor them later also. |
What we do in the |
Nice. I'm AFK all weekend but I can check it next week |
203a053
to
8f2c674
Compare
Allow each-in to iterate iterables that return pairs of key/value This is was not expressly intended when I started developing this feature, but it turns out that if every time the `next()` function of an iterator is returns a tuple, that can be considered a valid entry for `{{each-in}}`
8f2c674
to
a276e8a
Compare
@rwjblue It's not too hard, but I was thinking that we should probably just allow to iterate anything that was
@@iterator
support, so keep this as a WIP.I mostly want feedback on the tests, the implementation might change.