@satoshibits/functional 1.0.2
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 +242 -0
- package/dist/array-utils.d.mts +317 -0
- package/dist/array-utils.d.mts.map +1 -0
- package/dist/array-utils.mjs +370 -0
- package/dist/array-utils.mjs.map +1 -0
- package/dist/composition.d.mts +603 -0
- package/dist/composition.d.mts.map +1 -0
- package/dist/composition.mjs +516 -0
- package/dist/composition.mjs.map +1 -0
- package/dist/object-utils.d.mts +267 -0
- package/dist/object-utils.d.mts.map +1 -0
- package/dist/object-utils.mjs +258 -0
- package/dist/object-utils.mjs.map +1 -0
- package/dist/option.d.mts +622 -0
- package/dist/option.d.mts.map +1 -0
- package/dist/option.mjs +637 -0
- package/dist/option.mjs.map +1 -0
- package/dist/performance.d.mts +265 -0
- package/dist/performance.d.mts.map +1 -0
- package/dist/performance.mjs +453 -0
- package/dist/performance.mjs.map +1 -0
- package/dist/pipeline.d.mts +431 -0
- package/dist/pipeline.d.mts.map +1 -0
- package/dist/pipeline.mjs +460 -0
- package/dist/pipeline.mjs.map +1 -0
- package/dist/predicates.d.mts +722 -0
- package/dist/predicates.d.mts.map +1 -0
- package/dist/predicates.mjs +802 -0
- package/dist/predicates.mjs.map +1 -0
- package/dist/reader-result.d.mts +422 -0
- package/dist/reader-result.d.mts.map +1 -0
- package/dist/reader-result.mjs +758 -0
- package/dist/reader-result.mjs.map +1 -0
- package/dist/result.d.mts +684 -0
- package/dist/result.d.mts.map +1 -0
- package/dist/result.mjs +814 -0
- package/dist/result.mjs.map +1 -0
- package/dist/types.d.mts +439 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +191 -0
- package/dist/types.mjs.map +1 -0
- package/dist/validation.d.mts +622 -0
- package/dist/validation.d.mts.map +1 -0
- package/dist/validation.mjs +852 -0
- package/dist/validation.mjs.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module performance
|
|
3
|
+
* @description Functional utilities for optimizing performance through timing control,
|
|
4
|
+
* batching, and caching. These utilities help manage expensive operations
|
|
5
|
+
* and prevent performance issues in applications. All utilities are designed
|
|
6
|
+
* to be composable and work well with functional programming patterns.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { debounce, throttle, batch, cache, Performance } from './performance.mts';
|
|
11
|
+
*
|
|
12
|
+
* // debounce user input
|
|
13
|
+
* const search = debounce((query: string) => {
|
|
14
|
+
* performSearch(query);
|
|
15
|
+
* }, 300);
|
|
16
|
+
*
|
|
17
|
+
* // throttle scroll events
|
|
18
|
+
* const handleScroll = throttle(() => {
|
|
19
|
+
* updateScrollPosition();
|
|
20
|
+
* }, 100);
|
|
21
|
+
*
|
|
22
|
+
* // batch API calls
|
|
23
|
+
* const saveItem = batch<Item>(async (items) => {
|
|
24
|
+
* await api.saveMany(items);
|
|
25
|
+
* }, { maxSize: 100, maxWait: 1000 });
|
|
26
|
+
*
|
|
27
|
+
* // cache expensive computations
|
|
28
|
+
* const fibonacci = cache((n: number): number => {
|
|
29
|
+
* if (n <= 1) return n;
|
|
30
|
+
* return fibonacci(n - 1) + fibonacci(n - 2);
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @category Performance
|
|
35
|
+
* @since 2025-07-03
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* Debounce function execution.
|
|
39
|
+
* @description Delays invoking the function until after the specified delay has elapsed
|
|
40
|
+
* since the last time it was invoked. Useful for expensive operations triggered
|
|
41
|
+
* by user input like search or resize events. Each new call resets the timer.
|
|
42
|
+
*
|
|
43
|
+
* @template T - The types of the function arguments
|
|
44
|
+
* @param {function(...T): void} fn - The function to debounce
|
|
45
|
+
* @param {number} delay - The delay in milliseconds
|
|
46
|
+
* @returns {function(...T): void} The debounced function
|
|
47
|
+
*
|
|
48
|
+
* @category Timing
|
|
49
|
+
* @example
|
|
50
|
+
* // Basic debounce
|
|
51
|
+
* const saveChanges = debounce((text: string) => {
|
|
52
|
+
* console.log('Saving:', text);
|
|
53
|
+
* }, 1000);
|
|
54
|
+
*
|
|
55
|
+
* saveChanges('H');
|
|
56
|
+
* saveChanges('He');
|
|
57
|
+
* saveChanges('Hello'); // Only this will execute after 1 second
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* // Search input debouncing
|
|
61
|
+
* const searchInput = document.getElementById('search');
|
|
62
|
+
* const performSearch = debounce((query: string) => {
|
|
63
|
+
* fetch(`/api/search?q=${query}`)
|
|
64
|
+
* .then(res => res.json())
|
|
65
|
+
* .then(results => displayResults(results));
|
|
66
|
+
* }, 300);
|
|
67
|
+
*
|
|
68
|
+
* searchInput.addEventListener('input', (e) => {
|
|
69
|
+
* performSearch(e.target.value);
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* // Window resize handler
|
|
74
|
+
* const handleResize = debounce(() => {
|
|
75
|
+
* const width = window.innerWidth;
|
|
76
|
+
* const height = window.innerHeight;
|
|
77
|
+
* console.log(`Resized to ${width}x${height}`);
|
|
78
|
+
* recalculateLayout();
|
|
79
|
+
* }, 250);
|
|
80
|
+
*
|
|
81
|
+
* window.addEventListener('resize', handleResize);
|
|
82
|
+
*
|
|
83
|
+
* @see throttle - Limit execution rate without delaying
|
|
84
|
+
* @since 2025-07-03
|
|
85
|
+
*/
|
|
86
|
+
export declare const debounce: <T extends any[]>(fn: (...args: T) => void, delay: number) => ((...args: T) => void);
|
|
87
|
+
/**
|
|
88
|
+
* Throttle function execution.
|
|
89
|
+
* @description Ensures the function is called at most once per specified time period.
|
|
90
|
+
* Unlike debounce, throttle guarantees regular execution for continuous events.
|
|
91
|
+
* The first call is executed immediately, then subsequent calls are rate-limited.
|
|
92
|
+
*
|
|
93
|
+
* @template T - The types of the function arguments
|
|
94
|
+
* @param {function(...T): void} fn - The function to throttle
|
|
95
|
+
* @param {number} delay - The minimum delay between calls in milliseconds
|
|
96
|
+
* @returns {function(...T): void} The throttled function
|
|
97
|
+
*
|
|
98
|
+
* @category Timing
|
|
99
|
+
* @example
|
|
100
|
+
* // Basic throttle
|
|
101
|
+
* const logScroll = throttle(() => {
|
|
102
|
+
* console.log('Scroll position:', window.scrollY);
|
|
103
|
+
* }, 100);
|
|
104
|
+
*
|
|
105
|
+
* window.addEventListener('scroll', logScroll);
|
|
106
|
+
* // Logs at most once every 100ms during scrolling
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* // API rate limiting
|
|
110
|
+
* const trackEvent = throttle((event: string, data: any) => {
|
|
111
|
+
* fetch('/api/analytics', {
|
|
112
|
+
* method: 'POST',
|
|
113
|
+
* body: JSON.stringify({ event, data, timestamp: Date.now() })
|
|
114
|
+
* });
|
|
115
|
+
* }, 1000);
|
|
116
|
+
*
|
|
117
|
+
* // Won't exceed 1 request per second
|
|
118
|
+
* button.addEventListener('click', () => trackEvent('button_click', { id: 'submit' }));
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* // Game loop or animation
|
|
122
|
+
* const updateGame = throttle(() => {
|
|
123
|
+
* player.updatePosition();
|
|
124
|
+
* enemies.forEach(e => e.update());
|
|
125
|
+
* renderer.draw();
|
|
126
|
+
* }, 16); // ~60 FPS
|
|
127
|
+
*
|
|
128
|
+
* setInterval(updateGame, 0);
|
|
129
|
+
*
|
|
130
|
+
* @see debounce - Delay execution until activity stops
|
|
131
|
+
* @since 2025-07-03
|
|
132
|
+
*/
|
|
133
|
+
export declare const throttle: <T extends any[], R>(fn: (...args: T) => R, limit: number) => ((...args: T) => R | undefined);
|
|
134
|
+
/**
|
|
135
|
+
* Batch async operations to avoid overwhelming external services.
|
|
136
|
+
* @description Processes items in chunks with optional delays between batches.
|
|
137
|
+
* Essential for rate-limited APIs or resource-intensive operations.
|
|
138
|
+
* Executes operations in parallel within each batch but sequential between batches.
|
|
139
|
+
*
|
|
140
|
+
* @template T - The type of items to process
|
|
141
|
+
* @template R - The type of results
|
|
142
|
+
* @param {T[]} items - Array of items to process
|
|
143
|
+
* @param {function(T): Promise<R>} fn - Async function to process each item
|
|
144
|
+
* @param {number} batchSize - Maximum number of items to process in parallel
|
|
145
|
+
* @param {number} [delayMs=0] - Delay in milliseconds between batches
|
|
146
|
+
* @returns {Promise<R[]>} Array of results in the same order as input
|
|
147
|
+
*
|
|
148
|
+
* @category Batching
|
|
149
|
+
* @example
|
|
150
|
+
* // Basic batch processing
|
|
151
|
+
* const userIds = Array.from({ length: 100 }, (_, i) => i + 1);
|
|
152
|
+
* const fetchUser = async (id: number) => {
|
|
153
|
+
* const res = await fetch(`/api/users/${id}`);
|
|
154
|
+
* return res.json();
|
|
155
|
+
* };
|
|
156
|
+
*
|
|
157
|
+
* const users = await batchAsync(userIds, fetchUser, 10, 100);
|
|
158
|
+
* // Fetches 10 users at a time with 100ms delay between batches
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* // Email sending with rate limits
|
|
162
|
+
* const recipients = [
|
|
163
|
+
* { email: 'user1@example.com', name: 'User 1' },
|
|
164
|
+
* { email: 'user2@example.com', name: 'User 2' },
|
|
165
|
+
* // ... many more
|
|
166
|
+
* ];
|
|
167
|
+
*
|
|
168
|
+
* const sendEmail = async (recipient: typeof recipients[0]) => {
|
|
169
|
+
* return await emailService.send({
|
|
170
|
+
* to: recipient.email,
|
|
171
|
+
* subject: 'Newsletter',
|
|
172
|
+
* body: `Hello ${recipient.name}!`
|
|
173
|
+
* });
|
|
174
|
+
* };
|
|
175
|
+
*
|
|
176
|
+
* // Send 20 emails per batch with 1 second delay (rate limit compliance)
|
|
177
|
+
* const results = await batchAsync(recipients, sendEmail, 20, 1000);
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* // Image processing
|
|
181
|
+
* const imageUrls = ['img1.jpg', 'img2.jpg', // ... more images, 'img100.jpg'];
|
|
182
|
+
*
|
|
183
|
+
* const processImage = async (url: string) => {
|
|
184
|
+
* const img = await loadImage(url);
|
|
185
|
+
* const processed = await applyFilters(img);
|
|
186
|
+
* return await saveImage(processed);
|
|
187
|
+
* };
|
|
188
|
+
*
|
|
189
|
+
* // Process 5 images at a time to avoid memory issues
|
|
190
|
+
* const processed = await batchAsync(imageUrls, processImage, 5, 200);
|
|
191
|
+
* console.log(`Processed ${processed.length} images`);
|
|
192
|
+
*
|
|
193
|
+
* @see Promise.all - Process all items concurrently without batching
|
|
194
|
+
*/
|
|
195
|
+
export declare const batchAsync: <T, U>(items: T[], fn: (item: T) => Promise<U>, batchSize?: number, delayMs?: number) => Promise<U[]>;
|
|
196
|
+
/**
|
|
197
|
+
* Advanced timing utilities for specialized use cases.
|
|
198
|
+
*
|
|
199
|
+
* @category Advanced
|
|
200
|
+
*/
|
|
201
|
+
export declare const timingUtils: {
|
|
202
|
+
/**
|
|
203
|
+
* Debounce with immediate option.
|
|
204
|
+
* Optionally invokes the function immediately on the leading edge.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* // Execute immediately on first call, then debounce
|
|
208
|
+
* const saveWithFeedback = timingUtils.debounceWithImmediate(
|
|
209
|
+
* (data: string) => {
|
|
210
|
+
* showSaveIndicator();
|
|
211
|
+
* saveToServer(data);
|
|
212
|
+
* },
|
|
213
|
+
* 1000,
|
|
214
|
+
* true // immediate
|
|
215
|
+
* );
|
|
216
|
+
*
|
|
217
|
+
* // First call executes immediately, subsequent calls are debounced
|
|
218
|
+
* saveWithFeedback('data1'); // Executes immediately
|
|
219
|
+
* saveWithFeedback('data2'); // Debounced
|
|
220
|
+
* saveWithFeedback('data3'); // Debounced, only this executes after 1s
|
|
221
|
+
*/
|
|
222
|
+
debounceWithImmediate: <T extends any[]>(fn: (...args: T) => void, delay: number, immediate?: boolean) => ((...args: T) => void);
|
|
223
|
+
/**
|
|
224
|
+
* Throttle with trailing call option.
|
|
225
|
+
* Ensures the last call is always executed.
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* // Progress updates with final state guarantee
|
|
229
|
+
* const updateProgress = timingUtils.throttleWithTrailing(
|
|
230
|
+
* (percent: number) => {
|
|
231
|
+
* progressBar.style.width = `${percent}%`;
|
|
232
|
+
* if (percent === 100) {
|
|
233
|
+
* showCompletionMessage();
|
|
234
|
+
* }
|
|
235
|
+
* },
|
|
236
|
+
* 100,
|
|
237
|
+
* true // trailing
|
|
238
|
+
* );
|
|
239
|
+
*
|
|
240
|
+
* // Updates at most every 100ms, but guarantees the final 100% is shown
|
|
241
|
+
* for (let i = 0; i <= 100; i++) {
|
|
242
|
+
* updateProgress(i);
|
|
243
|
+
* }
|
|
244
|
+
*/
|
|
245
|
+
throttleWithTrailing: <T extends any[]>(fn: (...args: T) => void, limit: number, trailing?: boolean) => ((...args: T) => void);
|
|
246
|
+
/**
|
|
247
|
+
* Create a function that measures its execution time.
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* const timedFetch = timingUtils.measureTime(
|
|
251
|
+
* async (url: string) => {
|
|
252
|
+
* const response = await fetch(url);
|
|
253
|
+
* return response.json();
|
|
254
|
+
* },
|
|
255
|
+
* (duration, result) => {
|
|
256
|
+
* console.log(`Fetch took ${duration}ms`);
|
|
257
|
+
* analytics.track('api_call_duration', { duration, url: result.url });
|
|
258
|
+
* }
|
|
259
|
+
* );
|
|
260
|
+
*
|
|
261
|
+
* const data = await timedFetch('/api/data');
|
|
262
|
+
*/
|
|
263
|
+
measureTime: <T extends unknown[], R>(fn: (...args: T) => R, onComplete?: (duration: number, result: Awaited<R>) => void) => ((...args: T) => R);
|
|
264
|
+
};
|
|
265
|
+
//# sourceMappingURL=performance.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"performance.d.mts","sourceRoot":"","sources":["../src/performance.mts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,GAAG,EAAE,MAClC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,SACjB,MAAM,KACZ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,CAOvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,GAAG,EAAE,EAAE,CAAC,MACrC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,SACd,MAAM,KACZ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAahC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,eAAO,MAAM,UAAU,GAAU,CAAC,EAAE,CAAC,SAC5B,CAAC,EAAE,MACN,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,2CAG1B,OAAO,CAAC,CAAC,EAAE,CAeb,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW;IACtB;;;;;;;;;;;;;;;;;;;OAmBG;4BAEqB,CAAC,SAAS,GAAG,EAAE,MACjC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,SACjB,MAAM,0BAEZ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAuBzB;;;;;;;;;;;;;;;;;;;;;OAqBG;2BAEoB,CAAC,SAAS,GAAG,EAAE,MAChC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,SACjB,MAAM,yBAEZ,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IA+BzB;;;;;;;;;;;;;;;;OAgBG;kBACW,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,MAC9B,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,eACR,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,KAC1D,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;CAuBvB,CAAC"}
|