diff --git a/CHANGELOG.md b/CHANGELOG.md index 2da455ef..f4107197 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ # @rescript/core Changelog ## master + +- Docstrings for `Map` and `Iterator`. https://github.com/rescript-association/rescript-core/pull/34 +- Change `Map.set` to not return self, to indicate that it's mutable. https://github.com/rescript-association/rescript-core/pull/34 +- Change `Iterator` bindings to have the same shape as `AsyncIterator` for consistency. https://github.com/rescript-association/rescript-core/pull/34 +- Add `Iterator.toArray` binding for turning an iterator into an array. https://github.com/rescript-association/rescript-core/pull/34 diff --git a/src/Core__Iterator.res b/src/Core__Iterator.res index a13b29a1..161973ad 100644 --- a/src/Core__Iterator.res +++ b/src/Core__Iterator.res @@ -1,7 +1,9 @@ type t<'a> -type next<'a> -@get external done: next<'a> => bool = "done" -@get external value: next<'a> => option<'a> = "value" +type value<'a> = { + done: bool, + value: option<'a>, +} -@send external next: t<'a> => next<'a> = "next" +@send external next: t<'a> => value<'a> = "next" +@scope("Array") external toArray: t<'a> => array<'a> = "from" diff --git a/src/Core__Iterator.resi b/src/Core__Iterator.resi new file mode 100644 index 00000000..c22c336b --- /dev/null +++ b/src/Core__Iterator.resi @@ -0,0 +1,59 @@ +/*** +Bindings to JavaScript iterators. + +See [`iterator protocols`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. +*/ + +/** +The type representing an iterator. +*/ +type t<'a> + +/** +The current value of an iterator. +*/ +type value<'a> = { + /** + Whether there are more values to iterate on before the iterator is done. + */ + done: bool, + /** + The value of this iteration, if any. + */ + value: option<'a>, +} + +/** +Returns the next value of the iterator, if any. + +See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. + +## Examples +```rescript +// Pulls out the next value of the iterator +let {done, value} = someIterator->Iterator.next +``` +*/ +@send +external next: t<'a> => value<'a> = "next" + +/** +Turns an iterator into an array of the remaining values. +Remember that each invocation of `next` of an iterator consumes a value. `Iterator.toArray` will consume all remaining values of the iterator and return them in an array to you. + +See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("someKey2", "someValue2") + +// `Map.keys` returns all keys of the map as an iterator. +let mapKeysAsArray = map->Map.keys->Iterator.toArray + +Console.log(mapKeysAsArray) // Logs ["someKey", "someKey2"] to the console. +``` +*/ +@scope("Array") +external toArray: t<'a> => array<'a> = "from" diff --git a/src/Core__Map.res b/src/Core__Map.res index f1592588..bedcc6d7 100644 --- a/src/Core__Map.res +++ b/src/Core__Map.res @@ -13,7 +13,7 @@ type t<'k, 'v> @send external get: (t<'k, 'v>, 'k) => option<'v> = "get" @send external has: (t<'k, 'v>, 'k) => bool = "has" -@send external set: (t<'k, 'v>, 'k, 'v) => t<'k, 'v> = "set" +@send external set: (t<'k, 'v>, 'k, 'v) => unit = "set" @send external delete: (t<'k, 'v>, 'k) => bool = "delete" @send external keys: t<'k, 'v> => Core__Iterator.t<'k> = "keys" diff --git a/src/Core__Map.resi b/src/Core__Map.resi new file mode 100644 index 00000000..7d3d4c09 --- /dev/null +++ b/src/Core__Map.resi @@ -0,0 +1,265 @@ +/*** +Bindings to the mutable JavaScript `Map`. + +See [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) on MDN. +*/ + +/** +Type representing an instance of `Map`. +*/ +type t<'k, 'v> + +/** +Creates a new, mutable JavaScript `Map`. A `Map` can have any values as both keys and values. + +See [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) on MDN. + + + +## Examples +```rescript +`make()` +// You can annotate the type of your map if you want to +let myMap: Map.t = Map.make() + +// Or you can let ReScript infer what's in your map +let map = Map.make() +map->Map.set("lang", "ReScript") // Inferred as Map.t +``` + +## Alternatives +A JavaScript `Map` is mutable. If you're looking for an immutable alternative, check out`Belt.Map`. +*/ +@new +external make: unit => t<'k, 'v> = "Map" + +/** +Turns an array of key/value pairs into a Map. + +## Examples +```rescript +type languages = ReScript | JavaScript | TypeScript +let languageRank = [(ReScript, 1), (JavaScript, 2), (TypeScript, 3)] + +let map = Map.fromArray(languageRank) // Map.t + +switch map->Map.get(ReScript) { +| Some(1) => Console.log("Yay, ReScript is #1!") +| _ => Console.log("Uh-oh, something is _terribly_ wrong with this program... abort.") +} +``` +*/ +@new +external fromArray: array<('k, 'v)> => t<'k, 'v> = "Map" + +/** +Turns an iterator in the shape of `('key, 'value)` into a `Map`. + +## Examples +```rescript +// Let's pretend we have an interator in the correct shape +@val external someIterator: Iterator.t<(string, int)> = "someIterator" + +let map = Map.fromIterator(someIterator) // Map.t +``` +*/ +@new +external fromIterator: Core__Iterator.t<('k, 'v)> => t<'k, 'v> = "Map" + +/** +Returns the size, the number of key/value pairs, of the map. + +## Examples +```rescript +let map = Map.make() + +map->Map.set("someKey", "someValue") + +let size = map->Map.size // 1 +``` +*/ +@get +external size: t<'k, 'v> => int = "size" + +/** +Clears all entries in the map. + +## Examples +```rescript +let map = Map.make() + +map->Map.set("someKey", "someValue") +let size = map->Map.size // 1 + +map->Map.clear +let size = map->Map.size // 0 +``` +*/ +@send +external clear: t<'k, 'v> => unit = "clear" + +/** +Iterates through all values of the map. + +> Please note that this is *without the keys*, just the values. If you need the key as well, use `Map.forEachWithKey`. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("someKey2", "someValue2") + +map->Map.forEach(value => { + Console.log(value) +}) +``` +*/ +@send +external forEach: (t<'k, 'v>, 'v => unit) => unit = "forEach" + +/** +Iterates through all values of the map, including the key for each value. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("someKey2", "someValue2") + +map->Map.forEachWithKey((value, key) => { + Console.log2(value, key) +}) +``` +*/ +@send +external forEachWithKey: (t<'k, 'v>, ('v, 'k) => unit) => unit = "forEach" + +/** +Returns the value for a key, if a value exists at that key. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") + +switch map->Map.get("someKey") { +| None => Console.log("Nope, didn't have it.") +| Some(value) => Console.log2("Yay, had the value, and it's:", value) +} +``` +*/ +@send +external get: (t<'k, 'v>, 'k) => option<'v> = "get" + +/** +Checks whether the map has a specific key. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") + +switch map->Map.has("someKey") { +| false => Console.log("Nope, didn't have it.") +| true => Console.log("Yay, we have the value!") +} +``` +*/ +@send +external has: (t<'k, 'v>, 'k) => bool = "has" + +/** +Sets the provided `value` to the provided `key`. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +``` +*/ +@send +external set: (t<'k, 'v>, 'k, 'v) => unit = "set" + +/** +Deletes the provided `key` and its value from the map. Returns a `bool` for whether the key existed, and was deleted. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +let didDeleteKey = map->Map.delete("someKey") +Console.log(didDeleteKey) // Logs `true` to the console, becuase the map had the key, so it was successfully deleted + +let didDeleteKey = map->Map.delete("someNonExistantKey") +Console.log(didDeleteKey) // Logs `false` to the console, becuase the key did not exist +``` +*/ +@send +external delete: (t<'k, 'v>, 'k) => bool = "delete" + +/** +Returns an iterator that holds all keys of the map. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("anotherKey", "anotherValue") + +let keys = map->Map.keys + +// Logs the first key +Console.log(Iterator.next(keys).value) + +// You can also turn the iterator into an array. +// Remember that an iterator consumes values. We'll need a fresh keys iterator to get an array of all keys, since we consumed a value via `next` above already. +Console.log(map->Map.keys->Iterator.toArray) +``` +*/ +@send +external keys: t<'k, 'v> => Core__Iterator.t<'k> = "keys" + +/** +Returns an iterator that holds all values of the map. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("anotherKey", "anotherValue") + +let values = map->Map.values + +// Logs the first value +Console.log(Iterator.next(values).value) + +// You can also turn the iterator into an array. +// Remember that an iterator consumes values. We'll need a fresh values iterator to get an array of all values, since we consumed a value via `next` above already. +Console.log(map->Map.values->Iterator.toArray) +``` +*/ +@send +external values: t<'k, 'v> => Core__Iterator.t<'v> = "values" + +/** +Returns an iterator that holds all entries of the map. +An entry is represented as a tuple of `('key, 'value)`, + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("anotherKey", "anotherValue") + +let entries = map->Map.entries + +// Logs the first value +Console.log(Iterator.next(entries).value) + +// You can also turn the iterator into an array. +// Remember that an iterator consumes entries. We'll need a fresh entries iterator to get an array of all entries, since we consumed a value via `next` above already. +Console.log(map->Map.entries->Iterator.toArray) +``` +*/ +@send +external entries: t<'k, 'v> => Core__Iterator.t<('k, 'v)> = "entries"