@homer0/jimple 6.0.7 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -6
- package/src/jimple/index.ts +2 -2
- package/src/original/helpers.ts +32 -0
- package/src/original/index.ts +1 -0
- package/src/original/jimple.ts +169 -0
- package/src/jimplemod/index.ts +0 -8
- package/src/jimplemod/jimple.type.ts +0 -91
package/README.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
An extended version of the [Jimple](https://www.npmjs.com/package/jimple) lib, with extra features.
|
|
4
4
|
|
|
5
|
+
## ⚠️ v2
|
|
6
|
+
|
|
7
|
+
After a few years, the original Jimple library finally released a v2 version, which added types, and introduced a few design changes that are not fully compatible with the features that built here; plus, I'm not a fan of some of the choices.
|
|
8
|
+
|
|
9
|
+
As of October 2026, this package vendors the original Jimple library v1 ([`1.5.0`](https://www.npmjs.com/package/jimple/v/1.5.0)) internally and I don't plan to upgrade to v2.
|
|
10
|
+
|
|
11
|
+
But, maybe v2 is something that may fit your use case, so you might want to check it out directly, and give it a chance.
|
|
12
|
+
|
|
5
13
|
## 🍿 Usage
|
|
6
14
|
|
|
7
15
|
> If you are wondering why I built this, go to the [Motivation](#motivation) section.
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
function e(e,t){if(!e)throw Error(t)}const t=e=>Object.prototype.toString.call(e)===`[object Function]`&&e.constructor.name===`Function`,n=e=>{if(Object.prototype.toString.call(e)!==`[object Object]`)return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype},r=(t,n)=>{e(t.has(n),`Identifier "${n}" is not defined.`)},i=(n,r)=>(e(t(r),`Service definition is not a Closure or invokable object`),n.add(r),r);var a=class{static provider(e){return{register:e}}_items={};_instances=/* @__PURE__ */ new Map;_factories=/* @__PURE__ */ new Set;_protected=/* @__PURE__ */ new Set;constructor(e){let t=n(e)?e:{};Object.entries(t).forEach(([e,t])=>{this.set(e,t)},this)}get(e){r(this,e);let n=this._items[e],i;return t(n)?this._protected.has(n)?i=n:this._instances.has(n)?i=this._instances.get(n):(i=n(this),this._factories.has(n)||this._instances.set(n,i)):i=n,i}set(e,t){this._items[e]=t}has(e){return Object.hasOwn(this._items,e)}factory(e){return i(this._factories,e)}protect(e){return i(this._protected,e)}keys(){return Object.keys(this._items)}extend(n,i){r(this,n);let a=this._items[n];e(t(a)&&this._protected.has(a)===!1,`Identifier '${n}' does not contain a service definition`),e(t(i),`The 'new' service definition for '${n}' is not a invokable object.`),this._items[n]=e=>i(a(e),e),this._factories.has(a)&&(this._factories.delete(a),this._factories.add(this._items[n]))}register(e){e.register(this)}raw(e){return r(this,e),this._items[e]}},o=class extends a{try(e){if(this.has(e))return this.get(e)}};const s=(...e)=>new o(...e),c=()=>(e,t,n)=>({[e]:!0,[t]:n}),l=()=>(e,t,n)=>new Proxy((...r)=>{let i=n(...r);return c()(e,t,i)},{name:e,resource:null,get(e,r){let i;if(r===this.name)i=!0;else if(r===t){if(this.resource===null){let e=n();this.resource=e}i=this.resource}else i=e[r];return i},has(e,n){return n===this.name||n===t||n in e}}),u=()=>(e,t,n)=>{let r=c();return i=>{let a=[e,t],o=Object.keys(i);if(o.some(e=>a.includes(String(e))))throw Error(`No item on the collection can have the keys \`${e}\` nor \`${t}\``);let s=o.find(e=>typeof i[e]?.[t]!=`function`);if(s)throw Error(`The item \`${String(s)}\` is invalid: it doesn't have a \`${t}\` function`);return{...r(e,t,n?(...e)=>n(i,...e):(...e)=>{o.forEach(n=>{let r=i[n][t];r(...e)})}),...i}}};var d=class{get(e,t,n){let r=e[t];return r===void 0?n():r}resolve(e,t,n){return e.reduce((e,r)=>{if(n[r])return e[r]=t.get(n[r]),e;let i=r;return t.has(i)&&(e[r]=t.get(i)),e},{})}};const f=()=>new d,p=()=>{let e=c();return t=>e(`provider`,`register`,t)},m=p(),h=()=>{let e=l();return t=>e(`provider`,`register`,t)},g=h(),_=()=>u()(`provider`,`register`),v=_();export{d as InjectHelper,o as Jimple,p as createProvider,h as createProviderCreator,_ as createProviders,f as injectHelper,s as jimple,m as provider,g as providerCreator,v as providers,l as resourceCreatorFactory,c as resourceFactory,u as resourcesCollectionFactory};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Jimple","JimpleOriginal","JimpleMod","targetKey"],"sources":["../../../../node_modules/.pnpm/jimple@1.5.0/node_modules/jimple/src/Jimple.js","../src/jimplemod/index.ts","../src/jimple/index.ts","../src/factories/resourceFactory.ts","../src/factories/resourceCreatorFactory.ts","../src/factories/resourcesCollectionFactory.ts","../src/helpers/injectHelper.ts","../src/helpers/provider.ts","../src/helpers/providerCreator.ts","../src/helpers/providers.ts"],"sourcesContent":["\"use strict\";\n\nfunction assert(ok, message) {\n if (!ok) {\n throw new Error(message)\n }\n}\n\nfunction isFunction(fn) {\n return Object.prototype.toString.call(fn) === \"[object Function]\" && fn.constructor.name === \"Function\";\n}\n\nfunction isPlainObject(value) {\n if (Object.prototype.toString.call(value) !== '[object Object]') {\n return false;\n }\n let prototype = Object.getPrototypeOf(value);\n return prototype === null || prototype === Object.prototype;\n}\n\nfunction checkDefined(container, key) {\n assert(container.has(key), `Identifier \"${key}\" is not defined.`);\n}\n\nfunction addFunctionTo(set, fn) {\n assert(isFunction(fn), \"Service definition is not a Closure or invokable object\");\n set.add(fn);\n return fn;\n}\n\n/**\n * The Jimple Container class\n *\n * @public\n */\nclass Jimple {\n static provider(register) {\n return ({ register });\n }\n /**\n * Create a Jimple Container.\n * @param {Object?} [values] - An optional object whose keys and values will be associated in the container at initialization\n */\n constructor(values) {\n this._items = {};\n this._instances = new Map();\n this._factories = new Set();\n this._protected = new Set();\n values = isPlainObject(values) ? values : {};\n Object.keys(values).forEach(function(key) {\n this.set(key, values[key]);\n }, this);\n }\n /**\n * Return the specified parameter or service. If the service is not built yet, this function will construct the service\n * injecting all the dependencies needed in it's definition so the returned object is totally usable on the fly.\n * @param {string} key - The key of the parameter or service to return\n * @return {*} The object related to the service or the value of the parameter associated with the key informed\n * @throws If the key does not exist\n */\n get(key) {\n checkDefined(this, key);\n let item = this._items[key];\n let obj;\n if (isFunction(item)) {\n if (this._protected.has(item)) {\n obj = item;\n } else if (this._instances.has(item)) {\n obj = this._instances.get(item);\n } else {\n obj = item(this);\n if (!this._factories.has(item)) {\n this._instances.set(item, obj);\n }\n }\n } else {\n obj = item;\n }\n return obj;\n }\n /**\n * Defines a new parameter or service.\n * @param {string} key - The key of the parameter or service to be defined\n * @param {*} value - The value of the parameter or a function that receives the container as parameter and constructs the service\n */\n set(key, value) {\n this._items[key] = value;\n }\n\n /**\n * Returns if a service or parameter with the informed key is already defined in the container.\n * @param {string} key - The key of the parameter or service to be checked.\n * @return {boolean} If the key exists in the container or not\n */\n has(key) {\n return this._items.hasOwnProperty(key);\n }\n\n /**\n * Defines a service as a factory, so the instances are not cached in the service and that function is always called\n * @param {function(Jimple):*} fn - The function that constructs the service that is a factory\n * @return {function(Jimple):*} The same function passed as parameter\n */\n factory(fn) {\n return addFunctionTo(this._factories, fn);\n }\n\n /**\n * Defines a function as a parameter, so that function is not considered a service\n * @param {*} fn - The function to not be considered a service\n * @return {*} The same function passed as parameter\n */\n protect(fn) {\n return addFunctionTo(this._protected, fn);\n }\n\n /**\n * Return all the keys registered in the container\n * @returns {Array<string>}\n */\n keys() {\n return Object.keys(this._items);\n }\n\n /**\n * Extends a service already registered in the container\n * @param {string} key - The key of the service to be extended\n * @param {function(*, Jimple):*} fn - The function that will be used to extend the service\n * @throws If the key is not already defined\n * @throws If the key saved in the container does not correspond to a service\n * @throws If the function passed it not...well, a function\n */\n extend(key, fn) {\n checkDefined(this, key);\n let originalItem = this._items[key];\n assert(isFunction(originalItem) && this._protected.has(originalItem) === false, `Identifier '${key}' does not contain a service definition`);\n assert(isFunction(fn), `The 'new' service definition for '${key}' is not a invokable object.`);\n this._items[key] = function(app) {\n return fn(originalItem(app), app);\n }\n if (this._factories.has(originalItem)) {\n this._factories.delete(originalItem);\n this._factories.add(this._items[key]);\n }\n }\n\n /**\n * Uses an provider to extend the service, so it's easy to split the service and parameter definitions across the system\n * @param {{register: function(Jimple)}} provider - The provider to be used to register services and parameters in this container\n */\n register(provider) {\n provider.register(this);\n }\n\n /**\n * Returns the raw value of a service or parameter. So, in the case of a service, for example, the value returned is the\n * function used to construct the service.\n * @param {string} key - The key of the service or parameter to return.\n * @throws If the key does not exist in the container\n * @return {*} The raw value of the service or parameter\n */\n raw(key) {\n checkDefined(this, key);\n return this._items[key];\n }\n}\n\nmodule.exports = Jimple;\n","// @ts-expect-error - the idea is to have `any` and assert on export.\nimport JimpleOriginal from 'jimple';\nimport { Container as JimpleContainer } from './jimple.type.js';\n\nconst Jimple = JimpleOriginal as typeof JimpleContainer;\n\nexport { Jimple };\nexport type { JimpleContainer };\n","import { Jimple as JimpleMod } from '../jimplemod/index.js';\n\nexport class Jimple extends JimpleMod {\n /**\n * This is a version of the `get` method that doesn't throw if the key doesn't exist. It\n * will return `undefined` instead.\n *\n * @template T The type of the returned object.\n * @param key The key of the parameter or service to return.\n * @returns The object related to the service or the value of the parameter associated\n * with the given key.\n */\n try<T = unknown>(key: string): T | undefined {\n if (!this.has(key)) {\n return undefined;\n }\n\n return this.get<T>(key);\n }\n}\n/**\n * Shorthand for `new Jimple()`.\n *\n * @param args The same parameters as the {@link Jimple} constructor.\n * @returns A new instance of {@link Jimple}.\n */\nexport const jimple = (...args: ConstructorParameters<typeof Jimple>): Jimple =>\n new Jimple(...args);\n","import type { GenericFn, Resource } from './factories.types.js';\n/**\n * Generates a function to create resources of an specified type. This function itself\n * doesn't have logic, but it's just in charge of creating the constraint for the resource\n * function.\n *\n * As all the other _\"factory functions\"_, this is meant to be used as a building block\n * when extending the container.\n *\n * @example\n * type ActionFn = (c: Jimple) => void;\n * const factory = resourceFactory<ActionFn>();\n * const myAction = factory('action', 'fn', (c) => {\n * c.set('foo', 'bar');\n * });\n *\n * @template ResourceFn The type of function the resource needs to have.\n * @returns A function that can be used to create a resource with a specified type of\n * function.\n */\nexport const resourceFactory =\n <ResourceFn extends GenericFn>() =>\n /**\n * Generates a new resource using the contraint defined in the factory.\n *\n * @example\n * const myAction = factory('action', 'fn', (c) => {\n * c.set('foo', 'bar');\n * });\n *\n * @template Name The literal type of `name`, to be used in the return object.\n * @template Key The literal type of `key`, to be used in the return object.\n * @template Fn The type of `fn`, restricted by the factory constraint.\n * @param name The name of the resource.\n * @param key The property key for the function.\n * @param fn The resource function.\n * @returns An object with the `name` set to `true`, and the `fn` as the `key`.\n */\n <Name extends string, Key extends string, Fn extends ResourceFn>(\n name: Name,\n key: Key,\n fn: Fn,\n ): Resource<Name, Key, Fn> =>\n ({\n [name]: true,\n [key]: fn,\n }) as Resource<Name, Key, Fn>;\n","import type {\n GenericFn,\n GenericCurriedFn,\n ResourceCreator,\n ResourceCreatorCurriedFn,\n ResourceCreatorHandler,\n} from './factories.types.js';\nimport { resourceFactory } from './resourceFactory.js';\n/**\n * Generates a function to create resource creators of an specified type. This function\n * itself doesn't have logic, but it's just in charge of creating the constraint for the\n * resource creator function.\n *\n * As all the other _\"factory functions\"_, this is meant to be used as a building block\n * when extending the container.\n *\n * @example\n * type ActionFn = (c: Jimple) => void;\n * const factory = resourceCreatorFactory<ActionFn>();\n * const myAction = factory('action', 'fn', (name = 'foo') => (c) => {\n * c.set(name, 'bar');\n * });\n *\n * @template ResourceFn The type of function the resource creator needs to have.\n * @returns A function that can be used to create \"resource creators\".\n */\nexport const resourceCreatorFactory =\n <ResourceFn extends GenericFn>() =>\n /**\n * Generates a new resource creator using the contraint defined in the factory.\n *\n * @example\n * const myAction = factory('action', 'fn', (name = 'foo') => (c) => {\n * c.set(name, 'bar');\n * });\n *\n * @template Name The literal type of `name`, to be used in the return object.\n * @template Key The literal type of `key`, to be used in the return object.\n * @template ResFn The type of the resource function, the creator function needs to\n * return. This is restricted by the factory constraint.\n * @template CreatorFn The literal type of `creatorFn`, to be used in the return object.\n * @param name The name of the resource.\n * @param key The property key for the function.\n * @param creatorFn The curried function that returns the actual resource function.\n * @returns A resource creator: an object that can be used as a resource, and as a\n * function that returns a resource.\n */\n <\n Name extends string,\n Key extends string,\n ResFn extends ResourceFn,\n CreatorFn extends GenericCurriedFn<ResFn>,\n >(\n name: Name,\n key: Key,\n creatorFn: CreatorFn,\n ): ResourceCreator<Name, Key, CreatorFn, ResourceFn> => {\n const fnToProxy: ResourceCreatorCurriedFn<Name, Key, CreatorFn> = (...args) => {\n const actualResource = creatorFn(...args) as ReturnType<CreatorFn>;\n return resourceFactory<ResFn>()(name, key, actualResource);\n };\n\n const handler: ResourceCreatorHandler<Name, Key, CreatorFn> = {\n name,\n resource: null,\n get(target, property) {\n let result;\n if (property === this.name) {\n result = true;\n } else if (property === key) {\n if (this.resource === null) {\n const newResource = creatorFn() as ReturnType<CreatorFn>;\n this.resource = newResource;\n }\n result = this.resource;\n } else {\n const targetKey = property as keyof typeof target;\n result = target[targetKey];\n }\n\n return result;\n },\n has(target, property) {\n if (property === this.name || property === key) {\n return true;\n }\n\n const targetKey = property as keyof typeof target;\n return targetKey in target;\n },\n };\n\n return new Proxy(fnToProxy, handler) as unknown as ResourceCreator<\n Name,\n Key,\n CreatorFn,\n ResourceFn\n >;\n };\n","import type { GenericFn, Resource } from './factories.types.js';\nimport { resourceFactory } from './resourceFactory.js';\n/**\n * Generates a function to configure a collection of resources of an specified type. This\n * function itself doesn't have logic, but it's just in charge of creating the constraint\n * for the resource name and function.\n *\n * As all the other _\"factory functions\"_, this is meant to be used as a building block\n * when extending the container.\n *\n * @example\n * type ActionFn = (c: Jimple) => void;\n * const factory = resourcesCollectionFactory<'action', ActionFn>();\n * const myActions = factory('action', 'fn')({ myActionA, myActionB });\n *\n * @template ResourceName The literal type of the name the resources needs to have.\n * @template ResourceFn The type of function the resources needs to have.\n * @returns A function that can be used to configure a collection of resources.\n */\nexport const resourcesCollectionFactory =\n <ResourceName extends string, ResourceFn extends GenericFn>() =>\n /**\n * Generates a function to create a collection of resources of an specified type. A\n * collection is a dictionary of resources, and a resource itself, and when its\n * \"resource function\" gets called, it calls the function of every resource (with the\n * same args it recevied).\n *\n * @example\n * const myActions = factory('action', 'fn')({ myActionA, myActionB });\n *\n * @template Name The literal type of `name`, to be used in the return object.\n * @template Key The literal type of `key`, to be used in the return object.\n * @template ItemKey To capture the name of the resources in the collection.\n * @template Items The kind of dictionary of resources the return function will expect.\n * @template CustomFn The type of `fn`, restricted by the factory constraint.\n * @param name The resource name the items in the collection must have.\n * @param key The key property the items in the collection must have.\n * @param fn A custom function to process the items in the collection, when the\n * collection function gets called.\n * @returns A function that can be used to create a resources collection.\n */\n <\n Name extends string,\n Key extends string,\n ItemKey extends string,\n Items extends Record<ItemKey, Resource<ResourceName, Key, ResourceFn>>,\n CustomFn extends (items: Items, ...rest: Parameters<ResourceFn>) => void,\n >(\n name: Name,\n key: Key,\n fn?: CustomFn,\n ) => {\n const collectionResourceFactory = resourceFactory<ResourceFn>();\n /**\n * The actual function that recevies the items and creates the collection.\n *\n * @template ItemsParam The literal type of `items`, to be used in the return object.\n * @param items A dictionary of resources for the collection.\n * @returns A dictionary of the resources, that it's also a resource.\n * @throws If the dictionary contains the resource name or function key as keys.\n * @throws If one of the items doesn't have the resource function.\n */\n return <ItemsParam>(\n items: ItemsParam & Items,\n ): typeof items & Resource<Name, Key, ResourceFn> => {\n const invalidKeys: string[] = [name, key];\n const itemsKeys = Object.keys(items) as Array<keyof Items>;\n\n const invalidKey = itemsKeys.some((itemKey) =>\n invalidKeys.includes(String(itemKey)),\n );\n if (invalidKey) {\n throw new Error(\n `No item on the collection can have the keys \\`${name}\\` nor \\`${key}\\``,\n );\n }\n\n const invalidItem = itemsKeys.find(\n (itemKey) => typeof items[itemKey]?.[key] !== 'function',\n );\n if (invalidItem) {\n throw new Error(\n `The item \\`${String(\n invalidItem,\n )}\\` is invalid: it doesn't have a \\`${key}\\` function`,\n );\n }\n\n const useFn = fn\n ? (...args: Parameters<ResourceFn>) => fn(items, ...args)\n : (...args: Parameters<ResourceFn>) => {\n itemsKeys.forEach((itemK) => {\n const item = items[itemK]!;\n const itemFn = item[key];\n itemFn(...args);\n });\n };\n\n return {\n ...collectionResourceFactory(name, key, useFn as ResourceFn),\n ...items,\n };\n };\n };\n","import type { Jimple } from '../jimple/index.js';\n\n// oxlint-disable-next-line typescript/no-explicit-any -- Dictionary keys and values are dynamically extended.\ntype GenericDict = Record<any, any>;\n/**\n * A helper that reusable services can use to resolve dependencies in constructors and/or\n * providers.\n *\n * @template InjectDictionary A dictionary of the dependencies and their types.\n * @template InjectKey The literal type of the dictionary types.\n */\nexport class InjectHelper<\n InjectDictionary extends GenericDict,\n InjectKey = keyof InjectDictionary,\n> {\n /**\n * This method is meant to be used to validate the dependencies a service receives, and\n * needs. It will check on the received dependencies, if a specific dependency exists,\n * it will return it, otherwise, it will create a new instance.\n *\n * @example\n * type Dependencies = {\n * dep: string;\n * };\n * const helper = new InjectHelper<Dependencies>();\n *\n * type MyServiceOptions = {\n * inject?: Partial<Dependencies>;\n * };\n * const myService = ({ inject = {} }: MyServiceOptions) => {\n * const dep = helper.get(inject, 'dep', () => 'default');\n * console.log('dep:', dep);\n * };\n *\n * @template DepKey The literal key of the dependency to validate.\n * @template DepType The type of the dependency, obtained from the dictionary sent to\n * the constructor.\n * @param dependencies The dependencies received by the implementation.\n * @param key The key of the dependency to validate.\n * @param init A function to create a dependency in case it doesn't exist in the\n * dictionary.\n * @returns An instance of the dependency.\n */\n get<DepKey extends InjectKey, DepType = InjectDictionary[DepKey]>(\n dependencies: Partial<InjectDictionary>,\n key: InjectKey,\n init: () => DepType,\n ): DepType {\n const existing = dependencies[key];\n if (typeof existing !== 'undefined') {\n return existing!;\n }\n\n return init();\n }\n /**\n * This is meant to be used in a provider creator to resolve dependencies' names sent as\n * options. For each dependency, the method will first check if a new name was\n * specified, and try to get it with that name, otherwise, it will try to get it with\n * the default name, and if it doesn't exist, it will just keep it as `undefined` and\n * expect the service implements {@link InjectHelper.get} to ensure the dependency.\n *\n * @example\n * type Dependencies = {\n * dep: string;\n * };\n * const helper = new InjectHelper<Dependencies>();\n *\n * type MyProviderOptions = {\n * services?: {\n * [key in keyof Dependencies]?: string;\n * };\n * };\n *\n * const myProvider = providerCreator(\n * ({ services = {} }: MyProviderOptions) =>\n * (container) => {\n * container.set('myService', () => {\n * const inject = helper.resolve(['dep'], container, services);\n * return myService({ inject });\n * });\n * },\n * );\n *\n * @template DepKey The literal key of the dependencies to validate.\n * @template Container The type of the Jimple container.\n * @param dependencies The dependencies needed by the service.\n * @param container A reference to the Jimple container.\n * @param inject A dictionary of dependencies names.\n * @returns A dictionary of dependencies to send to the service.\n */\n resolve<DepKey extends InjectKey, Container extends Jimple>(\n dependencies: DepKey[],\n container: Container,\n inject: Partial<Record<keyof InjectDictionary, string>>,\n ): Partial<InjectDictionary> {\n const result = dependencies.reduce<Partial<InjectDictionary>>((acc, key) => {\n if (inject[key]) {\n acc[key] = container.get<InjectDictionary[typeof key]>(inject[key]!);\n return acc;\n }\n\n const keyStr = key as unknown as string;\n if (container.has(keyStr)) {\n acc[key] = container.get<InjectDictionary[typeof key]>(keyStr);\n return acc;\n }\n\n return acc;\n }, {});\n\n return result;\n }\n}\n/**\n * Shorthand for `new InjectHelper()`.\n *\n * @returns A new instance of {@link InjectHelper}.\n */\nexport const injectHelper = <InjectDictionary extends GenericDict>() =>\n new InjectHelper<InjectDictionary>();\n","import { resourceFactory } from '../factories/index.js';\nimport type { Jimple } from '../jimple/index.js';\n\nexport type ProviderName = 'provider';\nexport type ProviderKey = 'register';\n/**\n * The function the container will call when the provider is registered.\n *\n * @template ContainerType The type of the Jimple container (in case it gets subclassed).\n * @param container A reference for container where the provider is being registered.\n */\nexport type ProviderRegisterFn<ContainerType extends Jimple = Jimple> = (\n container: ContainerType,\n) => void;\n/**\n * Generates a function to create providers for a specific type of container.\n *\n * @template ContainerType The type of the Jimple container (in case it gets subclassed).\n * @returns A function to create providers.\n */\nexport const createProvider = <ContainerType extends Jimple = Jimple>() => {\n type RegisterFn = ProviderRegisterFn<ContainerType>;\n const factory = resourceFactory<RegisterFn>();\n return (register: RegisterFn) => factory('provider', 'register', register);\n};\n/**\n * Creates a resource to be registered in a Jimple container.\n *\n * @example\n * export const myService = provider((c) => {\n * c.set('myService', () => new MyService());\n * });\n */\nexport const provider = createProvider();\n/** A resource that can be registered in a Jimple container. */\nexport type Provider = ReturnType<typeof provider>;\n","import { resourceCreatorFactory, type GenericCurriedFn } from '../factories/index.js';\nimport type { Jimple } from '../jimple/index.js';\nimport type { ProviderRegisterFn } from './provider.js';\n/**\n * Generates a function to create \"provider creators\" for a specific type of container.\n *\n * @template ContainerType The type of the Jimple container (in case it gets subclassed).\n * @returns A function to generate provider creators.\n */\nexport const createProviderCreator = <ContainerType extends Jimple = Jimple>() => {\n type RegisterFn = ProviderRegisterFn<ContainerType>;\n type ProviderCreatorFunction = GenericCurriedFn<RegisterFn>;\n const factory = resourceCreatorFactory<RegisterFn>();\n return <CreatorFn extends ProviderCreatorFunction>(creator: CreatorFn) =>\n factory('provider', 'register', creator);\n};\n/**\n * Generates a \"provider creator\": a provider that can also be called as a function in\n * order to create a configured provider.\n *\n * @example\n * export const myService = providerCreator((options: Opts = {}) => (c) => {\n * c.set('myService', () => new MyService(options));\n * });\n */\nexport const providerCreator = createProviderCreator();\n/** A function that returns a provider registration function. */\nexport type ProviderCreatorFn = Parameters<typeof providerCreator>[0];\n","import { resourcesCollectionFactory } from '../factories/index.js';\nimport type { Jimple } from '../jimple/index.js';\nimport type { ProviderRegisterFn, ProviderName } from './provider.js';\n/**\n * Generates a function to create a providers collection for a specific type of container.\n *\n * @template ContainerType The type of the Jimple container (in case it gets subclassed).\n * @returns A function to create providers collections.\n */\nexport const createProviders = <ContainerType extends Jimple = Jimple>() => {\n type RegisterFn = ProviderRegisterFn<ContainerType>;\n const factory = resourcesCollectionFactory<ProviderName, RegisterFn>();\n return factory('provider', 'register');\n};\n/**\n * Generates a collection of providers. A collection is a dictionary of providers that can\n * also be used as a provider, and when it gets registered, it will register all of the\n * providers in the collection.\n *\n * @example <caption>Assuming we already have two service providers...</caption>\n * export const services = providers({\n * myServiceProvider,\n * myOtherServiceProvider,\n * });\n *\n * @param items A dictionary of providers.\n */\nexport const providers = createProviders();\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["Jimple","JimpleOriginal","targetKey","assert","ok","message","isFunction","fn","isPlainObject","value","prototype","checkDefined","container","key","addFunctionTo","set","Jimple$1","mappedValues","values","item","obj","originalItem","app","provider","Jimple","jimple","args","resourceFactory","name","resourceCreatorFactory","actualResource","creatorFn","result","property","newResource","target","resourcesCollectionFactory","collectionResourceFactory","invalidKeys","itemsKeys","items","itemKey","invalidItem","itemFn","itemK","InjectHelper","existing","dependencies","init","inject","acc","keyStr","injectHelper","createProvider","factory","register","createProviderCreator","creator","providerCreator","createProviders","providers"],"sources":["../src/original/helpers.ts","../src/original/jimple.ts","../src/jimple/index.ts","../src/factories/resourceFactory.ts","../src/factories/resourceCreatorFactory.ts","../src/factories/resourcesCollectionFactory.ts","../src/helpers/injectHelper.ts","../src/helpers/provider.ts","../src/helpers/providerCreator.ts","../src/helpers/providers.ts"],"sourcesContent":["/* oxlint-disable typescript/no-unsafe-function-type */\nexport function assert(ok: unknown, message: string): asserts ok {\n if (!ok) {\n throw new Error(message);\n }\n}\n\nexport const isFunction = (fn: unknown): fn is Function =>\n Object.prototype.toString.call(fn) === '[object Function]' &&\n (fn as object).constructor.name === 'Function';\n\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (Object.prototype.toString.call(value) !== '[object Object]') {\n return false;\n }\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || prototype === Object.prototype;\n};\n\ntype ContainerLike = {\n has: (key: string) => boolean;\n};\n\nexport const checkDefined = (container: ContainerLike, key: string): void => {\n assert(container.has(key), `Identifier \"${key}\" is not defined.`);\n};\n\nexport const addFunctionTo = <T extends Function>(set: Set<Function>, fn: T): T => {\n assert(isFunction(fn), 'Service definition is not a Closure or invokable object');\n set.add(fn);\n return fn;\n};\n","/* oxlint-disable typescript/no-unsafe-function-type */\nimport {\n assert,\n isFunction,\n isPlainObject,\n checkDefined,\n addFunctionTo,\n} from './helpers.js';\n\n/**\n * The Jimple Container class\n *\n * @public\n */\nexport class Jimple {\n static provider<T extends (register: Jimple) => void>(\n register: T,\n ): {\n register: T;\n } {\n return { register };\n }\n\n _items: Record<string, unknown> = {};\n _instances: Map<unknown, unknown> = new Map();\n _factories: Set<Function> = new Set();\n _protected: Set<Function> = new Set();\n /**\n * Create a Jimple Container.\n *\n * @param values An optional object whose keys and values will be associated in the\n * container at initialization.\n */\n constructor(values?: Record<string, unknown>) {\n const mappedValues = isPlainObject(values) ? values : {};\n Object.entries(mappedValues).forEach(([key, value]) => {\n this.set(key, value);\n }, this);\n }\n /**\n * Return the specified parameter or service. If the service is not built yet, this\n * function will construct the service injecting all the dependencies needed in it's\n * definition so the returned object is totally usable on the fly.\n *\n * @param key The key of the parameter or service to return\n * @returns The object related to the service or the value of the parameter associated\n * with the key informed\n * @throws If the key does not exist\n */\n get<T = unknown>(key: string): T {\n checkDefined(this, key);\n const item = this._items[key];\n let obj: unknown;\n if (isFunction(item)) {\n if (this._protected.has(item)) {\n obj = item;\n } else if (this._instances.has(item)) {\n obj = this._instances.get(item);\n } else {\n obj = item(this);\n if (!this._factories.has(item)) {\n this._instances.set(item, obj);\n }\n }\n } else {\n obj = item;\n }\n return obj as T;\n }\n /**\n * Defines a new parameter or service.\n *\n * @param key The key of the parameter or service to be defined\n * @param value The value of the parameter or a function that receives the container as\n * parameter and constructs the service\n */\n set(key: string, value: unknown): void {\n this._items[key] = value;\n }\n\n /**\n * Returns if a service or parameter with the informed key is already defined in the\n * container.\n *\n * @param key The key of the parameter or service to be checked.\n * @returns If the key exists in the container or not\n */\n has(key: string): boolean {\n return Object.hasOwn(this._items, key);\n }\n\n /**\n * Defines a service as a factory, so the instances are not cached in the service and\n * that function is always called\n *\n * @param fn The function that constructs the service that is a factory\n * @returns The same function passed as parameter\n */\n factory<C = this>(fn: (app: C) => unknown): (arg0: C) => unknown {\n return addFunctionTo(this._factories, fn);\n }\n\n /**\n * Defines a function as a parameter, so that function is not considered a service\n *\n * @param fn The function to not be considered a service\n * @returns The same function passed as parameter\n */\n protect<T extends () => unknown>(fn: T): T {\n return addFunctionTo(this._protected, fn);\n }\n\n /** Return all the keys registered in the container */\n keys(): string[] {\n return Object.keys(this._items);\n }\n\n /**\n * Extends a service already registered in the container\n *\n * @param key The key of the service to be extended\n * @param fn The function that will be used to extend the service\n * @throws If the key is not already defined\n * @throws If the key saved in the container does not correspond to a service\n * @throws If the function passed it not...well, a function\n */\n extend<C = this>(key: string, fn: (original: unknown, app: C) => unknown): void {\n checkDefined(this, key);\n const originalItem = this._items[key];\n assert(\n isFunction(originalItem) && this._protected.has(originalItem) === false,\n `Identifier '${key}' does not contain a service definition`,\n );\n assert(\n isFunction(fn),\n `The 'new' service definition for '${key}' is not a invokable object.`,\n );\n this._items[key] = (app: C): unknown => fn(originalItem(app), app);\n\n if (this._factories.has(originalItem)) {\n this._factories.delete(originalItem);\n this._factories.add(this._items[key] as Function);\n }\n }\n\n /**\n * Uses an provider to extend the service, so it's easy to split the service and\n * parameter definitions across the system\n *\n * @param provider The provider to be used to register services and parameters in this\n * container\n */\n register<C = this>(provider: { register: (arg0: C) => void }): void {\n provider.register(this as unknown as C);\n }\n\n /**\n * Returns the raw value of a service or parameter. So, in the case of a service, for\n * example, the value returned is the function used to construct the service.\n *\n * @param key - The key of the service or parameter to return.\n * @returns The raw value of the service or parameter\n * @throws If the key does not exist in the container\n */\n raw<T = unknown>(key: string): T {\n checkDefined(this, key);\n return this._items[key] as T;\n }\n}\n","import { Jimple as JimpleOriginal } from '../original/index.js';\n\nexport class Jimple extends JimpleOriginal {\n /**\n * This is a version of the `get` method that doesn't throw if the key doesn't exist. It\n * will return `undefined` instead.\n *\n * @template T The type of the returned object.\n * @param key The key of the parameter or service to return.\n * @returns The object related to the service or the value of the parameter associated\n * with the given key.\n */\n try<T = unknown>(key: string): T | undefined {\n if (!this.has(key)) {\n return undefined;\n }\n\n return this.get<T>(key);\n }\n}\n/**\n * Shorthand for `new Jimple()`.\n *\n * @param args The same parameters as the {@link Jimple} constructor.\n * @returns A new instance of {@link Jimple}.\n */\nexport const jimple = (...args: ConstructorParameters<typeof Jimple>): Jimple =>\n new Jimple(...args);\n","import type { GenericFn, Resource } from './factories.types.js';\n/**\n * Generates a function to create resources of an specified type. This function itself\n * doesn't have logic, but it's just in charge of creating the constraint for the resource\n * function.\n *\n * As all the other _\"factory functions\"_, this is meant to be used as a building block\n * when extending the container.\n *\n * @example\n * type ActionFn = (c: Jimple) => void;\n * const factory = resourceFactory<ActionFn>();\n * const myAction = factory('action', 'fn', (c) => {\n * c.set('foo', 'bar');\n * });\n *\n * @template ResourceFn The type of function the resource needs to have.\n * @returns A function that can be used to create a resource with a specified type of\n * function.\n */\nexport const resourceFactory =\n <ResourceFn extends GenericFn>() =>\n /**\n * Generates a new resource using the contraint defined in the factory.\n *\n * @example\n * const myAction = factory('action', 'fn', (c) => {\n * c.set('foo', 'bar');\n * });\n *\n * @template Name The literal type of `name`, to be used in the return object.\n * @template Key The literal type of `key`, to be used in the return object.\n * @template Fn The type of `fn`, restricted by the factory constraint.\n * @param name The name of the resource.\n * @param key The property key for the function.\n * @param fn The resource function.\n * @returns An object with the `name` set to `true`, and the `fn` as the `key`.\n */\n <Name extends string, Key extends string, Fn extends ResourceFn>(\n name: Name,\n key: Key,\n fn: Fn,\n ): Resource<Name, Key, Fn> =>\n ({\n [name]: true,\n [key]: fn,\n }) as Resource<Name, Key, Fn>;\n","import type {\n GenericFn,\n GenericCurriedFn,\n ResourceCreator,\n ResourceCreatorCurriedFn,\n ResourceCreatorHandler,\n} from './factories.types.js';\nimport { resourceFactory } from './resourceFactory.js';\n/**\n * Generates a function to create resource creators of an specified type. This function\n * itself doesn't have logic, but it's just in charge of creating the constraint for the\n * resource creator function.\n *\n * As all the other _\"factory functions\"_, this is meant to be used as a building block\n * when extending the container.\n *\n * @example\n * type ActionFn = (c: Jimple) => void;\n * const factory = resourceCreatorFactory<ActionFn>();\n * const myAction = factory('action', 'fn', (name = 'foo') => (c) => {\n * c.set(name, 'bar');\n * });\n *\n * @template ResourceFn The type of function the resource creator needs to have.\n * @returns A function that can be used to create \"resource creators\".\n */\nexport const resourceCreatorFactory =\n <ResourceFn extends GenericFn>() =>\n /**\n * Generates a new resource creator using the contraint defined in the factory.\n *\n * @example\n * const myAction = factory('action', 'fn', (name = 'foo') => (c) => {\n * c.set(name, 'bar');\n * });\n *\n * @template Name The literal type of `name`, to be used in the return object.\n * @template Key The literal type of `key`, to be used in the return object.\n * @template ResFn The type of the resource function, the creator function needs to\n * return. This is restricted by the factory constraint.\n * @template CreatorFn The literal type of `creatorFn`, to be used in the return object.\n * @param name The name of the resource.\n * @param key The property key for the function.\n * @param creatorFn The curried function that returns the actual resource function.\n * @returns A resource creator: an object that can be used as a resource, and as a\n * function that returns a resource.\n */\n <\n Name extends string,\n Key extends string,\n ResFn extends ResourceFn,\n CreatorFn extends GenericCurriedFn<ResFn>,\n >(\n name: Name,\n key: Key,\n creatorFn: CreatorFn,\n ): ResourceCreator<Name, Key, CreatorFn, ResourceFn> => {\n const fnToProxy: ResourceCreatorCurriedFn<Name, Key, CreatorFn> = (...args) => {\n const actualResource = creatorFn(...args) as ReturnType<CreatorFn>;\n return resourceFactory<ResFn>()(name, key, actualResource);\n };\n\n const handler: ResourceCreatorHandler<Name, Key, CreatorFn> = {\n name,\n resource: null,\n get(target, property) {\n let result;\n if (property === this.name) {\n result = true;\n } else if (property === key) {\n if (this.resource === null) {\n const newResource = creatorFn() as ReturnType<CreatorFn>;\n this.resource = newResource;\n }\n result = this.resource;\n } else {\n const targetKey = property as keyof typeof target;\n result = target[targetKey];\n }\n\n return result;\n },\n has(target, property) {\n if (property === this.name || property === key) {\n return true;\n }\n\n const targetKey = property as keyof typeof target;\n return targetKey in target;\n },\n };\n\n return new Proxy(fnToProxy, handler) as unknown as ResourceCreator<\n Name,\n Key,\n CreatorFn,\n ResourceFn\n >;\n };\n","import type { GenericFn, Resource } from './factories.types.js';\nimport { resourceFactory } from './resourceFactory.js';\n/**\n * Generates a function to configure a collection of resources of an specified type. This\n * function itself doesn't have logic, but it's just in charge of creating the constraint\n * for the resource name and function.\n *\n * As all the other _\"factory functions\"_, this is meant to be used as a building block\n * when extending the container.\n *\n * @example\n * type ActionFn = (c: Jimple) => void;\n * const factory = resourcesCollectionFactory<'action', ActionFn>();\n * const myActions = factory('action', 'fn')({ myActionA, myActionB });\n *\n * @template ResourceName The literal type of the name the resources needs to have.\n * @template ResourceFn The type of function the resources needs to have.\n * @returns A function that can be used to configure a collection of resources.\n */\nexport const resourcesCollectionFactory =\n <ResourceName extends string, ResourceFn extends GenericFn>() =>\n /**\n * Generates a function to create a collection of resources of an specified type. A\n * collection is a dictionary of resources, and a resource itself, and when its\n * \"resource function\" gets called, it calls the function of every resource (with the\n * same args it recevied).\n *\n * @example\n * const myActions = factory('action', 'fn')({ myActionA, myActionB });\n *\n * @template Name The literal type of `name`, to be used in the return object.\n * @template Key The literal type of `key`, to be used in the return object.\n * @template ItemKey To capture the name of the resources in the collection.\n * @template Items The kind of dictionary of resources the return function will expect.\n * @template CustomFn The type of `fn`, restricted by the factory constraint.\n * @param name The resource name the items in the collection must have.\n * @param key The key property the items in the collection must have.\n * @param fn A custom function to process the items in the collection, when the\n * collection function gets called.\n * @returns A function that can be used to create a resources collection.\n */\n <\n Name extends string,\n Key extends string,\n ItemKey extends string,\n Items extends Record<ItemKey, Resource<ResourceName, Key, ResourceFn>>,\n CustomFn extends (items: Items, ...rest: Parameters<ResourceFn>) => void,\n >(\n name: Name,\n key: Key,\n fn?: CustomFn,\n ) => {\n const collectionResourceFactory = resourceFactory<ResourceFn>();\n /**\n * The actual function that recevies the items and creates the collection.\n *\n * @template ItemsParam The literal type of `items`, to be used in the return object.\n * @param items A dictionary of resources for the collection.\n * @returns A dictionary of the resources, that it's also a resource.\n * @throws If the dictionary contains the resource name or function key as keys.\n * @throws If one of the items doesn't have the resource function.\n */\n return <ItemsParam>(\n items: ItemsParam & Items,\n ): typeof items & Resource<Name, Key, ResourceFn> => {\n const invalidKeys: string[] = [name, key];\n const itemsKeys = Object.keys(items) as Array<keyof Items>;\n\n const invalidKey = itemsKeys.some((itemKey) =>\n invalidKeys.includes(String(itemKey)),\n );\n if (invalidKey) {\n throw new Error(\n `No item on the collection can have the keys \\`${name}\\` nor \\`${key}\\``,\n );\n }\n\n const invalidItem = itemsKeys.find(\n (itemKey) => typeof items[itemKey]?.[key] !== 'function',\n );\n if (invalidItem) {\n throw new Error(\n `The item \\`${String(\n invalidItem,\n )}\\` is invalid: it doesn't have a \\`${key}\\` function`,\n );\n }\n\n const useFn = fn\n ? (...args: Parameters<ResourceFn>) => fn(items, ...args)\n : (...args: Parameters<ResourceFn>) => {\n itemsKeys.forEach((itemK) => {\n const item = items[itemK]!;\n const itemFn = item[key];\n itemFn(...args);\n });\n };\n\n return {\n ...collectionResourceFactory(name, key, useFn as ResourceFn),\n ...items,\n };\n };\n };\n","import type { Jimple } from '../jimple/index.js';\n\n// oxlint-disable-next-line typescript/no-explicit-any -- Dictionary keys and values are dynamically extended.\ntype GenericDict = Record<any, any>;\n/**\n * A helper that reusable services can use to resolve dependencies in constructors and/or\n * providers.\n *\n * @template InjectDictionary A dictionary of the dependencies and their types.\n * @template InjectKey The literal type of the dictionary types.\n */\nexport class InjectHelper<\n InjectDictionary extends GenericDict,\n InjectKey = keyof InjectDictionary,\n> {\n /**\n * This method is meant to be used to validate the dependencies a service receives, and\n * needs. It will check on the received dependencies, if a specific dependency exists,\n * it will return it, otherwise, it will create a new instance.\n *\n * @example\n * type Dependencies = {\n * dep: string;\n * };\n * const helper = new InjectHelper<Dependencies>();\n *\n * type MyServiceOptions = {\n * inject?: Partial<Dependencies>;\n * };\n * const myService = ({ inject = {} }: MyServiceOptions) => {\n * const dep = helper.get(inject, 'dep', () => 'default');\n * console.log('dep:', dep);\n * };\n *\n * @template DepKey The literal key of the dependency to validate.\n * @template DepType The type of the dependency, obtained from the dictionary sent to\n * the constructor.\n * @param dependencies The dependencies received by the implementation.\n * @param key The key of the dependency to validate.\n * @param init A function to create a dependency in case it doesn't exist in the\n * dictionary.\n * @returns An instance of the dependency.\n */\n get<DepKey extends InjectKey, DepType = InjectDictionary[DepKey]>(\n dependencies: Partial<InjectDictionary>,\n key: InjectKey,\n init: () => DepType,\n ): DepType {\n const existing = dependencies[key];\n if (typeof existing !== 'undefined') {\n return existing!;\n }\n\n return init();\n }\n /**\n * This is meant to be used in a provider creator to resolve dependencies' names sent as\n * options. For each dependency, the method will first check if a new name was\n * specified, and try to get it with that name, otherwise, it will try to get it with\n * the default name, and if it doesn't exist, it will just keep it as `undefined` and\n * expect the service implements {@link InjectHelper.get} to ensure the dependency.\n *\n * @example\n * type Dependencies = {\n * dep: string;\n * };\n * const helper = new InjectHelper<Dependencies>();\n *\n * type MyProviderOptions = {\n * services?: {\n * [key in keyof Dependencies]?: string;\n * };\n * };\n *\n * const myProvider = providerCreator(\n * ({ services = {} }: MyProviderOptions) =>\n * (container) => {\n * container.set('myService', () => {\n * const inject = helper.resolve(['dep'], container, services);\n * return myService({ inject });\n * });\n * },\n * );\n *\n * @template DepKey The literal key of the dependencies to validate.\n * @template Container The type of the Jimple container.\n * @param dependencies The dependencies needed by the service.\n * @param container A reference to the Jimple container.\n * @param inject A dictionary of dependencies names.\n * @returns A dictionary of dependencies to send to the service.\n */\n resolve<DepKey extends InjectKey, Container extends Jimple>(\n dependencies: DepKey[],\n container: Container,\n inject: Partial<Record<keyof InjectDictionary, string>>,\n ): Partial<InjectDictionary> {\n const result = dependencies.reduce<Partial<InjectDictionary>>((acc, key) => {\n if (inject[key]) {\n acc[key] = container.get<InjectDictionary[typeof key]>(inject[key]!);\n return acc;\n }\n\n const keyStr = key as unknown as string;\n if (container.has(keyStr)) {\n acc[key] = container.get<InjectDictionary[typeof key]>(keyStr);\n return acc;\n }\n\n return acc;\n }, {});\n\n return result;\n }\n}\n/**\n * Shorthand for `new InjectHelper()`.\n *\n * @returns A new instance of {@link InjectHelper}.\n */\nexport const injectHelper = <InjectDictionary extends GenericDict>() =>\n new InjectHelper<InjectDictionary>();\n","import { resourceFactory } from '../factories/index.js';\nimport type { Jimple } from '../jimple/index.js';\n\nexport type ProviderName = 'provider';\nexport type ProviderKey = 'register';\n/**\n * The function the container will call when the provider is registered.\n *\n * @template ContainerType The type of the Jimple container (in case it gets subclassed).\n * @param container A reference for container where the provider is being registered.\n */\nexport type ProviderRegisterFn<ContainerType extends Jimple = Jimple> = (\n container: ContainerType,\n) => void;\n/**\n * Generates a function to create providers for a specific type of container.\n *\n * @template ContainerType The type of the Jimple container (in case it gets subclassed).\n * @returns A function to create providers.\n */\nexport const createProvider = <ContainerType extends Jimple = Jimple>() => {\n type RegisterFn = ProviderRegisterFn<ContainerType>;\n const factory = resourceFactory<RegisterFn>();\n return (register: RegisterFn) => factory('provider', 'register', register);\n};\n/**\n * Creates a resource to be registered in a Jimple container.\n *\n * @example\n * export const myService = provider((c) => {\n * c.set('myService', () => new MyService());\n * });\n */\nexport const provider = createProvider();\n/** A resource that can be registered in a Jimple container. */\nexport type Provider = ReturnType<typeof provider>;\n","import { resourceCreatorFactory, type GenericCurriedFn } from '../factories/index.js';\nimport type { Jimple } from '../jimple/index.js';\nimport type { ProviderRegisterFn } from './provider.js';\n/**\n * Generates a function to create \"provider creators\" for a specific type of container.\n *\n * @template ContainerType The type of the Jimple container (in case it gets subclassed).\n * @returns A function to generate provider creators.\n */\nexport const createProviderCreator = <ContainerType extends Jimple = Jimple>() => {\n type RegisterFn = ProviderRegisterFn<ContainerType>;\n type ProviderCreatorFunction = GenericCurriedFn<RegisterFn>;\n const factory = resourceCreatorFactory<RegisterFn>();\n return <CreatorFn extends ProviderCreatorFunction>(creator: CreatorFn) =>\n factory('provider', 'register', creator);\n};\n/**\n * Generates a \"provider creator\": a provider that can also be called as a function in\n * order to create a configured provider.\n *\n * @example\n * export const myService = providerCreator((options: Opts = {}) => (c) => {\n * c.set('myService', () => new MyService(options));\n * });\n */\nexport const providerCreator = createProviderCreator();\n/** A function that returns a provider registration function. */\nexport type ProviderCreatorFn = Parameters<typeof providerCreator>[0];\n","import { resourcesCollectionFactory } from '../factories/index.js';\nimport type { Jimple } from '../jimple/index.js';\nimport type { ProviderRegisterFn, ProviderName } from './provider.js';\n/**\n * Generates a function to create a providers collection for a specific type of container.\n *\n * @template ContainerType The type of the Jimple container (in case it gets subclassed).\n * @returns A function to create providers collections.\n */\nexport const createProviders = <ContainerType extends Jimple = Jimple>() => {\n type RegisterFn = ProviderRegisterFn<ContainerType>;\n const factory = resourcesCollectionFactory<ProviderName, RegisterFn>();\n return factory('provider', 'register');\n};\n/**\n * Generates a collection of providers. A collection is a dictionary of providers that can\n * also be used as a provider, and when it gets registered, it will register all of the\n * providers in the collection.\n *\n * @example <caption>Assuming we already have two service providers...</caption>\n * export const services = providers({\n * myServiceProvider,\n * myOtherServiceProvider,\n * });\n *\n * @param items A dictionary of providers.\n */\nexport const providers = createProviders();\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@homer0/jimple",
|
|
3
3
|
"description": "An extended version of the Jimple lib, with extra features",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "7.0.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/homer0/packages.git",
|
|
@@ -35,10 +35,9 @@
|
|
|
35
35
|
"src/"
|
|
36
36
|
],
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@homer0/oxlint-config": "
|
|
39
|
-
"@homer0/tsconfig": "
|
|
38
|
+
"@homer0/oxlint-config": "3.0.0",
|
|
39
|
+
"@homer0/tsconfig": "6.0.0",
|
|
40
40
|
"@vitest/coverage-v8": "catalog:",
|
|
41
|
-
"jimple": "^1.5.0",
|
|
42
41
|
"oxlint": "catalog:",
|
|
43
42
|
"tsdown": "catalog:",
|
|
44
43
|
"typescript": "catalog:",
|
|
@@ -47,7 +46,7 @@
|
|
|
47
46
|
},
|
|
48
47
|
"engine-strict": true,
|
|
49
48
|
"engines": {
|
|
50
|
-
"node": ">=
|
|
49
|
+
"node": ">=24"
|
|
51
50
|
},
|
|
52
51
|
"scripts": {
|
|
53
52
|
"lint": "oxlint .",
|
|
@@ -57,5 +56,5 @@
|
|
|
57
56
|
"build": "tsdown",
|
|
58
57
|
"prepublishOnly": "pnpm run build"
|
|
59
58
|
},
|
|
60
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "cc45fa7b2a70d060ac154c13d4dcaed6ca69334f"
|
|
61
60
|
}
|
package/src/jimple/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Jimple as
|
|
1
|
+
import { Jimple as JimpleOriginal } from '../original/index.js';
|
|
2
2
|
|
|
3
|
-
export class Jimple extends
|
|
3
|
+
export class Jimple extends JimpleOriginal {
|
|
4
4
|
/**
|
|
5
5
|
* This is a version of the `get` method that doesn't throw if the key doesn't exist. It
|
|
6
6
|
* will return `undefined` instead.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* oxlint-disable typescript/no-unsafe-function-type */
|
|
2
|
+
export function assert(ok: unknown, message: string): asserts ok {
|
|
3
|
+
if (!ok) {
|
|
4
|
+
throw new Error(message);
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const isFunction = (fn: unknown): fn is Function =>
|
|
9
|
+
Object.prototype.toString.call(fn) === '[object Function]' &&
|
|
10
|
+
(fn as object).constructor.name === 'Function';
|
|
11
|
+
|
|
12
|
+
export const isPlainObject = (value: unknown): value is Record<string, unknown> => {
|
|
13
|
+
if (Object.prototype.toString.call(value) !== '[object Object]') {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const prototype = Object.getPrototypeOf(value);
|
|
17
|
+
return prototype === null || prototype === Object.prototype;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type ContainerLike = {
|
|
21
|
+
has: (key: string) => boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const checkDefined = (container: ContainerLike, key: string): void => {
|
|
25
|
+
assert(container.has(key), `Identifier "${key}" is not defined.`);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const addFunctionTo = <T extends Function>(set: Set<Function>, fn: T): T => {
|
|
29
|
+
assert(isFunction(fn), 'Service definition is not a Closure or invokable object');
|
|
30
|
+
set.add(fn);
|
|
31
|
+
return fn;
|
|
32
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Jimple } from './jimple.js';
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/* oxlint-disable typescript/no-unsafe-function-type */
|
|
2
|
+
import {
|
|
3
|
+
assert,
|
|
4
|
+
isFunction,
|
|
5
|
+
isPlainObject,
|
|
6
|
+
checkDefined,
|
|
7
|
+
addFunctionTo,
|
|
8
|
+
} from './helpers.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The Jimple Container class
|
|
12
|
+
*
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export class Jimple {
|
|
16
|
+
static provider<T extends (register: Jimple) => void>(
|
|
17
|
+
register: T,
|
|
18
|
+
): {
|
|
19
|
+
register: T;
|
|
20
|
+
} {
|
|
21
|
+
return { register };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_items: Record<string, unknown> = {};
|
|
25
|
+
_instances: Map<unknown, unknown> = new Map();
|
|
26
|
+
_factories: Set<Function> = new Set();
|
|
27
|
+
_protected: Set<Function> = new Set();
|
|
28
|
+
/**
|
|
29
|
+
* Create a Jimple Container.
|
|
30
|
+
*
|
|
31
|
+
* @param values An optional object whose keys and values will be associated in the
|
|
32
|
+
* container at initialization.
|
|
33
|
+
*/
|
|
34
|
+
constructor(values?: Record<string, unknown>) {
|
|
35
|
+
const mappedValues = isPlainObject(values) ? values : {};
|
|
36
|
+
Object.entries(mappedValues).forEach(([key, value]) => {
|
|
37
|
+
this.set(key, value);
|
|
38
|
+
}, this);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Return the specified parameter or service. If the service is not built yet, this
|
|
42
|
+
* function will construct the service injecting all the dependencies needed in it's
|
|
43
|
+
* definition so the returned object is totally usable on the fly.
|
|
44
|
+
*
|
|
45
|
+
* @param key The key of the parameter or service to return
|
|
46
|
+
* @returns The object related to the service or the value of the parameter associated
|
|
47
|
+
* with the key informed
|
|
48
|
+
* @throws If the key does not exist
|
|
49
|
+
*/
|
|
50
|
+
get<T = unknown>(key: string): T {
|
|
51
|
+
checkDefined(this, key);
|
|
52
|
+
const item = this._items[key];
|
|
53
|
+
let obj: unknown;
|
|
54
|
+
if (isFunction(item)) {
|
|
55
|
+
if (this._protected.has(item)) {
|
|
56
|
+
obj = item;
|
|
57
|
+
} else if (this._instances.has(item)) {
|
|
58
|
+
obj = this._instances.get(item);
|
|
59
|
+
} else {
|
|
60
|
+
obj = item(this);
|
|
61
|
+
if (!this._factories.has(item)) {
|
|
62
|
+
this._instances.set(item, obj);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
obj = item;
|
|
67
|
+
}
|
|
68
|
+
return obj as T;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Defines a new parameter or service.
|
|
72
|
+
*
|
|
73
|
+
* @param key The key of the parameter or service to be defined
|
|
74
|
+
* @param value The value of the parameter or a function that receives the container as
|
|
75
|
+
* parameter and constructs the service
|
|
76
|
+
*/
|
|
77
|
+
set(key: string, value: unknown): void {
|
|
78
|
+
this._items[key] = value;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Returns if a service or parameter with the informed key is already defined in the
|
|
83
|
+
* container.
|
|
84
|
+
*
|
|
85
|
+
* @param key The key of the parameter or service to be checked.
|
|
86
|
+
* @returns If the key exists in the container or not
|
|
87
|
+
*/
|
|
88
|
+
has(key: string): boolean {
|
|
89
|
+
return Object.hasOwn(this._items, key);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Defines a service as a factory, so the instances are not cached in the service and
|
|
94
|
+
* that function is always called
|
|
95
|
+
*
|
|
96
|
+
* @param fn The function that constructs the service that is a factory
|
|
97
|
+
* @returns The same function passed as parameter
|
|
98
|
+
*/
|
|
99
|
+
factory<C = this>(fn: (app: C) => unknown): (arg0: C) => unknown {
|
|
100
|
+
return addFunctionTo(this._factories, fn);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Defines a function as a parameter, so that function is not considered a service
|
|
105
|
+
*
|
|
106
|
+
* @param fn The function to not be considered a service
|
|
107
|
+
* @returns The same function passed as parameter
|
|
108
|
+
*/
|
|
109
|
+
protect<T extends () => unknown>(fn: T): T {
|
|
110
|
+
return addFunctionTo(this._protected, fn);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Return all the keys registered in the container */
|
|
114
|
+
keys(): string[] {
|
|
115
|
+
return Object.keys(this._items);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Extends a service already registered in the container
|
|
120
|
+
*
|
|
121
|
+
* @param key The key of the service to be extended
|
|
122
|
+
* @param fn The function that will be used to extend the service
|
|
123
|
+
* @throws If the key is not already defined
|
|
124
|
+
* @throws If the key saved in the container does not correspond to a service
|
|
125
|
+
* @throws If the function passed it not...well, a function
|
|
126
|
+
*/
|
|
127
|
+
extend<C = this>(key: string, fn: (original: unknown, app: C) => unknown): void {
|
|
128
|
+
checkDefined(this, key);
|
|
129
|
+
const originalItem = this._items[key];
|
|
130
|
+
assert(
|
|
131
|
+
isFunction(originalItem) && this._protected.has(originalItem) === false,
|
|
132
|
+
`Identifier '${key}' does not contain a service definition`,
|
|
133
|
+
);
|
|
134
|
+
assert(
|
|
135
|
+
isFunction(fn),
|
|
136
|
+
`The 'new' service definition for '${key}' is not a invokable object.`,
|
|
137
|
+
);
|
|
138
|
+
this._items[key] = (app: C): unknown => fn(originalItem(app), app);
|
|
139
|
+
|
|
140
|
+
if (this._factories.has(originalItem)) {
|
|
141
|
+
this._factories.delete(originalItem);
|
|
142
|
+
this._factories.add(this._items[key] as Function);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Uses an provider to extend the service, so it's easy to split the service and
|
|
148
|
+
* parameter definitions across the system
|
|
149
|
+
*
|
|
150
|
+
* @param provider The provider to be used to register services and parameters in this
|
|
151
|
+
* container
|
|
152
|
+
*/
|
|
153
|
+
register<C = this>(provider: { register: (arg0: C) => void }): void {
|
|
154
|
+
provider.register(this as unknown as C);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Returns the raw value of a service or parameter. So, in the case of a service, for
|
|
159
|
+
* example, the value returned is the function used to construct the service.
|
|
160
|
+
*
|
|
161
|
+
* @param key - The key of the service or parameter to return.
|
|
162
|
+
* @returns The raw value of the service or parameter
|
|
163
|
+
* @throws If the key does not exist in the container
|
|
164
|
+
*/
|
|
165
|
+
raw<T = unknown>(key: string): T {
|
|
166
|
+
checkDefined(this, key);
|
|
167
|
+
return this._items[key] as T;
|
|
168
|
+
}
|
|
169
|
+
}
|
package/src/jimplemod/index.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// @ts-expect-error - the idea is to have `any` and assert on export.
|
|
2
|
-
import JimpleOriginal from 'jimple';
|
|
3
|
-
import { Container as JimpleContainer } from './jimple.type.js';
|
|
4
|
-
|
|
5
|
-
const Jimple = JimpleOriginal as typeof JimpleContainer;
|
|
6
|
-
|
|
7
|
-
export { Jimple };
|
|
8
|
-
export type { JimpleContainer };
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/* oxlint-disable no-unused-vars -- This ambient type workaround only declares API shapes. */
|
|
2
|
-
// @ts-nocheck -- This is just a workaround to get the type.
|
|
3
|
-
export class Container {
|
|
4
|
-
static provider<T extends (arg0: Container) => void>(
|
|
5
|
-
register: T,
|
|
6
|
-
): {
|
|
7
|
-
register: T;
|
|
8
|
-
} {}
|
|
9
|
-
_items: Record<string, unknown>;
|
|
10
|
-
_instances: Map<string, unknown>;
|
|
11
|
-
_factories: Set<unknown>;
|
|
12
|
-
_protected: Set<unknown>;
|
|
13
|
-
/**
|
|
14
|
-
* Creates a Jimple Container.
|
|
15
|
-
*
|
|
16
|
-
* @param values An optional object whose keys and values will be associated in the
|
|
17
|
-
* container at initialization.
|
|
18
|
-
*/
|
|
19
|
-
constructor(values?: Record<string, unknown>) {}
|
|
20
|
-
/**
|
|
21
|
-
* Return the specified parameter or service. If the service is not built yet, this
|
|
22
|
-
* function will construct the service injecting all the dependencies needed in it's
|
|
23
|
-
* definition so the returned object is totally usable on the fly.
|
|
24
|
-
*
|
|
25
|
-
* @template T The type of the returned object.
|
|
26
|
-
* @param key The key of the parameter or service to return.
|
|
27
|
-
* @returns The object related to the service or the value of the parameter associated
|
|
28
|
-
* with the given key.
|
|
29
|
-
* @throws If the key does not exist.
|
|
30
|
-
*/
|
|
31
|
-
get<T = unknown>(key: string): T {}
|
|
32
|
-
/**
|
|
33
|
-
* Defines a new parameter or service.
|
|
34
|
-
*
|
|
35
|
-
* @param key The key of the parameter or service to be defined.
|
|
36
|
-
* @param value The value of the parameter or a function that receives the container as
|
|
37
|
-
* parameter and constructs the service.
|
|
38
|
-
*/
|
|
39
|
-
set(key: string, value: unknown): void {}
|
|
40
|
-
/**
|
|
41
|
-
* Returns if a service or parameter with the informed key is already defined in the
|
|
42
|
-
* container.
|
|
43
|
-
*
|
|
44
|
-
* @param key The key of the parameter or service to be checked.
|
|
45
|
-
* @returns If the key exists in the container or not.
|
|
46
|
-
*/
|
|
47
|
-
has(key: string): boolean {}
|
|
48
|
-
/**
|
|
49
|
-
* Defines a service as a factory, so the instances are not cached in the service and
|
|
50
|
-
* that function is always called.
|
|
51
|
-
*
|
|
52
|
-
* @param fn The function that constructs the service that is a factory.
|
|
53
|
-
* @returns The same function passed as parameter.
|
|
54
|
-
*/
|
|
55
|
-
factory<C = this>(fn: (arg0: C) => unknown): (arg0: C) => unknown {}
|
|
56
|
-
/**
|
|
57
|
-
* Defines a function as a parameter, so that function is not considered a service.
|
|
58
|
-
*
|
|
59
|
-
* @param fn The function to not be considered a service.
|
|
60
|
-
* @returns The same function passed as parameter.
|
|
61
|
-
*/
|
|
62
|
-
protect<T extends () => unknown>(fn: T): T {}
|
|
63
|
-
/** Return all the keys registered in the container. */
|
|
64
|
-
keys(): string[] {}
|
|
65
|
-
/**
|
|
66
|
-
* Extends a service already registered in the container.
|
|
67
|
-
*
|
|
68
|
-
* @param key The key of the service to be extended.
|
|
69
|
-
* @param fn The function that will be used to extend the service.
|
|
70
|
-
* @throws If the key is not already defined.
|
|
71
|
-
* @throws If the key saved in the container does not correspond to a service.
|
|
72
|
-
* @throws If the function passed it not...well, a function.
|
|
73
|
-
*/
|
|
74
|
-
extend<C = this>(key: string, fn: (arg0: unknown, arg1: C) => unknown): void {}
|
|
75
|
-
/**
|
|
76
|
-
* Uses an provider to extend the service, so it's easy to split the service and
|
|
77
|
-
* parameter definitions across the system.
|
|
78
|
-
*
|
|
79
|
-
* @param provider The provider to be used to register services and parameters in this
|
|
80
|
-
* container.
|
|
81
|
-
*/
|
|
82
|
-
register<C = this>(provider: { register: (arg0: C) => void }): void {}
|
|
83
|
-
/**
|
|
84
|
-
* Returns the raw value of a service or parameter. So, in the case of a service, for
|
|
85
|
-
* example, the value returned is the function used to construct the service.
|
|
86
|
-
*
|
|
87
|
-
* @param key The key of the service or parameter to return.
|
|
88
|
-
* @throws If the key does not exist in the container.
|
|
89
|
-
*/
|
|
90
|
-
raw<T = unknown>(key: string): T {}
|
|
91
|
-
}
|