Aspect Oriented Programming based on decorators, for browser & node
npm install @aspectjs/core[![ci-status]](https://gitlab.com/aspectjs/aspectjs)
[![coverage report]](https://gitlab.com/aspectjs/aspectjs/-/commits/main)
[![npm version]](https://www.npmjs.com/package/@aspectjs/core)
[![license]](https://www.npmjs.com/package/@aspectjs/core)
[![NPM Downloads]](https://www.npmjs.com/package/@aspectjs/core)
[![bundlejs]](https://bundlejs.com/?q=%40aspectjs%2Fcommon%2C%40aspectjs%2Fcore&treeshake=[]%2C[])
[![Latest Release]](https://gitlab.com/aspectjs/aspectjs/-/releases)
Inspired by the AspectJ java framework,
AspectJS leverages ES Decorators to bring
Aspect Oriented Programming to Javascript and Typescript.
![example]
Demo on stackedit.
ECMAScript Decorators are fantastic: they allow developers to hide boilerplate code behind a simple @ sign, keeping the code clean, easy to read, and easy to write. Widely used in popular projects such as Angular, Nest.js or TypeORM, decorators have one major drawback: they come with their own built-in behavior, making interoperability between tools difficult, and preventing them from being repurposed for other uses.
_AspectJS_ takes a different approach, by introducing two important concepts: Annotations and Aspects.
- An _Annotation_ is essentially an empty decorator that marks a target (_class_, _property_, _method_ or _parameter_) as a candidate for further enhancements.
- Aspects can be selectively enabled to introduce new behaviors into the annotated elements.
``ts`
const A = function( target: Function) {
// behaviorA
}
const B = function( target: Function) {
// behaviorB
}
@A()
@B()
class MyClass {}
`ts
const af = new AnnotationFactory('my.org')
const A = af.create('A');
const B = af.create('B');
@A()
@B()
class MyClass {}
@Aspect()
class AB_Aspect {
// behavior A
// behavior B
}
getWeaver().enable(new AB_Aspect())
`
- Install the packages
`bash`
npm i @aspectjs/core @aspectjs/common
- Create an annotation:
`ts
// toasted.annotation.ts
import { AnnotationFactory, AnnotationKind } from '@aspectjs/common';
const ANNOTATION_FACTORY = new AnnotationFactory('demo');
const Toasted = ANNOTATION_FACTORY.create(
AnnotationKind.METHOD,
'Toasted',
function Toasted() {},
);
`
- Use that annotation on a class, a property, a method or a parameter:
`ts`
// main.ts
class Main {
@Toasted()
run() {
console.log('run');
}
}
`
- Declare an aspect triggered by the annotation:
ts${ctxt.target.label} completed successfully
// toasted.aspect.ts
import { Around, AroundContext, Aspect, JoinPoint, on } from '@aspectjs/core';
@Aspect()
class ToastedAspect {
@Around(on.methods.withAnnotations(Toasted))
toast(ctxt: AroundContext, jp: JoinPoint, jpArgs: unknown[]) {
const result = jp(...jpArgs);
const text = ;`
showToast(text);
return result;
}
}
- Enable the aspect
`ts
// aop.ts
import { getWeaver } from '@aspectjs/core';
getWeaver().enable(new ToastedAspect());
``
For more advanced usage, please read the documentation: https://aspectjs.gitlab.io/.
MIT Licensed
[coverage report]: https://gitlab.com/aspectjs/aspectjs/badges/main/coverage.svg?job=coverage
[ci-status]: https://gitlab.com/aspectjs/aspectjs/badges/main/pipeline.svg
[Latest Release]: https://gitlab.com/aspectjs/aspectjs/-/badges/release.svg
[npm version]: https://img.shields.io/npm/v/@aspectjs/core.svg
[license]: https://img.shields.io/npm/l/@aspectjs/core.svg
[NPM Downloads]: https://img.shields.io/npm/dm/@aspectjs/common.svg
[bundlejs]: https://deno.bundlejs.com/badge?q=@aspectjs/common,@aspectjs/core&treeshake=[],[]
[example]: ./.assets/aspectjs-example.png