@asuka/di
Version:
Dependencies inject library
349 lines (338 loc) • 13.4 kB
JavaScript
import { __values, __spread, __extends } from 'tslib';
import React, { createContext, memo, useContext, useMemo } from 'react';
var ReflectiveProvider = (function () {
function ReflectiveProvider(provider) {
this.provider = provider;
if (typeof provider === 'function') {
this.name = provider.name;
this.token = provider;
}
else {
this.name = provider.provide.toString();
this.token = provider.provide;
}
}
ReflectiveProvider.prototype.toString = function () {
return this.name;
};
return ReflectiveProvider;
}());
var InjectionProvider = (function () {
function InjectionProvider() {
this.providersMap = new Map();
}
InjectionProvider.prototype.addProvider = function (provider) {
var _a;
this.providersMap.set((_a = provider.provide, (_a !== null && _a !== void 0 ? _a : provider)), provider);
return provider;
};
InjectionProvider.prototype.findProviderByToken = function (token) {
if (!this.providersMap.has(token)) {
return null;
}
return this.providersMap.get(token);
};
return InjectionProvider;
}());
var Injector = (function () {
function Injector(parent) {
if (parent === void 0) { parent = null; }
this.parent = parent;
this.provider = new InjectionProvider();
this.resolvedProviders = new Map();
this.providersCache = new Map();
}
Injector.prototype.addProvider = function (provider) {
return this.provider.addProvider(provider);
};
Injector.prototype.addProviders = function (providers) {
var e_1, _a;
try {
for (var providers_1 = __values(providers), providers_1_1 = providers_1.next(); !providers_1_1.done; providers_1_1 = providers_1.next()) {
var provider = providers_1_1.value;
this.provider.addProvider(provider);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (providers_1_1 && !providers_1_1.done && (_a = providers_1.return)) _a.call(providers_1);
}
finally { if (e_1) throw e_1.error; }
}
return this;
};
Injector.prototype.getInstance = function (provider) {
return this._getInstance(provider, true);
};
Injector.prototype.resolveAndInstantiate = function (provider) {
return this._getInstance(provider, false);
};
Injector.prototype.createChild = function (providers) {
var e_2, _a;
var childInjector = new Injector(this);
try {
for (var providers_2 = __values(providers), providers_2_1 = providers_2.next(); !providers_2_1.done; providers_2_1 = providers_2.next()) {
var provider = providers_2_1.value;
childInjector.provider.addProvider(provider);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (providers_2_1 && !providers_2_1.done && (_a = providers_2.return)) _a.call(providers_2);
}
finally { if (e_2) throw e_2.error; }
}
return childInjector;
};
Injector.prototype.resolveReflectiveProvider = function (provider) {
var _a;
var reflectiveProvider = null;
if (this.provider.findProviderByToken((_a = provider.provide, (_a !== null && _a !== void 0 ? _a : provider)))) {
if (this.providersCache.has(provider)) {
return this.providersCache.get(provider);
}
reflectiveProvider = new ReflectiveProvider(provider);
this.providersCache.set(provider, reflectiveProvider);
}
return reflectiveProvider;
};
Injector.prototype._getInstance = function (provider, useCache) {
var injector = this;
var instance = null;
var reflectiveProvider = null;
var deps = this._findDeps(provider);
while (injector) {
reflectiveProvider = injector.resolveReflectiveProvider(provider);
if (!reflectiveProvider) {
injector = injector.parent;
continue;
}
if (injector.resolvedProviders.has(reflectiveProvider)) {
if (deps) {
if (useCache && (injector === this || this._checkDepenciesClean(injector, deps))) {
instance = injector.resolvedProviders.get(reflectiveProvider);
}
else {
instance = this._resolveByReflectiveProvider(reflectiveProvider, false, this);
if (useCache) {
this.resolvedProviders.set(reflectiveProvider, instance);
}
}
}
else {
instance = injector.resolvedProviders.get(reflectiveProvider);
}
break;
}
instance = injector._resolveByReflectiveProvider(reflectiveProvider, useCache, this);
if (instance) {
if (useCache) {
injector.resolvedProviders.set(reflectiveProvider, instance);
}
break;
}
injector = injector.parent;
}
if (!instance) {
reflectiveProvider = new ReflectiveProvider(provider);
throw new TypeError("No provider for " + reflectiveProvider.name + "!");
}
return instance;
};
Injector.prototype._resolveByReflectiveProvider = function (reflectiveProvider, useCache, leaf) {
var _a;
if (useCache === void 0) { useCache = true; }
if (leaf === void 0) { leaf = this; }
var _b;
var instance = null;
var provider = reflectiveProvider.provider, name = reflectiveProvider.name;
if (typeof provider === 'function') {
var deps = (_b = Reflect.getMetadata('design:paramtypes', provider), (_b !== null && _b !== void 0 ? _b : []));
var depsInstance = deps.map(function (dep) { return leaf._getInstance(leaf._findExisting(dep), useCache); });
instance = new (provider.bind.apply(provider, __spread([void 0], depsInstance)))();
}
else if (provider.useValue) {
instance = provider.useValue;
}
else if (provider.useClass) {
instance = leaf._getInstance(provider.useClass, useCache);
}
else if (provider.useFactory) {
var deps = [];
if (provider.deps) {
deps = provider.deps.map(function (dep) { return leaf._getInstance(leaf._findExisting(dep), useCache); });
}
instance = (_a = provider).useFactory.apply(_a, __spread(deps));
}
else if (provider.useExisting) {
instance = leaf._getInstance(this._findExisting(provider.useExisting), useCache);
}
if (!instance) {
throw new TypeError("Can not resolve " + name + ", it's not a valid provider");
}
return instance;
};
Injector.prototype._findExisting = function (token) {
var _a;
var provider = null;
var injector = this;
while (injector) {
provider = injector.provider.findProviderByToken(token);
if (provider) {
break;
}
injector = injector.parent;
}
if (!provider) {
throw new TypeError("No provider for " + (_a = token.name, (_a !== null && _a !== void 0 ? _a : token.toString())));
}
return provider;
};
Injector.prototype._findDeps = function (provider) {
return typeof provider === 'function'
? Reflect.getMetadata('design:paramtypes', provider)
: provider.useClass
? Reflect.getMetadata('design:paramtypes', provider.useClass)
: provider.deps
? provider.deps
: null;
};
Injector.prototype._checkDepenciesClean = function (leaf, deps) {
var _this = this;
return deps.every(function (dep) {
var depInLeaf = leaf._findExisting(dep);
var depInRoot = _this._findExisting(dep);
var isEqual = depInLeaf === depInRoot;
var deps = _this._findDeps(depInLeaf);
if (deps) {
return _this._checkDepenciesClean(leaf, deps) && isEqual;
}
return isEqual;
});
};
return Injector;
}());
var RootInjector = (function (_super) {
__extends(RootInjector, _super);
function RootInjector() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.provider = new InjectionProvider();
return _this;
}
RootInjector.prototype.reset = function () {
this.provider = new InjectionProvider();
this.providersCache.clear();
this.resolvedProviders.clear();
};
return RootInjector;
}(Injector));
var rootInjector = new RootInjector();
function Injectable() {
return function (target) {
rootInjector.addProvider({
useClass: target,
provide: target,
});
return target;
};
}
var _InjectableContext = createContext(rootInjector);
function InjectableContext(_a) {
var children = _a.children;
return React.createElement(_InjectableContext.Provider, { value: rootInjector }, children);
}
var ProvidersContext = createContext([]);
var InjectionProvidersContext = memo(function (_a) {
var _b = _a.providers, providers = _b === void 0 ? [] : _b, children = _a.children;
var parentInjector = useContext(_InjectableContext);
var childInjectableFactory = useMemo(function () { return parentInjector.createChild(providers); }, [providers]);
return (React.createElement(_InjectableContext.Provider, { value: childInjectableFactory },
React.createElement(ProvidersContext.Provider, { value: providers }, children)));
});
function useInstance(provider) {
var childInjector = useContext(_InjectableContext);
return childInjector.getInstance(provider);
}
var InjectionToken = (function () {
function InjectionToken(desc) {
this.desc = desc;
}
InjectionToken.prototype.toString = function () {
return this.desc;
};
return InjectionToken;
}());
function Inject(token) {
return function (target, _key, paramIndex) {
var deps = Reflect.getMetadata('design:paramtypes', target);
deps[paramIndex] = token;
};
}
var Test = (function () {
function Test(providers, TestModule) {
var e_1, _a;
var _b;
this.TestModule = TestModule;
this.providersMap = new Map();
try {
for (var providers_1 = __values(providers), providers_1_1 = providers_1.next(); !providers_1_1.done; providers_1_1 = providers_1.next()) {
var provier = providers_1_1.value;
this.providersMap.set((_b = provier.provide, (_b !== null && _b !== void 0 ? _b : provier)), provier);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (providers_1_1 && !providers_1_1.done && (_a = providers_1.return)) _a.call(providers_1);
}
finally { if (e_1) throw e_1.error; }
}
}
Test.createTestingModule = function (overrideConfig) {
return new Test(overrideConfig && overrideConfig.providers ? overrideConfig.providers : [], overrideConfig && overrideConfig.TestModule ? overrideConfig.TestModule : TestModule);
};
Test.prototype.overrideProvider = function (token) {
return new MockProvider(this, token);
};
Test.prototype.compile = function () {
var childInjector = rootInjector.createChild(Array.from(this.providersMap.values()));
return new this.TestModule(childInjector);
};
return Test;
}());
var MockProvider = (function () {
function MockProvider(test, token) {
this.test = test;
this.token = token;
}
MockProvider.prototype.useClass = function (value) {
this.test.providersMap.set(this.token, { provide: this.token, useClass: value });
return this.test;
};
MockProvider.prototype.useValue = function (value) {
this.test.providersMap.set(this.token, { provide: this.token, useValue: value });
return this.test;
};
MockProvider.prototype.useFactory = function (value) {
this.test.providersMap.set(this.token, { provide: this.token, useFactory: value });
return this.test;
};
return MockProvider;
}());
var AbstractTestModule = (function () {
function AbstractTestModule() {
}
return AbstractTestModule;
}());
var TestModule = (function () {
function TestModule(injector) {
this.injector = injector;
}
TestModule.prototype.getInstance = function (token) {
return this.injector.getInstance(token);
};
return TestModule;
}());
export { AbstractTestModule, Inject, Injectable, InjectableContext, InjectionProvidersContext, InjectionToken, Injector, MockProvider, RootInjector, Test, TestModule, rootInjector, useInstance };