Comparing version 1.0.0 to 1.1.0
@@ -1,95 +0,1 @@ | ||
## Express usage: | ||
`hekdi` can be integrated with [express.js](https://github.com/expressjs/express). | ||
```javascript | ||
'use strict'; | ||
const express = require('express'); | ||
const { expressDI, createModule } = require('hekdi'); | ||
const app = express(); // create express app | ||
class Ctrl { // create controller | ||
static get $inject() { | ||
return ['hello', 'world']; | ||
} | ||
constructor(hello, world) { | ||
this.hello = hello; | ||
this.world = world; | ||
} | ||
next(req, res, next) { | ||
console.log('hi from next Ctrl method'); | ||
next(); | ||
} | ||
greet(req, res) { | ||
console.log('greet'); | ||
console.log('\n'); | ||
res.send(`${this.hello},${this.world}`); | ||
} | ||
hi(req, res, next, data) { | ||
console.log('hi', data); | ||
console.log('\n'); | ||
res.send(`${this.hello} there`); | ||
} | ||
} | ||
const importedModule = createModule({ // create module to be injected | ||
name: 'ServicesModule', | ||
declarations: [ | ||
{ name: 'hello', strategy: 'value', value: 'Hello' }, | ||
{ name: 'world', strategy: 'value', value: 'World' }, | ||
], | ||
exports: '*' | ||
}); | ||
// create DI instance and register a router config to it. | ||
const di = expressDI.create(app, { | ||
'/api': { // router path | ||
get: { // http method | ||
controller: 'Controller', // Dependency | ||
fn: 'hi', // dependency function to be called | ||
data: ['args'] // data that will be passed to function as arguments after (req, res, next) | ||
} | ||
}, | ||
'/api/:test': { | ||
get: { | ||
controller: 'Controller', | ||
fn: 'greet', | ||
middlewares: [ // this array will register middlewares for this route. | ||
(req, res, next) => { // if middleware is a function it will be registered | ||
console.log('from middleware'); | ||
next(); | ||
}, { // but if it is a config then this dependency function will be found in module | ||
controller: 'Controller', | ||
fn: 'next' | ||
} | ||
] | ||
}, | ||
} | ||
}); | ||
di.bootstrap({ // bootstraps di | ||
name: 'Module', | ||
declarations: [ | ||
{ name: 'Controller', strategy: 'singleton', value: Ctrl } | ||
], | ||
imports: [ importedModule ] | ||
}); | ||
app.listen(3000); // launch app | ||
``` | ||
In the case of `get` request to `/api` we will get: | ||
- console: 'hi' 'args' | ||
- response: 'hello there' | ||
In the case of `get` request to `/api/param` we will get: | ||
- console: | ||
- 'from middleware'; | ||
- 'hi from next Ctrl method'; | ||
- 'greet' | ||
- response: 'Hello, World' | ||
not done yet |
@@ -8,3 +8,3 @@ 'use strict'; | ||
createModule: Module.createModule, | ||
expressDI: require('./src/frameworks/express') | ||
koaDI: require('./src/frameworks/koa') | ||
}; |
{ | ||
"name": "hekdi", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Depedency injection framework for node.js", | ||
@@ -18,7 +18,8 @@ "main": "index.js", | ||
"koa-router": "^7.2.1", | ||
"mocha": "^3.5.0" | ||
"mocha": "^3.5.0", | ||
"koa-body-parser": "^1.1.2" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git@github.com:IvanProdaiko94/Injector.git" | ||
"url": "git@github.com:IvanProdaiko94/hekdi.git" | ||
}, | ||
@@ -41,4 +42,4 @@ "keywords": [ | ||
"engines": { | ||
"node": ">=6.0.0" | ||
"node": ">=7.6.0" | ||
} | ||
} |
@@ -6,3 +6,6 @@ [![Build Status](https://travis-ci.org/IvanProdaiko94/hekdi.svg?branch=master)](https://travis-ci.org/IvanProdaiko94/hekdi) | ||
[![license](https://img.shields.io/github/license/mashape/apistatus.svg)]() | ||
[![npm](https://img.shields.io/npm/dm/hekdi.svg)](https://www.npmjs.com/package/hekdi) | ||
[![npm](https://img.shields.io/npm/dt/hekdi.svg)](https://www.npmjs.com/package/hekdi) | ||
# node.js Dependency Injection | ||
@@ -18,4 +21,4 @@ This module provides dependency injection for node.js | ||
- [Express](./docs/express.md) | ||
- [Koa](./examples/koa.js) | ||
- [Hapi](./examples/hapi.js) | ||
- [Koa](./docs/koa.md) | ||
- [Hapi](./docs/hapi.md) | ||
@@ -22,0 +25,0 @@ ## Basic usage: |
@@ -7,42 +7,2 @@ /** | ||
const DI = require('../di'); | ||
/** | ||
* | ||
* @param app | ||
* @param config Object | ||
* @constructor | ||
*/ | ||
function ExpressDI(app, config) { | ||
DI.call(this); | ||
for (const key in config) { | ||
for (const method in config[key]) { | ||
const routeConfig = config[key][method]; | ||
if (routeConfig.middlewares && routeConfig.middlewares.length) { | ||
const fns = routeConfig.middlewares.map(middleware => { | ||
return typeof middleware === 'function' ? | ||
middleware : | ||
(...args) => this.resolve(middleware.controller)[middleware.fn](...args); | ||
}); | ||
app.use(key, ...fns); | ||
} | ||
if (!routeConfig.data) { | ||
routeConfig.data = []; | ||
} | ||
app[method]( | ||
key, | ||
(...args) => this.resolve(routeConfig.controller)[routeConfig.fn](...args, ...routeConfig.data) | ||
); | ||
} | ||
} | ||
} | ||
ExpressDI.prototype = DI.prototype; | ||
DI.prototype.constructor = DI; | ||
ExpressDI.create = function(app, config) { | ||
return new ExpressDI(app, config); | ||
}; | ||
module.exports = ExpressDI; | ||
const DI = require('../di'); |
@@ -6,1 +6,3 @@ /** | ||
'use strict'; | ||
const DI = require('../di'); |
@@ -6,1 +6,90 @@ /** | ||
'use strict'; | ||
const DI = require('../di'); | ||
/** | ||
* @param ctx {Object} | ||
* @param original {Function} | ||
* @returns {Function} | ||
*/ | ||
const diResolver = function(ctx, original) { | ||
/** @param diConfig {Function|String|Object<{controller: string, action: string, [params]: Array}>} */ | ||
return function(diConfig) { | ||
switch (typeof diConfig) { | ||
case 'string': | ||
original.call(ctx, ctx.context.di.resolve(diConfig)); | ||
break; | ||
case 'object': // array | ||
const { controller, action, params } = diConfig; | ||
const dependency = ctx.context.di.resolve(controller); | ||
original.call(ctx, async (ctx, next) => { | ||
if (next) { | ||
await dependency[action](ctx, next, params); | ||
} else { | ||
await dependency[action](ctx, params); | ||
} | ||
}); | ||
break; | ||
default: // function | ||
original.call(ctx, diConfig); | ||
} | ||
return ctx; | ||
}; | ||
}; | ||
/** | ||
* @param app {Object} | ||
* @param ctx {Object} | ||
* @param original {Function} | ||
* @returns {Function} | ||
*/ | ||
const diRouterResolver = function(app, ctx, original) { | ||
/** | ||
* path {string} | ||
* @param diConfig {Function|String|Object<{controller: string, action: string, [params]: Array}>} | ||
*/ | ||
return function(path, diConfig) { | ||
switch (typeof diConfig) { | ||
case 'string': | ||
original.call(ctx, path, app.context.di.resolve(diConfig)); | ||
break; | ||
case 'object': // array | ||
const { controller, action, params } = diConfig; | ||
const dependency = app.context.di.resolve(controller); | ||
original.call(ctx, path, async (ctx, next) => { | ||
if (next) { | ||
await dependency[action](ctx, next, params); | ||
} else { | ||
await dependency[action](ctx, params); | ||
} | ||
}); | ||
break; | ||
default: // function | ||
original.call(ctx, path, diConfig); | ||
} | ||
return ctx; | ||
}; | ||
}; | ||
/** | ||
* | ||
* @param app | ||
* @param bootstrapModule {Module|Object} | ||
* @param [router] | ||
*/ | ||
module.exports = function koaDi(bootstrapModule, app, router) { | ||
const di = new DI(); | ||
di.bootstrap(bootstrapModule); | ||
di.main.injector.register({name: 'App', strategy: 'constant', value: app}); | ||
app.context.di = di; | ||
app.use = diResolver(app, app.use); | ||
if (router) { | ||
router.use = diRouterResolver(app, router, router.use); | ||
router.methods.forEach(method => { | ||
const methodName = method.toLowerCase(); | ||
router[methodName] = diRouterResolver(app, router, router[methodName]); | ||
}) | ||
} | ||
}; |
@@ -5,70 +5,69 @@ 'use strict'; | ||
class Injector { | ||
/** | ||
* @param moduleName {string} | ||
*/ | ||
constructor(moduleName) { | ||
this.belongTo = moduleName; | ||
this.dependencies = new Map(); | ||
} | ||
/** | ||
* | ||
* @param moduleName {string} | ||
* @constructor | ||
*/ | ||
function Injector(moduleName) { | ||
this.belongTo = moduleName; | ||
this.dependencies = new Map(); | ||
} | ||
/** | ||
* @param dependencyName {String} | ||
* @return {*} | ||
*/ | ||
resolve(dependencyName) { | ||
if (this.dependencies.has(dependencyName)) { | ||
return this.dependencies.get(dependencyName).resolver(); | ||
} else { | ||
throw new ReferenceError(errors.unmetDependency(this.belongTo, dependencyName)); | ||
} | ||
/** | ||
* @param dependencyName {String} | ||
* @return {*} | ||
*/ | ||
Injector.prototype.resolve = function(dependencyName) { | ||
if (this.dependencies.has(dependencyName)) { | ||
return this.dependencies.get(dependencyName).resolver(); | ||
} | ||
throw new ReferenceError(errors.unmetDependency(this.belongTo, dependencyName)); | ||
}; | ||
/** | ||
* @param dependencies {Map} | ||
*/ | ||
addImports(dependencies) { | ||
dependencies.forEach((dependencyConfig, key) => { | ||
this.dependencies.set(key, dependencyConfig); | ||
}); | ||
} | ||
/** | ||
* @param dependencies {Map} | ||
*/ | ||
Injector.prototype.addImports = function(dependencies) { | ||
dependencies.forEach((dependencyConfig, key) => { | ||
this.dependencies.set(key, dependencyConfig); | ||
}); | ||
}; | ||
/** | ||
* @param dependencies {Object<{name: string, strategy: string: value: any}>} | ||
* @return {Map} | ||
*/ | ||
register(...dependencies) { | ||
dependencies.map(config => { | ||
const inject = config.value.$inject || []; | ||
const dConf = this.getConfigOf(config.name); | ||
if (dConf && dConf.strategy === 'constant') { | ||
throw new Error(errors.dependencyIsRegistered(config.name)); | ||
} else if (!strategies.hasOwnProperty(config.strategy)) { | ||
throw new Error(errors.incorrectResolutionStrategy(config.strategy, strategies)); | ||
} else if (inject.indexOf(config.name) !== -1) { | ||
throw new Error(errors.selfDependency(config.name)); | ||
/** | ||
* @param dependencies {Object<{name: string, strategy: string: value: any}>} | ||
* @return {Map} | ||
*/ | ||
Injector.prototype.register = function(...dependencies) { | ||
dependencies.map(config => { | ||
const inject = config.value.$inject || []; | ||
const dConf = this.getConfigOf(config.name); | ||
if (dConf && dConf.strategy === 'constant') { | ||
throw new Error(errors.dependencyIsRegistered(config.name)); | ||
} else if (!strategies.hasOwnProperty(config.strategy)) { | ||
throw new Error(errors.incorrectResolutionStrategy(config.strategy, strategies)); | ||
} else if (inject.indexOf(config.name) !== -1) { | ||
throw new Error(errors.selfDependency(config.name)); | ||
} | ||
inject.forEach(dep => { | ||
if (this.dependencies.has(dep)) { | ||
const depsToCheck = this.getConfigOf(dep).value.$inject || []; | ||
if (depsToCheck.indexOf(config.name) !== -1) { | ||
throw new Error(errors.circularDependency(config.name, dep)); | ||
} | ||
} | ||
inject.forEach(dep => { | ||
if (this.dependencies.has(dep)) { | ||
const depsToCheck = this.getConfigOf(dep).value.$inject || []; | ||
if (depsToCheck.indexOf(config.name) !== -1) { | ||
throw new Error(errors.circularDependency(config.name, dep)); | ||
} | ||
} | ||
}); | ||
config.resolver = strategies[config.strategy](config.name).bind(this); | ||
config.belongTo = this.belongTo; | ||
this.dependencies.set(config.name, config); | ||
}); | ||
} | ||
config.resolver = strategies[config.strategy](config.name).bind(this); | ||
config.belongTo = this.belongTo; | ||
this.dependencies.set(config.name, config); | ||
}); | ||
}; | ||
/** | ||
* @param dependencyName {String} | ||
* @return {*} | ||
*/ | ||
getConfigOf(dependencyName) { | ||
return this.dependencies.get(dependencyName); | ||
} | ||
} | ||
/** | ||
* @param dependencyName {String} | ||
* @return {*} | ||
*/ | ||
Injector.prototype.getConfigOf = function(dependencyName) { | ||
return this.dependencies.get(dependencyName); | ||
}; | ||
module.exports = Injector; |
'use strict'; | ||
const Injector = require('./injector'); | ||
class Module { | ||
/** | ||
* @param config <{ | ||
* name: string, | ||
* [declarations]: Array<Object>, | ||
* [imports]: Array<Module>, | ||
* [exports]: Array<string>|string> | ||
* }> | ||
* @return Module <{name: string, injector: Injector, [exports]: Map}> | ||
*/ | ||
constructor(config) { | ||
this.name = config.name; | ||
this.injector = new Injector(this.name); | ||
/** | ||
* | ||
* @constructor | ||
* @param config <{ | ||
* name: string, | ||
* [declarations]: Array<Object>, | ||
* [imports]: Array<Module>, | ||
* [exports]: Array<string>|string> | ||
* }> | ||
* @return Module <{name: string, injector: Injector, [exports]: Map}> | ||
*/ | ||
function Module(config) { | ||
this.name = config.name; | ||
this.injector = new Injector(this.name); | ||
if (config.imports) { | ||
config.imports.forEach(importedModule => { | ||
if (importedModule.exports) { | ||
this.injector.addImports(importedModule.exports); | ||
if (config.imports) { | ||
config.imports.forEach(importedModule => { | ||
if (importedModule.exports) { | ||
this.injector.addImports(importedModule.exports); | ||
} | ||
}); | ||
} | ||
this.injector.register(...(config.declarations || [])); | ||
if (config.exports) { | ||
const dependencies = this.injector.dependencies; | ||
if (config.exports === '*') { | ||
this.exports = new Map(dependencies); | ||
} else { | ||
this.exports = new Map(); | ||
config.exports.forEach(dependencyName => { | ||
const dependencyConfig = this.injector.getConfigOf(dependencyName); | ||
if (dependencyConfig.belongTo === this.name) { | ||
this.exports.set(dependencyName, dependencyConfig); | ||
} | ||
}); | ||
} | ||
this.injector.register(...(config.declarations || [])); | ||
if (config.exports) { | ||
const dependencies = this.injector.dependencies; | ||
if (config.exports === '*') { | ||
this.exports = new Map(dependencies); | ||
} else { | ||
this.exports = new Map(); | ||
config.exports.forEach(dependencyName => { | ||
const dependencyConfig = this.injector.getConfigOf(dependencyName); | ||
if (dependencyConfig.belongTo === this.name) { | ||
this.exports.set(dependencyName, dependencyConfig); | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
static createModule(config) { | ||
return new Module(config); | ||
} | ||
} | ||
Module.createModule = function(config) { | ||
return new Module(config); | ||
}; | ||
module.exports = Module; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
17933
16
300
138
8