Last active
December 8, 2018 17:36
-
-
Save stuxcrystal/f7b7fe67dcb2b7d8cbba62b1d96763cb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const _patch_ll = function(list) { | |
list.split = function() { | |
return _patch_ll({node: list.node}); | |
} | |
list.append = function(data) { | |
list.node = { | |
target: data | |
prev: list.node | |
} | |
}; | |
list.push = function(data) { | |
let sp = list.split(); | |
sp.append(data); | |
return sp; | |
}; | |
list.each = function*() { | |
let node = list.node; | |
if (node === null) return; | |
while (node.prev !== null) { | |
yield node.target; | |
node = node.prev; | |
} | |
}; | |
return list; | |
} | |
const _make_ll = function() { | |
return _patch_ll({node: null}); | |
} | |
const RETURN = 0; | |
const BUBBLE = 1; | |
const RETRY = 2; | |
const _runner = function(fn, catcher, async_) { | |
let _fore; | |
if (async_) { | |
_fore = async function(...args) { | |
let retry = 0; | |
while (true) { | |
try { | |
return await fn(...args); | |
} catch (e) { | |
const op = catcher._handle(e, retry); | |
} | |
if (op.op === RETRY) { | |
retry += 1; | |
continue; | |
} | |
if (op.op === BUBBLE) | |
throw op.e; | |
return op.result; | |
} | |
} | |
} else { | |
_fore = function(...args) { | |
let retry = 0; | |
while (true) { | |
try { | |
return fn(...args); | |
} catch (e) { | |
const op = catcher._handle(e, retry); | |
} | |
if (op.op === RETRY) { | |
retry += 1; | |
continue; | |
} | |
if (op.op === BUBBLE) | |
throw op.e; | |
return op.result; | |
} | |
} | |
} | |
return _fore; | |
} | |
const _catcher = function(_ball, ops) { | |
const _handler = { | |
fn: _ball.fn, | |
async_: _ball.async_ | |
ops: ops | |
}; | |
_handler._handle = function(e, retry) { | |
const op = { | |
op: RETURN, | |
e: e, | |
result: undefined, | |
retry: retry | |
} | |
for (let cb of _handler.ops.each()) { | |
cb(op); | |
} | |
return op; | |
} | |
const _caught = _runner(_ball.catcher, _handler.async_); | |
_caught.push = function(fn) { | |
return _catcher(_handler, _ball.ops.push(fn)); | |
} | |
_caught.except = function(...errors) { | |
return _caught.push((op) => { | |
for (let error of errors) { | |
if (op.e instanceof error) | |
op.op = BUBBLE; | |
} | |
}); | |
} | |
_caught.on = function(err, fn) { | |
return _caught.push((op) => { | |
if (err===null || op.e instanceof err) { | |
op.op = RETURN; | |
op.result = fn(op.e); | |
} | |
}) | |
} | |
_caught.retry_on = function(err, count) { | |
return _caught.push((op) => { | |
if (op.e instanceof err) { | |
if (!count || op.retry+1 < count) { | |
op.op = RETRY; | |
} | |
} | |
}); | |
} | |
_caught.retry = function(count) { | |
return _caught.push((op) => { | |
if (op.retry+1 < count) | |
op.op = RETRY; | |
}); | |
} | |
_caught.default = function(fn) { | |
return _caught.on(null, fn); | |
} | |
_caught.async = function() { | |
const _catcher_async = { | |
fn: _ball.fn, | |
async_: true | |
ops: _catcher.ops | |
}; | |
return _catcher(_catcher_async, _catcher.ops); | |
} | |
_caught.encapsulate = function() { | |
return (...args) => _caught(...args); | |
} | |
return _caught; | |
} | |
const pokeball = function(fn) { | |
return _catcher({fn, _make_ll()}); | |
} | |
pokeball.IGNORE = IGNORE; | |
pokeball.BUBBLE = BUBBLE; | |
pokeball.RETRY = RETRY; | |
pokeball.default = pokeball; | |
// Example: | |
// let p = pokeball(() => {throw new Error();}) | |
// .on(SomeSpecialError, (e) => e.valueOf()) | |
// .default((e) => e)) | |
// .except(SomeErrorType); | |
// .retry(3); | |
// .encapsulate(); | |
// p(); | |
module.exports = pokeball; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment