Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

to-aop

mjancarik13.6kISC0.5.5

AOP(aspect-oriented programming) library or creating hooks for debug and monkey patch function using ES6 Proxy|Class Prototype.

hook, aop, aspect, advice, debug, monkey-patch, pointcut, join-point, aspect-oriented-programming, javascript, ES6, Proxy

readme

to-aop

Coverage Status NPM package version code style: prettier

The to-aop module help you with applying Aspect Oriented Programming to JavaScript. It use under the hood ES Proxy for object same as other similar modules. It allow you hook class without creating new instance as well. It use javascript prototype for that.

For example I am using it for adding hooks to production code where all debug code is missing. I don't have got access to instance but I have only class constructor. But usage is unlimited.

More articles about AOP:

  1. https://blog.mgechev.com/2015/07/29/aspect-oriented-programming-javascript-aop-js/
  2. https://hackernoon.com/aspect-oriented-programming-in-javascript-es5-typescript-d751dda576d0

Examples:

  1. https://github.com/mjancarik/shallow-with-context/blob/master/src/shallowWithContext.js
  2. https://github.com/seznam/ima/blob/master/packages/devtools/src/services/defaultSettings.json

Installation

npm i to-aop --save

Usage

Easy example for native Date.now method.

import { aop, hookName, createHook } from 'to-aop';

const nowHook = createHook(hookName.aroundMethod, 'now', (args) => {
    return 1;
});

aop(Date, nowHook);

Date.now() // returns 1

Other example with more hooks for your defined class.

// a.js
export default class A {
  constructor(variable) {
    this.variable = variable;
  }

  method() {
    return this.variable;
  }

  notHookedMethod() {
    return 'not hook';
  }    
}

Applying AOP to class

You can use it for creating hook to your favorite framework or your own application without modification source code.

import { aop, hookName, createHook, unAop } from 'to-aop';
import A from './a';

const classHookBefore = createHook(
  hookName.beforeMethod,
  /^(method)$/,
  ({ target, object, property, context, args, meta }) => {
    //call your own hook
    meta.startTime = performance.now();
    console.log(
      `Instance of ${target.name} call "${property}"
with arguments ${args && args.length ? args : '[]'}.`
    );
  }
);

const classHookAfter = createHook(
  hookName.afterMethod,
  /^(method)$/,
  ({ target, object, property, context, args, payload, meta }) => {
    //call your own hook
    console.log(
      `Instance of ${target.name} call "${property}"
with arguments ${args && args.length ? args : '[]'}
and return value is "${payload}" took ${performance.now() - meta.startTime}.`
    );
  }
);

const hooks = Object.assign({}, classHookBefore, classHookAfter);

aop(
  A,
  hooks
); // bind hook to class
const a = new A('my hook');

a.method(); // log: 'Instance of A call "method" with arguments [] and return value is "my hook".', returns: 'my hook'
a.notHookedClassMethod(); // returns: 'not hook'

unAop(A);
a.method(); // returns: 'my hook'
a.notHookedClassMethod(); // returns: 'not hook'

Applying AOP to instance or object

import { aop, hookName, createHook, unAop } from 'to-aop';
import A from './a';

const instanceHook = createHook(
  hookName.afterMethod,
  /^(method)$/,
  ({ target, object, property, context, args, payload, meta }) => {
    console.log(
      `Instance of ${object.constructor.name} call "${property}"
with arguments ${args && args.length ? args : '[]'}
and return value is "${payload}".`
    );
  }
);

const a = new A('my hook');
const hookedInstance = aop(a, instanceHook); // bind hook to instance

hookedInstance.method(); // log: 'Instance of A call "method" with arguments [] and return value is "my hook.', returns: 'my hook'
hookedInstance.notHookedClassMethod(); // returns: 'not hook'

unAop(a);
a.method(); // returns: 'my hook'
a.notHookedClassMethod(); // returns: 'not hook'

Documentation

createHook(hookName, regular, callbackHook)

  • (string) hookName - set of hooks
  • (string, regexp, Array, function) regular - condition for filtering
  • (function) callbackHook - your defined action

aop(target, pattern, settings)

  • (class, object) - target for hooks
  • (Object<string, Array<function>>) - pattern of hooks
  • {Object} settings
  • {booelan} [settings.constructor=false] - allow hook class constructor

unAop(target)

  • (class, object) - target for hooks

Hooks API

We implemented base set of hooks which you can use for AOP.

  1. beforeMethod
  2. afterMethod
  3. aroundMethod
  4. beforeGetter
  5. afterGetter
  6. aroundGetter
  7. beforeSetter
  8. afterSetter
  9. aroundSetter
import { hookName } from 'to-aop';

// hookName.(beforeMethod|afterMethod|...)

changelog

0.5.5 (2024-08-29)

0.5.4 (2021-10-06)

Bug Fixes

  • error property of undefined (62beec3)

Features

  • console: turn off console warnings for static getters (f59fce4)

0.5.3 (2021-08-18)

Bug Fixes

  • unaop: fixed reinitialization of aop hook after it was cleared by unaop (#3) (5fccd3c)

0.5.2 (2021-03-27)

Features

  • aop: added support for hooking constructor (6fc48c7)

0.5.1 (2020-12-05)

Features

0.5.0 (2020-10-04)

Features

  • aroundmethod: call only last aroundMethod hook (bcf42f9)
  • trap: added new meta property to argument for all trap (fa9d314)

0.4.1 (2020-09-19)

Bug Fixes

  • added js file extension to dist (799f63c)

0.4.0 (2020-09-16)

Features

  • aroundmethod: call all defined aroundMethod hooks (5d5f4c8)

0.3.6 (2020-07-29)

Features

  • static: static methods, getters and setters are hooked only for defined names (a6881fb)

0.3.5 (2020-07-23)

Features

  • aroundmethod: added original method to meta for arround hook (f83eae1)

0.3.4 (2020-03-18)

0.3.3 (2020-02-28)

Bug Fixes

  • class: returnig value from static getter is not modified (100295d)

0.3.2 (2020-01-05)

Bug Fixes

  • static methods, getters and setters not throw error during hooking (911216d)

0.3.1 (2019-12-16)

Bug Fixes

  • returning value from static getter (2189021)

0.3.0 (2019-12-09)

Features

  • static: added support for static getter, setter and method (d94583a)

0.2.1 (2019-08-29)

Bug Fixes

  • trap: must keep context of called method (f88f26f)

0.2.0 (2019-08-11)

Bug Fixes

  • trap: createCallTrap works for global object console (78d7de8)

0.1.3 (2019-07-12)

Bug Fixes

  • aop: builtin Object hasOwnProperty call (fd2b69a)

0.1.2 (2019-05-19)

0.1.1 (2019-04-26)

0.1.0 (2019-04-23)

0.0.11 (2019-04-18)

Bug Fixes

  • constructable: fixed detection of constructable function (d68389c)

0.0.10 (2019-04-18)

Bug Fixes

  • aop: cunstructable function is not hook for static getter (c40c7b0)

0.0.9 (2019-04-09)

Bug Fixes

  • hook: added missing hooks name for setter (2a652f6)

Features

  • class: added aop to class static method (937873d)

0.0.8 (2018-12-14)

Features

  • main: to-aop exports hookName and all traps (195fcf5)

0.0.7 (2018-12-08)

Bug Fixes

  • instance: fixing aop for instance which use proxy (c28aeb7)

0.0.6 (2018-10-12)

Features

  • aop: the method may be called more times for class (5922d14)

0.0.5 (2018-08-30)

Features

  • class: allow hook traspiled ES6 class to es5 (9d5774e)

0.0.4 (2018-08-02)

Bug Fixes

  • file: fix case sensitive for file structure (8662df2)

0.0.3 (2018-08-02)

Features

  • hook: added new exported method createHook and hookFor (5bc390c)

BREAKING CHANGES

  • hook: Method createPattern was renamed to createAspect. The arguments order was changed in aop method.

0.0.2 (2018-07-27)

Features