diff --git a/src/core/AdvicePool.ts b/src/core/AdvicePool.ts index f051f377..96c17175 100644 --- a/src/core/AdvicePool.ts +++ b/src/core/AdvicePool.ts @@ -8,5 +8,6 @@ export abstract class AdvicePool { static stopped: boolean static next () {} + static break () {} static stop () {} } diff --git a/src/core/CallStackIterator.ts b/src/core/CallStackIterator.ts index 8cd8e401..affa414c 100644 --- a/src/core/CallStackIterator.ts +++ b/src/core/CallStackIterator.ts @@ -13,6 +13,7 @@ export class CallStackIterator { private index: number = -1 private stopped: boolean = false + private broken: boolean = false /** * {constructor} @@ -34,7 +35,7 @@ export class CallStackIterator { this.index++ // asign currentEntry to the following entry - let currentEntry = this.stack[this.index] + let currentEntry = this.broken ? null : this.stack[this.index] // currentEntry evals to 'null' meaning that the next entry is invoke main method. // but it will be skipped if 'this.stopped' evals to 'true' (this.stop was invoked) @@ -56,7 +57,9 @@ export class CallStackIterator { } } } - this.next() + if (!this.broken) { + this.next() + } } // if currentEntry has a value, it must be an entry/advice descriptor @@ -74,6 +77,20 @@ export class CallStackIterator { this.stopped = true } + /** + * this method will prevent all following advices to be called by + * removing them from call stack queue + */ + private break () { + this.broken = true + } + + /** + * @private executeAdvice + * this method executes de current advice on the current context, if the advice is not + * `asynchronous`, it will call next() on finish. + * @param currentEntry + */ private executeAdvice (currentEntry: IStackEntry) { currentEntry.adviceFn.apply(this, this.transformArguments(currentEntry)) if (!this.isAsync(currentEntry.adviceFn)) { diff --git a/src/interface/IAdviceContext.ts b/src/interface/IAdviceContext.ts index 98b1e2c1..355ae15a 100644 --- a/src/interface/IAdviceContext.ts +++ b/src/interface/IAdviceContext.ts @@ -6,5 +6,6 @@ export interface IAdviceContext { stopped: boolean next (): void + break (): void stop (): void } diff --git a/test/demos/breakCallStack.spec.ts b/test/demos/breakCallStack.spec.ts new file mode 100644 index 00000000..55ba7de1 --- /dev/null +++ b/test/demos/breakCallStack.spec.ts @@ -0,0 +1,21 @@ +import { beforeMethod, afterMethod } from "../../src/kaop-ts" + +class YetAnotherDummyTest { + + static something: number = 1 + + @beforeMethod(function (meta) { this.break() }) + @beforeMethod(function (meta) { meta.target.something++ }) + @beforeMethod(function (meta) { throw new Error(`Shouldn't be called here!!!`) }) + @beforeMethod(function (meta) { meta.target.something++ }) + @afterMethod(function (meta) { throw new Error(`I also shouldn't be called!!!11`) }) + @afterMethod(function (meta) { meta.target.something++ }) + static some () { console.log('hi') } +} + +describe("kaop-ts demo -> break call stack if needed", () => { + it("advices can determine if the following call stack must be break apart", () => { + YetAnotherDummyTest.some() + expect(YetAnotherDummyTest.something).toBeLessThan(2) + }) +})