promise-logic 2.4.3 → 2.4.4
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 +164 -237
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,300 +1,227 @@
|
|
|
1
|
+
# Promise Logic - A Declarative Promise Library Based on Logic Gates
|
|
1
2
|
|
|
2
|
-
|
|
3
|
+
This description might sound a bit awkward, but it essentially means a Promise wrapper library designed based on the concept of logic gates, providing a more declarative syntax. However, promiseLogic's implementation is based on promises, so we can say it's a promise-based wrapper library.
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
This design is really interesting. I spent a lot of time thinking about it and realized that promise state machines ultimately have only two outcomes: either fulfilled or rejected. This state design can be abstracted using boolean operations, allowing for declarative writing that reduces our memory burden and mental load during development. Let's look at some examples.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Installation:
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
- **Dual Entry Points**: Choose between JavaScript or enhanced TypeScript experience
|
|
10
|
-
- **Type Safety**: Complete TypeScript definitions with strict type checking
|
|
11
|
-
- **Promise Utilities**: Additional utilities like Flip-Flop state management
|
|
12
|
-
- **Zero Dependencies**: Pure JavaScript/TypeScript implementation
|
|
13
|
-
- **Tree Shakeable**: Optimized for modern bundlers
|
|
14
|
-
|
|
15
|
-
## Recent Updates
|
|
16
|
-
|
|
17
|
-
### Version 2.3.2 Highlights
|
|
18
|
-
|
|
19
|
-
**🚀 NOT Gate Implementation**
|
|
20
|
-
Introduced the NOT logic gate for promise inversion, enabling flexible negation patterns in asynchronous workflows:
|
|
21
|
-
|
|
22
|
-
```javascript
|
|
23
|
-
// Success -> Failure transformation
|
|
24
|
-
await PromiseLogic.not(Promise.resolve('success')); // Rejects with 'success'
|
|
25
|
-
|
|
26
|
-
// Failure -> Success transformation
|
|
27
|
-
const result = await PromiseLogic.not(Promise.reject('error')); // Resolves with 'error'
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**📦 Enhanced TypeScript System**
|
|
31
|
-
Completely revamped TypeScript architecture with:
|
|
32
|
-
- Full generic type propagation
|
|
33
|
-
- Strict type checking with zero `any` types
|
|
34
|
-
- Advanced type inference for all operations
|
|
35
|
-
- Seamless IDE integration with IntelliSense
|
|
36
|
-
|
|
37
|
-
**⚡ Performance Optimizations**
|
|
38
|
-
- Optimized internal logic for better efficiency
|
|
39
|
-
- Reduced memory overhead in gate operations
|
|
40
|
-
- Improved error handling and edge case management
|
|
41
|
-
|
|
42
|
-
**📚 Documentation Enhancements**
|
|
43
|
-
- Comprehensive API reference with TypeScript examples
|
|
44
|
-
- Better usage guidelines and best practices
|
|
45
|
-
- Clear entry point documentation for different environments
|
|
46
|
-
|
|
47
|
-
## Installation
|
|
9
|
+
npm:
|
|
48
10
|
|
|
49
11
|
```bash
|
|
50
12
|
npm install promise-logic
|
|
51
13
|
```
|
|
52
14
|
|
|
53
|
-
## Quick Start
|
|
54
|
-
|
|
55
|
-
### JavaScript (Default)
|
|
56
|
-
|
|
57
15
|
```javascript
|
|
58
|
-
|
|
59
|
-
import { PromiseLogic } from 'promise-logic';
|
|
60
|
-
|
|
61
|
-
// CommonJS
|
|
62
|
-
const { PromiseLogic } = require('promise-logic');
|
|
63
|
-
|
|
64
|
-
// Use logic gates
|
|
65
|
-
const results = await PromiseLogic.and([
|
|
66
|
-
Promise.resolve('data1'),
|
|
67
|
-
Promise.resolve('data2')
|
|
68
|
-
]);
|
|
69
|
-
// results = ['data1', 'data2']
|
|
70
|
-
```
|
|
16
|
+
import PromiseLogic from 'promise-logic';
|
|
71
17
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
// TypeScript version with full type inference
|
|
76
|
-
import { PromiseLogic } from 'promise-logic/typescript';
|
|
77
|
-
|
|
78
|
-
// Type-safe operations with automatic inference
|
|
79
|
-
const numbers = await PromiseLogic.and<number>([
|
|
18
|
+
// Native Promise
|
|
19
|
+
const promise = Promise.all([
|
|
80
20
|
Promise.resolve(1),
|
|
81
|
-
Promise.resolve(2)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const strings = await PromiseLogic.or<string>([
|
|
85
|
-
Promise.resolve('hello'),
|
|
86
|
-
Promise.resolve('world')
|
|
87
|
-
]);
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Core Logic Gates
|
|
91
|
-
|
|
92
|
-
### `and(promises)`
|
|
93
|
-
Resolves with all values when all promises fulfill. Equivalent to `Promise.all()`.
|
|
21
|
+
Promise.resolve(2),
|
|
22
|
+
Promise.resolve(3)
|
|
23
|
+
]);
|
|
94
24
|
|
|
95
|
-
|
|
96
|
-
const
|
|
25
|
+
// Promise Logic -- AND gate
|
|
26
|
+
const promiseLogic = PromiseLogic.and([
|
|
97
27
|
Promise.resolve(1),
|
|
98
28
|
Promise.resolve(2),
|
|
99
29
|
Promise.resolve(3)
|
|
100
|
-
]);
|
|
101
|
-
// results = [1, 2, 3]
|
|
102
|
-
```
|
|
30
|
+
]); // [1,2,3]
|
|
103
31
|
|
|
104
|
-
|
|
105
|
-
Resolves with the first fulfilled promise. Equivalent to `Promise.any()`.
|
|
32
|
+
// This syntax is more semantic, easier to understand, reduces team communication costs, and is more friendly to learners
|
|
106
33
|
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
Promise.
|
|
110
|
-
Promise.
|
|
111
|
-
|
|
112
|
-
//
|
|
113
|
-
```
|
|
34
|
+
// Native promise
|
|
35
|
+
const promise = Promise.any([
|
|
36
|
+
Promise.resolve(1),
|
|
37
|
+
Promise.reject(2),
|
|
38
|
+
Promise.resolve(3)
|
|
39
|
+
]); // 1
|
|
114
40
|
|
|
115
|
-
|
|
116
|
-
|
|
41
|
+
// Promise Logic -- OR gate
|
|
42
|
+
const promiseLogicOr = PromiseLogic.or([
|
|
43
|
+
Promise.resolve(1),
|
|
44
|
+
Promise.reject(2),
|
|
45
|
+
Promise.resolve(3)
|
|
46
|
+
]); // 1
|
|
117
47
|
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
const result = await PromiseLogic.xor([
|
|
121
|
-
Promise.reject('error1'),
|
|
122
|
-
Promise.resolve('success'),
|
|
123
|
-
Promise.reject('error2')
|
|
124
|
-
]);
|
|
125
|
-
// result = 'success'
|
|
126
|
-
} catch (error) {
|
|
127
|
-
// Throws if zero or multiple promises fulfill
|
|
128
|
-
}
|
|
48
|
+
// The result of or is consistent with native promise.any, but from here, I think you should see the pattern, and there's more to it
|
|
129
49
|
```
|
|
130
50
|
|
|
131
|
-
|
|
132
|
-
Not AND - resolves when not all promises fulfill.
|
|
51
|
+
It also supports TypeScript syntax:
|
|
133
52
|
|
|
134
53
|
```javascript
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
]
|
|
139
|
-
|
|
54
|
+
const promiseLogic =
|
|
55
|
+
PromiseLogic.and <
|
|
56
|
+
number >
|
|
57
|
+
[Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]; // [1,2,3]
|
|
58
|
+
|
|
59
|
+
const promiseLogicOr =
|
|
60
|
+
PromiseLogic.or <
|
|
61
|
+
string >
|
|
62
|
+
[
|
|
63
|
+
Promise.resolve('data 1'),
|
|
64
|
+
Promise.reject('error 2'),
|
|
65
|
+
Promise.resolve('data 3')
|
|
66
|
+
]; // 'data 1'
|
|
140
67
|
```
|
|
141
68
|
|
|
142
|
-
|
|
143
|
-
Not OR - resolves only when all promises reject.
|
|
69
|
+
#### We can also create flexible combinations for complex request resources
|
|
144
70
|
|
|
145
71
|
```javascript
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
Promise.reject('error2')
|
|
149
|
-
]);
|
|
150
|
-
// results = []
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### `xnor(promises)`
|
|
154
|
-
Exclusive NOR - resolves when all promises have the same outcome.
|
|
72
|
+
// OR + AND
|
|
73
|
+
// Suppose we have a scenario where we want to get data from multiple data sources, need the fastest request result, but also need all requests in one request group to succeed before returning a result. Implementing this with native Promise would be extremely complex
|
|
155
74
|
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
//
|
|
75
|
+
// Now we can implement it like this:
|
|
76
|
+
const result = await PromiseLogic.or([
|
|
77
|
+
PromiseLogic.and([
|
|
78
|
+
// Request group 1
|
|
79
|
+
fetch('/api/data1'), // Request 1
|
|
80
|
+
fetch('/api/data2') // Request 2
|
|
81
|
+
]),
|
|
82
|
+
PromiseLogic.and([
|
|
83
|
+
// Request group 2
|
|
84
|
+
fetch('/api/data3'), // Request 3
|
|
85
|
+
fetch('/api/data4') // Request 4
|
|
86
|
+
])
|
|
87
|
+
]); // Result: [fetch('/api/data1'),fetch('/api/data2')] or [fetch('/api/data3'),fetch('/api/data4')] or error
|
|
88
|
+
|
|
89
|
+
// This returns the fastest successful result, and this successful result must come from a request group where all requests in the AND combination have succeeded
|
|
162
90
|
```
|
|
163
91
|
|
|
164
|
-
|
|
165
|
-
Resolves when majority (>50%) of promises fulfill.
|
|
166
|
-
|
|
167
|
-
```javascript
|
|
168
|
-
const results = await PromiseLogic.majority([
|
|
169
|
-
Promise.resolve('a'),
|
|
170
|
-
Promise.resolve('b'),
|
|
171
|
-
Promise.reject('error')
|
|
172
|
-
]);
|
|
173
|
-
// results = ['a', 'b']
|
|
174
|
-
```
|
|
92
|
+
Of course, there are other logic gates like exclusive OR, NAND, NOR, XNOR, majority, etc. Their implementations are all very simple, so I won't introduce them one by one. They all use the same pattern but have different logical semantics, so you can choose which one to use based on your scenario.
|
|
175
93
|
|
|
176
|
-
|
|
94
|
+
#### `PromiseLogic.xor`
|
|
177
95
|
|
|
178
|
-
|
|
179
|
-
Inverts promise resolution - successful promises become rejections, and vice versa.
|
|
96
|
+
#### `PromiseLogic.majority`
|
|
180
97
|
|
|
181
|
-
|
|
182
|
-
// Success -> Failure
|
|
183
|
-
try {
|
|
184
|
-
await PromiseLogic.not(Promise.resolve('success'));
|
|
185
|
-
} catch (error) {
|
|
186
|
-
console.log(error); // 'success'
|
|
187
|
-
}
|
|
98
|
+
#### `PromiseLogic.nor`
|
|
188
99
|
|
|
189
|
-
|
|
190
|
-
const result = await PromiseLogic.not(Promise.reject('error'));
|
|
191
|
-
console.log(result); // 'error'
|
|
192
|
-
```
|
|
100
|
+
#### `PromiseLogic.xnor`
|
|
193
101
|
|
|
194
|
-
|
|
195
|
-
- Transform error handling patterns
|
|
196
|
-
- Create conditional promise flows
|
|
197
|
-
- Implement retry logic with inverted conditions
|
|
198
|
-
- Build fallback mechanisms
|
|
102
|
+
#### `PromiseLogic.nand`
|
|
199
103
|
|
|
200
|
-
|
|
104
|
+
#### `PromiseLogic.not`
|
|
201
105
|
|
|
202
|
-
|
|
203
|
-
Equivalent to `Promise.race()`.
|
|
106
|
+
We've kept the native methods for more straightforward usage:
|
|
204
107
|
|
|
205
|
-
|
|
206
|
-
|
|
108
|
+
- `PromiseLogic.allSettled`
|
|
109
|
+
- `PromiseLogic.race`
|
|
207
110
|
|
|
208
|
-
### `
|
|
209
|
-
Resolves with all fulfilled values, ignoring rejections.
|
|
111
|
+
### `PromiseLogic.createFlipFlop` - Async Boolean Flip-Flop
|
|
210
112
|
|
|
211
|
-
|
|
212
|
-
Resolves with all rejection reasons, ignoring fulfillments.
|
|
113
|
+
This is used to create a stateful flip-flop for managing boolean states in asynchronous operations. You might be wondering why, but let's continue:
|
|
213
114
|
|
|
214
|
-
|
|
215
|
-
Creates a stateful flip-flop for managing boolean state across async operations.
|
|
115
|
+
Here's how to use this flip-flop to manage connection states:
|
|
216
116
|
|
|
217
117
|
```javascript
|
|
218
|
-
const
|
|
118
|
+
const connectionState = PromiseLogic.createFlipFlop(false);
|
|
119
|
+
|
|
120
|
+
// Managing device connection state
|
|
121
|
+
class ConnectionManager {
|
|
122
|
+
constructor() {
|
|
123
|
+
this.connectionState = PromiseLogic.createFlipFlop(false); // Initial disconnected state
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async connect() {
|
|
127
|
+
console.log('Connecting...');
|
|
128
|
+
// Simulate connection process
|
|
129
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
130
|
+
await this.connectionState.set(true); // Set connected state
|
|
131
|
+
console.log('Connected!');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async disconnect() {
|
|
135
|
+
console.log('Disconnecting...');
|
|
136
|
+
await this.connectionState.set(false); // Set disconnected state
|
|
137
|
+
console.log('Disconnected!');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async waitForConnection() {
|
|
141
|
+
console.log('Waiting for connection...');
|
|
142
|
+
await this.connectionState.waitFor(true); // Wait until connected
|
|
143
|
+
console.log('Connection established!');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async monitorConnection() {
|
|
147
|
+
// Monitor state changes
|
|
148
|
+
while (true) {
|
|
149
|
+
const newState = await this.connectionState.waitForChange();
|
|
150
|
+
console.log('Connection state changed to:', newState ? 'connected' : 'disconnected');
|
|
151
|
+
if (!newState) break; // Exit if disconnected
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
219
155
|
|
|
220
|
-
//
|
|
221
|
-
|
|
156
|
+
// Usage
|
|
157
|
+
const manager = new ConnectionManager();
|
|
222
158
|
|
|
223
|
-
//
|
|
224
|
-
|
|
225
|
-
console.log(flipFlop.getState()); // true
|
|
159
|
+
// Start monitoring in background
|
|
160
|
+
manager.monitorConnection();
|
|
226
161
|
|
|
227
|
-
//
|
|
228
|
-
await
|
|
162
|
+
// Connect and wait
|
|
163
|
+
await manager.connect();
|
|
164
|
+
await manager.waitForConnection();
|
|
229
165
|
|
|
230
|
-
//
|
|
231
|
-
setTimeout(() =>
|
|
232
|
-
await
|
|
166
|
+
// Disconnect after 2 seconds
|
|
167
|
+
setTimeout(async () => {
|
|
168
|
+
await manager.disconnect();
|
|
169
|
+
}, 2000);
|
|
233
170
|
```
|
|
234
171
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
The TypeScript version (`promise-logic/typescript`) provides:
|
|
238
|
-
|
|
239
|
-
- **Full Type Inference**: Automatic type deduction for all operations
|
|
240
|
-
- **Strict Type Checking**: Zero `any` types, complete type safety
|
|
241
|
-
- **IDE Support**: Enhanced IntelliSense and code completion
|
|
242
|
-
- **Generic Type Propagation**: Proper handling of complex generic scenarios
|
|
172
|
+
This is because in asynchronous operations, we often need to make decisions and execute subsequent operations based on a certain state, and this flip-flop can help us manage this state in asynchronous operations.
|
|
243
173
|
|
|
244
|
-
|
|
245
|
-
import { PromiseLogic } from 'promise-logic/typescript';
|
|
174
|
+
API
|
|
246
175
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
Promise.resolve({ id: 1, name: 'Alice' }),
|
|
250
|
-
Promise.resolve({ id: 2, name: 'Bob' })
|
|
251
|
-
]);
|
|
252
|
-
// result type: Array<{ id: number, name: string }>
|
|
253
|
-
|
|
254
|
-
// Complex generic types work seamlessly
|
|
255
|
-
async function processPromises<T>(promises: Promise<T>[]): Promise<T[]> {
|
|
256
|
-
return await PromiseLogic.and(promises);
|
|
257
|
-
}
|
|
176
|
+
```javascript
|
|
177
|
+
PromiseLogic.createFlipFlop(initialState);
|
|
258
178
|
```
|
|
259
179
|
|
|
260
|
-
|
|
180
|
+
**Parameters:**
|
|
261
181
|
|
|
262
|
-
|
|
263
|
-
|------------|---------|----------------|
|
|
264
|
-
| `promise-logic` | Default JavaScript version | General use, mixed codebases |
|
|
265
|
-
| `promise-logic/typescript` | Enhanced TypeScript version | TypeScript projects, strict type safety |
|
|
182
|
+
- `initialState` (boolean, optional): Initial state, default value is `false`
|
|
266
183
|
|
|
267
|
-
|
|
184
|
+
**Returns:**
|
|
185
|
+
An object with the following methods:
|
|
268
186
|
|
|
269
|
-
|
|
187
|
+
- `getState()`: Returns the current boolean state
|
|
188
|
+
- `set(newState: boolean)`: Sets the new state and returns Promise<boolean>
|
|
189
|
+
- `toggle()`: Toggles the current state and returns Promise<boolean>
|
|
190
|
+
- `waitForChange()`: Returns a Promise that resolves when the state changes
|
|
191
|
+
- `waitFor(targetState: boolean)`: Returns a Promise that resolves when the state matches the target
|
|
270
192
|
|
|
271
|
-
|
|
193
|
+
### `createPromiseLogic(options)`
|
|
272
194
|
|
|
273
|
-
|
|
274
|
-
# Install dependencies
|
|
275
|
-
npm install
|
|
276
|
-
|
|
277
|
-
# Build the project
|
|
278
|
-
npm run build
|
|
279
|
-
|
|
280
|
-
# Run tests
|
|
281
|
-
npm test
|
|
282
|
-
|
|
283
|
-
# Run tests in watch mode
|
|
284
|
-
npm run test:watch
|
|
195
|
+
Creates a customizable object containing PromiseLogic methods with configurable naming.
|
|
285
196
|
|
|
286
|
-
|
|
287
|
-
npm run test:coverage
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
## Contributing
|
|
197
|
+
**Parameters:**
|
|
291
198
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
5. Submit a pull request
|
|
199
|
+
- `options` (object, optional): Configuration options
|
|
200
|
+
- `prefix` (string, optional): String to prepend to all method names
|
|
201
|
+
- `suffix` (string, optional): String to append to all method names
|
|
202
|
+
- `rename` (Record<string, string>, optional): Mapping of original method names to new names
|
|
297
203
|
|
|
298
|
-
|
|
204
|
+
**Returns:**
|
|
205
|
+
An object containing PromiseLogic methods with customized names.
|
|
299
206
|
|
|
300
|
-
|
|
207
|
+
```javascript
|
|
208
|
+
// Basic usage - returns all methods with default names
|
|
209
|
+
const logic = createPromiseLogic();
|
|
210
|
+
|
|
211
|
+
// Combined options
|
|
212
|
+
const combined = createPromiseLogic({
|
|
213
|
+
prefix: 'async', // Add prefix
|
|
214
|
+
suffix: 'Op', // Add suffix
|
|
215
|
+
rename: {
|
|
216
|
+
// API renaming
|
|
217
|
+
and: 'Conjunction',
|
|
218
|
+
or: 'Disjunction'
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Call combined method (async)+ (Conjunction) + (Op)
|
|
223
|
+
const result = await logic.asycnConjunctionOp([
|
|
224
|
+
fetch('/api/data1'),
|
|
225
|
+
fetch('/api/data2')
|
|
226
|
+
]);
|
|
227
|
+
```
|
package/package.json
CHANGED