Align property & lazy signatures (getName & self) (#1611)
* Align property & lazy signatures (getName & self) * Adjust tests
This commit is contained in:
@@ -35,7 +35,7 @@ describe('lazyMethod', (): void => {
|
||||
expect(Object.prototype.hasOwnProperty.call(test, 'a')).toEqual(true);
|
||||
expect(getter).not.toHaveBeenCalled();
|
||||
expect(test.a).toEqual(123);
|
||||
expect(getter).toHaveBeenCalledWith('a');
|
||||
expect(getter).toHaveBeenCalledWith('a', 0, expect.objectContaining({}));
|
||||
});
|
||||
|
||||
it('calls the getter a single time', (): void => {
|
||||
@@ -46,7 +46,7 @@ describe('lazyMethod', (): void => {
|
||||
|
||||
expect(getter).not.toHaveBeenCalled();
|
||||
expect(test.a).toEqual(123);
|
||||
expect(getter).toHaveBeenCalledWith('a');
|
||||
expect(getter).toHaveBeenCalledWith('a', 0, expect.objectContaining({}));
|
||||
expect(test.a).toEqual(123);
|
||||
expect(getter).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -10,9 +10,9 @@ type WithToString = { toString: () => string };
|
||||
* @description
|
||||
* Creates a lazy, on-demand getter for the specific value. Upon get the value will be evaluated.
|
||||
*/
|
||||
export function lazyMethod <T, K> (result: Record<string, T> | AnyFn, item: K, creator: (d: K) => T, getName?: (d: K) => string): void {
|
||||
export function lazyMethod <T, K, S> (result: Record<string, T> | AnyFn, item: K, creator: (item: K, index: number, self: S) => T, getName?: (item: K, index: number) => string, index = 0): void {
|
||||
const name = getName
|
||||
? getName(item)
|
||||
? getName(item, index)
|
||||
: (item as WithToString).toString();
|
||||
let value: T | undefined;
|
||||
|
||||
@@ -30,7 +30,7 @@ export function lazyMethod <T, K> (result: Record<string, T> | AnyFn, item: K, c
|
||||
// with a value below ... however we ensure we are quire vigilant against
|
||||
// all environment failures, so we are rather be safe than sorry
|
||||
if (value === undefined) {
|
||||
value = creator(item);
|
||||
value = creator(item, index, this as S);
|
||||
|
||||
try {
|
||||
// re-define the property as a value, next time around this
|
||||
@@ -54,9 +54,9 @@ export function lazyMethod <T, K> (result: Record<string, T> | AnyFn, item: K, c
|
||||
* @description
|
||||
* Creates lazy, on-demand getters for the specific values.
|
||||
*/
|
||||
export function lazyMethods <T, K> (result: Record<string, T>, items: readonly K[], creator: (v: K) => T, getName?: (m: K) => string): Record<string, T> {
|
||||
export function lazyMethods <T, K, S> (result: Record<string, T>, items: readonly K[], creator: (item: K, index: number, self: S) => T, getName?: (item: K, index: number) => string): Record<string, T> {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
lazyMethod(result, items[i], creator, getName);
|
||||
lazyMethod(result, items[i], creator, getName, i);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -128,7 +128,7 @@ describe('objectProperty/objectProperties', (): void => {
|
||||
|
||||
expect(getter).not.toHaveBeenCalled();
|
||||
expect(test.a).toEqual(123);
|
||||
expect(getter).toHaveBeenCalledWith('a', expect.objectContaining({}));
|
||||
expect(getter).toHaveBeenCalledWith('a', 0, expect.objectContaining({}));
|
||||
});
|
||||
|
||||
it('calls back with the key name & index (numtiple)', (): void => {
|
||||
|
||||
@@ -5,20 +5,24 @@
|
||||
* @name objectProperty
|
||||
* @summary Assign a get property on the input object
|
||||
*/
|
||||
export function objectProperty <T> (that: object, key: string, getter: (k: string, self: T) => unknown): void {
|
||||
export function objectProperty <S> (that: object, key: string, getter: (key: string, index: number, self: S) => unknown, getName?: (key: string, index: number) => string, index = 0): void {
|
||||
const name = getName
|
||||
? getName(key, index)
|
||||
: key;
|
||||
|
||||
// There are 3 approaches here -
|
||||
// - Object.prototype.hasOwnProperty.call(that, key) - this only checks the current class, i.e
|
||||
// will retuirn false if the property is set in the parent class
|
||||
// - isUndefined(...) - this may yield a false positive when the property is there, but not set.
|
||||
// Additionally, on pre-defined getters it may make a call
|
||||
// - key in that - Does not need to be combined with either of the above and checks the full chain
|
||||
if (!(key in that)) {
|
||||
Object.defineProperty(that, key, {
|
||||
if (!(name in that)) {
|
||||
Object.defineProperty(that, name, {
|
||||
enumerable: true,
|
||||
// Unlike in lazy, we always call into the upper function, i.e. this method
|
||||
// does not cache old values (it is expected to be used for dynamic values)
|
||||
get: function (): unknown {
|
||||
return getter(key, this as unknown as T);
|
||||
return getter(key, index, this as S);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -28,8 +32,8 @@ export function objectProperty <T> (that: object, key: string, getter: (k: strin
|
||||
* @name objectProperties
|
||||
* @summary Assign get properties on the input object
|
||||
*/
|
||||
export function objectProperties <T> (that: object, keys: string[], getter: (k: string, i: number, self: T) => unknown): void {
|
||||
export function objectProperties <S> (that: object, keys: string[], getter: (key: string, index: number, self: S) => unknown, getName?: (key: string, index: number) => string): void {
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
objectProperty(that, keys[i], (k, self) => getter(k, i, self as T));
|
||||
objectProperty(that, keys[i], getter, getName, i);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user