Skip to content

Commit

Permalink
feature: add algorithm for Map.prototype.mapKeys
Browse files Browse the repository at this point in the history
Resolves #24
  • Loading branch information
Ginden committed Aug 1, 2024
1 parent a11f7b5 commit ab486a7
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 28 deletions.
15 changes: 2 additions & 13 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -136,19 +136,8 @@ <h1><span class="secnum">3.1</span> Map.prototype.mapValues( <var>callbackfn</va
<emu-clause id="Map.prototype.mapKeys">
<h1><span class="secnum">3.2</span> Map.prototype.mapKeys( <var>callbackfn</var>, [ <var>thisArg</var> ] )</h1>
<emu-import href="./map/prototype-map-keys.html"><emu-note type="editor"><span class="note">Editor's Note</span><div class="note-contents">
This code serves as placeholder until formal spec is written for this method.
</div></emu-note><pre><code class="javascript hljs"><span class="hljs-keyword">function</span> <span class="hljs-title function_">mapKeys</span>(<span class="hljs-params">callbackFn, thisArg</span>) {
<span class="hljs-title function_">assert</span>(<span class="hljs-title function_">isObject</span>(<span class="hljs-variable language_">this</span>), <span class="hljs-string">'this is not an object'</span>);
<span class="hljs-title function_">assert</span>(<span class="hljs-title function_">isCallable</span>(callbackFn), <span class="hljs-string">'callback is not a function'</span>);
<span class="hljs-keyword">const</span> <span class="hljs-title class_">Ctor</span> = <span class="hljs-title class_">SpeciesConstructor</span>(<span class="hljs-variable language_">this</span>, <span class="hljs-title class_">Map</span>);
<span class="hljs-keyword">const</span> retObj = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Ctor</span>();
<span class="hljs-keyword">const</span> _set = retObj.<span class="hljs-property">set</span>;
<span class="hljs-keyword">for</span>(<span class="hljs-keyword">const</span> [key, value] <span class="hljs-keyword">of</span> <span class="hljs-variable language_">this</span>) {
<span class="hljs-keyword">const</span> newKey = <span class="hljs-title class_">Reflect</span>.<span class="hljs-title function_">apply</span>(callbackFn, thisArg, [value, key, <span class="hljs-variable language_">this</span>])
<span class="hljs-title class_">Reflect</span>.<span class="hljs-title function_">apply</span>(_set, retObj, [newKey, value]);
}
<span class="hljs-keyword">return</span> retObj;
}</code></pre></emu-import>
TODO: how to handle duplicate keys? Obvious way is to use <code>Map.prototype.set</code> through <code>Map</code> constructor, but that would break convention set by <code>Map.groupBy</code>.
</div></emu-note><emu-alg><ol><li>Let <var>M</var> be the <emu-val>this</emu-val> value.</li><li>Perform ?&nbsp;RequireInternalSlot(<var>M</var>, <var class="field">[[MapData]]</var>).</li><li>If IsCallable(<var>callbackfn</var>) is **false*<emu-val>, throw a *TypeError</emu-val> exception.</li><li>Let <var>result</var> be !&nbsp;Construct(%Map%).</li><li>Let <var>resultKeys</var> be a new empty List.</li><li>For each Record { <var class="field">[[Key]]</var>, <var class="field">[[Value]]</var>&nbsp;} <var>e</var> of <var>M</var>.<var class="field">[[MapData]]</var>, do<ol><li>If <var>e</var>.<var class="field">[[Key]]</var> is not <emu-const>empty</emu-const>, then<ol><li>Let <var>newKey</var> be CanonicalizeKeyedCollectionKey(? Call(<var>callbackfn</var>, <var>T</var>, « <var>e</var>.<var class="field">[[Value]]</var>, <var>e</var>.<var class="field">[[Key]]</var>, <var>map</var>&nbsp;»))</li><li>Let <var>p</var> be the Record { <var class="field">[[Key]]</var>: <var>newKey</var>, <var class="field">[[Value]]</var>: <var>e</var>.<var class="field">[[Value]]</var>&nbsp;}</li><li>If <var>newKey</var> is present in <var>resultKeys</var>, throw **RangeError**</li><li>Append <var>p</var> to <var>result</var>.<var class="field">[[MapData]]</var></li><li>Append <var>newKey</var> to <var>resultKeys</var></li></ol></li></ol></li><li>Return <var>result</var>.</li></ol></emu-alg></emu-import>
</emu-clause>
<emu-clause id="Map.prototype.filter">
Expand Down
31 changes: 16 additions & 15 deletions spec/map/prototype-map-keys.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
<!DOCTYPE html>
<emu-note type="editor">
This code serves as placeholder until formal spec is written for this method.
TODO: how to handle duplicate keys? Obvious way is to use `Map.prototype.set` through `Map` constructor, but that would break convention set by `Map.groupBy`.
</emu-note>

<pre><code class="javascript">
function mapKeys(callbackFn, thisArg) {
assert(isObject(this), 'this is not an object');
assert(isCallable(callbackFn), 'callback is not a function');
const Ctor = SpeciesConstructor(this, Map);
const retObj = new Ctor();
const _set = retObj.set;
for(const [key, value] of this) {
const newKey = Reflect.apply(callbackFn, thisArg, [value, key, this])
Reflect.apply(_set, retObj, [newKey, value]);
}
return retObj;
}
</code></pre>
<emu-alg>
1. Let _M_ be the *this* value.
1. Perform ? RequireInternalSlot(_M_, [[MapData]]).
1. If IsCallable(_callbackfn_) is **false**, throw a *TypeError* exception.
1. Let _result_ be ! Construct(%Map%).
1. Let _resultKeys_ be a new empty List.
1. For each Record { [[Key]], [[Value]] } _e_ of _M_.[[MapData]], do
1. If _e_.[[Key]] is not ~empty~, then
1. Let _newKey_ be CanonicalizeKeyedCollectionKey(? Call(_callbackfn_, _T_, « _e_.[[Value]], _e_.[[Key]], _map_ »))
1. Let _p_ be the Record { [[Key]]: _newKey_, [[Value]]: _e_.[[Value]] }
1. If _newKey_ is present in _resultKeys_, throw **RangeError**
1. Append _p_ to _result_.[[MapData]]
1. Append _newKey_ to _resultKeys_
1. Return _result_.
</emu-alg>

0 comments on commit ab486a7

Please sign in to comment.