@unshared/decorators 0.0.20 → 0.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"Debounce.cjs","sources":["../Debounce.ts"],"sourcesContent":["import { debounce } from '@unshared/functions/debounce'\nimport { Function, MethodDecorator } from '@unshared/types'\n\n/**\n * Debounce a method so that it will only execute after the specified delay. If the method\n * is called multiple times before the delay has passed, the method will only execute once\n * after the delay has passed. The method will be called with the parameters of the last call.\n *\n * **Note:** This decorator will omit the return value of the method and return `undefined`.\n *\n * @param delay The delay in milliseconds to wait before executing the method.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a debounced method.\n * class Greeter {\n * ->@Debounce(100)\n * greet(name: string) { return `Hello, ${name}! - ${Date.now()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice')\n * instance.greet('Bob')\n * instance.greet('Charlie')\n *\n * // After 100ms the method will be called with the parameters of the last call.\n * // => Hello, Charlie!\n */\nexport function Debounce<T extends Function<void>>(delay: number): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = debounce(method, delay) as unknown as T\n return descriptor\n }\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n beforeAll(() => {\n vi.useFakeTimers()\n })\n\n test('should not call the function if the delay has not passed', () => {\n const fn = vi.fn()\n class Greeter { @Debounce(100) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n instance.fn()\n instance.fn()\n vi.advanceTimersByTime(50)\n expect(fn).not.toHaveBeenCalled()\n })\n\n test('should call the function once after the delay has passed', () => {\n const fn = vi.fn()\n class Greeter { @Debounce(10) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n instance.fn()\n instance.fn()\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledTimes(1)\n })\n\n test('should call the function once with the parameters of the last call', () => {\n const fn = vi.fn()\n class Greeter { @Debounce(10) fn(name: string) { fn(name) } }\n const instance = new Greeter()\n instance.fn('Alice')\n instance.fn('Bob')\n instance.fn('Charlie')\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledWith('Charlie')\n })\n\n test('should call the function multiple times if the delay has passed', () => {\n const fn = vi.fn()\n class Greeter { @Debounce(10) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n vi.advanceTimersByTime(100)\n instance.fn()\n vi.advanceTimersByTime(100)\n instance.fn()\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledTimes(3)\n })\n\n test('should return undefined', () => {\n const fn = vi.fn(() => 'foobar')\n class Greeter { @Debounce(10) fn() { return fn() } }\n const instance = new Greeter()\n const result = instance.fn()\n expect(result).toBeUndefined()\n })\n}\n"],"names":["debounce"],"mappings":";;AA4BO,SAAS,SAAmC,OAAmC;AAC7E,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQA,SAAAA,SAAS,QAAQ,KAAK,GAClC;AAAA,EAAA;AAEX;;"}
1
+ {"version":3,"file":"Debounce.cjs","sources":["../Debounce.ts"],"sourcesContent":["import type { Function, MethodDecorator } from '@unshared/types'\nimport { debounce } from '@unshared/functions/debounce'\n\n/**\n * Debounce a method so that it will only execute after the specified delay. If the method\n * is called multiple times before the delay has passed, the method will only execute once\n * after the delay has passed. The method will be called with the parameters of the last call.\n *\n * **Note:** This decorator will omit the return value of the method and return `undefined`.\n *\n * @param delay The delay in milliseconds to wait before executing the method.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a debounced method.\n * class Greeter {\n * ->@Debounce(100)\n * greet(name: string) { return `Hello, ${name}! - ${Date.now()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice')\n * instance.greet('Bob')\n * instance.greet('Charlie')\n *\n * // After 100ms the method will be called with the parameters of the last call.\n * // => Hello, Charlie!\n */\nexport function Debounce<T extends Function<void>>(delay: number): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = debounce(method, delay) as unknown as T\n return descriptor\n }\n}\n"],"names":["debounce"],"mappings":";;AA4BO,SAAS,SAAmC,OAAmC;AAC7E,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQA,SAAAA,SAAS,QAAQ,KAAK,GAClC;AAAA,EACT;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Debounce.js","sources":["../Debounce.ts"],"sourcesContent":["import { debounce } from '@unshared/functions/debounce'\nimport { Function, MethodDecorator } from '@unshared/types'\n\n/**\n * Debounce a method so that it will only execute after the specified delay. If the method\n * is called multiple times before the delay has passed, the method will only execute once\n * after the delay has passed. The method will be called with the parameters of the last call.\n *\n * **Note:** This decorator will omit the return value of the method and return `undefined`.\n *\n * @param delay The delay in milliseconds to wait before executing the method.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a debounced method.\n * class Greeter {\n * ->@Debounce(100)\n * greet(name: string) { return `Hello, ${name}! - ${Date.now()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice')\n * instance.greet('Bob')\n * instance.greet('Charlie')\n *\n * // After 100ms the method will be called with the parameters of the last call.\n * // => Hello, Charlie!\n */\nexport function Debounce<T extends Function<void>>(delay: number): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = debounce(method, delay) as unknown as T\n return descriptor\n }\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n beforeAll(() => {\n vi.useFakeTimers()\n })\n\n test('should not call the function if the delay has not passed', () => {\n const fn = vi.fn()\n class Greeter { @Debounce(100) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n instance.fn()\n instance.fn()\n vi.advanceTimersByTime(50)\n expect(fn).not.toHaveBeenCalled()\n })\n\n test('should call the function once after the delay has passed', () => {\n const fn = vi.fn()\n class Greeter { @Debounce(10) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n instance.fn()\n instance.fn()\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledTimes(1)\n })\n\n test('should call the function once with the parameters of the last call', () => {\n const fn = vi.fn()\n class Greeter { @Debounce(10) fn(name: string) { fn(name) } }\n const instance = new Greeter()\n instance.fn('Alice')\n instance.fn('Bob')\n instance.fn('Charlie')\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledWith('Charlie')\n })\n\n test('should call the function multiple times if the delay has passed', () => {\n const fn = vi.fn()\n class Greeter { @Debounce(10) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n vi.advanceTimersByTime(100)\n instance.fn()\n vi.advanceTimersByTime(100)\n instance.fn()\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledTimes(3)\n })\n\n test('should return undefined', () => {\n const fn = vi.fn(() => 'foobar')\n class Greeter { @Debounce(10) fn() { return fn() } }\n const instance = new Greeter()\n const result = instance.fn()\n expect(result).toBeUndefined()\n })\n}\n"],"names":[],"mappings":";AA4BO,SAAS,SAAmC,OAAmC;AAC7E,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQ,SAAS,QAAQ,KAAK,GAClC;AAAA,EAAA;AAEX;"}
1
+ {"version":3,"file":"Debounce.js","sources":["../Debounce.ts"],"sourcesContent":["import type { Function, MethodDecorator } from '@unshared/types'\nimport { debounce } from '@unshared/functions/debounce'\n\n/**\n * Debounce a method so that it will only execute after the specified delay. If the method\n * is called multiple times before the delay has passed, the method will only execute once\n * after the delay has passed. The method will be called with the parameters of the last call.\n *\n * **Note:** This decorator will omit the return value of the method and return `undefined`.\n *\n * @param delay The delay in milliseconds to wait before executing the method.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a debounced method.\n * class Greeter {\n * ->@Debounce(100)\n * greet(name: string) { return `Hello, ${name}! - ${Date.now()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice')\n * instance.greet('Bob')\n * instance.greet('Charlie')\n *\n * // After 100ms the method will be called with the parameters of the last call.\n * // => Hello, Charlie!\n */\nexport function Debounce<T extends Function<void>>(delay: number): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = debounce(method, delay) as unknown as T\n return descriptor\n }\n}\n"],"names":[],"mappings":";AA4BO,SAAS,SAAmC,OAAmC;AAC7E,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQ,SAAS,QAAQ,KAAK,GAClC;AAAA,EACT;AACF;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Memoize.cjs","sources":["../Memoize.ts"],"sourcesContent":["import { memoize, MemoizeOptions } from '@unshared/functions/memoize'\nimport { Function, MethodDecorator } from '@unshared/types'\n\n/**\n * Decorate a method to memoize it's result based on the arguments. Meaning\n * that it will return the same result without executing the method again,\n * **unless the arguments change**.\n *\n * @param options The memoization options.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a memoized method.\n * class Greeter {\n * ->@Memoize()\n * greet(name: string) { return `Hello, ${name}! - ${Math.random()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Bob') // 'Hello, Bob! - 0.987654321'\n */\nexport function Memoize<T extends Function>(options?: MemoizeOptions<T>): MethodDecorator<T> {\n return function(_target, _propertyName, descriptor) {\n const method = descriptor.value!\n descriptor.value = memoize(method, options) as unknown as T\n return descriptor\n }\n}\n\n/* v8 ignore start */\n\nif (import.meta.vitest) {\n test('should memoize the method', () => {\n const fn = vi.fn(Math.random)\n class MyClass { @Memoize() getId() { return fn() } }\n const instance = new MyClass()\n const id1 = instance.getId()\n const id2 = instance.getId()\n expect(id1).toStrictEqual(id2)\n expect(fn).toHaveBeenCalledTimes(1)\n expect(fn).toHaveBeenCalledWith()\n })\n\n test('should memoize the method by parameter', () => {\n const fn = vi.fn((n = 0) => (n as number) + Math.random())\n class MyClass { @Memoize() getId(n: number) { return fn(n) } }\n const instance = new MyClass()\n const id1 = instance.getId(1)\n const id2 = instance.getId(1)\n const id3 = instance.getId(2)\n expect(id1).toStrictEqual(id2)\n expect(id1).not.toStrictEqual(id3)\n expect(fn).toHaveBeenCalledTimes(2)\n expect(fn).toHaveBeenCalledWith(1)\n expect(fn).toHaveBeenCalledWith(2)\n })\n\n test('should preserve the method context', () => {\n class MyClass { value = { foo: 42 }; @Memoize() getValue() { return this?.value } }\n const instance = new MyClass()\n const result1 = instance.getValue()\n const result2 = instance.value\n expect(result1).toBe(result2)\n })\n}\n"],"names":["memoize"],"mappings":";;AAuBO,SAAS,QAA4B,SAAiD;AACpF,SAAA,SAAS,SAAS,eAAe,YAAY;AAClD,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQA,QAAAA,QAAQ,QAAQ,OAAO,GACnC;AAAA,EAAA;AAEX;;"}
1
+ {"version":3,"file":"Memoize.cjs","sources":["../Memoize.ts"],"sourcesContent":["import type { MemoizeOptions } from '@unshared/functions/memoize'\nimport type { Function, MethodDecorator } from '@unshared/types'\nimport { memoize } from '@unshared/functions/memoize'\n\n/**\n * Decorate a method to memoize it's result based on the arguments. Meaning\n * that it will return the same result without executing the method again,\n * **unless the arguments change**.\n *\n * @param options The memoization options.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a memoized method.\n * class Greeter {\n * ->@Memoize()\n * greet(name: string) { return `Hello, ${name}! - ${Math.random()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Bob') // 'Hello, Bob! - 0.987654321'\n */\nexport function Memoize<T extends Function>(options?: MemoizeOptions<T>): MethodDecorator<T> {\n return function(_target, _propertyName, descriptor) {\n const method = descriptor.value!\n descriptor.value = memoize(method, options) as unknown as T\n return descriptor\n }\n}\n"],"names":["memoize"],"mappings":";;AAwBO,SAAS,QAA4B,SAAiD;AACpF,SAAA,SAAS,SAAS,eAAe,YAAY;AAClD,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQA,QAAAA,QAAQ,QAAQ,OAAO,GACnC;AAAA,EACT;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Memoize.js","sources":["../Memoize.ts"],"sourcesContent":["import { memoize, MemoizeOptions } from '@unshared/functions/memoize'\nimport { Function, MethodDecorator } from '@unshared/types'\n\n/**\n * Decorate a method to memoize it's result based on the arguments. Meaning\n * that it will return the same result without executing the method again,\n * **unless the arguments change**.\n *\n * @param options The memoization options.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a memoized method.\n * class Greeter {\n * ->@Memoize()\n * greet(name: string) { return `Hello, ${name}! - ${Math.random()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Bob') // 'Hello, Bob! - 0.987654321'\n */\nexport function Memoize<T extends Function>(options?: MemoizeOptions<T>): MethodDecorator<T> {\n return function(_target, _propertyName, descriptor) {\n const method = descriptor.value!\n descriptor.value = memoize(method, options) as unknown as T\n return descriptor\n }\n}\n\n/* v8 ignore start */\n\nif (import.meta.vitest) {\n test('should memoize the method', () => {\n const fn = vi.fn(Math.random)\n class MyClass { @Memoize() getId() { return fn() } }\n const instance = new MyClass()\n const id1 = instance.getId()\n const id2 = instance.getId()\n expect(id1).toStrictEqual(id2)\n expect(fn).toHaveBeenCalledTimes(1)\n expect(fn).toHaveBeenCalledWith()\n })\n\n test('should memoize the method by parameter', () => {\n const fn = vi.fn((n = 0) => (n as number) + Math.random())\n class MyClass { @Memoize() getId(n: number) { return fn(n) } }\n const instance = new MyClass()\n const id1 = instance.getId(1)\n const id2 = instance.getId(1)\n const id3 = instance.getId(2)\n expect(id1).toStrictEqual(id2)\n expect(id1).not.toStrictEqual(id3)\n expect(fn).toHaveBeenCalledTimes(2)\n expect(fn).toHaveBeenCalledWith(1)\n expect(fn).toHaveBeenCalledWith(2)\n })\n\n test('should preserve the method context', () => {\n class MyClass { value = { foo: 42 }; @Memoize() getValue() { return this?.value } }\n const instance = new MyClass()\n const result1 = instance.getValue()\n const result2 = instance.value\n expect(result1).toBe(result2)\n })\n}\n"],"names":[],"mappings":";AAuBO,SAAS,QAA4B,SAAiD;AACpF,SAAA,SAAS,SAAS,eAAe,YAAY;AAClD,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQ,QAAQ,QAAQ,OAAO,GACnC;AAAA,EAAA;AAEX;"}
1
+ {"version":3,"file":"Memoize.js","sources":["../Memoize.ts"],"sourcesContent":["import type { MemoizeOptions } from '@unshared/functions/memoize'\nimport type { Function, MethodDecorator } from '@unshared/types'\nimport { memoize } from '@unshared/functions/memoize'\n\n/**\n * Decorate a method to memoize it's result based on the arguments. Meaning\n * that it will return the same result without executing the method again,\n * **unless the arguments change**.\n *\n * @param options The memoization options.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a memoized method.\n * class Greeter {\n * ->@Memoize()\n * greet(name: string) { return `Hello, ${name}! - ${Math.random()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Bob') // 'Hello, Bob! - 0.987654321'\n */\nexport function Memoize<T extends Function>(options?: MemoizeOptions<T>): MethodDecorator<T> {\n return function(_target, _propertyName, descriptor) {\n const method = descriptor.value!\n descriptor.value = memoize(method, options) as unknown as T\n return descriptor\n }\n}\n"],"names":[],"mappings":";AAwBO,SAAS,QAA4B,SAAiD;AACpF,SAAA,SAAS,SAAS,eAAe,YAAY;AAClD,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQ,QAAQ,QAAQ,OAAO,GACnC;AAAA,EACT;AACF;"}
package/dist/Once.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Once.cjs","sources":["../Once.ts"],"sourcesContent":["import { once } from '@unshared/functions/once'\nimport { Function, MethodDecorator } from '@unshared/types'\n\n/**\n * Decorate a method to memoize it's result. Meaning that if the method is called,\n * it will return the same result without executing the method again, **even if the\n * method is called with different arguments**.\n *\n * @returns The method descriptor.\n * @example\n * // Declare a class with a onced method.\n * class Greeter {\n * ->@Once()\n * greet(name: string) { return `Hello, ${name}! - ${Math.random()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Bob') // 'Hello, Alice! - 0.123456789'\n */\nexport function Once<T extends Function>(): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = once(method) as unknown as T\n return descriptor\n }\n}\n\n/* v8 ignore start */\n\nif (import.meta.vitest) {\n test('should return the same value if no arguments are passed', () => {\n const fn = vi.fn(Math.random)\n class MyClass { @Once() getId() { return fn() } }\n const instance = new MyClass()\n const id1 = instance.getId()\n const id2 = instance.getId()\n expect(id1).toStrictEqual(id2)\n expect(fn).toHaveBeenCalledTimes(1)\n expect(fn).toHaveBeenCalledWith()\n })\n\n test('should return the same values if different arguments are passed', () => {\n const fn = vi.fn((n = 0) => (n as number) + Math.random())\n class MyClass { @Once() getId(n: number) { return fn(n) } }\n const instance = new MyClass()\n const id1 = instance.getId(1)\n const id2 = instance.getId(1)\n const id3 = instance.getId(2)\n expect(id1).toStrictEqual(id2)\n expect(id1).toStrictEqual(id3)\n expect(fn).toHaveBeenCalledTimes(1)\n expect(fn).toHaveBeenCalledWith(1)\n expect(fn).not.toHaveBeenCalledWith(2)\n })\n\n test('should preserve the method context', () => {\n class MyClass { value = { foo: 42 }; @Once() getValue() { return this?.value } }\n const instance = new MyClass()\n const result1 = instance.getValue()\n const result2 = instance.value\n expect(result1).toBe(result2)\n })\n\n test('should have different results for different instances', () => {\n class MyClass { @Once() getValue() { return Math.random() } }\n const instance1 = new MyClass()\n const instance2 = new MyClass()\n const result1 = instance1.getValue()\n const result2 = instance2.getValue()\n expect(result1).not.toStrictEqual(result2)\n })\n}\n"],"names":["once"],"mappings":";;AAqBO,SAAS,OAA+C;AACtD,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AACf,WAAA,WAAA,QAAQA,KAAK,KAAA,MAAM,GACvB;AAAA,EAAA;AAEX;;"}
1
+ {"version":3,"file":"Once.cjs","sources":["../Once.ts"],"sourcesContent":["import type { Function, MethodDecorator } from '@unshared/types'\nimport { once } from '@unshared/functions/once'\n\n/**\n * Decorate a method to memoize it's result. Meaning that if the method is called,\n * it will return the same result without executing the method again, **even if the\n * method is called with different arguments**.\n *\n * @returns The method descriptor.\n * @example\n * // Declare a class with a onced method.\n * class Greeter {\n * ->@Once()\n * greet(name: string) { return `Hello, ${name}! - ${Math.random()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Bob') // 'Hello, Alice! - 0.123456789'\n */\nexport function Once<T extends Function>(): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = once(method) as unknown as T\n return descriptor\n }\n}\n"],"names":["once"],"mappings":";;AAqBO,SAAS,OAA+C;AACtD,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AACf,WAAA,WAAA,QAAQA,UAAK,MAAM,GACvB;AAAA,EACT;AACF;;"}
package/dist/Once.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Once.js","sources":["../Once.ts"],"sourcesContent":["import { once } from '@unshared/functions/once'\nimport { Function, MethodDecorator } from '@unshared/types'\n\n/**\n * Decorate a method to memoize it's result. Meaning that if the method is called,\n * it will return the same result without executing the method again, **even if the\n * method is called with different arguments**.\n *\n * @returns The method descriptor.\n * @example\n * // Declare a class with a onced method.\n * class Greeter {\n * ->@Once()\n * greet(name: string) { return `Hello, ${name}! - ${Math.random()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Bob') // 'Hello, Alice! - 0.123456789'\n */\nexport function Once<T extends Function>(): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = once(method) as unknown as T\n return descriptor\n }\n}\n\n/* v8 ignore start */\n\nif (import.meta.vitest) {\n test('should return the same value if no arguments are passed', () => {\n const fn = vi.fn(Math.random)\n class MyClass { @Once() getId() { return fn() } }\n const instance = new MyClass()\n const id1 = instance.getId()\n const id2 = instance.getId()\n expect(id1).toStrictEqual(id2)\n expect(fn).toHaveBeenCalledTimes(1)\n expect(fn).toHaveBeenCalledWith()\n })\n\n test('should return the same values if different arguments are passed', () => {\n const fn = vi.fn((n = 0) => (n as number) + Math.random())\n class MyClass { @Once() getId(n: number) { return fn(n) } }\n const instance = new MyClass()\n const id1 = instance.getId(1)\n const id2 = instance.getId(1)\n const id3 = instance.getId(2)\n expect(id1).toStrictEqual(id2)\n expect(id1).toStrictEqual(id3)\n expect(fn).toHaveBeenCalledTimes(1)\n expect(fn).toHaveBeenCalledWith(1)\n expect(fn).not.toHaveBeenCalledWith(2)\n })\n\n test('should preserve the method context', () => {\n class MyClass { value = { foo: 42 }; @Once() getValue() { return this?.value } }\n const instance = new MyClass()\n const result1 = instance.getValue()\n const result2 = instance.value\n expect(result1).toBe(result2)\n })\n\n test('should have different results for different instances', () => {\n class MyClass { @Once() getValue() { return Math.random() } }\n const instance1 = new MyClass()\n const instance2 = new MyClass()\n const result1 = instance1.getValue()\n const result2 = instance2.getValue()\n expect(result1).not.toStrictEqual(result2)\n })\n}\n"],"names":[],"mappings":";AAqBO,SAAS,OAA+C;AACtD,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AACf,WAAA,WAAA,QAAQ,KAAK,MAAM,GACvB;AAAA,EAAA;AAEX;"}
1
+ {"version":3,"file":"Once.js","sources":["../Once.ts"],"sourcesContent":["import type { Function, MethodDecorator } from '@unshared/types'\nimport { once } from '@unshared/functions/once'\n\n/**\n * Decorate a method to memoize it's result. Meaning that if the method is called,\n * it will return the same result without executing the method again, **even if the\n * method is called with different arguments**.\n *\n * @returns The method descriptor.\n * @example\n * // Declare a class with a onced method.\n * class Greeter {\n * ->@Once()\n * greet(name: string) { return `Hello, ${name}! - ${Math.random()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice') // 'Hello, Alice! - 0.123456789'\n * instance.greet('Bob') // 'Hello, Alice! - 0.123456789'\n */\nexport function Once<T extends Function>(): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = once(method) as unknown as T\n return descriptor\n }\n}\n"],"names":[],"mappings":";AAqBO,SAAS,OAA+C;AACtD,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AACf,WAAA,WAAA,QAAQ,KAAK,MAAM,GACvB;AAAA,EACT;AACF;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Throttle.cjs","sources":["../Throttle.ts"],"sourcesContent":["import { throttle } from '@unshared/functions/throttle'\nimport { Function, MethodDecorator } from '@unshared/types'\n\n/**\n * Throttle a method so that it will only execute once every specified delay.\n * Useful for implementing spam protection. When the method is called, it will\n * execute immediately and then wait for the specified delay before it can be\n * called again.\n *\n * **Note:** This decorator will omit the return value of the method and return `undefined`.\n *\n * @param delay The delay in milliseconds to wait before executing the method.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a debounced method.\n * class Greeter {\n * ->@Throttle(100)\n * greet(name: string) { return `Hello, ${name}! - ${Date.now()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice')\n * instance.greet('Bob')\n * instance.greet('Charlie')\n *\n * // The method will be called immediately and can only be called again after 100ms.\n * // => Hello, Alice!\n */\nexport function Throttle<T extends Function<void>>(delay: number): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = throttle(method, delay) as unknown as T\n return descriptor\n }\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n beforeEach(() => vi.useFakeTimers)\n\n test('should call the function immediately', () => {\n const fn = vi.fn()\n class Greeter { @Throttle(100) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n expect(fn).toHaveBeenCalledTimes(1)\n })\n\n test('should not call the function more than once within the delay', () => {\n const fn = vi.fn()\n class Greeter { @Throttle(100) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n instance.fn()\n instance.fn()\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledTimes(1)\n })\n\n test('should pass the parameters of the first call to the function', () => {\n const fn = vi.fn()\n class Greeter { @Throttle(10) fn(name: string) { fn(name) } }\n const instance = new Greeter()\n instance.fn('Alice')\n instance.fn('Bob')\n instance.fn('Charlie')\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledWith('Alice')\n })\n\n test('should call the function again after the delay has passed', () => {\n const fn = vi.fn()\n class Greeter { @Throttle(100) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n vi.advanceTimersByTime(100)\n instance.fn()\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledTimes(2)\n })\n\n test('should return undefined', () => {\n const fn = vi.fn(() => 'foobar')\n class Greeter { @Throttle(100) fn() { return fn() } }\n const instance = new Greeter()\n const result = instance.fn()\n expect(result).toBeUndefined()\n })\n}\n"],"names":["throttle"],"mappings":";;AA6BO,SAAS,SAAmC,OAAmC;AAC7E,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQA,SAAAA,SAAS,QAAQ,KAAK,GAClC;AAAA,EAAA;AAEX;;"}
1
+ {"version":3,"file":"Throttle.cjs","sources":["../Throttle.ts"],"sourcesContent":["import type { Function, MethodDecorator } from '@unshared/types'\nimport { throttle } from '@unshared/functions/throttle'\n\n/**\n * Throttle a method so that it will only execute once every specified delay.\n * Useful for implementing spam protection. When the method is called, it will\n * execute immediately and then wait for the specified delay before it can be\n * called again.\n *\n * **Note:** This decorator will omit the return value of the method and return `undefined`.\n *\n * @param delay The delay in milliseconds to wait before executing the method.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a debounced method.\n * class Greeter {\n * ->@Throttle(100)\n * greet(name: string) { return `Hello, ${name}! - ${Date.now()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice')\n * instance.greet('Bob')\n * instance.greet('Charlie')\n *\n * // The method will be called immediately and can only be called again after 100ms.\n * // => Hello, Alice!\n */\nexport function Throttle<T extends Function<void>>(delay: number): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = throttle(method, delay) as unknown as T\n return descriptor\n }\n}\n"],"names":["throttle"],"mappings":";;AA6BO,SAAS,SAAmC,OAAmC;AAC7E,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQA,SAAAA,SAAS,QAAQ,KAAK,GAClC;AAAA,EACT;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Throttle.js","sources":["../Throttle.ts"],"sourcesContent":["import { throttle } from '@unshared/functions/throttle'\nimport { Function, MethodDecorator } from '@unshared/types'\n\n/**\n * Throttle a method so that it will only execute once every specified delay.\n * Useful for implementing spam protection. When the method is called, it will\n * execute immediately and then wait for the specified delay before it can be\n * called again.\n *\n * **Note:** This decorator will omit the return value of the method and return `undefined`.\n *\n * @param delay The delay in milliseconds to wait before executing the method.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a debounced method.\n * class Greeter {\n * ->@Throttle(100)\n * greet(name: string) { return `Hello, ${name}! - ${Date.now()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice')\n * instance.greet('Bob')\n * instance.greet('Charlie')\n *\n * // The method will be called immediately and can only be called again after 100ms.\n * // => Hello, Alice!\n */\nexport function Throttle<T extends Function<void>>(delay: number): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = throttle(method, delay) as unknown as T\n return descriptor\n }\n}\n\n/* v8 ignore start */\nif (import.meta.vitest) {\n beforeEach(() => vi.useFakeTimers)\n\n test('should call the function immediately', () => {\n const fn = vi.fn()\n class Greeter { @Throttle(100) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n expect(fn).toHaveBeenCalledTimes(1)\n })\n\n test('should not call the function more than once within the delay', () => {\n const fn = vi.fn()\n class Greeter { @Throttle(100) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n instance.fn()\n instance.fn()\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledTimes(1)\n })\n\n test('should pass the parameters of the first call to the function', () => {\n const fn = vi.fn()\n class Greeter { @Throttle(10) fn(name: string) { fn(name) } }\n const instance = new Greeter()\n instance.fn('Alice')\n instance.fn('Bob')\n instance.fn('Charlie')\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledWith('Alice')\n })\n\n test('should call the function again after the delay has passed', () => {\n const fn = vi.fn()\n class Greeter { @Throttle(100) fn() { fn() } }\n const instance = new Greeter()\n instance.fn()\n vi.advanceTimersByTime(100)\n instance.fn()\n vi.advanceTimersByTime(100)\n expect(fn).toHaveBeenCalledTimes(2)\n })\n\n test('should return undefined', () => {\n const fn = vi.fn(() => 'foobar')\n class Greeter { @Throttle(100) fn() { return fn() } }\n const instance = new Greeter()\n const result = instance.fn()\n expect(result).toBeUndefined()\n })\n}\n"],"names":[],"mappings":";AA6BO,SAAS,SAAmC,OAAmC;AAC7E,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQ,SAAS,QAAQ,KAAK,GAClC;AAAA,EAAA;AAEX;"}
1
+ {"version":3,"file":"Throttle.js","sources":["../Throttle.ts"],"sourcesContent":["import type { Function, MethodDecorator } from '@unshared/types'\nimport { throttle } from '@unshared/functions/throttle'\n\n/**\n * Throttle a method so that it will only execute once every specified delay.\n * Useful for implementing spam protection. When the method is called, it will\n * execute immediately and then wait for the specified delay before it can be\n * called again.\n *\n * **Note:** This decorator will omit the return value of the method and return `undefined`.\n *\n * @param delay The delay in milliseconds to wait before executing the method.\n * @returns The method descriptor.\n * @example\n * // Declare a class with a debounced method.\n * class Greeter {\n * ->@Throttle(100)\n * greet(name: string) { return `Hello, ${name}! - ${Date.now()}` }\n * }\n *\n * // The first call to the method will be executed.\n * const instance = new Greeter()\n * instance.greet('Alice')\n * instance.greet('Bob')\n * instance.greet('Charlie')\n *\n * // The method will be called immediately and can only be called again after 100ms.\n * // => Hello, Alice!\n */\nexport function Throttle<T extends Function<void>>(delay: number): MethodDecorator<T> {\n return (target, propertyName, descriptor) => {\n const method = descriptor.value!\n descriptor.value = throttle(method, delay) as unknown as T\n return descriptor\n }\n}\n"],"names":[],"mappings":";AA6BO,SAAS,SAAmC,OAAmC;AAC7E,SAAA,CAAC,QAAQ,cAAc,eAAe;AAC3C,UAAM,SAAS,WAAW;AAC1B,WAAA,WAAW,QAAQ,SAAS,QAAQ,KAAK,GAClC;AAAA,EACT;AACF;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unshared/decorators",
3
3
  "type": "module",
4
- "version": "0.0.20",
4
+ "version": "0.2.0",
5
5
  "license": "MIT",
6
6
  "sideEffects": false,
7
7
  "author": "Stanley Horwood <stanley@hsjm.io>",
@@ -48,7 +48,7 @@
48
48
  "LICENSE.md"
49
49
  ],
50
50
  "dependencies": {
51
- "@unshared/functions": "0.0.20",
52
- "@unshared/types": "0.0.20"
51
+ "@unshared/functions": "0.2.0",
52
+ "@unshared/types": "0.2.0"
53
53
  }
54
54
  }