knifecycle
Advanced tools
Comparing version 11.0.0-beta.7 to 11.0.0-beta.8
@@ -1,5 +0,10 @@ | ||
# [11.0.0-beta.7](https://github.com/nfroidure/knifecycle/compare/v10.0.3...v11.0.0-beta.7) (2020-11-21) | ||
# [11.0.0-beta.8](https://github.com/nfroidure/knifecycle/compare/v10.0.3...v11.0.0-beta.8) (2020-11-22) | ||
### Bug Fixes | ||
* **types:** fix generic types initializer passthrough ([59aa179](https://github.com/nfroidure/knifecycle/commit/59aa17986bd98d75263acb5ab7732bc2ae66a1ca)) | ||
## [10.0.3](https://github.com/nfroidure/knifecycle/compare/v10.0.2...v10.0.3) (2020-10-18) | ||
@@ -6,0 +11,0 @@ |
@@ -1,2 +0,2 @@ | ||
import { SPECIAL_PROPS, SPECIAL_PROPS_PREFIX, DECLARATION_SEPARATOR, OPTIONAL_FLAG, ALLOWED_INITIALIZER_TYPES, ALLOWED_SPECIAL_PROPS, parseInjections, readFunctionName, reuseSpecialProps, parseName, name, autoName, inject, useInject, mergeInject, autoInject, alsoInject, type, extra, singleton, initializer, constant, service, autoService, provider, autoProvider, wrapInitializer, handler, autoHandler, parseDependencyDeclaration, stringifyDependencyDeclaration } from './util'; | ||
import { SPECIAL_PROPS, SPECIAL_PROPS_PREFIX, DECLARATION_SEPARATOR, OPTIONAL_FLAG, ALLOWED_INITIALIZER_TYPES, ALLOWED_SPECIAL_PROPS, parseInjections, readFunctionName, reuseSpecialProps, parseName, name, autoName, inject, useInject, mergeInject, autoInject, alsoInject, type, extra, singleton, initializer, constant, service, autoService, provider, autoProvider, wrapInitializer, handler, autoHandler, parseDependencyDeclaration, stringifyDependencyDeclaration, unwrapInitializerProperties } from './util'; | ||
import initInitializerBuilder from './build'; | ||
@@ -11,3 +11,3 @@ import type { ServiceName, Service, Disposer, FatalErrorProvider, Provider, Dependencies, DependencyName, DependencyDeclaration, ExtraInformations, ParsedDependencyDeclaration, ConstantProperties, ConstantInitializer, ProviderInitializerBuilder, ProviderProperties, ProviderInitializer, ProviderInputProperties, ServiceInitializerBuilder, ServiceProperties, ServiceInitializer, ServiceInputProperties, AsyncInitializerBuilder, AsyncInitializer, PartialAsyncInitializer, Initializer, ServiceInitializerWrapper, ProviderInitializerWrapper, Parameters, HandlerFunction } from './util'; | ||
(name: DependencyDeclaration): Promise<{ | ||
initializer: Initializer<S>; | ||
initializer: Initializer<S, Dependencies<S>>; | ||
path: string; | ||
@@ -215,2 +215,2 @@ }>; | ||
export default Knifecycle; | ||
export { SPECIAL_PROPS, SPECIAL_PROPS_PREFIX, DECLARATION_SEPARATOR, OPTIONAL_FLAG, ALLOWED_INITIALIZER_TYPES, ALLOWED_SPECIAL_PROPS, parseInjections, readFunctionName, parseName, Knifecycle, initializer, name, autoName, type, inject, useInject, mergeInject, autoInject, alsoInject, extra, singleton, reuseSpecialProps, wrapInitializer, constant, service, autoService, provider, autoProvider, handler, autoHandler, parseDependencyDeclaration, stringifyDependencyDeclaration, initInitializerBuilder, }; | ||
export { SPECIAL_PROPS, SPECIAL_PROPS_PREFIX, DECLARATION_SEPARATOR, OPTIONAL_FLAG, ALLOWED_INITIALIZER_TYPES, ALLOWED_SPECIAL_PROPS, parseInjections, readFunctionName, parseName, Knifecycle, initializer, name, autoName, type, inject, useInject, mergeInject, autoInject, alsoInject, extra, singleton, reuseSpecialProps, wrapInitializer, constant, service, autoService, provider, autoProvider, handler, autoHandler, parseDependencyDeclaration, stringifyDependencyDeclaration, unwrapInitializerProperties, initInitializerBuilder, }; |
@@ -192,2 +192,8 @@ "use strict"; | ||
}); | ||
Object.defineProperty(exports, "unwrapInitializerProperties", { | ||
enumerable: true, | ||
get: function () { | ||
return _util.unwrapInitializerProperties; | ||
} | ||
}); | ||
Object.defineProperty(exports, "initInitializerBuilder", { | ||
@@ -354,25 +360,6 @@ enumerable: true, | ||
if (typeof initializer !== 'function' && typeof initializer !== 'object') { | ||
throw new _yerror.default(E_BAD_INITIALIZER, initializer); | ||
} | ||
initializer[_util.SPECIAL_PROPS.INJECT] = initializer[_util.SPECIAL_PROPS.INJECT] || []; | ||
initializer[_util.SPECIAL_PROPS.SINGLETON] = initializer[_util.SPECIAL_PROPS.SINGLETON] || false; | ||
initializer[_util.SPECIAL_PROPS.TYPE] = initializer[_util.SPECIAL_PROPS.TYPE] || _util.ALLOWED_INITIALIZER_TYPES[0]; | ||
if (!initializer[_util.SPECIAL_PROPS.NAME]) { | ||
throw new _yerror.default(E_ANONYMOUS_ANALYZER, initializer[_util.SPECIAL_PROPS.NAME]); | ||
} | ||
if (initializer[_util.SPECIAL_PROPS.NAME] === AUTOLOAD && !initializer[_util.SPECIAL_PROPS.SINGLETON]) { | ||
throw new _yerror.default(E_BAD_AUTOLOADER, initializer[_util.SPECIAL_PROPS.SINGLETON]); | ||
} | ||
if (!_util.ALLOWED_INITIALIZER_TYPES.includes(initializer[_util.SPECIAL_PROPS.TYPE])) { | ||
throw new _yerror.default(E_BAD_INITIALIZER_TYPE, initializer[_util.SPECIAL_PROPS.NAME], initializer[_util.SPECIAL_PROPS.TYPE], _util.ALLOWED_INITIALIZER_TYPES); | ||
} // Temporary cast constants into providers | ||
const properties = (0, _util.unwrapInitializerProperties)(initializer); // Temporary cast constants into providers | ||
// Best would be to threat each differently | ||
// at dependencies initialization level to boost performances | ||
if (initializer[_util.SPECIAL_PROPS.TYPE] === 'constant') { | ||
@@ -379,0 +366,0 @@ const value = initializer[_util.SPECIAL_PROPS.VALUE]; |
@@ -29,2 +29,3 @@ export declare const DECLARATION_SEPARATOR = ">"; | ||
$name: DependencyName; | ||
$singleton: true; | ||
}; | ||
@@ -42,3 +43,3 @@ export declare type ConstantInitializer<S extends Service> = ConstantProperties & { | ||
}; | ||
export declare type ProviderInitializer<D extends Dependencies, S extends Service> = ProviderInitializerBuilder<D, S> & ProviderProperties; | ||
export declare type ProviderInitializer<D extends Dependencies, S extends Service> = (dependencies?: D) => Promise<Provider<S>>; | ||
export declare type ProviderInputProperties = { | ||
@@ -59,3 +60,3 @@ type: 'provider'; | ||
}; | ||
export declare type ServiceInitializer<D extends Dependencies, S extends Service> = ServiceInitializerBuilder<D, S> & ServiceProperties; | ||
export declare type ServiceInitializer<D extends Dependencies, S extends Service> = (dependencies?: D) => Promise<S>; | ||
export declare type ServiceInputProperties = { | ||
@@ -68,8 +69,9 @@ type: 'service'; | ||
}; | ||
export declare type InitializerProperties = ConstantProperties | ProviderProperties | ServiceProperties; | ||
export declare type AsyncInitializerBuilder<D extends Dependencies, S extends Service> = ProviderInitializerBuilder<D, S> | ServiceInitializerBuilder<D, S>; | ||
export declare type AsyncInitializer<D extends Dependencies, S extends Service> = ServiceInitializer<D, S> | ProviderInitializer<D, S>; | ||
export declare type PartialAsyncInitializer<D extends Dependencies, S extends Service> = Partial<ServiceInitializer<D, S>> | Partial<ProviderInitializer<D, S>>; | ||
export declare type Initializer<S extends Service, D extends Dependencies = Dependencies> = ConstantInitializer<S> | ServiceInitializer<D, S> | ProviderInitializer<D, S>; | ||
export declare type ServiceInitializerWrapper<S extends Service, D extends Dependencies = Dependencies> = (dependencies: D, baseService: S) => Promise<S>; | ||
export declare type ProviderInitializerWrapper<S extends Service, D extends Dependencies = Dependencies> = (dependencies: D, baseService: Provider<S>) => Promise<Provider<S>>; | ||
export declare type Initializer<S extends Service, D extends Dependencies> = ConstantInitializer<S> | ServiceInitializer<D, S> | ProviderInitializer<D, S>; | ||
export declare type ServiceInitializerWrapper<S extends Service, D extends Dependencies> = (dependencies: D, baseService: S) => Promise<S>; | ||
export declare type ProviderInitializerWrapper<S extends Service, D extends Dependencies> = (dependencies: D, baseService: Provider<S>) => Promise<Provider<S>>; | ||
export declare type Parameters<V = any> = { | ||
@@ -565,1 +567,12 @@ [name: string]: V; | ||
export declare function stringifyDependencyDeclaration(dependencyDeclarationParts: ParsedDependencyDeclaration): DependencyDeclaration; | ||
/** | ||
* Utility function to check and reveal initializer properties. | ||
* @param {Function} initializer | ||
* The initializer to tweak | ||
* @return {Function} | ||
* Returns revealed initializer (with TypeScript types for properties) | ||
*/ | ||
export declare function unwrapInitializerProperties<S, D>(initializer: ProviderInitializer<D, S>): ProviderProperties; | ||
export declare function unwrapInitializerProperties<S, D>(initializer: ServiceInitializer<D, S>): ServiceProperties; | ||
export declare function unwrapInitializerProperties<S, D>(initializer: ConstantInitializer<S>): ConstantProperties; | ||
export declare function unwrapInitializerProperties<S, D>(initializer: Initializer<S, D>): InitializerProperties; |
@@ -31,2 +31,3 @@ "use strict"; | ||
exports.stringifyDependencyDeclaration = stringifyDependencyDeclaration; | ||
exports.unwrapInitializerProperties = unwrapInitializerProperties; | ||
exports.ALLOWED_SPECIAL_PROPS = exports.SPECIAL_PROPS = exports.SPECIAL_PROPS_PREFIX = exports.ALLOWED_INITIALIZER_TYPES = exports.OPTIONAL_FLAG = exports.DECLARATION_SEPARATOR = void 0; | ||
@@ -184,2 +185,3 @@ | ||
$name: name, | ||
$singleton: true, | ||
$value: value | ||
@@ -818,2 +820,61 @@ }; | ||
} | ||
/* Architecture Note #3: TypeScript tweaks | ||
Sadly TypeScript does not allow to add generic types | ||
in all cases. This is why `(Service|Provider)Initializer` | ||
types do not embed the `(Service|Provider)Properties` | ||
direclty. Instead, we use this utility function to | ||
reveal it to TypeScript and, by the way, check their | ||
completeness at execution time. | ||
For more details, see: | ||
https://stackoverflow.com/questions/64948037/generics-type-loss-while-infering/64950184#64950184 | ||
*/ | ||
/** | ||
* Utility function to check and reveal initializer properties. | ||
* @param {Function} initializer | ||
* The initializer to tweak | ||
* @return {Function} | ||
* Returns revealed initializer (with TypeScript types for properties) | ||
*/ | ||
function unwrapInitializerProperties(initializer) { | ||
if (typeof initializer !== 'function' && typeof initializer !== 'object') { | ||
throw new _yerror.default('E_BAD_INITIALIZER', initializer); | ||
} | ||
const properties = initializer; | ||
if (typeof properties[SPECIAL_PROPS.NAME] !== 'string' || properties[SPECIAL_PROPS.NAME] === '') { | ||
throw new _yerror.default('E_ANONYMOUS_ANALYZER', properties[SPECIAL_PROPS.NAME]); | ||
} | ||
if (!ALLOWED_INITIALIZER_TYPES.includes(properties[SPECIAL_PROPS.TYPE])) { | ||
throw new _yerror.default('E_BAD_INITIALIZER_TYPE', initializer[SPECIAL_PROPS.NAME], initializer[SPECIAL_PROPS.TYPE], ALLOWED_INITIALIZER_TYPES); | ||
} | ||
if (initializer[SPECIAL_PROPS.NAME] === '$autoload' && !initializer[SPECIAL_PROPS.SINGLETON]) { | ||
throw new _yerror.default('E_BAD_AUTOLOADER', initializer[SPECIAL_PROPS.SINGLETON] || false); | ||
} | ||
if (properties[SPECIAL_PROPS.TYPE] === 'constant') { | ||
if ('undefined' === typeof initializer[SPECIAL_PROPS.VALUE]) { | ||
throw new _yerror.default('E_UNDEFINED_CONSTANT_INITIALIZER', properties[SPECIAL_PROPS.NAME]); | ||
} | ||
properties[SPECIAL_PROPS.SINGLETON] = true; | ||
} else { | ||
if ('undefined' !== typeof initializer[SPECIAL_PROPS.VALUE]) { | ||
throw new _yerror.default('E_BAD_VALUED_NON_CONSTANT_INITIALIZER', initializer[SPECIAL_PROPS.NAME]); | ||
} | ||
properties[SPECIAL_PROPS.INJECT] = properties[SPECIAL_PROPS.INJECT] || []; | ||
properties[SPECIAL_PROPS.SINGLETON] = properties[SPECIAL_PROPS.SINGLETON] || false; | ||
properties[SPECIAL_PROPS.EXTRA] = properties[SPECIAL_PROPS.EXTRA] || undefined; | ||
} | ||
return initializer; | ||
} | ||
//# sourceMappingURL=util.js.map |
@@ -84,4 +84,4 @@ "use strict"; | ||
describe('wrapInitializer', () => { | ||
it('should work with a service initialzer', async () => { | ||
async function baseInitializer() { | ||
it('should work with a service initializer', async () => { | ||
async function baseServiceInitializer() { | ||
return () => 'test'; | ||
@@ -97,3 +97,3 @@ } | ||
return () => service() + '-wrapped'; | ||
}, (0, _util.service)(baseInitializer, 'baseInitializer', ['log', '?test'], false, { | ||
}, (0, _util.service)(baseServiceInitializer, 'baseServiceInitializer', ['log', '?test'], false, { | ||
httpHandler: false | ||
@@ -120,2 +120,5 @@ })); | ||
const baseProviderInitializer = (0, _util.provider)(baseInitializer, 'baseInitializer', ['log', '?test'], false, { | ||
httpHandler: false | ||
}); | ||
const newInitializer = (0, _util.wrapInitializer)(async ({ | ||
@@ -128,5 +131,3 @@ log | ||
}; | ||
}, (0, _util.provider)(baseInitializer, 'baseInitializer', ['log', '?test'], false, { | ||
httpHandler: false | ||
})); | ||
}, baseProviderInitializer); | ||
const newService = await newInitializer({ | ||
@@ -694,4 +695,4 @@ log | ||
}); | ||
it('should allow to create an initializer from a service builder', async () => { | ||
const aServiceBuilder = async _services => undefined; | ||
it('should allow to create an initializer from a generic service builder', async () => { | ||
const aServiceBuilder = async _services => ''; | ||
@@ -704,3 +705,3 @@ const dependencies = ['ANOTHER_ENV>ENV']; | ||
const baseType = 'service'; | ||
const newInitializer = (0, _util.service)((0, _util.inject)(dependencies, (0, _util.name)(baseName, (0, _util.singleton)((0, _util.extra)(extraData, aServiceBuilder))))); | ||
const newInitializer = (0, _util.service)(aServiceBuilder, baseName, dependencies, true, extraData); | ||
@@ -707,0 +708,0 @@ _assert.default.notEqual(newInitializer, aProviderInitializer); |
{ | ||
"name": "knifecycle", | ||
"version": "11.0.0-beta.7", | ||
"version": "11.0.0-beta.8", | ||
"description": "Manage your NodeJS processes's lifecycle automatically with an unobtrusive dependency injection implementation.", | ||
@@ -5,0 +5,0 @@ "main": "dist/index", |
@@ -508,2 +508,5 @@ [//]: # ( ) | ||
</dd> | ||
<dt><a href="#unwrapInitializerProperties">unwrapInitializerProperties(initializer)</a> ⇒ <code>function</code></dt> | ||
<dd><p>Utility function to check and reveal initializer properties.</p> | ||
</dd> | ||
</dl> | ||
@@ -1226,3 +1229,15 @@ | ||
``` | ||
<a name="unwrapInitializerProperties"></a> | ||
## unwrapInitializerProperties(initializer) ⇒ <code>function</code> | ||
Utility function to check and reveal initializer properties. | ||
**Kind**: global function | ||
**Returns**: <code>function</code> - Returns revealed initializer (with TypeScript types for properties) | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| initializer | <code>function</code> | The initializer to tweak | | ||
# Authors | ||
@@ -1229,0 +1244,0 @@ - [Nicolas Froidure](http://insertafter.com/en/index.html) |
@@ -34,2 +34,3 @@ /* eslint max-len: ["warn", { "ignoreComments": true }] @typescript-eslint/no-this-alias: "warn" */ | ||
stringifyDependencyDeclaration, | ||
unwrapInitializerProperties, | ||
} from './util'; | ||
@@ -107,3 +108,3 @@ import initInitializerBuilder from './build'; | ||
(name: DependencyDeclaration): Promise<{ | ||
initializer: Initializer<S>; | ||
initializer: Initializer<S, Dependencies<S>>; | ||
path: string; | ||
@@ -297,29 +298,4 @@ }>; | ||
if (typeof initializer !== 'function' && typeof initializer !== 'object') { | ||
throw new YError(E_BAD_INITIALIZER, initializer); | ||
} | ||
const properties = unwrapInitializerProperties(initializer); | ||
initializer[SPECIAL_PROPS.INJECT] = initializer[SPECIAL_PROPS.INJECT] || []; | ||
initializer[SPECIAL_PROPS.SINGLETON] = | ||
initializer[SPECIAL_PROPS.SINGLETON] || false; | ||
initializer[SPECIAL_PROPS.TYPE] = | ||
initializer[SPECIAL_PROPS.TYPE] || ALLOWED_INITIALIZER_TYPES[0]; | ||
if (!initializer[SPECIAL_PROPS.NAME]) { | ||
throw new YError(E_ANONYMOUS_ANALYZER, initializer[SPECIAL_PROPS.NAME]); | ||
} | ||
if ( | ||
initializer[SPECIAL_PROPS.NAME] === AUTOLOAD && | ||
!initializer[SPECIAL_PROPS.SINGLETON] | ||
) { | ||
throw new YError(E_BAD_AUTOLOADER, initializer[SPECIAL_PROPS.SINGLETON]); | ||
} | ||
if (!ALLOWED_INITIALIZER_TYPES.includes(initializer[SPECIAL_PROPS.TYPE])) { | ||
throw new YError( | ||
E_BAD_INITIALIZER_TYPE, | ||
initializer[SPECIAL_PROPS.NAME], | ||
initializer[SPECIAL_PROPS.TYPE], | ||
ALLOWED_INITIALIZER_TYPES, | ||
); | ||
} | ||
// Temporary cast constants into providers | ||
@@ -1203,2 +1179,3 @@ // Best would be to threat each differently | ||
stringifyDependencyDeclaration, | ||
unwrapInitializerProperties, | ||
initInitializerBuilder, | ||
@@ -1205,0 +1182,0 @@ }; |
@@ -29,2 +29,3 @@ import assert from 'assert'; | ||
import type { PromiseValue } from 'type-fest'; | ||
import type { Provider } from './util'; | ||
@@ -86,4 +87,4 @@ async function aProviderInitializer(_services: unknown) { | ||
describe('wrapInitializer', () => { | ||
it('should work with a service initialzer', async () => { | ||
async function baseInitializer() { | ||
it('should work with a service initializer', async () => { | ||
async function baseServiceInitializer() { | ||
return () => 'test'; | ||
@@ -94,9 +95,15 @@ } | ||
const newInitializer = wrapInitializer( | ||
async ({ log }, service) => { | ||
async ({ log }, service: () => string) => { | ||
log('Wrapping...'); | ||
return () => service() + '-wrapped'; | ||
}, | ||
service(baseInitializer, 'baseInitializer', ['log', '?test'], false, { | ||
httpHandler: false, | ||
}), | ||
service( | ||
baseServiceInitializer, | ||
'baseServiceInitializer', | ||
['log', '?test'], | ||
false, | ||
{ | ||
httpHandler: false, | ||
}, | ||
), | ||
); | ||
@@ -116,11 +123,17 @@ | ||
const log = sinon.stub(); | ||
const newInitializer = wrapInitializer( | ||
async ({ log }, service) => { | ||
log('Wrapping...'); | ||
return { service: () => service.service() + '-wrapped' }; | ||
const baseProviderInitializer = provider( | ||
baseInitializer, | ||
'baseInitializer', | ||
['log', '?test'], | ||
false, | ||
{ | ||
httpHandler: false, | ||
}, | ||
provider(baseInitializer, 'baseInitializer', ['log', '?test'], false, { | ||
httpHandler: false, | ||
}), | ||
); | ||
const newInitializer = wrapInitializer(async ({ log }, service): Promise< | ||
Provider<() => string> | ||
> => { | ||
log('Wrapping...'); | ||
return { service: () => service.service() + '-wrapped' }; | ||
}, baseProviderInitializer); | ||
@@ -734,4 +747,4 @@ const newService = await newInitializer({ log }); | ||
it('should allow to create an initializer from a service builder', async () => { | ||
const aServiceBuilder = async (_services: unknown) => undefined; | ||
it('should allow to create an initializer from a generic service builder', async () => { | ||
const aServiceBuilder = async <T>(_services: T) => ''; | ||
const dependencies = ['ANOTHER_ENV>ENV']; | ||
@@ -742,6 +755,7 @@ const extraData = { nice: true }; | ||
const newInitializer = service( | ||
inject( | ||
dependencies, | ||
name(baseName, singleton(extra(extraData, aServiceBuilder))), | ||
), | ||
aServiceBuilder, | ||
baseName, | ||
dependencies, | ||
true, | ||
extraData, | ||
); | ||
@@ -886,4 +900,4 @@ | ||
assert.deepEqual(theInitializer.$name, baseName); | ||
assert.deepEqual(theInitializer.$inject, injectedServices); | ||
assert.deepEqual((theInitializer as any).$name, baseName); | ||
assert.deepEqual((theInitializer as any).$inject, injectedServices); | ||
@@ -917,4 +931,4 @@ const theHandler = await theInitializer(services); | ||
assert.deepEqual(theInitializer.$name, sampleHandler.name); | ||
assert.deepEqual(theInitializer.$inject, ['kikooo', 'lol']); | ||
assert.deepEqual((theInitializer as any).$name, sampleHandler.name); | ||
assert.deepEqual((theInitializer as any).$inject, ['kikooo', 'lol']); | ||
@@ -940,4 +954,4 @@ const theHandler = await theInitializer(services); | ||
assert.deepEqual(theInitializer.$name, sampleHandler.name); | ||
assert.deepEqual(theInitializer.$inject, ['kikooo', 'lol']); | ||
assert.deepEqual((theInitializer as any).$name, sampleHandler.name); | ||
assert.deepEqual((theInitializer as any).$inject, ['kikooo', 'lol']); | ||
@@ -944,0 +958,0 @@ const theHandler = await theInitializer(services); |
130
src/util.ts
@@ -62,2 +62,3 @@ /* eslint @typescript-eslint/ban-types:0 */ | ||
$name: DependencyName; | ||
$singleton: true; | ||
}; | ||
@@ -79,6 +80,5 @@ export type ConstantInitializer<S extends Service> = ConstantProperties & { | ||
}; | ||
export type ProviderInitializer< | ||
D extends Dependencies, | ||
S extends Service | ||
> = ProviderInitializerBuilder<D, S> & ProviderProperties; | ||
export type ProviderInitializer<D extends Dependencies, S extends Service> = ( | ||
dependencies?: D, | ||
) => Promise<Provider<S>>; | ||
export type ProviderInputProperties = { | ||
@@ -103,6 +103,5 @@ type: 'provider'; | ||
}; | ||
export type ServiceInitializer< | ||
D extends Dependencies, | ||
S extends Service | ||
> = ServiceInitializerBuilder<D, S> & ServiceProperties; | ||
export type ServiceInitializer<D extends Dependencies, S extends Service> = ( | ||
dependencies?: D, | ||
) => Promise<S>; | ||
export type ServiceInputProperties = { | ||
@@ -116,2 +115,7 @@ type: 'service'; | ||
export type InitializerProperties = | ||
| ConstantProperties | ||
| ProviderProperties | ||
| ServiceProperties; | ||
export type AsyncInitializerBuilder< | ||
@@ -129,6 +133,3 @@ D extends Dependencies, | ||
export type Initializer< | ||
S extends Service, | ||
D extends Dependencies = Dependencies | ||
> = | ||
export type Initializer<S extends Service, D extends Dependencies> = | ||
| ConstantInitializer<S> | ||
@@ -140,7 +141,7 @@ | ServiceInitializer<D, S> | ||
S extends Service, | ||
D extends Dependencies = Dependencies | ||
D extends Dependencies | ||
> = (dependencies: D, baseService: S) => Promise<S>; | ||
export type ProviderInitializerWrapper< | ||
S extends Service, | ||
D extends Dependencies = Dependencies | ||
D extends Dependencies | ||
> = (dependencies: D, baseService: Provider<S>) => Promise<Provider<S>>; | ||
@@ -324,2 +325,3 @@ | ||
$name: name, | ||
$singleton: true, | ||
$value: value, | ||
@@ -1323,1 +1325,101 @@ }; | ||
} | ||
/* Architecture Note #3: TypeScript tweaks | ||
Sadly TypeScript does not allow to add generic types | ||
in all cases. This is why `(Service|Provider)Initializer` | ||
types do not embed the `(Service|Provider)Properties` | ||
direclty. Instead, we use this utility function to | ||
reveal it to TypeScript and, by the way, check their | ||
completeness at execution time. | ||
For more details, see: | ||
https://stackoverflow.com/questions/64948037/generics-type-loss-while-infering/64950184#64950184 | ||
*/ | ||
/** | ||
* Utility function to check and reveal initializer properties. | ||
* @param {Function} initializer | ||
* The initializer to tweak | ||
* @return {Function} | ||
* Returns revealed initializer (with TypeScript types for properties) | ||
*/ | ||
export function unwrapInitializerProperties<S, D>( | ||
initializer: ProviderInitializer<D, S>, | ||
): ProviderProperties; | ||
export function unwrapInitializerProperties<S, D>( | ||
initializer: ServiceInitializer<D, S>, | ||
): ServiceProperties; | ||
export function unwrapInitializerProperties<S, D>( | ||
initializer: ConstantInitializer<S>, | ||
): ConstantProperties; | ||
export function unwrapInitializerProperties<S, D>( | ||
initializer: Initializer<S, D>, | ||
): InitializerProperties; | ||
export function unwrapInitializerProperties<S, D>( | ||
initializer: | ||
| ProviderInitializerBuilder<D, S> | ||
| ServiceInitializerBuilder<D, S> | ||
| ConstantInitializer<S>, | ||
): ProviderProperties | ServiceProperties | ConstantProperties { | ||
if (typeof initializer !== 'function' && typeof initializer !== 'object') { | ||
throw new YError('E_BAD_INITIALIZER', initializer); | ||
} | ||
const properties = initializer as InitializerProperties; | ||
if ( | ||
typeof properties[SPECIAL_PROPS.NAME] !== 'string' || | ||
properties[SPECIAL_PROPS.NAME] === '' | ||
) { | ||
throw new YError('E_ANONYMOUS_ANALYZER', properties[SPECIAL_PROPS.NAME]); | ||
} | ||
if (!ALLOWED_INITIALIZER_TYPES.includes(properties[SPECIAL_PROPS.TYPE])) { | ||
throw new YError( | ||
'E_BAD_INITIALIZER_TYPE', | ||
initializer[SPECIAL_PROPS.NAME], | ||
initializer[SPECIAL_PROPS.TYPE], | ||
ALLOWED_INITIALIZER_TYPES, | ||
); | ||
} | ||
if ( | ||
initializer[SPECIAL_PROPS.NAME] === '$autoload' && | ||
!initializer[SPECIAL_PROPS.SINGLETON] | ||
) { | ||
throw new YError( | ||
'E_BAD_AUTOLOADER', | ||
initializer[SPECIAL_PROPS.SINGLETON] || false, | ||
); | ||
} | ||
if (properties[SPECIAL_PROPS.TYPE] === 'constant') { | ||
if ( | ||
'undefined' === | ||
typeof (initializer as ConstantInitializer<S>)[SPECIAL_PROPS.VALUE] | ||
) { | ||
throw new YError( | ||
'E_UNDEFINED_CONSTANT_INITIALIZER', | ||
properties[SPECIAL_PROPS.NAME], | ||
); | ||
} | ||
properties[SPECIAL_PROPS.SINGLETON] = true; | ||
} else { | ||
if ('undefined' !== typeof initializer[SPECIAL_PROPS.VALUE]) { | ||
throw new YError( | ||
'E_BAD_VALUED_NON_CONSTANT_INITIALIZER', | ||
initializer[SPECIAL_PROPS.NAME], | ||
); | ||
} | ||
properties[SPECIAL_PROPS.INJECT] = properties[SPECIAL_PROPS.INJECT] || []; | ||
properties[SPECIAL_PROPS.SINGLETON] = | ||
properties[SPECIAL_PROPS.SINGLETON] || false; | ||
properties[SPECIAL_PROPS.EXTRA] = | ||
properties[SPECIAL_PROPS.EXTRA] || undefined; | ||
} | ||
return initializer as | ||
| (ProviderInitializer<D, S> & ProviderProperties) | ||
| (ServiceInitializer<D, S> & ServiceProperties) | ||
| ConstantInitializer<S>; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1176771
12949
1246
102
2
2
4