Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mgechev/aspect.js
JavaScript library for aspect-oriented programming using modern syntax.
https://github.com/mgechev/aspect.js
aspect-oriented-programming decorators javascript
Last synced: 11 days ago
JSON representation
JavaScript library for aspect-oriented programming using modern syntax.
- Host: GitHub
- URL: https://github.com/mgechev/aspect.js
- Owner: mgechev
- License: mit
- Created: 2015-04-18T10:40:38.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2021-05-10T19:24:40.000Z (over 3 years ago)
- Last Synced: 2024-04-26T04:35:13.434Z (7 months ago)
- Topics: aspect-oriented-programming, decorators, javascript
- Language: TypeScript
- Homepage:
- Size: 2.11 MB
- Stars: 473
- Watchers: 24
- Forks: 37
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Introduction
[![Build Status](https://travis-ci.org/mgechev/aspect.js.svg?branch=master)](https://travis-ci.org/mgechev/aspect.js)
Library for aspect-oriented programming with JavaScript, which takes advantage of ECMAScript 2016 decorators syntax.
> NOTE: if you are using `aspect.js` in a plain JavaScript project that uses [`@babel/plugin-proposal-decorators`](https://www.npmjs.com/package/@babel/plugin-proposal-decorators), you _must_ set its `legacy` property to `true` until [#72](https://github.com/mgechev/aspect.js/issues/72) is fixed.
See [this migration note](https://babeljs.io/docs/en/v7-migration#babel-plugin-proposal-decorators) for more information.
A sample project using JavaScript with Node >=10.12.0 (or >=8.12.0) & Babel 7.x can be found at https://github.com/matthewadams/aspect.js-babel7-poc.
It's a good way to get going quickly with `aspect.js` in that environment.For further reading on decorators, take a look at [the spec](https://github.com/wycats/javascript-decorators).
Blog post, introduction to the AOP and the library could be found [here](http://blog.mgechev.com/2015/07/29/aspect-oriented-programming-javascript-aop-js).
Talk from [AngularConnect](https://www.youtube.com/watch?v=C6e6-31HD5A).
[![Cutting Angular's Crosscuts](https://github.com/mgechev/aspect.js/blob/master/assets/aspectjs.png?raw=true)](https://www.youtube.com/watch?v=C6e6-31HD5A)
# Sample usage
```ts
import {beforeMethod, Advised, Metadata} from 'aspect.js';class LoggerAspect {
@beforeMethod({
classNamePattern: /^Article/,
methodNamePattern: /^(get|set)/
})
invokeBeforeMethod(meta: Metadata) {
// meta.advisedMetadata == { bar: 42 }
console.log(`Inside of the logger. Called ${meta.className}.${meta.method.name} with args: ${meta.method.args.join(', ')}.`);
}
}class Article {
id: number;
title: string;
content: string;
}@Advised({ bar: 42 })
class ArticleCollection {
articles: Article[] = [];
getArticle(id: number) {
console.log(`Getting article with id: ${id}.`);
return this.articles.filter(a => {
return a.id === id;
}).pop();
}
setArticle(article: Article) {
console.log(`Setting article with id: ${article.id}.`);
this.articles.push(article);
}
}new ArticleCollection().getArticle(1);
// Result:
// Inside of the logger. Called ArticleCollection.getArticle with args: 1.
// Getting article with id: 1.
```In case you're using aspect.js in a browser environment the minifier may break the annotated code because of the performed mangling. In order to handle this problem you can use:
```ts
class LoggerAspect {
@beforeMethod({
classes: [ArticleCollection],
methods: [ArticleCollection.prototype.getArticle, ArticleCollection.prototype.setArticle]
})
invokeBeforeMethod(meta: Metadata) {
// meta.advisedMetadata == { bar: 42 }
console.log(`Inside of the logger. Called ${meta.className}.${meta.method.name} with args: ${meta.method.args.join(', ')}.`);
}
}class ArticleCollection {
getArticle(id: number) {...}
setArticle(article: Article) {...}
}
```In this case you can omit the `@Advised` decorator.
This way, by explicitly listing the classes and methods which should be woven, you can prevent the unwanted effect of mangling.
# Demo
```
git clone https://github.com/mgechev/aop.js --depth 1
npm install -g ts-node
ts-node demo/index.ts
```# API
The library offers the following combinations of advices and join points:
## Method calls
- `beforeMethod(MethodSelector)` - invoked before method call
- `afterMethod(MethodSelector)` - invoked after method call
- `aroundMethod(MethodSelector)` - invoked around method call
- `onThrowOfMethod(MethodSelector)` - invoked on throw of method call
- `asyncOnThrowOfMethod(MethodSelector)` - invoked on throw of async method call## Static method calls
- `beforeStaticMethod(MethodSelector)` - invoked before static method call
- `afterStaticMethod(MethodSelector)` - invoked after static method call
- `aroundStaticMethod(MethodSelector)` - invoked around static method call
- `onThrowOfStaticMethod(MethodSelector)` - invoked on throw of static method call
- `asyncOnThrowOfStaticMethod(MethodSelector)` - invoked on throw of async static method call## Accessors
- `beforeSetter(PropertySelector)` - invoked before setter call
- `afterSetter(PropertySelector)` - invoked after setter call
- `aroundSetter(PropertySelector)` - invoked around setter call
- `onThrowOfSetter(PropertySelector)` - invoked on throw of setter call
- `asyncOnThrowOfSetter(PropertySelector)` - invoked on throw of async setter call
- `beforeGetter(PropertySelector)` - invoked before getter call
- `afterGetter(PropertySelector)` - invoked after getter call
- `aroundGetter(PropertySelector)` - invoked around getter call
- `onThrowOfGetter(PropertySelector)` - invoked on throw of getter call
- `asyncOnThrowOfGetter(PropertySelector)` - invoked on throw of async getter call## `MethodSelector`
```ts
export interface MethodSelector {
classNamePattern?: RegExp;
methodNamePattern?: RegExp;
classes?: Function[];
methods?: Function[];
}
```## `PropertySelector`
```ts
export interface PropertySelector {
classNamePattern?: RegExp;
propertyNamePattern?: RegExp;
classes?: Function[];
properties?: PropertyDescriptor[];
}
```## `Metadata`
```ts
export class Metadata {
public method: MethodMetadata;
public className: string;
public advisedMetadata: any;
}
```## `MethodMetadata`
```ts
export class MethodMetadata {
public proceed: boolean;
public name: string;
public args: any[];
public context: any;
public result: any;
public exception: any;
public invoke: (...args: any[]) => any;
}
```# Diagram
Here's a UML class diagram which shows the relations between the individual abstractions:
[![UML Diagram](https://github.com/mgechev/aspect.js/blob/master/assets/diagram.png?raw=true)](https://github.com/mgechev/aspect.js/blob/master/assets/diagram.png?raw=true)
# Roadmap
- [x] Tests
- [x] Type annotations and DTS generation
- [x] Aspect factories
- [x] Generic aspects
- [x] Implement the following advices:
- [x] Before
- [x] After
- [x] Throwing
- [x] Returning
- [x] Around
- [x] Implement the following join points:
- [x] Method execution
- [x] Static method execution
- [x] Filed get
- [x] Field set# License
MIT