@homer0/jimple
Advanced tools
Comparing version 2.0.1 to 2.0.2
@@ -24,2 +24,6 @@ "use strict"; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
// If the importer is in node compatibility mode or this is not an ESM | ||
// file that has been converted to a CommonJS file using a Babel- | ||
// compatible transform (i.e. "__esModule" has not been set), then set | ||
// "default" to the CommonJS "module.exports" for node compatibility. | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
@@ -61,2 +65,6 @@ mod | ||
} | ||
/** | ||
* Create a Jimple Container. | ||
* @param {Object?} [values] - An optional object whose keys and values will be associated in the container at initialization | ||
*/ | ||
constructor(values) { | ||
@@ -72,2 +80,9 @@ this._items = {}; | ||
} | ||
/** | ||
* 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 {string} key - The key of the parameter or service to return | ||
* @return {*} The object related to the service or the value of the parameter associated with the key informed | ||
* @throws If the key does not exist | ||
*/ | ||
get(key) { | ||
@@ -93,17 +108,49 @@ checkDefined(this, key); | ||
} | ||
/** | ||
* Defines a new parameter or service. | ||
* @param {string} 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, value) { | ||
this._items[key] = value; | ||
} | ||
/** | ||
* Returns if a service or parameter with the informed key is already defined in the container. | ||
* @param {string} key - The key of the parameter or service to be checked. | ||
* @return {boolean} If the key exists in the container or not | ||
*/ | ||
has(key) { | ||
return this._items.hasOwnProperty(key); | ||
} | ||
/** | ||
* Defines a service as a factory, so the instances are not cached in the service and that function is always called | ||
* @param {function(Jimple):*} fn - The function that constructs the service that is a factory | ||
* @return {function(Jimple):*} The same function passed as parameter | ||
*/ | ||
factory(fn) { | ||
return addFunctionTo(this._factories, fn); | ||
} | ||
/** | ||
* Defines a function as a parameter, so that function is not considered a service | ||
* @param {*} fn - The function to not be considered a service | ||
* @return {*} The same function passed as parameter | ||
*/ | ||
protect(fn) { | ||
return addFunctionTo(this._protected, fn); | ||
} | ||
/** | ||
* Return all the keys registered in the container | ||
* @returns {Array<string>} | ||
*/ | ||
keys() { | ||
return Object.keys(this._items); | ||
} | ||
/** | ||
* Extends a service already registered in the container | ||
* @param {string} key - The key of the service to be extended | ||
* @param {function(*, Jimple):*} 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(key, fn) { | ||
@@ -122,5 +169,16 @@ checkDefined(this, key); | ||
} | ||
/** | ||
* Uses an provider to extend the service, so it's easy to split the service and parameter definitions across the system | ||
* @param {{register: function(Jimple)}} provider - The provider to be used to register services and parameters in this container | ||
*/ | ||
register(provider2) { | ||
provider2.register(this); | ||
} | ||
/** | ||
* 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 {string} key - The key of the service or parameter to return. | ||
* @throws If the key does not exist in the container | ||
* @return {*} The raw value of the service or parameter | ||
*/ | ||
raw(key) { | ||
@@ -160,2 +218,11 @@ checkDefined(this, key); | ||
var Jimple2 = class extends Jimple { | ||
/** | ||
* 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(key) { | ||
@@ -171,83 +238,179 @@ if (!this.has(key)) { | ||
// src/factories/resourceFactory.ts | ||
var resourceFactory = () => (name, key, fn) => ({ | ||
[name]: true, | ||
[key]: fn | ||
}); | ||
var resourceFactory = () => ( | ||
/** | ||
* Generates a new resource using the contraint defined in the factory. | ||
* | ||
* @param name The name of the resource. | ||
* @param key The property key for the function. | ||
* @param fn The resource function. | ||
* @returns An object with the `name` set to `true`, and the `fn` as the `key`. | ||
* @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 Fn The type of `fn`, restricted by the factory constraint. | ||
* @example | ||
* | ||
* const myAction = factory('action', 'fn', (c) => { | ||
* c.set('foo', 'bar'); | ||
* }); | ||
* | ||
*/ | ||
(name, key, fn) => ({ | ||
[name]: true, | ||
[key]: fn | ||
}) | ||
); | ||
// src/factories/resourceCreatorFactory.ts | ||
var resourceCreatorFactory = () => (name, key, creatorFn) => { | ||
const fnToProxy = (...args) => { | ||
const actualResource = creatorFn(...args); | ||
return resourceFactory()(name, key, actualResource); | ||
}; | ||
const handler = { | ||
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(); | ||
this.resource = newResource; | ||
var resourceCreatorFactory = () => ( | ||
/** | ||
* 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, key, creatorFn) => { | ||
const fnToProxy = (...args) => { | ||
const actualResource = creatorFn(...args); | ||
return resourceFactory()(name, key, actualResource); | ||
}; | ||
const handler = { | ||
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(); | ||
this.resource = newResource; | ||
} | ||
result = this.resource; | ||
} else { | ||
const targetKey = property; | ||
result = target[targetKey]; | ||
} | ||
result = this.resource; | ||
} else { | ||
return result; | ||
}, | ||
has(target, property) { | ||
if (property === this.name || property === key) { | ||
return true; | ||
} | ||
const targetKey = property; | ||
result = target[targetKey]; | ||
return targetKey in target; | ||
} | ||
return result; | ||
}, | ||
has(target, property) { | ||
if (property === this.name || property === key) { | ||
return true; | ||
} | ||
const targetKey = property; | ||
return targetKey in target; | ||
} | ||
}; | ||
return new Proxy(fnToProxy, handler); | ||
}; | ||
}; | ||
return new Proxy(fnToProxy, handler); | ||
} | ||
); | ||
// src/factories/resourcesCollectionFactory.ts | ||
var resourcesCollectionFactory = () => (name, key, fn) => { | ||
const collectionResourceFactory = resourceFactory(); | ||
return (items) => { | ||
const invalidKeys = [name, key]; | ||
const itemsKeys = Object.keys(items); | ||
const invalidKey = itemsKeys.some( | ||
(itemKey) => invalidKeys.includes(String(itemKey)) | ||
); | ||
if (invalidKey) { | ||
throw new Error( | ||
`No item on the collection can have the keys \`${name}\` nor \`${key}\`` | ||
var resourcesCollectionFactory = () => ( | ||
/** | ||
* Generates a function to create a collection of resources of an specified type. A | ||
* collection is a dictionary of resources, and a resource itself, and when its | ||
* "resource function" gets called, it calls the function of every resource (with the | ||
* same args it recevied). | ||
* | ||
* @param name The resource name the items in the collection must have. | ||
* @param key The key property the items in the collection must have. | ||
* @param fn A custom function to process the items in the collection, when the | ||
* collection function gets called. | ||
* @returns A function that can be used to create a resources collection. | ||
* @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 ItemKey To capture the name of the resources in the collection. | ||
* @template Items The kind of dictionary of resources the return function will | ||
* expect. | ||
* @template CustomFn The type of `fn`, restricted by the factory constraint. | ||
* @example | ||
* | ||
* const myActions = factory('action', 'fn')({ myActionA, myActionB }); | ||
* | ||
*/ | ||
(name, key, fn) => { | ||
const collectionResourceFactory = resourceFactory(); | ||
return (items) => { | ||
const invalidKeys = [name, key]; | ||
const itemsKeys = Object.keys(items); | ||
const invalidKey = itemsKeys.some( | ||
(itemKey) => invalidKeys.includes(String(itemKey)) | ||
); | ||
} | ||
const invalidItem = itemsKeys.find( | ||
(itemKey) => typeof items[itemKey]?.[key] !== "function" | ||
); | ||
if (invalidItem) { | ||
throw new Error( | ||
`The item \`${String( | ||
invalidItem | ||
)}\` is invalid: it doesn't have a \`${key}\` function` | ||
if (invalidKey) { | ||
throw new Error( | ||
`No item on the collection can have the keys \`${name}\` nor \`${key}\`` | ||
); | ||
} | ||
const invalidItem = itemsKeys.find( | ||
(itemKey) => typeof items[itemKey]?.[key] !== "function" | ||
); | ||
} | ||
const useFn = fn ? (...args) => fn(items, ...args) : (...args) => { | ||
itemsKeys.forEach((itemK) => { | ||
const item = items[itemK]; | ||
const itemFn = item[key]; | ||
itemFn(...args); | ||
}); | ||
if (invalidItem) { | ||
throw new Error( | ||
`The item \`${String( | ||
invalidItem | ||
)}\` is invalid: it doesn't have a \`${key}\` function` | ||
); | ||
} | ||
const useFn = fn ? (...args) => fn(items, ...args) : (...args) => { | ||
itemsKeys.forEach((itemK) => { | ||
const item = items[itemK]; | ||
const itemFn = item[key]; | ||
itemFn(...args); | ||
}); | ||
}; | ||
return { | ||
...collectionResourceFactory(name, key, useFn), | ||
...items | ||
}; | ||
}; | ||
return { | ||
...collectionResourceFactory(name, key, useFn), | ||
...items | ||
}; | ||
}; | ||
}; | ||
} | ||
); | ||
// src/helpers/injectHelper.ts | ||
var InjectHelper = class { | ||
/** | ||
* 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(dependencies, key, init) { | ||
@@ -260,2 +423,39 @@ const existing = dependencies[key]; | ||
} | ||
/** | ||
* 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(dependencies, container, inject) { | ||
@@ -262,0 +462,0 @@ const result = dependencies.reduce((acc, key) => { |
@@ -19,2 +19,6 @@ var __create = Object.create; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
// If the importer is in node compatibility mode or this is not an ESM | ||
// file that has been converted to a CommonJS file using a Babel- | ||
// compatible transform (i.e. "__esModule" has not been set), then set | ||
// "default" to the CommonJS "module.exports" for node compatibility. | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
@@ -55,2 +59,6 @@ mod | ||
} | ||
/** | ||
* Create a Jimple Container. | ||
* @param {Object?} [values] - An optional object whose keys and values will be associated in the container at initialization | ||
*/ | ||
constructor(values) { | ||
@@ -66,2 +74,9 @@ this._items = {}; | ||
} | ||
/** | ||
* 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 {string} key - The key of the parameter or service to return | ||
* @return {*} The object related to the service or the value of the parameter associated with the key informed | ||
* @throws If the key does not exist | ||
*/ | ||
get(key) { | ||
@@ -87,17 +102,49 @@ checkDefined(this, key); | ||
} | ||
/** | ||
* Defines a new parameter or service. | ||
* @param {string} 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, value) { | ||
this._items[key] = value; | ||
} | ||
/** | ||
* Returns if a service or parameter with the informed key is already defined in the container. | ||
* @param {string} key - The key of the parameter or service to be checked. | ||
* @return {boolean} If the key exists in the container or not | ||
*/ | ||
has(key) { | ||
return this._items.hasOwnProperty(key); | ||
} | ||
/** | ||
* Defines a service as a factory, so the instances are not cached in the service and that function is always called | ||
* @param {function(Jimple):*} fn - The function that constructs the service that is a factory | ||
* @return {function(Jimple):*} The same function passed as parameter | ||
*/ | ||
factory(fn) { | ||
return addFunctionTo(this._factories, fn); | ||
} | ||
/** | ||
* Defines a function as a parameter, so that function is not considered a service | ||
* @param {*} fn - The function to not be considered a service | ||
* @return {*} The same function passed as parameter | ||
*/ | ||
protect(fn) { | ||
return addFunctionTo(this._protected, fn); | ||
} | ||
/** | ||
* Return all the keys registered in the container | ||
* @returns {Array<string>} | ||
*/ | ||
keys() { | ||
return Object.keys(this._items); | ||
} | ||
/** | ||
* Extends a service already registered in the container | ||
* @param {string} key - The key of the service to be extended | ||
* @param {function(*, Jimple):*} 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(key, fn) { | ||
@@ -116,5 +163,16 @@ checkDefined(this, key); | ||
} | ||
/** | ||
* Uses an provider to extend the service, so it's easy to split the service and parameter definitions across the system | ||
* @param {{register: function(Jimple)}} provider - The provider to be used to register services and parameters in this container | ||
*/ | ||
register(provider2) { | ||
provider2.register(this); | ||
} | ||
/** | ||
* 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 {string} key - The key of the service or parameter to return. | ||
* @throws If the key does not exist in the container | ||
* @return {*} The raw value of the service or parameter | ||
*/ | ||
raw(key) { | ||
@@ -135,2 +193,11 @@ checkDefined(this, key); | ||
var Jimple2 = class extends Jimple { | ||
/** | ||
* 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(key) { | ||
@@ -146,83 +213,179 @@ if (!this.has(key)) { | ||
// src/factories/resourceFactory.ts | ||
var resourceFactory = () => (name, key, fn) => ({ | ||
[name]: true, | ||
[key]: fn | ||
}); | ||
var resourceFactory = () => ( | ||
/** | ||
* Generates a new resource using the contraint defined in the factory. | ||
* | ||
* @param name The name of the resource. | ||
* @param key The property key for the function. | ||
* @param fn The resource function. | ||
* @returns An object with the `name` set to `true`, and the `fn` as the `key`. | ||
* @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 Fn The type of `fn`, restricted by the factory constraint. | ||
* @example | ||
* | ||
* const myAction = factory('action', 'fn', (c) => { | ||
* c.set('foo', 'bar'); | ||
* }); | ||
* | ||
*/ | ||
(name, key, fn) => ({ | ||
[name]: true, | ||
[key]: fn | ||
}) | ||
); | ||
// src/factories/resourceCreatorFactory.ts | ||
var resourceCreatorFactory = () => (name, key, creatorFn) => { | ||
const fnToProxy = (...args) => { | ||
const actualResource = creatorFn(...args); | ||
return resourceFactory()(name, key, actualResource); | ||
}; | ||
const handler = { | ||
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(); | ||
this.resource = newResource; | ||
var resourceCreatorFactory = () => ( | ||
/** | ||
* 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, key, creatorFn) => { | ||
const fnToProxy = (...args) => { | ||
const actualResource = creatorFn(...args); | ||
return resourceFactory()(name, key, actualResource); | ||
}; | ||
const handler = { | ||
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(); | ||
this.resource = newResource; | ||
} | ||
result = this.resource; | ||
} else { | ||
const targetKey = property; | ||
result = target[targetKey]; | ||
} | ||
result = this.resource; | ||
} else { | ||
return result; | ||
}, | ||
has(target, property) { | ||
if (property === this.name || property === key) { | ||
return true; | ||
} | ||
const targetKey = property; | ||
result = target[targetKey]; | ||
return targetKey in target; | ||
} | ||
return result; | ||
}, | ||
has(target, property) { | ||
if (property === this.name || property === key) { | ||
return true; | ||
} | ||
const targetKey = property; | ||
return targetKey in target; | ||
} | ||
}; | ||
return new Proxy(fnToProxy, handler); | ||
}; | ||
}; | ||
return new Proxy(fnToProxy, handler); | ||
} | ||
); | ||
// src/factories/resourcesCollectionFactory.ts | ||
var resourcesCollectionFactory = () => (name, key, fn) => { | ||
const collectionResourceFactory = resourceFactory(); | ||
return (items) => { | ||
const invalidKeys = [name, key]; | ||
const itemsKeys = Object.keys(items); | ||
const invalidKey = itemsKeys.some( | ||
(itemKey) => invalidKeys.includes(String(itemKey)) | ||
); | ||
if (invalidKey) { | ||
throw new Error( | ||
`No item on the collection can have the keys \`${name}\` nor \`${key}\`` | ||
var resourcesCollectionFactory = () => ( | ||
/** | ||
* Generates a function to create a collection of resources of an specified type. A | ||
* collection is a dictionary of resources, and a resource itself, and when its | ||
* "resource function" gets called, it calls the function of every resource (with the | ||
* same args it recevied). | ||
* | ||
* @param name The resource name the items in the collection must have. | ||
* @param key The key property the items in the collection must have. | ||
* @param fn A custom function to process the items in the collection, when the | ||
* collection function gets called. | ||
* @returns A function that can be used to create a resources collection. | ||
* @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 ItemKey To capture the name of the resources in the collection. | ||
* @template Items The kind of dictionary of resources the return function will | ||
* expect. | ||
* @template CustomFn The type of `fn`, restricted by the factory constraint. | ||
* @example | ||
* | ||
* const myActions = factory('action', 'fn')({ myActionA, myActionB }); | ||
* | ||
*/ | ||
(name, key, fn) => { | ||
const collectionResourceFactory = resourceFactory(); | ||
return (items) => { | ||
const invalidKeys = [name, key]; | ||
const itemsKeys = Object.keys(items); | ||
const invalidKey = itemsKeys.some( | ||
(itemKey) => invalidKeys.includes(String(itemKey)) | ||
); | ||
} | ||
const invalidItem = itemsKeys.find( | ||
(itemKey) => typeof items[itemKey]?.[key] !== "function" | ||
); | ||
if (invalidItem) { | ||
throw new Error( | ||
`The item \`${String( | ||
invalidItem | ||
)}\` is invalid: it doesn't have a \`${key}\` function` | ||
if (invalidKey) { | ||
throw new Error( | ||
`No item on the collection can have the keys \`${name}\` nor \`${key}\`` | ||
); | ||
} | ||
const invalidItem = itemsKeys.find( | ||
(itemKey) => typeof items[itemKey]?.[key] !== "function" | ||
); | ||
} | ||
const useFn = fn ? (...args) => fn(items, ...args) : (...args) => { | ||
itemsKeys.forEach((itemK) => { | ||
const item = items[itemK]; | ||
const itemFn = item[key]; | ||
itemFn(...args); | ||
}); | ||
if (invalidItem) { | ||
throw new Error( | ||
`The item \`${String( | ||
invalidItem | ||
)}\` is invalid: it doesn't have a \`${key}\` function` | ||
); | ||
} | ||
const useFn = fn ? (...args) => fn(items, ...args) : (...args) => { | ||
itemsKeys.forEach((itemK) => { | ||
const item = items[itemK]; | ||
const itemFn = item[key]; | ||
itemFn(...args); | ||
}); | ||
}; | ||
return { | ||
...collectionResourceFactory(name, key, useFn), | ||
...items | ||
}; | ||
}; | ||
return { | ||
...collectionResourceFactory(name, key, useFn), | ||
...items | ||
}; | ||
}; | ||
}; | ||
} | ||
); | ||
// src/helpers/injectHelper.ts | ||
var InjectHelper = class { | ||
/** | ||
* 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(dependencies, key, init) { | ||
@@ -235,2 +398,39 @@ const existing = dependencies[key]; | ||
} | ||
/** | ||
* 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(dependencies, container, inject) { | ||
@@ -237,0 +437,0 @@ const result = dependencies.reduce((acc, key) => { |
@@ -24,2 +24,6 @@ "use strict"; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
// If the importer is in node compatibility mode or this is not an ESM | ||
// file that has been converted to a CommonJS file using a Babel- | ||
// compatible transform (i.e. "__esModule" has not been set), then set | ||
// "default" to the CommonJS "module.exports" for node compatibility. | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
@@ -61,2 +65,6 @@ mod | ||
} | ||
/** | ||
* Create a Jimple Container. | ||
* @param {Object?} [values] - An optional object whose keys and values will be associated in the container at initialization | ||
*/ | ||
constructor(values) { | ||
@@ -72,2 +80,9 @@ this._items = {}; | ||
} | ||
/** | ||
* 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 {string} key - The key of the parameter or service to return | ||
* @return {*} The object related to the service or the value of the parameter associated with the key informed | ||
* @throws If the key does not exist | ||
*/ | ||
get(key) { | ||
@@ -93,17 +108,49 @@ checkDefined(this, key); | ||
} | ||
/** | ||
* Defines a new parameter or service. | ||
* @param {string} 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, value) { | ||
this._items[key] = value; | ||
} | ||
/** | ||
* Returns if a service or parameter with the informed key is already defined in the container. | ||
* @param {string} key - The key of the parameter or service to be checked. | ||
* @return {boolean} If the key exists in the container or not | ||
*/ | ||
has(key) { | ||
return this._items.hasOwnProperty(key); | ||
} | ||
/** | ||
* Defines a service as a factory, so the instances are not cached in the service and that function is always called | ||
* @param {function(Jimple):*} fn - The function that constructs the service that is a factory | ||
* @return {function(Jimple):*} The same function passed as parameter | ||
*/ | ||
factory(fn) { | ||
return addFunctionTo(this._factories, fn); | ||
} | ||
/** | ||
* Defines a function as a parameter, so that function is not considered a service | ||
* @param {*} fn - The function to not be considered a service | ||
* @return {*} The same function passed as parameter | ||
*/ | ||
protect(fn) { | ||
return addFunctionTo(this._protected, fn); | ||
} | ||
/** | ||
* Return all the keys registered in the container | ||
* @returns {Array<string>} | ||
*/ | ||
keys() { | ||
return Object.keys(this._items); | ||
} | ||
/** | ||
* Extends a service already registered in the container | ||
* @param {string} key - The key of the service to be extended | ||
* @param {function(*, Jimple):*} 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(key, fn) { | ||
@@ -122,5 +169,16 @@ checkDefined(this, key); | ||
} | ||
/** | ||
* Uses an provider to extend the service, so it's easy to split the service and parameter definitions across the system | ||
* @param {{register: function(Jimple)}} provider - The provider to be used to register services and parameters in this container | ||
*/ | ||
register(provider2) { | ||
provider2.register(this); | ||
} | ||
/** | ||
* 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 {string} key - The key of the service or parameter to return. | ||
* @throws If the key does not exist in the container | ||
* @return {*} The raw value of the service or parameter | ||
*/ | ||
raw(key) { | ||
@@ -160,2 +218,11 @@ checkDefined(this, key); | ||
var Jimple2 = class extends Jimple { | ||
/** | ||
* 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(key) { | ||
@@ -171,83 +238,179 @@ if (!this.has(key)) { | ||
// src/factories/resourceFactory.ts | ||
var resourceFactory = () => (name, key, fn) => ({ | ||
[name]: true, | ||
[key]: fn | ||
}); | ||
var resourceFactory = () => ( | ||
/** | ||
* Generates a new resource using the contraint defined in the factory. | ||
* | ||
* @param name The name of the resource. | ||
* @param key The property key for the function. | ||
* @param fn The resource function. | ||
* @returns An object with the `name` set to `true`, and the `fn` as the `key`. | ||
* @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 Fn The type of `fn`, restricted by the factory constraint. | ||
* @example | ||
* | ||
* const myAction = factory('action', 'fn', (c) => { | ||
* c.set('foo', 'bar'); | ||
* }); | ||
* | ||
*/ | ||
(name, key, fn) => ({ | ||
[name]: true, | ||
[key]: fn | ||
}) | ||
); | ||
// src/factories/resourceCreatorFactory.ts | ||
var resourceCreatorFactory = () => (name, key, creatorFn) => { | ||
const fnToProxy = (...args) => { | ||
const actualResource = creatorFn(...args); | ||
return resourceFactory()(name, key, actualResource); | ||
}; | ||
const handler = { | ||
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(); | ||
this.resource = newResource; | ||
var resourceCreatorFactory = () => ( | ||
/** | ||
* 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, key, creatorFn) => { | ||
const fnToProxy = (...args) => { | ||
const actualResource = creatorFn(...args); | ||
return resourceFactory()(name, key, actualResource); | ||
}; | ||
const handler = { | ||
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(); | ||
this.resource = newResource; | ||
} | ||
result = this.resource; | ||
} else { | ||
const targetKey = property; | ||
result = target[targetKey]; | ||
} | ||
result = this.resource; | ||
} else { | ||
return result; | ||
}, | ||
has(target, property) { | ||
if (property === this.name || property === key) { | ||
return true; | ||
} | ||
const targetKey = property; | ||
result = target[targetKey]; | ||
return targetKey in target; | ||
} | ||
return result; | ||
}, | ||
has(target, property) { | ||
if (property === this.name || property === key) { | ||
return true; | ||
} | ||
const targetKey = property; | ||
return targetKey in target; | ||
} | ||
}; | ||
return new Proxy(fnToProxy, handler); | ||
}; | ||
}; | ||
return new Proxy(fnToProxy, handler); | ||
} | ||
); | ||
// src/factories/resourcesCollectionFactory.ts | ||
var resourcesCollectionFactory = () => (name, key, fn) => { | ||
const collectionResourceFactory = resourceFactory(); | ||
return (items) => { | ||
const invalidKeys = [name, key]; | ||
const itemsKeys = Object.keys(items); | ||
const invalidKey = itemsKeys.some( | ||
(itemKey) => invalidKeys.includes(String(itemKey)) | ||
); | ||
if (invalidKey) { | ||
throw new Error( | ||
`No item on the collection can have the keys \`${name}\` nor \`${key}\`` | ||
var resourcesCollectionFactory = () => ( | ||
/** | ||
* Generates a function to create a collection of resources of an specified type. A | ||
* collection is a dictionary of resources, and a resource itself, and when its | ||
* "resource function" gets called, it calls the function of every resource (with the | ||
* same args it recevied). | ||
* | ||
* @param name The resource name the items in the collection must have. | ||
* @param key The key property the items in the collection must have. | ||
* @param fn A custom function to process the items in the collection, when the | ||
* collection function gets called. | ||
* @returns A function that can be used to create a resources collection. | ||
* @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 ItemKey To capture the name of the resources in the collection. | ||
* @template Items The kind of dictionary of resources the return function will | ||
* expect. | ||
* @template CustomFn The type of `fn`, restricted by the factory constraint. | ||
* @example | ||
* | ||
* const myActions = factory('action', 'fn')({ myActionA, myActionB }); | ||
* | ||
*/ | ||
(name, key, fn) => { | ||
const collectionResourceFactory = resourceFactory(); | ||
return (items) => { | ||
const invalidKeys = [name, key]; | ||
const itemsKeys = Object.keys(items); | ||
const invalidKey = itemsKeys.some( | ||
(itemKey) => invalidKeys.includes(String(itemKey)) | ||
); | ||
} | ||
const invalidItem = itemsKeys.find( | ||
(itemKey) => typeof items[itemKey]?.[key] !== "function" | ||
); | ||
if (invalidItem) { | ||
throw new Error( | ||
`The item \`${String( | ||
invalidItem | ||
)}\` is invalid: it doesn't have a \`${key}\` function` | ||
if (invalidKey) { | ||
throw new Error( | ||
`No item on the collection can have the keys \`${name}\` nor \`${key}\`` | ||
); | ||
} | ||
const invalidItem = itemsKeys.find( | ||
(itemKey) => typeof items[itemKey]?.[key] !== "function" | ||
); | ||
} | ||
const useFn = fn ? (...args) => fn(items, ...args) : (...args) => { | ||
itemsKeys.forEach((itemK) => { | ||
const item = items[itemK]; | ||
const itemFn = item[key]; | ||
itemFn(...args); | ||
}); | ||
if (invalidItem) { | ||
throw new Error( | ||
`The item \`${String( | ||
invalidItem | ||
)}\` is invalid: it doesn't have a \`${key}\` function` | ||
); | ||
} | ||
const useFn = fn ? (...args) => fn(items, ...args) : (...args) => { | ||
itemsKeys.forEach((itemK) => { | ||
const item = items[itemK]; | ||
const itemFn = item[key]; | ||
itemFn(...args); | ||
}); | ||
}; | ||
return { | ||
...collectionResourceFactory(name, key, useFn), | ||
...items | ||
}; | ||
}; | ||
return { | ||
...collectionResourceFactory(name, key, useFn), | ||
...items | ||
}; | ||
}; | ||
}; | ||
} | ||
); | ||
// src/helpers/injectHelper.ts | ||
var InjectHelper = class { | ||
/** | ||
* 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(dependencies, key, init) { | ||
@@ -260,2 +423,39 @@ const existing = dependencies[key]; | ||
} | ||
/** | ||
* 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(dependencies, container, inject) { | ||
@@ -262,0 +462,0 @@ const result = dependencies.reduce((acc, key) => { |
{ | ||
"name": "@homer0/jimple", | ||
"description": "An extended version of the Jimple lib, with extra features", | ||
"version": "2.0.1", | ||
"version": "2.0.2", | ||
"repository": { | ||
@@ -26,7 +26,7 @@ "type": "git", | ||
"devDependencies": { | ||
"jest": "^29.4.1", | ||
"jest": "^29.4.3", | ||
"jimple": "^1.5.0", | ||
"ts-jest": "^29.0.5", | ||
"tsup": "^6.5.0", | ||
"typescript": "^4.9.4" | ||
"tsup": "^6.6.3", | ||
"typescript": "^4.9.5" | ||
}, | ||
@@ -47,3 +47,3 @@ "engine-strict": true, | ||
}, | ||
"gitHead": "59c0f6af6901b9f4edb8d2ec36abaf11f6b0780d" | ||
"gitHead": "1ed6ea29e2035f10f0dff60203b6b1d54c601dc8" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
151292
1823