Skip to content

Instantly share code, notes, and snippets.

@unscriptable
Created March 3, 2016 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save unscriptable/0d5f5a157f3dd9a06021 to your computer and use it in GitHub Desktop.
Save unscriptable/0d5f5a157f3dd9a06021 to your computer and use it in GitHub Desktop.
'use strict';
/*@flow*/
// TODO: parameterize by argument type when flow supports it:
// type Func<A,R> = (...args:A) => R
// type Adviser<F:Func<A,R>> = (x:F) => F
// export type TraceAdvice<A,R> = (args:A, result:R) => mixed
type Func<R> = () => R
type Adviser<F:Function> = (x:F) => F
export type TraceAdvice<R>
= (args:Array<mixed>, result:R) => mixed
& (args:Array<mixed>, result:void, error:Error) => mixed
export type BeforeAdvice = (args:Array<mixed>) => mixed
export type AfterAdvice<R> = (result:R) => mixed
export type OnAdviceError = (e:Error) => mixed
// Execute a side-effect before a function.
export const before
: (advice:BeforeAdvice, onError:OnAdviceError) => Adviser
= (advice, onError = logErrorToConsole) => {
const safeAdvice = _captureError(onError, advice)
return _before(safeAdvice)
}
// Execute a side-effect after a function.
export const after
: (advice:AfterAdvice, onError:OnAdviceError) => Adviser
= (advice, onError = logErrorToConsole) => {
const safeAdvice = _captureError(onError, advice)
return _after(safeAdvice)
}
// Call a function to record the arguments and result of a function.
// If the function throws, the Error is sent as the third parameter.
export const trace
: (advice:TraceAdvice, onError:OnAdviceError) => Adviser
= (advice, onError = logErrorToConsole) => {
const safeAdvice = _captureError(onError, advice)
return _trace(safeAdvice)
}
// A Collection of advise functions.
export type Advice = {
before (advice:BeforeAdvice, onError:OnAdviceError): Adviser,
after (advice:AfterAdvice, onError:OnAdviceError): Adviser,
trace (advice:TraceAdvice, onError:OnAdviceError): Adviser
}
// Creates a collection of similarly-defaulted advice functions.
const advice
: (defaultError:OnAdviceError) => Advice
= (defaultError) => {
return {
before: (advice, onError = defaultError) => _before(advice, onError),
after: (advice, onError = defaultError) => _after(advice, onError),
trace: (advice, onError = defaultError) => _trace(advice, onError)
}
}
export default advice
export const logErrorToConsole
: OnAdviceError
= (e) => { console.log(e) }
export const squelchError
: OnAdviceError
= (e) => {}
// --------------- Exported for testing ---------------
export const _before
: (advice:BeforeAdvice) => Adviser
= (advice) => (f) => (...args) => {
advice(...args)
return f(...args)
}
export const _after
: (advice:AfterAdvice) => Adviser
= (advice) => (f) => (...args) => {
const result = f(...args)
advice(result)
return result
}
export const _trace
: (record:TraceAdvice) => Adviser
= (record) => (f) => (...args) => {
let result
try {
result = f(...args)
}
catch (err) {
record(args, undefined, err)
throw err
}
record(args, result)
return result
}
// TODO: Increase the type safety of this function
export const _captureError
: (onError:OnAdviceError, advice:Function) => Function
= (onError, advice) => (...args) => {
try {
advice(...args)
}
catch (err) {
onError(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment