@homer0/jimple
Version:
An extended version of the Jimple lib, with extra features
372 lines (360 loc) • 16.7 kB
text/typescript
declare class Container {
static provider<T extends (arg0: Container) => void>(register: T): {
register: T;
};
_items: Record<string, unknown>;
_instances: Map<string, unknown>;
_factories: Set<unknown>;
_protected: Set<unknown>;
/**
* Creates a Jimple Container.
*
* @param values An optional object whose keys and values will be associated in the
* container at initialization.
*/
constructor(values?: Record<string, unknown>);
/**
* Return the specified parameter or service. If the service is not built yet, this
* function will construct the service injecting all the dependencies needed in it's
* definition so the returned object is totally usable on the fly.
*
* @param key The key of the parameter or service to return.
* @returns The object related to the service or the value of the parameter
* associated with the given key.
* @template T The type of the returned object.
* @throws If the key does not exist.
*/
get<T = unknown>(key: string): T;
/**
* Defines a new parameter or service.
*
* @param key The key of the parameter or service to be defined.
* @param value The value of the parameter or a function that receives the container
* as parameter and constructs the service.
*/
set(key: string, value: unknown): void;
/**
* Returns if a service or parameter with the informed key is already defined in the
* container.
*
* @param key The key of the parameter or service to be checked.
* @returns If the key exists in the container or not.
*/
has(key: string): boolean;
/**
* Defines a service as a factory, so the instances are not cached in the service and
* that function is always called.
*
* @param fn The function that constructs the service that is a factory.
* @returns The same function passed as parameter.
*/
factory<C = this>(fn: (arg0: C) => unknown): (arg0: C) => unknown;
/**
* Defines a function as a parameter, so that function is not considered a service.
*
* @param fn The function to not be considered a service.
* @returns The same function passed as parameter.
*/
protect<T extends () => unknown>(fn: T): T;
/**
* Return all the keys registered in the container.
*/
keys(): string[];
/**
* Extends a service already registered in the container.
*
* @param key The key of the service to be extended.
* @param fn The function that will be used to extend the service.
* @throws If the key is not already defined.
* @throws If the key saved in the container does not correspond to a service.
* @throws If the function passed it not...well, a function.
*/
extend<C = this>(key: string, fn: (arg0: unknown, arg1: C) => unknown): void;
/**
* Uses an provider to extend the service, so it's easy to split the service and
* parameter definitions across the system.
*
* @param provider The provider to be used to register services and parameters in
* this container.
*/
register<C = this>(provider: {
register: (arg0: C) => void;
}): void;
/**
* Returns the raw value of a service or parameter. So, in the case of a service,
* for example, the value returned is the function used to construct the service.
*
* @param key The key of the service or parameter to return.
* @throws If the key does not exist in the container.
*/
raw<T = unknown>(key: string): T;
}
declare const Jimple$1: typeof Container;
declare class Jimple extends Jimple$1 {
/**
* This is a version of the `get` method that doesn't throw if the key doesn't exist. It
* will return `undefined` instead.
*
* @param key The key of the parameter or service to return.
* @returns The object related to the service or the value of the parameter
* associated with the given key.
* @template T The type of the returned object.
*/
try<T = unknown>(key: string): T | undefined;
}
/**
* Shorthand for `new Jimple()`.
*
* @param args The same parameters as the {@link Jimple} constructor.
* @returns A new instance of {@link Jimple}.
*/
declare const jimple: (...args: ConstructorParameters<typeof Jimple>) => Jimple;
type GenericFn = (...args: any[]) => any;
type GenericCurriedFn<ReturnFn = GenericFn> = (...args: any[]) => ReturnFn;
type Resource<Name extends string, Key extends string, Fn extends GenericFn> = {
[NameItem in Name]: true;
} & {
[KeyItem in Key]: Fn;
} & Record<string, unknown>;
type ResourceCreatorCurriedFn<Name extends string, Key extends string, Fn extends GenericCurriedFn> = (...args: any[]) => Resource<Name, Key, ReturnType<Fn>>;
type ResourceCreatorHandler<Name extends string, Key extends string, Fn extends GenericCurriedFn> = ProxyHandler<ResourceCreatorCurriedFn<Name, Key, Fn>> & {
name: Name;
resource: ReturnType<Fn> | null;
};
type ResourceCreator<Name extends string, Key extends string, CreatorFn extends GenericCurriedFn, ResourceFn extends GenericFn> = ((...args: Parameters<CreatorFn>) => Resource<Name, Key, ResourceFn>) & Resource<Name, Key, ResourceFn>;
/**
* Generates a function to create resource creators of an specified type. This function
* itself doesn't have logic, but it's just in charge of creating the constraint for the
* resource creator function.
*
* As all the other _"factory functions"_, this is meant to be used as a building block
* when extending the container.
*
* @returns A function that can be used to create "resource creators".
* @template ResourceFn The type of function the resource creator needs to have.
* @example
*
* type ActionFn = (c: Jimple) => void;
* const factory = resourceCreatorFactory<ActionFn>();
* const myAction = factory('action', 'fn', (name = 'foo') => (c) => {
* c.set(name, 'bar');
* });
*
*/
declare const resourceCreatorFactory: <ResourceFn extends GenericFn>() => <Name extends string, Key extends string, ResFn extends ResourceFn, CreatorFn extends GenericCurriedFn<ResFn>>(name: Name, key: Key, creatorFn: CreatorFn) => ResourceCreator<Name, Key, CreatorFn, ResourceFn>;
/**
* Generates a function to create resources of an specified type. This function itself
* doesn't have logic, but it's just in charge of creating the constraint for the resource
* function.
*
* As all the other _"factory functions"_, this is meant to be used as a building block
* when extending the container.
*
* @returns A function that can be used to create a resource with a specified type of
* function.
* @template ResourceFn The type of function the resource needs to have.
* @example
*
* type ActionFn = (c: Jimple) => void;
* const factory = resourceFactory<ActionFn>();
* const myAction = factory('action', 'fn', (c) => {
* c.set('foo', 'bar');
* });
*
*/
declare const resourceFactory: <ResourceFn extends GenericFn>() => <Name extends string, Key extends string, Fn extends ResourceFn>(name: Name, key: Key, fn: Fn) => Resource<Name, Key, Fn>;
/**
* Generates a function to configure a collection of resources of an specified type. This
* function itself doesn't have logic, but it's just in charge of creating the constraint
* for the resource name and function.
*
* As all the other _"factory functions"_, this is meant to be used as a building block
* when extending the container.
*
* @returns A function that can be used to configure a collection of resources.
* @template ResourceName The literal type of the name the resources needs to have.
* @template ResourceFn The type of function the resources needs to have.
* @example
*
* type ActionFn = (c: Jimple) => void;
* const factory = resourcesCollectionFactory<'action', ActionFn>();
* const myActions = factory('action', 'fn')({ myActionA, myActionB });
*
*/
declare const resourcesCollectionFactory: <ResourceName extends string, ResourceFn extends GenericFn>() => <Name extends string, Key extends string, ItemKey extends string, Items extends Record<ItemKey, Resource<ResourceName, Key, ResourceFn>>, CustomFn extends (items: Items, ...rest: Parameters<ResourceFn>) => void>(name: Name, key: Key, fn?: CustomFn) => <ItemsParam>(items: ItemsParam & Items) => typeof items & Resource<Name, Key, ResourceFn>;
type GenericDict = Record<any, any>;
/**
* A helper that reusable services can use to resolve dependencies in constructors and/or
* providers.
*
* @template InjectDictionary A dictionary of the dependencies and their types.
* @template InjectKey The literal type of the dictionary types.
*/
declare class InjectHelper<InjectDictionary extends GenericDict, InjectKey = keyof InjectDictionary> {
/**
* This method is meant to be used to validate the dependencies a service receives, and
* needs.
* It will check on the received dependencies, if a specific dependency exists, it will
* return it, otherwise, it will create a new instance.
*
* @param dependencies The dependencies received by the implementation.
* @param key The key of the dependency to validate.
* @param init A function to create a dependency in case it doesn't exist in
* the dictionary.
* @returns An instance of the dependency.
* @template DepKey The literal key of the dependency to validate.
* @template DepType The type of the dependency, obtained from the dictionary sent
* to the constructor.
* @example
*
* type Dependencies = {
* dep: string;
* };
* const helper = new InjectHelper<Dependencies>();
*
* type MyServiceOptions = {
* inject?: Partial<Dependencies>;
* };
* const myService = ({ inject = {} }: MyServiceOptions) => {
* const dep = helper.get(inject, 'dep', () => 'default');
* console.log('dep:', dep);
* };
*
*/
get<DepKey extends InjectKey, DepType = InjectDictionary[DepKey]>(dependencies: Partial<InjectDictionary>, key: InjectKey, init: () => DepType): DepType;
/**
* This is meant to be used in a provider creator to resolve dependencies' names sent as
* options. For each dependency, the method will first check if a new name was
* specified, and try to get it with that name, otherwise, it will try to get it with
* the default name, and if it doesn't exist, it will just keep it as `undefined` and
* expect the service implements {@link InjectHelper.get} to ensure the dependency.
*
* @param dependencies The dependencies needed by the service.
* @param container A reference to the Jimple container.
* @param inject A dictionary of dependencies names.
* @returns A dictionary of dependencies to send to the service.
* @template DepKey The literal key of the dependencies to validate.
* @template Container The type of the Jimple container.
* @example
*
* type Dependencies = {
* dep: string;
* };
* const helper = new InjectHelper<Dependencies>();
*
* type MyProviderOptions = {
* services?: {
* [key in keyof Dependencies]?: string;
* };
* };
*
* const myProvider = providerCreator(
* ({ services = {} }: MyProviderOptions) =>
* (container) => {
* container.set('myService', () => {
* const inject = helper.resolve(['dep'], container, services);
* return myService({ inject });
* });
* },
* );
*
*/
resolve<DepKey extends InjectKey, Container extends Jimple>(dependencies: DepKey[], container: Container, inject: Partial<Record<keyof InjectDictionary, string>>): Partial<InjectDictionary>;
}
/**
* Shorthand for `new InjectHelper()`.
*
* @returns A new instance of {@link InjectHelper}.
*/
declare const injectHelper: <InjectDictionary extends GenericDict>() => InjectHelper<InjectDictionary, keyof InjectDictionary>;
type ProviderName = 'provider';
type ProviderKey = 'register';
/**
* The function the container will call when the provider is registered.
*
* @param container A reference for container where the provider is being registered.
* @template ContainerType The type of the Jimple container (in case it gets
* subclassed).
*/
type ProviderRegisterFn<ContainerType extends Jimple = Jimple> = (container: ContainerType) => void;
/**
* Generates a function to create providers for a specific type of container.
*
* @returns A function to create providers.
* @template ContainerType The type of the Jimple container (in case it gets
* subclassed).
*/
declare const createProvider: <ContainerType extends Jimple = Jimple>() => (register: ProviderRegisterFn<ContainerType>) => Resource<"provider", "register", ProviderRegisterFn<ContainerType>>;
/**
* Creates a resource to be registered in a Jimple container.
*
* @example
*
* export const myService = provider((c) => {
* c.set('myService', () => new MyService());
* });
*
*/
declare const provider: (register: ProviderRegisterFn<Jimple>) => Resource<"provider", "register", ProviderRegisterFn<Jimple>>;
/**
* A resource that can be registered in a Jimple container.
*/
type Provider = ReturnType<typeof provider>;
/**
* Generates a function to create "provider creators" for a specific type of container.
*
* @returns A function to generate provider creators.
* @template ContainerType The type of the Jimple container (in case it gets
* subclassed).
*/
declare const createProviderCreator: <ContainerType extends Jimple = Jimple>() => <CreatorFn extends GenericCurriedFn<ProviderRegisterFn<ContainerType>>>(creator: CreatorFn) => ResourceCreator<"provider", "register", CreatorFn, ProviderRegisterFn<ContainerType>>;
/**
* Generates a "provider creator": a provider that can also be called as a function in
* order to create a configured provider.
*
* @example
*
* export const myService = providerCreator((options: Opts = {}) => (c) => {
* c.set('myService', () => new MyService(options));
* });
*
*/
declare const providerCreator: <CreatorFn extends GenericCurriedFn<ProviderRegisterFn<Jimple>>>(creator: CreatorFn) => ResourceCreator<"provider", "register", CreatorFn, ProviderRegisterFn<Jimple>>;
/**
* A function that returns a provider registration function.
*/
type ProviderCreatorFn = Parameters<typeof providerCreator>[0];
/**
* Generates a function to create a providers collection for a specific type of container.
*
* @returns A function to create providers collections.
* @template ContainerType The type of the Jimple container (in case it gets
* subclassed).
*/
declare const createProviders: <ContainerType extends Jimple = Jimple>() => <ItemsParam>(items: ItemsParam & Record<string, Resource<"provider", "register", ProviderRegisterFn<ContainerType>>>) => ItemsParam & Record<string, Resource<"provider", "register", ProviderRegisterFn<ContainerType>>> & {
provider: true;
} & {
register: ProviderRegisterFn<ContainerType>;
} & Record<string, unknown>;
/**
* Generates a collection of providers. A collection is a dictionary of providers that can
* also be used as a provider, and when it gets registered, it will register all of the
* providers in the collection.
*
* @param items A dictionary of providers.
* @example
*
* <caption>Assuming we already have two service providers...</caption>
*
* export const services = providers({
* myServiceProvider,
* myOtherServiceProvider,
* });
*
*/
declare const providers: <ItemsParam>(items: ItemsParam & Record<string, Resource<"provider", "register", ProviderRegisterFn<Jimple>>>) => ItemsParam & Record<string, Resource<"provider", "register", ProviderRegisterFn<Jimple>>> & {
provider: true;
} & {
register: ProviderRegisterFn<Jimple>;
} & Record<string, unknown>;
export { type GenericCurriedFn, type GenericFn, InjectHelper, Jimple, type Provider, type ProviderCreatorFn, type ProviderKey, type ProviderName, type ProviderRegisterFn, type Resource, type ResourceCreator, type ResourceCreatorCurriedFn, type ResourceCreatorHandler, createProvider, createProviderCreator, createProviders, injectHelper, jimple, provider, providerCreator, providers, resourceCreatorFactory, resourceFactory, resourcesCollectionFactory };