Comparing version 3.2.0 to 4.0.0
{ | ||
"name": "diogenes", | ||
"version": "3.2.0", | ||
"version": "4.0.0", | ||
"description": "A dependency injection framework.", | ||
@@ -10,5 +10,5 @@ "main": "src/index.js", | ||
"lint": "eslint --fix --ext .js ./src ./tests", | ||
"release:major": "./node_modules/.bin/npm-release major", | ||
"release:minor": "./node_modules/.bin/npm-release minor", | ||
"release:patch": "./node_modules/.bin/npm-release patch", | ||
"release:major": "npm-release major", | ||
"release:minor": "npm-release minor", | ||
"release:patch": "npm-release patch", | ||
"precommit": "npm run lint", | ||
@@ -39,5 +39,5 @@ "prepush": "npm run test" | ||
"es6-promisify": "^6.0.0", | ||
"object-assign": "^4.1.1", | ||
"little-ds-toolkit": "^1.0.0", | ||
"uuid": "^3.2.1" | ||
} | ||
} |
@@ -141,3 +141,3 @@ Diogenes | ||
console.log("This paragraph is " + p.count + " words long"); | ||
console.log("The abstract is: " + p.anstract); | ||
console.log("The abstract is: " + p.abstract); | ||
console.log("This is the original text:"); | ||
@@ -156,3 +156,3 @@ console.log(p.text); | ||
console.log("This paragraph is " + p.count + " words long"); | ||
console.log("The abstract is: " + p.anstract); | ||
console.log("The abstract is: " + p.abstract); | ||
console.log("This is the original text:"); | ||
@@ -177,2 +177,65 @@ console.log(p.text); | ||
Using function references | ||
========================= | ||
"service" and "dependsOn" allow to use function references instead of strings (the functions should have a name!): | ||
```js | ||
registry | ||
.service(function service2 (deps) { | ||
// ... function implementation ... | ||
}) | ||
.dependsOn([service2]); | ||
``` | ||
is equivalent to: | ||
```js | ||
registry | ||
.service('service2') | ||
.provides((deps) => { | ||
// ... function implementation ... | ||
}) | ||
.dependsOn(['service2']); | ||
``` | ||
Caching | ||
======= | ||
When you run a service, diogenes ensures you only execute a service once. There are cases in which you want to cache the output of a service between different executions. You can do so setting the cache. | ||
```js | ||
registry | ||
.service('service1') | ||
.provides((deps) => { /* ... */ }) | ||
.setCache({ len: 1 }) | ||
``` | ||
The cache depends on the service dependencies, so you are going to use the cached value only if the dependencies didn't change. Objects are compared by reference. You can set 2 cache options: | ||
* **len**: number of cached version to store | ||
* **ttl**: time to live in ms | ||
The len is mandatory. | ||
Here's some guideline: | ||
* if you want to execute something only once set "len: 1" and ensure the dependencies are cached in the same way | ||
* for pure functions, only use "len" | ||
* for functions with side effects you can decide to not use caching, in this way they are executed every time. But you can also apply a bit of caching (if the service only READ data), in this case you should use both len and ttl. | ||
Docstring | ||
========= | ||
You can define a docstring in 2 ways: | ||
```js | ||
registry | ||
.service('service1') | ||
.doc('this is some helpful information') | ||
``` | ||
or | ||
```js | ||
registry | ||
.service(function service1(deps) { | ||
/** | ||
this is some helpful information | ||
**/ | ||
}) | ||
``` | ||
And you can retrieve a docString with: | ||
```js | ||
registry | ||
.service('service1') | ||
.doc() | ||
``` | ||
Docstrings can be used to store info about services. | ||
Syntax | ||
@@ -201,2 +264,7 @@ ====== | ||
``` | ||
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. | ||
@@ -248,2 +316,9 @@ init | ||
``` | ||
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 }) => { | ||
... | ||
}) | ||
``` | ||
@@ -284,2 +359,3 @@ merge/clone | ||
``` | ||
As an optional argument you can pass an object with some extra dependencies. | ||
@@ -309,2 +385,3 @@ getMetadata | ||
``` | ||
As an optional argument you can pass an object with some extra dependencies. | ||
@@ -336,3 +413,3 @@ shutdown | ||
--------- | ||
It defines the dependencies of a service. It may be an array or a function returning an array of strings (service names): | ||
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: | ||
```js | ||
@@ -396,3 +473,3 @@ service.dependsOn(array); | ||
============= | ||
Diogenes is written is ES5 but it requires "Promise" support. Please provide a polyfill in the global namespace if promises are not supported. | ||
Diogenes is written is ES6. Please transpile it for using with old browsers/node.js. Also provide a polyfill for Promises and WeakMaps. | ||
@@ -399,0 +476,0 @@ Acknowledgements |
@@ -1,2 +0,2 @@ | ||
var Registry = require('./registry') | ||
const Registry = require('./registry') | ||
module.exports = Registry |
@@ -1,6 +0,6 @@ | ||
var assign = require('object-assign') | ||
var uuid = require('uuid/v1') | ||
var Service = require('./service') | ||
var DiogenesError = require('./lib/diogenes-error') | ||
var DiogenesShutdownError = require('./lib/diogenes-shutdown') | ||
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') | ||
@@ -21,18 +21,30 @@ /* | ||
Registry.prototype.has = function registryHas (nameOrFunc) { | ||
return getName(nameOrFunc) in this.services | ||
} | ||
Registry.prototype.set = function registrySet (nameOrFunc, service) { | ||
this.services[getName(nameOrFunc)] = service | ||
} | ||
Registry.prototype.get = function registryGet (nameOrFunc) { | ||
return this.services[getName(nameOrFunc)] | ||
} | ||
Registry.prototype.init = function registryInit (funcs) { | ||
for (var i = 0; i < funcs.length; i++) { | ||
funcs[i].call(this, this) | ||
for (const func of funcs) { | ||
func.call(this, this) | ||
} | ||
} | ||
Registry.prototype.service = function registryService (name) { | ||
if (typeof name !== 'string') { | ||
throw new DiogenesError('Diogenes: the name of the service should be a string') | ||
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') | ||
} | ||
if (!(name in this.services)) { | ||
this.services[name] = new Service(name) | ||
if (!this.has(nameOrFunc)) { | ||
this.set(nameOrFunc, new Service(nameOrFunc)) | ||
} | ||
return this.services[name] | ||
return this.get(nameOrFunc) | ||
} | ||
@@ -42,49 +54,60 @@ | ||
var out = {} | ||
Object.keys(this.services) | ||
.map(this.service.bind(this)) | ||
.forEach(function (service) { | ||
out[service.name] = func(service) | ||
}) | ||
for (const service of Object.values(this.services)) { | ||
out[service.name] = func(service) | ||
} | ||
return out | ||
} | ||
Registry.prototype.getAdjList = function registryGetAdjList () { | ||
return this.map(function (service) { return service._deps() }) | ||
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.getMetadata = function registryGetAdjList () { | ||
return this.map(function (service) { return service.getMetadata() }) | ||
Registry.prototype.getAdjList = function registryGetAdjList (deps) { | ||
const reg = deps ? this.addDeps(deps) : this | ||
return reg.map((service) => service.deps()) | ||
} | ||
Registry.prototype._run = function registryRun (name) { | ||
var registry = this | ||
var c = 0 | ||
var runId = uuid() | ||
var promise | ||
Registry.prototype.getMetadata = function registryGetMetadata (deps) { | ||
const reg = deps ? this.addDeps(deps) : this | ||
return reg.map(function (service) { return service.getMetadata() }) | ||
} | ||
if (this._isShuttingDown) { | ||
return Promise.reject(new DiogenesShutdownError('Diogenes: shutting down')) | ||
} | ||
Registry.prototype._run = function registryRun (name, runId) { | ||
const cache = {} | ||
let c = 0 | ||
function getPromiseFromStr (str) { | ||
const getPromiseFromStr = (nameOfFunc) => { | ||
if (c++ > 1000) { | ||
throw new DiogenesError('Diogenes: circular dependency') | ||
} | ||
if (!(str in registry.services)) { | ||
return Promise.reject(new DiogenesError('Diogenes: missing dependency: ' + str)) | ||
const service = this.get(nameOfFunc) | ||
if (!service) { | ||
return Promise.reject(new DiogenesError(`Diogenes: missing dependency: ${getName(nameOfFunc)}`)) | ||
} | ||
var deps = registry.services[str]._getDeps() | ||
if (service.name in cache) { | ||
return cache[service.name] | ||
} | ||
const deps = service.deps() | ||
if (deps.length === 0) { | ||
return registry.services[str]._run(runId, {}) | ||
cache[service.name] = service._run(runId, {}) | ||
} else { | ||
cache[service.name] = getPromisesFromStrArray(deps) | ||
.then((d) => service._run(runId, d)) | ||
} | ||
return getPromisesFromStrArray(deps) | ||
.then(registry.services[str]._run.bind(registry.services[str], runId)) | ||
return cache[service.name] | ||
} | ||
function getPromisesFromStrArray (strArray) { | ||
return Promise.all(strArray.map(getPromiseFromStr)) | ||
const getPromisesFromStrArray = (strArray) => | ||
Promise.all(strArray.map(getPromiseFromStr)) | ||
.then(function (results) { | ||
var out = {} | ||
const out = {} | ||
for (var i = 0; i < strArray.length; i++) { | ||
@@ -95,18 +118,7 @@ out[strArray[i]] = results[i] | ||
}) | ||
} | ||
try { | ||
promise = getPromiseFromStr(name) | ||
.then(function (res) { | ||
delete registry.running[runId] | ||
return Promise.resolve(res) | ||
}) | ||
.catch(function (err) { | ||
delete registry.running[runId] | ||
return Promise.reject(err) | ||
}) | ||
registry.running[runId] = promise | ||
const promise = getPromiseFromStr(name) | ||
return promise | ||
} catch (e) { | ||
delete registry.running[runId] | ||
return Promise.reject(e) | ||
@@ -116,26 +128,48 @@ } | ||
Registry.prototype.run = function registryRun (name, done) { | ||
var promise | ||
if (typeof name === 'string') { | ||
promise = this._run(name, done) | ||
// 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 { | ||
if (name instanceof RegExp) { | ||
name = Object.keys(this.services).filter(RegExp.prototype.test.bind(name)) | ||
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) | ||
} | ||
} | ||
var tempreg = this.clone() | ||
const promiseWithCleanUp = promise | ||
.then((res) => { | ||
delete this.running[runId] | ||
return Promise.resolve(res) | ||
}) | ||
.catch((err) => { | ||
delete this.running[runId] | ||
return Promise.reject(err) | ||
}) | ||
tempreg.service('__temp__').dependsOn(name) | ||
.provides(function (deps) { | ||
return Promise.resolve(deps) | ||
}) | ||
promise = tempreg.run('__temp__') | ||
} | ||
this.running[runId] = promiseWithCleanUp | ||
if (done) { | ||
promise | ||
.then(function (res) { | ||
promiseWithCleanUp | ||
.then((res) => { | ||
done(null, res) | ||
}) | ||
.catch(function (err) { | ||
.catch((err) => { | ||
done(err) | ||
@@ -145,3 +179,3 @@ }) | ||
} else { | ||
return promise | ||
return promiseWithCleanUp | ||
} | ||
@@ -160,3 +194,3 @@ } | ||
registry.services = assign.apply(null, services) | ||
registry.services = Object.assign.apply(null, services) | ||
return registry | ||
@@ -166,10 +200,6 @@ } | ||
Registry.prototype.shutdown = function registryShutdown (done) { | ||
var registry = this | ||
registry._isShuttingDown = true | ||
this._isShuttingDown = true | ||
var promise = Promise.all(Object.keys(registry.running) | ||
.map(function (key) { | ||
return registry.running[key] | ||
.catch(function () { return Promise.resolve(null) }) | ||
})) | ||
var promise = Promise.all(Object.keys(this.running) | ||
.map((key) => this.running[key].catch(() => Promise.resolve(null)))) | ||
@@ -190,2 +220,23 @@ if (done) { | ||
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 |
@@ -0,16 +1,23 @@ | ||
const promisify = require('es6-promisify').promisify | ||
const LRUCache = require('little-ds-toolkit/lib/lru-cache') | ||
const getName = require('./lib/get-name') | ||
const DiogenesError = require('./lib/diogenes-error') | ||
const DepsToKey = require('./lib/deps-to-key') | ||
const depsToKey = new DepsToKey() | ||
/* | ||
Service object | ||
*/ | ||
var promisify = require('es6-promisify').promisify | ||
function getDebugInfo (func) { | ||
function getDebugInfo (func, stackLevel) { | ||
try { | ||
var orig = Error.prepareStackTrace | ||
const orig = Error.prepareStackTrace | ||
Error.prepareStackTrace = function (_, stack) { | ||
return stack | ||
} | ||
var err = new Error() | ||
var stack = err.stack | ||
const err = new Error() | ||
const stack = err.stack | ||
Error.prepareStackTrace = orig | ||
var stackItem = stack[2] | ||
const stackItem = stack[stackLevel] | ||
return { | ||
@@ -27,10 +34,44 @@ line: stackItem.getLineNumber(), | ||
function Service (name) { | ||
this.name = name | ||
function extractDocString (f) { | ||
const str = f.toString() | ||
const re = /\/\*\*(.+?)\*\*\// | ||
const match = re.exec(str) | ||
if (match) { | ||
return match[1].trim() | ||
} | ||
} | ||
function Service (nameOrFunc) { | ||
this._doc = '' | ||
this._deps = function () { return [] } | ||
this._func = function () { return Promise.resolve() } | ||
this._cache = undefined | ||
this._doc = '' | ||
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)) | ||
} | ||
} | ||
Service.prototype.disableCache = function serviceDisableCache () { | ||
this.cache = undefined | ||
return this | ||
} | ||
Service.prototype.setCache = function serviceSetCache (opts) { | ||
if (typeof opts !== 'object') { | ||
throw new Error('You should pass an option object with "len" and "ttl" (optional)') | ||
} | ||
if (!('len' in opts)) { | ||
throw new Error('You should define a the length of the cache (len)') | ||
} | ||
const defaultTTL = opts.ttl | ||
const maxLen = opts.len | ||
this.cache = new LRUCache({ maxLen, defaultTTL }) | ||
return this | ||
} | ||
Service.prototype.doc = function serviceDoc (text) { | ||
@@ -44,8 +85,12 @@ if (typeof text === 'undefined') { | ||
Service.prototype.deps = function serviceDeps () { | ||
return this._deps().map(getName) | ||
} | ||
Service.prototype.getMetadata = function serviceGetMetadata () { | ||
return { | ||
name: this.name, | ||
deps: this._deps(), | ||
deps: this.deps(), | ||
doc: this.doc(), | ||
cached: !!this._cache, | ||
cache: this.cache ? { len: this.cache.maxLen, ttl: this.cache.defaultTTL } : false, | ||
debugInfo: this._debugInfo | ||
@@ -61,5 +106,12 @@ } | ||
Service.prototype.provides = function serviceProvides (func) { | ||
this._debugInfo = getDebugInfo(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}`) | ||
} | ||
if (typeof func !== 'function') { | ||
this._func = function () { Promise.resolve(func) } // plain value | ||
this._func = function () { return Promise.resolve(func) } // plain value | ||
} else if (func.length > 1) { | ||
@@ -85,19 +137,18 @@ this._func = promisify(func) // callback function | ||
Service.prototype._run = function serviceRun (id, deps) { | ||
var service = this | ||
var context = { id: id, service: service } | ||
if (service._cache) { | ||
return service._cache | ||
const context = { id: id, service: this } | ||
if (!this.cache) { // uncached | ||
return this._func.call(context, deps) | ||
} | ||
service._cache = service._func.call(context, deps) | ||
.catch(function (err) { | ||
service._cache = undefined | ||
return Promise.reject(err) | ||
// cached | ||
const cacheKey = depsToKey.getIdFromValues(deps) | ||
if (this.cache.has(cacheKey)) { | ||
return Promise.resolve(this.cache.get(cacheKey)) | ||
} | ||
return this._func.call(context, deps) | ||
.then((value) => { | ||
this.cache.set(cacheKey, value) | ||
return value | ||
}) | ||
return service._cache | ||
} | ||
Service.prototype._getDeps = function serviceGetDeps () { | ||
return this._cache ? [] : this._deps() | ||
} | ||
module.exports = Service |
/* eslint-env node, mocha */ | ||
var Diogenes = require('../src') | ||
var assert = require('chai').assert | ||
const Diogenes = require('../src') | ||
const assert = require('chai').assert | ||
describe('async parallel execution', function (done) { | ||
var str, registry | ||
describe('async parallel execution', (done) => { | ||
let str, registry | ||
@@ -46,3 +46,3 @@ beforeEach(function () { | ||
it('must run service asynchronously', function (done) { | ||
it('must run service asynchronously', (done) => { | ||
registry.run('C', function (err, dep) { | ||
@@ -49,0 +49,0 @@ if (err) return |
/* eslint-env node, mocha */ | ||
var Diogenes = require('../src') | ||
var assert = require('chai').assert | ||
const Diogenes = require('../src') | ||
const assert = require('chai').assert | ||
describe('dfs: 4 functions', function (done) { | ||
var registry | ||
describe('dfs: 4 functions', (done) => { | ||
let registry | ||
@@ -39,3 +39,3 @@ beforeEach(function () { | ||
it('must return leftmost service', function (done) { | ||
it('must return leftmost service', (done) => { | ||
registry.run('A', function (err, dep) { | ||
@@ -48,3 +48,3 @@ if (err) return | ||
it('must return middle service (1)', function (done) { | ||
it('must return middle service (1)', (done) => { | ||
registry.run('B', function (err, dep) { | ||
@@ -57,3 +57,3 @@ if (err) return | ||
it('must return middle service (2)', function (done) { | ||
it('must return middle service (2)', (done) => { | ||
registry.run('C', function (err, dep) { | ||
@@ -66,3 +66,3 @@ if (err) return | ||
it('must return rightmost service', function (done) { | ||
it('must return rightmost service', (done) => { | ||
registry.run('D', function (err, dep) { | ||
@@ -75,3 +75,3 @@ if (err) return | ||
it('must return adjList', function () { | ||
it('must return adjList', () => { | ||
assert.deepEqual(registry.getAdjList(), | ||
@@ -86,3 +86,3 @@ { | ||
it('must run without callback', function (done) { | ||
it('must run without callback', (done) => { | ||
registry.run('D') | ||
@@ -94,3 +94,3 @@ setTimeout(function () { | ||
it('must run more than one service', function (done) { | ||
it('must run more than one service', (done) => { | ||
registry.run(['A', 'D'], function (err, deps) { | ||
@@ -104,3 +104,3 @@ if (err) return | ||
it('must run more than one service, no config, no callback', function (done) { | ||
it('must run more than one service, no config, no callback', (done) => { | ||
registry.run(['A', 'D']) | ||
@@ -112,3 +112,3 @@ setTimeout(function () { | ||
it('must run more than one service using regexp', function (done) { | ||
it('must run more than one service using regexp', (done) => { | ||
registry.run(/(A|B)/, function (err, deps) { | ||
@@ -115,0 +115,0 @@ if (err) return |
/* eslint-env node, mocha */ | ||
var Diogenes = require('../src') | ||
var assert = require('chai').assert | ||
var DiogenesError = require('../src/lib/diogenes-error') | ||
const Diogenes = require('../src') | ||
const assert = require('chai').assert | ||
const DiogenesError = require('../src/lib/diogenes-error') | ||
describe('diogenes merge registries', function () { | ||
var registry1, registry2, registry3 | ||
describe('diogenes merge registries', () => { | ||
let registry1, registry2, registry3 | ||
@@ -17,3 +17,3 @@ beforeEach(function () { | ||
it('must be different from previous registries', function () { | ||
it('must be different from previous registries', () => { | ||
assert.notEqual(registry1, registry3) | ||
@@ -28,70 +28,183 @@ assert.notEqual(registry2, registry3) | ||
describe('metadata', function () { | ||
var registry, service1 | ||
describe('diogenes adding additional deps on the fly', () => { | ||
it('add deps on the fly', (done) => { | ||
const registry = Diogenes.getRegistry() | ||
registry | ||
.service('B') | ||
.provides(({ A }) => A) | ||
.dependsOn(['A']) | ||
beforeEach(function () { | ||
registry = Diogenes.getRegistry() | ||
service1 = registry | ||
.service('answer').provides(42).doc('to all the questions') | ||
registry.run('B', { A: 10 }) | ||
.then(res => { | ||
assert.equal(res, 10) | ||
done() | ||
}) | ||
}) | ||
}) | ||
registry.service('question') | ||
.dependsOn(['answer']) | ||
.provides(function theanswer () {}) | ||
.doc('the important bit') | ||
describe('diogenes caching behaviour', () => { | ||
it('executes every time without cache', (done) => { | ||
const registry = Diogenes.getRegistry() | ||
let executeA = 0 | ||
let executeB = 0 | ||
registry.service('A') | ||
.provides(() => { | ||
executeA++ | ||
return 'A' | ||
}) | ||
registry.service('B').dependsOn(['A']) | ||
.provides(() => { | ||
executeB++ | ||
return 'B' | ||
}) | ||
registry.run('B') | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeA, 1) | ||
assert.equal(executeB, 1) | ||
registry.run('B') | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeA, 2) | ||
assert.equal(executeB, 2) | ||
done() | ||
}) | ||
}) | ||
}) | ||
it('must return services metadata', function () { | ||
assert.deepEqual(service1.getMetadata(), { | ||
name: 'answer', | ||
cached: false, | ||
deps: [], | ||
doc: 'to all the questions', | ||
debugInfo: { | ||
line: 33, | ||
functionName: null, | ||
parentFunctionName: null, | ||
fileName: __filename | ||
} | ||
}) | ||
it('executes only once with cache', (done) => { | ||
const registry = Diogenes.getRegistry() | ||
let executeA = 0 | ||
let executeB = 0 | ||
registry.service('A') | ||
.provides(() => { | ||
executeA++ | ||
return 'A' | ||
}) | ||
registry.service('B').dependsOn(['A']) | ||
.provides(() => { | ||
executeB++ | ||
return 'B' | ||
}) | ||
.setCache({ len: 1 }) | ||
registry.run('B') | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeA, 1) | ||
assert.equal(executeB, 1) | ||
registry.run('B') | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeA, 2) | ||
assert.equal(executeB, 1) | ||
done() | ||
}) | ||
}) | ||
}) | ||
it('must return registry metadata', function () { | ||
assert.deepEqual(registry.getMetadata(), { | ||
answer: { | ||
name: 'answer', | ||
cached: false, | ||
deps: [], | ||
doc: 'to all the questions', | ||
debugInfo: { | ||
line: 33, | ||
functionName: null, | ||
parentFunctionName: null, | ||
fileName: __filename | ||
} | ||
}, | ||
question: { | ||
name: 'question', | ||
cached: false, | ||
deps: ['answer'], | ||
doc: 'the important bit', | ||
debugInfo: { | ||
line: 37, | ||
functionName: 'theanswer', | ||
parentFunctionName: null, | ||
fileName: __filename | ||
} | ||
} | ||
}) | ||
it('executes only once with cache', (done) => { | ||
const registry = Diogenes.getRegistry() | ||
let executeB = 0 | ||
registry.service('B').dependsOn(['A']) | ||
.provides(() => { | ||
executeB++ | ||
return 'B' | ||
}) | ||
.setCache({ len: 1 }) | ||
registry.run('B', { A: 'A' }) | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeB, 1) | ||
registry.run('B', { A: 'A' }) | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeB, 1) | ||
done() | ||
}) | ||
}) | ||
}) | ||
it('executes twice with cache invalidation', (done) => { | ||
const registry = Diogenes.getRegistry() | ||
let executeB = 0 | ||
registry.service('B').dependsOn(['A']) | ||
.provides(() => { | ||
executeB++ | ||
return 'B' | ||
}) | ||
.setCache({ len: 1 }) | ||
registry.run('B', { A: 'A' }) | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeB, 1) | ||
registry.run('B', { A: 'A2' }) | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeB, 2) | ||
done() | ||
}) | ||
}) | ||
}) | ||
it('executes only once with cache (and ttl)', (done) => { | ||
const registry = Diogenes.getRegistry() | ||
let executeB = 0 | ||
registry.service('B').dependsOn(['A']) | ||
.provides(() => { | ||
executeB++ | ||
return 'B' | ||
}) | ||
.setCache({ len: 1, ttl: 5 }) | ||
registry.run('B', { A: 'A' }) | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeB, 1) | ||
registry.run('B', { A: 'A' }) | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeB, 1) | ||
done() | ||
}) | ||
}) | ||
}) | ||
it('executes twice with cache (and ttl)', (done) => { | ||
const registry = Diogenes.getRegistry() | ||
let executeB = 0 | ||
registry.service('B').dependsOn(['A']) | ||
.provides(() => { | ||
executeB++ | ||
return 'B' | ||
}) | ||
.setCache({ len: 1, ttl: 5 }) | ||
registry.run('B', { A: 'A' }) | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeB, 1) | ||
setTimeout(() => { | ||
registry.run('B', { A: 'A' }) | ||
.then(res => { | ||
assert.equal(res, 'B') | ||
assert.equal(executeB, 2) | ||
done() | ||
}) | ||
}, 10) | ||
}) | ||
}) | ||
}) | ||
describe('registry', function () { | ||
var registry | ||
describe('registry', () => { | ||
let registry | ||
beforeEach(function () { | ||
beforeEach(() => { | ||
registry = Diogenes.getRegistry() | ||
}) | ||
describe('init', function () { | ||
it('must run with right context', function () { | ||
describe('init', () => { | ||
it('must run with right context', () => { | ||
registry.init([function () { | ||
@@ -103,3 +216,3 @@ assert.equal(registry, this) | ||
it('must return a service in a simple case (1 function)', function (done) { | ||
it('must return a service in a simple case (1 function)', (done) => { | ||
registry.service('hello').provides(function (deps, next) { | ||
@@ -117,3 +230,3 @@ assert.deepEqual(deps, {}) | ||
it('must return undefined (1 function)', function (done) { | ||
it('must return undefined (1 function)', (done) => { | ||
registry.run('hello', function (err, dep) { | ||
@@ -126,3 +239,3 @@ assert.equal(err.message, 'Diogenes: missing dependency: hello') | ||
it('must return an exception if the function fails', function (done) { | ||
it('must return an exception if the function fails', (done) => { | ||
registry.service('hello').provides(function (deps) { | ||
@@ -139,3 +252,3 @@ throw new Error('broken') | ||
it('must return a service in a simple case (2 functions)', function (done) { | ||
it('must return a service in a simple case (2 functions)', (done) => { | ||
registry.service('hello').provides(function (deps, next) { | ||
@@ -162,3 +275,3 @@ assert.typeOf(this.id, 'string') | ||
it('must return a service in a simple case (2 functions) not using next', function (done) { | ||
it('must return a service in a simple case (2 functions) not using next', (done) => { | ||
registry.service('hello').provides(function (deps) { | ||
@@ -181,3 +294,3 @@ assert.deepEqual(deps, {}) | ||
it('must return a service in a simple case (2 functions), dependencies are a function', function (done) { | ||
it('must return a service in a simple case (2 functions), dependencies are a function', (done) => { | ||
registry.service('hello').provides(function (deps, next) { | ||
@@ -192,3 +305,3 @@ assert.deepEqual(deps, {}) | ||
registry.service('world').dependsOn(getDeps).provides(function (deps, next) { | ||
registry.service('world').dependsOn(getDeps).provides((deps, next) => { | ||
assert.deepEqual(deps, {hello: 'hello '}) | ||
@@ -205,3 +318,3 @@ next(undefined, deps.hello + 'world!') | ||
it('must recognize a circular dependency', function (done) { | ||
it('must recognize a circular dependency', (done) => { | ||
registry.service('hello').dependsOn(['world']).provides(function (deps, next) { | ||
@@ -222,3 +335,3 @@ next(undefined, 'hello ') | ||
it('must recognize a circular dependency (3 services)', function (done) { | ||
it('must recognize a circular dependency (3 services)', (done) => { | ||
registry.service('A').dependsOn(['C']).provides(function (deps, next) { | ||
@@ -243,3 +356,3 @@ next(undefined, undefined) | ||
it('must throw an exception when missing dependency', function (done) { | ||
it('must throw an exception when missing dependency', (done) => { | ||
registry.service('hello').dependsOn(['world']).provides(function (deps, next) { | ||
@@ -256,5 +369,5 @@ next(undefined, 'hello ') | ||
describe('shutdown', function () { | ||
it('must wait to shutdown', function (done) { | ||
var services = '' | ||
describe('shutdown', () => { | ||
it('must wait to shutdown', (done) => { | ||
let services = '' | ||
@@ -275,3 +388,3 @@ registry.service('A').provides(function (deps, next) { | ||
registry.service('C').dependsOn(['A']).provides(function (deps, next) { | ||
registry.service('C').dependsOn(['A', 'B']).provides(function (deps, next) { | ||
setTimeout(function () { | ||
@@ -283,4 +396,4 @@ services += 'C' | ||
registry.run('B') | ||
registry.run('C') | ||
registry.run('B') // AB | ||
registry.run('C') // ABC | ||
registry.shutdown(function () { | ||
@@ -290,3 +403,3 @@ registry.run('B', function (err) { | ||
}) | ||
assert.equal(services, 'ABC') | ||
assert.equal(services, 'AABBC') | ||
done() | ||
@@ -296,3 +409,3 @@ }) | ||
it('must wait to shutdown, also failing methods', function (done) { | ||
it('must wait to shutdown, also failing methods', (done) => { | ||
var services = '' | ||
@@ -299,0 +412,0 @@ |
Sorry, the diff of this file is not supported yet
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
172588
22
1083
472
+ Addedlittle-ds-toolkit@^1.0.0
+ Addedlittle-ds-toolkit@1.1.1(transitive)
- Removedobject-assign@^4.1.1
- Removedobject-assign@4.1.1(transitive)