All Projects → dboikliev → AspecTS

dboikliev / AspecTS

Licence: other
An aspect-oriented programming library implemented in TypeScript

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to AspecTS

CNeptune
CNeptune improve productivity & efficiency by urbanize .net module with meta-code to lay foundation for frameworks
Stars: ✭ 30 (+42.86%)
Mutual labels:  aop, aspect-oriented-programming, cross-cutting-concerns
Aspect4Delphi
Concepts of aspect-oriented programming (AOP) in Delphi.
Stars: ✭ 28 (+33.33%)
Mutual labels:  aop, aspect-oriented-programming, aspects
NCop
Composite-aspect oriented framework for .NET
Stars: ✭ 30 (+42.86%)
Mutual labels:  aspect, aop, aspect-oriented-programming
controller-logger
AOP based API logging for Spring Boot
Stars: ✭ 57 (+171.43%)
Mutual labels:  aop, aspects
aspectgo
Aspect-Oriented Programming framework for Go
Stars: ✭ 62 (+195.24%)
Mutual labels:  aop, aspect-oriented-programming
goaop-laravel-bridge
Integration bridge for Go! AOP framework and Laravel
Stars: ✭ 91 (+333.33%)
Mutual labels:  aop, aspect-oriented-programming
Norns
dotnet core aop static weaving on roslyn
Stars: ✭ 23 (+9.52%)
Mutual labels:  aspect, aop
Beike AspectD
Flutter AOP framework.(Flutter面向切面库, 最新适配Flutter v2.5.3, null-safety)
Stars: ✭ 39 (+85.71%)
Mutual labels:  aspect, aop
kaop
Advanced OOP Library with createClass, inheritance, providers, injectors, advices which enables handy Inversion of Control techniques
Stars: ✭ 40 (+90.48%)
Mutual labels:  aspect-oriented-programming, aop-aspects
aspecio
Aspecio, AOP Proxies for OSGi services
Stars: ✭ 14 (-33.33%)
Mutual labels:  aspects, cross-cutting-concerns
Cauldron
C# Toolkit
Stars: ✭ 68 (+223.81%)
Mutual labels:  aspect, aop
KYHooker
A library for complex aspect oriented programming
Stars: ✭ 38 (+80.95%)
Mutual labels:  aspect-oriented-programming, aspects
Decor.NET
A simple way to decorate a class with additional functionality using attributes.
Stars: ✭ 29 (+38.1%)
Mutual labels:  aop, aspect-oriented-programming
Mimick.Fody
An integrated framework for dependency injection and aspect-oriented processing.
Stars: ✭ 15 (-28.57%)
Mutual labels:  aop, aspect-oriented-programming
Online-Testing-Platform
在线考试系统 colleges online examination system base on spring-boot and MyBatis
Stars: ✭ 21 (+0%)
Mutual labels:  aop
java-springboot
(Java & React) Yazılım Geliştirici Yetiştirme Kampı Java kısmına ait yazılan kaynak kodlar ve ödev çalışmalarım.
Stars: ✭ 17 (-19.05%)
Mutual labels:  aop
cachex
CacheX注解缓存框架
Stars: ✭ 39 (+85.71%)
Mutual labels:  aop
fastaop
🚀 lightweight, high-performance AOP framework based on Java Annotation Processing, similar to Lombok
Stars: ✭ 87 (+314.29%)
Mutual labels:  aop
RuntimeNullables
Automatic null check injection for runtime C# 8+ Nullable Reference Type (NRT) contract validation.
Stars: ✭ 24 (+14.29%)
Mutual labels:  aop
monogram
Aspect-oriented layer on top of the MongoDB Node.js driver
Stars: ✭ 76 (+261.9%)
Mutual labels:  aspect-oriented-programming

AspecTS

Build Status

An aspect-oriented programming library implemented in TypeScript

Supported aspects:

Basic aspects:

Advanced aspects:

Supported targets:

The aspects can be applied on methods or on the class itself. When applied on a class the aspect is applied on all instance and static members and accessors and on the constructor. It is possible to choose only specific members using the Target enum.

  • Instance methods
  • Static methods
  • Instance accessors
  • Static accessors
  • Constructor

Basic Aspects Examples:

BoundaryAspect:

The BoundaryAspect class provides method for intercepting the places of entry and exit of functions. Classes inheriting from BoundaryAspect can provide custom iplementations to onEntry and/or onExit. onEntry recieves the decorated function's arguments. Its return value is passed as argument(s) to the decorated function. onExit reieves the decorated function's return value. Its return value will be returned to the caller of the decorated method. This aspect is most suitable when you want to perform some action specifically on function entry and/or exit.

import { aspect, BoundaryAspect } from "./aspect";

class TestBoundaryAspect extends BoundaryAspect {
    onEntry(...args) {
        console.log("On Entry.");
        args[0] = 10;
        return args;
    }

    onExit(returnValue) {
        console.log("On Exit.");
        return returnValue + 5;
    }
}

class Test {
    @aspect(new TestBoundaryAspect())
    doSomething(argument) {
        console.log("In doSomething.");
        console.log(argument)
        return "doSomething's result.";
    }
}

let test = new Test();
console.log(test.doSomething(1));

Output:

On Entry.
In doSomething.
10
On Exit.
doSomething's result.5

SurroundAspect:

The SurroundAspect class provides a method for intercepting a function invocation. onInvoke function recieves as paramerameter the decorated function and returns a new function. This aspect is most suitable for cases where you want to place code around the method, hence the name.

import { aspect, SurroundAspect } from "./aspect";

class TestSurroundAspect extends SurroundAspect {
    onInvoke(func) {
        return function(...args) {
            console.log("You've been");
            let returnValue = func.apply(this, args);
            console.log("surrounded.");
            return returnValue;
        };
    }
}

class Test {
    @aspect(new TestSurroundAspect())
    doSomething(argument) {
        console.log("In doSomething.");
        return "doSomething's result.";
    }
}

let test = new Test();
console.log(test.doSomething(1));

Output:

You've been
In doSomething.
surrounded.
doSomething's result.

ErrorAspect:

The ErrorAspect provides an onError function which is called when the decorated function throws an error. onError receives as argument the caught object which the decorated function has thrown. This aspect is suitable for implementing loggers and error handlers.

import { aspect, ErrorAspect } from "./aspect";

class TestErrorAspect extends ErrorAspect {
    onError(error) {
        console.log("LOGGED ERROR: " + (error.message ? error.message : error));
    }
}

class Test {
    @aspect(new TestErrorAspect())
    doSomething() {
        throw Error("Something went wrong while doing something.");
    }
}

let test = new Test();
test.doSomething();

Output:

LOGGED ERROR: Something went wrong while doing something.

Aspect mixins:

The surround, boundary, error methods allow the creation of a new aspect by combining joint points of SurroundAspect, BoundaryAspect and ErrorAspect.

import {
    aspect,
    ErrorAspect,
    BoundaryAspect,
    Target,
    surround,
    boundary,
    error
} from "./aspect";

class BaseLogger {
    protected _logger: { log: (...args: any[]) => void };

    constructor() {
        this._logger = console;
    }
}

class LoggerAspect extends error(surround(boundary(BaseLogger))) {
    onError(e: Error) {
        this._logger.log("ERROR: " + e.message);
    }

    onEntry(...args) {
        this._logger.log("ENTRY: " + args);
        return args;
    }

    onExit(returnValue) {
        this._logger.log("EXIT: " + returnValue);
        return returnValue;
    }

    onInvoke(func: Function) {
        let logger = this._logger;
        return function (...args) {
            logger.log("INVOKE BEGIN");
            let result = func.apply(this, args);
            logger.log("INVOKE END");
            return result;
        };
    }
}


@aspect(new LoggerAspect(), Target.All ^ Target.Constructor)
class TestClass {
    private _testField: number;
    private static _testStaticField: number;

    get instanceAccessor() {
        return this._testField;
    }

    set instanceAccessor(value) {
        this._testField = value;
    }

    instanceMethod(testParameter: number) {
        throw Error("Test error.");
        return testParameter;
    }

    static staticMethod(testParameter: number) {
        return testParameter;
    }

    static get staticAccessor() {
        return this._testStaticField;
    }

    static set staticAccessor(value) {
        this._testStaticField = value;
    }
}


let instance = new TestClass();
instance.instanceMethod(1);
console.log("-".repeat(20));
TestClass.staticMethod(1);

Output:

INVOKE BEGIN
ENTRY: 1
ERROR: Test error.
--------------------
INVOKE BEGIN
ENTRY: 1
EXIT: 1
INVOKE END

Target:

Target is a bit flags enum which contains the possible targets for an aspect. Targets can be combined with the bitwise-or operator ( | ).

@aspect(new TestBoundary(), 
    Target.InstanceAccessors | 
    Target.InstanceMethods | 
    Target.StaticMethods | 
    Target.StaticAccessors)
class TestClass {
    private _testField: number;
    private static _testStaticField: number;

    get instanceAccessor() {
        return this._testField;
    }

    set instanceAccessor(value) {
        this._testField = value;
    }

    instanceMethod(testParameter: number) {
        return testParameter;
    }

    static staticMethod(testParameter: number) {
        return testParameter;
    }

    static get staticField() {
        return this._testStaticField;
    }

    static set staticField(value) {
        this._testStaticField = value;
    }
}

Advanced Aspects Examples:

You can use the basic types of aspects to build more complex solutions like caching, logging etc.

Caching:

The cache and invalidateCache functions are supposed to be used on methods. Both functions expenct and instance of a caching service - the cache wich will hold the data. The cache functions also exptects a keyIndex - the index of the method argument which will be used as a key in the cache and an optional period parameter - the time in milliseconds after which the cache will expire. Calling a method marked with the invalidateCache decorator will cause the cache at the specified index to be removed.

Example:

import { cache, invalidateCache, MemoryCache } from "./caching"

const cachingService = new MemoryCache<User>();

class UserService {
    @cache(cachingService, 0, 1000)
    getUserById(id: number): User {
        console.log("In get user by id");
        return {
            name: "Ivan",
            age: 21
        }
    }

    @invalidateCache(cachingService, 0)
    setUserById(id: number, user: User) {
        
    }
}

interface User {
    name: string,
    age: number
}

const us = new UserService()
const first = us.getUserById(1)

us.setUserById(1, {
    name: "bla",
    age: 23
})

const second = us.getUserById(1);
console.log(first == second) //false - cache was invalidated by set method

const third = us.getUserById(1);
console.log(second == third) //true - result was cached during previous call 

setTimeout(() => {
    const fourth = us.getUserById(1)
    console.log(third == fourth) //false - cache expired
}, 2000)

Repeating:

The repeatOnError aspect allows code to be executed a maximumg of count times with delays between calls of interval milliseconds. The repeater can be set to block until all repetitions are over by setting the wait parameter to true.

Example:

import { cache, invalidateCache, MemoryCache } from "./cache"
import { repeatOnError } from "./repeat";

const cachingService = new MemoryCache<User>();

class UserService {
    private count: number = 3;

    @cache(cachingService, 0, 1000)
    @repeatOnError(5, 100, true)    
    getUserById(id: number): User {
        console.log("In get user by id");
        if (this.count > 0) {
            this.count--;
            throw Error("Err");
        }

        return {
            name: "Ivan",
            age: 21
        };
    }
}

interface User {
    name: string,
    age: number
}

const us = new UserService()

let user = us.getUserById(1)
let cached = us.getUserById(1)

console.log(user)
console.log("Is cached: ", user == cached) 

Output:

In get user by id
In get user by id
In get user by id
In get user by id

Object {name: "Ivan", age: 21}
Is cached:  true
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].