Socket
Socket
Sign inDemoInstall

fluture

Package Overview
Dependencies
2
Maintainers
1
Versions
109
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.4.1 to 0.5.0

308

fluture.js

@@ -25,2 +25,6 @@ /*global define*/

////////////////////
// Error handling //
////////////////////
//A toString function to provide a slightly more meaningful representation of values.

@@ -38,36 +42,31 @@ const toString = x =>

function error(message, actual){
return message + '\n Actual: ' + actual;
function error$invalidArgument(it, at, expected, actual){
throw new TypeError(
`${it} expects argument ${at} to ${expected}\n Actual: ${toString(actual)}`
);
}
function error$invalidContext(it, actual){
throw new TypeError(
`${it} was invoked outside the context of a Future. You might want to use`
+ ` a dispatcher instead\n Called on: ${toString(actual)}`
)
}
//Check input to Future.
function check$Future(fork){
if(typeof fork !== 'function') throw new TypeError(error(
'Future expects its argument to be a function',
toString(fork)
));
if(typeof fork !== 'function') error$invalidArgument('Future', 0, 'be a function', fork);
}
//Check input to Future#fork.
function check$fork$rej(f){
if(typeof f !== 'function') throw new TypeError(error(
'Future#fork expects its first argument to be a function',
toString(f)
));
function check$fork(it, rej, res){
if(!(it instanceof FutureClass)) error$invalidContext('Future#chain', it);
if(typeof rej !== 'function') error$invalidArgument('Future#fork', 0, 'be a function', rej);
if(typeof res !== 'function') error$invalidArgument('Future#fork', 1, 'be a function', res);
}
//Check input to Future#fork.
function check$fork$res(f){
if(typeof f !== 'function') throw new TypeError(error(
'Future#fork expects its second argument to be a function',
toString(f)
));
}
//Check input to Future#chain.
function check$chain(f){
if(typeof f !== 'function') throw new TypeError(error(
'Future#chain expects its argument to be a function',
toString(f)
));
function check$chain(it, f){
if(!(it instanceof FutureClass)) error$invalidContext('Future#chain', it);
if(typeof f !== 'function') error$invalidArgument('Future#chain', 0, 'be a function', f);
}

@@ -77,22 +76,30 @@

function check$chain$f(m, f, x){
if(!(m instanceof FutureClass)) throw new TypeError(error(
'Future#chain expects the function its given to return a Future',
`${toString(m)}\n From calling: ${toString(f)}\n With: ${toString(x)}`
));
if(!(m instanceof FutureClass)) throw new TypeError(
'Future#chain expects the function its given to return a Future'
+ `\n Actual: ${toString(m)}\n From calling: ${toString(f)}\n With: ${toString(x)}`
);
}
function check$chainRej(it, f){
if(!(it instanceof FutureClass)) error$invalidContext('Future.chainRej', it);
if(typeof f !== 'function') error$invalidArgument('Future.chainRej', 0, 'a function', f);
}
function check$chainRej$f(m, f, x){
if(!(m instanceof FutureClass)) throw new TypeError(
'Future.chainRej expects the function its given to return a Future'
+ `\n Actual: ${toString(m)}\n From calling: ${toString(f)}\n With: ${toString(x)}`
);
}
//Check input to Future#map.
function check$map(f){
if(typeof f !== 'function') throw new TypeError(error(
'Future#map expects its argument to be a function',
toString(f)
));
function check$map(it, f){
if(!(it instanceof FutureClass)) error$invalidContext('Future#map', it);
if(typeof f !== 'function') error$invalidArgument('Future#map', 0, 'be a function', f);
}
//Check input to Future#ap.
function check$ap(m){
if(!(m instanceof FutureClass)) throw new TypeError(error(
'Future#ap expects its argument to be a Future',
toString(m)
));
function check$ap(it, m){
if(!(it instanceof FutureClass)) error$invalidContext('Future#map', it);
if(!(m instanceof FutureClass)) error$invalidArgument('Future#ap', 0, 'be a Future', m);
}

@@ -102,13 +109,14 @@

function check$ap$f(f){
if(typeof f !== 'function') throw new TypeError(error(
'Future#ap was called on something other than Future<Function>',
`Future.of(${toString(f)})`
));
if(typeof f !== 'function') throw new TypeError(
`Future#ap can only b used on Future<Function> but was used on: ${toString(f)}`
);
}
function check$race(it, m){
if(!(it instanceof FutureClass)) error$invalidContext('Future.race', it);
if(!(m instanceof FutureClass)) error$invalidArgument('Future.race', 0, 'be a function', m);
}
function check$cache(m){
if(!(m instanceof FutureClass)) throw new TypeError(error(
'Future.cache expects its argument to be a Future',
toString(m)
));
if(!(m instanceof FutureClass)) error$invalidArgument('Future.cache', 0, 'be a Future', m);
}

@@ -126,58 +134,18 @@

function check$liftNode(f){
if(typeof f !== 'function') throw new TypeError(error(
'Future.liftNode expects its first argument to be a function',
toString(f)
));
}
function check$liftPromise(f){
if(typeof f !== 'function') throw new TypeError(error(
'Future.liftPromise expects its first argument to be a function',
toString(f)
));
}
function check$liftPromise$f(m, f, x){
if(!m || typeof m.then !== 'function') throw new TypeError(error(
'Future.liftPromise expects the function its given to return a Promise',
`${toString(m)}\n From calling: ${toString(f)}\n With: ${toString(x)}`
));
}
function check$after(n){
if(typeof n !== 'number') throw new TypeError(error(
'Future.after expects its first argument to be a number',
toString(n)
));
if(typeof n !== 'number') error$invalidArgument('Future.after', 0, 'be a number', n);
}
function check$try(f){
if(typeof f !== 'function') throw new TypeError(error(
'Future.try expects its first argument to be a function',
toString(f)
));
if(typeof f !== 'function') error$invalidArgument('Future.try', 0, 'be a function', f);
}
function check$node(f){
if(typeof f !== 'function') throw new TypeError(error(
'Future.node expects its first argument to be a function',
toString(f)
));
if(typeof f !== 'function') error$invalidArgument('Future.node', 0, 'be a function', f);
}
function check$race$m1(m){
if(!(m instanceof FutureClass)) throw new TypeError(error(
'Future.race expects its first argument to be a Future',
toString(m)
));
}
////////////
// Future //
////////////
function check$race$m2(m){
if(!(m instanceof FutureClass)) throw new TypeError(error(
'Future.race expects its second argument to be a Future',
toString(m)
));
}
//Constructor.

@@ -202,4 +170,3 @@ function FutureClass(f){

function Future$fork(rej, res){
check$fork$rej(rej);
check$fork$res(res);
check$fork(this, rej, res);
this._f(rej, res);

@@ -209,3 +176,3 @@ }

function Future$chain(f){
check$chain(f);
check$chain(this, f);
const _this = this;

@@ -221,4 +188,16 @@ return new FutureClass(function Future$chain$fork(rej, res){

function Future$chainRej(f){
check$chainRej(this, f);
const _this = this;
return new FutureClass(function Future$chainRej$fork(rej, res){
_this._f(function Future$chainRej$rej(x){
const m = f(x);
check$chainRej$f(m, f, x);
m._f(rej, res);
}, res);
});
}
function Future$map(f){
check$map(f);
check$map(this, f);
const _this = this;

@@ -233,3 +212,3 @@ return new FutureClass(function Future$map$fork(rej, res){

function Future$ap(m){
check$ap(m);
check$ap(this, m);
const _this = this;

@@ -256,2 +235,13 @@ return new FutureClass(function Future$ap$fork(g, h){

function Future$race(m){
check$race(this, m);
const _this = this;
return new FutureClass(function Future$race$fork(rej, res){
let settled = false;
const once = f => a => settled || (settled = true, f(a));
_this._f(once(rej), once(res));
m._f(once(rej), once(res));
});
}
//Give Future a prototype.

@@ -265,2 +255,3 @@ FutureClass.prototype = Future.prototype = {

chain: Future$chain,
chainRej: Future$chainRej,
[FL.map]: Future$map,

@@ -270,3 +261,4 @@ map: Future$map,

ap: Future$ap,
toString: Future$toString
toString: Future$toString,
race: Future$race
};

@@ -280,2 +272,47 @@

/////////////////
// Dispatchers //
/////////////////
//Creates a dispatcher for a unary method.
function createUnaryDispatcher(method){
return curry(function dispatch(a, m){
if(m && typeof m[method] === 'function') return m[method](a);
error$invalidArgument(`Future.${method}`, 1, `have a "${method}" method`, m);
});
}
//Creates a dispatcher for a binary method.
function createBinaryDispatcher(method){
return curry(function dispatch(a, b, m){
if(m && typeof m[method] === 'function') return m[method](a, b);
error$invalidArgument(`Future.${method}`, 2, `have a "${method}" method`, m);
});
}
//chain :: Chain m => (a -> m b) -> m a -> m b
Future.chain = createUnaryDispatcher('chain');
//chainRej :: (a -> Future a c) -> Future a b -> Future a c
Future.chainRej = createUnaryDispatcher('chainRej');
//map :: Functor m => (a -> b) -> m a -> m b
Future.map = createUnaryDispatcher('map');
//ap :: Apply m => m (a -> b) -> m a -> m b
Future.ap = curry(function dispatch$ap(m, a){
if(m && typeof m.ap === 'function') return m.ap(a);
error$invalidArgument('Future.ap', 0, 'have a "ap" method', m);
});
//fork :: (a -> Void) -> (b -> Void) -> Future a b -> Void
Future.fork = createBinaryDispatcher('fork');
//race :: Future a b -> Future a b -> Future a b
Future.race = createUnaryDispatcher('race');
///////////////
// Utilities //
///////////////
/**

@@ -318,47 +355,2 @@ * Cache a Future

/**
* Turn a node continuation-passing-style function into a function which returns a Future.
*
* Takes a function which uses a node-style callback for continuation and
* returns a function which returns a Future for continuation.
*
* @sig liftNode :: (x..., (a, b -> Void) -> Void) -> x... -> Future[a, b]
*
* @param {Function} f The node function to wrap.
*
* @return {Function} A function which returns a Future.
*/
Future.liftNode = function Future$liftNode(f){
check$liftNode(f);
return function Future$liftNode$lifted(){
const xs = arguments;
return new FutureClass(function Future$liftNode$fork(rej, res){
return f(...xs, function Future$liftNode$callback(err, result){
err ? rej(err) : res(result);
});
});
};
};
/**
* Turn a function which returns a Promise into a function which returns a Future.
*
* @sig liftPromise :: (x... -> Promise a b) -> x... -> Future a b
*
* @param {Function} f The function to wrap.
*
* @return {Function} A function which returns a Future.
*/
Future.liftPromise = function Future$liftPromise(f){
check$liftPromise(f);
return function Future$liftPromise$lifted(){
const xs = arguments;
return new FutureClass(function Future$liftPromise$fork(rej, res){
const m = f(...xs);
check$liftPromise$f(m, f, xs);
return m.then(res, rej);
});
};
};
//Create a Future which rejects witth the given value.

@@ -415,32 +407,2 @@ Future.reject = function Future$reject(x){

/**
* Race two Futures against eachother.
*
* Creates a new Future which resolves or rejects with the resolution or
* rejection value of the first Future to settle.
*
* @param {Future} m1 The first Future.
* @param {Future} m2 The second Future.
*
* @return {Future}
*
* @example
*
* race(
* Future(rej => setTimeout(rej, 8000, new Error('Request timed out'))),
* fromNode(done => request('http://example.com', done))
* )
*
*/
Future.race = curry(function Future$race(m1, m2){
check$race$m1(m1);
check$race$m2(m2);
return new FutureClass(function Future$race$fork(rej, res){
let settled = false;
const once = f => a => settled || (settled = true, f(a));
m1._f(once(rej), once(res));
m2._f(once(rej), once(res));
});
});
//Export Future factory.

@@ -447,0 +409,0 @@ return Future;

{
"name": "fluture",
"version": "0.4.1",
"version": "0.5.0",
"description": "A complete Fantasy Land compatible Future library",

@@ -5,0 +5,0 @@ "main": "fluture.js",

# Fluture
A complete Fantasy Land compatible Future library.
A complete [Fantasy Land][1] compatible Future library.

@@ -11,23 +11,45 @@ > `npm install --save fluture` <sup>Requires a node 5.0.0 compatible environment

Using the low level, high performance method API:
```js
Future.node(done => fs.readFile('package.json', 'utf8', done))
.chain(x => Future.try(() => JSON.parse(x)))
.map(x => x.name)
.fork(console.error, console.log)
const Future = require('fluture');
const program = file =>
Future.node(done => fs.readFile(file, 'utf8', done))
.chain(x => Future.try(() => JSON.parse(x)))
.map(x => x.name)
.fork(console.error, console.log);
program('package.json');
//> "fluture"
```
## Motivation
Or use the high level, fully curried, functional dispatch API for function
composition using composers like [`S.pipe`][2]:
* A stand-alone Fantasy Future package.
```js
const {node, chain, try, map, fork} = require('fluture');
const program = S.pipe([
file => node(fs.readFile.bind(fs, file, 'utf8')),
chain(x => try(() => JSON.parse(x))),
map(x => x.name),
fork(console.error, console.log)
]);
program('package.json')
//> "fluture"
```
## Why?
* Great error messages.
* Async control utilities included.
* Easier debugging than `f(...).fork is not a function`.
* Still maintain decent speed.
* High performance Future implementation.
* Decent documentation.
## Documentation
### Future
### Constructors
#### Future :: ((a -> Void), (b -> Void) -> Void) -> Future a b
A (monadic) container which represents an eventual value. A lot like Promise but
more principled in that it follows the Fantasy Land algebraic JavaScript
more principled in that it follows the [Fantasy Land][1] algebraic JavaScript
specification.

@@ -44,4 +66,2 @@

----
#### `of :: b -> Future a b`

@@ -114,4 +134,26 @@

----
### Method API
#### `fork :: Future a b ~> (a -> Void), (b -> Void) -> Void`
Execute the Future (which up until now was merely a container for its
computation), and get at the result or error.
It is the return from Fantasy Land to the real world. This function best shows
the fundamental difference between Promises and Futures.
```js
Future.of('world').fork(
err => console.log(`Oh no! ${err.message}`),
thing => console.log(`Hello ${thing}!`)
);
//> "Hello world!"
Future.reject(new Error('It broke!')).fork(
err => console.log(`Oh no! ${err.message}`),
thing => console.log(`Hello ${thing}!`)
);
//> "Oh no! It broke!"
```
#### `map :: Future a b ~> (b -> c) -> Future a c`

@@ -137,2 +179,16 @@

#### `chainRej :: Future a b ~> (a -> Future a c) -> Future a c`
FlatMap over the **rejection** value inside the Future. If the Future is
resolved, chaining is not performed.
```js
Future.reject(new Error('It broke!')).chainRej(err => {
console.error(err);
return Future.of('All is good')
})
.fork(console.error, console.log)
//> "All is good"
```
#### `ap :: Future a (b -> c) ~> Future a b -> Future a c`

@@ -148,6 +204,4 @@

----
#### `race :: Future a b ~> Future a b -> Future a b`
#### `race :: Future a b -> Future a b -> Future a b`
Race two Futures against eachother. Creates a new Future which resolves or

@@ -157,6 +211,38 @@ rejects with the resolution or rejection value of the first Future to settle.

```js
Future.race(Future.after(100, 'hello'), Future.after(50, 'bye'))
Future.after(100, 'hello')
.race(Future.after(50, 'bye'))
.fork(console.error, console.log)
//> "bye"
```
### Dispatcher API
#### `fork :: (a -> Void) -> (b -> Void) -> Future a b -> Void`
Dispatches the first and second arguments to the `fork` method of the third argument.
#### `map :: Functor m => (a -> b) -> m a -> m b`
Dispatches the first argument to the `map` method of the second argument.
Has the same effect as [`R.map`][3].
#### `chain :: Chain m => (a -> m b) -> m a -> m b`
Dispatches the first argument to the `chain` method of the second argument.
Has the same effect as [`R.chain`][4].
#### `chainRej :: (a -> Future a c) -> Future a b -> Future a c`
Dispatches the first argument to the `chainRej` method of the second argument.
#### `ap :: Apply m => m (a -> b) -> m a -> m b`
Dispatches the second argument to the `ap` method of the first argument.
Has the same effect as [`R.ap`][5].
#### `race :: Future a b -> Future a b -> Future a b`
Dispatches the first argument to the `race` method of the second argument.
```js
const first = futures => futures.reduce(Future.race);

@@ -172,13 +258,11 @@ first([

----
### Futurization
#### `liftNode :: (x..., (a, b -> Void) -> Void) -> x... -> Future a b`
To reduce the boilerplate of making Node or Promise functions return Future's
instead, one might use the [Futurize][6] library:
Turn a node continuation-passing-style function into a function which returns a Future.
Takes a function which uses a node-style callback for continuation and returns a
function which returns a Future for continuation.
```js
const readFile = Future.liftNode(fs.readFile);
const Future = require('fluture');
const futurize = require('futurize').futurize(Future);
const readFile = futurize(require('fs').readFile);
readFile('README.md', 'utf8')

@@ -191,8 +275,2 @@ .map(text => text.split('\n'))

#### `liftPromise :: (x... -> Promise a b) -> x... -> Future a b`
Turn a function which returns a Promise into a function which returns a Future.
Like liftNode, but for a function which returns a Promise.
## Road map

@@ -205,13 +283,17 @@

* [x] Implement Future.cache
* [ ] Implement Future.mapRej
* [ ] Implement Future.chainRej
* [ ] Implement dispatchers: chain, map, ap, fork
* [ ] Implement Future.swap
* [ ] Implement Future.and
* [ ] Implement Future.or
* [x] Implement Future.race
* [ ] Implement Future#mapRej
* [x] Implement Future#chainRej
* [x] Implement dispatchers
* [ ] Implement Future#swap
* [ ] Implement Future#and
* [ ] Implement Future#or
* [ ] Implement Future#fold
* [ ] Implement Future#value
* [x] Implement Future#race
* [ ] Implement Future.parallel
* [ ] Implement Future.predicate
* [ ] Implement Future.promise
* [ ] Implement Future#promise
* [ ] Implement Future.cast
* [ ] Implement Future.encase
* [x] Check `this` on instance methods
* [x] Create documentation

@@ -239,1 +321,10 @@ * [ ] Wiki: Comparison between Future libs

[MIT licensed](LICENSE)
<!-- References -->
[1]: https://github.com/fantasyland/fantasy-land
[2]: https://github.com/plaid/sanctuary#pipe--a-bb-cm-n---a---n
[3]: http://ramdajs.com/docs/#map
[4]: http://ramdajs.com/docs/#chain
[5]: http://ramdajs.com/docs/#ap
[6]: https://github.com/futurize/futurize
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc