@beforeInstance(meta => {
// stuff
})
const myCustomAdvice = beforeInstance(meta => {
// stuff
})
@myCustomAdvice
const myCustomAdvice = (...args) => beforeInstance(meta => {
// stuff
})
@myCustomAdvice(arg0, arg1)
const myCustomAdvice = beforeMethod<MyComponent, 'ngOnInit'>(function() {
// stuff
})
@myCustomAdvice // can only be used at MyComponent::ngOnInit
@beforeInstance(function(meta) {
meta.args // Arguments to be received by decorated method
meta.key // Name of the decorated method as string
meta.scope // Instance or the context of the call stack
meta.method // Original method
meta.target // Class definition
meta.result // The returned value by the method
meta.prevented // The main method was not executed, prevent() was called
meta.exception // current exception (if any). The exception should be handled
// using `meta.handle()` to avoid error to be thrown.
meta.commit() // triggers the next advice or method in the
// call stack (mandatory if your advice contains async operations)
// if arguments are provided then it will be pushed to meta.args as kaop/issues/12
meta.skip() // prevent execution of following advices until method execution
meta.handle() // returns the exception (if any) and prevents to be thrown.
meta.prevent() // prevents the main method to be executed (GUESS WHY).
})
Join points allow you to plug Advices into parts of your code.
@afterMethod // `method`. Accepts <B = any, K extends keyof B = any>
@beforeMethod // `method`. Accepts <B = any, K extends keyof B = any>
@onException // `method`. Built on top afterMethod. Accepts <B = any>
@afterInstance // `class`. Accepts <B = any>
@beforeInstance // `class`. Accepts <B = any>
Join points provide two generic placeholder to enhace strong typings. Check out angular 2 example:
- Advices plugged in the same callstack share arguments and result
- Advices plugged in static methods share its static context
- Advices plugged in non static methods share static and instance context
An Advice have access to the original method/instance by accessing its metadata. But Advices can be parametrized too:
const log = (path, num) => afterMethod(meta => {
path // "log/file/path"
num // 31
})
class Person {
// passed through join point
@log('log/file/path', 31)
getAge() { ... }
}
You can place many join points, they'll be executed sequentially, from top to bottom.
class Component {
...
@beforeMethod(YourHttpService.getCached, '/url/to/html')
@beforeMethod(YourHtmlParser.template)
invalidate (parsedHtml?: any) {
this.element.append(parsedHtml)
}
}
You have control over this call stack, for example you can also create Async Advices.
Note: you might find an IMetadata was not found in 'kaop-ts'
issue. See Troubleshooting section for more info.
By default, advices are synchronous, unless you use meta.commit()
in your code. Then it is asynchronous and the flow will not continue until meta.commit()
is called.
const fetch = meta => {
...
meta.commit() // It must be called and reachable, otherwise the flow hangs
}
const transform = meta => {
...
const [ result, ...args ] = meta.args
// applying some transformation to first argument received by the decorated method
meta.args = [transformParams(result), ...args ]
}
The following example uses 2 Advices: the first one is asynchronous, while the second not. The second one needs to be called right after fetch
has finished:
// view.ts
import { beforeMethod } from 'kaop-ts'
class View {
@beforeMethod(fetch, transform)
setPermission () { ... }
}