ayanami
Version:
A better way to react with state
75 lines (74 loc) • 2.89 kB
JavaScript
import { InjectableFactory, Inject } from '@asuka/di';
import { SameScopeMetadataKey } from './same-scope-decorator';
import { CleanupSymbol } from '../../ssr/constants';
import { isSSREnabled } from '../../ssr/flag';
import { reqMap } from '../../ssr/express';
const map = new Map();
export const ayanamiInstances = new Map();
export function createOrGetInstanceInScope(constructor, scope) {
const instanceAtScope = getInstanceFrom(constructor, scope);
return instanceAtScope ? instanceAtScope : createInstanceInScope(constructor, scope);
}
function createInstanceInScope(constructor, scope) {
const paramTypes = Reflect.getMetadata('design:paramtypes', constructor) || [];
// parameters decorated by @Inject
const paramAnnotations = Reflect.getMetadata('parameters', constructor) || [];
const sameScopeParams = Reflect.getMetadata(SameScopeMetadataKey, constructor) || [];
const deps = paramTypes.map((type, index) => {
if (sameScopeParams[index]) {
return createOrGetInstanceInScope(type, scope);
}
if (paramAnnotations[index] !== null) {
let metadata = paramAnnotations[index];
metadata = Array.isArray(metadata) ? metadata : [metadata];
const inject = metadata.find((factory) => factory instanceof Inject);
if (inject && inject.token) {
return InjectableFactory.getInstanceByToken(inject.token);
}
}
return InjectableFactory.getInstance(type);
});
const newInstance = new constructor(...deps);
setInstanceInScope(constructor, scope, newInstance);
return newInstance;
}
function setInstanceInScope(constructor, scope, newInstance) {
const scopeMap = map.get(constructor) || new Map();
scopeMap.set(scope, newInstance);
map.set(constructor, scopeMap);
newInstance[CleanupSymbol] = () => {
newInstance.destroy();
scopeMap.delete(scope);
};
if (isSSREnabled()) {
ayanamiInstances.set(scope, (ayanamiInstances.get(scope) || []).concat(newInstance));
}
}
function getInstanceFrom(constructor, scope) {
const scopeMap = map.get(constructor);
return scopeMap && scopeMap.get(scope);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function createScopeWithRequest(req, scope) {
if (!scope) {
return req;
}
if (reqMap.has(req)) {
const scopes = reqMap.get(req);
if (scopes.has(scope)) {
return scopes.get(scope);
}
else {
const reqScope = { req, scope };
scopes.set(scope, reqScope);
return reqScope;
}
}
else {
const reqScopeMap = new Map();
const reqScope = { req, scope };
reqScopeMap.set(scope, reqScope);
reqMap.set(req, reqScopeMap);
return reqScope;
}
}