knifecycle
Advanced tools
Comparing version 1.1.2 to 1.2.0
@@ -8,2 +8,4 @@ 'use strict'; | ||
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
@@ -33,2 +35,3 @@ | ||
var E_BAD_INJECTION = 'E_BAD_INJECTION'; | ||
var DECLARATION_SEPARATOR = ':'; | ||
@@ -180,7 +183,11 @@ // Constants that should use Symbol whenever possible | ||
uniqueServiceProvider[DEPENDENCIES].forEach(function (dependencyName) { | ||
var dependencyProvider = _this._servicesProviders.get(dependencyName); | ||
uniqueServiceProvider[DEPENDENCIES].forEach(function (dependencyDeclaration) { | ||
var serviceName = _pickServiceNameFromDeclaration(dependencyDeclaration); | ||
var dependencyProvider = _this._servicesProviders.get(serviceName); | ||
if (dependencyProvider && -1 !== dependencyProvider[DEPENDENCIES].indexOf(serviceName)) { | ||
throw new _yerror2.default(E_CIRCULAR_DEPENDENCY, dependencyName, serviceName); | ||
if (dependencyProvider && dependencyProvider[DEPENDENCIES].some(function (childDependencyDeclaration) { | ||
var childServiceName = _pickServiceNameFromDeclaration(childDependencyDeclaration); | ||
return childServiceName === serviceName; | ||
})) { | ||
throw new _yerror2.default(E_CIRCULAR_DEPENDENCY, dependencyDeclaration, serviceName); | ||
} | ||
@@ -196,3 +203,3 @@ }); | ||
* Decorator to claim that a service depends on others ones. | ||
* @param {String[]} dependenciesNames Dependencies the decorated service provider depends on. | ||
* @param {String[]} dependenciesDeclarations Dependencies the decorated service provider depends on. | ||
* @param {Function} serviceProvider Service provider or a service provider promise | ||
@@ -229,9 +236,9 @@ * @return {Function} Returns the decorator function | ||
key: 'depends', | ||
value: function depends(dependenciesNames, serviceProvider) { | ||
value: function depends(dependenciesDeclarations, serviceProvider) { | ||
// eslint-disable-line | ||
var uniqueServiceProvider = serviceProvider.bind(); | ||
uniqueServiceProvider[DEPENDENCIES] = (serviceProvider[DEPENDENCIES] || []).concat(dependenciesNames); | ||
uniqueServiceProvider[DEPENDENCIES] = (serviceProvider[DEPENDENCIES] || []).concat(dependenciesDeclarations); | ||
debug('Wrapped a service provider with dependencies:', dependenciesNames); | ||
debug('Wrapped a service provider with dependencies:', dependenciesDeclarations); | ||
@@ -243,3 +250,3 @@ return uniqueServiceProvider; | ||
* Creates a new execution silo | ||
* @param {String[]} dependenciesNames Service name. | ||
* @param {String[]} dependenciesDeclarations Service name. | ||
* @return {Promise} Service descriptor promise Returns the decorator function | ||
@@ -261,3 +268,3 @@ * @example | ||
key: 'run', | ||
value: function run(dependenciesNames) { | ||
value: function run(dependenciesDeclarations) { | ||
var _this2 = this; | ||
@@ -307,4 +314,4 @@ | ||
} | ||
if (reversedServiceSequence.some(function (servicesNames) { | ||
return servicesNames.includes(serviceName); | ||
if (reversedServiceSequence.some(function (servicesDeclarations) { | ||
return servicesDeclarations.includes(serviceName); | ||
})) { | ||
@@ -326,8 +333,8 @@ debug('Delaying service shutdown:', serviceName); | ||
siloContext.servicesDescriptors.set(INJECT, { | ||
servicePromise: Promise.resolve(function (dependenciesNames) { | ||
return _this2._initializeDependencies(siloContext, siloContext.name, dependenciesNames, true); | ||
servicePromise: Promise.resolve(function (dependenciesDeclarations) { | ||
return _this2._initializeDependencies(siloContext, siloContext.name, dependenciesDeclarations, true); | ||
}) | ||
}); | ||
return this._initializeDependencies(siloContext, siloContext.name, dependenciesNames).then(function (servicesHash) { | ||
return this._initializeDependencies(siloContext, siloContext.name, dependenciesDeclarations).then(function (servicesHash) { | ||
debug('Handling fatal errors:', siloContext.errorsPromises); | ||
@@ -422,3 +429,3 @@ Promise.all(siloContext.errorsPromises).catch(siloContext.throwFatalError); | ||
* @param {String} serviceName Service name. | ||
* @param {String} servicesNames Dependencies names. | ||
* @param {String} servicesDeclarations Dependencies names. | ||
* @param {Boolean} injectOnly Flag indicating if existing services only should be used | ||
@@ -430,3 +437,3 @@ * @return {Promise} Service dependencies hash promise. | ||
key: '_initializeDependencies', | ||
value: function _initializeDependencies(siloContext, serviceName, servicesNames) { | ||
value: function _initializeDependencies(siloContext, serviceName, servicesDeclarations) { | ||
var _this3 = this; | ||
@@ -436,10 +443,10 @@ | ||
debug('Initializing dependencies:', serviceName, servicesNames); | ||
debug('Initializing dependencies:', serviceName, servicesDeclarations); | ||
return Promise.resolve().then(function () { | ||
return Promise.all(servicesNames.map(_this3._getServiceDescriptor.bind(_this3, siloContext, injectOnly))).then(function (servicesDescriptors) { | ||
debug('Initialized dependencies descriptors:', serviceName, servicesNames); | ||
siloContext.servicesSequence.push(servicesNames); | ||
return Promise.all(servicesDeclarations.map(_pickMappedNameFromDeclaration).map(_this3._getServiceDescriptor.bind(_this3, siloContext, injectOnly))).then(function (servicesDescriptors) { | ||
debug('Initialized dependencies descriptors:', serviceName, servicesDeclarations); | ||
siloContext.servicesSequence.push(servicesDeclarations.map(_pickMappedNameFromDeclaration)); | ||
return Promise.all(servicesDescriptors.map(function (serviceDescriptor, index) { | ||
if (!serviceDescriptor.servicePromise || !serviceDescriptor.servicePromise.then) { | ||
return Promise.reject(new _yerror2.default(E_BAD_SERVICE_PROMISE, servicesNames[index])); | ||
return Promise.reject(new _yerror2.default(E_BAD_SERVICE_PROMISE, servicesDeclarations[index])); | ||
} | ||
@@ -452,3 +459,4 @@ return serviceDescriptor.servicePromise.then(function (service) { | ||
return services.reduce(function (hash, service, index) { | ||
hash[servicesNames[index]] = service; | ||
var serviceName = _pickServiceNameFromDeclaration(servicesDeclarations[index]); | ||
hash[serviceName] = service; | ||
return hash; | ||
@@ -471,2 +479,20 @@ }, {}); | ||
exports.default = Knifecycle; | ||
exports.default = Knifecycle; | ||
function _pickServiceNameFromDeclaration(serviceDeclaration) { | ||
var _serviceDeclaration$s = serviceDeclaration.split(DECLARATION_SEPARATOR), | ||
_serviceDeclaration$s2 = _slicedToArray(_serviceDeclaration$s, 1), | ||
serviceName = _serviceDeclaration$s2[0]; | ||
return serviceName; | ||
} | ||
function _pickMappedNameFromDeclaration(serviceDeclaration) { | ||
var _serviceDeclaration$s3 = serviceDeclaration.split(DECLARATION_SEPARATOR), | ||
_serviceDeclaration$s4 = _slicedToArray(_serviceDeclaration$s3, 2), | ||
serviceName = _serviceDeclaration$s4[0], | ||
mappedName = _serviceDeclaration$s4[1]; | ||
return mappedName || serviceName; | ||
} |
@@ -86,2 +86,14 @@ 'use strict'; | ||
}); | ||
it('should fail with circular dependencies on mapped services', function () { | ||
try { | ||
$.provider('aHash', $.depends(['hash3:aHash3'], hashProvider)); | ||
$.provider('aHash1', $.depends(['hash:aHash'], hashProvider)); | ||
$.provider('aHash2', $.depends(['hash1:aHash1'], hashProvider)); | ||
$.provider('aHash3', $.depends(['hash:aHash'], hashProvider)); | ||
} catch (err) { | ||
_assert2.default.deepEqual(err.code, 'E_CIRCULAR_DEPENDENCY'); | ||
_assert2.default.deepEqual(err.params, ['hash', 'hash3']); | ||
} | ||
}); | ||
}); | ||
@@ -94,2 +106,6 @@ | ||
}); | ||
it('should allow to map services dependencies', function () { | ||
$.service('hash', $.depends(['ANOTHER_ENV:ENV'], hashProvider)); | ||
}); | ||
}); | ||
@@ -184,2 +200,18 @@ | ||
it('should instanciate services with mappings', function (done) { | ||
var timeServiceStub = _sinon2.default.spy(timeService); | ||
$.constant('ENV', ENV); | ||
$.service('aTime', timeServiceStub); | ||
$.provider('aHash', $.depends(['ENV', 'time:aTime'], hashProvider)); | ||
$.provider('aHash2', $.depends(['ENV', 'hash:aHash'], hashProvider)); | ||
$.provider('aHash3', $.depends(['ENV', 'hash:aHash'], hashProvider)); | ||
$.run(['hash2:aHash2', 'hash3:aHash3', 'time:aTime']).then(function (dependencies) { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['hash2', 'hash3', 'time']); | ||
_assert2.default.deepEqual(timeServiceStub.args, [[{}]]); | ||
done(); | ||
}).catch(done); | ||
}); | ||
it('should fail with bad service', function (done) { | ||
@@ -186,0 +218,0 @@ $.service('lol', function () {}); |
{ | ||
"name": "knifecycle", | ||
"version": "1.1.2", | ||
"version": "1.2.0", | ||
"description": "Manage your NodeJS processes's lifecycle.", | ||
"main": "dist/index.js", | ||
"engines": { | ||
"node": ">=4" | ||
"node": ">=6" | ||
}, | ||
@@ -9,0 +9,0 @@ "files": [ |
@@ -14,2 +14,3 @@ import YError from 'yerror'; | ||
const E_BAD_INJECTION = 'E_BAD_INJECTION'; | ||
const DECLARATION_SEPARATOR = ':'; | ||
@@ -153,7 +154,15 @@ // Constants that should use Symbol whenever possible | ||
uniqueServiceProvider[DEPENDENCIES].forEach((dependencyName) => { | ||
const dependencyProvider = this._servicesProviders.get(dependencyName); | ||
uniqueServiceProvider[DEPENDENCIES].forEach((dependencyDeclaration) => { | ||
const serviceName = _pickServiceNameFromDeclaration(dependencyDeclaration); | ||
const dependencyProvider = this._servicesProviders.get(serviceName); | ||
if(dependencyProvider && -1 !== dependencyProvider[DEPENDENCIES].indexOf(serviceName)) { | ||
throw new YError(E_CIRCULAR_DEPENDENCY, dependencyName, serviceName); | ||
if( | ||
dependencyProvider && | ||
dependencyProvider[DEPENDENCIES] | ||
.some((childDependencyDeclaration) => { | ||
const childServiceName = _pickServiceNameFromDeclaration(childDependencyDeclaration); | ||
return childServiceName === serviceName; | ||
}) | ||
) { | ||
throw new YError(E_CIRCULAR_DEPENDENCY, dependencyDeclaration, serviceName); | ||
} | ||
@@ -169,3 +178,3 @@ }); | ||
* Decorator to claim that a service depends on others ones. | ||
* @param {String[]} dependenciesNames Dependencies the decorated service provider depends on. | ||
* @param {String[]} dependenciesDeclarations Dependencies the decorated service provider depends on. | ||
* @param {Function} serviceProvider Service provider or a service provider promise | ||
@@ -199,3 +208,3 @@ * @return {Function} Returns the decorator function | ||
*/ | ||
depends(dependenciesNames, serviceProvider) { // eslint-disable-line | ||
depends(dependenciesDeclarations, serviceProvider) { // eslint-disable-line | ||
const uniqueServiceProvider = serviceProvider.bind(); | ||
@@ -206,5 +215,5 @@ | ||
[] | ||
).concat(dependenciesNames); | ||
).concat(dependenciesDeclarations); | ||
debug('Wrapped a service provider with dependencies:', dependenciesNames); | ||
debug('Wrapped a service provider with dependencies:', dependenciesDeclarations); | ||
@@ -216,3 +225,3 @@ return uniqueServiceProvider; | ||
* Creates a new execution silo | ||
* @param {String[]} dependenciesNames Service name. | ||
* @param {String[]} dependenciesDeclarations Service name. | ||
* @return {Promise} Service descriptor promise Returns the decorator function | ||
@@ -231,3 +240,3 @@ * @example | ||
*/ | ||
run(dependenciesNames) { | ||
run(dependenciesDeclarations) { | ||
const siloContext = { | ||
@@ -277,3 +286,3 @@ name: 'silo-' + Date.now(), | ||
if(reversedServiceSequence.some( | ||
servicesNames => servicesNames.includes(serviceName) | ||
servicesDeclarations => servicesDeclarations.includes(serviceName) | ||
)) { | ||
@@ -299,8 +308,8 @@ debug('Delaying service shutdown:', serviceName); | ||
siloContext.servicesDescriptors.set(INJECT, { | ||
servicePromise: Promise.resolve(dependenciesNames => | ||
this._initializeDependencies(siloContext, siloContext.name, dependenciesNames, true) | ||
servicePromise: Promise.resolve(dependenciesDeclarations => | ||
this._initializeDependencies(siloContext, siloContext.name, dependenciesDeclarations, true) | ||
), | ||
}); | ||
return this._initializeDependencies(siloContext, siloContext.name, dependenciesNames) | ||
return this._initializeDependencies(siloContext, siloContext.name, dependenciesDeclarations) | ||
.then((servicesHash) => { | ||
@@ -401,20 +410,22 @@ debug('Handling fatal errors:', siloContext.errorsPromises); | ||
* @param {String} serviceName Service name. | ||
* @param {String} servicesNames Dependencies names. | ||
* @param {String} servicesDeclarations Dependencies names. | ||
* @param {Boolean} injectOnly Flag indicating if existing services only should be used | ||
* @return {Promise} Service dependencies hash promise. | ||
*/ | ||
_initializeDependencies(siloContext, serviceName, servicesNames, injectOnly = false) { | ||
debug('Initializing dependencies:', serviceName, servicesNames); | ||
_initializeDependencies(siloContext, serviceName, servicesDeclarations, injectOnly = false) { | ||
debug('Initializing dependencies:', serviceName, servicesDeclarations); | ||
return Promise.resolve() | ||
.then( | ||
() => Promise.all( | ||
servicesNames.map(this._getServiceDescriptor.bind(this, siloContext, injectOnly)) | ||
servicesDeclarations | ||
.map(_pickMappedNameFromDeclaration) | ||
.map(this._getServiceDescriptor.bind(this, siloContext, injectOnly)) | ||
) | ||
.then((servicesDescriptors) => { | ||
debug('Initialized dependencies descriptors:', serviceName, servicesNames); | ||
siloContext.servicesSequence.push(servicesNames); | ||
debug('Initialized dependencies descriptors:', serviceName, servicesDeclarations); | ||
siloContext.servicesSequence.push(servicesDeclarations.map(_pickMappedNameFromDeclaration)); | ||
return Promise.all(servicesDescriptors.map( | ||
(serviceDescriptor, index) => { | ||
if((!serviceDescriptor.servicePromise) || !serviceDescriptor.servicePromise.then) { | ||
return Promise.reject(new YError(E_BAD_SERVICE_PROMISE, servicesNames[index])); | ||
return Promise.reject(new YError(E_BAD_SERVICE_PROMISE, servicesDeclarations[index])); | ||
} | ||
@@ -426,3 +437,4 @@ return serviceDescriptor.servicePromise.then(service => service); | ||
.then(services => services.reduce((hash, service, index) => { | ||
hash[servicesNames[index]] = service; | ||
const serviceName = _pickServiceNameFromDeclaration(servicesDeclarations[index]); | ||
hash[serviceName] = service; | ||
return hash; | ||
@@ -433,1 +445,11 @@ }, {})) | ||
} | ||
function _pickServiceNameFromDeclaration(serviceDeclaration) { | ||
const [serviceName] = serviceDeclaration.split(DECLARATION_SEPARATOR); | ||
return serviceName; | ||
} | ||
function _pickMappedNameFromDeclaration(serviceDeclaration) { | ||
const [serviceName, mappedName] = serviceDeclaration.split(DECLARATION_SEPARATOR); | ||
return mappedName || serviceName; | ||
} |
@@ -77,2 +77,14 @@ import assert from 'assert'; | ||
it('should fail with circular dependencies on mapped services', () => { | ||
try { | ||
$.provider('aHash', $.depends(['hash3:aHash3'], hashProvider)); | ||
$.provider('aHash1', $.depends(['hash:aHash'], hashProvider)); | ||
$.provider('aHash2', $.depends(['hash1:aHash1'], hashProvider)); | ||
$.provider('aHash3', $.depends(['hash:aHash'], hashProvider)); | ||
} catch (err) { | ||
assert.deepEqual(err.code, 'E_CIRCULAR_DEPENDENCY'); | ||
assert.deepEqual(err.params, ['hash', 'hash3']); | ||
} | ||
}); | ||
}); | ||
@@ -86,2 +98,6 @@ | ||
it('should allow to map services dependencies', () => { | ||
$.service('hash', $.depends(['ANOTHER_ENV:ENV'], hashProvider)); | ||
}); | ||
}); | ||
@@ -186,2 +202,20 @@ | ||
it('should instanciate services with mappings', (done) => { | ||
const timeServiceStub = sinon.spy(timeService); | ||
$.constant('ENV', ENV); | ||
$.service('aTime', timeServiceStub); | ||
$.provider('aHash', $.depends(['ENV', 'time:aTime'], hashProvider)); | ||
$.provider('aHash2', $.depends(['ENV', 'hash:aHash'], hashProvider)); | ||
$.provider('aHash3', $.depends(['ENV', 'hash:aHash'], hashProvider)); | ||
$.run(['hash2:aHash2', 'hash3:aHash3', 'time:aTime']) | ||
.then((dependencies) => { | ||
assert.deepEqual(Object.keys(dependencies), ['hash2', 'hash3', 'time']); | ||
assert.deepEqual(timeServiceStub.args, [[{}]]); | ||
done(); | ||
}) | ||
.catch(done); | ||
}); | ||
it('should fail with bad service', (done) => { | ||
@@ -188,0 +222,0 @@ $.service('lol', () => {}); |
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
90275
1786