aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Pilfold <louis@lpil.uk>2021-08-29 17:18:37 +0100
committerLouis Pilfold <louis@lpil.uk>2021-08-29 17:18:37 +0100
commitc2d25106df806fd9de96f1ab3186102ba27dceab (patch)
tree833f17fd6e3821f6ee2d536ecdef96cc3418d944
parent08bf033063a8d3ce789939bac36ed39fc6bc2eca (diff)
downloadjavascript-c2d25106df806fd9de96f1ab3186102ba27dceab.tar.gz
javascript-c2d25106df806fd9de96f1ab3186102ba27dceab.zip
Promises
-rw-r--r--CHANGELOG.md6
-rw-r--r--src/ffi.js30
-rw-r--r--src/gleam/javascript/promise.gleam11
-rw-r--r--test/gleam/javascript/promise_test.gleam20
4 files changed, 65 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fe8e251..556e284 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,10 @@
## Unreleased
+- The `javascript` module was created with the `TypeOf`, and `Symbol` types, and
+ `find_symbol`, and `type_of` functions.
- The `javascript/array` module was created with the `Array(element)` type and
`to_list`, `from_list`, `map`, `fold`, `fold_right`, `get`, and `length`
functions.
-- The `javascript` module was created with the `TypeOf`, and `Symbol` types, and
- `find_symbol`, and `type_of` functions.
+- The `javascript/promise` module was created with the `Promise(value)` type and
+ `resolve`, `map`, and `then` functions.
diff --git a/src/ffi.js b/src/ffi.js
index 07e7b0f..450f5e3 100644
--- a/src/ffi.js
+++ b/src/ffi.js
@@ -64,3 +64,33 @@ export function type_of(value) {
export function get_symbol(name) {
return Symbol.for(name);
}
+
+// A wrapper around a promise to prevent `Promise<Promise<T>>` collapsing into
+// `Promise<T>`.
+class PromiseLayer {
+ constructor(promise) {
+ this.promise = promise;
+ }
+
+ static wrap(value) {
+ return value instanceof Promise ? new PromiseLayer(value) : value;
+ }
+
+ static unwrap(value) {
+ return value instanceof PromiseLayer ? value.promise : value;
+ }
+}
+
+export function resolve(value) {
+ return Promise.resolve(PromiseLayer.wrap(value));
+}
+
+export function then(promise, fn) {
+ return promise.then((value) => fn(PromiseLayer.unwrap(value)));
+}
+
+export function map_promise(promise, fn) {
+ return promise.then((value) =>
+ PromiseLayer.wrap(fn(PromiseLayer.unwrap(value)))
+ );
+}
diff --git a/src/gleam/javascript/promise.gleam b/src/gleam/javascript/promise.gleam
new file mode 100644
index 0000000..4f8d54c
--- /dev/null
+++ b/src/gleam/javascript/promise.gleam
@@ -0,0 +1,11 @@
+// TODO: docs
+pub external type Promise(value)
+
+pub external fn resolve(value) -> Promise(value) =
+ "../../ffi.js" "resolve"
+
+pub external fn then(Promise(a), fn(a) -> Promise(b)) -> Promise(b) =
+ "../../ffi.js" "then"
+
+pub external fn map(Promise(a), fn(a) -> b) -> Promise(b) =
+ "../../ffi.js" "map_promise"
diff --git a/test/gleam/javascript/promise_test.gleam b/test/gleam/javascript/promise_test.gleam
new file mode 100644
index 0000000..876aefb
--- /dev/null
+++ b/test/gleam/javascript/promise_test.gleam
@@ -0,0 +1,20 @@
+import gleam/javascript/promise.{Promise}
+import gleam/javascript.{ObjectType}
+
+pub fn map_does_not_collapse_nested_promise_test() -> Promise(Promise(Int)) {
+ promise.resolve(1)
+ |> promise.map(promise.resolve)
+ |> promise.map(fn(value) {
+ // If the `Promise(Promise(Int))` collapsed into `Promise(Int)` (as they
+ // do for normal JS promises) then this would fail as the value would be the
+ // int value `1`.
+ assert ObjectType = javascript.type_of(value)
+ value
+ })
+}
+
+pub fn then_does_collapse_nested_promise_test() -> Promise(Int) {
+ promise.resolve(1)
+ |> promise.then(promise.resolve)
+ |> promise.map(fn(value) { assert 1 = value })
+}