defered-branch 1.2.2 β†’ 2.0.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 CHANGED
@@ -1,111 +1,221 @@
1
- # defered-branch 🚦
2
-
3
- A tiny TypeScript/JavaScript utility for deferred branching logic.
4
- It provides a small, chainable API to register conditional branches and two kinds of "no-match" handlers: one that runs immediately when no branch was matched, and another that runs later when you call `run()`.
1
+ # Defered Branch 🌿
5
2
 
6
3
  For more awesome packages, check out [my homepageπŸ’›](https://baendlorel.github.io/?repoType=npm)
7
4
 
8
- ## Highlights ✨
5
+ > Sometimes we need to judge something with multiple cases, but the main job should be done later. So we have Defered Branch! ✨
6
+
7
+ A TypeScript/JavaScript library that provides elegant deferred conditional branching with two powerful variants: **defered-branch** for immediate execution and **defered-branch-dynamic** for reusable logic patterns.
8
+
9
+ ## πŸš€ Features
9
10
 
10
- - Chainable API for registering branches
11
- - Only the last matched branch is executed
12
- - Immediate `nomatch` handler (runs instantly when no branch matched)
13
- - Deferred `deferedNomatch` handler (runs when `run()` is invoked)
14
- - TypeScript declarations included
11
+ - 🎯 **Two Execution Models**: Choose between immediate execution or dynamic reusable logic
12
+ - πŸ”’ **Type Safe**: Full TypeScript support with proper type inference
13
+ - πŸͺΆ **Lightweight**: Zero dependencies, minimal footprint
14
+ - 🧩 **Flexible**: Works with any function signature and return types
15
+ - πŸ“¦ **ESM Ready**: Modern module system support
15
16
 
16
- ## Installation πŸ“¦
17
+ ## πŸ“¦ Installation
17
18
 
18
19
  ```bash
19
- pnpm add defered-branch
20
- # or
21
20
  npm install defered-branch
21
+ # or
22
+ pnpm add defered-branch
22
23
  ```
23
24
 
24
- ## Export / Import πŸš€
25
+ ## 🌟 When to Use Which?
26
+
27
+ ### `deferedBranch` - One-time Immediate Execution πŸƒβ€β™‚οΈ
28
+
29
+ Perfect for scenarios where you need to evaluate conditions **once** and execute immediately:
30
+
31
+ - One-time conditional flows
32
+ - Static condition evaluation
33
+
34
+ ### `deferedBranchDynamic` - Reusable Logic Patterns πŸ”„
35
+
36
+ Ideal when you need to **reuse** the same branching logic multiple times with different inputs:
25
37
 
26
- The package exports a factory named `deferedBranch` (note the spelling):
38
+ - Event handlers with varying states
39
+ - Repeated conditional logic with dynamic data
40
+ - State-dependent operations that change over time
27
41
 
28
- ```ts
42
+ ## πŸ“š Usage Examples
43
+
44
+ ### Basic deferedBranch Usage
45
+
46
+ ```typescript
29
47
  import { deferedBranch } from 'defered-branch';
48
+
49
+ // Steps to use:
50
+ // 1. Create instance
51
+ const branch = deferedBranch();
52
+
53
+ // 2. Add conditional branches
54
+ branch
55
+ .add(user.role === 'admin', () => 'Access granted to admin panel')
56
+ .add(user.role === 'user', () => 'Access granted to user dashboard')
57
+ .add(user.role === 'guest', () => 'Limited access granted');
58
+
59
+ // 3. Handle no-match case (optional)
60
+ branch.nomatch(() => 'Access denied');
61
+
62
+ // 4. Execute and get result
63
+ const result = branch.run();
64
+ console.log(result); // Output based on user.role
30
65
  ```
31
66
 
32
- ## Basic Usage
67
+ ### Advanced deferedBranch with Parameters
33
68
 
34
- ```ts
35
- import { deferedBranch } from 'defered-branch';
69
+ ```typescript
70
+ const calculator = deferedBranch<(a: number, b: number) => number>();
71
+
72
+ calculator
73
+ .add(operation === 'add', (a, b) => a + b)
74
+ .add(operation === 'multiply', (a, b) => a * b)
75
+ .add(operation === 'divide', (a, b) => a / b)
76
+ .nomatch(() => {
77
+ throw new Error('Unknown operation');
78
+ });
36
79
 
37
- // register branches - only the last matched branch will run
38
- const b = deferedBranch()
39
- .add(false, () => 'A')
40
- .add(true, () => 'B');
80
+ const result = calculator.run(10, 5); // Returns calculated result
81
+ ```
41
82
 
42
- console.log(b.run()); // 'B'
83
+ ### deferedBranchDynamic for Reusable Logic
84
+
85
+ ```typescript
86
+ import { deferedBranchDynamic } from 'defered-branch';
87
+
88
+ // Steps to use:
89
+ // 1. Create instance
90
+ const statusHandler = deferedBranchDynamic<(message: string) => void>();
91
+
92
+ // 2. Add predicate-based branches
93
+ statusHandler
94
+ .add(
95
+ () => server.status === 'online',
96
+ (msg) => logger.info(`βœ… ${msg}`)
97
+ )
98
+ .add(
99
+ () => server.status === 'maintenance',
100
+ (msg) => logger.warn(`⚠️ ${msg}`)
101
+ )
102
+ .add(
103
+ () => server.status === 'offline',
104
+ (msg) => logger.error(`❌ ${msg}`)
105
+ );
106
+
107
+ // 3. Add fallback handler
108
+ statusHandler.nomatch((msg) => logger.debug(`πŸ€” Unknown status: ${msg}`));
109
+
110
+ // 4. Use repeatedly with different conditions
111
+ statusHandler.predicate(); // Evaluates current server.status
112
+ statusHandler.run('Server health check completed');
113
+
114
+ // Later, when server.status changes...
115
+ statusHandler.predicate(); // Re-evaluates with new status
116
+ statusHandler.run('Status updated');
43
117
  ```
44
118
 
45
- ## nomatch vs deferedNomatch
119
+ ### Real-world Example: Theme Switching
120
+
121
+ ```typescript
122
+ const themeHandler = deferedBranchDynamic<() => void>();
123
+
124
+ themeHandler
125
+ .add(
126
+ () => preferences.theme === 'dark',
127
+ () => applyDarkTheme()
128
+ )
129
+ .add(
130
+ () => preferences.theme === 'light',
131
+ () => applyLightTheme()
132
+ )
133
+ .add(
134
+ () => preferences.theme === 'auto',
135
+ () => applySystemTheme()
136
+ )
137
+ .nomatch(() => {
138
+ // usually handles parameter validations
139
+ throw new TypeError('Invalid theme preference');
140
+ });
141
+
142
+ // Reuse whenever preferences change
143
+ function onConfigChange() {
144
+ themeHandler.predicate();
145
+ xxxHandler.predicate();
146
+ yyyHandler.predicate();
147
+
148
+ // some other logic...create some objects..
149
+ // some other logic...run some funtions...
150
+
151
+ themeHandler.run();
152
+ xxxHandler.run();
153
+ yyyHandler.run();
154
+ }
155
+ ```
46
156
 
47
- There are two ways to handle the case when no branch matches:
157
+ ## πŸ”§ API Reference
48
158
 
49
- - `nomatch(handler: Fn)` β€” runs the handler immediately if no branch has been matched yet. Note: if `nomatch` runs the handler immediately, later calls to `add(true, ...)` will not retroactively affect that call.
50
- - `deferedNomatch(handler: Fn)` β€” registers a handler that will be executed when `run()` is called and no branch matched.
159
+ ### deferedBranch()
51
160
 
52
- Examples:
161
+ Creates a new deferred branch instance for immediate execution scenarios.
53
162
 
54
- ```ts
55
- import { deferedBranch } from 'defered-branch';
163
+ #### Methods
56
164
 
57
- // nomatch runs immediately when invoked if no branch matched
58
- deferedBranch()
59
- .add(false, () => 'x')
60
- .nomatch(() => console.log('immediate nomatch')) // prints now
61
- .add(true, () => console.log('will not be printed')); // ignored for the already-called nomatch
165
+ ##### `.add(condition: boolean, branch: Function): DeferBranch`
62
166
 
63
- // deferedNomatch runs when run() is called
64
- const b2 = deferedBranch()
65
- .add(false, () => 'x')
66
- .deferedNomatch(() => 'deferred fallback');
167
+ - Adds a conditional branch that executes if condition is `true`
168
+ - **Overrides** previous matched branches
169
+ - Returns the instance for chaining
67
170
 
68
- console.log(b2.run()); // 'deferred fallback'
69
- ```
171
+ ##### `.nomatch(handler: Function): DeferBranch`
70
172
 
71
- ## API Reference πŸ“š
173
+ - Sets an immediate fallback handler
174
+ - **Executes instantly** if no previous branch matched
175
+ - **Ignores** later matched branches
72
176
 
73
- All functions accept a `Fn` type: `type Fn = (...args: unknown[]) => unknown`.
177
+ ##### `.run(...args): any`
74
178
 
75
- ### `deferedBranch(): DeferBranch`
179
+ - Executes the matched branch or fallback handler
180
+ - Passes arguments to the executed function
181
+ - Returns the function's return value or `undefined`
76
182
 
77
- Create a new `DeferBranch` instance.
183
+ ### deferedBranchDynamic()
78
184
 
79
- ### `add(condition: boolean, branch: Fn): DeferBranch`
185
+ Creates a new dynamic deferred branch instance for reusable logic patterns.
80
186
 
81
- Register a branch. If `condition` is true the provided `branch` becomes the current matched branch. Later `add(true, ...)` calls will override the matched branch.
187
+ #### Methods
82
188
 
83
- Throws `TypeError` if `branch` is not a function.
189
+ ##### `.add(condition: Predicate, branch: Function): DeferBranchDynamic`
84
190
 
85
- ### `nomatch(handler: Fn): DeferBranch`
191
+ - Adds a predicate-based conditional branch
192
+ - `condition` is a function that returns boolean
193
+ - **Overrides** previous matched branches
86
194
 
87
- If no branch has been matched when this is called, the `handler` is invoked immediately. This is useful for side-effects that should run right away when a branch is absent. Returns the instance for chaining. Throws `TypeError` when `handler` is not a function.
195
+ ##### `.nomatch(handler: Function): DeferBranchDynamic`
88
196
 
89
- ### `deferedNomatch(handler: Fn): DeferBranch`
197
+ - Sets a fallback handler for when no predicates match
198
+ - Executes during `.predicate()` evaluation
90
199
 
91
- Register a handler to be executed by `run()` if no branch matched. Unlike `nomatch`, this does not run immediately β€” it defers execution until `run()`.
200
+ ##### `.predicate(...args): void`
92
201
 
93
- ### `run(...args: unknown): unknown`
202
+ - Evaluates all conditions to find the first match
203
+ - Call this before `.run()` to update the matched branch
204
+ - Essential for dynamic behavior
94
205
 
95
- Execute the matched branch and return its value. If no branch matched but a `deferedNomatch` handler was set, returns the handler's return value. Returns `undefined` if neither exists.
206
+ ##### `.run(...args): any`
96
207
 
97
- `args` will be passed to the matched branch or the `deferedNomatch` handler when they are invoked.
208
+ - Executes the currently matched branch
209
+ - Returns the function's return value or `undefined`
98
210
 
99
- ## Types & Distribution
211
+ ## πŸ“„ License
100
212
 
101
- - Types are included (`"types": "./dist/index.d.ts"` in package.json).
102
- - The package entrypoint is an ESM module at `./dist/index.mjs`.
213
+ MIT License - see [LICENSE](LICENSE) file for details.
103
214
 
104
- ## Error Handling ⚠️
215
+ ## 🀝 Contributing
105
216
 
106
- - `TypeError` is thrown if a non-function is passed as a branch or handler.
217
+ Contributions are welcome! Please feel free to submit issues and pull requests.
107
218
 
108
- ## Author & License
219
+ ---
109
220
 
110
- - Author: Kasukabe Tsumugi (<futami16237@gmail.com>)
111
- - License: MIT
221
+ Made with ❀️ by [Kasukabe Tsumugi](https://github.com/baendlorel) (´q‒ α΅• ‒q`) β™‘
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- declare class DeferBranch {
1
+ declare class DeferBranch<BranchFn extends AnyFn, NoMatchFn extends AnyFn = AnyFn> {
2
2
  private _branch;
3
3
  private _nomatch;
4
4
  /**
@@ -8,42 +8,98 @@ declare class DeferBranch {
8
8
  * @param branch the branch to run when matched
9
9
  * @returns this
10
10
  */
11
- add(condition: boolean, branch: Fn): DeferBranch;
11
+ add(condition: boolean, branch: BranchFn): DeferBranch<BranchFn>;
12
12
  /**
13
- * When no branch matched, run this handler
14
- * - This will be called **instantly** and **ignores later matched branches**
13
+ * Register a handler to be called when no branch matched
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: Fn): DeferBranch;
18
+ nomatch(handler: AnyFn): DeferBranch<BranchFn>;
19
19
  /**
20
- * When no branch matched, run this handler
21
- * - Will be called when `run()` is called
20
+ * If some branch matched, return its returnValue
21
+ * - if no branch matched, return the nomatch handler's returnValue
22
+ * - if no branch matched and no nomatch handler, return undefined
23
+ *
24
+ * > Note: Although args are for the matched branch, they will also be passed to nomatch handler
25
+ * @param args arguments to pass to the matched branch or nomatch handler
26
+ */
27
+ run(...args: Parameters<BranchFn>): ReturnType<BranchFn> | ReturnType<NoMatchFn> | undefined;
28
+ }
29
+
30
+ declare class DeferBranchDynamic<BranchFn extends AnyFn, NoMatchFn extends AnyFn = AnyFn> {
31
+ /**
32
+ * & Compress conditions and branches into a single array since they are paired
33
+ */
34
+ private _condranches;
35
+ private _branch;
36
+ private _nomatch;
37
+ /**
38
+ * Add a new entry
39
+ * - will **override** the previous matched branch
40
+ * @param condition the condition to match
41
+ * @param branch the branch to run when matched
42
+ * @returns this
43
+ */
44
+ add(condition: Predicate<BranchFn>, branch: BranchFn): DeferBranchDynamic<BranchFn, NoMatchFn>;
45
+ /**
46
+ * When calling `this.predicate` and no branch matched, run this handler
22
47
  * @param handler handle the exhausted case
23
48
  * @returns this
24
49
  */
25
- deferedNomatch(handler: Fn): DeferBranch;
50
+ nomatch(handler: AnyFn): DeferBranchDynamic<BranchFn, NoMatchFn>;
51
+ /**
52
+ * Run the condition to find the first matched branch
53
+ */
54
+ predicate(...args: Parameters<BranchFn>): void;
26
55
  /**
27
56
  * If some branch matched, return its returnValue
28
- * - if no branch matched, return the nomatch handler returnValue
29
- * - if no branch matched and no nomatch handler, return undefined
30
- * @param args arguments to pass to the matched branch or nomatch handler
57
+ * @param args arguments to pass to the matched branch
31
58
  */
32
- run(...args: unknown[]): unknown;
59
+ run(...args: Parameters<BranchFn>): ReturnType<BranchFn> | undefined;
33
60
  }
61
+
62
+ /**
63
+ * ## Steps to use
64
+ * 1. const a = deferedBranch()
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 this branch by a.run();
68
+ *
69
+ * ## About
70
+ * @package DeferedBranch
71
+ * @author Kasukabe Tsumugi <futami16237@gmail.com>
72
+ * @version 2.0.0 (Last Update: 2025.09.20 21:23:15.798)
73
+ * @license MIT
74
+ * @link https://github.com/baendlorel/defered-branch
75
+ * @link https://baendlorel.github.io/ Welcome to my site!
76
+ * @description Sometimes we need to judge something with multiple cases, but the main job should be done later. So we have Defered Branch!
77
+ * @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
78
+ */
79
+ declare const deferedBranch: () => DeferBranch<AnyFn, AnyFn>;
34
80
  /**
81
+ * ## Steps to use
82
+ * 1. const a = deferedBranchDynamic()
83
+ * 2. add branches by a.add(condition, branch)
84
+ * 3. add nomatch handler by a.nomatch(handler)
85
+ * 4. call a.predicate(...) to find the matched branch
86
+ * 5. ...run some other logic
87
+ * 6. run this branch by a.run();
88
+ *
35
89
  * ## About
36
90
  * @package DeferedBranch
37
91
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
38
- * @version 1.2.2 (Last Update: 2025.09.19 08:09:05.967)
92
+ * @version 2.0.0 (Last Update: 2025.09.20 21:23:15.798)
39
93
  * @license MIT
40
94
  * @link https://github.com/baendlorel/defered-branch
95
+ * @link https://baendlorel.github.io/ Welcome to my site!
41
96
  * @description Sometimes we need to judge something with multiple cases, but the main job should be done later. So we have Defered Branch!
42
97
  * @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
43
98
  */
44
- declare const deferedBranch: () => DeferBranch;
99
+ declare const deferedBranchDynamic: () => DeferBranchDynamic<AnyFn, AnyFn>;
45
100
 
46
- export { deferedBranch };
101
+ export { deferedBranch, deferedBranchDynamic };
47
102
 
48
103
  // # from: src/global.d.ts
49
- type Fn = (...args: any[]) => any;
104
+ type AnyFn = (...args: any[]) => any;
105
+ type Predicate<Fn extends AnyFn> = (...args: Parameters<Fn>) => boolean;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- class t{t=null;o=null;add(t,n){if("function"!=typeof n)throw new TypeError("Branch must be a function");return t&&(this.t=n),this}nomatch(t){if("function"!=typeof t)throw new TypeError("Branch must be a function");return this.t||t(),this}deferedNomatch(t){if("function"!=typeof t)throw new TypeError("Branch must be a function");return this.o=t,this}run(...t){return this.t?this.t(...t):this.o?this.o(...t):void 0}}const n=()=>new t;export{n as deferedBranch};
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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "defered-branch",
3
- "version": "1.2.2",
3
+ "version": "2.0.0",
4
4
  "author": {
5
5
  "name": "Kasukabe Tsumugi",
6
6
  "email": "futami16237@gmail.com"