Simple but powerful, functional-programming ready Dependency Injector/Container library for node.js.
dependency injection library for not only classes but also functions, strings, numbers, ... and all objects in the world.
- simple syntax, easy to use
- functional-programming ready
- lightweight
- built-in typescript supports
- supports lazy-instantiation
npm i smart-factory
const { init, injectable, resolve } = require('smart-factory');
// module names
const ModuleNames = {
MSG_PROVIDER: 'MSG_PROVIDER',
MSG_PRINTER: 'MSG_PRINTER',
GREETER: 'GREETER'
};
// regiser message provider function to container
injectable(ModuleNames.MSG_PROVIDER,
[],
() =>
new Promise((resolve) => {
const toBeRegistered = (lang) => { // msgProvider function.
if (lang === 'en') return 'HELLO!';
else if (lang === 'ko') return '안녕하세요!';
else if (lang === 'es') return 'HOLA!';
return 'UNKNOWN';
};
resolve(toBeRegistered);
}));
// register message printer function to container
injectable(ModuleNames.MSG_PRINTER,
[],
() =>
new Promise((resolve) => {
const toBeRegistered = (msg) => console.log(msg); // msgPrinter function
resolve(toBeRegistered);
}));
// register greeter function to container.
injectable(ModuleNames.GREETER,
[ModuleNames.MSG_PROVIDER, ModuleNames.MSG_PRINTER], // required dependencies
(provider, printer) => // dependencies which injected from container
new Promise((resolve) => {
const toBeRegistered = (lang) => { // greeter function.
printer(provider(lang));
};
resolve(toBeRegistered);
}));
(() => {
init() // awaiting container ready
.then(() => {
const greet = resolve(ModuleNames.GREETER); // injects greeter function from container.
greet('en'); // HELLO!
});
})();import { init, injectable, resolve } from 'smart-factory';
export enum Modules {
HELLO_FUNC = 'HELLO_FUNC',
MSG_PROVIDER = 'MSG_PROVIDER',
MSG_PRINTER = 'MSG_PRINTER'
}
export type MsgProvider = (lang: string) => string;
export type MsgPrinter = (msg: string) => void;
export type HelloFunction = (lang: string) => void;
injectable(
Modules.MSG_PROVIDER, // module name
[], // dependencies
async (): Promise<MsgProvider> =>
(lang: string): string => {
if (lang === 'en') return 'HELLO!';
else if (lang === 'ko') return '안녕하세요!';
else if (lang === 'es') return 'HOLA!';
return 'UNKNOWN';
});
injectable(
Modules.MSG_PRINTER,
[],
async () : Promise<MsgPrinter> =>
(msg: string) => console.log(msg);
injectable(
Modules.HELLO_FUNC,
[ Modules.MSG_PROVIDER, Modules.MSG_PRINTER ], // has dependencies to MsgProvider, MsgPrinter
async (provider: MsgProvider, printer: MsgPrinter): HelloFunction =>
(lang: string) => {
printer(provider(lang));
});
(async () => {
await init();
const helloFunc = resolve<HelloFunction>(Modules.HELLO_FUNC);
helloFunc('es'); // HOLA!
})();initialize container. after init() executed, you can retreive a modules from container.
| key | mandantory | default | description |
|---|---|---|---|
| debug?: boolean | no | false | show container logs. for debug purpose. |
| includes?: string[] | no | null | specify path for modules which calls injectable(). |
| excludes?: string[] | no | null | specify path for exceptional modules. |
(async () => {
await init({
debug: true,
includes: [`${__dirname}/**/*.ts`]
});
})();register modules to container. the dependencies deps[] will be injeted before the module instantiated.
after all dependencies meets requirements, the modules will be instantiated and registered to container with name key.
the instantiator is your async function that preparing instance from given dependencies deps[].
type Coffee = {
bean: CoffeeBean;
water: Water;
sugar: Sugar;
};
type CoffeeMaker = () => Coffee;
injectable(
'COFFEE_MAKER', // module name
[ 'COFFEE_BEAN', 'WATER', 'SUGAR' ], // required dependencies
async (bean, water, sugar): Promise<CoffeeMaker> => // the "Instantiator": returns coffeeMaker function.
() => { // coffeeMaker function
return {
bean, water, sugar
}
}
);resolves module from container. with typescript, you can specify type.
(async () => {
const makeCoffee = await <CoffeeMaker>resolve('COFFEE_MAKER');
const coffee = makeCoffee();
console.log(coffee); // { bean, water, sugar }!
})();replace an instance in container with given key and instance. you can use this feature in the test codes.
(async () => {
injectable('A', [], async () => 10);
await init(); // container initialized.
const value = <number>resolve('A');
console.log(value); // "10"
set('A', 20);
const valueAfterSet = <number>resolve('A');
console.log(valueAfterSet); // "20"
})();clear all instances in container
(async () => {
injectable('A', [], async () => 10);
await init(); // container initialized.
const value = <number>resolve('A');
console.log(value); // "10"
clear(); // nothing in container.
})();There are a more complicated examples that using smart-factory. you can learn how to manage complicated dependencies (ex: configuration, database, models..) for complicated application with the smart-factory.
- Chatpot-Room-Server
- chatting-room server written with Typescript, smart-factory
- configurations, mysql, models, api endpoints
- shows handling modules names and types with typescript way.