knifecycle
Advanced tools
Comparing version 2.4.2 to 2.5.0
@@ -0,1 +1,16 @@ | ||
<a name="2.5.0"></a> | ||
# [2.5.0](https://github.com/nfroidure/knifecycle/compare/v2.4.2...v2.5.0) (2018-03-21) | ||
### Bug Fixes | ||
* **Build:** Fix build for providers ([2847929](https://github.com/nfroidure/knifecycle/commit/2847929)) | ||
### Features | ||
* **API:** Ensure existing initializer type are provided ([bf880d9](https://github.com/nfroidure/knifecycle/commit/bf880d9)) | ||
<a name="2.4.2"></a> | ||
@@ -2,0 +17,0 @@ ## [2.4.2](https://github.com/nfroidure/knifecycle/compare/v2.4.1...v2.4.2) (2017-12-02) |
@@ -44,7 +44,5 @@ 'use strict'; | ||
function buildInitializer(constants, loader, dependencies) { | ||
return Promise.all(dependencies.map(function (dependency) { | ||
return buildDependencyTree(constants, loader, dependency); | ||
})).then(function (dependencyTrees) { | ||
var dependenciesHash = buildDependenciesHash(dependencyTrees.filter(identity)); | ||
var batches = (0, _sequence.buildInitializationSequence)({ | ||
return Promise.all(dependencies.map(dependency => buildDependencyTree(constants, loader, dependency))).then(dependencyTrees => { | ||
const dependenciesHash = buildDependenciesHash(dependencyTrees.filter(identity)); | ||
const batches = (0, _sequence.buildInitializationSequence)({ | ||
__name: 'main', | ||
@@ -55,26 +53,29 @@ __childNodes: dependencyTrees.filter(identity) | ||
return batches.map(function (batch, index) { | ||
return '\n// Definition batch #' + index + batch.map(function (name) { | ||
if (!dependenciesHash[name].__initializer) { | ||
return '\nconst ' + name + ' = ' + JSON.stringify(constants[name], null, 2) + ';'; | ||
} | ||
return `${batches.map((batch, index) => ` | ||
// Definition batch #${index}${batch.map(name => { | ||
if (!dependenciesHash[name].__initializer) { | ||
return ` | ||
const ${name} = ${JSON.stringify(constants[name], null, 2)};`; | ||
} | ||
return '\nimport ' + dependenciesHash[name].__initializerName + ' from \'' + dependenciesHash[name].__path + '\';'; | ||
}).join(''); | ||
}).join('\n') + '\n\nexport async function initialize(services = {}) {' + batches.map(function (batch, index) { | ||
return '\n // Initialization batch #' + index + batch.map(function (name) { | ||
if (!dependenciesHash[name].__initializer) { | ||
return '\n services[\'' + name + '\'] = ' + name + ';'; | ||
} | ||
return '\n services[\'' + name + '\'] = await ' + dependenciesHash[name].__initializerName + '({' + (dependenciesHash[name].__inject ? dependenciesHash[name].__inject.map(_util.parseDependencyDeclaration).map(function (_ref) { | ||
var serviceName = _ref.serviceName, | ||
mappedName = _ref.mappedName; | ||
return '\n ' + serviceName + ': services[\'' + mappedName + '\'],'; | ||
}).join('') + '\n ' : '') + '});'; | ||
}).join('') + '\n'; | ||
}).join('') + '\n return {' + dependencies.map(_util.parseDependencyDeclaration).map(function (_ref2) { | ||
var serviceName = _ref2.serviceName, | ||
mappedName = _ref2.mappedName; | ||
return '\n ' + serviceName + ': services[\'' + mappedName + '\'],'; | ||
}).join('') + '\n };\n}\n'; | ||
return ` | ||
import ${dependenciesHash[name].__initializerName} from '${dependenciesHash[name].__path}';`; | ||
}).join('')}`).join('\n')} | ||
export async function initialize(services = {}) {${batches.map((batch, index) => ` | ||
// Initialization batch #${index}${batch.map(name => { | ||
if (!dependenciesHash[name].__initializer) { | ||
return ` | ||
services['${name}'] = ${name};`; | ||
} | ||
return ` | ||
services['${name}'] = (await ${dependenciesHash[name].__initializerName}({${dependenciesHash[name].__inject ? `${dependenciesHash[name].__inject.map(_util.parseDependencyDeclaration).map(({ serviceName, mappedName }) => ` | ||
${serviceName}: services['${mappedName}'],`).join('')}\n ` : ''}}))${'provider' === dependenciesHash[name].__type ? '.service' : ''};`; | ||
}).join('')} | ||
`).join('')} | ||
return {${dependencies.map(_util.parseDependencyDeclaration).map(({ serviceName, mappedName }) => ` | ||
${serviceName}: services['${mappedName}'],`).join('')} | ||
}; | ||
} | ||
`; | ||
}); | ||
@@ -84,5 +85,3 @@ } | ||
function buildDependencyTree(constants, loader, dependencyDeclaration) { | ||
var _parseDependencyDecla = (0, _util.parseDependencyDeclaration)(dependencyDeclaration), | ||
mappedName = _parseDependencyDecla.mappedName, | ||
optional = _parseDependencyDecla.optional; | ||
const { mappedName, optional } = (0, _util.parseDependencyDeclaration)(dependencyDeclaration); | ||
@@ -96,10 +95,8 @@ if (constants[mappedName]) { | ||
return loader(mappedName).then(function (_ref3) { | ||
var path = _ref3.path, | ||
initializer = _ref3.initializer; | ||
var node = { | ||
return loader(mappedName).then(({ path, initializer }) => { | ||
const node = { | ||
__name: mappedName, | ||
__initializer: initializer, | ||
__inject: initializer && initializer[_util.SPECIAL_PROPS.INJECT] ? initializer[_util.SPECIAL_PROPS.INJECT] : [], | ||
__type: initializer && initializer[_util.SPECIAL_PROPS.TYPE] ? initializer[_util.SPECIAL_PROPS.TYPE] : 'provider', | ||
__initializerName: 'init' + upperCaseFirst(mappedName), | ||
@@ -110,9 +107,7 @@ __path: path, | ||
return initializer[_util.SPECIAL_PROPS.INJECT] && initializer[_util.SPECIAL_PROPS.INJECT].length ? Promise.all(initializer[_util.SPECIAL_PROPS.INJECT].map(function (childDependencyDeclaration) { | ||
return buildDependencyTree(constants, loader, childDependencyDeclaration); | ||
})).then(function (childNodes) { | ||
return initializer[_util.SPECIAL_PROPS.INJECT] && initializer[_util.SPECIAL_PROPS.INJECT].length ? Promise.all(initializer[_util.SPECIAL_PROPS.INJECT].map(childDependencyDeclaration => buildDependencyTree(constants, loader, childDependencyDeclaration))).then(childNodes => { | ||
node.__childNodes = childNodes.filter(identity); | ||
return node; | ||
}) : node; | ||
}).catch(function (err) { | ||
}).catch(err => { | ||
if (optional) { | ||
@@ -125,15 +120,9 @@ return null; | ||
function buildDependenciesHash(dependencyTrees) { | ||
var hash = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
return dependencyTrees.reduce(function (hash, tree) { | ||
return buildHashFromNode(tree, hash); | ||
}, hash); | ||
function buildDependenciesHash(dependencyTrees, hash = {}) { | ||
return dependencyTrees.reduce((hash, tree) => buildHashFromNode(tree, hash), hash); | ||
} | ||
function buildHashFromNode(node) { | ||
var hash = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
function buildHashFromNode(node, hash = {}) { | ||
const nodeIsALeaf = !(node.__childNodes && node.__childNodes.length); | ||
var nodeIsALeaf = !(node.__childNodes && node.__childNodes.length); | ||
hash[node.__name] = node; | ||
@@ -145,3 +134,3 @@ | ||
node.__childNodes.forEach(function (childNode) { | ||
node.__childNodes.forEach(childNode => { | ||
hash = buildHashFromNode(childNode, hash); | ||
@@ -148,0 +137,0 @@ }); |
@@ -19,8 +19,8 @@ 'use strict'; | ||
describe('buildInitializer', function () { | ||
describe('buildInitializer', () => { | ||
function aProvider() {} | ||
var mockedConstants = { | ||
const mockedConstants = { | ||
NODE_ENV: 'development' | ||
}; | ||
var mockedDepsHash = { | ||
const mockedDepsHash = { | ||
dep1: (0, _util.initializer)({ | ||
@@ -35,3 +35,3 @@ inject: [], | ||
options: {}, | ||
type: 'initializer', | ||
type: 'provider', | ||
name: 'dep2' | ||
@@ -48,3 +48,3 @@ }, aProvider), | ||
return mockedDepsHash[name] ? Promise.resolve({ | ||
path: './services/' + name, | ||
path: `./services/${name}`, | ||
initializer: mockedDepsHash[name] | ||
@@ -54,7 +54,40 @@ }) : Promise.reject(new _yerror2.default('E_UNMATCHED_DEPENDENCY', name)); | ||
it('should build an initialization module', function () { | ||
return (0, _build2.default)(mockedConstants, mockedLoader, ['dep1', 'finalMappedDep>dep3']).then(function (content) { | ||
_assert2.default.equal(content, '\n// Definition batch #0\nimport initDep1 from \'./services/dep1\';\nconst NODE_ENV = "development";\n\n// Definition batch #1\nimport initDep2 from \'./services/dep2\';\n\n// Definition batch #2\nimport initDep3 from \'./services/dep3\';\n\nexport async function initialize(services = {}) {\n // Initialization batch #0\n services[\'dep1\'] = await initDep1({\n });\n services[\'NODE_ENV\'] = NODE_ENV;\n\n // Initialization batch #1\n services[\'dep2\'] = await initDep2({\n dep1: services[\'dep1\'],\n NODE_ENV: services[\'NODE_ENV\'],\n });\n\n // Initialization batch #2\n services[\'dep3\'] = await initDep3({\n dep2: services[\'dep2\'],\n dep1: services[\'dep1\'],\n depOpt: services[\'depOpt\'],\n });\n\n return {\n dep1: services[\'dep1\'],\n finalMappedDep: services[\'dep3\'],\n };\n}\n'); | ||
}); | ||
}); | ||
it('should build an initialization module', () => (0, _build2.default)(mockedConstants, mockedLoader, ['dep1', 'finalMappedDep>dep3']).then(content => { | ||
_assert2.default.equal(content, ` | ||
// Definition batch #0 | ||
import initDep1 from './services/dep1'; | ||
const NODE_ENV = "development"; | ||
// Definition batch #1 | ||
import initDep2 from './services/dep2'; | ||
// Definition batch #2 | ||
import initDep3 from './services/dep3'; | ||
export async function initialize(services = {}) { | ||
// Initialization batch #0 | ||
services['dep1'] = (await initDep1({ | ||
})); | ||
services['NODE_ENV'] = NODE_ENV; | ||
// Initialization batch #1 | ||
services['dep2'] = (await initDep2({ | ||
dep1: services['dep1'], | ||
NODE_ENV: services['NODE_ENV'], | ||
})).service; | ||
// Initialization batch #2 | ||
services['dep3'] = (await initDep3({ | ||
dep2: services['dep2'], | ||
dep1: services['dep1'], | ||
depOpt: services['depOpt'], | ||
})); | ||
return { | ||
dep1: services['dep1'], | ||
finalMappedDep: services['dep3'], | ||
}; | ||
} | ||
`); | ||
})); | ||
}); |
1096
dist/index.js
@@ -8,5 +8,2 @@ 'use strict'; | ||
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; }; }(); /* eslint max-len: ["warn", { "ignoreComments": true }] */ | ||
var _util = require('./util'); | ||
@@ -24,26 +21,24 @@ | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
const debug = (0, _debug2.default)('knifecycle'); /* eslint max-len: ["warn", { "ignoreComments": true }] */ | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
const DISPOSE = '$dispose'; | ||
const DESTROY = '$destroy'; | ||
const INJECTOR = '$injector'; | ||
const SILO_CONTEXT = '$siloContext'; | ||
const FATAL_ERROR = '$fatalError'; | ||
var debug = (0, _debug2.default)('knifecycle'); | ||
const ALLOWED_INITIALIZER_TYPES = ['provider', 'service']; | ||
var DISPOSE = '$dispose'; | ||
var DESTROY = '$destroy'; | ||
var INJECTOR = '$injector'; | ||
var SILO_CONTEXT = '$siloContext'; | ||
var FATAL_ERROR = '$fatalError'; | ||
const E_BAD_ANALYZER_TYPE = 'E_BAD_ANALYZER_TYPE'; | ||
const E_UNMATCHED_DEPENDENCY = 'E_UNMATCHED_DEPENDENCY'; | ||
const E_CIRCULAR_DEPENDENCY = 'E_CIRCULAR_DEPENDENCY'; | ||
const E_ANONYMOUS_ANALYZER = 'E_ANONYMOUS_ANALYZER'; | ||
const E_BAD_SERVICE_PROVIDER = 'E_BAD_SERVICE_PROVIDER'; | ||
const E_BAD_SERVICE_PROMISE = 'E_BAD_SERVICE_PROMISE'; | ||
const E_BAD_INJECTION = 'E_BAD_INJECTION'; | ||
const E_CONSTANT_INJECTION = 'E_CONSTANT_INJECTION'; | ||
var E_UNMATCHED_DEPENDENCY = 'E_UNMATCHED_DEPENDENCY'; | ||
var E_CIRCULAR_DEPENDENCY = 'E_CIRCULAR_DEPENDENCY'; | ||
var E_ANONYMOUS_ANALYZER = 'E_ANONYMOUS_ANALYZER'; | ||
var E_BAD_SERVICE_PROVIDER = 'E_BAD_SERVICE_PROVIDER'; | ||
var E_BAD_SERVICE_PROMISE = 'E_BAD_SERVICE_PROMISE'; | ||
var E_BAD_INJECTION = 'E_BAD_INJECTION'; | ||
var E_CONSTANT_INJECTION = 'E_CONSTANT_INJECTION'; | ||
// Constants that should use Symbol whenever possible | ||
var INSTANCE = '__instance'; | ||
const INSTANCE = '__instance'; | ||
@@ -76,4 +71,3 @@ /* Architecture Note #1: Knifecycle | ||
*/ | ||
var Knifecycle = function () { | ||
class Knifecycle { | ||
/** | ||
@@ -88,7 +82,3 @@ * Create a new Knifecycle instance | ||
*/ | ||
function Knifecycle() { | ||
var _this2 = this; | ||
_classCallCheck(this, Knifecycle); | ||
constructor() { | ||
this._silosCounter = 0; | ||
@@ -100,27 +90,20 @@ this._silosContexts = new Set(); | ||
this._singletonsServicesShutdownsPromises = new Map(); | ||
this.provider(INJECTOR, (0, _util.inject)([SILO_CONTEXT], function (_ref) { | ||
var $siloContext = _ref.$siloContext; | ||
return Promise.resolve({ | ||
service: function service(dependenciesDeclarations) { | ||
return _this2._initializeDependencies($siloContext, $siloContext.name, dependenciesDeclarations, true); | ||
} | ||
}); | ||
})); | ||
this.provider(DESTROY, function () { | ||
return Promise.resolve({ | ||
service: function service() { | ||
_this2.shutdownPromise = _this2.shutdownPromise || Promise.all([].concat(_toConsumableArray(_this2._silosContexts)).map(function (siloContext) { | ||
var $dispose = siloContext.servicesDescriptors.get(DISPOSE).service; | ||
this.provider(INJECTOR, (0, _util.inject)([SILO_CONTEXT], ({ $siloContext }) => Promise.resolve({ | ||
service: dependenciesDeclarations => this._initializeDependencies($siloContext, $siloContext.name, dependenciesDeclarations, true) | ||
}))); | ||
this.provider(DESTROY, () => Promise.resolve({ | ||
service: () => { | ||
this.shutdownPromise = this.shutdownPromise || Promise.all([...this._silosContexts].map(siloContext => { | ||
const $dispose = siloContext.servicesDescriptors.get(DISPOSE).service; | ||
return $dispose(); | ||
})); | ||
return $dispose(); | ||
})); | ||
debug('Shutting down Knifecycle instance.'); | ||
debug('Shutting down Knifecycle instance.'); | ||
return _this2.shutdownPromise; | ||
} | ||
}, { | ||
singleton: true | ||
}); | ||
}); | ||
return this.shutdownPromise; | ||
} | ||
}, { | ||
singleton: true | ||
})); | ||
} | ||
@@ -138,598 +121,525 @@ | ||
*/ | ||
static getInstance() { | ||
Knifecycle[INSTANCE] = Knifecycle[INSTANCE] || new Knifecycle(); | ||
debug('Spawning an instance.'); | ||
return Knifecycle[INSTANCE]; | ||
} | ||
/* Architecture Note #1.3: Declaring services | ||
The first step to use `knifecycle` is to declare | ||
services. There are two way of declaring services: | ||
- constants: a constant is a simple value that will | ||
never change. It can be literal values, objects | ||
or even functions. | ||
- initializers: they are asynchronous functions | ||
that handle the initialization phase. | ||
Initializers can be of two types: | ||
- services: a `service` initializer directly | ||
resolve to the actual service it builds. It can | ||
be objects, functions or literal values. | ||
- providers: they instead resolve to an object that | ||
contains the service built into the `service` property | ||
but also an optional `dispose` property exposing a | ||
method to properly stop the service and a | ||
`fatalErrorPromise` that will be rejected if an | ||
unrecoverable error happens. | ||
Initializers can be declared as singletons. This means | ||
that they will be instanciated once for all for each | ||
executions silos using them (we will cover this | ||
topic later on). | ||
*/ | ||
_createClass(Knifecycle, [{ | ||
key: 'constant', | ||
/** | ||
* Register a constant service | ||
* @param {String} constantName | ||
* The name of the service | ||
* @param {any} constantValue | ||
* The constant value | ||
* @return {Knifecycle} | ||
* The Knifecycle instance (for chaining) | ||
* @example | ||
* | ||
* import Knifecycle from 'knifecycle' | ||
* | ||
* const $ = new Knifecycle(); | ||
* | ||
* // Expose the process env | ||
* $.constant('ENV', process.env); | ||
* // Expose a time() function | ||
* $.constant('time', Date.now.bind(Date)); | ||
*/ | ||
constant(constantName, constantValue) { | ||
const contantLooksLikeAnInitializer = constantValue instanceof Function && constantValue[_util.SPECIAL_PROPS.INJECT]; | ||
if (contantLooksLikeAnInitializer) { | ||
throw new _yerror2.default(E_CONSTANT_INJECTION, constantValue[_util.SPECIAL_PROPS.INJECT]); | ||
} | ||
/* Architecture Note #1.3: Declaring services | ||
The first step to use `knifecycle` is to declare | ||
services. There are two way of declaring services: | ||
- constants: a constant is a simple value that will | ||
never change. It can be literal values, objects | ||
or even functions. | ||
- initializers: they are asynchronous functions | ||
that handle the initialization phase. | ||
Initializers can be of two types: | ||
- services: a `service` initializer directly | ||
resolve to the actual service it builds. It can | ||
be objects, functions or literal values. | ||
- providers: they instead resolve to an object that | ||
contains the service built into the `service` property | ||
but also an optional `dispose` property exposing a | ||
method to properly stop the service and a | ||
`fatalErrorPromise` that will be rejected if an | ||
unrecoverable error happens. | ||
Initializers can be declared as singletons. This means | ||
that they will be instanciated once for all for each | ||
executions silos using them (we will cover this | ||
topic later on). | ||
*/ | ||
this.register((0, _util.initializer)({ | ||
name: constantName, | ||
options: { singleton: true } | ||
}, Promise.resolve.bind(Promise, { | ||
service: constantValue, | ||
dispose: Promise.resolve.bind(Promise) | ||
}))); | ||
/** | ||
* Register a constant service | ||
* @param {String} constantName | ||
* The name of the service | ||
* @param {any} constantValue | ||
* The constant value | ||
* @return {Knifecycle} | ||
* The Knifecycle instance (for chaining) | ||
* @example | ||
* | ||
* import Knifecycle from 'knifecycle' | ||
* | ||
* const $ = new Knifecycle(); | ||
* | ||
* // Expose the process env | ||
* $.constant('ENV', process.env); | ||
* // Expose a time() function | ||
* $.constant('time', Date.now.bind(Date)); | ||
*/ | ||
value: function constant(constantName, constantValue) { | ||
var contantLooksLikeAnInitializer = constantValue instanceof Function && constantValue[_util.SPECIAL_PROPS.INJECT]; | ||
debug('Registered a new constant:', constantName); | ||
if (contantLooksLikeAnInitializer) { | ||
throw new _yerror2.default(E_CONSTANT_INJECTION, constantValue[_util.SPECIAL_PROPS.INJECT]); | ||
} | ||
return this; | ||
} | ||
this.register((0, _util.initializer)({ | ||
name: constantName, | ||
options: { singleton: true } | ||
}, Promise.resolve.bind(Promise, { | ||
service: constantValue, | ||
dispose: Promise.resolve.bind(Promise) | ||
}))); | ||
/** | ||
* Register a service initializer | ||
* @param {String} serviceName | ||
* Service name | ||
* @param {Function} initializer | ||
* An initializer returning the service promise | ||
* @param {Object} options | ||
* Options attached to the initializer | ||
* @return {Knifecycle} | ||
* The Knifecycle instance (for chaining) | ||
* @example | ||
* | ||
* import Knifecycle from 'knifecycle' | ||
* import fs from 'fs'; | ||
* | ||
* const $ = new Knifecycle(); | ||
* | ||
* $.service('config', configServiceInitializer, { | ||
* singleton: true, | ||
* }); | ||
* | ||
* function configServiceInitializer({ CONFIG_PATH }) { | ||
* return new Promise((resolve, reject) { | ||
* fs.readFile(CONFIG_PATH, function(err, data) { | ||
* if(err) { | ||
* return reject(err); | ||
* } | ||
* try { | ||
* resolve(JSON.parse(data)); | ||
* } catch (err) { | ||
* reject(err); | ||
* } | ||
* }, 'utf-8'); | ||
* } | ||
*/ | ||
service(serviceName, initializer, options) { | ||
this.register((0, _util.reuseSpecialProps)(initializer, initializer, { | ||
[_util.SPECIAL_PROPS.NAME]: serviceName, | ||
[_util.SPECIAL_PROPS.OPTIONS]: options, | ||
[_util.SPECIAL_PROPS.TYPE]: 'service' | ||
}), options); | ||
debug('Registered a new service initializer:', serviceName); | ||
return this; | ||
} | ||
debug('Registered a new constant:', constantName); | ||
/** | ||
* Register a provider initializer | ||
* @param {String} serviceName | ||
* Service name resolved by the provider | ||
* @param {Function} initializer | ||
* An initializer returning the service promise | ||
* @param {Object} options | ||
* Options attached to the initializer | ||
* @return {Knifecycle} | ||
* The Knifecycle instance (for chaining) | ||
* @example | ||
* | ||
* import Knifecycle from 'knifecycle' | ||
* import fs from 'fs'; | ||
* | ||
* const $ = new Knifecycle(); | ||
* | ||
* $.provider('config', function configProvider() { | ||
* return new Promise((resolve, reject) { | ||
* fs.readFile('config.js', function(err, data) { | ||
* let config; | ||
* if(err) { | ||
* return reject(err); | ||
* } | ||
* try { | ||
* config = JSON.parse(data.toString); | ||
* } catch (err) { | ||
* return reject(err); | ||
* } | ||
* resolve({ | ||
* service: config, | ||
* }); | ||
* }); | ||
* }); | ||
* }); | ||
*/ | ||
provider(serviceName, initializer, options = {}) { | ||
this.register((0, _util.reuseSpecialProps)(initializer, initializer, { | ||
[_util.SPECIAL_PROPS.NAME]: serviceName, | ||
[_util.SPECIAL_PROPS.OPTIONS]: options | ||
})); | ||
debug('Registered a new service provider:', serviceName); | ||
return this; | ||
} | ||
return this; | ||
register(initializer) { | ||
initializer[_util.SPECIAL_PROPS.INJECT] = initializer[_util.SPECIAL_PROPS.INJECT] || []; | ||
initializer[_util.SPECIAL_PROPS.OPTIONS] = initializer[_util.SPECIAL_PROPS.OPTIONS] || {}; | ||
initializer[_util.SPECIAL_PROPS.TYPE] = initializer[_util.SPECIAL_PROPS.TYPE] || ALLOWED_INITIALIZER_TYPES[0]; | ||
if (!initializer[_util.SPECIAL_PROPS.NAME]) { | ||
throw new _yerror2.default(E_ANONYMOUS_ANALYZER, initializer[_util.SPECIAL_PROPS.NAME]); | ||
} | ||
if (!ALLOWED_INITIALIZER_TYPES.includes(initializer[_util.SPECIAL_PROPS.TYPE])) { | ||
throw new _yerror2.default(E_BAD_ANALYZER_TYPE, initializer[_util.SPECIAL_PROPS.TYPE], ALLOWED_INITIALIZER_TYPES); | ||
} | ||
/** | ||
* Register a service initializer | ||
* @param {String} serviceName | ||
* Service name | ||
* @param {Function} initializer | ||
* An initializer returning the service promise | ||
* @param {Object} options | ||
* Options attached to the initializer | ||
* @return {Knifecycle} | ||
* The Knifecycle instance (for chaining) | ||
* @example | ||
* | ||
* import Knifecycle from 'knifecycle' | ||
* import fs from 'fs'; | ||
* | ||
* const $ = new Knifecycle(); | ||
* | ||
* $.service('config', configServiceInitializer, { | ||
* singleton: true, | ||
* }); | ||
* | ||
* function configServiceInitializer({ CONFIG_PATH }) { | ||
* return new Promise((resolve, reject) { | ||
* fs.readFile(CONFIG_PATH, function(err, data) { | ||
* if(err) { | ||
* return reject(err); | ||
* } | ||
* try { | ||
* resolve(JSON.parse(data)); | ||
* } catch (err) { | ||
* reject(err); | ||
* } | ||
* }, 'utf-8'); | ||
* } | ||
*/ | ||
if ('service' === initializer[_util.SPECIAL_PROPS.TYPE]) { | ||
initializer = (0, _util.reuseSpecialProps)(initializer, serviceAdapter.bind(null, initializer[_util.SPECIAL_PROPS.NAME], initializer)); | ||
initializer[_util.SPECIAL_PROPS.TYPE] = 'provider'; | ||
} | ||
}, { | ||
key: 'service', | ||
value: function service(serviceName, initializer, options) { | ||
var _reuseSpecialProps; | ||
const initializerDependsOfItself = initializer[_util.SPECIAL_PROPS.INJECT].map(_pickServiceNameFromDeclaration).includes(initializer[_util.SPECIAL_PROPS.NAME]); | ||
this.register((0, _util.reuseSpecialProps)(initializer, initializer, (_reuseSpecialProps = {}, _defineProperty(_reuseSpecialProps, _util.SPECIAL_PROPS.NAME, serviceName), _defineProperty(_reuseSpecialProps, _util.SPECIAL_PROPS.OPTIONS, options), _defineProperty(_reuseSpecialProps, _util.SPECIAL_PROPS.TYPE, 'service'), _reuseSpecialProps)), options); | ||
debug('Registered a new service initializer:', serviceName); | ||
return this; | ||
if (initializerDependsOfItself) { | ||
throw new _yerror2.default(E_CIRCULAR_DEPENDENCY, initializer[_util.SPECIAL_PROPS.NAME]); | ||
} | ||
/** | ||
* Register a provider initializer | ||
* @param {String} serviceName | ||
* Service name resolved by the provider | ||
* @param {Function} initializer | ||
* An initializer returning the service promise | ||
* @param {Object} options | ||
* Options attached to the initializer | ||
* @return {Knifecycle} | ||
* The Knifecycle instance (for chaining) | ||
* @example | ||
* | ||
* import Knifecycle from 'knifecycle' | ||
* import fs from 'fs'; | ||
* | ||
* const $ = new Knifecycle(); | ||
* | ||
* $.provider('config', function configProvider() { | ||
* return new Promise((resolve, reject) { | ||
* fs.readFile('config.js', function(err, data) { | ||
* let config; | ||
* if(err) { | ||
* return reject(err); | ||
* } | ||
* try { | ||
* config = JSON.parse(data.toString); | ||
* } catch (err) { | ||
* return reject(err); | ||
* } | ||
* resolve({ | ||
* service: config, | ||
* }); | ||
* }); | ||
* }); | ||
* }); | ||
*/ | ||
initializer[_util.SPECIAL_PROPS.INJECT].forEach(dependencyDeclaration => { | ||
this._lookupCircularDependencies(initializer[_util.SPECIAL_PROPS.NAME], dependencyDeclaration); | ||
}); | ||
}, { | ||
key: 'provider', | ||
value: function provider(serviceName, initializer) { | ||
var _reuseSpecialProps2; | ||
this._servicesProviders.set(initializer[_util.SPECIAL_PROPS.NAME], initializer); | ||
debug('Registered a new initializer:', initializer[_util.SPECIAL_PROPS.NAME]); | ||
return this; | ||
} | ||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
_lookupCircularDependencies(rootServiceName, dependencyDeclaration, declarationsStacks = []) { | ||
const serviceName = _pickServiceNameFromDeclaration(dependencyDeclaration); | ||
const dependencyProvider = this._servicesProviders.get(serviceName); | ||
this.register((0, _util.reuseSpecialProps)(initializer, initializer, (_reuseSpecialProps2 = {}, _defineProperty(_reuseSpecialProps2, _util.SPECIAL_PROPS.NAME, serviceName), _defineProperty(_reuseSpecialProps2, _util.SPECIAL_PROPS.OPTIONS, options), _reuseSpecialProps2))); | ||
debug('Registered a new service provider:', serviceName); | ||
return this; | ||
if (!dependencyProvider) { | ||
return; | ||
} | ||
}, { | ||
key: 'register', | ||
value: function register(initializer) { | ||
var _this3 = this; | ||
declarationsStacks = declarationsStacks.concat(dependencyDeclaration); | ||
dependencyProvider[_util.SPECIAL_PROPS.INJECT].forEach(childDependencyDeclaration => { | ||
const childServiceName = _pickServiceNameFromDeclaration(childDependencyDeclaration); | ||
initializer[_util.SPECIAL_PROPS.INJECT] = initializer[_util.SPECIAL_PROPS.INJECT] || []; | ||
initializer[_util.SPECIAL_PROPS.OPTIONS] = initializer[_util.SPECIAL_PROPS.OPTIONS] || {}; | ||
initializer[_util.SPECIAL_PROPS.TYPE] = initializer[_util.SPECIAL_PROPS.TYPE] || 'provider'; | ||
if (!initializer[_util.SPECIAL_PROPS.NAME]) { | ||
throw new _yerror2.default(E_ANONYMOUS_ANALYZER, initializer[_util.SPECIAL_PROPS.NAME]); | ||
if (rootServiceName === childServiceName) { | ||
throw new _yerror2.default(...[E_CIRCULAR_DEPENDENCY, rootServiceName].concat(declarationsStacks).concat(childDependencyDeclaration)); | ||
} | ||
if ('service' === initializer[_util.SPECIAL_PROPS.TYPE]) { | ||
initializer = (0, _util.reuseSpecialProps)(initializer, serviceAdapter.bind(null, initializer[_util.SPECIAL_PROPS.NAME], initializer)); | ||
initializer[_util.SPECIAL_PROPS.TYPE] = 'provider'; | ||
} | ||
this._lookupCircularDependencies(rootServiceName, childDependencyDeclaration, declarationsStacks); | ||
}); | ||
} | ||
var initializerDependsOfItself = initializer[_util.SPECIAL_PROPS.INJECT].map(_pickServiceNameFromDeclaration).includes(initializer[_util.SPECIAL_PROPS.NAME]); | ||
/** | ||
* Outputs a Mermaid compatible dependency graph of the declared services. | ||
* See [Mermaid docs](https://github.com/knsv/mermaid) | ||
* @param {Object} options Options for generating the graph (destructured) | ||
* @param {Array<Object>} options.shapes Various shapes to apply | ||
* @param {Array<Object>} options.styles Various styles to apply | ||
* @param {Object} options.classes A hash of various classes contents | ||
* @return {String} Returns a string containing the Mermaid dependency graph | ||
* @example | ||
* | ||
* import { Knifecycle, inject } from 'knifecycle'; | ||
* import appInitializer from './app'; | ||
* | ||
* const $ = new Knifecycle(); | ||
* | ||
* $.constant('ENV', process.env); | ||
* $.constant('OS', require('os')); | ||
* $.service('app', inject(['ENV', 'OS'], appInitializer)); | ||
* $.toMermaidGraph(); | ||
* | ||
* // returns | ||
* graph TD | ||
* app-->ENV | ||
* app-->OS | ||
*/ | ||
toMermaidGraph({ shapes = [], styles = [], classes = {} } = {}) { | ||
const servicesProviders = this._servicesProviders; | ||
const links = Array.from(servicesProviders.keys()).filter(provider => !provider.startsWith('$')).reduce((links, serviceName) => { | ||
const serviceProvider = servicesProviders.get(serviceName); | ||
if (initializerDependsOfItself) { | ||
throw new _yerror2.default(E_CIRCULAR_DEPENDENCY, initializer[_util.SPECIAL_PROPS.NAME]); | ||
if (!serviceProvider[_util.SPECIAL_PROPS.INJECT].length) { | ||
return links; | ||
} | ||
return links.concat(serviceProvider[_util.SPECIAL_PROPS.INJECT].map(dependencyDeclaration => { | ||
const dependedServiceName = _pickServiceNameFromDeclaration(dependencyDeclaration); | ||
initializer[_util.SPECIAL_PROPS.INJECT].forEach(function (dependencyDeclaration) { | ||
_this3._lookupCircularDependencies(initializer[_util.SPECIAL_PROPS.NAME], dependencyDeclaration); | ||
}); | ||
return { serviceName, dependedServiceName }; | ||
})); | ||
}, []); | ||
const classesApplications = _applyClasses(classes, styles, links); | ||
this._servicesProviders.set(initializer[_util.SPECIAL_PROPS.NAME], initializer); | ||
debug('Registered a new initializer:', initializer[_util.SPECIAL_PROPS.NAME]); | ||
return this; | ||
if (!links.length) { | ||
return ''; | ||
} | ||
}, { | ||
key: '_lookupCircularDependencies', | ||
value: function _lookupCircularDependencies(rootServiceName, dependencyDeclaration) { | ||
var _this4 = this; | ||
var declarationsStacks = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; | ||
return ['graph TD'].concat(links.map(({ serviceName, dependedServiceName }) => ` ${_applyShapes(shapes, serviceName) || serviceName}-->${_applyShapes(shapes, dependedServiceName) || dependedServiceName}`)).concat(Object.keys(classes).map(className => ` classDef ${className} ${classes[className]}`)).concat(Object.keys(classesApplications).map(serviceName => ` class ${serviceName} ${classesApplications[serviceName]};`)).join('\n'); | ||
} | ||
var serviceName = _pickServiceNameFromDeclaration(dependencyDeclaration); | ||
var dependencyProvider = this._servicesProviders.get(serviceName); | ||
/* Architecture Note #1.4: Execution silos | ||
Once all the services are declared, we need a way to bring | ||
them to life. Execution silos are where the magic happen. | ||
For each call of the `run` method with given dependencies, | ||
a new silo is created and the required environment to | ||
run the actual code is leveraged. | ||
Depending of your application design, you could run it | ||
in only one execution silo or into several ones | ||
according to the isolation level your wish to reach. | ||
*/ | ||
if (!dependencyProvider) { | ||
return; | ||
} | ||
declarationsStacks = declarationsStacks.concat(dependencyDeclaration); | ||
dependencyProvider[_util.SPECIAL_PROPS.INJECT].forEach(function (childDependencyDeclaration) { | ||
var childServiceName = _pickServiceNameFromDeclaration(childDependencyDeclaration); | ||
/** | ||
* Creates a new execution silo | ||
* @param {String[]} dependenciesDeclarations Service name. | ||
* @return {Promise} Service descriptor promise | ||
* @example | ||
* | ||
* import Knifecycle from 'knifecycle' | ||
* | ||
* const $ = new Knifecycle(); | ||
* | ||
* $.constant('ENV', process.env); | ||
* $.run(['ENV']) | ||
* .then(({ ENV }) => { | ||
* // Here goes your code | ||
* }) | ||
*/ | ||
run(dependenciesDeclarations) { | ||
const _this = this; | ||
const internalDependencies = [...new Set(dependenciesDeclarations.concat(DISPOSE))]; | ||
const siloContext = { | ||
name: `silo-${this._silosCounter++}`, | ||
servicesDescriptors: new Map(), | ||
servicesSequence: [], | ||
servicesShutdownsPromises: new Map(), | ||
errorsPromises: [] | ||
}; | ||
if (rootServiceName === childServiceName) { | ||
throw new (Function.prototype.bind.apply(_yerror2.default, [null].concat(_toConsumableArray([E_CIRCULAR_DEPENDENCY, rootServiceName].concat(declarationsStacks).concat(childDependencyDeclaration)))))(); | ||
} | ||
_this4._lookupCircularDependencies(rootServiceName, childDependencyDeclaration, declarationsStacks); | ||
}); | ||
if (this.shutdownPromise) { | ||
throw new _yerror2.default('E_INSTANCE_DESTROYED'); | ||
} | ||
/** | ||
* Outputs a Mermaid compatible dependency graph of the declared services. | ||
* See [Mermaid docs](https://github.com/knsv/mermaid) | ||
* @param {Object} options Options for generating the graph (destructured) | ||
* @param {Array<Object>} options.shapes Various shapes to apply | ||
* @param {Array<Object>} options.styles Various styles to apply | ||
* @param {Object} options.classes A hash of various classes contents | ||
* @return {String} Returns a string containing the Mermaid dependency graph | ||
* @example | ||
* | ||
* import { Knifecycle, inject } from 'knifecycle'; | ||
* import appInitializer from './app'; | ||
* | ||
* const $ = new Knifecycle(); | ||
* | ||
* $.constant('ENV', process.env); | ||
* $.constant('OS', require('os')); | ||
* $.service('app', inject(['ENV', 'OS'], appInitializer)); | ||
* $.toMermaidGraph(); | ||
* | ||
* // returns | ||
* graph TD | ||
* app-->ENV | ||
* app-->OS | ||
*/ | ||
}, { | ||
key: 'toMermaidGraph', | ||
value: function toMermaidGraph() { | ||
var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | ||
_ref2$shapes = _ref2.shapes, | ||
shapes = _ref2$shapes === undefined ? [] : _ref2$shapes, | ||
_ref2$styles = _ref2.styles, | ||
styles = _ref2$styles === undefined ? [] : _ref2$styles, | ||
_ref2$classes = _ref2.classes, | ||
classes = _ref2$classes === undefined ? {} : _ref2$classes; | ||
var servicesProviders = this._servicesProviders; | ||
var links = Array.from(servicesProviders.keys()).filter(function (provider) { | ||
return !provider.startsWith('$'); | ||
}).reduce(function (links, serviceName) { | ||
var serviceProvider = servicesProviders.get(serviceName); | ||
if (!serviceProvider[_util.SPECIAL_PROPS.INJECT].length) { | ||
return links; | ||
} | ||
return links.concat(serviceProvider[_util.SPECIAL_PROPS.INJECT].map(function (dependencyDeclaration) { | ||
var dependedServiceName = _pickServiceNameFromDeclaration(dependencyDeclaration); | ||
return { serviceName: serviceName, dependedServiceName: dependedServiceName }; | ||
})); | ||
}, []); | ||
var classesApplications = _applyClasses(classes, styles, links); | ||
if (!links.length) { | ||
return ''; | ||
// Create a provider for the special fatal error service | ||
siloContext.servicesDescriptors.set(FATAL_ERROR, { | ||
service: { | ||
promise: new Promise((resolve, reject) => { | ||
siloContext.throwFatalError = err => { | ||
debug('Handled a fatal error', err); | ||
reject(err); | ||
}; | ||
}) | ||
} | ||
}); | ||
return ['graph TD'].concat(links.map(function (_ref3) { | ||
var serviceName = _ref3.serviceName, | ||
dependedServiceName = _ref3.dependedServiceName; | ||
return ' ' + (_applyShapes(shapes, serviceName) || serviceName) + '-->' + (_applyShapes(shapes, dependedServiceName) || dependedServiceName); | ||
})).concat(Object.keys(classes).map(function (className) { | ||
return ' classDef ' + className + ' ' + classes[className]; | ||
})).concat(Object.keys(classesApplications).map(function (serviceName) { | ||
return ' class ' + serviceName + ' ' + classesApplications[serviceName] + ';'; | ||
})).join('\n'); | ||
} | ||
// Make the siloContext available for internal injections | ||
siloContext.servicesDescriptors.set(SILO_CONTEXT, { | ||
service: siloContext | ||
}); | ||
// Create a provider for the shutdown special dependency | ||
siloContext.servicesDescriptors.set(DISPOSE, { | ||
service: () => { | ||
siloContext.shutdownPromise = siloContext.shutdownPromise || _shutdownNextServices(siloContext.servicesSequence); | ||
/* Architecture Note #1.4: Execution silos | ||
Once all the services are declared, we need a way to bring | ||
them to life. Execution silos are where the magic happen. | ||
For each call of the `run` method with given dependencies, | ||
a new silo is created and the required environment to | ||
run the actual code is leveraged. | ||
Depending of your application design, you could run it | ||
in only one execution silo or into several ones | ||
according to the isolation level your wish to reach. | ||
*/ | ||
debug('Shutting down services'); | ||
/** | ||
* Creates a new execution silo | ||
* @param {String[]} dependenciesDeclarations Service name. | ||
* @return {Promise} Service descriptor promise | ||
* @example | ||
* | ||
* import Knifecycle from 'knifecycle' | ||
* | ||
* const $ = new Knifecycle(); | ||
* | ||
* $.constant('ENV', process.env); | ||
* $.run(['ENV']) | ||
* .then(({ ENV }) => { | ||
* // Here goes your code | ||
* }) | ||
*/ | ||
return siloContext.shutdownPromise.then(() => { | ||
this._silosContexts.delete(siloContext); | ||
}); | ||
}, { | ||
key: 'run', | ||
value: function run(dependenciesDeclarations) { | ||
var _this5 = this; | ||
// Shutdown services in their instanciation order | ||
function _shutdownNextServices(reversedServiceSequence) { | ||
if (0 === reversedServiceSequence.length) { | ||
return Promise.resolve(); | ||
} | ||
return Promise.all(reversedServiceSequence.pop().map(serviceName => { | ||
const singletonServiceDescriptor = _this._singletonsServicesDescriptors.get(serviceName); | ||
const serviceDescriptor = singletonServiceDescriptor || siloContext.servicesDescriptors.get(serviceName); | ||
let serviceShutdownPromise = _this._singletonsServicesShutdownsPromises.get(serviceName) || siloContext.servicesShutdownsPromises.get(serviceName); | ||
var _this = this; | ||
var internalDependencies = [].concat(_toConsumableArray(new Set(dependenciesDeclarations.concat(DISPOSE)))); | ||
var siloContext = { | ||
name: 'silo-' + this._silosCounter++, | ||
servicesDescriptors: new Map(), | ||
servicesSequence: [], | ||
servicesShutdownsPromises: new Map(), | ||
errorsPromises: [] | ||
}; | ||
if (serviceShutdownPromise) { | ||
debug('Reusing a service shutdown promise:', serviceName); | ||
return serviceShutdownPromise; | ||
} | ||
if (this.shutdownPromise) { | ||
throw new _yerror2.default('E_INSTANCE_DESTROYED'); | ||
} | ||
// Create a provider for the special fatal error service | ||
siloContext.servicesDescriptors.set(FATAL_ERROR, { | ||
service: { | ||
promise: new Promise(function (resolve, reject) { | ||
siloContext.throwFatalError = function (err) { | ||
debug('Handled a fatal error', err); | ||
reject(err); | ||
}; | ||
}) | ||
} | ||
}); | ||
// Make the siloContext available for internal injections | ||
siloContext.servicesDescriptors.set(SILO_CONTEXT, { | ||
service: siloContext | ||
}); | ||
// Create a provider for the shutdown special dependency | ||
siloContext.servicesDescriptors.set(DISPOSE, { | ||
service: function service() { | ||
siloContext.shutdownPromise = siloContext.shutdownPromise || _shutdownNextServices(siloContext.servicesSequence); | ||
debug('Shutting down services'); | ||
return siloContext.shutdownPromise.then(function () { | ||
_this5._silosContexts.delete(siloContext); | ||
}); | ||
// Shutdown services in their instanciation order | ||
function _shutdownNextServices(reversedServiceSequence) { | ||
if (0 === reversedServiceSequence.length) { | ||
if (reversedServiceSequence.some(servicesDeclarations => servicesDeclarations.includes(serviceName))) { | ||
debug('Delaying service shutdown:', serviceName); | ||
return Promise.resolve(); | ||
} | ||
return Promise.all(reversedServiceSequence.pop().map(function (serviceName) { | ||
var singletonServiceDescriptor = _this._singletonsServicesDescriptors.get(serviceName); | ||
var serviceDescriptor = singletonServiceDescriptor || siloContext.servicesDescriptors.get(serviceName); | ||
var serviceShutdownPromise = _this._singletonsServicesShutdownsPromises.get(serviceName) || siloContext.servicesShutdownsPromises.get(serviceName); | ||
if (singletonServiceDescriptor) { | ||
const handleSet = _this._singletonsServicesHandles.get(serviceName); | ||
if (serviceShutdownPromise) { | ||
debug('Reusing a service shutdown promise:', serviceName); | ||
return serviceShutdownPromise; | ||
} | ||
if (reversedServiceSequence.some(function (servicesDeclarations) { | ||
return servicesDeclarations.includes(serviceName); | ||
})) { | ||
debug('Delaying service shutdown:', serviceName); | ||
handleSet.delete(siloContext.name); | ||
if (handleSet.size) { | ||
debug('Singleton is used elsewhere:', serviceName, handleSet); | ||
return Promise.resolve(); | ||
} | ||
if (singletonServiceDescriptor) { | ||
var handleSet = _this._singletonsServicesHandles.get(serviceName); | ||
_this._singletonsServicesDescriptors.delete(serviceName); | ||
} | ||
debug('Shutting down a service:', serviceName); | ||
serviceShutdownPromise = serviceDescriptor.dispose ? serviceDescriptor.dispose() : Promise.resolve(); | ||
if (singletonServiceDescriptor) { | ||
_this._singletonsServicesShutdownsPromises.set(serviceName, serviceShutdownPromise); | ||
} | ||
siloContext.servicesShutdownsPromises.set(serviceName, serviceShutdownPromise); | ||
return serviceShutdownPromise; | ||
})).then(_shutdownNextServices.bind(null, reversedServiceSequence)); | ||
} | ||
}, | ||
dispose: Promise.resolve.bind(Promise) | ||
}); | ||
handleSet.delete(siloContext.name); | ||
if (handleSet.size) { | ||
debug('Singleton is used elsewhere:', serviceName, handleSet); | ||
return Promise.resolve(); | ||
} | ||
_this._singletonsServicesDescriptors.delete(serviceName); | ||
} | ||
debug('Shutting down a service:', serviceName); | ||
serviceShutdownPromise = serviceDescriptor.dispose ? serviceDescriptor.dispose() : Promise.resolve(); | ||
if (singletonServiceDescriptor) { | ||
_this._singletonsServicesShutdownsPromises.set(serviceName, serviceShutdownPromise); | ||
} | ||
siloContext.servicesShutdownsPromises.set(serviceName, serviceShutdownPromise); | ||
return serviceShutdownPromise; | ||
})).then(_shutdownNextServices.bind(null, reversedServiceSequence)); | ||
} | ||
}, | ||
dispose: Promise.resolve.bind(Promise) | ||
}); | ||
this._silosContexts.add(siloContext); | ||
this._silosContexts.add(siloContext); | ||
return this._initializeDependencies(siloContext, siloContext.name, internalDependencies).then(servicesHash => { | ||
debug('Handling fatal errors:', siloContext.errorsPromises); | ||
Promise.all(siloContext.errorsPromises).catch(siloContext.throwFatalError); | ||
return dependenciesDeclarations.reduce((finalHash, dependencyDeclaration) => { | ||
const { serviceName, mappedName } = (0, _util.parseDependencyDeclaration)(dependencyDeclaration); | ||
return this._initializeDependencies(siloContext, siloContext.name, internalDependencies).then(function (servicesHash) { | ||
debug('Handling fatal errors:', siloContext.errorsPromises); | ||
Promise.all(siloContext.errorsPromises).catch(siloContext.throwFatalError); | ||
return dependenciesDeclarations.reduce(function (finalHash, dependencyDeclaration) { | ||
var _parseDependencyDecla = (0, _util.parseDependencyDeclaration)(dependencyDeclaration), | ||
serviceName = _parseDependencyDecla.serviceName, | ||
mappedName = _parseDependencyDecla.mappedName; | ||
finalHash[serviceName] = servicesHash[mappedName]; | ||
return finalHash; | ||
}, {}); | ||
}); | ||
} | ||
finalHash[serviceName] = servicesHash[mappedName]; | ||
return finalHash; | ||
}, {}); | ||
}); | ||
/** | ||
* Initialize or return a service descriptor | ||
* @param {Object} siloContext Current execution silo context | ||
* @param {Boolean} injectOnly Flag indicating if existing services only should be used | ||
* @param {String} serviceName Service name. | ||
* @param {String} serviceProvider Service provider. | ||
* @return {Promise} Service dependencies hash promise. | ||
*/ | ||
_getServiceDescriptor(siloContext, injectOnly, serviceName) { | ||
let serviceDescriptor = this._singletonsServicesDescriptors.get(serviceName); | ||
if (serviceDescriptor) { | ||
this._singletonsServicesHandles.get(serviceName).add(siloContext.name); | ||
} else { | ||
serviceDescriptor = siloContext.servicesDescriptors.get(serviceName); | ||
} | ||
/** | ||
* Initialize or return a service descriptor | ||
* @param {Object} siloContext Current execution silo context | ||
* @param {Boolean} injectOnly Flag indicating if existing services only should be used | ||
* @param {String} serviceName Service name. | ||
* @param {String} serviceProvider Service provider. | ||
* @return {Promise} Service dependencies hash promise. | ||
*/ | ||
if (serviceDescriptor) { | ||
return Promise.resolve(serviceDescriptor); | ||
} | ||
}, { | ||
key: '_getServiceDescriptor', | ||
value: function _getServiceDescriptor(siloContext, injectOnly, serviceName) { | ||
var serviceDescriptor = this._singletonsServicesDescriptors.get(serviceName); | ||
// The inject service is intended to be used as a workaround for unavoidable | ||
// circular dependencies. It wouldn't make sense to instanciate new services | ||
// at this level so throwing an error | ||
if (injectOnly) { | ||
return Promise.reject(new _yerror2.default(E_BAD_INJECTION, serviceName)); | ||
} | ||
if (serviceDescriptor) { | ||
this._singletonsServicesHandles.get(serviceName).add(siloContext.name); | ||
} else { | ||
serviceDescriptor = siloContext.servicesDescriptors.get(serviceName); | ||
} | ||
return this._initializeServiceDescriptor(siloContext, serviceName); | ||
} | ||
if (serviceDescriptor) { | ||
return Promise.resolve(serviceDescriptor); | ||
} | ||
/** | ||
* Initialize a service | ||
* @param {Object} siloContext Current execution silo context | ||
* @param {String} serviceName Service name. | ||
* @param {String} serviceProvider Service provider. | ||
* @return {Promise} Service dependencies hash promise. | ||
*/ | ||
_initializeServiceDescriptor(siloContext, serviceName) { | ||
const serviceProvider = this._servicesProviders.get(serviceName); | ||
let serviceDescriptorPromise; | ||
// The inject service is intended to be used as a workaround for unavoidable | ||
// circular dependencies. It wouldn't make sense to instanciate new services | ||
// at this level so throwing an error | ||
if (injectOnly) { | ||
return Promise.reject(new _yerror2.default(E_BAD_INJECTION, serviceName)); | ||
} | ||
debug('Initializing a service descriptor:', serviceName); | ||
return this._initializeServiceDescriptor(siloContext, serviceName); | ||
if (!serviceProvider) { | ||
debug('No service provider:', serviceName); | ||
serviceDescriptorPromise = Promise.reject(new _yerror2.default(E_UNMATCHED_DEPENDENCY, serviceName)); | ||
siloContext.servicesDescriptors.set(serviceName, serviceDescriptorPromise); | ||
return serviceDescriptorPromise; | ||
} | ||
/** | ||
* Initialize a service | ||
* @param {Object} siloContext Current execution silo context | ||
* @param {String} serviceName Service name. | ||
* @param {String} serviceProvider Service provider. | ||
* @return {Promise} Service dependencies hash promise. | ||
*/ | ||
// A singleton service may use a reserved resource | ||
// like a TCP socket. This is why we have to be aware | ||
// of singleton services full shutdown before creating | ||
// a new one | ||
serviceDescriptorPromise = (this._singletonsServicesShutdownsPromises.get(serviceName) || Promise.resolve()). | ||
// Anyway delete any shutdown promise before instanciating | ||
// a new service | ||
then(() => { | ||
this._singletonsServicesShutdownsPromises.delete(serviceName); | ||
siloContext.servicesShutdownsPromises.delete(serviceName); | ||
}).then(this._initializeDependencies.bind(this, siloContext, serviceName, serviceProvider[_util.SPECIAL_PROPS.INJECT])); | ||
}, { | ||
key: '_initializeServiceDescriptor', | ||
value: function _initializeServiceDescriptor(siloContext, serviceName) { | ||
var _this6 = this; | ||
serviceDescriptorPromise = serviceDescriptorPromise.then(servicesHash => { | ||
debug('Successfully gathered service dependencies:', serviceName); | ||
return serviceProvider[_util.SPECIAL_PROPS.INJECT].reduce((finalHash, dependencyDeclaration) => { | ||
const { serviceName, mappedName } = (0, _util.parseDependencyDeclaration)(dependencyDeclaration); | ||
var serviceProvider = this._servicesProviders.get(serviceName); | ||
var serviceDescriptorPromise = void 0; | ||
debug('Initializing a service descriptor:', serviceName); | ||
if (!serviceProvider) { | ||
debug('No service provider:', serviceName); | ||
serviceDescriptorPromise = Promise.reject(new _yerror2.default(E_UNMATCHED_DEPENDENCY, serviceName)); | ||
siloContext.servicesDescriptors.set(serviceName, serviceDescriptorPromise); | ||
return serviceDescriptorPromise; | ||
finalHash[serviceName] = servicesHash[mappedName]; | ||
return finalHash; | ||
}, {}); | ||
}).then(serviceProvider).then(serviceDescriptor => { | ||
if (!serviceDescriptor) { | ||
debug('Provider did not return a descriptor:', serviceName); | ||
return Promise.reject(new _yerror2.default(E_BAD_SERVICE_PROVIDER, serviceName)); | ||
} | ||
debug('Successfully initialized a service descriptor:', serviceName); | ||
if (serviceDescriptor.fatalErrorPromise) { | ||
debug('Registering service descriptor error promise:', serviceName); | ||
siloContext.errorsPromises.push(serviceDescriptor.fatalErrorPromise); | ||
} | ||
siloContext.servicesDescriptors.set(serviceName, serviceDescriptor); | ||
return serviceDescriptor; | ||
}).catch(err => { | ||
debug('Error initializing a service descriptor:', serviceName, err.stack); | ||
if (E_UNMATCHED_DEPENDENCY === err.code) { | ||
throw _yerror2.default.wrap(...[err, E_UNMATCHED_DEPENDENCY, serviceName].concat(err.params)); | ||
} | ||
throw err; | ||
}); | ||
if (serviceProvider[_util.SPECIAL_PROPS.OPTIONS].singleton) { | ||
const handlesSet = new Set(); | ||
// A singleton service may use a reserved resource | ||
// like a TCP socket. This is why we have to be aware | ||
// of singleton services full shutdown before creating | ||
// a new one | ||
serviceDescriptorPromise = (this._singletonsServicesShutdownsPromises.get(serviceName) || Promise.resolve()). | ||
// Anyway delete any shutdown promise before instanciating | ||
// a new service | ||
then(function () { | ||
_this6._singletonsServicesShutdownsPromises.delete(serviceName); | ||
siloContext.servicesShutdownsPromises.delete(serviceName); | ||
}).then(this._initializeDependencies.bind(this, siloContext, serviceName, serviceProvider[_util.SPECIAL_PROPS.INJECT])); | ||
handlesSet.add(siloContext.name); | ||
this._singletonsServicesHandles.set(serviceName, handlesSet); | ||
this._singletonsServicesDescriptors.set(serviceName, serviceDescriptorPromise); | ||
} else { | ||
siloContext.servicesDescriptors.set(serviceName, serviceDescriptorPromise); | ||
} | ||
return serviceDescriptorPromise; | ||
} | ||
serviceDescriptorPromise = serviceDescriptorPromise.then(function (servicesHash) { | ||
debug('Successfully gathered service dependencies:', serviceName); | ||
return serviceProvider[_util.SPECIAL_PROPS.INJECT].reduce(function (finalHash, dependencyDeclaration) { | ||
var _parseDependencyDecla2 = (0, _util.parseDependencyDeclaration)(dependencyDeclaration), | ||
serviceName = _parseDependencyDecla2.serviceName, | ||
mappedName = _parseDependencyDecla2.mappedName; | ||
/** | ||
* Initialize a service dependencies | ||
* @param {Object} siloContext Current execution silo siloContext | ||
* @param {String} serviceName Service name. | ||
* @param {String} servicesDeclarations Dependencies declarations. | ||
* @param {Boolean} injectOnly Flag indicating if existing services only should be used | ||
* @return {Promise} Service dependencies hash promise. | ||
*/ | ||
_initializeDependencies(siloContext, serviceName, servicesDeclarations, injectOnly = false) { | ||
debug('Initializing dependencies:', serviceName, servicesDeclarations); | ||
return Promise.resolve().then(() => Promise.all(servicesDeclarations.map(serviceDeclaration => { | ||
const { mappedName, optional } = (0, _util.parseDependencyDeclaration)(serviceDeclaration); | ||
finalHash[serviceName] = servicesHash[mappedName]; | ||
return finalHash; | ||
}, {}); | ||
}).then(serviceProvider).then(function (serviceDescriptor) { | ||
if (!serviceDescriptor) { | ||
debug('Provider did not return a descriptor:', serviceName); | ||
return Promise.reject(new _yerror2.default(E_BAD_SERVICE_PROVIDER, serviceName)); | ||
return this._getServiceDescriptor(siloContext, injectOnly, mappedName).catch(err => { | ||
if (optional) { | ||
return Promise.resolve(); | ||
} | ||
debug('Successfully initialized a service descriptor:', serviceName); | ||
if (serviceDescriptor.fatalErrorPromise) { | ||
debug('Registering service descriptor error promise:', serviceName); | ||
siloContext.errorsPromises.push(serviceDescriptor.fatalErrorPromise); | ||
} | ||
siloContext.servicesDescriptors.set(serviceName, serviceDescriptor); | ||
return serviceDescriptor; | ||
}).catch(function (err) { | ||
debug('Error initializing a service descriptor:', serviceName, err.stack); | ||
if (E_UNMATCHED_DEPENDENCY === err.code) { | ||
throw _yerror2.default.wrap.apply(_yerror2.default, _toConsumableArray([err, E_UNMATCHED_DEPENDENCY, serviceName].concat(err.params))); | ||
} | ||
throw err; | ||
}); | ||
if (serviceProvider[_util.SPECIAL_PROPS.OPTIONS].singleton) { | ||
var handlesSet = new Set(); | ||
})).then(servicesDescriptors => { | ||
debug('Initialized dependencies descriptors:', serviceName, servicesDeclarations); | ||
siloContext.servicesSequence.push(servicesDeclarations.map(_pickMappedNameFromDeclaration)); | ||
return Promise.all(servicesDescriptors.map(serviceDescriptor => { | ||
if (!serviceDescriptor) { | ||
return {}.undef; | ||
} | ||
return serviceDescriptor.service; | ||
})); | ||
}).then(services => services.reduce((hash, service, index) => { | ||
const mappedName = _pickMappedNameFromDeclaration(servicesDeclarations[index]); | ||
handlesSet.add(siloContext.name); | ||
this._singletonsServicesHandles.set(serviceName, handlesSet); | ||
this._singletonsServicesDescriptors.set(serviceName, serviceDescriptorPromise); | ||
} else { | ||
siloContext.servicesDescriptors.set(serviceName, serviceDescriptorPromise); | ||
} | ||
return serviceDescriptorPromise; | ||
} | ||
hash[mappedName] = service; | ||
return hash; | ||
}, {}))); | ||
} | ||
} | ||
/** | ||
* Initialize a service dependencies | ||
* @param {Object} siloContext Current execution silo siloContext | ||
* @param {String} serviceName Service name. | ||
* @param {String} servicesDeclarations Dependencies declarations. | ||
* @param {Boolean} injectOnly Flag indicating if existing services only should be used | ||
* @return {Promise} Service dependencies hash promise. | ||
*/ | ||
}, { | ||
key: '_initializeDependencies', | ||
value: function _initializeDependencies(siloContext, serviceName, servicesDeclarations) { | ||
var _this7 = this; | ||
var injectOnly = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; | ||
debug('Initializing dependencies:', serviceName, servicesDeclarations); | ||
return Promise.resolve().then(function () { | ||
return Promise.all(servicesDeclarations.map(function (serviceDeclaration) { | ||
var _parseDependencyDecla3 = (0, _util.parseDependencyDeclaration)(serviceDeclaration), | ||
mappedName = _parseDependencyDecla3.mappedName, | ||
optional = _parseDependencyDecla3.optional; | ||
return _this7._getServiceDescriptor(siloContext, injectOnly, mappedName).catch(function (err) { | ||
if (optional) { | ||
return Promise.resolve(); | ||
} | ||
throw err; | ||
}); | ||
})).then(function (servicesDescriptors) { | ||
debug('Initialized dependencies descriptors:', serviceName, servicesDeclarations); | ||
siloContext.servicesSequence.push(servicesDeclarations.map(_pickMappedNameFromDeclaration)); | ||
return Promise.all(servicesDescriptors.map(function (serviceDescriptor) { | ||
if (!serviceDescriptor) { | ||
return {}.undef; | ||
} | ||
return serviceDescriptor.service; | ||
})); | ||
}).then(function (services) { | ||
return services.reduce(function (hash, service, index) { | ||
var mappedName = _pickMappedNameFromDeclaration(servicesDeclarations[index]); | ||
hash[mappedName] = service; | ||
return hash; | ||
}, {}); | ||
}); | ||
}); | ||
} | ||
}], [{ | ||
key: 'getInstance', | ||
value: function getInstance() { | ||
Knifecycle[INSTANCE] = Knifecycle[INSTANCE] || new Knifecycle(); | ||
debug('Spawning an instance.'); | ||
return Knifecycle[INSTANCE]; | ||
} | ||
}]); | ||
return Knifecycle; | ||
}(); | ||
exports.default = Knifecycle; | ||
var getInstance = exports.getInstance = Knifecycle.getInstance; | ||
const getInstance = exports.getInstance = Knifecycle.getInstance; | ||
exports.Knifecycle = Knifecycle; | ||
@@ -744,4 +654,3 @@ exports.initializer = _util.initializer; | ||
function _pickServiceNameFromDeclaration(dependencyDeclaration) { | ||
var _parseDependencyDecla4 = (0, _util.parseDependencyDeclaration)(dependencyDeclaration), | ||
serviceName = _parseDependencyDecla4.serviceName; | ||
const { serviceName } = (0, _util.parseDependencyDeclaration)(dependencyDeclaration); | ||
@@ -752,5 +661,3 @@ return serviceName; | ||
function _pickMappedNameFromDeclaration(dependencyDeclaration) { | ||
var _parseDependencyDecla5 = (0, _util.parseDependencyDeclaration)(dependencyDeclaration), | ||
serviceName = _parseDependencyDecla5.serviceName, | ||
mappedName = _parseDependencyDecla5.mappedName; | ||
const { serviceName, mappedName } = (0, _util.parseDependencyDeclaration)(dependencyDeclaration); | ||
@@ -761,4 +668,4 @@ return mappedName || serviceName; | ||
function _applyShapes(shapes, serviceName) { | ||
return shapes.reduce(function (shapedService, shape) { | ||
var matches = void 0; | ||
return shapes.reduce((shapedService, shape) => { | ||
let matches; | ||
@@ -772,5 +679,3 @@ if (shapedService) { | ||
} | ||
return shape.template.replace(/\$([0-9])+/g, function ($, $1) { | ||
return matches[parseInt($1, 10)]; | ||
}); | ||
return shape.template.replace(/\$([0-9])+/g, ($, $1) => matches[parseInt($1, 10)]); | ||
}, ''); | ||
@@ -780,12 +685,7 @@ } | ||
function _applyClasses(classes, styles, links) { | ||
return links.reduce(function (classesApplications, link) { | ||
return Object.assign(classesApplications, _applyStyles(classes, styles, link)); | ||
}, {}); | ||
return links.reduce((classesApplications, link) => Object.assign(classesApplications, _applyStyles(classes, styles, link)), {}); | ||
} | ||
function _applyStyles(classes, styles, _ref4) { | ||
var serviceName = _ref4.serviceName, | ||
dependedServiceName = _ref4.dependedServiceName; | ||
return styles.reduce(function (classesApplications, style) { | ||
function _applyStyles(classes, styles, { serviceName, dependedServiceName }) { | ||
return styles.reduce((classesApplications, style) => { | ||
if (style.pattern.test(serviceName) && !classesApplications[serviceName]) { | ||
@@ -808,3 +708,3 @@ if (!classes[style.className]) { | ||
function serviceAdapter(serviceName, initializer, dependenciesHash) { | ||
var servicePromise = initializer(dependenciesHash); | ||
const servicePromise = initializer(dependenciesHash); | ||
@@ -814,7 +714,5 @@ if (!servicePromise || !servicePromise.then) { | ||
} | ||
return servicePromise.then(function (_service_) { | ||
return Promise.resolve({ | ||
service: _service_ | ||
}); | ||
}); | ||
return servicePromise.then(_service_ => Promise.resolve({ | ||
service: _service_ | ||
})); | ||
} |
'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 _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /* eslint max-nested-callbacks:0 */ | ||
var _assert = require('assert'); | ||
@@ -19,8 +15,8 @@ | ||
describe('Knifecycle', function () { | ||
var $ = void 0; | ||
var ENV = { | ||
describe('Knifecycle', () => { | ||
let $; | ||
const ENV = { | ||
MY_ENV_VAR: 'plop' | ||
}; | ||
var time = Date.now.bind(Date); | ||
const time = Date.now.bind(Date); | ||
@@ -37,12 +33,12 @@ function timeService() { | ||
beforeEach(function () { | ||
beforeEach(() => { | ||
$ = new _index.Knifecycle(); | ||
}); | ||
describe('getInstance', function () { | ||
it('should return an instance', function () { | ||
describe('getInstance', () => { | ||
it('should return an instance', () => { | ||
(0, _assert2.default)(_index.Knifecycle.getInstance()); | ||
}); | ||
it('should always return the same instance', function () { | ||
it('should always return the same instance', () => { | ||
_assert2.default.equal(_index.Knifecycle.getInstance(), _index.Knifecycle.getInstance()); | ||
@@ -52,13 +48,13 @@ }); | ||
describe('constant', function () { | ||
it('should register an object', function () { | ||
describe('constant', () => { | ||
it('should register an object', () => { | ||
$.constant('ENV', ENV); | ||
}); | ||
it('should register a function', function () { | ||
it('should register a function', () => { | ||
$.constant('time', time); | ||
}); | ||
it('should fail with dependencies since it makes no sense', function () { | ||
_assert2.default.throws(function () { | ||
it('should fail with dependencies since it makes no sense', () => { | ||
_assert2.default.throws(() => { | ||
$.constant('time', (0, _index.inject)(['hash3'], time)); | ||
@@ -69,4 +65,4 @@ }, 'E_CONSTANT_INJECTION'); | ||
describe('service', function () { | ||
it('should register service', function () { | ||
describe('service', () => { | ||
it('should register service', () => { | ||
$.service('time', timeService); | ||
@@ -76,11 +72,11 @@ }); | ||
describe('provider', function () { | ||
it('should register provider', function () { | ||
describe('provider', () => { | ||
it('should register provider', () => { | ||
$.provider('hash', hashProvider); | ||
}); | ||
it('should fail with direct circular dependencies', function () { | ||
_assert2.default.throws(function () { | ||
it('should fail with direct circular dependencies', () => { | ||
_assert2.default.throws(() => { | ||
$.provider('hash', (0, _index.inject)(['hash'], hashProvider)); | ||
}, function (err) { | ||
}, err => { | ||
_assert2.default.deepEqual(err.code, 'E_CIRCULAR_DEPENDENCY'); | ||
@@ -92,6 +88,6 @@ _assert2.default.deepEqual(err.params, ['hash']); | ||
it('should fail with direct circular dependencies on mapped services', function () { | ||
_assert2.default.throws(function () { | ||
it('should fail with direct circular dependencies on mapped services', () => { | ||
_assert2.default.throws(() => { | ||
$.provider('hash', (0, _index.inject)(['hash>lol'], hashProvider)); | ||
}, function (err) { | ||
}, err => { | ||
_assert2.default.deepEqual(err.code, 'E_CIRCULAR_DEPENDENCY'); | ||
@@ -103,4 +99,4 @@ _assert2.default.deepEqual(err.params, ['hash']); | ||
it('should fail with circular dependencies', function () { | ||
_assert2.default.throws(function () { | ||
it('should fail with circular dependencies', () => { | ||
_assert2.default.throws(() => { | ||
$.provider('hash', (0, _index.inject)(['hash3'], hashProvider)); | ||
@@ -110,3 +106,3 @@ $.provider('hash1', (0, _index.inject)(['hash'], hashProvider)); | ||
$.provider('hash3', (0, _index.inject)(['hash'], hashProvider)); | ||
}, function (err) { | ||
}, err => { | ||
_assert2.default.deepEqual(err.code, 'E_CIRCULAR_DEPENDENCY'); | ||
@@ -118,4 +114,4 @@ _assert2.default.deepEqual(err.params, ['hash3', 'hash', 'hash3']); | ||
it('should fail with deeper circular dependencies', function () { | ||
_assert2.default.throws(function () { | ||
it('should fail with deeper circular dependencies', () => { | ||
_assert2.default.throws(() => { | ||
$.provider('hash', (0, _index.inject)(['hash1'], hashProvider)); | ||
@@ -125,3 +121,3 @@ $.provider('hash1', (0, _index.inject)(['hash2'], hashProvider)); | ||
$.provider('hash3', (0, _index.inject)(['hash'], hashProvider)); | ||
}, function (err) { | ||
}, err => { | ||
_assert2.default.deepEqual(err.code, 'E_CIRCULAR_DEPENDENCY'); | ||
@@ -133,4 +129,4 @@ _assert2.default.deepEqual(err.params, ['hash3', 'hash', 'hash1', 'hash2', 'hash3']); | ||
it('should fail with circular dependencies on mapped services', function () { | ||
_assert2.default.throws(function () { | ||
it('should fail with circular dependencies on mapped services', () => { | ||
_assert2.default.throws(() => { | ||
$.provider('hash', (0, _index.inject)(['hash3>aHash3'], hashProvider)); | ||
@@ -140,3 +136,3 @@ $.provider('hash1', (0, _index.inject)(['hash>aHash'], hashProvider)); | ||
$.provider('hash3', (0, _index.inject)(['hash>aHash'], hashProvider)); | ||
}, function (err) { | ||
}, err => { | ||
_assert2.default.deepEqual(err.code, 'E_CIRCULAR_DEPENDENCY'); | ||
@@ -149,35 +145,29 @@ _assert2.default.deepEqual(err.params, ['hash3', 'hash>aHash', 'hash3>aHash3']); | ||
describe('run', function () { | ||
it('should work with no dependencies', function (done) { | ||
$.run([]).then(function (dependencies) { | ||
describe('run', () => { | ||
it('should work with no dependencies', done => { | ||
$.run([]).then(dependencies => { | ||
_assert2.default.deepEqual(dependencies, {}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with constant dependencies', function (done) { | ||
it('should work with constant dependencies', done => { | ||
$.constant('ENV', ENV); | ||
$.constant('time', time); | ||
$.run(['time', 'ENV']).then(function (dependencies) { | ||
$.run(['time', 'ENV']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['time', 'ENV']); | ||
_assert2.default.deepEqual(dependencies, { | ||
ENV: ENV, | ||
time: time | ||
ENV, | ||
time | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with service dependencies', function (done) { | ||
$.service('sample', (0, _index.inject)(['time'], function sampleService(_ref) { | ||
var time = _ref.time; | ||
return Promise.resolve(typeof time === 'undefined' ? 'undefined' : _typeof(time)); | ||
it('should work with service dependencies', done => { | ||
$.service('sample', (0, _index.inject)(['time'], function sampleService({ time }) { | ||
return Promise.resolve(typeof time); | ||
})); | ||
$.constant('time', time); | ||
$.run(['sample']).then(function (dependencies) { | ||
$.run(['sample']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['sample']); | ||
@@ -187,8 +177,6 @@ _assert2.default.deepEqual(dependencies, { | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with simple dependencies', function (done) { | ||
it('should work with simple dependencies', done => { | ||
$.constant('ENV', ENV); | ||
@@ -198,14 +186,12 @@ $.constant('time', time); | ||
$.run(['time', 'hash']).then(function (dependencies) { | ||
$.run(['time', 'hash']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['time', 'hash']); | ||
_assert2.default.deepEqual(dependencies, { | ||
hash: { ENV: ENV }, | ||
time: time | ||
hash: { ENV }, | ||
time | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with given optional dependencies', function (done) { | ||
it('should work with given optional dependencies', done => { | ||
$.constant('ENV', ENV); | ||
@@ -216,14 +202,12 @@ $.constant('DEBUG', {}); | ||
$.run(['time', 'hash']).then(function (dependencies) { | ||
$.run(['time', 'hash']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['time', 'hash']); | ||
_assert2.default.deepEqual(dependencies, { | ||
hash: { ENV: ENV, DEBUG: {} }, | ||
time: time | ||
hash: { ENV, DEBUG: {} }, | ||
time | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with lacking optional dependencies', function (done) { | ||
it('should work with lacking optional dependencies', done => { | ||
$.constant('ENV', ENV); | ||
@@ -233,14 +217,12 @@ $.constant('time', time); | ||
$.run(['time', 'hash']).then(function (dependencies) { | ||
$.run(['time', 'hash']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['time', 'hash']); | ||
_assert2.default.deepEqual(dependencies, { | ||
hash: { ENV: ENV, DEBUG: {}.undef }, | ||
time: time | ||
hash: { ENV, DEBUG: {}.undef }, | ||
time | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with deeper dependencies', function (done) { | ||
it('should work with deeper dependencies', done => { | ||
$.constant('ENV', ENV); | ||
@@ -255,11 +237,9 @@ $.constant('time', time); | ||
$.run(['hash5', 'time']).then(function (dependencies) { | ||
$.run(['hash5', 'time']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['hash5', 'time']); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should instanciate services once', function (done) { | ||
var timeServiceStub = _sinon2.default.spy(timeService); | ||
it('should instanciate services once', done => { | ||
const timeServiceStub = _sinon2.default.spy(timeService); | ||
@@ -272,15 +252,13 @@ $.constant('ENV', ENV); | ||
$.run(['hash', 'hash2', 'hash3', 'time']).then(function (dependencies) { | ||
$.run(['hash', 'hash2', 'hash3', 'time']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['hash', 'hash2', 'hash3', 'time']); | ||
_assert2.default.deepEqual(timeServiceStub.args, [[{}]]); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should instanciate a single mapped service', function (done) { | ||
var providerStub = _sinon2.default.stub().returns(Promise.resolve({ | ||
it('should instanciate a single mapped service', done => { | ||
const providerStub = _sinon2.default.stub().returns(Promise.resolve({ | ||
service: 'stub' | ||
})); | ||
var providerStub2 = _sinon2.default.stub().returns(Promise.resolve({ | ||
const providerStub2 = _sinon2.default.stub().returns(Promise.resolve({ | ||
service: 'stub2' | ||
@@ -291,3 +269,3 @@ })); | ||
$.provider('mappedStub2', providerStub2); | ||
$.run(['stub>mappedStub']).then(function (dependencies) { | ||
$.run(['stub>mappedStub']).then(dependencies => { | ||
_assert2.default.deepEqual(dependencies, { | ||
@@ -299,9 +277,7 @@ stub: 'stub' | ||
}]]); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should instanciate several services with mappings', function (done) { | ||
var timeServiceStub = _sinon2.default.spy(timeService); | ||
it('should instanciate several services with mappings', done => { | ||
const timeServiceStub = _sinon2.default.spy(timeService); | ||
@@ -314,60 +290,48 @@ $.constant('ENV', ENV); | ||
$.run(['hash2>aHash2', 'hash3>aHash3', 'time>aTime']).then(function (dependencies) { | ||
$.run(['hash2>aHash2', 'hash3>aHash3', 'time>aTime']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['hash2', 'hash3', 'time']); | ||
_assert2.default.deepEqual(timeServiceStub.args, [[{}]]); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should fail with bad service', function (done) { | ||
$.service('lol', function () {}); | ||
$.run(['lol']).then(function () { | ||
it('should fail with bad service', done => { | ||
$.service('lol', () => {}); | ||
$.run(['lol']).then(() => { | ||
throw new Error('E_UNEXPECTED_SUCCESS'); | ||
}).catch(function (err) { | ||
}).catch(err => { | ||
_assert2.default.deepEqual(err.code, 'E_BAD_SERVICE_PROMISE'); | ||
_assert2.default.deepEqual(err.params, ['lol']); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should fail with bad provider', function (done) { | ||
$.provider('lol', function () {}); | ||
$.run(['lol']).then(function () { | ||
it('should fail with bad provider', done => { | ||
$.provider('lol', () => {}); | ||
$.run(['lol']).then(() => { | ||
throw new Error('E_UNEXPECTED_SUCCESS'); | ||
}).catch(function (err) { | ||
}).catch(err => { | ||
_assert2.default.deepEqual(err.code, 'E_BAD_SERVICE_PROVIDER'); | ||
_assert2.default.deepEqual(err.params, ['lol']); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should fail with bad service in a provider', function (done) { | ||
$.provider('lol', function () { | ||
return Promise.resolve(); | ||
}); | ||
$.run(['lol']).then(function () { | ||
it('should fail with bad service in a provider', done => { | ||
$.provider('lol', () => Promise.resolve()); | ||
$.run(['lol']).then(() => { | ||
throw new Error('E_UNEXPECTED_SUCCESS'); | ||
}).catch(function (err) { | ||
}).catch(err => { | ||
_assert2.default.deepEqual(err.code, 'E_BAD_SERVICE_PROVIDER'); | ||
_assert2.default.deepEqual(err.params, ['lol']); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should fail with undeclared dependencies', function (done) { | ||
$.run(['lol']).then(function () { | ||
it('should fail with undeclared dependencies', done => { | ||
$.run(['lol']).then(() => { | ||
throw new Error('E_UNEXPECTED_SUCCESS'); | ||
}).catch(function (err) { | ||
}).catch(err => { | ||
_assert2.default.deepEqual(err.code, 'E_UNMATCHED_DEPENDENCY'); | ||
_assert2.default.deepEqual(err.params, ['lol']); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should fail with undeclared dependencies upstream', function (done) { | ||
it('should fail with undeclared dependencies upstream', done => { | ||
$.constant('ENV', ENV); | ||
@@ -378,13 +342,11 @@ $.constant('time', time); | ||
$.run(['time', 'hash']).then(function () { | ||
$.run(['time', 'hash']).then(() => { | ||
throw new Error('E_UNEXPECTED_SUCCESS'); | ||
}).catch(function (err) { | ||
}).catch(err => { | ||
_assert2.default.deepEqual(err.code, 'E_UNMATCHED_DEPENDENCY'); | ||
_assert2.default.deepEqual(err.params, ['hash', 'hash2', 'lol']); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should provide a fatal error handler', function (done) { | ||
it('should provide a fatal error handler', done => { | ||
$.constant('ENV', ENV); | ||
@@ -396,5 +358,3 @@ $.constant('time', time); | ||
function processProvider(_ref2) { | ||
var $fatalError = _ref2.$fatalError; | ||
function processProvider({ $fatalError }) { | ||
return Promise.resolve({ | ||
@@ -407,12 +367,10 @@ service: { | ||
function dbProvider(_ref3) { | ||
var ENV = _ref3.ENV; | ||
return Promise.resolve().then(function () { | ||
var service = void 0; | ||
var fatalErrorPromise = new Promise(function (resolve, reject) { | ||
function dbProvider({ ENV }) { | ||
return Promise.resolve().then(() => { | ||
let service; | ||
const fatalErrorPromise = new Promise((resolve, reject) => { | ||
service = Promise.resolve({ | ||
resolve: resolve, | ||
reject: reject, | ||
ENV: ENV | ||
resolve, | ||
reject, | ||
ENV | ||
}); | ||
@@ -422,4 +380,4 @@ }); | ||
return { | ||
service: service, | ||
fatalErrorPromise: fatalErrorPromise | ||
service, | ||
fatalErrorPromise | ||
}; | ||
@@ -429,13 +387,8 @@ }); | ||
$.run(['time', 'hash', 'db', 'process']).then(function (_ref4) { | ||
var process = _ref4.process, | ||
db = _ref4.db; | ||
process.fatalErrorPromise.then(function () { | ||
$.run(['time', 'hash', 'db', 'process']).then(({ process, db }) => { | ||
process.fatalErrorPromise.then(() => { | ||
done(new Error('E_UNEXPECTED_SUCCESS')); | ||
}).catch(function (err) { | ||
}).catch(err => { | ||
_assert2.default.deepEqual(err.message, 'E_DB_ERROR'); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
db.reject(new Error('E_DB_ERROR')); | ||
@@ -446,4 +399,4 @@ }).catch(done); | ||
describe('inject', function () { | ||
it('should work with no dependencies', function (done) { | ||
describe('inject', () => { | ||
it('should work with no dependencies', done => { | ||
$.constant('ENV', ENV); | ||
@@ -453,14 +406,12 @@ $.constant('time', time); | ||
$.run(['time', 'hash', '$injector']).then(function (dependencies) { | ||
$.run(['time', 'hash', '$injector']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['time', 'hash', '$injector']); | ||
return dependencies.$injector([]).then(function (injectDependencies) { | ||
return dependencies.$injector([]).then(injectDependencies => { | ||
_assert2.default.deepEqual(Object.keys(injectDependencies), []); | ||
_assert2.default.deepEqual(injectDependencies, {}); | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with same dependencies then the running silo', function (done) { | ||
it('should work with same dependencies then the running silo', done => { | ||
$.constant('ENV', ENV); | ||
@@ -470,17 +421,15 @@ $.constant('time', time); | ||
$.run(['time', 'hash', '$injector']).then(function (dependencies) { | ||
$.run(['time', 'hash', '$injector']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['time', 'hash', '$injector']); | ||
return dependencies.$injector(['time', 'hash']).then(function (injectDependencies) { | ||
return dependencies.$injector(['time', 'hash']).then(injectDependencies => { | ||
_assert2.default.deepEqual(Object.keys(injectDependencies), ['time', 'hash']); | ||
_assert2.default.deepEqual(injectDependencies, { | ||
hash: { ENV: ENV }, | ||
time: time | ||
hash: { ENV }, | ||
time | ||
}); | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should fail with non instanciated dependencies', function (done) { | ||
it('should fail with non instanciated dependencies', done => { | ||
$.constant('ENV', ENV); | ||
@@ -490,33 +439,23 @@ $.constant('time', time); | ||
$.run(['time', '$injector']).then(function (dependencies) { | ||
$.run(['time', '$injector']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['time', '$injector']); | ||
return dependencies.$injector(['time', 'hash']).catch(function (err) { | ||
return dependencies.$injector(['time', 'hash']).catch(err => { | ||
_assert2.default.equal(err.code, 'E_BAD_INJECTION'); | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should create dependencies when not declared as singletons', function (done) { | ||
it('should create dependencies when not declared as singletons', done => { | ||
$.constant('ENV', ENV); | ||
$.provider('hash', (0, _index.inject)(['ENV'], hashProvider)); | ||
Promise.all([$.run(['hash']), $.run(['hash'])]).then(function (_ref5) { | ||
var _ref6 = _slicedToArray(_ref5, 2), | ||
hash = _ref6[0].hash, | ||
sameHash = _ref6[1].hash; | ||
Promise.all([$.run(['hash']), $.run(['hash'])]).then(([{ hash }, { hash: sameHash }]) => { | ||
_assert2.default.notEqual(hash, sameHash); | ||
return $.run(['hash']).then(function (_ref7) { | ||
var yaSameHash = _ref7.hash; | ||
return $.run(['hash']).then(({ hash: yaSameHash }) => { | ||
_assert2.default.notEqual(hash, yaSameHash); | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should reuse dependencies when declared as singletons', function (done) { | ||
it('should reuse dependencies when declared as singletons', done => { | ||
$.constant('ENV', ENV); | ||
@@ -530,36 +469,22 @@ $.provider('hash', (0, _index.inject)(['ENV'], hashProvider), { | ||
Promise.all([$.run(['hash']), $.run(['hash']), $.run(['hash2']), $.run(['hash2'])]).then(function (_ref8) { | ||
var _ref9 = _slicedToArray(_ref8, 2), | ||
_ref9$ = _ref9[0], | ||
hash = _ref9$.hash, | ||
hash2 = _ref9$.hash2, | ||
_ref9$2 = _ref9[1], | ||
sameHash = _ref9$2.hash, | ||
sameHash2 = _ref9$2.hash2; | ||
Promise.all([$.run(['hash']), $.run(['hash']), $.run(['hash2']), $.run(['hash2'])]).then(([{ hash, hash2 }, { hash: sameHash, hash2: sameHash2 }]) => { | ||
_assert2.default.equal(hash, sameHash); | ||
_assert2.default.equal(hash2, sameHash2); | ||
return $.run(['hash']).then(function (_ref10) { | ||
var yaSameHash = _ref10.hash; | ||
return $.run(['hash']).then(({ hash: yaSameHash }) => { | ||
_assert2.default.equal(hash, yaSameHash); | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
}); | ||
describe('$destroy', function () { | ||
it('should work even with one silo and no dependencies', function (done) { | ||
$.run(['$destroy']).then(function (dependencies) { | ||
_assert2.default.equal(_typeof(dependencies.$destroy), 'function'); | ||
describe('$destroy', () => { | ||
it('should work even with one silo and no dependencies', done => { | ||
$.run(['$destroy']).then(dependencies => { | ||
_assert2.default.equal(typeof dependencies.$destroy, 'function'); | ||
return dependencies.$destroy(); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with several silos and dependencies', function (done) { | ||
it('should work with several silos and dependencies', done => { | ||
$.constant('ENV', ENV); | ||
@@ -571,15 +496,10 @@ $.constant('time', time); | ||
Promise.all([$.run(['$destroy']), $.run(['ENV', 'hash', 'hash1', 'time']), $.run(['ENV', 'hash', 'hash2'])]).then(function (_ref11) { | ||
var _ref12 = _slicedToArray(_ref11, 1), | ||
dependencies = _ref12[0]; | ||
Promise.all([$.run(['$destroy']), $.run(['ENV', 'hash', 'hash1', 'time']), $.run(['ENV', 'hash', 'hash2'])]).then(([dependencies]) => { | ||
_assert2.default.equal(typeof dependencies.$destroy, 'function'); | ||
_assert2.default.equal(_typeof(dependencies.$destroy), 'function'); | ||
return dependencies.$destroy(); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work when trigered from several silos simultaneously', function (done) { | ||
it('should work when trigered from several silos simultaneously', done => { | ||
$.constant('ENV', ENV); | ||
@@ -591,12 +511,6 @@ $.constant('time', time); | ||
Promise.all([$.run(['$destroy']), $.run(['$destroy', 'ENV', 'hash', 'hash1', 'time']), $.run(['$destroy', 'ENV', 'hash', 'hash2'])]).then(function (dependenciesBuckets) { | ||
return Promise.all(dependenciesBuckets.map(function (dependencies) { | ||
return dependencies.$destroy(); | ||
})); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
Promise.all([$.run(['$destroy']), $.run(['$destroy', 'ENV', 'hash', 'hash1', 'time']), $.run(['$destroy', 'ENV', 'hash', 'hash2'])]).then(dependenciesBuckets => Promise.all(dependenciesBuckets.map(dependencies => dependencies.$destroy()))).then(() => done()).catch(done); | ||
}); | ||
it('should work when a silo shutdown is in progress', function (done) { | ||
it('should work when a silo shutdown is in progress', done => { | ||
$.constant('ENV', ENV); | ||
@@ -608,14 +522,6 @@ $.constant('time', time); | ||
Promise.all([$.run(['$destroy']), $.run(['$dispose', 'ENV', 'hash', 'hash1', 'time']), $.run(['ENV', 'hash', 'hash2'])]).then(function (_ref13) { | ||
var _ref14 = _slicedToArray(_ref13, 2), | ||
dependencies1 = _ref14[0], | ||
dependencies2 = _ref14[1]; | ||
return Promise.all([dependencies2.$dispose(), dependencies1.$destroy()]); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
Promise.all([$.run(['$destroy']), $.run(['$dispose', 'ENV', 'hash', 'hash1', 'time']), $.run(['ENV', 'hash', 'hash2'])]).then(([dependencies1, dependencies2]) => Promise.all([dependencies2.$dispose(), dependencies1.$destroy()])).then(() => done()).catch(done); | ||
}); | ||
it('should disallow new runs', function (done) { | ||
it('should disallow new runs', done => { | ||
$.constant('ENV', ENV); | ||
@@ -626,44 +532,36 @@ $.constant('time', time); | ||
$.run(['$destroy']).then(function (dependencies) { | ||
_assert2.default.equal(_typeof(dependencies.$destroy), 'function'); | ||
$.run(['$destroy']).then(dependencies => { | ||
_assert2.default.equal(typeof dependencies.$destroy, 'function'); | ||
return dependencies.$destroy(); | ||
}).then(function () { | ||
_assert2.default.throws(function () { | ||
return $.run(['ENV', 'hash', 'hash1']); | ||
}, function (err) { | ||
}).then(() => { | ||
_assert2.default.throws(() => $.run(['ENV', 'hash', 'hash1']), err => { | ||
_assert2.default.equal(err.code, 'E_INSTANCE_DESTROYED'); | ||
return true; | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
}); | ||
describe('$dispose', function () { | ||
it('should work with no dependencies', function (done) { | ||
$.run(['$dispose']).then(function (dependencies) { | ||
_assert2.default.equal(_typeof(dependencies.$dispose), 'function'); | ||
describe('$dispose', () => { | ||
it('should work with no dependencies', done => { | ||
$.run(['$dispose']).then(dependencies => { | ||
_assert2.default.equal(typeof dependencies.$dispose, 'function'); | ||
return dependencies.$dispose(); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with constant dependencies', function (done) { | ||
it('should work with constant dependencies', done => { | ||
$.constant('ENV', ENV); | ||
$.constant('time', time); | ||
$.run(['time', 'ENV', '$dispose']).then(function (dependencies) { | ||
$.run(['time', 'ENV', '$dispose']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['time', 'ENV', '$dispose']); | ||
return dependencies.$dispose(); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with simple dependencies', function (done) { | ||
it('should work with simple dependencies', done => { | ||
$.constant('ENV', ENV); | ||
@@ -673,20 +571,18 @@ $.constant('time', time); | ||
$.run(['time', 'hash', '$dispose']).then(function (dependencies) { | ||
$.run(['time', 'hash', '$dispose']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['time', 'hash', '$dispose']); | ||
return dependencies.$dispose(); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should work with deeper dependencies', function (done) { | ||
var shutdownCallResolve = void 0; | ||
var shutdownResolve = void 0; | ||
var shutdownCallPromise = new Promise(function (resolve) { | ||
it('should work with deeper dependencies', done => { | ||
let shutdownCallResolve; | ||
let shutdownResolve; | ||
const shutdownCallPromise = new Promise(resolve => { | ||
shutdownCallResolve = resolve; | ||
}); | ||
var shutdownStub = _sinon2.default.spy(function () { | ||
const shutdownStub = _sinon2.default.spy(() => { | ||
shutdownCallResolve(); | ||
return new Promise(function (resolve) { | ||
return new Promise(resolve => { | ||
shutdownResolve = resolve; | ||
@@ -704,16 +600,14 @@ }); | ||
$.provider('hash5', (0, _index.inject)(['hash4'], hashProvider)); | ||
$.provider('shutdownChecker', (0, _index.inject)(['hash4'], function () { | ||
return Promise.resolve({ | ||
service: { | ||
shutdownStub: shutdownStub, | ||
shutdownResolve: shutdownResolve | ||
}, | ||
dispose: shutdownStub | ||
}); | ||
})); | ||
$.provider('shutdownChecker', (0, _index.inject)(['hash4'], () => Promise.resolve({ | ||
service: { | ||
shutdownStub, | ||
shutdownResolve | ||
}, | ||
dispose: shutdownStub | ||
}))); | ||
$.run(['hash5', 'time', '$dispose', 'shutdownChecker']).then(function (dependencies) { | ||
$.run(['hash5', 'time', '$dispose', 'shutdownChecker']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['hash5', 'time', '$dispose', 'shutdownChecker']); | ||
shutdownCallPromise.then(function () { | ||
shutdownCallPromise.then(() => { | ||
_assert2.default.deepEqual(shutdownStub.args, [[]]); | ||
@@ -727,11 +621,11 @@ shutdownResolve(); | ||
it('should work with deeper multi used dependencies', function (done) { | ||
var shutdownCallResolve = void 0; | ||
var shutdownResolve = void 0; | ||
var shutdownCallPromise = new Promise(function (resolve) { | ||
it('should work with deeper multi used dependencies', done => { | ||
let shutdownCallResolve; | ||
let shutdownResolve; | ||
const shutdownCallPromise = new Promise(resolve => { | ||
shutdownCallResolve = resolve; | ||
}); | ||
var shutdownStub = _sinon2.default.spy(function () { | ||
const shutdownStub = _sinon2.default.spy(() => { | ||
shutdownCallResolve(); | ||
return new Promise(function (resolve) { | ||
return new Promise(resolve => { | ||
shutdownResolve = resolve; | ||
@@ -743,18 +637,16 @@ }); | ||
$.provider('hash', (0, _index.inject)(['ENV'], hashProvider)); | ||
$.provider('shutdownChecker', (0, _index.inject)(['hash'], function () { | ||
return Promise.resolve({ | ||
service: { | ||
shutdownStub: shutdownStub, | ||
shutdownResolve: shutdownResolve | ||
}, | ||
dispose: shutdownStub | ||
}); | ||
})); | ||
$.provider('shutdownChecker', (0, _index.inject)(['hash'], () => Promise.resolve({ | ||
service: { | ||
shutdownStub, | ||
shutdownResolve | ||
}, | ||
dispose: shutdownStub | ||
}))); | ||
$.provider('hash1', (0, _index.inject)(['shutdownChecker'], hashProvider)); | ||
$.provider('hash2', (0, _index.inject)(['shutdownChecker'], hashProvider)); | ||
$.run(['hash1', 'hash2', '$dispose', 'shutdownChecker']).then(function (dependencies) { | ||
$.run(['hash1', 'hash2', '$dispose', 'shutdownChecker']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['hash1', 'hash2', '$dispose', 'shutdownChecker']); | ||
shutdownCallPromise.then(function () { | ||
shutdownCallPromise.then(() => { | ||
_assert2.default.deepEqual(shutdownStub.args, [[]]); | ||
@@ -765,42 +657,30 @@ shutdownResolve(); | ||
return dependencies.$dispose(); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should delay service shutdown to their deeper dependencies', function (done) { | ||
var servicesShutdownCalls = _sinon2.default.spy(function () { | ||
return Promise.resolve(); | ||
}); | ||
it('should delay service shutdown to their deeper dependencies', done => { | ||
const servicesShutdownCalls = _sinon2.default.spy(() => Promise.resolve()); | ||
$.provider('hash', function () { | ||
return Promise.resolve({ | ||
service: {}, | ||
dispose: servicesShutdownCalls.bind(null, 'hash') | ||
}); | ||
}); | ||
$.provider('hash1', (0, _index.inject)(['hash'], function () { | ||
return Promise.resolve({ | ||
service: {}, | ||
dispose: servicesShutdownCalls.bind(null, 'hash1') | ||
}); | ||
$.provider('hash', () => Promise.resolve({ | ||
service: {}, | ||
dispose: servicesShutdownCalls.bind(null, 'hash') | ||
})); | ||
$.provider('hash2', (0, _index.inject)(['hash1', 'hash'], function () { | ||
return Promise.resolve({ | ||
service: {}, | ||
dispose: servicesShutdownCalls.bind(null, 'hash2') | ||
}); | ||
})); | ||
$.provider('hash1', (0, _index.inject)(['hash'], () => Promise.resolve({ | ||
service: {}, | ||
dispose: servicesShutdownCalls.bind(null, 'hash1') | ||
}))); | ||
$.provider('hash2', (0, _index.inject)(['hash1', 'hash'], () => Promise.resolve({ | ||
service: {}, | ||
dispose: servicesShutdownCalls.bind(null, 'hash2') | ||
}))); | ||
$.run(['hash2', '$dispose']).then(function (dependencies) { | ||
$.run(['hash2', '$dispose']).then(dependencies => { | ||
_assert2.default.deepEqual(Object.keys(dependencies), ['hash2', '$dispose']); | ||
return dependencies.$dispose(); | ||
}).then(function () { | ||
}).then(() => { | ||
_assert2.default.deepEqual(servicesShutdownCalls.args, [['hash2'], ['hash1'], ['hash']]); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should not shutdown singleton dependencies if used elsewhere', function (done) { | ||
it('should not shutdown singleton dependencies if used elsewhere', done => { | ||
$.constant('ENV', ENV); | ||
@@ -812,20 +692,15 @@ $.constant('time', time); | ||
$.run(['time', 'hash']).then(function (dependencies) { | ||
var hash = dependencies.hash; | ||
$.run(['time', 'hash']).then(dependencies => { | ||
const { hash } = dependencies; | ||
return $.run(['time', 'hash', '$dispose']).then(function (dependencies) { | ||
return $.run(['time', 'hash', '$dispose']).then(dependencies => { | ||
_assert2.default.equal(dependencies.hash, hash); | ||
return dependencies.$dispose().then(function () { | ||
return $.run(['time', 'hash']).then(function (dependencies) { | ||
_assert2.default.equal(dependencies.hash, hash); | ||
}); | ||
}); | ||
return dependencies.$dispose().then(() => $.run(['time', 'hash']).then(dependencies => { | ||
_assert2.default.equal(dependencies.hash, hash); | ||
})); | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
}).then(() => done()).catch(done); | ||
}); | ||
it('should shutdown singleton dependencies if not used elsewhere', function (done) { | ||
it('should shutdown singleton dependencies if not used elsewhere', done => { | ||
$.constant('ENV', ENV); | ||
@@ -837,19 +712,14 @@ $.constant('time', time); | ||
$.run(['time', 'hash', '$dispose']).then(function (dependencies) { | ||
var hash = dependencies.hash; | ||
$.run(['time', 'hash', '$dispose']).then(dependencies => { | ||
const { hash } = dependencies; | ||
return dependencies.$dispose().then(function () { | ||
return $.run(['time', 'hash']).then(function (dependencies) { | ||
_assert2.default.notEqual(dependencies.hash, hash); | ||
}); | ||
}); | ||
}).then(function () { | ||
return done(); | ||
}).catch(done); | ||
return dependencies.$dispose().then(() => $.run(['time', 'hash']).then(dependencies => { | ||
_assert2.default.notEqual(dependencies.hash, hash); | ||
})); | ||
}).then(() => done()).catch(done); | ||
}); | ||
}); | ||
describe('toMermaidGraph', function () { | ||
it('should print nothing when no dependency', function () { | ||
describe('toMermaidGraph', () => { | ||
it('should print nothing when no dependency', () => { | ||
$.constant('ENV', ENV); | ||
@@ -860,3 +730,3 @@ $.constant('time', time); | ||
it('should print a dependency graph', function () { | ||
it('should print a dependency graph', () => { | ||
$.constant('ENV', ENV); | ||
@@ -873,3 +743,3 @@ $.constant('time', time); | ||
it('should allow custom shapes', function () { | ||
it('should allow custom shapes', () => { | ||
$.constant('ENV', ENV); | ||
@@ -897,3 +767,3 @@ $.constant('time', time); | ||
it('should allow custom styles', function () { | ||
it('should allow custom styles', () => { | ||
$.constant('ENV', ENV); | ||
@@ -931,2 +801,2 @@ $.constant('time', time); | ||
}); | ||
}); | ||
}); /* eslint max-nested-callbacks:0 */ |
@@ -10,14 +10,14 @@ 'use strict'; | ||
var $ = exports.$ = (0, _index.getInstance)(); /* Architecture Note #1.2: One instance to rule them all | ||
We almost never need to use several Knifecycle instances. | ||
This is why we are providing the `knifecycle/instance` | ||
module that give a direct access to a lazy instanciated | ||
`Knifecycle` instance. | ||
At the same time, I prefer choosing when instantiating a | ||
singleton this is why I decided to not do it on the behalf | ||
of the developers by instead providing an opt-in interface | ||
to this singleton. | ||
*/ | ||
const $ = exports.$ = (0, _index.getInstance)(); /* Architecture Note #1.2: One instance to rule them all | ||
We almost never need to use several Knifecycle instances. | ||
This is why we are providing the `knifecycle/instance` | ||
module that give a direct access to a lazy instanciated | ||
`Knifecycle` instance. | ||
At the same time, I prefer choosing when instantiating a | ||
singleton this is why I decided to not do it on the behalf | ||
of the developers by instead providing an opt-in interface | ||
to this singleton. | ||
*/ | ||
exports.default = $; |
@@ -17,6 +17,6 @@ 'use strict'; | ||
describe('Knifecycle instance module', function () { | ||
it('should provide the singleton instance', function () { | ||
describe('Knifecycle instance module', () => { | ||
it('should provide the singleton instance', () => { | ||
_assert2.default.equal(_instance2.default, _index2.default.getInstance()); | ||
}); | ||
}); |
@@ -14,12 +14,10 @@ 'use strict'; | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
const MAX_ITERATIONS = 99; | ||
var MAX_ITERATIONS = 99; | ||
function buildInitializationSequence(rootNode) { | ||
var batches = []; | ||
var i = 0; | ||
const batches = []; | ||
let i = 0; | ||
while (i < MAX_ITERATIONS) { | ||
var batch = recursivelyGetNextSequenceBatch(rootNode, batches); | ||
const batch = recursivelyGetNextSequenceBatch(rootNode, batches); | ||
@@ -40,7 +38,5 @@ if (0 === batch.length) { | ||
function recursivelyGetNextSequenceBatch(node, batches) { | ||
var batch = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; | ||
function recursivelyGetNextSequenceBatch(node, batches, batch = []) { | ||
const nodeIsALeaf = !(node.__childNodes && node.__childNodes.length); | ||
var nodeIsALeaf = !(node.__childNodes && node.__childNodes.length); | ||
if (nodeIsInBatches(batches, node)) { | ||
@@ -54,11 +50,7 @@ return batch; | ||
return node.__childNodes.reduce(function (batch, childNode) { | ||
return [].concat(_toConsumableArray(new Set(recursivelyGetNextSequenceBatch(childNode, batches, batch)))); | ||
}, batch); | ||
return node.__childNodes.reduce((batch, childNode) => [...new Set(recursivelyGetNextSequenceBatch(childNode, batches, batch))], batch); | ||
} | ||
function nodeIsInBatches(batches, node) { | ||
return batches.some(function (batch) { | ||
return batch.includes(node.__name); | ||
}); | ||
return batches.some(batch => batch.includes(node.__name)); | ||
} |
@@ -11,5 +11,5 @@ 'use strict'; | ||
describe('buildInitializationSequence()', function () { | ||
it('should work with one level trees', function () { | ||
var tree = { | ||
describe('buildInitializationSequence()', () => { | ||
it('should work with one level trees', () => { | ||
const tree = { | ||
__name: 'lol' | ||
@@ -21,4 +21,4 @@ }; | ||
it('should work with multi-level trees', function () { | ||
var tree = { | ||
it('should work with multi-level trees', () => { | ||
const tree = { | ||
__name: 'lol', | ||
@@ -57,4 +57,4 @@ __childNodes: [{ | ||
it('should work with multi-level trees and cross dependencies', function () { | ||
var tree = { | ||
it('should work with multi-level trees and cross dependencies', () => { | ||
const tree = { | ||
__name: 'lol', | ||
@@ -61,0 +61,0 @@ __childNodes: [{ |
105
dist/util.js
@@ -7,5 +7,2 @@ 'use strict'; | ||
exports.OPTIONAL_FLAG = exports.DECLARATION_SEPARATOR = exports.ALLOWED_SPECIAL_PROPS = exports.SPECIAL_PROPS = exports.SPECIAL_PROPS_PREFIX = undefined; | ||
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"); } }; }(); | ||
exports.reuseSpecialProps = reuseSpecialProps; | ||
@@ -32,21 +29,15 @@ exports.wrapInitializer = wrapInitializer; | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
const debug = (0, _debug2.default)('knifecycle'); | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
var debug = (0, _debug2.default)('knifecycle'); | ||
var SPECIAL_PROPS_PREFIX = exports.SPECIAL_PROPS_PREFIX = '$'; | ||
var SPECIAL_PROPS = exports.SPECIAL_PROPS = { | ||
INJECT: SPECIAL_PROPS_PREFIX + 'inject', | ||
OPTIONS: SPECIAL_PROPS_PREFIX + 'options', | ||
NAME: SPECIAL_PROPS_PREFIX + 'name', | ||
TYPE: SPECIAL_PROPS_PREFIX + 'type', | ||
EXTRA: SPECIAL_PROPS_PREFIX + 'extra' | ||
const SPECIAL_PROPS_PREFIX = exports.SPECIAL_PROPS_PREFIX = '$'; | ||
const SPECIAL_PROPS = exports.SPECIAL_PROPS = { | ||
INJECT: `${SPECIAL_PROPS_PREFIX}inject`, | ||
OPTIONS: `${SPECIAL_PROPS_PREFIX}options`, | ||
NAME: `${SPECIAL_PROPS_PREFIX}name`, | ||
TYPE: `${SPECIAL_PROPS_PREFIX}type`, | ||
EXTRA: `${SPECIAL_PROPS_PREFIX}extra` | ||
}; | ||
var ALLOWED_SPECIAL_PROPS = exports.ALLOWED_SPECIAL_PROPS = Object.keys(SPECIAL_PROPS).map(function (key) { | ||
return SPECIAL_PROPS[key]; | ||
}); | ||
var DECLARATION_SEPARATOR = exports.DECLARATION_SEPARATOR = '>'; | ||
var OPTIONAL_FLAG = exports.OPTIONAL_FLAG = '?'; | ||
const ALLOWED_SPECIAL_PROPS = exports.ALLOWED_SPECIAL_PROPS = Object.keys(SPECIAL_PROPS).map(key => SPECIAL_PROPS[key]); | ||
const DECLARATION_SEPARATOR = exports.DECLARATION_SEPARATOR = '>'; | ||
const OPTIONAL_FLAG = exports.OPTIONAL_FLAG = '?'; | ||
@@ -60,9 +51,5 @@ /** | ||
*/ | ||
function reuseSpecialProps(from, to) { | ||
var amend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
return [].concat(_toConsumableArray(new Set(Object.keys(from).concat(Object.keys(amend))))).filter(function (prop) { | ||
return prop.startsWith(SPECIAL_PROPS_PREFIX); | ||
}).reduce(function (fn, prop) { | ||
var value = 'undefined' !== typeof amend[prop] ? amend[prop] : from[prop]; | ||
function reuseSpecialProps(from, to, amend = {}) { | ||
return [...new Set(Object.keys(from).concat(Object.keys(amend)))].filter(prop => prop.startsWith(SPECIAL_PROPS_PREFIX)).reduce((fn, prop) => { | ||
const value = 'undefined' !== typeof amend[prop] ? amend[prop] : from[prop]; | ||
if (value instanceof Array) { | ||
@@ -90,5 +77,3 @@ fn[prop] = value.concat(); | ||
function wrapInitializer(wrapper, baseInitializer) { | ||
return reuseSpecialProps(baseInitializer, function (services) { | ||
return baseInitializer(services).then(wrapper.bind(null, services)); | ||
}); | ||
return reuseSpecialProps(baseInitializer, services => baseInitializer(services).then(wrapper.bind(null, services))); | ||
} | ||
@@ -120,7 +105,7 @@ | ||
*/ | ||
function inject(dependenciesDeclarations, initializer) { | ||
var merge = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
function inject(dependenciesDeclarations, initializer, merge = false) { | ||
const uniqueInitializer = reuseSpecialProps(initializer, initializer, { | ||
[SPECIAL_PROPS.INJECT]: merge ? (initializer[SPECIAL_PROPS.INJECT] || []).concat(dependenciesDeclarations) : dependenciesDeclarations | ||
}); | ||
var uniqueInitializer = reuseSpecialProps(initializer, initializer, _defineProperty({}, SPECIAL_PROPS.INJECT, merge ? (initializer[SPECIAL_PROPS.INJECT] || []).concat(dependenciesDeclarations) : dependenciesDeclarations)); | ||
debug('Wrapped an initializer with dependencies:', dependenciesDeclarations); | ||
@@ -156,7 +141,7 @@ | ||
*/ | ||
function extra(extraInformations, initializer) { | ||
var merge = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
function extra(extraInformations, initializer, merge = false) { | ||
const uniqueInitializer = reuseSpecialProps(initializer, initializer, { | ||
[SPECIAL_PROPS.EXTRA]: merge ? Object.assign(initializer[SPECIAL_PROPS.EXTRA] || {}, extraInformations) : extraInformations | ||
}); | ||
var uniqueInitializer = reuseSpecialProps(initializer, initializer, _defineProperty({}, SPECIAL_PROPS.EXTRA, merge ? Object.assign(initializer[SPECIAL_PROPS.EXTRA] || {}, extraInformations) : extraInformations)); | ||
debug('Wrapped an initializer with extra informations:', extraInformations); | ||
@@ -192,7 +177,7 @@ | ||
*/ | ||
function options(options, initializer) { | ||
var merge = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
function options(options, initializer, merge = false) { | ||
const uniqueInitializer = reuseSpecialProps(initializer, initializer, { | ||
[SPECIAL_PROPS.OPTIONS]: merge ? options : Object.assign({}, initializer[SPECIAL_PROPS.OPTIONS] || {}, options) | ||
}); | ||
var uniqueInitializer = reuseSpecialProps(initializer, initializer, _defineProperty({}, SPECIAL_PROPS.OPTIONS, merge ? options : Object.assign({}, initializer[SPECIAL_PROPS.OPTIONS] || {}, options))); | ||
debug('Wrapped an initializer with options:', options); | ||
@@ -220,3 +205,5 @@ | ||
function name(name, initializer) { | ||
var uniqueInitializer = reuseSpecialProps(initializer, initializer, _defineProperty({}, SPECIAL_PROPS.NAME, name)); | ||
const uniqueInitializer = reuseSpecialProps(initializer, initializer, { | ||
[SPECIAL_PROPS.NAME]: name | ||
}); | ||
@@ -251,3 +238,5 @@ debug('Wrapped an initializer with a name:', name); | ||
function type(type, initializer) { | ||
var uniqueInitializer = reuseSpecialProps(initializer, initializer, _defineProperty({}, SPECIAL_PROPS.TYPE, type)); | ||
const uniqueInitializer = reuseSpecialProps(initializer, initializer, { | ||
[SPECIAL_PROPS.TYPE]: type | ||
}); | ||
@@ -281,4 +270,4 @@ debug('Wrapped an initializer with a type:', type); | ||
function initializer(properties, initializer) { | ||
var uniqueInitializer = reuseSpecialProps(initializer, initializer, Object.keys(properties).reduce(function (finalProperties, property) { | ||
var finalProperty = SPECIAL_PROPS_PREFIX + property; | ||
const uniqueInitializer = reuseSpecialProps(initializer, initializer, Object.keys(properties).reduce((finalProperties, property) => { | ||
const finalProperty = SPECIAL_PROPS_PREFIX + property; | ||
@@ -318,5 +307,3 @@ if (!ALLOWED_SPECIAL_PROPS.includes(finalProperty)) { | ||
*/ | ||
function handler(handlerFunction) { | ||
var dependencies = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; | ||
function handler(handlerFunction, dependencies = []) { | ||
if (!handlerFunction.name) { | ||
@@ -329,9 +316,3 @@ throw new _yerror2.default('E_NO_HANDLER_NAME'); | ||
inject: dependencies | ||
}, function () { | ||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
return Promise.resolve(handlerFunction.bind.apply(handlerFunction, [null].concat(args))); | ||
}); | ||
}, (...args) => Promise.resolve(handlerFunction.bind(null, ...args))); | ||
} | ||
@@ -366,14 +347,10 @@ | ||
function parseDependencyDeclaration(dependencyDeclaration) { | ||
var optional = dependencyDeclaration.startsWith(OPTIONAL_FLAG); | ||
const optional = dependencyDeclaration.startsWith(OPTIONAL_FLAG); | ||
const [serviceName, mappedName] = (optional ? dependencyDeclaration.slice(1) : dependencyDeclaration).split(DECLARATION_SEPARATOR); | ||
var _split = (optional ? dependencyDeclaration.slice(1) : dependencyDeclaration).split(DECLARATION_SEPARATOR), | ||
_split2 = _slicedToArray(_split, 2), | ||
serviceName = _split2[0], | ||
mappedName = _split2[1]; | ||
return { | ||
serviceName: serviceName, | ||
serviceName, | ||
mappedName: mappedName || serviceName, | ||
optional: optional | ||
optional | ||
}; | ||
} |
@@ -17,4 +17,4 @@ 'use strict'; | ||
describe('reuseSpecialProps', function () { | ||
it('should work', function () { | ||
describe('reuseSpecialProps', () => { | ||
it('should work', () => { | ||
// We can safely ignore coverage here since the | ||
@@ -37,3 +37,3 @@ // function are here just as placeholders | ||
var newFn = (0, _util.reuseSpecialProps)(from, to); | ||
const newFn = (0, _util.reuseSpecialProps)(from, to); | ||
@@ -50,3 +50,3 @@ _assert2.default.notEqual(newFn, to); | ||
var newFn2 = (0, _util.reuseSpecialProps)(from, to, { | ||
const newFn2 = (0, _util.reuseSpecialProps)(from, to, { | ||
$name: 'yolo' | ||
@@ -67,8 +67,6 @@ }); | ||
describe('wrapInitializer', function (done) { | ||
it('should work', function () { | ||
describe('wrapInitializer', done => { | ||
it('should work', () => { | ||
function baseInitializer() { | ||
return Promise.resolve(function () { | ||
return 'test'; | ||
}); | ||
return Promise.resolve(() => 'test'); | ||
} | ||
@@ -82,13 +80,9 @@ | ||
var log = _sinon2.default.stub(); | ||
var newInitializer = (0, _util.wrapInitializer)(function (_ref, service) { | ||
var log = _ref.log; | ||
const log = _sinon2.default.stub(); | ||
const newInitializer = (0, _util.wrapInitializer)(({ log }, service) => { | ||
log('Wrapping...'); | ||
return function () { | ||
return service() + '-wrapped'; | ||
}; | ||
return () => service() + '-wrapped'; | ||
}, baseInitializer); | ||
newInitializer({ log: log }).then(function (service) { | ||
newInitializer({ log }).then(service => { | ||
_assert2.default.equal(service(), 'test-wrapped'); | ||
@@ -100,6 +94,6 @@ _assert2.default.deepEqual(log.args, [['Wrapping...']]); | ||
describe('inject', function () { | ||
it('should allow to decorate an initializer with dependencies', function () { | ||
var dependencies = ['ENV']; | ||
var newInitializer = (0, _util.inject)(dependencies, aProvider); | ||
describe('inject', () => { | ||
it('should allow to decorate an initializer with dependencies', () => { | ||
const dependencies = ['ENV']; | ||
const newInitializer = (0, _util.inject)(dependencies, aProvider); | ||
@@ -111,5 +105,5 @@ _assert2.default.notEqual(newInitializer, aProvider); | ||
it('should allow to decorate an initializer with mapped dependencies', function () { | ||
var dependencies = ['ANOTHER_ENV>ENV']; | ||
var newInitializer = (0, _util.inject)(dependencies, aProvider); | ||
it('should allow to decorate an initializer with mapped dependencies', () => { | ||
const dependencies = ['ANOTHER_ENV>ENV']; | ||
const newInitializer = (0, _util.inject)(dependencies, aProvider); | ||
@@ -122,7 +116,7 @@ _assert2.default.notEqual(newInitializer, aProvider); | ||
describe('options', function () { | ||
it('should allow to decorate an initializer with options', function () { | ||
var dependencies = ['ANOTHER_ENV>ENV']; | ||
var baseOptions = { singleton: true }; | ||
var newInitializer = (0, _util.inject)(dependencies, (0, _util.options)(baseOptions, aProvider)); | ||
describe('options', () => { | ||
it('should allow to decorate an initializer with options', () => { | ||
const dependencies = ['ANOTHER_ENV>ENV']; | ||
const baseOptions = { singleton: true }; | ||
const newInitializer = (0, _util.inject)(dependencies, (0, _util.options)(baseOptions, aProvider)); | ||
@@ -137,8 +131,8 @@ _assert2.default.notEqual(newInitializer, aProvider); | ||
describe('name', function () { | ||
it('should allow to decorate an initializer with a name', function () { | ||
var dependencies = ['ANOTHER_ENV>ENV']; | ||
var baseOptions = { singleton: true }; | ||
var baseName = 'hash'; | ||
var newInitializer = (0, _util.inject)(dependencies, (0, _util.options)(baseOptions, (0, _util.name)(baseName, aProvider))); | ||
describe('name', () => { | ||
it('should allow to decorate an initializer with a name', () => { | ||
const dependencies = ['ANOTHER_ENV>ENV']; | ||
const baseOptions = { singleton: true }; | ||
const baseName = 'hash'; | ||
const newInitializer = (0, _util.inject)(dependencies, (0, _util.options)(baseOptions, (0, _util.name)(baseName, aProvider))); | ||
@@ -154,6 +148,6 @@ _assert2.default.notEqual(newInitializer, aProvider); | ||
describe('extra', function () { | ||
it('should allow to decorate an initializer with extra infos', function () { | ||
var extraInformations = { httpHandler: true }; | ||
var newInitializer = (0, _util.extra)(extraInformations, aProvider); | ||
describe('extra', () => { | ||
it('should allow to decorate an initializer with extra infos', () => { | ||
const extraInformations = { httpHandler: true }; | ||
const newInitializer = (0, _util.extra)(extraInformations, aProvider); | ||
@@ -166,9 +160,9 @@ _assert2.default.notEqual(newInitializer, aProvider); | ||
describe('type', function () { | ||
it('should allow to decorate an initializer with a type', function () { | ||
var dependencies = ['ANOTHER_ENV>ENV']; | ||
var baseOptions = { singleton: true }; | ||
var baseName = 'hash'; | ||
var baseType = 'service'; | ||
var newInitializer = (0, _util.inject)(dependencies, (0, _util.options)(baseOptions, (0, _util.name)(baseName, (0, _util.type)(baseType, aProvider)))); | ||
describe('type', () => { | ||
it('should allow to decorate an initializer with a type', () => { | ||
const dependencies = ['ANOTHER_ENV>ENV']; | ||
const baseOptions = { singleton: true }; | ||
const baseName = 'hash'; | ||
const baseType = 'service'; | ||
const newInitializer = (0, _util.inject)(dependencies, (0, _util.options)(baseOptions, (0, _util.name)(baseName, (0, _util.type)(baseType, aProvider)))); | ||
@@ -185,9 +179,9 @@ _assert2.default.notEqual(newInitializer, aProvider); | ||
describe('initializer', function () { | ||
it('should allow to decorate an initializer with every properties', function () { | ||
var dependencies = ['ANOTHER_ENV>ENV']; | ||
var baseOptions = { singleton: true }; | ||
var baseName = 'hash'; | ||
var baseType = 'service'; | ||
var newInitializer = (0, _util.initializer)({ | ||
describe('initializer', () => { | ||
it('should allow to decorate an initializer with every properties', () => { | ||
const dependencies = ['ANOTHER_ENV>ENV']; | ||
const baseOptions = { singleton: true }; | ||
const baseName = 'hash'; | ||
const baseType = 'service'; | ||
const newInitializer = (0, _util.initializer)({ | ||
inject: dependencies, | ||
@@ -209,10 +203,10 @@ options: baseOptions, | ||
describe('handler', function () { | ||
it('should work', function () { | ||
var injectedServices = ['kikooo', 'lol']; | ||
var services = { | ||
describe('handler', () => { | ||
it('should work', () => { | ||
const injectedServices = ['kikooo', 'lol']; | ||
const services = { | ||
kikooo: 'kikooo', | ||
lol: 'lol' | ||
}; | ||
var theInitializer = (0, _util.handler)(sampleHandler, injectedServices); | ||
const theInitializer = (0, _util.handler)(sampleHandler, injectedServices); | ||
@@ -222,23 +216,15 @@ _assert2.default.deepEqual(theInitializer.$name, sampleHandler.name); | ||
return theInitializer(services).then(function (theHandler) { | ||
return theHandler('test'); | ||
}).then(function (result) { | ||
return _assert2.default.deepEqual(result, { | ||
deps: services, | ||
args: ['test'] | ||
}); | ||
}); | ||
return theInitializer(services).then(theHandler => theHandler('test')).then(result => _assert2.default.deepEqual(result, { | ||
deps: services, | ||
args: ['test'] | ||
})); | ||
function sampleHandler(deps) { | ||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
args[_key - 1] = arguments[_key]; | ||
} | ||
return Promise.resolve({ deps: deps, args: args }); | ||
function sampleHandler(deps, ...args) { | ||
return Promise.resolve({ deps, args }); | ||
} | ||
}); | ||
it('should fail for anonymous functions', function () { | ||
_assert2.default.throws(function () { | ||
(0, _util.handler)(function () {}); | ||
it('should fail for anonymous functions', () => { | ||
_assert2.default.throws(() => { | ||
(0, _util.handler)(() => {}); | ||
}, /E_NO_HANDLER_NAME/); | ||
@@ -248,4 +234,4 @@ }); | ||
describe('parseDependencyDeclaration', function () { | ||
it('should work', function () { | ||
describe('parseDependencyDeclaration', () => { | ||
it('should work', () => { | ||
_assert2.default.deepEqual((0, _util.parseDependencyDeclaration)('pgsql>db'), { | ||
@@ -252,0 +238,0 @@ serviceName: 'pgsql', |
{ | ||
"name": "knifecycle", | ||
"version": "2.4.2", | ||
"version": "2.5.0", | ||
"description": "Manage your NodeJS processes's lifecycle.", | ||
@@ -38,3 +38,3 @@ "main": "dist/index.js", | ||
"cz": "env NODE_ENV=${NODE_ENV:-cli} git cz", | ||
"doc": "mkdir -p .readme; echo \"# API\" > .readme/API.md; jsdoc2md src/*.js >> .readme/API.md", | ||
"doc": "echo \"# API\" > API.md; jsdoc2md src/*.js >> API.md", | ||
"karma": "karma start karma.conf.js", | ||
@@ -60,30 +60,29 @@ "lint": "eslint src/*.js", | ||
"babel-cli": "^6.26.0", | ||
"babel-eslint": "^7.1.0", | ||
"babel-plugin-transform-async-to-module-method": "^6.24.1", | ||
"babel-plugin-transform-es2015-modules-systemjs": "^6.9.0", | ||
"babel-core": "^6.26.0", | ||
"babel-eslint": "^8.2.2", | ||
"babel-plugin-transform-object-rest-spread": "^6.26.0", | ||
"babel-preset-env": "^1.6.1", | ||
"babel-register": "^6.9.0", | ||
"babel-register": "^6.26.0", | ||
"browserify": "^14.4.0", | ||
"commitizen": "^2.9.6", | ||
"conventional-changelog-cli": "^1.3.5", | ||
"coveralls": "^2.13.3", | ||
"cz-conventional-changelog": "^2.0.0", | ||
"eslint": "^4.12.1", | ||
"eslint-plugin-prettier": "^2.3.1", | ||
"conventional-changelog-cli": "^1.3.8", | ||
"coveralls": "^3.0.0", | ||
"cz-conventional-changelog": "^2.1.0", | ||
"eslint": "^4.19.0", | ||
"eslint-plugin-prettier": "^2.6.0", | ||
"istanbul": "^1.0.0-alpha.2", | ||
"jsarch": "^1.2.5", | ||
"jsdoc-to-markdown": "^3.0.2", | ||
"karma": "^1.7.0", | ||
"jsarch": "^1.3.0", | ||
"jsdoc-to-markdown": "^4.0.1", | ||
"karma": "^2.0.0", | ||
"karma-browserify": "^5.1.2", | ||
"karma-chrome-launcher": "^2.2.0", | ||
"karma-firefox-launcher": "^1.0.1", | ||
"karma-firefox-launcher": "^1.1.0", | ||
"karma-mocha": "^1.3.0", | ||
"karma-sauce-launcher": "^1.1.0", | ||
"metapak": "^1.0.1", | ||
"metapak-nfroidure": "^2.0.2", | ||
"mocha": "^3.5.3", | ||
"metapak": "^1.0.3", | ||
"metapak-nfroidure": "^5.0.0", | ||
"mocha": "^5.0.0", | ||
"mocha-lcov-reporter": "^1.3.0", | ||
"prettier": "^1.8.2", | ||
"sinon": "^3.0.0" | ||
"prettier": "^1.11.1", | ||
"sinon": "^4.4.6" | ||
}, | ||
@@ -114,3 +113,18 @@ "dependencies": { | ||
] | ||
}, | ||
"babel": { | ||
"presets": [ | ||
[ | ||
"env", | ||
{ | ||
"targets": { | ||
"node": "6.9.5" | ||
} | ||
} | ||
] | ||
], | ||
"plugins": [ | ||
"transform-object-rest-spread" | ||
] | ||
} | ||
} |
@@ -1,6 +0,7 @@ | ||
<!-- | ||
# This file is automatically generated by a `metapak` | ||
# module. Do not change it elsewhere, changes would | ||
# be overridden. | ||
--> | ||
[//]: # ( ) | ||
[//]: # (This file is automatically generated by a `metapak`) | ||
[//]: # (module. Do not change it except between the) | ||
[//]: # (`content:(start/end)` flags, your changes would) | ||
[//]: # (be overridden.) | ||
[//]: # ( ) | ||
# knifecycle | ||
@@ -17,2 +18,5 @@ > Manage your NodeJS processes's lifecycle. | ||
[//]: # (::contents:start) | ||
[![Browser Support Matrix](https://saucelabs.com/open_sauce/build_matrix/nfroidure.svg)](https://saucelabs.com/u/nfroidure) | ||
@@ -335,2 +339,5 @@ | ||
[//]: # (::contents:end) | ||
# API | ||
@@ -337,0 +344,0 @@ ## Classes |
@@ -84,3 +84,3 @@ import { SPECIAL_PROPS, parseDependencyDeclaration } from './util'; | ||
return ` | ||
services['${name}'] = await ${dependenciesHash[name].__initializerName}({${ | ||
services['${name}'] = (await ${dependenciesHash[name].__initializerName}({${ | ||
dependenciesHash[name].__inject | ||
@@ -96,3 +96,5 @@ ? `${dependenciesHash[name].__inject | ||
: '' | ||
}});`; | ||
}}))${ | ||
'provider' === dependenciesHash[name].__type ? '.service' : '' | ||
};`; | ||
}) | ||
@@ -138,2 +140,6 @@ .join('')} | ||
: [], | ||
__type: | ||
initializer && initializer[SPECIAL_PROPS.TYPE] | ||
? initializer[SPECIAL_PROPS.TYPE] | ||
: 'provider', | ||
__initializerName: 'init' + upperCaseFirst(mappedName), | ||
@@ -140,0 +146,0 @@ __path: path, |
@@ -25,3 +25,3 @@ import assert from 'assert'; | ||
options: {}, | ||
type: 'initializer', | ||
type: 'provider', | ||
name: 'dep2', | ||
@@ -70,18 +70,18 @@ }, | ||
// Initialization batch #0 | ||
services['dep1'] = await initDep1({ | ||
}); | ||
services['dep1'] = (await initDep1({ | ||
})); | ||
services['NODE_ENV'] = NODE_ENV; | ||
// Initialization batch #1 | ||
services['dep2'] = await initDep2({ | ||
services['dep2'] = (await initDep2({ | ||
dep1: services['dep1'], | ||
NODE_ENV: services['NODE_ENV'], | ||
}); | ||
})).service; | ||
// Initialization batch #2 | ||
services['dep3'] = await initDep3({ | ||
services['dep3'] = (await initDep3({ | ||
dep2: services['dep2'], | ||
dep1: services['dep1'], | ||
depOpt: services['depOpt'], | ||
}); | ||
})); | ||
@@ -88,0 +88,0 @@ return { |
@@ -23,2 +23,5 @@ /* eslint max-len: ["warn", { "ignoreComments": true }] */ | ||
const ALLOWED_INITIALIZER_TYPES = ['provider', 'service']; | ||
const E_BAD_ANALYZER_TYPE = 'E_BAD_ANALYZER_TYPE'; | ||
const E_UNMATCHED_DEPENDENCY = 'E_UNMATCHED_DEPENDENCY'; | ||
@@ -310,6 +313,13 @@ const E_CIRCULAR_DEPENDENCY = 'E_CIRCULAR_DEPENDENCY'; | ||
initializer[SPECIAL_PROPS.TYPE] = | ||
initializer[SPECIAL_PROPS.TYPE] || 'provider'; | ||
initializer[SPECIAL_PROPS.TYPE] || ALLOWED_INITIALIZER_TYPES[0]; | ||
if (!initializer[SPECIAL_PROPS.NAME]) { | ||
throw new YError(E_ANONYMOUS_ANALYZER, initializer[SPECIAL_PROPS.NAME]); | ||
} | ||
if (!ALLOWED_INITIALIZER_TYPES.includes(initializer[SPECIAL_PROPS.TYPE])) { | ||
throw new YError( | ||
E_BAD_ANALYZER_TYPE, | ||
initializer[SPECIAL_PROPS.TYPE], | ||
ALLOWED_INITIALIZER_TYPES, | ||
); | ||
} | ||
@@ -316,0 +326,0 @@ if ('service' === initializer[SPECIAL_PROPS.TYPE]) { |
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
28
897
224819
4895