ts-advice
TypeScript icon, indicating that this package has built-in type declarations

0.9.7 • Public • Published

Aspect Oriented Programming

Getting started

At first create a managed class using the @Managed() decorator.

@Managed('Foo')
class ManagedExampleClass {
    a: string = 'aaa'
    b: string

    constructor(b: string = 'b') {
        this.b = b
    }

    getValue(additional: string = '') {
        return this.a + this.b + additional
    }

    upperCased(str: string) {
        return str.toUpperCase()
    }
}

Then create an aspect.

@Aspect
class TestAspect {
  	protected prefix = 'from_cache'
  	protected cache = new Map<string, any>()
  
    @Before(test, '->getValue()')
    beforeGetValue(jointPoint: BeforeJointPoint) {
        jointPoint.setArguments(['set from before'])
    }

    @After(ManagedExampleClass, '->getValue()')
    afterGetValue(jointPoint: AfterJointPoint) {
        return jointPoint.getLastReturn().toUpperCase()
    }

    @Around('Foo->upperCased()')
    cache(jointPoint: AroundJointPoint) {
        const id = jointPoint.getArguments().join('_')
        if (this.cache.has(id)) {
            return jointPoint.break(this.prefix + ':' + this.cache.get(id))
        }
        const ret = jointPoint.proceed()
        this.cache.set(id, ret)
        return ret
    }
}

Using the ManagedClass

// @Managed('Foo')
// class ManagedExampleClass { ... }

const test = new ManagedExampleClass('ccc')

// class TestAspect { ... }

console.log(test.getValue('ddd'))     // prints: AAACCCSET FROM BEFORE
console.log(test.upperCased('asdf'))  // prints: ASDF
console.log(test.upperCased('asdfa')) // prints: ASDFA
console.log(test.upperCased('asdf'))  // prints: from_cache:ASDF

Managed Classes

Aspects can only be applied to @Managed(entryIdentifier?: string) classes. The optional entryIdentifier is used to assign a unique name to a class. If no entryIdentifier is provided the class name gets used.

Example

@Managed('Foo')
class ManagedClass {
    a: string = 'aaa'
    b: string

    constructor(b: string = 'b') {
        this.b = b
    }

    getValue(additional: string = '') {
        return this.a + this.b + additional
    }

    upperCased(a: string) {
        return a.toUpperCase()
    }
}

Aspect

Expressions

It is possible to declare an Aspect in three different ways.

Using an instance of a managed class:

@Before(instanceOfManagedExampleClass, '->getValue()')

Using the managed class itself:

@Before(ManagedExampleClass, '->getValue()')

Using the identifier defined with the @Managed('Foo') annotation or the Classname if no identifier is provided

// @Managed('Foo')
// class ManagedExampleClass { }
// ...
@Before('Foo->getValue()')
// @Managed()
// class ManagedExampleClass { }
// ...
@Before('ManagedExampleClass->getValue()')

JointPoints

BeforeJointPoint

AfterJointPoint

AroundJointPoint

Package Sidebar

Install

npm i ts-advice

Weekly Downloads

5

Version

0.9.7

License

AGPL-3.0-or-later

Unpacked Size

63.5 kB

Total Files

25

Last publish

Collaborators

  • sjs-one