Align property & lazy signatures (getName & self) (#1611)

* Align property & lazy signatures (getName & self)

* Adjust tests
This commit is contained in:
Jaco
2022-07-20 09:34:13 +03:00
committed by GitHub
parent c1cdc80169
commit 092fbdd923
4 changed files with 18 additions and 14 deletions
+2 -2
View File
@@ -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);
});
+5 -5
View File
@@ -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;
+1 -1
View File
@@ -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 => {
+10 -6
View File
@@ -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);
}
}