UNPKG

reactant-di

Version:

A dependency injection lib for Reactant

209 lines (206 loc) 8.21 kB
import { __values, __extends, __spreadArray, __read } from './node_modules/tslib/tslib.es6.js'; import 'reflect-metadata'; import { decorate, ContainerModule, MetadataReader, Container as Container$1 } from 'inversify'; import { getMetadata, lookupOptionalIdentifier, setModulesDeps } from './util.js'; import { createCollector } from './middlewares/collector.js'; import { METADATA_KEY } from './constants.js'; import { defaultUndefinedValue } from './optional.js'; import { ModuleRef } from './moduleRef.js'; import { injectable } from './decorators/injectable.js'; import { inject } from './decorators/inject.js'; var CustomMetadataReader = /** @class */ (function (_super) { __extends(CustomMetadataReader, _super); function CustomMetadataReader() { return _super !== null && _super.apply(this, arguments) || this; } CustomMetadataReader.prototype.getConstructorMetadata = function (constructorFunc) { var constructorMetadata = _super.prototype.getConstructorMetadata.call(this, constructorFunc); // TODO: hook return constructorMetadata; }; return CustomMetadataReader; }(MetadataReader)); function autoBindModules() { return new ContainerModule(function (bind, unbind, isBound) { var e_1, _a; var provideMeta = getMetadata(METADATA_KEY.provide); var optionalMeta = getMetadata(METADATA_KEY.optional); try { for (var provideMeta_1 = __values(provideMeta), provideMeta_1_1 = provideMeta_1.next(); !provideMeta_1_1.done; provideMeta_1_1 = provideMeta_1.next()) { var _b = __read(provideMeta_1_1.value, 2), identifier = _b[0], provide = _b[1]; // default injection without optional module. if ((!optionalMeta.has(identifier) || lookupOptionalIdentifier(identifier)) && !isBound(identifier)) { bind(identifier).to(provide); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (provideMeta_1_1 && !provideMeta_1_1.done && (_a = provideMeta_1.return)) _a.call(provideMeta_1); } finally { if (e_1) throw e_1.error; } } }); } function isClassProvider(module) { return typeof module.useClass === 'function'; } function isFactoryProvider(module) { return typeof module.useFactory === 'function'; } /** * It ensures that the parameters of all modules from the configuration are decorated. * * class Foo { * constructor(bar: Bar) {} * } * * Equate to: * * class Foo { * constructor(@inject() bar: Bar) {} * } * * @param target {object} decorated target. */ function autoDecorateParams(target) { var metadata = Reflect.getMetadata(METADATA_KEY.inversifyParamtypes, target); metadata.forEach(function (_, index) { if (!Reflect.getMetadata(METADATA_KEY.inversifyTagged, target) || !Reflect.getMetadata(METADATA_KEY.inversifyTagged, target)[index]) { inject()(target, undefined, index); } }); } var Container = /** @class */ (function (_super) { __extends(Container, _super); function Container(options, _serviceIdentifiers) { var _this = _super.call(this, options) || this; _this._serviceIdentifiers = _serviceIdentifiers; return _this; } /** * get the loaded module */ Container.prototype.got = function (serviceIdentifier) { try { return this._serviceIdentifiers.has(serviceIdentifier) ? this.get(serviceIdentifier) : undefined; } catch (error) { if (process.env.NODE_ENV !== 'production') { console.warn(error); } return undefined; } }; /** * get loaded modules */ Container.prototype.gotAll = function (serviceIdentifier) { try { return this._serviceIdentifiers.has(serviceIdentifier) ? this.getAll(serviceIdentifier) : undefined; } catch (error) { if (process.env.NODE_ENV !== 'production') { console.warn(error); } return undefined; } }; return Container; }(Container$1)); function bindModules(container, modules) { var e_2, _a; var provideMeta = getMetadata(METADATA_KEY.provide); var _loop_1 = function (module_1) { if (typeof module_1 === 'function') { // auto decorate `@injectable` for module. if (!provideMeta.has(module_1)) decorate(injectable(), module_1); autoDecorateParams(module_1); container.bind(module_1).toSelf(); } else if (typeof module_1 === 'object') { if (isClassProvider(module_1)) { // auto decorate `@injectable` for module.useClass if (!provideMeta.has(module_1.useClass)) decorate(injectable(), module_1.useClass); autoDecorateParams(module_1.useClass); container.bind(module_1.provide).to(module_1.useClass); } else if (Object.hasOwnProperty.call(module_1, 'useValue')) { container .bind(module_1.provide) .toConstantValue(module_1.useValue); } else if (isFactoryProvider(module_1)) { container .bind(module_1.provide) .toFactory(function (context) { var deps = module_1.deps || []; var depInstances = deps.map(function (identifier) { // TODO: refactor with `is` assertion var provide = identifier.provide || identifier; if (identifier.optional && !context.container.isBound(identifier.provide)) { return undefined; } return context.container.get(provide); }); return module_1.useFactory.apply(module_1, __spreadArray([], __read(depInstances), false)); }); } else if (typeof module_1.provide === 'function') { // auto decorate `@injectable` for module.provide if (!provideMeta.has(module_1.provide)) decorate(injectable(), module_1.provide); autoDecorateParams(module_1.provide); container.bind(module_1.provide).toSelf(); } else { throw new Error("".concat(module_1, " option error")); } } else { throw new Error("".concat(module_1, " option error")); } }; try { for (var modules_1 = __values(modules), modules_1_1 = modules_1.next(); !modules_1_1.done; modules_1_1 = modules_1.next()) { var module_1 = modules_1_1.value; _loop_1(module_1); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (modules_1_1 && !modules_1_1.done && (_a = modules_1.return)) _a.call(modules_1); } finally { if (e_2) throw e_2.error; } } // load modules with `@injectable` decoration, but without `@optional` decoration. container.load(autoBindModules()); } function createContainer(_a) { var ServiceIdentifiers = _a.ServiceIdentifiers, _b = _a.modules, modules = _b === void 0 ? [] : _b, options = _a.options; setModulesDeps(modules); var container = new Container(options, ServiceIdentifiers); container.applyCustomMetadataReader(new CustomMetadataReader()); bindModules(container, modules); container.applyMiddleware(createCollector(ServiceIdentifiers)); if (container.isBound(ModuleRef)) { container.unbind(ModuleRef); } container.bind(ModuleRef).toConstantValue(container); container.bind(defaultUndefinedValue).toConstantValue(undefined); return container; } export { Container, bindModules, createContainer };