[
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.merlin\n.bsb.lock\nnpm-debug.log\n/lib/bs/\n/node_modules/\npackage-lock.json\n*.bs.js\n.nyc_output/\ncoverage/\n"
  },
  {
    "path": ".npmignore",
    "content": ".DS_Store\n.merlin\n.bsb.lock\nnpm-debug.log\n/lib/bs/\n/node_modules/\ntests/\npackage-lock.json\n.vscode/\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - lts/*\ncache: yarn\n"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "{\n    \"version\": \"2.0.0\",\n    \"command\": \"npm\",\n    \"options\": {\n      \"cwd\": \"${workspaceRoot}\"\n    },\n    \"type\": \"shell\",\n    \"args\": [\"run\", \"start\"],\n    \"presentation\": {\n      \"echo\": true,\n      \"reveal\": \"always\",\n      \"focus\": false,\n      \"panel\": \"shared\"\n    },\n    \"isBackground\": true,\n    \"problemMatcher\": {\n      \"fileLocation\": \"absolute\",\n      \"owner\": \"ocaml\",\n      \"background\": {\n        \"activeOnStart\": false,\n        \"beginsPattern\": \">>>> Start compiling\",\n        \"endsPattern\": \">>>> Finish compiling\"\n      },\n      \"pattern\": [\n        {\n          \"regexp\":\n            \"^File \\\"(.*)\\\", line (\\\\d+)(?:, characters (\\\\d+)-(\\\\d+))?:$\",\n          \"file\": 1,\n          \"line\": 2,\n          \"column\": 3,\n          \"endColumn\": 4\n        },\n        {\n          \"regexp\":\n            \"^(?:(?:Parse\\\\s+)?(Warning|[Ee]rror)(?:\\\\s+\\\\d+)?:)?\\\\s+(.*)$\",\n          \"severity\": 1,\n          \"message\": 2,\n          \"loop\": true\n        }\n      ]\n    },\n    \"tasks\": [\n      {\n        \"label\": \"npm\",\n        \"type\": \"shell\",\n        \"command\": \"npm\",\n        \"args\": [\n          \"run\",\n          \"start\"\n        ],\n        \"isBackground\": true,\n        \"problemMatcher\": {\n          \"fileLocation\": \"absolute\",\n          \"owner\": \"ocaml\",\n          \"background\": {\n            \"activeOnStart\": false,\n            \"beginsPattern\": \">>>> Start compiling\",\n            \"endsPattern\": \">>>> Finish compiling\"\n          },\n          \"pattern\": [\n            {\n              \"regexp\": \"^File \\\"(.*)\\\", line (\\\\d+)(?:, characters (\\\\d+)-(\\\\d+))?:$\",\n              \"file\": 1,\n              \"line\": 2,\n              \"column\": 3,\n              \"endColumn\": 4\n            },\n            {\n              \"regexp\": \"^(?:(?:Parse\\\\s+)?(Warning|[Ee]rror)(?:\\\\s+\\\\d+)?:)?\\\\s+(.*)$\",\n              \"severity\": 1,\n              \"message\": 2,\n              \"loop\": true\n            }\n          ]\n        },\n        \"group\": {\n          \"_id\": \"build\",\n          \"isDefault\": false\n        }\n      }\n    ]\n  }\n"
  },
  {
    "path": "README.md",
    "content": "[![npm](https://img.shields.io/npm/v/reason-future.svg)](https://www.npmjs.com/package/reason-future)\n[![Build Status](https://travis-ci.org/RationalJS/future.svg?branch=master)](https://travis-ci.org/RationalJS/future)\n[![Coverage Status](https://coveralls.io/repos/github/RationalJS/future/badge.svg?branch=test-coverage)](https://coveralls.io/github/RationalJS/future?branch=test-coverage)\n\n# The Future is Now\n\nFuture is a lightweight, functional alternative to `Js.Promise` for ReScript, designed to make async code more composable and maintainable.\n\n### Compatibility\n- Use `reason-future@2.6.0` for ReasonML or ReScript ≤ v10.\n- Use `reason-future@3.0.0` for ReScript ≥ v11.\n\n\n### Key Benefits of Using Future Over Promises:\n\n- **Lighter weight** – Only ~25 lines of implementation.\n- **Simpler** – Futures only resolve to a single type (as opposed to resolve and reject types), giving you more flexibility on your error handling.\n- **More robust** – Futures have sound typing (unlike JS promises).\n\n## Installation\n\nFirst make sure you have rescript `>= 11.1.X`. Then install with npm:\n\n```\n$ npm install --save reason-future\n```\n\nThen add `\"reason-future\"` to your `rescript.json` dev dependencies:\n\n```\n{\n  ...\n  \"bs-dependencies\": [\n    \"reason-future\"\n  ]\n}\n```\n\n## Basic Usage\n\nTo create a task, use `Future.make`. It provides a single `resolve` function, similar to how Promises work but without a `reject`:\n\n```js\nlet futureGreeting = Future.make(resolve => resolve(\"hi\"));\n```\n\nTo get the value of a future, use `Future.get`:\n\n```js\nlet futureGreeting = Future.make(resolve => resolve(\"hi\"));\nfutureGreeting->Future.get(x => Js.log(\"Got value: \" ++ x));\n\n/* Alternatively: */\n\nFuture.make(resolve => resolve(\"hi\"))\n->Future.get(x => Js.log(\"Got value: \" ++ x));\n```\n\n`Future.get` only *retrieves* the future value. If you want to **transform** it to a *different* value, then you should use `Future.map`:\n\n```js\n/* Shortcut for: let future_A = Future.make(resolve => resolve(99)); */\nlet future_A = Future.value(99);\n\nlet future_B = future_A->Future.map(n => n + 1);\n\n\nfuture_A->Future.get(n => Js.log(n)); /* logs: 99 */\n\nfuture_B->Future.get(n => Js.log(n)); /* logs: 100 */\n```\n\nAnd finally, if you `map` a future and return **another** future, you probably want to `flatMap` instead:\n\n```js\nlet futureNum = Future.value(50);\n\nlet ft_a = futureNum->Future.map(n => Future.value(n + 10));\nlet ft_b = futureNum->Future.flatMap(n => Future.value(n + 20));\n\n/* ft_a has type future(future(int)) – probably not what you want. */\n/* ft_b has type future(int) */\n```\n\n## API\n\nCore functions. **Note:** `_` represents the future itself as inserted by `->` (the [pipe](https://rescript-lang.org/docs/manual/latest/pipe) operator).\n\n- `Future.make(resolver)` - Create a new, potentially-async future.\n- `Future.value(x)` - Create a new future with a plain value (synchronous).\n- `Future.map(_,fn)` - Transform a future value into another value\n- `Future.flatMap(_,fn)` - Transform a future value into another future value\n- `Future.get(_,fn)` - Get the value of a future\n- `Future.tap(_,fn)` - Do something with the value of a future without changing it. Returns the same future so you can continue using it in a pipeline. Convenient for side effects such as console logging.\n- `Future.all(_,fn)` - Turn a list of futures into a future of a list.  Used when you want to wait for a collection of futures to complete before doing something (equivalent to Promise.all in Javascript).\n\n### Result\n\nConvenience functions when working with a future `Result`. **Note:** `_` represents the future itself as inserted by `->` (the [pipe](https://rescript-lang.org/docs/manual/latest/pipe) operator).\n\n**Note 2**: The terms `Result.Ok` and `Result.Error` in this context are expected to be read as `Ok` and `Error`.\n\n- `Future.mapOk(_,fn)` - Transform a future value into another value, but only if the value is an `Result.Ok`. Similar to `Promise.prototype.then`\n- `Future.mapError(_,fn)` - Transform a future value into another value, but only if the value is an `Result.Error`. Similar to `Promise.prototype.catch`\n- `Future.tapOk(_,fn)` - Do something with the value of a future without changing it, but only if the value is a `Ok`. Returns the same future. Convenience for side effects such as console logging.\n- `Future.tapError(_,fn)` - Same as `tapOk` but for `Result.Error`\n\nThe following are more situational:\n\n- `Future.flatMapOk(_, fn)` - Transform a future `Result.Ok` into\na future `Result`. Flattens the inner future.\n- `Future.flatMapError(_, fn)` - Transform a future `Result.Error` into\na future `Result`. Flattens the inner future.\n\n### FutureJs\n\nConvenience functions for interop with JavaScript land.\n\n- `FutureJs.fromPromise(promise, errorTransformer)`\n  - `promise` is the `RescriptCore.Promise.t('a)` that will be transformed into a\n    `Future.t(result('a, 'e))`\n  - `errorTransformer` allows you to determine how `Promise.error`\n    objects will be transformed before they are returned wrapped within\n    a `Error`.  This allows you to implement the error handling\n    method which best meets your application's needs.\n- `FutureJs.toPromise(future)`\n  - `future` is any `Future.t('a)` which is transformed into a\n    `RescriptCore.Promise.t('a)`. Always resolves, never rejects the promise.\n- `FutureJs.resultToPromise(future)`\n  - `future` is the `Future.t(result('a, 'e))` which is transformed into a\n    `RescriptCore.Promise.t('a)`. Resolves the promise on Ok result and rejects on Error result.\n\nExample use:\n\n\n```js\n/*\n  This error handler is super simple; you will probably want\n  to write something more sophisticated in your app.\n*/\nlet handleError = Js.String.make;\n\nsomePromiseGetter()\n->FutureJs.fromPromise(handleError)\n->Future.tap(value => Js.log2(\"It worked!\", value))\n->Future.tapError(err => Js.log2(\"uh on\", err));\n```\n\nSee [Composible Error Handling in OCaml][error-handling] for several strategies that you may employ.\n\n### Stack Safety\n\nBy default this library is not stack safe, you will recieve a 'Maximum call stack size exceeded' error if you recurse too deeply. You can opt into stack safety by passing an optional parameter to the constructors of trampoline. This has a slight overhead. For example:\n\n```reason\nlet stackSafe = Future.make(~executor=`trampoline, resolver);\nlet stackSafeValue = Future.value(~executor=`trampoline, \"Value\");\n```\n\n## TODO\n\n- [ ] Implement cancellation tokens\n- [x] Interop with `Js.Promise`\n- [x] `flatMapOk` / `flatMapError` (with [composable error handling](http://keleshev.com/composable-error-handling-in-ocaml))\n\n## Build\n\n```\nnpm run build\n```\n\n## Build + Watch\n\n```\nnpm run start\n```\n\n## Test\n\n```\nnpm test\n```\n\n## Editor\nIf you use `vscode`, Press `Windows + Shift + B` it will build automatically\n\n[error-handling]: http://keleshev.com/composable-error-handling-in-ocaml\n"
  },
  {
    "path": "__tests__/TestFuture.res",
    "content": "open Jest\nopen Expect\n\ndescribe(\"Future\", () => {\n  testAsync(\"sync chaining\", finish =>\n    Future.value(\"one\")\n    ->Future.map(s => s ++ \"!\")\n    ->Future.get(s => s->expect->toEqual(\"one!\")->finish)\n  )\n\n  testAsync(\"async chaining\", finish =>\n    Future.delay(25, () => 20)\n    ->Future.map(s => string_of_int(s))\n    ->Future.map(s => s ++ \"!\")\n    ->Future.get(s => s->expect->toEqual(\"20!\")->finish)\n  )\n\n  testAsync(\"tap\", finish => {\n    let v = ref(0)\n\n    Future.value(99)\n    ->Future.tap(n => v := n + 1)\n    ->Future.map(n => n - 9)\n    ->Future.get(n => (n, v.contents)->expect->toEqual((90, 100))->finish)\n  })\n\n  testAsync(\"flatMap\", finish =>\n    Future.value(59)\n    ->Future.flatMap(n => Future.value(n + 1))\n    ->Future.get(n => n->expect->toEqual(60)->finish)\n  )\n\n  testAsync(\"map2\", finish =>\n    Future.map2(Future.delay(20, () => 1), Future.value(\"a\"), (num, str) => (num, str))->Future.get(\n      tup => tup->expect->toEqual((1, \"a\"))->finish,\n    )\n  )\n\n  testAsync(\"map5\", finish =>\n    Future.map5(\n      Future.delay(20, () => 0),\n      Future.delay(40, () => 1.2),\n      Future.delay(60, () => \"foo\"),\n      Future.delay(80, () => list{}),\n      Future.delay(100, () => ()),\n      (a, b, c, d, e) => (a, b, c, d, e),\n    )->Future.get(tup => tup->expect->toEqual((0, 1.2, \"foo\", list{}, ()))->finish)\n  )\n\n  test(\"multiple gets\", () => {\n    let count = ref(0)\n    let future = Future.make(\n      resolve => {\n        count := count.contents + 1\n        resolve(count.contents)\n      },\n    )\n\n    future->Future.get(_ => ())\n\n    future->Future.get(_ => ())\n    count.contents->expect->toBe(1)\n  })\n\n  testAsync(\"multiple gets (async)\", finish => {\n    let count = ref(0)\n    let future = Future.sleep(25)->Future.map(() => 0)->Future.map(_ => count := count.contents + 1)\n\n    future->Future.get(_ => ())\n\n    let initialCount = count.contents\n\n    future->Future.get(_ => ())\n\n    future->Future.get(_ => (initialCount, count.contents)->expect->toEqual((0, 1))->finish)\n  })\n\n  testAsync(\"all (async)\", finish =>\n    {\n      open Future\n      all(list{value(1), delay(25, () => 2), delay(50, () => 3), sleep(75)->map(() => 4)})\n    }->Future.get(\n      result =>\n        switch result {\n        | list{1, 2, 3, 4} => pass->finish\n        | _ => fail(\"Expected [1, 2, 3, 4]\")->finish\n        },\n    )\n  )\n})\n\ndescribe(\"Future Result\", () => {\n  let (\\\">>=\", \\\"<$>\") = {\n    open Future\n    (\\\">>=\", \\\"<$>\")\n  }\n\n  testAsync(\"mapOk 1\", finish =>\n    Ok(\"two\")\n    ->Future.value\n    ->Future.mapOk(s => s ++ \"!\")\n    ->Future.get(r => Result.getExn(r)->expect->toEqual(\"two!\")->finish)\n  )\n\n  testAsync(\"mapOk 2\", finish =>\n    Error(\"err2\")\n    ->Future.value\n    ->Future.mapOk(s => s ++ \"!\")\n    ->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(e) => e->expect->toEqual(\"err2\")->finish\n        },\n    )\n  )\n\n  testAsync(\"mapError 1\", finish =>\n    Ok(\"three\")\n    ->Future.value\n    ->Future.mapError(s => s ++ \"!\")\n    ->Future.get(r => Result.getExn(r)->expect->toEqual(\"three\")->finish)\n  )\n\n  testAsync(\"mapError 2\", finish =>\n    Error(\"err3\")\n    ->Future.value\n    ->Future.mapError(s => s ++ \"!\")\n    ->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(e) => e->expect->toEqual(\"err3!\")->finish\n        },\n    )\n  )\n\n  testAsync(\"flatMapOk 1\", finish =>\n    Ok(\"four\")\n    ->Future.value\n    ->Future.flatMapOk(s => Ok(s ++ \"!\")->Future.value)\n    ->Future.get(r => Result.getExn(r)->expect->toEqual(\"four!\")->finish)\n  )\n\n  testAsync(\"flatMapOk 2\", finish =>\n    Error(\"err4.1\")\n    ->Future.value\n    ->Future.flatMapOk(s => Ok(s ++ \"!\")->Future.value)\n    ->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(e) => e->expect->toEqual(\"err4.1\")->finish\n        },\n    )\n  )\n\n  testAsync(\"flatMapOk 3\", finish =>\n    Error(\"err4\")\n    ->Future.value\n    ->Future.flatMapError(e => Error(e ++ \"!\")->Future.value)\n    ->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(e) => e->expect->toEqual(\"err4!\")->finish\n        },\n    )\n  )\n\n  testAsync(\"flatMapOkPure 1\", finish =>\n    Ok(\"four\")\n    ->Future.value\n    ->Future.flatMapOkPure(s => Ok(s ++ \"!\"))\n    ->Future.get(r => Result.getExn(r)->expect->toEqual(\"four!\")->finish)\n  )\n\n  testAsync(\"flatMapOkPure 2\", finish =>\n    Error(\"err4.1\")\n    ->Future.value\n    ->Future.flatMapOkPure(s => Ok(s ++ \"!\"))\n    ->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(e) => e->expect->toEqual(\"err4.1\")->finish\n        },\n    )\n  )\n\n  testAsync(\"flatMapError 1\", finish =>\n    Ok(\"five\")\n    ->Future.value\n    ->Future.flatMapError(s => Error(s ++ \"!\")->Future.value)\n    ->Future.get(r => Result.getExn(r)->expect->toEqual(\"five\")->finish)\n  )\n\n  testAsync(\"flatMapError 2\", finish =>\n    Error(\"err5\")\n    ->Future.value\n    ->Future.flatMapError(e => Error(e ++ \"!\")->Future.value)\n    ->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(e) => e->expect->toEqual(\"err5!\")->finish\n        },\n    )\n  )\n\n  testAsync(\"mapOk5 success\", finish =>\n    Future.mapOk5(\n      Future.value(Ok(0)),\n      Future.value(Ok(1.1)),\n      Future.value(Ok(\"\")),\n      Future.value(Ok(list{})),\n      Future.value(Ok(Some(\"x\"))),\n      (a, b, c, d, e) => (a, b, c, d, e),\n    )->Future.get(\n      r =>\n        switch r {\n        | Ok(tup) => tup->expect->toEqual((0, 1.1, \"\", list{}, Some(\"x\")))->finish\n        | Error(_) => fail(\"shouldn't be possible\")->finish\n        },\n    )\n  )\n\n  testAsync(\"mapOk5 fails on first error\", finish =>\n    Future.mapOk5(\n      Future.value(Ok(0)),\n      Future.delay(20, () => Ok(1.)),\n      Future.delay(10, () => Error(\"first\")),\n      Future.value(Ok(\"\")),\n      Future.delay(100, () => Error(\"second\")),\n      (_, _, _, _, _) => None,\n    )->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(x) => x->expect->toEqual(\"first\")->finish\n        },\n    )\n  )\n\n  testAsync(\"tapOk 1\", finish => {\n    let x = ref(1)\n\n    Ok(10)\n    ->Future.value\n    ->Future.tapOk(n => x := x.contents + n)\n    ->Future.get(_ => x.contents->expect->toEqual(11)->finish)\n  })\n\n  testAsync(\"tapOk 2\", finish => {\n    let y = ref(1)\n\n    Error(10)\n    ->Future.value\n    ->Future.tapOk(n => y := y.contents + n)\n    ->Future.get(_ => y.contents->expect->toEqual(1)->finish)\n  })\n\n  testAsync(\"tapError 1\", finish => {\n    let x = ref(1)\n\n    Ok(10)\n    ->Future.value\n    ->Future.tapError(n => x := x.contents + n)\n    ->Future.get(_ => x.contents->expect->toEqual(1)->finish)\n  })\n\n  testAsync(\"tapError\", finish => {\n    let y = ref(1)\n\n    Error(10)\n    ->Future.value\n    ->Future.tapError(n => y := y.contents + n)\n    ->Future.get(_ => y.contents->expect->toEqual(11)->finish)\n  })\n  testAsync(\"<$> 1\", finish =>\n    \\\"<$>\"(\n      \\\"<$>\"(Future.value(Ok(\"infix ops\")), x => x ++ \" \"),\n      x => x ++ \"rock!\",\n    )->Future.get(r => r->Result.getExn->expect->toEqual(\"infix ops rock!\")->finish)\n  )\n\n  testAsync(\"<$> 2\", finish =>\n    \\\"<$>\"(\n      \\\"<$>\"(Future.value(Error(\"infix ops\")), x => x ++ \" \"),\n      x => x ++ \"suck!\",\n    )->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(e) => e->expect->toEqual(\"infix ops\")->finish\n        },\n    )\n  )\n\n  testAsync(\">>= 1\", finish => {\n    let appendToString = (appendedString, s) => (s ++ appendedString)->Ok->Future.value\n\n    \\\">>=\"(\n      Future.value(Ok(\"infix ops\")),\n      s => appendToString(\" still rock!\", s),\n    )->Future.get(r => r->expect->toEqual(Ok(\"infix ops still rock!\"))->finish)\n  })\n\n  testAsync(\"value recursion is stack safe\", finish => {\n    let next = x => Future.value(~executor=#trampoline, x + 1)\n    let numberOfLoops = 10000\n    let rec loop = x =>\n      next(x)\n      ->Future.flatMap(x => Future.value(x + 1))\n      ->Future.map(x => x + 1)\n      ->Future.flatMap(x => Future.value(x + 1)->Future.flatMap(x => Future.value(x + 1)))\n      ->Future.flatMap(\n        x' =>\n          if x' > numberOfLoops {\n            Future.value(x')\n          } else {\n            loop(x')\n          },\n      )\n    loop(0)->Future.get(r => r->expect->toBeGreaterThan(numberOfLoops)->finish)\n  })\n\n  testAsync(\"async recursion is stack safe\", finish => {\n    let next = x => Future.delay(~executor=#trampoline, 1, () => x + 1)\n    let numberOfLoops = 1000\n    let rec loop = x =>\n      next(x)->Future.flatMap(\n        x' =>\n          if x' == numberOfLoops {\n            Future.value(x')\n          } else {\n            loop(x')\n          },\n      )\n    loop(0)->Future.get(r => r->expect->toEqual(numberOfLoops)->finish)\n  })\n})\n"
  },
  {
    "path": "__tests__/TestFutureJs.res",
    "content": "open Jest\nopen Expect\n\nexception TestError(string)\n\ndescribe(\"FutureJs\", () => {\n  let errorTransformer = x => x\n\n  testAsync(\"fromPromise (resolved)\", finish =>\n    Promise.resolve(42)\n    ->FutureJs.fromPromise(errorTransformer)\n    ->Future.get(r => Result.getExn(r)->expect->toEqual(42)->finish)\n  )\n\n  testAsync(\"fromPromise (rejected)\", finish => {\n    let err = TestError(\"oops!\")\n    Promise.reject(err)\n    ->FutureJs.fromPromise(errorTransformer)\n    ->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(_) => pass->finish\n        },\n    )\n  })\n\n  testAsync(\"fromPromise (internal rejection)\", finish => {\n    let err = TestError(\"boom!\")\n    let promise = Promise.make((_, reject) => reject(err))\n\n    FutureJs.fromPromise(promise, errorTransformer)->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(_) => pass->finish\n        },\n    )\n  })\n\n  testAsync(\"fromPromise (internal exception)\", finish => {\n    let err = TestError(\"explode!\")\n    let promise = Promise.make((_, _) => raise(err))\n\n    FutureJs.fromPromise(promise, errorTransformer)->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(_) => pass->finish\n        },\n    )\n  })\n\n  testAsync(\"fromPromise (wrapped callback)\", finish => {\n    let err = TestError(\"throwback!\")\n    let nodeFn = callback => callback(err)\n    let promise = Promise.make((_, reject) => nodeFn(err => reject(err)))\n\n    FutureJs.fromPromise(promise, errorTransformer)->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(_) => pass->finish\n        },\n    )\n  })\n\n  testAsync(\"fromPromise (layered failure)\", finish => {\n    let err = TestError(\"confused!\")\n    let nodeFn = callback => callback(err)\n    let promise = Promise.make((_, reject) => nodeFn(err => reject(err)))\n    let future = () => FutureJs.fromPromise(promise, errorTransformer)\n\n    Future.value(Ok(\"ignored\"))\n    ->Future.flatMapOk(_ => future())\n    ->Future.get(\n      r =>\n        switch r {\n        | Ok(_) => fail(\"shouldn't be possible\")->finish\n        | Error(_) => pass->finish\n        },\n    )\n  })\n  testPromise(\"toPromise\", () =>\n    Future.delay(5, () => \"payload\")\n    ->FutureJs.toPromise\n    ->Promise.then(x => Promise.resolve(x->expect->toEqual(\"payload\")))\n    ->Promise.catch(_ => raise(TestError(\"shouldn't be possible\")))\n  )\n\n  testPromise(\"resultToPromise (Ok result)\", () =>\n    FutureJs.resultToPromise(Future.delay(5, () => Ok(\"payload\")))\n    ->Promise.then(x => Promise.resolve(x->expect->toEqual(\"payload\")))\n    ->Promise.catch(_ => raise(TestError(\"shouldn't be possible\")))\n  )\n\n  testPromise(\"resultToPromise (Error exn)\", () => {\n    let err = TestError(\"error!\")\n\n    FutureJs.resultToPromise(Future.delay(5, () => Error(err)))\n    ->Promise.then(_ => raise(TestError(\"shouldn't be possible\")))\n    ->Promise.catch(_ => Promise.resolve(pass)) // Going from Future to Promise loses information...\n  })\n\n  testPromise(\"resultToPromise (Error `PolymorphicVariant)\", () => {\n    let err = #TestError\n\n    FutureJs.resultToPromise(Future.delay(5, () => Error(err)))\n    ->Promise.then(_ => raise(TestError(\"shouldn't be possible\")))\n    ->Promise.catch(_ => Promise.resolve(pass)) // Going from Future to Promise loses information...\n  })\n})\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  testPathIgnorePatterns: [\"/node_modules/\", \"__tests__/TestUtil.bs.js\"],\n  coveragePathIgnorePatterns: [\"/node_modules/\", \"__tests__/TestUtil.bs.js*\"]\n};\n\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"reason-future\",\n  \"version\": \"3.0.0\",\n  \"scripts\": {\n    \"build\": \"rescript build -with-deps\",\n    \"start\": \"rescript build -with-deps -w\",\n    \"clean\": \"rescript clean -with-deps\",\n    \"test\": \"yarn clean ; yarn build; jest --coverage --coverageReporters=text-lcov | coveralls\",\n    \"test:only\": \"yarn jest\"\n  },\n  \"files\": [\n    \"src/Future.res\",\n    \"src/FutureResult.res\",\n    \"src/FutureJs.res\",\n    \"rescript.json\",\n    \"README.md\"\n  ],\n  \"keywords\": [\n    \"Rescript\",\n    \"Future\",\n    \"Promise\",\n    \"JavaScript\",\n    \"Async\"\n  ],\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@glennsl/rescript-jest\": \"0.11.0\",\n    \"coveralls\": \"3.1.0\",\n    \"rescript\": \"11.1.4\"\n  },\n  \"description\": \"A lightweight, functional alternative to Js.Promise for ReScript, designed for better composability and error handling.\",\n  \"main\": \"index.js\",\n  \"dependencies\": {\n    \"@rescript/core\": \"^1.6.1\"\n  },\n  \"peerDependencies\": {\n    \"rescript\": \"^11.1.4\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/rationaljs/future.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/rationaljs/future/issues\"\n  },\n  \"homepage\": \"https://github.com/rationaljs/future#readme\"\n}\n"
  },
  {
    "path": "rescript.json",
    "content": "{\n  \"name\": \"reason-future\",\n  \"version\": \"3.0.0\",\n  \"sources\": [\n    {\n      \"dir\": \"src\",\n      \"subdirs\": true\n    },\n    {\n      \"dir\": \"__tests__\",\n      \"type\": \"dev\"\n    }\n  ],\n  \"package-specs\": {\n    \"module\": \"commonjs\",\n    \"in-source\": true\n  },\n  \"suffix\": \".bs.js\",\n  \"bs-dependencies\": [\"@rescript/core\"],\n  \"bs-dev-dependencies\": [\"@glennsl/rescript-jest\"],\n  \"bsc-flags\": [\"-open RescriptCore\"],\n  \"warnings\": {\n    \"error\": \"+101\"\n  },\n  \"namespace\": false\n}\n"
  },
  {
    "path": "src/Future.res",
    "content": "type getFn<'a> = ('a => unit) => unit\n\ntype executorType = [#none | #trampoline]\n\ntype t<'a> = Future(getFn<'a>, executorType)\n\nlet trampoline = {\n  let running = ref(false)\n  let callbacks = []\n  let rec runLoop = callback => {\n    callback()\n    switch Array.pop(callbacks) {\n    | None => ()\n    | Some(callback) => runLoop(callback)\n    }\n  }\n  callback =>\n    if running.contents {\n      ignore(Array.unshift(callbacks, callback))\n    } else {\n      running := true\n      runLoop(callback)\n      running := false\n    }\n}\n\nlet make = (~executor: executorType=#none, resolver) => {\n  let callbacks = ref(list{})\n  let data = ref(None)\n\n  let runCallback = switch executor {\n  | #none => (result, cb) => cb(result)\n  | #trampoline => (result, cb) => trampoline(() => cb(result))\n  }\n\n  resolver(result =>\n    switch data.contents {\n    | None =>\n      data := Some(result)\n      callbacks.contents->List.reverse->List.forEach(cb => runCallback(result, cb))\n      /* Clean up memory usage */\n      callbacks := list{}\n    | Some(_) => () /* Do nothing; theoretically not possible */\n    }\n  )->ignore\n\n  Future(\n    resolve =>\n      switch data.contents {\n      | Some(result) => runCallback(result, resolve)\n      | None => callbacks := list{resolve, ...callbacks.contents}\n      },\n    executor,\n  )\n}\n\nlet value = (~executor: executorType=#none, x) => make(~executor, resolve => resolve(x))\n\nlet map = (Future(get, executor), f) =>\n  make(~executor, resolve => get(result => resolve(f(result))))\n\nlet flatMap = (Future(get, executor), f) =>\n  make(~executor, resolve =>\n    get(result => {\n      let Future(get2, _) = f(result)\n      get2(resolve)\n    })\n  )\n\nlet map2 = (fa, fb, f) => flatMap(fa, a => map(fb, b => f(a, b)))\n\nlet map3 = (fa, fb, fc, f) => map2(map2(fa, fb, (a, b) => (a, b)), fc, ((a, b), c) => f(a, b, c))\n\nlet map4 = (fa, fb, fc, fd, f) =>\n  map2(map3(fa, fb, fc, (a, b, c) => (a, b, c)), fd, ((a, b, c), d) => f(a, b, c, d))\n\nlet map5 = (fa, fb, fc, fd, fe, f) =>\n  map2(map4(fa, fb, fc, fd, (a, b, c, d) => (a, b, c, d)), fe, ((a, b, c, d), e) =>\n    f(a, b, c, d, e)\n  )\n\nlet rec all = futures =>\n  switch futures {\n  | list{head, ...tail} =>\n    all(tail)->flatMap(tailResult => head->map(headResult => list{headResult, ...tailResult}))\n  | list{} => value(list{})\n  }\n\nlet tap = (Future(get, _) as future, f) => {\n  get(f)\n  future\n}\n\nlet get = (Future(getFn, _), f) => getFn(f)\n\n/**\n * Future Result convenience functions,\n * for working with a type Future.t( result('a,'b) )\n */\nlet mapOk = (future, f) => future->map(r => Result.map(r, f))\n\nlet mapError = (future, f) =>\n  future->map(r =>\n    switch r {\n    | Error(v) => Error(f(v))\n    | Ok(a) => Ok(a)\n    }\n  )\n\nlet flatMapOk = (future, f) =>\n  future->flatMap(r =>\n    switch r {\n    | Ok(v) => f(v)\n    | Error(e) => value(Error(e))\n    }\n  )\n\nlet flatMapOkPure = (fut, f) => fut->flatMapOk(result => value(result->f))\n\nlet flatMapError = (future, f) =>\n  future->flatMap(r =>\n    switch r {\n    | Ok(v) => value(Ok(v))\n    | Error(e) => f(e)\n    }\n  )\n\nlet mapOk2 = (fa, fb, f) => flatMapOk(fa, a => mapOk(fb, b => f(a, b)))\n\nlet mapOk3 = (fa, fb, fc, f) =>\n  mapOk2(mapOk2(fa, fb, (a, b) => (a, b)), fc, ((a, b), c) => f(a, b, c))\n\nlet mapOk4 = (fa, fb, fc, fd, f) =>\n  mapOk2(mapOk3(fa, fb, fc, (a, b, c) => (a, b, c)), fd, ((a, b, c), d) => f(a, b, c, d))\n\nlet mapOk5 = (fa, fb, fc, fd, fe, f) =>\n  mapOk2(mapOk4(fa, fb, fc, fd, (a, b, c, d) => (a, b, c, d)), fe, ((a, b, c, d), e) =>\n    f(a, b, c, d, e)\n  )\n\nlet tapOk = (future, f) =>\n  future->tap(r =>\n    switch r {\n    | Ok(v) => f(v)->ignore\n    | Error(_) => ()\n    }\n  )\n\nlet tapError = (future, f) =>\n  future->tap(r =>\n    switch r {\n    | Error(v) => f(v)->ignore\n    | Ok(_) => ()\n    }\n  )\n\nlet delay = (~executor=?, ms, f) =>\n  make(~executor?, resolve => setTimeout(() => resolve(f()), ms)->ignore)\n\nlet sleep = (~executor=?, ms) => delay(~executor?, ms, () => ())\n\nlet \\\">>=\" = flatMapOk\nlet \\\">>==\" = flatMapOkPure\nlet \\\"<$>\" = mapOk\n"
  },
  {
    "path": "src/Future.resi",
    "content": "type getFn<'a> = ('a => unit) => unit\ntype executorType = [#none | #trampoline]\ntype t<'a> = Future(getFn<'a>, executorType)\nlet trampoline: (unit => unit) => unit\nlet make: (~executor: executorType=?, ('a => unit) => 'b) => t<'a>\nlet value: (~executor: executorType=?, 'a) => t<'a>\nlet map: (t<'a>, 'a => 'b) => t<'b>\nlet flatMap: (t<'a>, 'a => t<'b>) => t<'b>\nlet map2: (t<'a>, t<'b>, ('a, 'b) => 'c) => t<'c>\nlet map3: (t<'a>, t<'b>, t<'c>, ('a, 'b, 'c) => 'd) => t<'d>\nlet map4: (t<'a>, t<'b>, t<'c>, t<'d>, ('a, 'b, 'c, 'd) => 'e) => t<'e>\nlet map5: (t<'a>, t<'b>, t<'c>, t<'d>, t<'e>, ('a, 'b, 'c, 'd, 'e) => 'f) => t<'f>\nlet all: list<t<'a>> => t<list<'a>>\nlet tap: (t<'a>, 'a => unit) => t<'a>\nlet get: (t<'a>, 'a => unit) => unit\nlet mapOk: (t<result<'a, 'b>>, 'a => 'c) => t<result<'c, 'b>>\nlet mapError: (t<result<'a, 'b>>, 'b => 'c) => t<result<'a, 'c>>\nlet flatMapOk: (t<result<'a, 'b>>, 'a => t<result<'c, 'b>>) => t<result<'c, 'b>>\nlet flatMapOkPure: (t<result<'a, 'b>>, 'a => result<'c, 'b>) => t<result<'c, 'b>>\nlet flatMapError: (t<result<'a, 'b>>, 'b => t<result<'a, 'c>>) => t<result<'a, 'c>>\nlet mapOk2: (t<result<'a, 'b>>, t<result<'c, 'b>>, ('a, 'c) => 'd) => t<result<'d, 'b>>\nlet mapOk3: (\n  t<result<'a, 'b>>,\n  t<result<'c, 'b>>,\n  t<result<'d, 'b>>,\n  ('a, 'c, 'd) => 'e,\n) => t<result<'e, 'b>>\nlet mapOk4: (\n  t<result<'a, 'b>>,\n  t<result<'c, 'b>>,\n  t<result<'d, 'b>>,\n  t<result<'e, 'b>>,\n  ('a, 'c, 'd, 'e) => 'f,\n) => t<result<'f, 'b>>\nlet mapOk5: (\n  t<result<'a, 'b>>,\n  t<result<'c, 'b>>,\n  t<result<'d, 'b>>,\n  t<result<'e, 'b>>,\n  t<result<'f, 'b>>,\n  ('a, 'c, 'd, 'e, 'f) => 'g,\n) => t<result<'g, 'b>>\nlet tapOk: (t<result<'a, 'b>>, 'a => 'c) => t<result<'a, 'b>>\nlet tapError: (t<result<'a, 'b>>, 'b => 'c) => t<result<'a, 'b>>\nlet delay: (~executor: executorType=?, int, unit => 'a) => t<'a>\nlet sleep: (~executor: executorType=?, int) => t<unit>\nlet \\\">>=\": (t<result<'a, 'b>>, 'a => t<result<'c, 'b>>) => t<result<'c, 'b>>\nlet \\\">>==\": (t<result<'a, 'b>>, 'a => result<'c, 'b>) => t<result<'c, 'b>>\nlet \\\"<$>\": (t<result<'a, 'b>>, 'a => 'c) => t<result<'c, 'b>>\n"
  },
  {
    "path": "src/FutureJs.res",
    "content": "@ocaml.doc(\"\n * Translate a Promise to a Future(result)\n *\n * errorTransformer: (Promise.error) => 'a\n * - The errorTransformer will provide you with the raw Promise.error\n *   object.  This is done so that you may decide on the appropriate error\n *   handling scheme for your application.\n *   See: http://keleshev.com/composable-error-handling-in-ocaml\n * - A good start is translating the Promise.error to a string.\n *   ```reason\n *   let errorTransformer = (error) =>\n *     String.make(error)\n *     ->(str => /*... do your transforms here */ str);\n*    ```\n \")\nlet fromPromise = (promise, errorTransformer) =>\n  Future.make(callback =>\n    promise\n    ->Promise.then(res => Promise.resolve(ignore(callback(Ok(res)))))\n    ->Promise.catch(error =>\n      Promise.resolve(\n        ignore(callback((transformed => Error(transformed))(errorTransformer(error)))),\n      )\n    )\n  )\n\nlet toPromise = future => Promise.make((resolve, _) => future->Future.get(value => resolve(value)))\n\nexception FutureError\n\nlet resultToPromise = future =>\n  Promise.make((resolve, reject) =>\n    future\n    ->Future.mapError(_ => FutureError)\n    ->Future.map(result =>\n      switch result {\n      | Ok(result) => resolve(result)\n      | Error(error) => reject(error)\n      }\n    )\n    ->ignore\n  )\n"
  },
  {
    "path": "src/FutureJs.resi",
    "content": "let fromPromise: (RescriptCore.Promise.t<'a>, exn => 'b) => Future.t<result<'a, 'b>>\nlet toPromise: Future.t<'a> => RescriptCore.Promise.t<'a>\ntype exn +=  FutureError\nlet resultToPromise: Future.t<result<'a, 'b>> => RescriptCore.Promise.t<'a>\n"
  },
  {
    "path": "src/FutureResult.res",
    "content": "let deprecate = (ft, name, more) =>\n  ft->Future.tap(_ => Console.warn(\"FutureResult.\" ++ (name ++ (\" is deprecated.\" ++ more))))\n\nlet mapOk = (future, f) =>\n  future\n  ->Future.map(r =>\n    switch r {\n    | Ok(v) => f(v)\n    | Error(e) => Error(e)\n    }\n  )\n  ->deprecate(\"mapOk\", \" Please use Future.mapOk instead.\")\n\nlet flatMapOk = (future, f) =>\n  future\n  ->Future.flatMap(r =>\n    switch r {\n    | Ok(v) => f(v)\n    | Error(e) => Future.value(Error(e))\n    }\n  )\n  ->deprecate(\"flatMapOk\", \"\")\n\nlet mapError = (future, f) =>\n  future\n  ->Future.map(r =>\n    switch r {\n    | Error(v) => f(v)\n    | Ok(a) => Ok(a)\n    }\n  )\n  ->deprecate(\"mapError\", \" Please use Future.mapError instead.\")\n\nlet flatMapError = (future, f) =>\n  future\n  ->Future.flatMap(r =>\n    switch r {\n    | Error(v) => f(v)\n    | Ok(a) => Future.value(Ok(a))\n    }\n  )\n  ->deprecate(\"mapOk\", \"\")\n\nlet tapOk = (future, f) =>\n  future\n  ->Future.tap(r =>\n    switch r {\n    | Ok(v) => f(v)->ignore\n    | Error(_) => ()\n    }\n  )\n  ->deprecate(\"tapOk\", \" Please use Future.tapOk instead.\")\n\nlet tapError = (future, f) =>\n  future\n  ->Future.tap(r =>\n    switch r {\n    | Error(v) => f(v)->ignore\n    | Ok(_) => ()\n    }\n  )\n  ->deprecate(\"tapError\", \" Please use Future.tapError instead.\")\n"
  }
]