Socket
Socket
Sign inDemoInstall

knifecycle

Package Overview
Dependencies
Maintainers
1
Versions
100
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

knifecycle - npm Package Compare versions

Comparing version 2.4.2 to 2.5.0

15

CHANGELOG.md

@@ -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)

91

dist/build.js

@@ -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'],
};
}
`);
}));
});

@@ -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: [{

@@ -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]) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc