@resq-sw/decorators 0.1.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.
- package/README.md +277 -0
- package/lib/_utils.d.ts +46 -0
- package/lib/_utils.d.ts.map +1 -0
- package/lib/_utils.js +91 -0
- package/lib/_utils.js.map +1 -0
- package/lib/after/after.d.ts +60 -0
- package/lib/after/after.d.ts.map +1 -0
- package/lib/after/after.fn.d.ts +39 -0
- package/lib/after/after.fn.d.ts.map +1 -0
- package/lib/after/after.fn.js +59 -0
- package/lib/after/after.fn.js.map +1 -0
- package/lib/after/after.js +41 -0
- package/lib/after/after.js.map +1 -0
- package/lib/after/after.types.d.ts +86 -0
- package/lib/after/after.types.d.ts.map +1 -0
- package/lib/after/after.types.js +0 -0
- package/lib/after/index.d.ts +3 -0
- package/lib/after/index.js +2 -0
- package/lib/before/before.d.ts +61 -0
- package/lib/before/before.d.ts.map +1 -0
- package/lib/before/before.fn.d.ts +39 -0
- package/lib/before/before.fn.d.ts.map +1 -0
- package/lib/before/before.fn.js +51 -0
- package/lib/before/before.fn.js.map +1 -0
- package/lib/before/before.js +40 -0
- package/lib/before/before.js.map +1 -0
- package/lib/before/before.types.d.ts +48 -0
- package/lib/before/before.types.d.ts.map +1 -0
- package/lib/before/before.types.js +0 -0
- package/lib/before/index.d.ts +3 -0
- package/lib/before/index.js +2 -0
- package/lib/bind/bind.d.ts +75 -0
- package/lib/bind/bind.d.ts.map +1 -0
- package/lib/bind/bind.fn.d.ts +46 -0
- package/lib/bind/bind.fn.d.ts.map +1 -0
- package/lib/bind/bind.fn.js +39 -0
- package/lib/bind/bind.fn.js.map +1 -0
- package/lib/bind/bind.js +64 -0
- package/lib/bind/bind.js.map +1 -0
- package/lib/bind/bind.types.d.ts +36 -0
- package/lib/bind/bind.types.d.ts.map +1 -0
- package/lib/bind/bind.types.js +0 -0
- package/lib/bind/index.d.ts +3 -0
- package/lib/bind/index.js +2 -0
- package/lib/debounce/debounce.d.ts +34 -0
- package/lib/debounce/debounce.d.ts.map +1 -0
- package/lib/debounce/debounce.fn.d.ts +40 -0
- package/lib/debounce/debounce.fn.d.ts.map +1 -0
- package/lib/debounce/debounce.fn.js +47 -0
- package/lib/debounce/debounce.fn.js.map +1 -0
- package/lib/debounce/debounce.js +48 -0
- package/lib/debounce/debounce.js.map +1 -0
- package/lib/debounce/index.d.ts +2 -0
- package/lib/debounce/index.js +2 -0
- package/lib/delay/delay.d.ts +35 -0
- package/lib/delay/delay.d.ts.map +1 -0
- package/lib/delay/delay.fn.d.ts +33 -0
- package/lib/delay/delay.fn.d.ts.map +1 -0
- package/lib/delay/delay.fn.js +38 -0
- package/lib/delay/delay.fn.js.map +1 -0
- package/lib/delay/delay.js +43 -0
- package/lib/delay/delay.js.map +1 -0
- package/lib/delay/index.d.ts +2 -0
- package/lib/delay/index.js +2 -0
- package/lib/delegate/delegate.d.ts +48 -0
- package/lib/delegate/delegate.d.ts.map +1 -0
- package/lib/delegate/delegate.fn.d.ts +57 -0
- package/lib/delegate/delegate.fn.d.ts.map +1 -0
- package/lib/delegate/delegate.fn.js +55 -0
- package/lib/delegate/delegate.fn.js.map +1 -0
- package/lib/delegate/delegate.js +56 -0
- package/lib/delegate/delegate.js.map +1 -0
- package/lib/delegate/delegate.types.d.ts +45 -0
- package/lib/delegate/delegate.types.d.ts.map +1 -0
- package/lib/delegate/delegate.types.js +0 -0
- package/lib/delegate/index.d.ts +3 -0
- package/lib/delegate/index.js +2 -0
- package/lib/exec-time/exec-time.d.ts +42 -0
- package/lib/exec-time/exec-time.d.ts.map +1 -0
- package/lib/exec-time/exec-time.fn.d.ts +50 -0
- package/lib/exec-time/exec-time.fn.d.ts.map +1 -0
- package/lib/exec-time/exec-time.fn.js +91 -0
- package/lib/exec-time/exec-time.fn.js.map +1 -0
- package/lib/exec-time/exec-time.js +55 -0
- package/lib/exec-time/exec-time.js.map +1 -0
- package/lib/exec-time/exec-time.types.d.ts +70 -0
- package/lib/exec-time/exec-time.types.d.ts.map +1 -0
- package/lib/exec-time/exec-time.types.js +0 -0
- package/lib/exec-time/index.d.ts +4 -0
- package/lib/exec-time/index.js +3 -0
- package/lib/execute/execute.d.ts +78 -0
- package/lib/execute/execute.d.ts.map +1 -0
- package/lib/execute/execute.js +82 -0
- package/lib/execute/execute.js.map +1 -0
- package/lib/execute/index.d.ts +2 -0
- package/lib/execute/index.js +2 -0
- package/lib/index.d.ts +30 -0
- package/lib/index.js +19 -0
- package/lib/memoize/index.d.ts +3 -0
- package/lib/memoize/index.js +2 -0
- package/lib/memoize/memoize.d.ts +67 -0
- package/lib/memoize/memoize.d.ts.map +1 -0
- package/lib/memoize/memoize.fn.d.ts +69 -0
- package/lib/memoize/memoize.fn.d.ts.map +1 -0
- package/lib/memoize/memoize.fn.js +43 -0
- package/lib/memoize/memoize.fn.js.map +1 -0
- package/lib/memoize/memoize.js +40 -0
- package/lib/memoize/memoize.js.map +1 -0
- package/lib/memoize/memoize.types.d.ts +107 -0
- package/lib/memoize/memoize.types.d.ts.map +1 -0
- package/lib/memoize/memoize.types.js +0 -0
- package/lib/memoize-async/index.d.ts +4 -0
- package/lib/memoize-async/index.js +3 -0
- package/lib/memoize-async/memoize-async.d.ts +68 -0
- package/lib/memoize-async/memoize-async.d.ts.map +1 -0
- package/lib/memoize-async/memoize-async.fn.d.ts +69 -0
- package/lib/memoize-async/memoize-async.fn.d.ts.map +1 -0
- package/lib/memoize-async/memoize-async.fn.js +52 -0
- package/lib/memoize-async/memoize-async.fn.js.map +1 -0
- package/lib/memoize-async/memoize-async.js +15 -0
- package/lib/memoize-async/memoize-async.js.map +1 -0
- package/lib/memoize-async/memoize-async.types.d.ts +74 -0
- package/lib/memoize-async/memoize-async.types.d.ts.map +1 -0
- package/lib/memoize-async/memoize-async.types.js +0 -0
- package/lib/observer/index.d.ts +3 -0
- package/lib/observer/index.js +2 -0
- package/lib/observer/observer.d.ts +54 -0
- package/lib/observer/observer.d.ts.map +1 -0
- package/lib/observer/observer.js +85 -0
- package/lib/observer/observer.js.map +1 -0
- package/lib/observer/observer.types.d.ts +41 -0
- package/lib/observer/observer.types.d.ts.map +1 -0
- package/lib/observer/observer.types.js +0 -0
- package/lib/rate-limit/index.d.ts +4 -0
- package/lib/rate-limit/index.js +3 -0
- package/lib/rate-limit/rate-limit.d.ts +58 -0
- package/lib/rate-limit/rate-limit.d.ts.map +1 -0
- package/lib/rate-limit/rate-limit.fn.d.ts +43 -0
- package/lib/rate-limit/rate-limit.fn.d.ts.map +1 -0
- package/lib/rate-limit/rate-limit.fn.js +56 -0
- package/lib/rate-limit/rate-limit.fn.js.map +1 -0
- package/lib/rate-limit/rate-limit.js +65 -0
- package/lib/rate-limit/rate-limit.js.map +1 -0
- package/lib/rate-limit/rate-limit.types.d.ts +148 -0
- package/lib/rate-limit/rate-limit.types.d.ts.map +1 -0
- package/lib/rate-limit/rate-limit.types.js +0 -0
- package/lib/rate-limit/simple-rate-limit-counter.d.ts +89 -0
- package/lib/rate-limit/simple-rate-limit-counter.d.ts.map +1 -0
- package/lib/rate-limit/simple-rate-limit-counter.js +98 -0
- package/lib/rate-limit/simple-rate-limit-counter.js.map +1 -0
- package/lib/readonly/index.d.ts +3 -0
- package/lib/readonly/index.js +2 -0
- package/lib/readonly/readonly.d.ts +39 -0
- package/lib/readonly/readonly.d.ts.map +1 -0
- package/lib/readonly/readonly.js +43 -0
- package/lib/readonly/readonly.js.map +1 -0
- package/lib/readonly/readonly.types.d.ts +40 -0
- package/lib/readonly/readonly.types.d.ts.map +1 -0
- package/lib/readonly/readonly.types.js +0 -0
- package/lib/throttle/index.d.ts +2 -0
- package/lib/throttle/index.js +2 -0
- package/lib/throttle/throttle.d.ts +35 -0
- package/lib/throttle/throttle.d.ts.map +1 -0
- package/lib/throttle/throttle.fn.d.ts +42 -0
- package/lib/throttle/throttle.fn.d.ts.map +1 -0
- package/lib/throttle/throttle.fn.js +52 -0
- package/lib/throttle/throttle.fn.js.map +1 -0
- package/lib/throttle/throttle.js +43 -0
- package/lib/throttle/throttle.js.map +1 -0
- package/lib/throttle-async/index.d.ts +2 -0
- package/lib/throttle-async/index.js +2 -0
- package/lib/throttle-async/throttle-async-executor.d.ts +79 -0
- package/lib/throttle-async/throttle-async-executor.d.ts.map +1 -0
- package/lib/throttle-async/throttle-async-executor.js +122 -0
- package/lib/throttle-async/throttle-async-executor.js.map +1 -0
- package/lib/throttle-async/throttle-async.d.ts +68 -0
- package/lib/throttle-async/throttle-async.d.ts.map +1 -0
- package/lib/throttle-async/throttle-async.fn.d.ts +41 -0
- package/lib/throttle-async/throttle-async.fn.d.ts.map +1 -0
- package/lib/throttle-async/throttle-async.fn.js +46 -0
- package/lib/throttle-async/throttle-async.fn.js.map +1 -0
- package/lib/throttle-async/throttle-async.js +45 -0
- package/lib/throttle-async/throttle-async.js.map +1 -0
- package/lib/types.d.ts +81 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +0 -0
- package/package.json +40 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
//#region src/after/after.types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2026 ResQ
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Function signature for after hooks.
|
|
19
|
+
*
|
|
20
|
+
* @template D - The return type of the decorated method
|
|
21
|
+
* @param {AfterParams<D>} [x] - Parameters containing args and response
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const afterHook: AfterFunc<string> = ({ args, response }) => {
|
|
27
|
+
* console.log(`Method returned: ${response}`);
|
|
28
|
+
* };
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
type AfterFunc<D> = (x?: AfterParams<D>) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Configuration options for the @after decorator.
|
|
34
|
+
*
|
|
35
|
+
* @interface AfterConfig
|
|
36
|
+
* @template T - The type of the class containing the decorated method
|
|
37
|
+
* @template D - The return type of the decorated method
|
|
38
|
+
* @property {AfterFunc<D> | keyof T} func - The after function to execute, or a method name on the class
|
|
39
|
+
* @property {boolean} [wait=false] - Whether to wait for the after function to complete before returning
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* // Using a function reference
|
|
44
|
+
* const config1: AfterConfig<MyClass, string> = {
|
|
45
|
+
* func: ({ args, response }) => console.log(response),
|
|
46
|
+
* wait: false
|
|
47
|
+
* };
|
|
48
|
+
|
|
49
|
+
* // Using a method name
|
|
50
|
+
* const config2: AfterConfig<MyClass, string> = {
|
|
51
|
+
* func: 'logResult', // Calls this.logResult()
|
|
52
|
+
* wait: true
|
|
53
|
+
* };
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
interface AfterConfig<T = any, D = any> {
|
|
57
|
+
/** The after function to execute, or a method name on the class */
|
|
58
|
+
func: AfterFunc<D> | keyof T;
|
|
59
|
+
/** Whether to wait for the after function to complete before returning */
|
|
60
|
+
wait?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Parameters passed to the after hook function.
|
|
64
|
+
*
|
|
65
|
+
* @interface AfterParams
|
|
66
|
+
* @template D - The return type of the decorated method
|
|
67
|
+
* @property {any[]} args - The arguments passed to the decorated method
|
|
68
|
+
* @property {D} response - The return value of the decorated method
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const params: AfterParams<number> = {
|
|
73
|
+
* args: ['input', 42],
|
|
74
|
+
* response: 100
|
|
75
|
+
* };
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
interface AfterParams<D = any> {
|
|
79
|
+
/** The arguments passed to the decorated method */
|
|
80
|
+
args: unknown[];
|
|
81
|
+
/** The return value of the decorated method */
|
|
82
|
+
response: D;
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
export { AfterConfig, AfterFunc, AfterParams };
|
|
86
|
+
//# sourceMappingURL=after.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"after.types.d.ts","names":[],"sources":["../../src/after/after.types.ts"],"mappings":";;AA8BA;;;;;;;;;;AA0BA;;;;;;;;;;;;;;;;;AAuBA;KAjDY,SAAA,OAAgB,CAAA,GAAI,WAAA,CAAY,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;UA0B3B,WAAA;;EAEf,IAAA,EAAM,SAAA,CAAU,CAAA,UAAW,CAAA;;EAE3B,IAAA;AAAA;;;;;;;;;;;;;;;;;UAmBe,WAAA;;EAEf,IAAA;;EAEA,QAAA,EAAU,CAAA;AAAA"}
|
|
File without changes
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Decorator } from "../types.js";
|
|
2
|
+
import { BeforeConfig } from "./before.types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/before/before.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* @fileoverview Before decorator - executes a function before the decorated method.
|
|
7
|
+
* Useful for validation, authentication, or preprocessing before method execution.
|
|
8
|
+
*
|
|
9
|
+
* @module @resq/typescript/decorators/before
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* class MyService {
|
|
14
|
+
* @before({
|
|
15
|
+
* func: 'validateInput',
|
|
16
|
+
* wait: true // Wait for before function to complete
|
|
17
|
+
* })
|
|
18
|
+
* saveData(data: any) {
|
|
19
|
+
* database.save(data);
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* validateInput() {
|
|
23
|
+
* if (!this.isValid) {
|
|
24
|
+
* throw new Error('Invalid state');
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @copyright Copyright (c) 2026 ResQ
|
|
31
|
+
* @license MIT
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Decorator that executes a function before the decorated method.
|
|
35
|
+
* The before function is called before the method body executes.
|
|
36
|
+
*
|
|
37
|
+
* @template T - The type of the class containing the decorated method
|
|
38
|
+
* @param {BeforeConfig<T>} config - Configuration for the before hook
|
|
39
|
+
* @returns {Decorator<T>} The decorator function
|
|
40
|
+
*
|
|
41
|
+
* @throws {Error} When applied to a non-method property
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* class DataProcessor {
|
|
46
|
+
* @before({
|
|
47
|
+
* func: function() {
|
|
48
|
+
* console.log('About to process...');
|
|
49
|
+
* },
|
|
50
|
+
* wait: false
|
|
51
|
+
* })
|
|
52
|
+
* processItems(items: string[]): number {
|
|
53
|
+
* return items.length;
|
|
54
|
+
* }
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
declare function before<T = any>(config: BeforeConfig<T>): Decorator<T>;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { before };
|
|
61
|
+
//# sourceMappingURL=before.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"before.d.ts","names":[],"sources":["../../src/before/before.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0EgB,MAAA,SAAA,CAAgB,MAAA,EAAQ,YAAA,CAAa,CAAA,IAAK,SAAA,CAAU,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Method } from "../types.js";
|
|
2
|
+
import { BeforeConfig } from "./before.types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/before/before.fn.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Wraps a method to execute a before hook function before the method runs.
|
|
7
|
+
*
|
|
8
|
+
* @template D - The return type of the original method
|
|
9
|
+
* @template A - The argument types of the original method
|
|
10
|
+
* @param {Method<D, A>} originalMethod - The method to wrap
|
|
11
|
+
* @param {BeforeConfig<any>} config - Configuration for the before hook
|
|
12
|
+
* @returns {Method<Promise<D>, A>} The wrapped method
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* class Service {
|
|
17
|
+
* process(data: string): string {
|
|
18
|
+
* return data.toUpperCase();
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* const service = new Service();
|
|
23
|
+
* const wrapped = beforeFn(
|
|
24
|
+
* service.process.bind(service),
|
|
25
|
+
* {
|
|
26
|
+
* func: () => {
|
|
27
|
+
* console.log('About to process...');
|
|
28
|
+
* },
|
|
29
|
+
* wait: false
|
|
30
|
+
* }
|
|
31
|
+
* );
|
|
32
|
+
*
|
|
33
|
+
* await wrapped('hello'); // Logs "About to process..." then returns "HELLO"
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
declare function beforeFn<D = any, A extends any[] = any[]>(originalMethod: Method<D, A>, config: BeforeConfig<any>): Method<Promise<D>, A>;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { beforeFn };
|
|
39
|
+
//# sourceMappingURL=before.fn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"before.fn.d.ts","names":[],"sources":["../../src/before/before.fn.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkDgB,QAAA,kCAAA,CACd,cAAA,EAAgB,MAAA,CAAO,CAAA,EAAG,CAAA,GAC1B,MAAA,EAAQ,YAAA,QACP,MAAA,CAAO,OAAA,CAAQ,CAAA,GAAI,CAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//#region src/before/before.fn.ts
|
|
2
|
+
/**
|
|
3
|
+
* Wraps a method to execute a before hook function before the method runs.
|
|
4
|
+
*
|
|
5
|
+
* @template D - The return type of the original method
|
|
6
|
+
* @template A - The argument types of the original method
|
|
7
|
+
* @param {Method<D, A>} originalMethod - The method to wrap
|
|
8
|
+
* @param {BeforeConfig<any>} config - Configuration for the before hook
|
|
9
|
+
* @returns {Method<Promise<D>, A>} The wrapped method
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* class Service {
|
|
14
|
+
* process(data: string): string {
|
|
15
|
+
* return data.toUpperCase();
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* const service = new Service();
|
|
20
|
+
* const wrapped = beforeFn(
|
|
21
|
+
* service.process.bind(service),
|
|
22
|
+
* {
|
|
23
|
+
* func: () => {
|
|
24
|
+
* console.log('About to process...');
|
|
25
|
+
* },
|
|
26
|
+
* wait: false
|
|
27
|
+
* }
|
|
28
|
+
* );
|
|
29
|
+
*
|
|
30
|
+
* await wrapped('hello'); // Logs "About to process..." then returns "HELLO"
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
function beforeFn(originalMethod, config) {
|
|
34
|
+
const resolvedConfig = {
|
|
35
|
+
wait: false,
|
|
36
|
+
...config
|
|
37
|
+
};
|
|
38
|
+
return async function(...args) {
|
|
39
|
+
const beforeFunc = typeof resolvedConfig.func === "string" ? this[resolvedConfig.func].bind(this) : resolvedConfig.func;
|
|
40
|
+
if (resolvedConfig.wait) {
|
|
41
|
+
await beforeFunc();
|
|
42
|
+
return originalMethod.apply(this, args);
|
|
43
|
+
}
|
|
44
|
+
beforeFunc();
|
|
45
|
+
return originalMethod.apply(this, args);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { beforeFn };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=before.fn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"before.fn.js","names":[],"sources":["../../src/before/before.fn.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Method } from '../types.js';\nimport type { BeforeConfig } from './before.types.js';\n\n/**\n * Wraps a method to execute a before hook function before the method runs.\n *\n * @template D - The return type of the original method\n * @template A - The argument types of the original method\n * @param {Method<D, A>} originalMethod - The method to wrap\n * @param {BeforeConfig<any>} config - Configuration for the before hook\n * @returns {Method<Promise<D>, A>} The wrapped method\n *\n * @example\n * ```typescript\n * class Service {\n * process(data: string): string {\n * return data.toUpperCase();\n * }\n * }\n *\n * const service = new Service();\n * const wrapped = beforeFn(\n * service.process.bind(service),\n * {\n * func: () => {\n * console.log('About to process...');\n * },\n * wait: false\n * }\n * );\n *\n * await wrapped('hello'); // Logs \"About to process...\" then returns \"HELLO\"\n * ```\n */\nexport function beforeFn<D = any, A extends any[] = any[]>(\n originalMethod: Method<D, A>,\n config: BeforeConfig<any>,\n): Method<Promise<D>, A> {\n const resolvedConfig: BeforeConfig<any> = {\n wait: false,\n ...config,\n };\n\n return async function (this: any, ...args: A): Promise<D> {\n const beforeFunc =\n typeof resolvedConfig.func === 'string'\n ? this[resolvedConfig.func].bind(this)\n : resolvedConfig.func;\n\n if (resolvedConfig.wait) {\n await beforeFunc();\n return originalMethod.apply(this, args);\n }\n\n beforeFunc();\n return originalMethod.apply(this, args);\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,SAAgB,SACd,gBACA,QACuB;CACvB,MAAM,iBAAoC;EACxC,MAAM;EACN,GAAG;EACJ;AAED,QAAO,eAA2B,GAAG,MAAqB;EACxD,MAAM,aACJ,OAAO,eAAe,SAAS,WAC3B,KAAK,eAAe,MAAM,KAAK,KAAK,GACpC,eAAe;AAErB,MAAI,eAAe,MAAM;AACvB,SAAM,YAAY;AAClB,UAAO,eAAe,MAAM,MAAM,KAAK;;AAGzC,cAAY;AACZ,SAAO,eAAe,MAAM,MAAM,KAAK"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { beforeFn } from "./before.fn.js";
|
|
2
|
+
//#region src/before/before.ts
|
|
3
|
+
/**
|
|
4
|
+
* Decorator that executes a function before the decorated method.
|
|
5
|
+
* The before function is called before the method body executes.
|
|
6
|
+
*
|
|
7
|
+
* @template T - The type of the class containing the decorated method
|
|
8
|
+
* @param {BeforeConfig<T>} config - Configuration for the before hook
|
|
9
|
+
* @returns {Decorator<T>} The decorator function
|
|
10
|
+
*
|
|
11
|
+
* @throws {Error} When applied to a non-method property
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* class DataProcessor {
|
|
16
|
+
* @before({
|
|
17
|
+
* func: function() {
|
|
18
|
+
* console.log('About to process...');
|
|
19
|
+
* },
|
|
20
|
+
* wait: false
|
|
21
|
+
* })
|
|
22
|
+
* processItems(items: string[]): number {
|
|
23
|
+
* return items.length;
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function before(config) {
|
|
29
|
+
return (target, propertyName, descriptor) => {
|
|
30
|
+
if (descriptor.value) {
|
|
31
|
+
descriptor.value = beforeFn(descriptor.value, config);
|
|
32
|
+
return descriptor;
|
|
33
|
+
}
|
|
34
|
+
throw new Error("@before is applicable only on a methods.");
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { before };
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=before.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"before.js","names":[],"sources":["../../src/before/before.ts"],"sourcesContent":["/**\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @fileoverview Before decorator - executes a function before the decorated method.\n * Useful for validation, authentication, or preprocessing before method execution.\n *\n * @module @resq/typescript/decorators/before\n *\n * @example\n * ```typescript\n * class MyService {\n * @before({\n * func: 'validateInput',\n * wait: true // Wait for before function to complete\n * })\n * saveData(data: any) {\n * database.save(data);\n * }\n *\n * validateInput() {\n * if (!this.isValid) {\n * throw new Error('Invalid state');\n * }\n * }\n * }\n * ```\n *\n * @copyright Copyright (c) 2026 ResQ\n * @license MIT\n */\n\nimport type { Decorator, Method } from '../types.js';\nimport { beforeFn } from './before.fn.js';\nimport type { BeforeConfig } from './before.types.js';\n\n/**\n * Decorator that executes a function before the decorated method.\n * The before function is called before the method body executes.\n *\n * @template T - The type of the class containing the decorated method\n * @param {BeforeConfig<T>} config - Configuration for the before hook\n * @returns {Decorator<T>} The decorator function\n *\n * @throws {Error} When applied to a non-method property\n *\n * @example\n * ```typescript\n * class DataProcessor {\n * @before({\n * func: function() {\n * console.log('About to process...');\n * },\n * wait: false\n * })\n * processItems(items: string[]): number {\n * return items.length;\n * }\n * }\n * ```\n */\nexport function before<T = any>(config: BeforeConfig<T>): Decorator<T> {\n return (\n target: T,\n propertyName: keyof T,\n descriptor: TypedPropertyDescriptor<Method<any>>,\n ): TypedPropertyDescriptor<Method<any>> => {\n if (descriptor.value) {\n descriptor.value = beforeFn(descriptor.value, config);\n\n return descriptor;\n }\n throw new Error('@before is applicable only on a methods.');\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA0EA,SAAgB,OAAgB,QAAuC;AACrE,SACE,QACA,cACA,eACyC;AACzC,MAAI,WAAW,OAAO;AACpB,cAAW,QAAQ,SAAS,WAAW,OAAO,OAAO;AAErD,UAAO;;AAET,QAAM,IAAI,MAAM,2CAA2C"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//#region src/before/before.types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2026 ResQ
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Configuration options for the @before decorator.
|
|
19
|
+
*
|
|
20
|
+
* @interface BeforeConfig
|
|
21
|
+
* @template T - The type of the class containing the decorated method
|
|
22
|
+
* @property {((...args: any[]) => any) | keyof T} func - The before function to execute, or a method name on the class
|
|
23
|
+
* @property {boolean} [wait=false] - Whether to wait for the before function to complete before executing the method
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // Using a function reference
|
|
28
|
+
* const config1: BeforeConfig<MyClass> = {
|
|
29
|
+
* func: () => console.log('Before method'),
|
|
30
|
+
* wait: false
|
|
31
|
+
* };
|
|
32
|
+
|
|
33
|
+
* // Using a method name
|
|
34
|
+
* const config2: BeforeConfig<MyClass> = {
|
|
35
|
+
* func: 'validate',
|
|
36
|
+
* wait: true
|
|
37
|
+
* };
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
interface BeforeConfig<T> {
|
|
41
|
+
/** The before function to execute, or a method name on the class */
|
|
42
|
+
func: ((...args: unknown[]) => unknown) | keyof T;
|
|
43
|
+
/** Whether to wait for the before function to complete before executing the method */
|
|
44
|
+
wait?: boolean;
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { BeforeConfig };
|
|
48
|
+
//# sourceMappingURL=before.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"before.types.d.ts","names":[],"sources":["../../src/before/before.types.ts"],"mappings":";;AAuCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAAiB,YAAA;;EAEf,IAAA,OAAW,IAAA,iCAAqC,CAAA;;EAEhD,IAAA;AAAA"}
|
|
File without changes
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Method } from "../types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/bind/bind.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* @fileoverview Bind decorator - automatically binds class methods to their
|
|
6
|
+
* instance context. Ensures `this` always refers to the class instance.
|
|
7
|
+
*
|
|
8
|
+
* @module @resq/typescript/decorators/bind
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* class EventHandler {
|
|
13
|
+
* private count = 0;
|
|
14
|
+
*
|
|
15
|
+
* @bind
|
|
16
|
+
* handleClick(event: MouseEvent): void {
|
|
17
|
+
* this.count++; // `this` correctly refers to EventHandler instance
|
|
18
|
+
* console.log(`Clicked ${this.count} times`);
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* const handler = new EventHandler();
|
|
23
|
+
* button.addEventListener('click', handler.handleClick);
|
|
24
|
+
* // Works correctly even when passed as callback
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @copyright Copyright (c) 2026 ResQ
|
|
28
|
+
* @license MIT
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Decorator that automatically binds a method to its class instance.
|
|
32
|
+
* This ensures `this` always refers to the class instance, even when
|
|
33
|
+
* the method is passed as a callback or stored separately.
|
|
34
|
+
*
|
|
35
|
+
* Uses lazy binding on first access for better performance.
|
|
36
|
+
*
|
|
37
|
+
* @template T - The type of the class containing the decorated method
|
|
38
|
+
* @param {T} _target - The class prototype (unused)
|
|
39
|
+
* @param {string | symbol} propertyKey - The name of the method
|
|
40
|
+
* @param {TypedPropertyDescriptor<Method<unknown>>} descriptor - The property descriptor
|
|
41
|
+
* @returns {TypedPropertyDescriptor<Method<unknown>>} The modified descriptor
|
|
42
|
+
*
|
|
43
|
+
* @throws {Error} When applied to a non-method property
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* class MyClass {
|
|
48
|
+
* private value = 42;
|
|
49
|
+
*
|
|
50
|
+
* @bind
|
|
51
|
+
* getValue(): number {
|
|
52
|
+
* return this.value;
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* @bind
|
|
56
|
+
* async fetchData(): Promise<Data> {
|
|
57
|
+
* return await this.api.getData();
|
|
58
|
+
* }
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* const instance = new MyClass();
|
|
62
|
+
*
|
|
63
|
+
* // Works correctly when passed as callback
|
|
64
|
+
* const getValue = instance.getValue;
|
|
65
|
+
* console.log(getValue()); // 42
|
|
66
|
+
*
|
|
67
|
+
* // Works with async methods too
|
|
68
|
+
* const fetchData = instance.fetchData;
|
|
69
|
+
* const data = await fetchData();
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare function bind<T = unknown>(_target: T, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<Method<unknown>>): TypedPropertyDescriptor<Method<unknown>>;
|
|
73
|
+
//#endregion
|
|
74
|
+
export { bind };
|
|
75
|
+
//# sourceMappingURL=bind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.d.ts","names":[],"sources":["../../src/bind/bind.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,IAAA,aAAA,CACd,OAAA,EAAS,CAAA,EACT,WAAA,mBACA,UAAA,EAAY,uBAAA,CAAwB,MAAA,aACnC,uBAAA,CAAwB,MAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Method } from "../types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/bind/bind.fn.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* @fileoverview Bind function implementation - creates a bound version of a method.
|
|
6
|
+
*
|
|
7
|
+
* @module @resq/typescript/decorators/bind.fn
|
|
8
|
+
*
|
|
9
|
+
* @copyright Copyright (c) 2026 ResQ
|
|
10
|
+
* @license MIT
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Creates a bound version of a method.
|
|
14
|
+
*
|
|
15
|
+
* @template D - The return type of the original method
|
|
16
|
+
* @template A - The argument types of the original method
|
|
17
|
+
* @param {Method<D, A>} originalMethod - The method to bind
|
|
18
|
+
* @param {unknown} context - The context (`this`) to bind to
|
|
19
|
+
* @returns {Method<D, A>} The bound method
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* class Calculator {
|
|
24
|
+
* private multiplier = 10;
|
|
25
|
+
*
|
|
26
|
+
* multiply(value: number): number {
|
|
27
|
+
* return value * this.multiplier;
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* const calc = new Calculator();
|
|
32
|
+
*
|
|
33
|
+
* // Create bound version
|
|
34
|
+
* const boundMultiply = bindFn(calc.multiply.bind(calc), calc);
|
|
35
|
+
* const result = boundMultiply(5); // 50
|
|
36
|
+
*
|
|
37
|
+
* // Can also be used with different context
|
|
38
|
+
* const calc2 = new Calculator();
|
|
39
|
+
* // calc2.multiplier = 20;
|
|
40
|
+
* const boundToCalc2 = bindFn(calc.multiply, calc2);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
declare function bindFn<D = unknown, A extends unknown[] = unknown[]>(originalMethod: Method<D, A>, context: unknown): Method<D, A>;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { bindFn };
|
|
46
|
+
//# sourceMappingURL=bind.fn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.fn.d.ts","names":[],"sources":["../../src/bind/bind.fn.ts"],"mappings":";;;;;;;;;;;;;AA0CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,MAAA,8CAAA,CACd,cAAA,EAAgB,MAAA,CAAO,CAAA,EAAG,CAAA,GAC1B,OAAA,YACC,MAAA,CAAO,CAAA,EAAG,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/bind/bind.fn.ts
|
|
2
|
+
/**
|
|
3
|
+
* Creates a bound version of a method.
|
|
4
|
+
*
|
|
5
|
+
* @template D - The return type of the original method
|
|
6
|
+
* @template A - The argument types of the original method
|
|
7
|
+
* @param {Method<D, A>} originalMethod - The method to bind
|
|
8
|
+
* @param {unknown} context - The context (`this`) to bind to
|
|
9
|
+
* @returns {Method<D, A>} The bound method
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* class Calculator {
|
|
14
|
+
* private multiplier = 10;
|
|
15
|
+
*
|
|
16
|
+
* multiply(value: number): number {
|
|
17
|
+
* return value * this.multiplier;
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* const calc = new Calculator();
|
|
22
|
+
*
|
|
23
|
+
* // Create bound version
|
|
24
|
+
* const boundMultiply = bindFn(calc.multiply.bind(calc), calc);
|
|
25
|
+
* const result = boundMultiply(5); // 50
|
|
26
|
+
*
|
|
27
|
+
* // Can also be used with different context
|
|
28
|
+
* const calc2 = new Calculator();
|
|
29
|
+
* // calc2.multiplier = 20;
|
|
30
|
+
* const boundToCalc2 = bindFn(calc.multiply, calc2);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
function bindFn(originalMethod, context) {
|
|
34
|
+
return originalMethod.bind(context);
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { bindFn };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=bind.fn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.fn.js","names":[],"sources":["../../src/bind/bind.fn.ts"],"sourcesContent":["/**\n * @fileoverview Bind function implementation - creates a bound version of a method.\n *\n * @module @resq/typescript/decorators/bind.fn\n *\n * @copyright Copyright (c) 2026 ResQ\n * @license MIT\n */\n\nimport type { Method } from '../types.js';\n\n/**\n * Creates a bound version of a method.\n *\n * @template D - The return type of the original method\n * @template A - The argument types of the original method\n * @param {Method<D, A>} originalMethod - The method to bind\n * @param {unknown} context - The context (`this`) to bind to\n * @returns {Method<D, A>} The bound method\n *\n * @example\n * ```typescript\n * class Calculator {\n * private multiplier = 10;\n *\n * multiply(value: number): number {\n * return value * this.multiplier;\n * }\n * }\n *\n * const calc = new Calculator();\n *\n * // Create bound version\n * const boundMultiply = bindFn(calc.multiply.bind(calc), calc);\n * const result = boundMultiply(5); // 50\n *\n * // Can also be used with different context\n * const calc2 = new Calculator();\n * // calc2.multiplier = 20;\n * const boundToCalc2 = bindFn(calc.multiply, calc2);\n * ```\n */\nexport function bindFn<D = unknown, A extends unknown[] = unknown[]>(\n originalMethod: Method<D, A>,\n context: unknown,\n): Method<D, A> {\n return originalMethod.bind(context);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,OACd,gBACA,SACc;AACd,QAAO,eAAe,KAAK,QAAQ"}
|
package/lib/bind/bind.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/bind/bind.ts
|
|
2
|
+
/**
|
|
3
|
+
* Decorator that automatically binds a method to its class instance.
|
|
4
|
+
* This ensures `this` always refers to the class instance, even when
|
|
5
|
+
* the method is passed as a callback or stored separately.
|
|
6
|
+
*
|
|
7
|
+
* Uses lazy binding on first access for better performance.
|
|
8
|
+
*
|
|
9
|
+
* @template T - The type of the class containing the decorated method
|
|
10
|
+
* @param {T} _target - The class prototype (unused)
|
|
11
|
+
* @param {string | symbol} propertyKey - The name of the method
|
|
12
|
+
* @param {TypedPropertyDescriptor<Method<unknown>>} descriptor - The property descriptor
|
|
13
|
+
* @returns {TypedPropertyDescriptor<Method<unknown>>} The modified descriptor
|
|
14
|
+
*
|
|
15
|
+
* @throws {Error} When applied to a non-method property
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* class MyClass {
|
|
20
|
+
* private value = 42;
|
|
21
|
+
*
|
|
22
|
+
* @bind
|
|
23
|
+
* getValue(): number {
|
|
24
|
+
* return this.value;
|
|
25
|
+
* }
|
|
26
|
+
*
|
|
27
|
+
* @bind
|
|
28
|
+
* async fetchData(): Promise<Data> {
|
|
29
|
+
* return await this.api.getData();
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* const instance = new MyClass();
|
|
34
|
+
*
|
|
35
|
+
* // Works correctly when passed as callback
|
|
36
|
+
* const getValue = instance.getValue;
|
|
37
|
+
* console.log(getValue()); // 42
|
|
38
|
+
*
|
|
39
|
+
* // Works with async methods too
|
|
40
|
+
* const fetchData = instance.fetchData;
|
|
41
|
+
* const data = await fetchData();
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
function bind(_target, propertyKey, descriptor) {
|
|
45
|
+
const originalMethod = descriptor.value;
|
|
46
|
+
if (!originalMethod) throw new Error("@bind is applicable only on methods.");
|
|
47
|
+
return {
|
|
48
|
+
configurable: true,
|
|
49
|
+
enumerable: false,
|
|
50
|
+
get() {
|
|
51
|
+
const boundMethod = originalMethod.bind(this);
|
|
52
|
+
Object.defineProperty(this, propertyKey, {
|
|
53
|
+
value: boundMethod,
|
|
54
|
+
configurable: true,
|
|
55
|
+
writable: true
|
|
56
|
+
});
|
|
57
|
+
return boundMethod;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { bind };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=bind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.js","names":[],"sources":["../../src/bind/bind.ts"],"sourcesContent":["/*\n * Copyright 2026 ResQ\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @fileoverview Bind decorator - automatically binds class methods to their\n * instance context. Ensures `this` always refers to the class instance.\n *\n * @module @resq/typescript/decorators/bind\n *\n * @example\n * ```typescript\n * class EventHandler {\n * private count = 0;\n *\n * @bind\n * handleClick(event: MouseEvent): void {\n * this.count++; // `this` correctly refers to EventHandler instance\n * console.log(`Clicked ${this.count} times`);\n * }\n * }\n *\n * const handler = new EventHandler();\n * button.addEventListener('click', handler.handleClick);\n * // Works correctly even when passed as callback\n * ```\n *\n * @copyright Copyright (c) 2026 ResQ\n * @license MIT\n */\n\nimport type { Method } from '../types.js';\n\n/**\n * Decorator that automatically binds a method to its class instance.\n * This ensures `this` always refers to the class instance, even when\n * the method is passed as a callback or stored separately.\n *\n * Uses lazy binding on first access for better performance.\n *\n * @template T - The type of the class containing the decorated method\n * @param {T} _target - The class prototype (unused)\n * @param {string | symbol} propertyKey - The name of the method\n * @param {TypedPropertyDescriptor<Method<unknown>>} descriptor - The property descriptor\n * @returns {TypedPropertyDescriptor<Method<unknown>>} The modified descriptor\n *\n * @throws {Error} When applied to a non-method property\n *\n * @example\n * ```typescript\n * class MyClass {\n * private value = 42;\n *\n * @bind\n * getValue(): number {\n * return this.value;\n * }\n *\n * @bind\n * async fetchData(): Promise<Data> {\n * return await this.api.getData();\n * }\n * }\n *\n * const instance = new MyClass();\n *\n * // Works correctly when passed as callback\n * const getValue = instance.getValue;\n * console.log(getValue()); // 42\n *\n * // Works with async methods too\n * const fetchData = instance.fetchData;\n * const data = await fetchData();\n * ```\n */\nexport function bind<T = unknown>(\n _target: T,\n propertyKey: string | symbol,\n descriptor: TypedPropertyDescriptor<Method<unknown>>,\n): TypedPropertyDescriptor<Method<unknown>> {\n const originalMethod = descriptor.value;\n\n if (!originalMethod) {\n throw new Error('@bind is applicable only on methods.');\n }\n\n // Use a getter to lazily bind the method on first access\n return {\n configurable: true,\n enumerable: false,\n get(this: object): Method<unknown> {\n const boundMethod = originalMethod.bind(this);\n\n // Define the bound method directly on the instance for subsequent accesses\n Object.defineProperty(this, propertyKey, {\n value: boundMethod,\n configurable: true,\n writable: true,\n });\n\n return boundMethod;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuFA,SAAgB,KACd,SACA,aACA,YAC0C;CAC1C,MAAM,iBAAiB,WAAW;AAElC,KAAI,CAAC,eACH,OAAM,IAAI,MAAM,uCAAuC;AAIzD,QAAO;EACL,cAAc;EACd,YAAY;EACZ,MAAmC;GACjC,MAAM,cAAc,eAAe,KAAK,KAAK;AAG7C,UAAO,eAAe,MAAM,aAAa;IACvC,OAAO;IACP,cAAc;IACd,UAAU;IACX,CAAC;AAEF,UAAO;;EAEV"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/bind/bind.types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Type definitions for the Bind decorator.
|
|
4
|
+
* Provides configuration types for the bind decorator.
|
|
5
|
+
*
|
|
6
|
+
* @module @resq/typescript/decorators/bind/types
|
|
7
|
+
*
|
|
8
|
+
* @copyright Copyright (c) 2026 ResQ
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Configuration options for the bind decorator.
|
|
13
|
+
*
|
|
14
|
+
* @interface BindConfig
|
|
15
|
+
* @property {boolean} [lazy=true] - If true, the method is bound lazily on first access.
|
|
16
|
+
* If false, the method is bound at decoration time.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Lazy binding (default) - binds on first access
|
|
21
|
+
* const lazyConfig: BindConfig = { lazy: true };
|
|
22
|
+
*
|
|
23
|
+
* // Eager binding - binds immediately
|
|
24
|
+
* const eagerConfig: BindConfig = { lazy: false };
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
interface BindConfig {
|
|
28
|
+
/**
|
|
29
|
+
* If true, the method is bound lazily on first access.
|
|
30
|
+
* If false (default), the method is bound at decoration time.
|
|
31
|
+
*/
|
|
32
|
+
lazy?: boolean;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { BindConfig };
|
|
36
|
+
//# sourceMappingURL=bind.types.d.ts.map
|