/inversify-vanillajs-helpers

Some helpers for the development of InversifyJS applications with VanillaJS or Babel

Primary LanguageTypeScriptMIT LicenseMIT

inversify-vanillajs-helpers

Join the chat at https://gitter.im/inversify/inversify-vanillajs-helpers Build Status Test Coverage npm version Dependencies img img Known Vulnerabilities

NPM NPM

Some helper for the development of InversifyJS applications with VanillaJS

Installation

$ npm install inversify-vanillajs-helpers

Usage

import { helpers } from "inversify-vanillajs-helpers";
var helpers = require("inversify-vanillajs-helpers").helpers;

Annotation helper

Helps you to reduce annotation boilerplate when working with VanillaJS so instead of writting:

inversify.decorate(inversify.injectable(), Ninja);
inversify.decorate(inversify.inject(TYPES.Katana), Ninja, 0);
inversify.decorate(inversify.inject(TYPES.Shuriken), Ninja, 1);

You can just write:

helpers.annotate(Ninja, [TYPES.Katana, TYPES.Shuriken]);

Let's take a look to an example:

var inversify = require("inversify");
var helpers = require("inversify-vanillajs-helpers").helpers;
require("reflect-metadata");

var TYPES = {
  Ninja: 'Ninja',
  Katana: 'Katana',
  Shuriken: 'Shuriken'
}

class Katana {
  hit () {
    return 'cut!'
  }
}

helpers.annotate(Katana);

class Shuriken {
  throw () {
    return 'hit!'
  }
}

helpers.annotate(Shuriken);

class Ninja {

  constructor(katana, shuriken) {
      this._katana = katana;
      this._shuriken = shuriken;
  }

  fight () { return this._katana.hit() }
  sneak () { return this._shuriken.throw() }

}

helpers.annotate(Ninja, [TYPES.Katana, TYPES.Shuriken]);

// Declare bindings
var container = new inversify.Container()
container.bind(TYPES.Ninja).to(Ninja);
container.bind(TYPES.Katana).to(Katana);
container.bind(TYPES.Shuriken).to(Shuriken);

// Resolve dependencies
var ninja = container.get(TYPES.Ninja);
console.log(ninja.fight(), ninja.sneak());

Named annotations

It is also possible to declare named metadata using the annotation helper:

helpers.annotate(
    Ninja,
    [
        { type: TYPES.Katana, named: "not-throwable" },
        { type: TYPES.Shuriken, named: "throwable" }
    ]
);

Tagged annotations

It is also possible to declare tagged metadata using the annotation helper:

helpers.annotate(
    Ninja,
    [
        { type: TYPES.Katana, tagged: { key: "throwable", value: false } },
        { type: TYPES.Shuriken, tagged: { key: "throwable", value: true } }
    ]
);

Registration helper

Helps you to reduce annotation and registration boilerplate when working with VanillaJS so instead of writting:

inversify.decorate(inversify.injectable(), Ninja);
inversify.decorate(inversify.inject(TYPES.Katana), Ninja, 0);
inversify.decorate(inversify.inject(TYPES.Shuriken), Ninja, 1);
container.bind(TYPES.Ninja).to(Ninja);

You can just write:

let register = helpers.register(container);
register(TYPES.Ninja, [TYPES.Katana, TYPES.Shuriken])(Ninja);

This helper can also be used as a class decorator when using Babel (continue reading for more details):

let register = helpers.register(container);

@register(TYPES.Ninja, [TYPES.Katana, TYPES.Shuriken])
class Ninja {

  constructor(katana, shuriken) {
      this._katana = katana;
      this._shuriken = shuriken;
  }

  fight () { return this._katana.hit() }
  sneak () { return this._shuriken.throw() }

}

Let's take a look to an example:

var inversify = require("inversify");
var helpers =  require("inversify-vanillajs-helpers").helpers;
require("reflect-metadata");

var TYPES = {
  Ninja: 'Ninja',
  Katana: 'Katana',
  Shuriken: 'Shuriken'
}

class Katana {
  hit () {
    return 'cut!'
  }
}

class Shuriken {
  throw () {
    return 'hit!'
  }
}

class Ninja {

  constructor(katana, shuriken) {
      this._katana = katana;
      this._shuriken = shuriken;
  }

  fight () { return this._katana.hit() }
  sneak () { return this._shuriken.throw() }

}

// Declare bindings
var container = new inversify.Container();
var register = helpers.register(container);
register(TYPES.Katana)(Katana);
register(TYPES.Shuriken)(Shuriken);
register(TYPES.Ninja, [TYPES.Katana, TYPES.Shuriken])(Ninja);

// Resolve dependencies
var ninja = container.get(TYPES.Ninja);
console.log(ninja.fight(), ninja.sneak());

We can use the helpers to register many types of bindings.

registerSelf

var registerSelf = helpers.registerSelf(container);
registerSelf()(Katana);

registerConstantValue

var registerConstantValue = helpers.registerConstantValue(container);
registerConstantValue(TYPES.Katana, new Katana());

registerDynamicValue

var registerDynamicValue = helpers.registerDynamicValue(container);
registerDynamicValue(TYPES.Katana, (context) => { new Katana(); });

registerConstructor

var registerConstructor = helpers.registerConstructor(container);
registerConstructor(TYPES.Katana)(Katana);

registerFunction

var registerFunction = helpers.registerFunction(container);
registerFunction(TYPES.SomeFunction, () {
  console.log("I'm doing something...");
});

registerAutoFactory

var registerAutoFactory = helpers.registerAutoFactory(container);
registerAutoFactory(TYPES.KatanaFactory, TYPES.Katana);

registerFactory

var registerFactory = helpers.registerFactory(container);
registerFactory(TYPES.KatanaFactory, (context) => {
  return () => {
    return context.container.get("Katana");
  };
});

registerProvider

var registerProvider = helpers.registerProvider(container);
registerProvider(TYPES.KatanaProvider, (context) => {
    return () => {
        return new Promise<Katana>((resolve) => {
            let katana = context.container.get("Katana");
            resolve(katana);
        });
    };
});

Declaring binding constraints

The register helper allows access to the fluent binding declaration API:

var register = helpers.register(container);

register(TYPES.Weapon, (b) => {
    b.whenTargetTagged("throwable", false);
})(Katana);

register(TYPES.Weapon, (b) => {
    b.whenTargetTagged("throwable", true);
})(Shuriken);

register(TYPES.Ninja, [
  { tagged: { key: "throwable", value: false }, type: "Weapon" },
  { tagged: { key: "throwable", value: true }, type: "Weapon" }
])(Ninja);

Babel decorators

If you are using babel you can also use the register helper as a class decorator with the transform-decorators-legacy plugin.

let helpers = require("inversify-vanillajs-helpers").helpers;
let inversify = require("inversify");
require("reflect-metadata");

let container = new inversify.Container();
let register = helpers.register(container);

let TYPE = {
    Warrior: "Warrior",
    Weapon: "Weapon"
};

@register(
    TYPE.Weapon, [],
    (b) => { b.whenTargetTagged("throwable", false); }
)
class Katana {
    constructor() {
        this.name = "Katana";
    }
}

@register(
    TYPE.Weapon, [],
    (b) => { b.whenTargetTagged("throwable", true); }
)
class Shuriken {
    constructor() {
        this.name = "Shuriken";
    }
}

@register(
    TYPE.Warrior,
    [
        { tagged: { key: "throwable", value: false }, type: TYPE.Weapon },
        { tagged: { key: "throwable", value: true }, type: TYPE.Weapon }
    ]
)
class Ninja {
    constructor(primaryWeapon, secondaryWeapon) {
        this.primaryWeapon = primaryWeapon;
        this.secondaryWeapon = secondaryWeapon;
    }
}

let ninja = container.get(TYPE.Warrior);
expect(ninja.primaryWeapon.name).to.eql("Katana");
expect(ninja.secondaryWeapon.name).to.eql("Shuriken");

Live demo

A live demo can be found here.

var helpers = require("inversify-vanillajs-helpers").helpers;
var inversify = require("inversify");
require("reflect-metadata");

class Katana {
    constructor() {
        this.name = "Katana";
    }
}

class Shuriken {
    constructor() {
        this.name = "Shuriken";
    }
}

class Ninja {
    constructor(primaryWeapon, secondaryWeapon) {
        this.primaryWeapon = primaryWeapon;
        this.secondaryWeapon = secondaryWeapon;
    }
}

let container = new inversify.Container();
let register = helpers.register(container);
 
let TYPE = {
    Warrior: "Warrior",
    Weapon: "Weapon"
};

register(TYPE.Weapon, [], (b) => b.whenTargetTagged("throwable", false))(Katana);
register(TYPE.Weapon, [], (b) => b.whenTargetTagged("throwable", true))(Shuriken);

register(TYPE.Warrior, [
    { tagged: { key: "throwable", value: false }, type: TYPE.Weapon },
    { tagged: { key: "throwable", value: true }, type: TYPE.Weapon }
])(Ninja);
 
container.get(TYPE.Warrior);