@homer0/jimple
Version:
An extended version of the Jimple lib, with extra features
103 lines (98 loc) • 3.5 kB
text/typescript
import { resourceFactory } from './resourceFactory.js';
import type {
GenericFn,
GenericCurriedFn,
ResourceCreator,
ResourceCreatorCurriedFn,
ResourceCreatorHandler,
} from './factories.types.js';
/**
* 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');
* });
*
*/
export const resourceCreatorFactory =
<ResourceFn extends GenericFn>() =>
/**
* Generates a new resource creator using the contraint defined in the factory.
*
* @param name The name of the resource.
* @param key The property key for the function.
* @param creatorFn The curried function that returns the actual resource function.
* @returns A resource creator: an object that can be used as a resource, and as a
* function that returns a resource.
* @template Name The literal type of `name`, to be used in the return object.
* @template Key The literal type of `key`, to be used in the return object.
* @template ResFn The type of the resource function, the creator function needs
* to return. This is restricted by the factory constraint.
* @template CreatorFn The literal type of `creatorFn`, to be used in the return
* object.
* @example
*
* const myAction = factory('action', 'fn', (name = 'foo') => (c) => {
* c.set(name, 'bar');
* });
*
*/
<
Name extends string,
Key extends string,
ResFn extends ResourceFn,
CreatorFn extends GenericCurriedFn<ResFn>,
>(
name: Name,
key: Key,
creatorFn: CreatorFn,
): ResourceCreator<Name, Key, CreatorFn, ResourceFn> => {
const fnToProxy: ResourceCreatorCurriedFn<Name, Key, CreatorFn> = (...args) => {
const actualResource = creatorFn(...args) as ReturnType<CreatorFn>;
return resourceFactory<ResFn>()(name, key, actualResource);
};
const handler: ResourceCreatorHandler<Name, Key, CreatorFn> = {
name,
resource: null,
get(target, property) {
let result;
if (property === this.name) {
result = true;
} else if (property === key) {
if (this.resource === null) {
const newResource = creatorFn() as ReturnType<CreatorFn>;
this.resource = newResource;
}
result = this.resource;
} else {
const targetKey = property as keyof typeof target;
result = target[targetKey];
}
return result;
},
has(target, property) {
if (property === this.name || property === key) {
return true;
}
const targetKey = property as keyof typeof target;
return targetKey in target;
},
};
return new Proxy(fnToProxy, handler) as unknown as ResourceCreator<
Name,
Key,
CreatorFn,
ResourceFn
>;
};