@furystack/utils 8.1.7 → 8.1.9
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/CHANGELOG.md +11 -32
- package/README.md +160 -44
- package/esm/event-hub.d.ts +27 -0
- package/esm/event-hub.d.ts.map +1 -1
- package/esm/event-hub.js +27 -0
- package/esm/event-hub.js.map +1 -1
- package/esm/sort-by.js +0 -1
- package/esm/sort-by.js.map +1 -1
- package/package.json +16 -8
- package/src/event-hub.ts +27 -0
- package/src/sort-by.ts +1 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,42 +1,21 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
3
|
+
## [8.1.9] - 2026-01-26
|
|
5
4
|
|
|
6
|
-
###
|
|
5
|
+
### 🔧 Chores
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
- Standardized author format, improved keywords, removed obsolete `gitHead`, added `engines` (Node 22+) and `sideEffects: false`
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
## [8.1.8] - 2026-01-22
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
### ⬆️ Dependencies
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
- Dependency updates
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
### 📚 Documentation
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
- Revamped README with improved utility documentation and examples
|
|
19
18
|
|
|
20
|
-
###
|
|
19
|
+
### 🔧 Chores
|
|
21
20
|
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
### 🚀 What's new
|
|
25
|
-
|
|
26
|
-
- **@furystack/shades:** Disposable resources on Shade Components ([#165](https://github.com/furystack/furystack/issues/165)) ([8567e7e](https://github.com/furystack/furystack/commit/8567e7e2e01cec232a5f4448dfc0833c1f183229))
|
|
27
|
-
|
|
28
|
-
### [1.2.46](https://github.com/furystack/furystack/compare/@furystack/utils@1.2.45...@furystack/utils@1.2.46) (2021-11-19)
|
|
29
|
-
|
|
30
|
-
**Note:** Version bump only for package @furystack/utils
|
|
31
|
-
|
|
32
|
-
### [1.2.45](https://github.com/furystack/furystack/compare/@furystack/utils@1.2.44...@furystack/utils@1.2.45) (2021-10-05)
|
|
33
|
-
|
|
34
|
-
**Note:** Version bump only for package @furystack/utils
|
|
35
|
-
|
|
36
|
-
### [1.2.44](https://github.com/furystack/furystack/compare/@furystack/utils@1.2.14...@furystack/utils@1.2.44) (2021-08-19)
|
|
37
|
-
|
|
38
|
-
**Note:** Version bump only for package @furystack/utils
|
|
39
|
-
|
|
40
|
-
### [1.2.43](https://github.com/furystack/furystack/compare/@furystack/utils@1.2.14...@furystack/utils@1.2.43) (2021-07-30)
|
|
41
|
-
|
|
42
|
-
**Note:** Version bump only for package @furystack/utils
|
|
21
|
+
- Migrated to centralized changelog management system
|
package/README.md
CHANGED
|
@@ -2,13 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
General utilities for FuryStack.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm install @furystack/utils
|
|
9
|
+
# or
|
|
10
|
+
yarn add @furystack/utils
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Disposable
|
|
14
|
+
|
|
15
|
+
You can implement disposable resources and use them with `using()` or `usingAsync()` syntax:
|
|
8
16
|
|
|
9
17
|
```ts
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
import { using, usingAsync } from '@furystack/utils'
|
|
19
|
+
|
|
20
|
+
class Resource implements Disposable {
|
|
21
|
+
[Symbol.dispose]() {
|
|
12
22
|
// cleanup logic
|
|
13
23
|
}
|
|
14
24
|
}
|
|
@@ -17,18 +27,18 @@ using(new Resource(), (resource) => {
|
|
|
17
27
|
// do something with the resource
|
|
18
28
|
})
|
|
19
29
|
|
|
20
|
-
usingAsync(new Resource(), async (resource) => {
|
|
30
|
+
await usingAsync(new Resource(), async (resource) => {
|
|
21
31
|
// do something with the resource, allows awaiting promises
|
|
22
32
|
})
|
|
23
33
|
```
|
|
24
34
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
You can track value changes using this simple Observable implementation.
|
|
35
|
+
## ObservableValue
|
|
28
36
|
|
|
29
|
-
|
|
37
|
+
You can track value changes using this simple Observable implementation:
|
|
30
38
|
|
|
31
39
|
```ts
|
|
40
|
+
import { ObservableValue } from '@furystack/utils'
|
|
41
|
+
|
|
32
42
|
const observableValue = new ObservableValue<number>(0)
|
|
33
43
|
const observer = observableValue.subscribe((newValue) => {
|
|
34
44
|
console.log('Value changed:', newValue)
|
|
@@ -42,51 +52,157 @@ observer[Symbol.dispose]()
|
|
|
42
52
|
observableValue[Symbol.dispose]()
|
|
43
53
|
```
|
|
44
54
|
|
|
45
|
-
|
|
55
|
+
## PathHelper
|
|
56
|
+
|
|
57
|
+
Helper class for path-related functions and methods:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { PathHelper } from '@furystack/utils'
|
|
61
|
+
|
|
62
|
+
PathHelper.joinPaths('api', 'users', '123') // 'api/users/123'
|
|
63
|
+
PathHelper.getSegments('/api/users/123') // ['api', 'users', '123']
|
|
64
|
+
PathHelper.getParentPath('/api/users/123') // 'api/users'
|
|
65
|
+
PathHelper.trimSlashes('/api/') // 'api'
|
|
66
|
+
PathHelper.joinUrl('http://example.com', '/api') // 'http://example.com/api'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## deepMerge
|
|
46
70
|
|
|
47
|
-
|
|
71
|
+
Deep merge objects together:
|
|
48
72
|
|
|
49
|
-
|
|
73
|
+
```ts
|
|
74
|
+
import { deepMerge } from '@furystack/utils'
|
|
50
75
|
|
|
51
|
-
|
|
76
|
+
const target = { a: 1, b: { c: 2 } }
|
|
77
|
+
const source = { b: { d: 3 } }
|
|
78
|
+
const result = deepMerge(target, source) // { a: 1, b: { c: 2, d: 3 } }
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## sleepAsync
|
|
82
|
+
|
|
83
|
+
Simple promise-based sleep utility:
|
|
52
84
|
|
|
53
85
|
```ts
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// custom logic
|
|
58
|
-
// ...
|
|
59
|
-
return hasSucceeded
|
|
60
|
-
}
|
|
61
|
-
const retrierSuccess = await Retrier.create(funcToRetry)
|
|
62
|
-
.setup({
|
|
63
|
-
Retries: 3,
|
|
64
|
-
RetryIntervalMs: 1,
|
|
65
|
-
timeoutMs: 1000,
|
|
66
|
-
})
|
|
67
|
-
.run()
|
|
86
|
+
import { sleepAsync } from '@furystack/utils'
|
|
87
|
+
|
|
88
|
+
await sleepAsync(1000) // wait 1 second
|
|
68
89
|
```
|
|
69
90
|
|
|
70
|
-
|
|
91
|
+
## debounce
|
|
71
92
|
|
|
72
|
-
|
|
93
|
+
Debounce a function to limit how often it can be called:
|
|
73
94
|
|
|
74
95
|
```ts
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
96
|
+
import { debounce } from '@furystack/utils'
|
|
97
|
+
|
|
98
|
+
const debouncedSearch = debounce((query: string) => {
|
|
99
|
+
console.log('Searching for:', query)
|
|
100
|
+
}, 300)
|
|
101
|
+
|
|
102
|
+
debouncedSearch('hello') // Will only execute after 300ms of no calls
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## EventHub
|
|
106
|
+
|
|
107
|
+
A typed event emitter:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { EventHub } from '@furystack/utils'
|
|
111
|
+
|
|
112
|
+
type MyEvents = {
|
|
113
|
+
userLoggedIn: { userId: string }
|
|
114
|
+
userLoggedOut: { userId: string }
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const hub = new EventHub<MyEvents>()
|
|
118
|
+
|
|
119
|
+
hub.subscribe('userLoggedIn', (event) => {
|
|
120
|
+
console.log('User logged in:', event.userId)
|
|
88
121
|
})
|
|
89
122
|
|
|
90
|
-
|
|
91
|
-
|
|
123
|
+
hub.emit('userLoggedIn', { userId: '123' })
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## sortBy
|
|
127
|
+
|
|
128
|
+
Array prototype extension for convenient sorting by field name:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import '@furystack/utils' // Adds sortBy to Array prototype
|
|
132
|
+
|
|
133
|
+
const users = [
|
|
134
|
+
{ name: 'Charlie', age: 30 },
|
|
135
|
+
{ name: 'Alice', age: 25 },
|
|
136
|
+
{ name: 'Bob', age: 35 },
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
// Sort by name ascending (default)
|
|
140
|
+
const byName = users.sortBy('name')
|
|
141
|
+
// [{ name: 'Alice', ... }, { name: 'Bob', ... }, { name: 'Charlie', ... }]
|
|
142
|
+
|
|
143
|
+
// Sort by age descending
|
|
144
|
+
const byAgeDesc = users.sortBy('age', 'desc')
|
|
145
|
+
// [{ name: 'Bob', age: 35 }, { name: 'Charlie', age: 30 }, { name: 'Alice', age: 25 }]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
You can also use the `compareBy` function directly for custom sorting:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { compareBy } from '@furystack/utils'
|
|
152
|
+
|
|
153
|
+
const users = [{ name: 'Charlie' }, { name: 'Alice' }]
|
|
154
|
+
users.sort((a, b) => compareBy(a, b, 'name', 'asc'))
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## tuple
|
|
158
|
+
|
|
159
|
+
Helper function for creating typed tuples from string literals:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import { tuple } from '@furystack/utils'
|
|
163
|
+
|
|
164
|
+
// Creates a tuple type ['admin', 'user', 'guest'] instead of string[]
|
|
165
|
+
const roles = tuple('admin', 'user', 'guest')
|
|
166
|
+
|
|
167
|
+
// TypeScript knows the exact values
|
|
168
|
+
type Role = (typeof roles)[number] // 'admin' | 'user' | 'guest'
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Type Guards
|
|
172
|
+
|
|
173
|
+
Check if a value is disposable:
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import { isDisposable, isAsyncDisposable } from '@furystack/utils'
|
|
177
|
+
|
|
178
|
+
if (isDisposable(value)) {
|
|
179
|
+
value[Symbol.dispose]()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (isAsyncDisposable(value)) {
|
|
183
|
+
await value[Symbol.asyncDispose]()
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## DeepPartial
|
|
188
|
+
|
|
189
|
+
A utility type for deep partial objects:
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
import type { DeepPartial } from '@furystack/utils'
|
|
193
|
+
|
|
194
|
+
type Config = {
|
|
195
|
+
server: {
|
|
196
|
+
host: string
|
|
197
|
+
port: number
|
|
198
|
+
}
|
|
199
|
+
database: {
|
|
200
|
+
url: string
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// All nested properties are optional
|
|
205
|
+
const partialConfig: DeepPartial<Config> = {
|
|
206
|
+
server: { port: 8080 }, // host is optional
|
|
207
|
+
}
|
|
92
208
|
```
|
package/esm/event-hub.d.ts
CHANGED
|
@@ -1,4 +1,31 @@
|
|
|
1
1
|
type ListenerFunction<EventTypeMap extends object, T extends keyof EventTypeMap> = (arg: EventTypeMap[T]) => void | PromiseLike<void>;
|
|
2
|
+
/**
|
|
3
|
+
* A typed event emitter that provides type-safe event subscription and emission.
|
|
4
|
+
* Use this to create strongly-typed pub/sub patterns in your application.
|
|
5
|
+
*
|
|
6
|
+
* @typeParam EventTypeMap - An object type where keys are event names and values are event payload types
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* type MyEvents = {
|
|
10
|
+
* userLoggedIn: { userId: string }
|
|
11
|
+
* userLoggedOut: { userId: string }
|
|
12
|
+
* dataUpdated: { items: string[] }
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* const hub = new EventHub<MyEvents>()
|
|
16
|
+
*
|
|
17
|
+
* // Subscribe to events
|
|
18
|
+
* hub.subscribe('userLoggedIn', (event) => {
|
|
19
|
+
* console.log('User logged in:', event.userId)
|
|
20
|
+
* })
|
|
21
|
+
*
|
|
22
|
+
* // Emit events
|
|
23
|
+
* hub.emit('userLoggedIn', { userId: '123' })
|
|
24
|
+
*
|
|
25
|
+
* // Clean up when done
|
|
26
|
+
* hub[Symbol.dispose]()
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
2
29
|
export declare class EventHub<EventTypeMap extends object> implements Disposable {
|
|
3
30
|
private listeners;
|
|
4
31
|
addListener<TEvent extends keyof EventTypeMap>(event: TEvent, listener: ListenerFunction<EventTypeMap, TEvent>): void;
|
package/esm/event-hub.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-hub.d.ts","sourceRoot":"","sources":["../src/event-hub.ts"],"names":[],"mappings":"AAAA,KAAK,gBAAgB,CAAC,YAAY,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,YAAY,IAAI,CACjF,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,KACjB,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;AAE7B,qBAAa,QAAQ,CAAC,YAAY,SAAS,MAAM,CAAE,YAAW,UAAU;IACtE,OAAO,CAAC,SAAS,CAAyF;IAEnG,WAAW,CAAC,MAAM,SAAS,MAAM,YAAY,EAClD,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,gBAAgB,CAAC,YAAY,EAAE,MAAM,CAAC;IAQ3C,cAAc,CAAC,MAAM,SAAS,MAAM,YAAY,EACrD,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,gBAAgB,CAAC,YAAY,EAAE,MAAM,CAAC;IAO3C,SAAS,CAAC,MAAM,SAAS,MAAM,YAAY,EAChD,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,gBAAgB,CAAC,YAAY,EAAE,MAAM,CAAC,GAC/C,UAAU;IAKN,IAAI,CAAC,MAAM,SAAS,MAAM,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,CAAC,MAAM,CAAC;IAMhF,CAAC,MAAM,CAAC,OAAO,CAAC;CAGxB"}
|
|
1
|
+
{"version":3,"file":"event-hub.d.ts","sourceRoot":"","sources":["../src/event-hub.ts"],"names":[],"mappings":"AAAA,KAAK,gBAAgB,CAAC,YAAY,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,YAAY,IAAI,CACjF,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,KACjB,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,QAAQ,CAAC,YAAY,SAAS,MAAM,CAAE,YAAW,UAAU;IACtE,OAAO,CAAC,SAAS,CAAyF;IAEnG,WAAW,CAAC,MAAM,SAAS,MAAM,YAAY,EAClD,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,gBAAgB,CAAC,YAAY,EAAE,MAAM,CAAC;IAQ3C,cAAc,CAAC,MAAM,SAAS,MAAM,YAAY,EACrD,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,gBAAgB,CAAC,YAAY,EAAE,MAAM,CAAC;IAO3C,SAAS,CAAC,MAAM,SAAS,MAAM,YAAY,EAChD,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,gBAAgB,CAAC,YAAY,EAAE,MAAM,CAAC,GAC/C,UAAU;IAKN,IAAI,CAAC,MAAM,SAAS,MAAM,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,CAAC,MAAM,CAAC;IAMhF,CAAC,MAAM,CAAC,OAAO,CAAC;CAGxB"}
|
package/esm/event-hub.js
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A typed event emitter that provides type-safe event subscription and emission.
|
|
3
|
+
* Use this to create strongly-typed pub/sub patterns in your application.
|
|
4
|
+
*
|
|
5
|
+
* @typeParam EventTypeMap - An object type where keys are event names and values are event payload types
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* type MyEvents = {
|
|
9
|
+
* userLoggedIn: { userId: string }
|
|
10
|
+
* userLoggedOut: { userId: string }
|
|
11
|
+
* dataUpdated: { items: string[] }
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* const hub = new EventHub<MyEvents>()
|
|
15
|
+
*
|
|
16
|
+
* // Subscribe to events
|
|
17
|
+
* hub.subscribe('userLoggedIn', (event) => {
|
|
18
|
+
* console.log('User logged in:', event.userId)
|
|
19
|
+
* })
|
|
20
|
+
*
|
|
21
|
+
* // Emit events
|
|
22
|
+
* hub.emit('userLoggedIn', { userId: '123' })
|
|
23
|
+
*
|
|
24
|
+
* // Clean up when done
|
|
25
|
+
* hub[Symbol.dispose]()
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
1
28
|
export class EventHub {
|
|
2
29
|
listeners = new Map();
|
|
3
30
|
addListener(event, listener) {
|
package/esm/event-hub.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-hub.js","sourceRoot":"","sources":["../src/event-hub.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,QAAQ;IACX,SAAS,GAAG,IAAI,GAAG,EAA+E,CAAA;IAEnG,WAAW,CAChB,KAAa,EACb,QAAgD;QAEhD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,CAAC,CAAA;QACtC,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,GAAG,CAAC,QAA8D,CAAC,CAAA;IAChG,CAAC;IAEM,cAAc,CACnB,KAAa,EACb,QAAgD;QAEhD,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,MAAM,CAAC,QAA8D,CAAC,CAAA;QACnG,CAAC;IACH,CAAC;IAEM,SAAS,CACd,KAAa,EACb,QAAgD;QAEhD,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QACjC,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAA;IACzE,CAAC;IAEM,IAAI,CAAoC,KAAa,EAAE,GAAyB;QACrF,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QACtE,CAAC;IACH,CAAC;IAEM,CAAC,MAAM,CAAC,OAAO,CAAC;QACrB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"event-hub.js","sourceRoot":"","sources":["../src/event-hub.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,OAAO,QAAQ;IACX,SAAS,GAAG,IAAI,GAAG,EAA+E,CAAA;IAEnG,WAAW,CAChB,KAAa,EACb,QAAgD;QAEhD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,CAAC,CAAA;QACtC,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,GAAG,CAAC,QAA8D,CAAC,CAAA;IAChG,CAAC;IAEM,cAAc,CACnB,KAAa,EACb,QAAgD;QAEhD,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,MAAM,CAAC,QAA8D,CAAC,CAAA;QACnG,CAAC;IACH,CAAC;IAEM,SAAS,CACd,KAAa,EACb,QAAgD;QAEhD,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QACjC,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAA;IACzE,CAAC;IAEM,IAAI,CAAoC,KAAa,EAAE,GAAyB;QACrF,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QACtE,CAAC;IACH,CAAC;IAEM,CAAC,MAAM,CAAC,OAAO,CAAC;QACrB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC;CACF"}
|
package/esm/sort-by.js
CHANGED
|
@@ -10,7 +10,6 @@ export const compareBy = (entity1, entity2, field, direction) => {
|
|
|
10
10
|
return 0;
|
|
11
11
|
};
|
|
12
12
|
Array.prototype.sortBy = function (key, direction = 'asc') {
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
14
13
|
return this.sort((a, b) => compareBy(a, b, key, direction));
|
|
15
14
|
};
|
|
16
15
|
//# sourceMappingURL=sort-by.js.map
|
package/esm/sort-by.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort-by.js","sourceRoot":"","sources":["../src/sort-by.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,SAAS,GAAG,CAAuB,OAAU,EAAE,OAAU,EAAE,KAAQ,EAAE,SAAyB,EAAE,EAAE;IAC7G,MAAM,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAA;IACjD,MAAM,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAA;IACjD,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,CAAC,CAAA;IACX,CAAC;IACD,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,CAAA;IACV,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC,CAAA;AAED,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"sort-by.js","sourceRoot":"","sources":["../src/sort-by.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,SAAS,GAAG,CAAuB,OAAU,EAAE,OAAU,EAAE,KAAQ,EAAE,SAAyB,EAAE,EAAE;IAC7G,MAAM,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAA;IACjD,MAAM,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAA;IACjD,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,CAAC,CAAA;IACX,CAAC;IACD,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,CAAA;IACV,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC,CAAA;AAED,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,UAAgC,GAAM,EAAE,YAA4B,KAAK;IAChG,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAA;AAC7D,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/utils",
|
|
3
|
-
"version": "8.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "8.1.9",
|
|
4
|
+
"description": "Utility functions and helpers for FuryStack including observables, events, and disposables",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"build
|
|
7
|
+
"build": "tsc --outDir ./esm"
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"types": "./esm/index.d.ts",
|
|
11
12
|
"import": "./esm/index.js"
|
|
12
13
|
}
|
|
13
14
|
},
|
|
14
15
|
"files": [
|
|
15
16
|
"esm",
|
|
16
|
-
"types",
|
|
17
17
|
"src"
|
|
18
18
|
],
|
|
19
19
|
"repository": {
|
|
@@ -21,8 +21,12 @@
|
|
|
21
21
|
"url": "https://github.com/furystack/furystack.git"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
|
-
"
|
|
25
|
-
"
|
|
24
|
+
"FuryStack",
|
|
25
|
+
"utilities",
|
|
26
|
+
"observable",
|
|
27
|
+
"events",
|
|
28
|
+
"debounce",
|
|
29
|
+
"disposable"
|
|
26
30
|
],
|
|
27
31
|
"publishConfig": {
|
|
28
32
|
"access": "public"
|
|
@@ -35,6 +39,10 @@
|
|
|
35
39
|
"homepage": "https://github.com/furystack/furystack",
|
|
36
40
|
"devDependencies": {
|
|
37
41
|
"typescript": "^5.9.3",
|
|
38
|
-
"vitest": "^4.0.
|
|
39
|
-
}
|
|
42
|
+
"vitest": "^4.0.17"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=22.0.0"
|
|
46
|
+
},
|
|
47
|
+
"sideEffects": false
|
|
40
48
|
}
|
package/src/event-hub.ts
CHANGED
|
@@ -2,6 +2,33 @@ type ListenerFunction<EventTypeMap extends object, T extends keyof EventTypeMap>
|
|
|
2
2
|
arg: EventTypeMap[T],
|
|
3
3
|
) => void | PromiseLike<void>
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* A typed event emitter that provides type-safe event subscription and emission.
|
|
7
|
+
* Use this to create strongly-typed pub/sub patterns in your application.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam EventTypeMap - An object type where keys are event names and values are event payload types
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* type MyEvents = {
|
|
13
|
+
* userLoggedIn: { userId: string }
|
|
14
|
+
* userLoggedOut: { userId: string }
|
|
15
|
+
* dataUpdated: { items: string[] }
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* const hub = new EventHub<MyEvents>()
|
|
19
|
+
*
|
|
20
|
+
* // Subscribe to events
|
|
21
|
+
* hub.subscribe('userLoggedIn', (event) => {
|
|
22
|
+
* console.log('User logged in:', event.userId)
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* // Emit events
|
|
26
|
+
* hub.emit('userLoggedIn', { userId: '123' })
|
|
27
|
+
*
|
|
28
|
+
* // Clean up when done
|
|
29
|
+
* hub[Symbol.dispose]()
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
5
32
|
export class EventHub<EventTypeMap extends object> implements Disposable {
|
|
6
33
|
private listeners = new Map<keyof EventTypeMap, Set<ListenerFunction<EventTypeMap, keyof EventTypeMap>>>()
|
|
7
34
|
|
package/src/sort-by.ts
CHANGED
|
@@ -25,7 +25,6 @@ export const compareBy = <T, K extends keyof T>(entity1: T, entity2: T, field: K
|
|
|
25
25
|
return 0
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
Array.prototype.sortBy = function (key, direction = 'asc') {
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
28
|
+
Array.prototype.sortBy = function <T, K extends keyof T>(key: K, direction: 'asc' | 'desc' = 'asc'): T[] {
|
|
30
29
|
return this.sort((a, b) => compareBy(a, b, key, direction))
|
|
31
30
|
}
|