defered-branch 2.0.0 โ 2.1.1
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 +62 -3
- package/dist/index.d.ts +51 -14
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ A TypeScript/JavaScript library that provides elegant deferred conditional branc
|
|
|
12
12
|
- ๐ **Type Safe**: Full TypeScript support with proper type inference
|
|
13
13
|
- ๐ชถ **Lightweight**: Zero dependencies, minimal footprint
|
|
14
14
|
- ๐งฉ **Flexible**: Works with any function signature and return types
|
|
15
|
-
- ๐ฆ **
|
|
15
|
+
- ๐ฆ **Type Annotation**: Full type annotation supported for the exported functions. You can customize handler's type of branch/condition/nomatch.
|
|
16
16
|
|
|
17
17
|
## ๐ฆ Installation
|
|
18
18
|
|
|
@@ -59,6 +59,8 @@ branch
|
|
|
59
59
|
// 3. Handle no-match case (optional)
|
|
60
60
|
branch.nomatch(() => 'Access denied');
|
|
61
61
|
|
|
62
|
+
// some other logic... like validate other arguments
|
|
63
|
+
|
|
62
64
|
// 4. Execute and get result
|
|
63
65
|
const result = branch.run();
|
|
64
66
|
console.log(result); // Output based on user.role
|
|
@@ -165,7 +167,7 @@ Creates a new deferred branch instance for immediate execution scenarios.
|
|
|
165
167
|
##### `.add(condition: boolean, branch: Function): DeferBranch`
|
|
166
168
|
|
|
167
169
|
- Adds a conditional branch that executes if condition is `true`
|
|
168
|
-
-
|
|
170
|
+
- First-match wins: the first truthy branch will be selected; later entries are ignored
|
|
169
171
|
- Returns the instance for chaining
|
|
170
172
|
|
|
171
173
|
##### `.nomatch(handler: Function): DeferBranch`
|
|
@@ -190,13 +192,70 @@ Creates a new dynamic deferred branch instance for reusable logic patterns.
|
|
|
190
192
|
|
|
191
193
|
- Adds a predicate-based conditional branch
|
|
192
194
|
- `condition` is a function that returns boolean
|
|
193
|
-
-
|
|
195
|
+
- First-match wins: the first truthy branch will be selected; later entries are ignored
|
|
194
196
|
|
|
195
197
|
##### `.nomatch(handler: Function): DeferBranchDynamic`
|
|
196
198
|
|
|
197
199
|
- Sets a fallback handler for when no predicates match
|
|
198
200
|
- Executes during `.predicate()` evaluation
|
|
199
201
|
|
|
202
|
+
## ๐งพ Type Annotation
|
|
203
|
+
|
|
204
|
+
The factory functions `deferedBranch` and `deferedBranchDynamic` are generic helpers. You can provide explicit type parameters to describe the branch function signature and the optional `nomatch` handler.
|
|
205
|
+
|
|
206
|
+
Below is an example using `deferedBranch`:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { deferedBranch } from 'defered-branch';
|
|
210
|
+
|
|
211
|
+
// Here we declare that branches accept a message (string) and return void.
|
|
212
|
+
// The factory signature is: deferedBranch<BranchFn, NoMatchFn>()
|
|
213
|
+
const handler = deferedBranch<(msg: string) => void, () => void>();
|
|
214
|
+
|
|
215
|
+
handler
|
|
216
|
+
.add(
|
|
217
|
+
process.env.STATUS === 'ok',
|
|
218
|
+
(msg) => console.log('OK:', msg) // this is restricted by `(msg: string) => void`
|
|
219
|
+
)
|
|
220
|
+
.add(
|
|
221
|
+
process.env.STATUS === 'warn',
|
|
222
|
+
(msg) => console.warn('WARN:', msg) // this is restricted by `(msg: string) => void`
|
|
223
|
+
)
|
|
224
|
+
.nomatch(
|
|
225
|
+
() => console.debug('unknown') // this is restricted by `() => void`
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
handler.run('hello world'); // input args for `run` are restricted by `(msg: string) => void`
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Notes:
|
|
232
|
+
|
|
233
|
+
- If you omit generic parameters TypeScript will fall back to `AnyFn` and inference is weaker.
|
|
234
|
+
- `BranchFn` defines the parameter types that `.run(...)` accepts and what each branch receives.
|
|
235
|
+
- `NoMatchFn` defines the signature of the `nomatch`/`deferedNomatch` handler.
|
|
236
|
+
|
|
237
|
+
Example: calculator with typed branches
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
const calc = deferedBranchDynamic<(a: number, b: number) => number, () => never>();
|
|
241
|
+
|
|
242
|
+
calc
|
|
243
|
+
.add(
|
|
244
|
+
() => operation === 'add',
|
|
245
|
+
(a, b) => a + b
|
|
246
|
+
)
|
|
247
|
+
.add(
|
|
248
|
+
() => operation === 'mul',
|
|
249
|
+
(a, b) => a * b
|
|
250
|
+
)
|
|
251
|
+
.nomatch(() => {
|
|
252
|
+
throw new Error('unknown operation');
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
calc.predicate();
|
|
256
|
+
const result = calc.run(2, 3); // typed as number | undefined
|
|
257
|
+
```
|
|
258
|
+
|
|
200
259
|
##### `.predicate(...args): void`
|
|
201
260
|
|
|
202
261
|
- Evaluates all conditions to find the first match
|
package/dist/index.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
declare class DeferBranch<BranchFn extends AnyFn, NoMatchFn extends AnyFn
|
|
1
|
+
declare class DeferBranch<BranchFn extends AnyFn, NoMatchFn extends AnyFn> {
|
|
2
2
|
private _branch;
|
|
3
3
|
private _nomatch;
|
|
4
4
|
/**
|
|
5
5
|
* Add a new entry
|
|
6
|
-
* -
|
|
6
|
+
* - **First truthy first served**.
|
|
7
7
|
* @param condition the condition to match
|
|
8
8
|
* @param branch the branch to run when matched
|
|
9
9
|
* @returns this
|
|
10
10
|
*/
|
|
11
|
-
add(condition: boolean, branch: BranchFn):
|
|
11
|
+
add(condition: boolean, branch: BranchFn): this;
|
|
12
12
|
/**
|
|
13
13
|
* Register a handler to be called when no branch matched
|
|
14
14
|
* - This will be called **instantly and ignores later matched branches**
|
|
15
15
|
* @param handler handle the exhausted case
|
|
16
16
|
* @returns this
|
|
17
17
|
*/
|
|
18
|
-
nomatch(handler: AnyFn):
|
|
18
|
+
nomatch(handler: AnyFn): this;
|
|
19
19
|
/**
|
|
20
20
|
* If some branch matched, return its returnValue
|
|
21
21
|
* - if no branch matched, return the nomatch handler's returnValue
|
|
@@ -27,7 +27,7 @@ declare class DeferBranch<BranchFn extends AnyFn, NoMatchFn extends AnyFn = AnyF
|
|
|
27
27
|
run(...args: Parameters<BranchFn>): ReturnType<BranchFn> | ReturnType<NoMatchFn> | undefined;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
declare class DeferBranchDynamic<BranchFn extends AnyFn, NoMatchFn extends AnyFn
|
|
30
|
+
declare class DeferBranchDynamic<BranchFn extends AnyFn, NoMatchFn extends AnyFn, ConditionFn extends AnyFn = Predicate<BranchFn>> {
|
|
31
31
|
/**
|
|
32
32
|
* & Compress conditions and branches into a single array since they are paired
|
|
33
33
|
*/
|
|
@@ -36,18 +36,18 @@ declare class DeferBranchDynamic<BranchFn extends AnyFn, NoMatchFn extends AnyFn
|
|
|
36
36
|
private _nomatch;
|
|
37
37
|
/**
|
|
38
38
|
* Add a new entry
|
|
39
|
-
* -
|
|
39
|
+
* - **First truthy first served**.
|
|
40
40
|
* @param condition the condition to match
|
|
41
41
|
* @param branch the branch to run when matched
|
|
42
42
|
* @returns this
|
|
43
43
|
*/
|
|
44
|
-
add(condition:
|
|
44
|
+
add(condition: ConditionFn, branch: BranchFn): this;
|
|
45
45
|
/**
|
|
46
46
|
* When calling `this.predicate` and no branch matched, run this handler
|
|
47
47
|
* @param handler handle the exhausted case
|
|
48
48
|
* @returns this
|
|
49
49
|
*/
|
|
50
|
-
nomatch(handler: AnyFn):
|
|
50
|
+
nomatch(handler: AnyFn): this;
|
|
51
51
|
/**
|
|
52
52
|
* Run the condition to find the first matched branch
|
|
53
53
|
*/
|
|
@@ -63,20 +63,36 @@ declare class DeferBranchDynamic<BranchFn extends AnyFn, NoMatchFn extends AnyFn
|
|
|
63
63
|
* ## Steps to use
|
|
64
64
|
* 1. const a = deferedBranch()
|
|
65
65
|
* 2. add branches by a.add(condition, branch)
|
|
66
|
-
* 3. add defered nomatch handler, or add and run at the same time by a.nomatch(handler)
|
|
67
|
-
* 4. run
|
|
66
|
+
* 3. (optional) add defered nomatch handler, or add and run at the same time by a.nomatch(handler)
|
|
67
|
+
* 4. ...run some other logic
|
|
68
|
+
* 5. run this branch by a.run();
|
|
69
|
+
*
|
|
70
|
+
* ## Type Annotation (optional)
|
|
71
|
+
* ```ts
|
|
72
|
+
* type BranchFn = (a: number) => void;
|
|
73
|
+
* type NoMatchFn = () => void;
|
|
74
|
+
* const a = deferedBranch<BranchFn, NoMatchFn>();
|
|
75
|
+
*
|
|
76
|
+
* // then we have restrictions:
|
|
77
|
+
* a.add(true, someFn satisfies BranchFn);
|
|
78
|
+
* a.nomatch(otherFn satisfies NoMatchFn);
|
|
79
|
+
*
|
|
80
|
+
* // some other logic
|
|
81
|
+
*
|
|
82
|
+
* a.run(...args); // input args are restricted to Parameters<BranchFn>
|
|
83
|
+
* ```
|
|
68
84
|
*
|
|
69
85
|
* ## About
|
|
70
86
|
* @package DeferedBranch
|
|
71
87
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
72
|
-
* @version 2.
|
|
88
|
+
* @version 2.1.1 (Last Update: 2025.09.21 09:04:58.051)
|
|
73
89
|
* @license MIT
|
|
74
90
|
* @link https://github.com/baendlorel/defered-branch
|
|
75
91
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
76
92
|
* @description Sometimes we need to judge something with multiple cases, but the main job should be done later. So we have Defered Branch!
|
|
77
93
|
* @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
|
|
78
94
|
*/
|
|
79
|
-
declare const deferedBranch: () => DeferBranch<
|
|
95
|
+
declare const deferedBranch: <BranchFn extends AnyFn = AnyFn, NoMatchFn extends AnyFn = AnyFn>() => DeferBranch<BranchFn, NoMatchFn>;
|
|
80
96
|
/**
|
|
81
97
|
* ## Steps to use
|
|
82
98
|
* 1. const a = deferedBranchDynamic()
|
|
@@ -86,17 +102,38 @@ declare const deferedBranch: () => DeferBranch<AnyFn, AnyFn>;
|
|
|
86
102
|
* 5. ...run some other logic
|
|
87
103
|
* 6. run this branch by a.run();
|
|
88
104
|
*
|
|
105
|
+
* ## Type Annotation (optional)
|
|
106
|
+
* ```ts
|
|
107
|
+
* type BranchFn = (a: number) => void;
|
|
108
|
+
* type NoMatchFn = () => void;
|
|
109
|
+
* // optional, you can customize the condition function type
|
|
110
|
+
* type ConditionFn = Predicate<BranchFn>;
|
|
111
|
+
* const a = deferedBranch<BranchFn, NoMatchFn, ConditionFn>();
|
|
112
|
+
*
|
|
113
|
+
* // then we have restrictions:
|
|
114
|
+
* a.add(someFn satisfies ConditionFn, secondFn satisfies BranchFn);
|
|
115
|
+
* a.nomatch(thirdFn satisfies NoMatchFn);
|
|
116
|
+
*
|
|
117
|
+
* // some other logic
|
|
118
|
+
*
|
|
119
|
+
* a.predicate(...args);
|
|
120
|
+
*
|
|
121
|
+
* // some other logic
|
|
122
|
+
*
|
|
123
|
+
* a.run(...args); // input args are restricted to Parameters<BranchFn>
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
89
126
|
* ## About
|
|
90
127
|
* @package DeferedBranch
|
|
91
128
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
92
|
-
* @version 2.
|
|
129
|
+
* @version 2.1.1 (Last Update: 2025.09.21 09:04:58.051)
|
|
93
130
|
* @license MIT
|
|
94
131
|
* @link https://github.com/baendlorel/defered-branch
|
|
95
132
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
96
133
|
* @description Sometimes we need to judge something with multiple cases, but the main job should be done later. So we have Defered Branch!
|
|
97
134
|
* @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
|
|
98
135
|
*/
|
|
99
|
-
declare const deferedBranchDynamic: () => DeferBranchDynamic<
|
|
136
|
+
declare const deferedBranchDynamic: <BranchFn extends AnyFn = AnyFn, NoMatchFn extends AnyFn = AnyFn, ConditionFn extends AnyFn = Predicate<BranchFn>>() => DeferBranchDynamic<BranchFn, NoMatchFn, ConditionFn>;
|
|
100
137
|
|
|
101
138
|
export { deferedBranch, deferedBranchDynamic };
|
|
102
139
|
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class n{t=null;h=null;add(n,t){if("function"!=typeof t)throw new TypeError("DeferBranch: branch must be a function");return n&&(this.t=t),this}nomatch(n){if("function"!=typeof n)throw new TypeError("DeferBranch: branch must be a function");return this.t||n(),this}run(...n){return this.t?this.t.apply(null,n):this.h?this.h.apply(null,n):void 0}}class t{i=[];t=null;h=null;add(n,t){if("function"!=typeof n)throw new TypeError("DeferBranch: condition must be a function");if("function"!=typeof t)throw new TypeError("DeferBranch: branch must be a function");return this.i.push(n,t),this}nomatch(n){if("function"!=typeof n)throw new TypeError("DeferBranch: handler must be a function");return this.h=n,this}predicate(...n){const t=this.i.length;for(let n=0;n<t;n+=2)if(this.i[n]())return void(this.t=this.i[n+1]);this.h?.apply(this,n)}run(...n){return this.t?.apply(this,n)}}const r=()=>new n,e=()=>new t;export{r as deferedBranch,e as deferedBranchDynamic};
|
|
1
|
+
class n{t=null;h=null;add(n,t){if("function"!=typeof t)throw new TypeError("DeferBranch: branch must be a function");return n&&!this.t&&(this.t=t),this}nomatch(n){if("function"!=typeof n)throw new TypeError("DeferBranch: branch must be a function");return this.t||n(),this}run(...n){return this.t?this.t.apply(null,n):this.h?this.h.apply(null,n):void 0}}class t{i=[];t=null;h=null;add(n,t){if("function"!=typeof n)throw new TypeError("DeferBranch: condition must be a function");if("function"!=typeof t)throw new TypeError("DeferBranch: branch must be a function");return this.i.push(n,t),this}nomatch(n){if("function"!=typeof n)throw new TypeError("DeferBranch: handler must be a function");return this.h=n,this}predicate(...n){const t=this.i.length;for(let n=0;n<t;n+=2)if(this.i[n]())return void(this.t=this.i[n+1]);this.h?.apply(this,n)}run(...n){return this.t?.apply(this,n)}}const r=()=>new n,e=()=>new t;export{r as deferedBranch,e as deferedBranchDynamic};
|