easy-injectionjs
TypeScript icon, indicating that this package has built-in type declarations

0.1.42 • Public • Published

easy-injectionJS

A package that provides dependency injection using common design patterns as stereotypes. It easily injects depedencies in runtime and supports inheritance:

There's no additional dependencies or containers needed to use the package. You can simply use it as follows:

npm i -S easy-injectionjs

Or

yarn add easy-injectionjs

Dependencies without inheritance:

import { Easy, EasyPrototype, EasySingleton } from 'easy-injectionjs';
 
// Creates a singleton instance of Movie class in runtime
@EasySingleton()
class Movie {
  constructor (private name: string, private ratings: number) {
    // Lets say that they just release the movie :D
    this.name = 'Black Panther';
    this.ratings = 9.0; // I really like that movie
  }
 
  public getName(): string {
    return this.name;
  }
 
  public getRatings(): number {
    return this.ratings;
  }
 
  public setName(v: string) {
    this.name = v;
  }
 
  public setRatings(v: number) {
    this.ratings = v;
  }
}
 
// Creates a multiple instances as needed in runtime
@EasyPrototype()
class Actor {
  @Easy()
  private movie: Movie;
  private name: string;
 
  constructor (name: string) {
    this.name = name;
  }
 
  public getMovieName(): string {
    return this.movie.getName();
  }
 
  public setMovieName(v: string) {
    this.movie.setName(v);
  }
}
 
let T_Challa = new Actor('Chadwick Boseman');
console.log(T_Challa.getMovieName());// Output is Black Panther
T_Challa.setMovieName('Black Panther II'); // Hopefully
console.log(T_Challa.getMovieName()); // Output is Black Panther II
let Erik_Killmonger = new Actor('Michael B Jordan');
console.log(Erik_Killmonger.getMovieName()) // // Output is Black Panther II

If the movie had the annotaion of EasyPrototype instead, Erik_Killmonger.getMovieName() will return Black Panther istead of Black Panther 2.

Interfaces and named dependencies example:

import { Easy, EasyPrototype, EasySingleton } from 'easy-injectionjs';
 
interface Show {
  getName(): string;
  getRatings(): number;
  setName(v: string);
  setRatings(v: number);
}
 
// Creates a singleton instance of Movie class in runtime
@EasySingleton('Movie')
class Movie implements Show {
  constructor (private name: string, private ratings: number) {
    // Lets say that they just release the movie :D
    this.name = 'Black Panther';
    this.ratings = 9.0; // I really like that movie
  }
 
  public getName(): string {
    return this.name;
  }
 
  public getRatings(): number {
    return this.ratings;
  }
 
  public setName(v: string) {
    this.name = v;
  }
 
  public setRatings(v: number) {
    this.ratings = v;
  }
}
 
// Creates a multiple instances as needed in runtime
@EasyPrototype()
class Actor {
  @Easy('Movie')
  private movie: Show;
  private name: string;
 
  constructor (name: string) {
    this.name = name;
  }
 
  public getMovieName(): string {
    return this.movie.getName();
  }
 
  public setMovieName(v: string) {
    this.movie.setName(v);
  }
}
 
let T_Challa = new Actor('Chadwick Boseman');
console.log(T_Challa.getMovieName());// Output is Black Panther
T_Challa.setMovieName('Black Panther II'); // Hopefully
console.log(T_Challa.getMovieName()); // Output is Black Panther II
let Erik_Killmonger = new Actor('Michael B Jordan');
console.log(Erik_Killmonger.getMovieName()) // // Output is Black Panther II

The package support inheritance even with abstract classes using the @EasyFactory decorator:

Example:

import { Easy, EasyFactory, EasyPrototype, EasySingleton } from 'easy-injectionjs';
 
@EasyFactory()
abstract class Show {
  public abstract getName(): string;
  public abstract getRatings(): number;
  public abstract setName(v: string);
  public abstract setRatings(v: number);
}
 
// Creates a singleton instance of Movie class in runtime
@EasySingleton()
class Movie extends Show {
  constructor (private name: string, private ratings: number) {
    super();
    // Lets say that they just release the movie :D
    this.name = 'Black Panther';
    this.ratings = 9.0; // I really like that movie
  }
 
  public getName(): string {
    return this.name;
  }
 
  public getRatings(): number {
    return this.ratings;
  }
 
  public setName(v: string) {
    this.name = v;
  }
 
  public setRatings(v: number) {
    this.ratings = v;
  }
}
 
// Creates a multiple instances as needed in runtime
@EasyPrototype()
class Actor {
  @Easy()
  private movie: Show;
  private name: string;
 
  constructor (name: string) {
    this.name = name;
  }
 
  public getMovieName(): string {
    return this.movie.getName();
  }
 
  public setMovieName(v: string) {
    this.movie.setName(v);
  }
}
 
let T_Challa = new Actor('Chadwick Boseman');
console.log(T_Challa.getMovieName());// Output is Black Panther
T_Challa.setMovieName('Black Panther II'); // Hopefully
console.log(T_Challa.getMovieName()); // Output is Black Panther II
let Erik_Killmonger = new Actor('Michael B Jordan');
console.log(Erik_Killmonger.getMovieName()) // // Output is Black Panther II

Both Iterfaces and abstract classes inheritance support naming to differentiate between the children dependencies and the names have to go into the @Easy decorator and have to match the names in the @EasyPrototype and @EasySingleton decorators. You can even name the @EasyFactory decorator if u have many abstract classes extending each others.

You can even not name anything and let the package figure out which dependencies as needed:

import { Easy, EasyFactory, EasyPrototype, EasySingleton } from 'easy-injectionjs';
 
@EasyFactory()
abstract class Person {
  abstract getName();
  abstract setName(v: string);
}
 
// @EasyObservable()
@EasySingleton()
class Somebody extends Person{
  // @Easy()
  constructor (private name: string) {
    super()
    this.name = 'Sal';
  }
 
  public getName() {
    return this.name;
  }
  public setName(v: string) {
    this.name = v;
  }
}
 
@EasyPrototype()
class Nobody extends Person{
  @Easy()
  somebody: Person;
  constructor () {
    super()
  }
  
  public getName() {
    return this.somebody.getName();
  }
 
  public setName(v: string) {
    this.somebody.setName(v);
  }
}
 
@EasyPrototype()
class Data {
  @Easy()
  somebody: Person;
  name: string;
 
  change(v: string) {
    this.somebody.setName(v);
  }
 
  getName(): string {
    return this.somebody.getName();
  }
}
 
let n = new Nobody();
console.log(n.getName()) // Prints Sal
n.setName('awesome');
console.log(n.getName())  // Prints awesome
let d = new Data()
console.log(d.getName())  // Prints awesome
d.change('Gelba')
console.log(n.getName())  // Prints Gelba
d.change('kaa')
console.log(n.getName())  // Prints Kaa
 

The "is" Keyword:

The "is" function is used to retrieve dependencies anywhere in the program. It can also be usint with constructor injection:

Example:

import { EasySingleton,
         EasyPrototype,
         is } import 'easy-injectionjs';
 
@EasySingleton()
class Somebody {
  // @Easy()
  constructor (private name: string) {
    this.name = 'Vladi';
  }
 
  public getName() {
    return this.name;
  }
  public setName(v: string) {
    this.name = v;
  }
}
 
@EasyPrototype()
class Awesome {
  private _name: string;
  constructor (someone: Somebody = is(Somebody)) {
    someone.setName('Sal')
    this._name = someone.getName();
    console.log(this._name);
  }
}
 
is(Awesome) // call returns an instance of Awesome
 
console.log(is(Somebody).getName()) // returns Sal since it is a singleton :D
 

The "Easily" Method:

The "Easily" is ideally used to define static constants or simple objects like:

import { Easily } from 'easy-injectionjs';
 
const config = {
  author: 'Sal'
}
Easily('config', config);

It requires a name to be injected. PS it can work for npm packages also, if imported like this: import * as smth from 'package'

@EasyPrototype()
class Nobody {
  @Easy('config')
  config: Object;
  constructor () {
    super()
  }
  
  public getName() {
    return this.somebody.getName();
  }
 
  public setName(v: string) {
    this.somebody.setName(v);
  }
}

A bit complicated example:

import {Easy, EasyPrototype, EasySingleton, EasyFactory, Easily, is} from 'easy-injectionjs';
 
Easily('config', {
  feeling: 'hungry'
})
 
@EasyFactory()
abstract class Person {
  abstract getName();
  abstract setName(v: string);
}
 
@EasySingleton()
class Somebody extends Person{
  // @Easy()
  constructor (private name: string) {
    super()
    this.name = 'Sal';
  }
 
  public getName() {
    return this.name;
  }
  public setName(v: string) {
    this.name = v;
  }
}
 
@EasyPrototype()
class Nobody extends Person{
  @Easy()
  somebody: Person;
  @Easy('config')
  config: Object;
  constructor () {
    super()
  }
  
  public getName() {
    return this.somebody.getName();
  }
 
  public setName(v: string) {
    this.somebody.setName(v);
  }
}
 
@EasyFactory()
abstract class Show {
  public abstract getName(): string;
  public abstract getRatings(): number;
  public abstract setName(v: string);
  public abstract setRatings(v: number);
}
 
// Creates a singleton instance of Movie class in runtime
@EasySingleton()
class Movie extends Show {
  constructor (private name: string, private ratings: number) {
    super();
    // Lets say that they just release the movie :D
    this.name = 'Black Panther';
    this.ratings = 9.0; // I really like that movie
  }
 
  public getName(): string {
    return this.name;
  }
 
  public getRatings(): number {
    return this.ratings;
  }
 
  public setName(v: string) {
    this.name = v;
  }
 
  public setRatings(v: number) {
    this.ratings = v;
  }
}
 
@EasySingleton()
class Data {
  @Easy()
  somebody: Person;
  name: string;
  @Easy()
  movie: Movie;
  change(v: string) {
    this.somebody.setName(v);
  }
 
  getName(): string {
    return this.somebody.getName();
  }
}
 
let n = new Nobody();
console.log(n)
console.log(n.getName()) // Prints Sal
n.setName('awesome');
console.log(n.getName())  // Prints awesome
let d = new Data()
console.log(d)
console.log(d.getName())  // Prints awesome
d.change('Gelba')
console.log(n.getName())  // Prints Gelba
d.change('kaa')
console.log(n.getName())

Even method injection is very easy using both "Easily", the decorators and "is". That makes dynamic injection very easy.

import { Easily } from 'easy-injectionjs';
 
Easily('Data', {
  name: 'Sal'
});
 

And somewhere in the program in another file:

import { is, Easily } from 'easy-injectionjs';
 
function modifyData(data: any = is('Data')) {
  data.name = 'I am Batman';
  // update it
  Easily('Data',data);
}

And maybe another class requires "Data":

import { EasyPrototype, Easy } from 'easy-injectionjs';
// why not :D
@EasyPrototype()
class Mule {
  @Easy('Data')
  private data:any;
}

If modifyData was called before Mule was used, the data name inside the property data of mule will change in runtime.

Package Sidebar

Install

npm i easy-injectionjs

Weekly Downloads

184

Version

0.1.42

License

MIT

Unpacked Size

43.9 kB

Total Files

38

Last publish

Collaborators

  • shehats