From 092fbdd9238380cd24526d9e8b7c0193dacf60dc Mon Sep 17 00:00:00 2001 From: Jaco Date: Wed, 20 Jul 2022 08:34:13 +0200 Subject: [PATCH] Align property & lazy signatures (getName & self) (#1611) * Align property & lazy signatures (getName & self) * Adjust tests --- packages/util/src/lazy.spec.ts | 4 ++-- packages/util/src/lazy.ts | 10 +++++----- packages/util/src/object/property.spec.ts | 2 +- packages/util/src/object/property.ts | 16 ++++++++++------ 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/util/src/lazy.spec.ts b/packages/util/src/lazy.spec.ts index 1604c288d..2b553fe03 100644 --- a/packages/util/src/lazy.spec.ts +++ b/packages/util/src/lazy.spec.ts @@ -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); }); diff --git a/packages/util/src/lazy.ts b/packages/util/src/lazy.ts index ab8cd3882..709d417f6 100644 --- a/packages/util/src/lazy.ts +++ b/packages/util/src/lazy.ts @@ -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 (result: Record | AnyFn, item: K, creator: (d: K) => T, getName?: (d: K) => string): void { +export function lazyMethod (result: Record | 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 (result: Record | 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 (result: Record | AnyFn, item: K, c * @description * Creates lazy, on-demand getters for the specific values. */ -export function lazyMethods (result: Record, items: readonly K[], creator: (v: K) => T, getName?: (m: K) => string): Record { +export function lazyMethods (result: Record, items: readonly K[], creator: (item: K, index: number, self: S) => T, getName?: (item: K, index: number) => string): Record { for (let i = 0; i < items.length; i++) { - lazyMethod(result, items[i], creator, getName); + lazyMethod(result, items[i], creator, getName, i); } return result; diff --git a/packages/util/src/object/property.spec.ts b/packages/util/src/object/property.spec.ts index 97e2c2a55..05804631d 100644 --- a/packages/util/src/object/property.spec.ts +++ b/packages/util/src/object/property.spec.ts @@ -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 => { diff --git a/packages/util/src/object/property.ts b/packages/util/src/object/property.ts index 704e09197..a17dd9944 100644 --- a/packages/util/src/object/property.ts +++ b/packages/util/src/object/property.ts @@ -5,20 +5,24 @@ * @name objectProperty * @summary Assign a get property on the input object */ -export function objectProperty (that: object, key: string, getter: (k: string, self: T) => unknown): void { +export function objectProperty (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 (that: object, key: string, getter: (k: strin * @name objectProperties * @summary Assign get properties on the input object */ -export function objectProperties (that: object, keys: string[], getter: (k: string, i: number, self: T) => unknown): void { +export function objectProperties (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); } }