Comparing version 5.0.0 to 6.0.0
{ | ||
"name": "diogenes", | ||
"version": "5.0.0", | ||
"version": "6.0.0", | ||
"description": "A dependency injection framework.", | ||
@@ -37,5 +37,4 @@ "main": "src/index.js", | ||
"dependencies": { | ||
"es6-promisify": "^6.0.0", | ||
"uuid": "^3.2.1" | ||
} | ||
} |
312
README.md
@@ -53,8 +53,7 @@ Diogenes | ||
----------------- | ||
A service is a unit of code with a name. It can be a simple value, a synchronous function (returning a value), an asynchronous function using a callback or an asynchronous function returning a promise. | ||
A service is a unit of code with a name. It can be a simple value, a synchronous function (returning a value) or an asynchronous function returning a promise. | ||
It takes as argument an object containing the dependencies (output of other services). | ||
Optionally you can pass a callback. | ||
A service outputs a "dependency", this is identified with the service name. | ||
Services are organized inside a registry. The common interface allows to automate how the dependencies are resolved within the registry. | ||
Services are organised inside a registry. The common interface allows to automate how the dependencies are resolved within the registry. | ||
@@ -75,3 +74,3 @@ A step by step example | ||
```js | ||
const registry = Diogenes.getRegistry(); // of new Diogenes() | ||
const registry = Diogenes.getRegistry(); // or new Diogenes() | ||
``` | ||
@@ -104,11 +103,4 @@ | ||
``` | ||
or you can use a callback: | ||
```js | ||
registry.service("text") | ||
.provides((deps, next) => { | ||
fs.readFile('diogenes.txt', {encoding: 'utf8'}, next); | ||
}); | ||
``` | ||
The callback should use the node.js convention: the first argument is the error instance (or null if there isn't any) and the second is the value returned. | ||
As you can see, Diogenes allows to mix sync and async (callback and promise based) functions. How cool is that? | ||
As you can see, Diogenes allows to mix sync and async functions. | ||
Let's add other services: | ||
@@ -150,73 +142,127 @@ ```js | ||
``` | ||
p will be the output of the paragraph service. You can alternatively pass a callback to "run". | ||
p will be the output of the paragraph service. | ||
When resolving a dependency graph, diogenes takes care of executing every service at most once. | ||
If a service returns or throws an exception, this is propagated along the execution graph. Services getting an exception as one of the dependencies, are not executed. | ||
Docstring | ||
========= | ||
A docstring is the description of the service. That may help using diogenes-lantern, a tool that shows your registry with a graph. | ||
You can set a docstring like this: | ||
```js | ||
registry.run('paragraph', (err, p) => { | ||
if (err) { | ||
console.log(err.message) | ||
return; | ||
} | ||
console.log("This paragraph is " + p.count + " words long"); | ||
console.log("The abstract is: " + p.abstract); | ||
console.log("This is the original text:"); | ||
console.log(p.text); | ||
registry | ||
.service('service1') | ||
.doc('this is some helpful information') | ||
``` | ||
And you can retrieve a docString with: | ||
```js | ||
registry | ||
.service('service1') | ||
.doc() | ||
``` | ||
registry-runner | ||
=============== | ||
Registry runner is an object that takes care of running services. This adds many features to a simple registry. You can create a runner like this: | ||
```js | ||
const registryRunner = Diogenes.getRegistryRunner() | ||
``` | ||
then you can run a service with: | ||
```js | ||
registryRunner.run(registry, 'myservice') | ||
``` | ||
Registry runner allows to use callbacks: | ||
```js | ||
registryRunner.run(registry, 'myservice', (err, myservice) => { | ||
... | ||
}) | ||
``` | ||
The callback uses the node.js convention, the error is the first argument. | ||
If you need more than one service, you can pass a list of services: | ||
Another feature allows to execute multiple services efficiently using an array or a regular expression: | ||
```js | ||
registry.run(["count", "abstract"]) | ||
.then({ count, paragraph } => { | ||
... | ||
}) | ||
registryRunner.run(registry, /myservice[1-3]/) | ||
``` | ||
In this case the result will be an object with an attribute for each dependency (deps.count, deps.abstract). | ||
or the equivalent: | ||
```js | ||
registryRunner.run(registry, ['myservice1', 'myservice2', 'myservice3']) | ||
``` | ||
The result will be an object with an attribute for every dependency. | ||
Errors | ||
====== | ||
If a service returns or throws an exception, this is propagated along the execution graph. Services getting an exception as one of the dependencies, are not executed. | ||
Using this feature is different to: | ||
```js | ||
Promise.all([registry.run('myservice1'), registry.run('myservice2'), registry.run('myservice3')]) | ||
``` | ||
Because it ensures that every service is executed at most once. | ||
Using function references | ||
========================= | ||
"service" and "dependsOn" allow to use function references instead of strings (the functions should have a name!): | ||
You can also use the same method to add services without dependencies, without changing the original registry: | ||
```js | ||
registry | ||
.service(function service2 (deps) { | ||
// ... function implementation ... | ||
}) | ||
.dependsOn([service2]); | ||
registryRunner.run(registry, 'myservice', { times: 3 }) | ||
``` | ||
is equivalent to: | ||
So if a service depends on "times", it will get 3. This can be useful for testing (injecting a mock in the dependency graph). | ||
It is also useful to give an "execution context" that is different every time (think for example the request data in a web application). | ||
The registry runner keeps track of all pending execution so is able to gracefully shutdown: | ||
```js | ||
registry | ||
.service('service2') | ||
.provides((deps) => { | ||
// ... function implementation ... | ||
registryRunner.shutdown() | ||
.then(() => { | ||
console.log('We can shutdown') | ||
}) | ||
.dependsOn(['service2']); | ||
registryRunner.run('myservice1') // this return a promise rejection because the registry is not accepting new tasks | ||
``` | ||
Docstring | ||
========= | ||
You can define a docstring in 2 ways: | ||
Registry and decorators | ||
======================= | ||
[The decorator pattern](https://en.wikipedia.org/wiki/Decorator_pattern) can be very useful to enhance a service. For example adding a caching layer, logging or to convert a callback based service to use a promise (promisify is a decorator). | ||
The method "provides" includes a shortcut to add decorators to the service. If you pass an array or more than one argument, to the method. In the next example I am able to add a service that uses a callback instead of promises: | ||
```js | ||
registry | ||
.service('service1') | ||
.doc('this is some helpful information') | ||
registry.service('myservice') | ||
.provides([ | ||
promisify, | ||
(deps, next) => { | ||
.. do something | ||
next(null, result) | ||
}]) | ||
``` | ||
or | ||
In the next example I use a decorator to ensure a service is executed only once: | ||
```js | ||
registry | ||
.service(function service1(deps) { | ||
/** | ||
this is some helpful information | ||
**/ | ||
}) | ||
// define my decorator | ||
const onlyOnce = (func) => { | ||
let cache | ||
return (deps) => { | ||
if (typeof cache === 'undefined') { | ||
cache = func(deps) | ||
} | ||
return cache | ||
} | ||
} | ||
registry.service('myservice') | ||
.provides([ | ||
onlyOnce, | ||
(deps) => { | ||
... | ||
}]) | ||
``` | ||
And you can retrieve a docString with: | ||
You can add multiple decorators: | ||
```js | ||
registry | ||
.service('service1') | ||
.doc() | ||
registry.service('myservice') | ||
.provides([logger, onlyOnce, myservice]) | ||
``` | ||
Docstrings can be used to store info about services. | ||
This is the equivalent of: | ||
```js | ||
registry.service('myservice') | ||
.provides(logger(onlyOnce(myservice))) | ||
``` | ||
You can find many examples of what you can do with decorators on [async-deco](https://github.com/sithmel/async-deco) and on [diogenes-utils](https://github.com/sithmel/diogenes-utils). This one in particular, contains a decorator that caches a service. | ||
```js | ||
const cacheService = require('diogenes-utils').cacheService | ||
registry.service('myservice') | ||
.provides([ | ||
cacheService({ len: 3, ttl: 10000 }), | ||
myservice | ||
]) | ||
``` | ||
@@ -237,2 +283,9 @@ Syntax | ||
Diogenes.getRegistryRunner | ||
-------------------- | ||
Create a registry runner instance: | ||
```js | ||
const registry = Diogenes.getRegistryRunner(); | ||
``` | ||
Registry | ||
@@ -247,7 +300,2 @@ ======== | ||
``` | ||
You can also pass a function (a named function!): | ||
```js | ||
registry.service(name); | ||
``` | ||
Passing a function is equivalent to both defining a service and providing an implementation. | ||
@@ -277,32 +325,3 @@ init | ||
``` | ||
It can also use a callback: | ||
```js | ||
registry.run(serviceName, (err, service) => { | ||
... | ||
}); | ||
``` | ||
The callback uses the node convention (error as first argument). | ||
You can also execute more than one service passing an array of names: | ||
```js | ||
registry.run(['service1', 'service2']) | ||
.then(({ service1, service2 }) => { | ||
... | ||
}) | ||
``` | ||
or using a regular expression: | ||
```js | ||
registry.run(/service[0-9]?/) | ||
.then(({ service1, service2 }) => { | ||
... | ||
}) | ||
``` | ||
You can also pass an object with some extra dependencies to be used for this execution: | ||
```js | ||
registry.run('service2', { service1: 'hello' }) | ||
.then(({ service1, service2 }) => { | ||
... | ||
}) | ||
``` | ||
merge/clone | ||
@@ -314,3 +333,2 @@ ----------- | ||
``` | ||
The state of of services will be preserved. So for example, if a service has already been successfully executed, this won't be executed again. | ||
Calling merge without argument, creates a clone. | ||
@@ -343,4 +361,8 @@ | ||
``` | ||
As an optional argument you can pass an object with some extra dependencies. | ||
missingDeps | ||
----------- | ||
This method returns an array of service names that are not in the registry, but are dependencies of another service. | ||
This can be useful for debugging. | ||
getMetadata | ||
@@ -368,19 +390,3 @@ ------------ | ||
``` | ||
As an optional argument you can pass an object with some extra dependencies. | ||
shutdown | ||
-------- | ||
The purpose of this method is allow all asynchronous call to be terminated before a system shutdown. | ||
After calling this method the service won't execute the "run" method anymore (It will return an exception). The method returns a promise (or a callback). This will be fulfilled when all previous "run" has been fulfilled of rejected. | ||
```js | ||
const A = registry.run('A') | ||
const C = registry.run('C') | ||
registry.shutdown() | ||
.then(() => { | ||
// "A" and "C" are fulfilled | ||
registry.run('B') // rejected with DiogenesShutdownError | ||
}) | ||
``` | ||
Service | ||
@@ -396,8 +402,18 @@ ======= | ||
--------- | ||
It defines the dependencies of a service. It may be an array or a function returning an array of strings (service names) or an array of functions: | ||
It defines the dependencies of a service. It may be an array or an object: | ||
```js | ||
service.dependsOn(array); | ||
service.dependsOn([...]); | ||
service.dependsOn(func); | ||
service.dependsOn({...}); | ||
``` | ||
Using an object you can use the dependencies under different names. For example, this are equivalent: | ||
```js | ||
service.dependsOn(['A', 'B']); | ||
service.dependsOn({ A: 'A', B: 'B' }); | ||
``` | ||
You can use the object like this: | ||
```js | ||
service.dependsOn({ value: 'A' }) | ||
.provides(({ value }) => return value * 2); | ||
``` | ||
@@ -414,16 +430,16 @@ provides | ||
``` | ||
A synchronous function: | ||
Or a synchronous function: | ||
```js | ||
service.provides((deps) => deps.something * 2); | ||
``` | ||
Or callback: | ||
If you pass an array or more than one argument, the first arguments are used to decorate the others: | ||
```js | ||
service.provides((deps, callback) => callback(null, deps.something * 2)); | ||
service.provides(arg1, arg2, arg3, arg4); | ||
// is the equivalent of | ||
service.provides(arg1(arg2(arg3(arg4)))); | ||
``` | ||
The "callback" behaviour is triggered by the extra argument "callback". Do not add that argument if you are not using the callback. Callbacks use the node convention of having the error as first argument and the result as second. | ||
When you pass a function to "provides", the first argument of this function is always a object with an attribute for every dependency. | ||
doc | ||
--- | ||
set/get the documentation string. | ||
get/set the documentation string. | ||
```js | ||
@@ -454,5 +470,49 @@ service.doc(); // returns documentation string | ||
Registry Runner | ||
=============== | ||
This object runs services, keeping track of their execution. | ||
run | ||
--- | ||
This method runs one or more services: | ||
```js | ||
registryRunner.run(service, 'servicename') | ||
``` | ||
by default it returns a promise but can also use a callback (using the node convention): | ||
```js | ||
registryRunner.run(service, 'servicename', (err, res) => { ... }) | ||
``` | ||
you can run multiple services using a regular expression or an array of names. | ||
You can also pass an object with some extra dependencies to be used for this execution: | ||
```js | ||
registry.run('service2', { service1: 'hello' }) | ||
.then(({ service2 }) => { | ||
... | ||
}) | ||
``` | ||
The extra dependencies won't be added to the original registry. | ||
shutdown | ||
-------- | ||
The purpose of this method is to allow all asynchronous call to be terminated before a system shutdown. | ||
After calling this method the registry runner won't execute the "run" method anymore (It will return an exception). The method returns a promise (or uses a callback). This will be fulfilled when all previous "run" has been fulfilled of rejected. | ||
```js | ||
registryRunner.run(registry, 'A') | ||
registryRunner.run(registry, 'C') | ||
registry.shutdown() | ||
.then(() => { | ||
// "A" and "C" are fulfilled | ||
}) | ||
registryRunner.run(registry, 'A') // rejected with DiogenesShutdownError | ||
``` | ||
flush | ||
----- | ||
Flush runs a shutdown and then restore the registry to its normal state. | ||
Compatibility | ||
============= | ||
Diogenes is written is ES6. Please transpile it for using with old browsers/node.js. Also provide a polyfill for Promises and WeakMaps. | ||
Diogenes is written is ES6. Please transpile it for using with old browsers/node.js. Also provide a polyfill for Promises, WeakMaps and Sets. | ||
@@ -459,0 +519,0 @@ Acknowledgements |
@@ -1,6 +0,5 @@ | ||
const uuid = require('uuid/v1') | ||
const Service = require('./service') | ||
const DiogenesError = require('./lib/diogenes-error') | ||
const DiogenesShutdownError = require('./lib/diogenes-shutdown') | ||
const getName = require('./lib/get-name') | ||
const uuid = require('uuid/v1') | ||
const RegistryRunner = require('./registry-runner') | ||
@@ -13,4 +12,2 @@ /* | ||
this.services = {} | ||
this.running = {} | ||
this._isShuttingDown = false | ||
} | ||
@@ -22,14 +19,18 @@ | ||
Registry.prototype.has = function registryHas (nameOrFunc) { | ||
return getName(nameOrFunc) in this.services | ||
Registry.getRegistryRunner = function registryGetRegistryRunner () { | ||
return new RegistryRunner() | ||
} | ||
Registry.prototype.set = function registrySet (nameOrFunc, service) { | ||
this.services[getName(nameOrFunc)] = service | ||
Registry.prototype.has = function registryHas (name) { | ||
return name in this.services | ||
} | ||
Registry.prototype.get = function registryGet (nameOrFunc) { | ||
return this.services[getName(nameOrFunc)] | ||
Registry.prototype.set = function registrySet (name, service) { | ||
this.services[name] = service | ||
} | ||
Registry.prototype.get = function registryGet (name) { | ||
return this.services[name] | ||
} | ||
Registry.prototype.init = function registryInit (funcs) { | ||
@@ -41,12 +42,12 @@ for (const func of funcs) { | ||
Registry.prototype.service = function registryService (nameOrFunc) { | ||
if (typeof nameOrFunc !== 'string' && typeof nameOrFunc !== 'function') { | ||
throw new DiogenesError('Diogenes: the service should be a string or a function') | ||
Registry.prototype.service = function registryService (name) { | ||
if (typeof name !== 'string') { | ||
throw new DiogenesError('Diogenes: the service name should be a string') | ||
} | ||
if (!this.has(nameOrFunc)) { | ||
this.set(nameOrFunc, new Service(nameOrFunc)) | ||
if (!this.has(name)) { | ||
this.set(name, new Service(name)) | ||
} | ||
return this.get(nameOrFunc) | ||
return this.get(name) | ||
} | ||
@@ -62,33 +63,33 @@ | ||
Registry.prototype.addDeps = function registryAddDeps (deps) { | ||
let reg = this.clone() | ||
Object.keys(deps) | ||
.forEach((serviceName) => { | ||
reg.service(serviceName).provides(() => deps[serviceName]) | ||
}) | ||
return reg | ||
Registry.prototype.getAdjList = function registryGetAdjList () { | ||
return this.map((service) => service.depsArray()) | ||
} | ||
Registry.prototype.getAdjList = function registryGetAdjList (deps) { | ||
const reg = deps ? this.addDeps(deps) : this | ||
return reg.map((service) => service.deps()) | ||
Registry.prototype.missingDeps = function registryMissingDeps () { | ||
const adjList = this.getAdjList() | ||
const deps = Object.keys(adjList) | ||
.reduce((accum, key) => { | ||
return accum.concat(adjList[key]) | ||
}, []) | ||
return Array.from(new Set(deps)) | ||
.filter((dep) => !(dep in adjList)) | ||
} | ||
Registry.prototype.getMetadata = function registryGetMetadata (deps) { | ||
const reg = deps ? this.addDeps(deps) : this | ||
return reg.map(function (service) { return service.getMetadata() }) | ||
Registry.prototype.getMetadata = function registryGetMetadata () { | ||
return this.map(function (service) { return service.getMetadata() }) | ||
} | ||
Registry.prototype._run = function registryRun (name, runId) { | ||
Registry.prototype.run = function registryRun (name, runId) { | ||
runId = runId || uuid() | ||
const cache = {} | ||
let c = 0 | ||
const getPromiseFromStr = (nameOfFunc) => { | ||
const getPromiseFromStr = (name) => { | ||
if (c++ > 1000) { | ||
throw new DiogenesError('Diogenes: circular dependency') | ||
} | ||
const service = this.get(nameOfFunc) | ||
const service = this.get(name) | ||
if (!service) { | ||
return Promise.reject(new DiogenesError(`Diogenes: missing dependency: ${getName(nameOfFunc)}`)) | ||
return Promise.reject(new DiogenesError(`Diogenes: missing dependency: ${name}`)) | ||
} | ||
@@ -101,8 +102,9 @@ | ||
const deps = service.deps() | ||
const depsArray = service.depsArray() | ||
if (deps.length === 0) { | ||
cache[service.name] = service._run(runId, {}) | ||
if (depsArray.length === 0) { | ||
cache[service.name] = service.run(runId, {}) | ||
} else { | ||
cache[service.name] = getPromisesFromStrArray(deps) | ||
.then((d) => service._run(runId, d)) | ||
cache[service.name] = getPromisesFromDeps(depsArray, deps) | ||
.then((d) => service.run(runId, d)) | ||
} | ||
@@ -112,9 +114,17 @@ return cache[service.name] | ||
const getPromisesFromStrArray = (strArray) => | ||
Promise.all(strArray.map(getPromiseFromStr)) | ||
const getPromisesFromDeps = (depsArray, depsObj) => | ||
Promise.all(depsArray.map(getPromiseFromStr)) | ||
.then(function (results) { | ||
// map dependencies on an object | ||
const depMap = {} | ||
for (let i = 0; i < depsArray.length; i++) { | ||
depMap[depsArray[i]] = results[i] | ||
} | ||
// map object on another object values | ||
const out = {} | ||
for (var i = 0; i < strArray.length; i++) { | ||
out[strArray[i]] = results[i] | ||
} | ||
Object.keys(depsObj).forEach((key) => { | ||
const value = depMap[depsObj[key]] | ||
out[key] = value | ||
}) | ||
return out | ||
@@ -131,54 +141,8 @@ }) | ||
// clone registry and run. BEWARE: "_run" runs in a different registry (the cloned one) | ||
Registry.prototype.run = function registryRun (name, deps, done) { | ||
done = typeof deps === 'function' ? deps : done | ||
deps = typeof deps === 'object' ? deps : {} | ||
const runId = uuid() | ||
let promise | ||
if (this._isShuttingDown) { | ||
promise = Promise.reject(new DiogenesShutdownError('Diogenes: shutting down')) | ||
} else { | ||
const tempreg = this.addDeps(deps) | ||
if (typeof name === 'string' || typeof name === 'function') { | ||
promise = tempreg._run(getName(name), runId) | ||
} else { | ||
if (name instanceof RegExp) { | ||
name = Object.keys(this.services).filter(RegExp.prototype.test.bind(name)) | ||
} else if (Array.isArray(name)) { | ||
name = name.map(getName) | ||
} | ||
tempreg.service('__temp__').dependsOn(name) | ||
.provides(function (deps) { | ||
return Promise.resolve(deps) | ||
}) | ||
promise = tempreg._run('__temp__', runId) | ||
} | ||
} | ||
const promiseWithCleanUp = promise | ||
.then((res) => { | ||
delete this.running[runId] | ||
return Promise.resolve(res) | ||
Registry.prototype.addDeps = function registryAddDeps (deps) { | ||
Object.keys(deps) | ||
.forEach((serviceName) => { | ||
this.service(serviceName).provides(deps[serviceName]) | ||
}) | ||
.catch((err) => { | ||
delete this.running[runId] | ||
return Promise.reject(err) | ||
}) | ||
this.running[runId] = promiseWithCleanUp | ||
if (done) { | ||
promiseWithCleanUp | ||
.then((res) => { | ||
done(null, res) | ||
}) | ||
.catch((err) => { | ||
done(err) | ||
}) | ||
return this | ||
} else { | ||
return promiseWithCleanUp | ||
} | ||
return this | ||
} | ||
@@ -200,43 +164,2 @@ | ||
Registry.prototype.shutdown = function registryShutdown (done) { | ||
this._isShuttingDown = true | ||
var promise = Promise.all(Object.keys(this.running) | ||
.map((key) => this.running[key].catch(() => Promise.resolve(null)))) | ||
if (done) { | ||
promise | ||
.then(function (res) { | ||
done(null, res) | ||
}) | ||
.catch(function (err) { | ||
done(err) | ||
}) | ||
return this | ||
} else { | ||
return promise | ||
} | ||
} | ||
Registry.prototype.flush = function registryFlush (done) { | ||
const promise = this.shutdown() | ||
.then(() => { | ||
this._isShuttingDown = false | ||
return Promise.resolve(null) | ||
}) | ||
if (done) { | ||
promise | ||
.then(function (res) { | ||
done(null, res) | ||
}) | ||
.catch(function (err) { | ||
done(err) | ||
}) | ||
return this | ||
} else { | ||
return promise | ||
} | ||
} | ||
module.exports = Registry |
@@ -1,4 +0,3 @@ | ||
const promisify = require('es6-promisify').promisify | ||
const getName = require('./lib/get-name') | ||
const DiogenesError = require('./lib/diogenes-error') | ||
const compose = require('./lib/compose') | ||
@@ -30,24 +29,6 @@ /* | ||
function extractDocString (f) { | ||
const str = f.toString() | ||
const re = /\/\*\*(.+?)\*\*\// | ||
const match = re.exec(str) | ||
if (match) { | ||
return match[1] | ||
} | ||
} | ||
function Service (nameOrFunc) { | ||
function Service (name) { | ||
this._doc = '' | ||
this._deps = [] | ||
this.name = getName(nameOrFunc) | ||
if (!this.name) { | ||
throw new DiogenesError('The service must have a name. Use either a string or a named function') | ||
} | ||
if (typeof nameOrFunc === 'function') { | ||
this._debugInfo = getDebugInfo(nameOrFunc, 3) | ||
this._provides(nameOrFunc) | ||
this.doc(extractDocString(nameOrFunc)) | ||
} | ||
this._deps = {} | ||
this.name = name | ||
} | ||
@@ -64,9 +45,13 @@ | ||
Service.prototype.deps = function serviceDeps () { | ||
return this._deps.map(getName) | ||
return this._deps | ||
} | ||
Service.prototype.depsArray = function serviceDepsArray () { | ||
return Array.from(new Set(Object.values(this._deps))) | ||
} | ||
Service.prototype.getMetadata = function serviceGetMetadata () { | ||
return { | ||
name: this.name, | ||
deps: this.deps(), | ||
deps: this.depsArray(), | ||
doc: this.doc(), | ||
@@ -78,3 +63,14 @@ debugInfo: this._debugInfo | ||
Service.prototype.dependsOn = function serviceDependsOn (deps) { | ||
this._deps = deps | ||
if (Array.isArray(deps)) { | ||
this._deps = deps.reduce((acc, value) => { | ||
acc[value] = value | ||
return acc | ||
}, {}) | ||
} else if (typeof deps === 'object') { | ||
this._deps = deps | ||
} else if (typeof deps === 'undefined') { | ||
this._deps = {} | ||
} else { | ||
throw new DiogenesError('Dependency can be an array, an object or undefined') | ||
} | ||
return this | ||
@@ -84,27 +80,16 @@ } | ||
Service.prototype.provides = function serviceProvides (func) { | ||
this._debugInfo = getDebugInfo(func, 2) | ||
return this._provides(func) | ||
} | ||
Service.prototype._provides = function serviceProvides (func) { | ||
if (this._func) { | ||
throw new DiogenesError(`You already defined a function for ${this.name}`) | ||
func = arguments.length > 1 ? Array.prototype.slice.call(arguments, 0) : func | ||
let originalFunction, resultingFunction | ||
if (Array.isArray(func)) { | ||
originalFunction = func[func.length - 1] | ||
resultingFunction = compose(func.slice(0, -1))(originalFunction) | ||
} else { | ||
originalFunction = func | ||
resultingFunction = func | ||
} | ||
if (typeof func !== 'function') { | ||
this._debugInfo = getDebugInfo(originalFunction, 2) | ||
if (typeof resultingFunction !== 'function') { | ||
this._func = function () { return Promise.resolve(func) } // plain value | ||
} else if (func.length > 1) { | ||
this._func = promisify(func) // callback function | ||
} else { | ||
this._func = function (deps) { // sync function or return promise | ||
try { | ||
var res = func(deps) | ||
} catch (e) { | ||
return Promise.reject(e) | ||
} | ||
if (res instanceof Object && 'then' in res) { | ||
return res | ||
} else { | ||
return Promise.resolve(res) | ||
} | ||
} | ||
this._func = resultingFunction | ||
} | ||
@@ -114,7 +99,8 @@ return this | ||
Service.prototype._run = function serviceRun (id, deps) { | ||
Service.prototype.run = function serviceRun (id, deps) { | ||
const context = { id: id, service: this } | ||
return this._func.call(context, deps) | ||
return Promise.resolve() | ||
.then(() => this._func.call(context, deps)) | ||
} | ||
module.exports = Service |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
1
834
511
120171
18
1
- Removedes6-promisify@^6.0.0
- Removedes6-promisify@6.1.1(transitive)