@triviality/core
Version:
Purely typed service container
69 lines (58 loc) • 3.26 kB
text/typescript
import { ServiceFactoryByTag, ServiceKeysOfType, ServiceTag, SF } from '../../ServiceFactory';
import {
ImmutableRegistryMap,
makeImmutableRegistryMap,
REGISTER_MAP_ARGUMENTS,
RegistryMap,
} from './ImmutableRegistryMap';
import { toPairs } from 'ramda';
import { wrapReturnAsReference } from '../ReferenceContext';
import { Override } from '../../Value/Override';
import { ServiceFunctionReferenceContainerInterface } from '../../Container/ServiceFunctionReferenceContainerInterface';
export type RegisterMapArgument<Services, TType, TKey> =
[TKey, ServiceKeysOfType<Services, TType> | SF<TType>]
| (TKey extends string | symbol | number ? Record<TKey, SF<TType> | ServiceKeysOfType<Services, TType>> : never);
export type RegisterMapArguments<Services, TType, TKey> = RegisterMapArgument<Services, TType, TKey>[];
export interface RegistryMapContext<Services> {
registerMap<TType, TKey = string>(...items: RegisterMapArguments<Services, TType, TKey>): SF<ImmutableRegistryMap<TType, TKey>>;
}
export const createFeatureFactoryRegistryMapContext = <Services>(container: ServiceFunctionReferenceContainerInterface): RegistryMapContext<Services> => {
return {
registerMap: wrapReturnAsReference(registerMap<Services>(container.getService)),
};
};
export type registerWithMapArguments<Services, TType, TKey> = (...items: RegisterMapArguments<Services, TType, TKey>) => {};
export type InferMapArgumentsRegisters<T> = {
[K in keyof T]: T[K] extends { [REGISTER_MAP_ARGUMENTS]: [infer TType, infer TKey] } ? registerWithMapArguments<T, TType, TKey> : unknown;
};
const getServices = <Services, TType, TKey>(getService: ServiceFactoryByTag<TType>, items: RegisterMapArguments<Services, TType, TKey>): [TKey, SF<TType>][] => {
const result: [TKey, SF<TType>][] = [];
items.forEach(
(arg: RegisterMapArgument<Services, TType, TKey>) => {
if (!(arg instanceof Array)) {
return toPairs(arg).forEach(([tag, item]) => {
result.push([tag, (typeof item === 'string' ? getService(item) : item)] as any as [TKey, SF<TType>]);
});
}
{
const [tag, item] = arg;
result.push([tag, (typeof item === 'string' ? getService(item) : item)] as [TKey, SF<TType>]);
}
});
return result;
};
const mapServices = <TType, TKey>(services: [TKey, SF<TType>][]): [TKey, TType][] => services.map(
([tag, sf]) => [tag, sf()]) as any;
export const registerMap = <Services>(getService: ServiceFactoryByTag<any>) => <TType, TKey>(...args: RegisterMapArguments<Services, TType, TKey>): SF<ImmutableRegistryMap<TType, TKey>> => {
const factories = getServices<Services, TType, TKey>(getService, args);
return () => makeImmutableRegistryMap<TType, TKey>(...mapServices<TType, TKey>(factories));
};
export const registerToMap = <Services, TType, TKey>(container: ServiceFunctionReferenceContainerInterface, registry: ServiceTag, ...items: RegisterMapArguments<Services, TType, TKey>): void => {
const serverFactories = getServices<Services, TType, TKey>(container.getService, items);
container.override(new Override<RegistryMap<TType, TKey>>({
tag: registry,
override: (service) => {
return service().register(...mapServices(serverFactories));
},
}));
};