Socket
Socket
Sign inDemoInstall

caco

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

caco - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

73

index.js

@@ -1,9 +0,44 @@

var isGenerator = function (val) {
function isGenerator (val) {
return val && typeof val.next === 'function' && typeof val.throw === 'function'
}
var isPromise = function (val) {
function isPromise (val) {
return val && typeof val.then === 'function'
}
module.exports = function caco (gen) {
function isObservable (val) {
return val && typeof val.subscribe === 'function'
}
// default yieldable mapper
function defaultMapper (val, cb) {
if (isPromise(val)) {
val.then(function (value) {
cb(null, value)
}, function (err) {
cb(err || new Error())
})
return true
}
if (isGenerator(val)) {
caco(val)(cb)
return true
}
if (isObservable(val)) {
var dispose = val.subscribe(function (res) {
cb(null, res)
dispose.dispose()
}, function (err) {
cb(err)
dispose.dispose()
})
return true
}
return false
}
function caco (gen, mapper) {
return function () {

@@ -15,3 +50,8 @@ var args = Array.prototype.slice.call(arguments)

args.push(next)
// callback stepper
args.push(function next (err, res) {
process.nextTick(function () {
step(err, res)
})
})

@@ -27,14 +67,7 @@ var iter = isGenerator(gen) ? gen : gen.apply(self, args)

if (isPromise(state.value)) {
// handle thenable
state.value.then(function (value) {
step(null, value)
}, function (err) {
step(err || true)
})
} else if (isGenerator(state.value)) {
caco(state.value)(next)
} else if (state.done) {
step(null, state.value)
}
var yieldable = defaultMapper(state.value, step) || (
mapper && mapper(state.value, step)
)
if (!yieldable && state.done) step(null, state.value)
} catch (err) {

@@ -46,8 +79,2 @@ // catch err, break iteration

function next (err, res) {
process.nextTick(function () {
step(err, res)
})
}
if (callback) {

@@ -67,1 +94,3 @@ step()

}
module.exports = caco
{
"name": "caco",
"version": "1.0.0",
"version": "1.1.0",
"description": "Generator based control flow that supports both callbacks and promises",

@@ -15,2 +15,3 @@ "scripts": {

"devDependencies": {
"rx": "^4.0.7",
"standard": "^6.0.4",

@@ -17,0 +18,0 @@ "tape": "^3.0.2"

@@ -7,7 +7,8 @@ # caco

Many of the existing async libraries require wrapping callback functions into promises to be usuable, which creates unnecessary complication.
Many existing flow-control libraries such as [co](https://github.com/tj/co), assumes promises to be the lowest denominator of async handling.
Callback functions require promisify to be compatible, which creates unnecessary complication.
In caco, both callbacks and promises are 'yieldable';
resulting function can be used by both callbacks and promises.
This enables a powerful control flow while maintaining compatibility.
In caco, both callbacks and promises are yieldable.
Resulting function can also be used by both callbacks and promises.
This enables a powerful control flow while maintaining simplicity.

@@ -18,2 +19,4 @@ ```bash

#### var fn = caco(fn *)
```js

@@ -23,8 +26,4 @@ var caco = require('caco')

var fn = caco(function * (next) {
var foo = yield Promise.resolve('bar') // yield promise
yield setTimeout(next, 100) // yield callback using 'next' argument
// try/catch errors
try {
yield Promise.reject('boom')
yield Promise.reject('boom') // yield promise reject throws error
} catch (err) {

@@ -34,38 +33,71 @@ console.log(err) // 'boom'

var data = yield fs.readFile('./foo/bar', next)
var foo = yield Promise.resolve('bar') // yield promise
yield setTimeout(next, 1000) // yield callback using 'next' argument, delay 1 second
// yield callback of form next(err, data): return data, throw if err exists
var data = yield fs.readFile('./foo/bar', next)
return data
})
// consume with callback
// Use with callback
fn(function (err, res) { })
// Use with promise
fn().then(...).catch(...)
```
## API
To enable yieldable callbacks, yielding non-promise-nor-generator value pauses the current generator.
Until `next(err, val)` being invoked by callback,
where `val` passes back to yielded value, or `throw` if `err` exists.
#### var fn = caco(fn *)
## Yieldables
Wraps a generator into a regular function that acceots callback or promise.
By default, the following objects are supported for `yield`:
* `Promise`
* `Observable`
* `Generator`
Caco also accepts a yield mapper function,
so that one can basically yield anything.
#### var fn = caco(fn *, mapper)
```js
var getN = caco(function * (n, next) {
if (n === 689) yield Promise.reject('boom') // yield reject throws error
return yield Promise.resolve(n)
})
function mapper (val, cb) {
// map array to Promise.all
if (Array.isArray(val)) {
Promise.all(val).then(function (res) {
cb(null, res)
}, cb)
return true // acknowledge yieldable
}
getN(123, function (err, val) {
console.log(val) // 123
})
getN(123).then(...)
// Anything can be mapped!
if (val === 689) {
cb(new Error('DLLM'))
return true
}
}
getN(689).catch(function (err) {
console.log(err) // boom
})
caco(function * () {
console.log(yield [
Promise.resolve(1),
Promise.resolve(2),
3
]) // [1, 2, 3]
// yield 689 throws error
try {
yield 689
} catch (err) {
console.log(err) // 'DLLM'
}
}, mapper)(function (err) { })
```
Generator accepts optional `next` argument for yieldable callback
## License
MIT
var test = require('tape')
var caco = require('./')
var Observable = require('rx').Observable
test('caco', function (t) {
t.plan(5)
test('arguments and return', function (t) {
t.plan(8)
function * v (n) {
var fn = caco(function * (num, str, next) {
t.equal(num, 167, 'arguemnt')
t.equal(str, '167', 'arguemnt')
t.equal(typeof next, 'function', 'stepping function')
})
t.notOk(fn(167, '167', function () { }), 'passing callback returns undefined')
t.equal(typeof fn(167, '167').then, 'function', 'no callback returns promise')
})
test('scope', function (t) {
var obj = {}
caco(function * () {
t.equal(this, obj, 'correct scope')
t.end()
}).call(obj)
})
test('resolve and reject', function (t) {
t.plan(6)
caco(function * () {
return 167
})().then(function (val) {
t.equal(val, 167, 'promise resolve')
}, t.error)
caco(function * () {
throw new Error('167')
})().then(t.error, function (err) {
t.equal(err.message, '167', 'promise reject')
})
caco(function * () {
return yield Promise.resolve(167)
})(function (err, val) {
t.error(err)
t.equal(val, 167, 'callback value')
})
caco(function * () {
return Promise.reject(167)
})(function (err, val) {
t.equal(err, 167, 'callback error')
t.error(val)
})
})
test('default yieldable', function (t) {
function * resolveGen (n) {
return yield Promise.resolve(n)
}
var n = caco(function * (n) {
var rejectFn = caco(function * (n) {
return yield Promise.reject(n)
})
var v1 = caco(function * (next) {
yield setTimeout(next, 0)
var instantVal = caco(function * (next) {
return 1044
})
var v2 = caco(function * () {
var tryCatch = caco(function * () {
try {
return yield n(689)
} catch (e) {
return yield v(167)
return yield rejectFn(689)
} catch (err) {
t.equal(err, 689, 'try/catch promise reject')
return yield resolveGen(167)
}
})
var f = caco(function * (str, next) {
var n = (yield v1()) / 2 + (yield v2(next))
return str + n
})
caco(function * (next) {
yield setTimeout(next, 0)
var o = yield Observable
.fromArray([1, 2])
.merge(Observable.fromPromise(Promise.resolve(3)))
.delay(10)
.toArray()
t.deepEqual(o, [1, 2, 3], 'yield observable')
t.equal(yield instantVal(next), 1044, 'yield callback')
t.equal(yield tryCatch(), 167, 'yield gnerator-promise')
})(t.end)
})
n('boom', function (err) {
t.equal(err, 'boom', 'correct callback error')
})
test('yieldable mapper', function (t) {
caco(function * () {
t.deepEqual(yield [
Promise.resolve(1),
Promise.resolve(2),
3
], [1, 2, 3], 'yield map array to Promise.all')
n('boom').then(t.error).catch(function (err) {
t.equal(err, 'boom', 'correct promise reject')
})
f('D7', function (err, res) {
t.notOk(err, 'no error')
t.deepEqual(res, 'D7689', 'correct callback value')
})
f('DLM').then(function (res) {
t.deepEqual(res, 'DLM689', 'correct promise value')
}).catch(t.error)
try {
yield 689
} catch (err) {
t.equal(err.message, 'DLLM', 'yield 689 throws error')
}
}, function (val, cb) {
// yield array
if (Array.isArray(val)) {
Promise.all(val).then(function (res) {
cb(null, res)
}, function (err) {
cb(err || new Error())
})
return true
}
// yield 689 throws error
if (val === 689) {
cb(new Error('DLLM'))
return true
}
})(t.end)
})
SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc