@ls-stack/utils 3.9.0 → 3.9.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 +82 -1
- package/lib/asyncQueue.cjs +22 -20
- package/lib/asyncQueue.d.cts +1 -1
- package/lib/asyncQueue.d.ts +1 -1
- package/lib/asyncQueue.js +22 -20
- package/lib/concurrentCalls.cjs +1 -1
- package/lib/concurrentCalls.js +1 -1
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -1 +1,82 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ls-stack/utils
|
|
2
|
+
|
|
3
|
+
Generic TypeScript utilities for modern JavaScript/TypeScript projects.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ls-stack/utils
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @ls-stack/utils
|
|
11
|
+
# or
|
|
12
|
+
yarn add @ls-stack/utils
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Import specific utilities from their modules:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { createAsyncQueue } from '@ls-stack/utils/asyncQueue';
|
|
21
|
+
import { deepEqual } from '@ls-stack/utils/deepEqual';
|
|
22
|
+
import { debounce } from '@ls-stack/utils/debounce';
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Available Utilities
|
|
26
|
+
|
|
27
|
+
This package includes a wide range of utilities for:
|
|
28
|
+
|
|
29
|
+
- **Array manipulation** (`arrayUtils`) - sorting, grouping, filtering
|
|
30
|
+
- **Async operations** (`asyncQueue`, `parallelAsyncCalls`, `promiseUtils`) - queue management and promise utilities
|
|
31
|
+
- **Type assertions** (`assertions`) - runtime type checking
|
|
32
|
+
- **Caching** (`cache`) - efficient caching with TTL support
|
|
33
|
+
- **Concurrency control** (`concurrentCalls`, `createThrottleController`) - rate limiting and throttling
|
|
34
|
+
- **Object utilities** (`objUtils`) - deep operations on objects
|
|
35
|
+
- **String utilities** (`stringUtils`) - string manipulation and formatting
|
|
36
|
+
- **Math utilities** (`mathUtils`) - mathematical operations and calculations
|
|
37
|
+
- **And many more...**
|
|
38
|
+
|
|
39
|
+
## Documentation
|
|
40
|
+
|
|
41
|
+
Comprehensive API documentation is available in the [`docs/`](docs/) folder. Start with the [modules overview](docs/modules.md) to explore all available utilities.
|
|
42
|
+
|
|
43
|
+
### Generating Documentation
|
|
44
|
+
|
|
45
|
+
To regenerate the documentation after making changes:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pnpm docs
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For continuous updates during development:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm docs:watch
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Development
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Install dependencies
|
|
61
|
+
pnpm install
|
|
62
|
+
|
|
63
|
+
# Run tests
|
|
64
|
+
pnpm test
|
|
65
|
+
|
|
66
|
+
# Run tests with UI
|
|
67
|
+
pnpm test:ui
|
|
68
|
+
|
|
69
|
+
# Build the library
|
|
70
|
+
pnpm build
|
|
71
|
+
|
|
72
|
+
# Lint code
|
|
73
|
+
pnpm lint
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
|
79
|
+
|
|
80
|
+
## Repository
|
|
81
|
+
|
|
82
|
+
[github:lucasols/utils](https://github.com/lucasols/utils)
|
package/lib/asyncQueue.cjs
CHANGED
|
@@ -95,13 +95,15 @@ var AsyncQueue = class {
|
|
|
95
95
|
return deferred.promise;
|
|
96
96
|
}
|
|
97
97
|
resultifyAdd(fn, options) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
98
|
+
return this.add(
|
|
99
|
+
(ctx) => (0, import_t_result.resultify)(async () => {
|
|
100
|
+
if (isPromise(fn)) {
|
|
101
|
+
return await fn;
|
|
102
|
+
}
|
|
103
|
+
return fn(ctx);
|
|
104
|
+
}),
|
|
105
|
+
options
|
|
106
|
+
);
|
|
105
107
|
}
|
|
106
108
|
async #processQueue() {
|
|
107
109
|
if (this.#pending >= this.#concurrency || this.#queue.length === 0) {
|
|
@@ -125,20 +127,20 @@ var AsyncQueue = class {
|
|
|
125
127
|
}
|
|
126
128
|
const signal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
|
|
127
129
|
let abortListener;
|
|
128
|
-
|
|
129
|
-
if (signal) {
|
|
130
|
+
try {
|
|
131
|
+
if (signal?.aborted) {
|
|
130
132
|
const error = signal.reason instanceof Error ? signal.reason : new DOMException("Aborted", "AbortError");
|
|
131
|
-
|
|
132
|
-
reject(error);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
abortListener = () => {
|
|
136
|
-
reject(error);
|
|
137
|
-
};
|
|
138
|
-
signal.addEventListener("abort", abortListener, { once: true });
|
|
133
|
+
throw error;
|
|
139
134
|
}
|
|
140
|
-
|
|
141
|
-
|
|
135
|
+
const signalAbortPromise = new Promise((_, reject) => {
|
|
136
|
+
if (signal) {
|
|
137
|
+
const error = signal.reason instanceof Error ? signal.reason : new DOMException("Aborted", "AbortError");
|
|
138
|
+
abortListener = () => {
|
|
139
|
+
reject(error);
|
|
140
|
+
};
|
|
141
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
142
144
|
const taskRunPromise = task.run({ signal, id: task.id });
|
|
143
145
|
this.events.emit("start", { id: task.id });
|
|
144
146
|
const result = await Promise.race([taskRunPromise, signalAbortPromise]);
|
|
@@ -157,7 +159,7 @@ var AsyncQueue = class {
|
|
|
157
159
|
this.#failed++;
|
|
158
160
|
this.events.emit("error", {
|
|
159
161
|
id: task.id,
|
|
160
|
-
error
|
|
162
|
+
error
|
|
161
163
|
});
|
|
162
164
|
}
|
|
163
165
|
} catch (error) {
|
package/lib/asyncQueue.d.cts
CHANGED
|
@@ -50,7 +50,7 @@ declare class AsyncQueueWithId<T, I, E extends ResultValidErrors = Error> extend
|
|
|
50
50
|
add(fn: ((ctx: RunCtx<I>) => Promise<Result<T, E>> | Result<T, E>) | Promise<Result<T, E>>, options?: AddOptionsWithId<I>): Promise<Result<T, E | Error>>;
|
|
51
51
|
resultifyAdd(fn: ((ctx: RunCtx<I>) => Promise<T> | T) | Promise<T>, options?: AddOptionsWithId<I>): Promise<Result<T, E | Error>>;
|
|
52
52
|
}
|
|
53
|
-
declare function createAsyncQueue<T, E extends ResultValidErrors = Error>(options?: AsyncQueueOptions): AsyncQueue<T, E
|
|
53
|
+
declare function createAsyncQueue<T, E extends ResultValidErrors = Error>(options?: AsyncQueueOptions): AsyncQueue<T, E>;
|
|
54
54
|
declare function createAsyncQueueWithId<T, I, E extends ResultValidErrors = Error>(options?: AsyncQueueOptions): AsyncQueueWithId<T, I, E>;
|
|
55
55
|
|
|
56
56
|
export { createAsyncQueue, createAsyncQueueWithId };
|
package/lib/asyncQueue.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ declare class AsyncQueueWithId<T, I, E extends ResultValidErrors = Error> extend
|
|
|
50
50
|
add(fn: ((ctx: RunCtx<I>) => Promise<Result<T, E>> | Result<T, E>) | Promise<Result<T, E>>, options?: AddOptionsWithId<I>): Promise<Result<T, E | Error>>;
|
|
51
51
|
resultifyAdd(fn: ((ctx: RunCtx<I>) => Promise<T> | T) | Promise<T>, options?: AddOptionsWithId<I>): Promise<Result<T, E | Error>>;
|
|
52
52
|
}
|
|
53
|
-
declare function createAsyncQueue<T, E extends ResultValidErrors = Error>(options?: AsyncQueueOptions): AsyncQueue<T, E
|
|
53
|
+
declare function createAsyncQueue<T, E extends ResultValidErrors = Error>(options?: AsyncQueueOptions): AsyncQueue<T, E>;
|
|
54
54
|
declare function createAsyncQueueWithId<T, I, E extends ResultValidErrors = Error>(options?: AsyncQueueOptions): AsyncQueueWithId<T, I, E>;
|
|
55
55
|
|
|
56
56
|
export { createAsyncQueue, createAsyncQueueWithId };
|
package/lib/asyncQueue.js
CHANGED
|
@@ -58,13 +58,15 @@ var AsyncQueue = class {
|
|
|
58
58
|
return deferred.promise;
|
|
59
59
|
}
|
|
60
60
|
resultifyAdd(fn, options) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
61
|
+
return this.add(
|
|
62
|
+
(ctx) => resultify(async () => {
|
|
63
|
+
if (isPromise(fn)) {
|
|
64
|
+
return await fn;
|
|
65
|
+
}
|
|
66
|
+
return fn(ctx);
|
|
67
|
+
}),
|
|
68
|
+
options
|
|
69
|
+
);
|
|
68
70
|
}
|
|
69
71
|
async #processQueue() {
|
|
70
72
|
if (this.#pending >= this.#concurrency || this.#queue.length === 0) {
|
|
@@ -88,20 +90,20 @@ var AsyncQueue = class {
|
|
|
88
90
|
}
|
|
89
91
|
const signal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
|
|
90
92
|
let abortListener;
|
|
91
|
-
|
|
92
|
-
if (signal) {
|
|
93
|
+
try {
|
|
94
|
+
if (signal?.aborted) {
|
|
93
95
|
const error = signal.reason instanceof Error ? signal.reason : new DOMException("Aborted", "AbortError");
|
|
94
|
-
|
|
95
|
-
reject(error);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
abortListener = () => {
|
|
99
|
-
reject(error);
|
|
100
|
-
};
|
|
101
|
-
signal.addEventListener("abort", abortListener, { once: true });
|
|
96
|
+
throw error;
|
|
102
97
|
}
|
|
103
|
-
|
|
104
|
-
|
|
98
|
+
const signalAbortPromise = new Promise((_, reject) => {
|
|
99
|
+
if (signal) {
|
|
100
|
+
const error = signal.reason instanceof Error ? signal.reason : new DOMException("Aborted", "AbortError");
|
|
101
|
+
abortListener = () => {
|
|
102
|
+
reject(error);
|
|
103
|
+
};
|
|
104
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
105
|
+
}
|
|
106
|
+
});
|
|
105
107
|
const taskRunPromise = task.run({ signal, id: task.id });
|
|
106
108
|
this.events.emit("start", { id: task.id });
|
|
107
109
|
const result = await Promise.race([taskRunPromise, signalAbortPromise]);
|
|
@@ -120,7 +122,7 @@ var AsyncQueue = class {
|
|
|
120
122
|
this.#failed++;
|
|
121
123
|
this.events.emit("error", {
|
|
122
124
|
id: task.id,
|
|
123
|
-
error
|
|
125
|
+
error
|
|
124
126
|
});
|
|
125
127
|
}
|
|
126
128
|
} catch (error) {
|
package/lib/concurrentCalls.cjs
CHANGED
|
@@ -288,7 +288,7 @@ var ConcurrentCallsWithMetadata = class {
|
|
|
288
288
|
`${failedProcessing.length}/${total} calls failed: ${truncateArray(
|
|
289
289
|
failedProcessing.map((f) => truncateString(f.error.message, 20)),
|
|
290
290
|
5,
|
|
291
|
-
|
|
291
|
+
"..."
|
|
292
292
|
).join("; ")}`
|
|
293
293
|
) : null;
|
|
294
294
|
return {
|
package/lib/concurrentCalls.js
CHANGED
|
@@ -235,7 +235,7 @@ var ConcurrentCallsWithMetadata = class {
|
|
|
235
235
|
`${failedProcessing.length}/${total} calls failed: ${truncateArray(
|
|
236
236
|
failedProcessing.map((f) => truncateString(f.error.message, 20)),
|
|
237
237
|
5,
|
|
238
|
-
|
|
238
|
+
"..."
|
|
239
239
|
).join("; ")}`
|
|
240
240
|
) : null;
|
|
241
241
|
return {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ls-stack/utils",
|
|
3
3
|
"description": "Typescript utils",
|
|
4
|
-
"version": "3.9.
|
|
4
|
+
"version": "3.9.1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
7
7
|
"lib"
|
|
@@ -179,6 +179,9 @@
|
|
|
179
179
|
"prettier-plugin-organize-imports": "^4.1.0",
|
|
180
180
|
"tsm": "^2.3.0",
|
|
181
181
|
"tsup": "^8.3.5",
|
|
182
|
+
"typedoc": "^0.28.4",
|
|
183
|
+
"typedoc-plugin-markdown": "^4.6.3",
|
|
184
|
+
"typedoc-plugin-missing-exports": "^4.0.0",
|
|
182
185
|
"typescript": "^5.7.3",
|
|
183
186
|
"typescript-eslint": "^8.21.0",
|
|
184
187
|
"vite": "^6.0.11",
|
|
@@ -195,12 +198,14 @@
|
|
|
195
198
|
"tsc": "tsc -p tsconfig.prod.json",
|
|
196
199
|
"tsc:watch": "tsc -p tsconfig.prod.json --watch",
|
|
197
200
|
"eslint": "CI=true eslint src/ scripts/ --color --max-warnings=0",
|
|
198
|
-
"build": "pnpm test && pnpm lint && pnpm build:no-test && pnpm build:update-exports",
|
|
201
|
+
"build": "pnpm test && pnpm lint && pnpm build:no-test && pnpm docs && pnpm build:update-exports",
|
|
199
202
|
"build:no-test": "tsup",
|
|
200
203
|
"build:update-exports": "tsm --no-warnings scripts/updatePackageExports.ts",
|
|
201
204
|
"build-test": "tsup --config tsup.test.config.ts",
|
|
202
205
|
"pre-publish": "./scripts/check-if-is-sync.sh && pnpm build",
|
|
203
206
|
"test:console-fmt": "tsm --no-warnings scripts/testConsoleFmt.ts",
|
|
204
|
-
"bench:deepEqual": "tsm --no-warnings benchmarks/deepEqual.ts"
|
|
207
|
+
"bench:deepEqual": "tsm --no-warnings benchmarks/deepEqual.ts",
|
|
208
|
+
"docs": "typedoc",
|
|
209
|
+
"docs:watch": "typedoc --watch"
|
|
205
210
|
}
|
|
206
211
|
}
|