@oscarpalmer/atoms 0.189.0 → 0.190.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/dist/beacon.d.mts +51 -31
- package/dist/beacon.mjs +163 -141
- package/dist/color/index.d.mts +1 -2
- package/dist/color/index.mjs +2 -2
- package/dist/color/instance.d.mts +3 -167
- package/dist/color/instance.mjs +58 -217
- package/dist/color/misc/get.d.mts +1 -2
- package/dist/color/misc/get.mjs +3 -3
- package/dist/color/misc/index.d.mts +4 -4
- package/dist/color/misc/index.mjs +9 -9
- package/dist/color/misc/is.d.mts +1 -2
- package/dist/color/misc/is.mjs +5 -2
- package/dist/color/models.d.mts +158 -2
- package/dist/function/memoize.d.mts +3 -9
- package/dist/function/memoize.mjs +43 -90
- package/dist/function/once.mjs +16 -4
- package/dist/herald.d.mts +19 -15
- package/dist/herald.mjs +79 -89
- package/dist/index.d.mts +173 -162
- package/dist/index.mjs +754 -996
- package/dist/internal/result.d.mts +6 -6
- package/dist/internal/result.mjs +1 -1
- package/dist/internal/value/has.d.mts +2 -2
- package/dist/logger.d.mts +7 -7
- package/dist/logger.mjs +72 -51
- package/dist/promise/helpers.d.mts +2 -2
- package/dist/promise/helpers.mjs +2 -2
- package/dist/queue.d.mts +24 -12
- package/dist/queue.mjs +288 -346
- package/dist/string/fuzzy.d.mts +4 -13
- package/dist/string/fuzzy.mjs +15 -41
- package/package.json +2 -2
- package/src/beacon.ts +262 -160
- package/src/color/index.ts +8 -8
- package/src/color/instance.ts +82 -258
- package/src/color/misc/get.ts +4 -4
- package/src/color/misc/index.ts +10 -11
- package/src/color/misc/is.ts +4 -1
- package/src/color/models.ts +180 -2
- package/src/function/memoize.ts +74 -65
- package/src/function/once.ts +4 -0
- package/src/herald.ts +136 -94
- package/src/internal/result.ts +6 -6
- package/src/internal/value/has.ts +2 -2
- package/src/logger.ts +93 -42
- package/src/promise/helpers.ts +2 -2
- package/src/queue.ts +480 -375
- package/src/string/fuzzy.ts +36 -31
package/dist/string/fuzzy.mjs
CHANGED
|
@@ -3,45 +3,6 @@ import { getString } from "../internal/string.mjs";
|
|
|
3
3
|
import { lowerCase } from "./case.mjs";
|
|
4
4
|
import { includes } from "./match.mjs";
|
|
5
5
|
//#region src/string/fuzzy.ts
|
|
6
|
-
/**
|
|
7
|
-
* Fuzzy searcher for an array of items
|
|
8
|
-
*/
|
|
9
|
-
var Fuzzy = class {
|
|
10
|
-
#state;
|
|
11
|
-
/**
|
|
12
|
-
* Get items currently being searched through
|
|
13
|
-
*
|
|
14
|
-
* @returns Original items
|
|
15
|
-
*/
|
|
16
|
-
get items() {
|
|
17
|
-
return this.#state.items.slice();
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Set new items to search through
|
|
21
|
-
*
|
|
22
|
-
* @param items New items to search through
|
|
23
|
-
*/
|
|
24
|
-
set items(items) {
|
|
25
|
-
if (Array.isArray(items)) {
|
|
26
|
-
this.#state.items = items.slice();
|
|
27
|
-
this.#state.strings = items.map(this.#state.handler);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Get strings currently being searched through _(the stringified version of `items`)_
|
|
32
|
-
*
|
|
33
|
-
* @returns Stringified items
|
|
34
|
-
*/
|
|
35
|
-
get strings() {
|
|
36
|
-
return this.#state.strings.slice();
|
|
37
|
-
}
|
|
38
|
-
constructor(state) {
|
|
39
|
-
this.#state = state;
|
|
40
|
-
}
|
|
41
|
-
search(value, options) {
|
|
42
|
-
return search(this.#state.items, this.#state.strings, value, options == null ? this.#state : getFuzzyOptions(options, this.#state));
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
6
|
function getHandler(input) {
|
|
46
7
|
if (input == null || input === getString) return getString;
|
|
47
8
|
switch (typeof input) {
|
|
@@ -80,7 +41,20 @@ function getTolerance(input, state) {
|
|
|
80
41
|
}
|
|
81
42
|
function fuzzy(items, configuration) {
|
|
82
43
|
if (!Array.isArray(items)) throw new TypeError(MESSAGE_ARRAY);
|
|
83
|
-
|
|
44
|
+
const state = getFuzzyState(items, configuration);
|
|
45
|
+
const instance = { search: (value, options) => search(state.items, state.strings, value, options == null ? state : getFuzzyOptions(options, state)) };
|
|
46
|
+
Object.defineProperties(instance, {
|
|
47
|
+
items: {
|
|
48
|
+
get: () => state.items.slice(),
|
|
49
|
+
set: (items) => {
|
|
50
|
+
if (!Array.isArray(items)) throw new TypeError(MESSAGE_ARRAY);
|
|
51
|
+
state.items = items.slice();
|
|
52
|
+
state.strings = items.map(state.handler);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
strings: { get: () => state.strings.slice() }
|
|
56
|
+
});
|
|
57
|
+
return Object.freeze(instance);
|
|
84
58
|
}
|
|
85
59
|
fuzzy.match = fuzzyMatch;
|
|
86
60
|
/**
|
|
@@ -88,7 +62,7 @@ fuzzy.match = fuzzyMatch;
|
|
|
88
62
|
*
|
|
89
63
|
* @param haystack Haystack to search through
|
|
90
64
|
* @param needle Needle to search for
|
|
91
|
-
* @returns `true` if the needle matches the haystack in a fuzzy way, `false`
|
|
65
|
+
* @returns `true` if the needle matches the haystack in a fuzzy way, otherwise `false`
|
|
92
66
|
*/
|
|
93
67
|
function fuzzyMatch(haystack, needle) {
|
|
94
68
|
if (typeof haystack !== "string" || typeof needle !== "string") return false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/atoms",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.190.0",
|
|
4
4
|
"description": "Atomic utilities for making your JavaScript better.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"helper",
|
|
@@ -259,7 +259,7 @@
|
|
|
259
259
|
"devDependencies": {
|
|
260
260
|
"@oxlint/plugins": "^1.78",
|
|
261
261
|
"@types/node": "^26.2",
|
|
262
|
-
"@vitest/coverage-istanbul": "
|
|
262
|
+
"@vitest/coverage-istanbul": "4.1.10",
|
|
263
263
|
"eslint": "^10.8",
|
|
264
264
|
"jsdom": "^30",
|
|
265
265
|
"tsdown": "^0.22",
|
package/src/beacon.ts
CHANGED
|
@@ -7,54 +7,31 @@ import type {PlainObject} from './models';
|
|
|
7
7
|
/**
|
|
8
8
|
* A beacon is a lighthouse, holding an observable value that can be subscribed to and emitted from
|
|
9
9
|
*/
|
|
10
|
-
|
|
11
|
-
readonly #options: Options;
|
|
12
|
-
readonly #state: BeaconState<Value>;
|
|
13
|
-
|
|
10
|
+
export type Beacon<Value> = {
|
|
14
11
|
/**
|
|
15
12
|
* Is the beacon active?
|
|
16
13
|
*/
|
|
17
|
-
get active(): boolean
|
|
18
|
-
return this.#state.active;
|
|
19
|
-
}
|
|
14
|
+
get active(): boolean;
|
|
20
15
|
|
|
21
16
|
/**
|
|
22
|
-
*
|
|
17
|
+
* Is the beacon closed?
|
|
23
18
|
*/
|
|
24
|
-
get
|
|
25
|
-
if (!this.#state.active) {
|
|
26
|
-
throw new Error(MESSAGE_BEACON);
|
|
27
|
-
}
|
|
19
|
+
get closed(): boolean;
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
/**
|
|
22
|
+
* The observable that can be subscribed to
|
|
23
|
+
*/
|
|
24
|
+
get observable(): Observable<Value>;
|
|
31
25
|
|
|
32
26
|
/**
|
|
33
27
|
* The current value
|
|
34
28
|
*/
|
|
35
|
-
get value(): Value
|
|
36
|
-
return this.#state.value;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
constructor(value: Value, options?: BeaconOptions<Value>) {
|
|
40
|
-
const observers = new Map<Subscription<Value>, Observer<Value>>();
|
|
41
|
-
|
|
42
|
-
this.#options = getBeaconOptions(options);
|
|
43
|
-
|
|
44
|
-
this.#state = {
|
|
45
|
-
observers,
|
|
46
|
-
value,
|
|
47
|
-
active: true,
|
|
48
|
-
observable: new Observable(this, observers),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
29
|
+
get value(): Value;
|
|
51
30
|
|
|
52
31
|
/**
|
|
53
|
-
*
|
|
32
|
+
* Close the beacon
|
|
54
33
|
*/
|
|
55
|
-
|
|
56
|
-
finishBeacon(this.#state, false);
|
|
57
|
-
}
|
|
34
|
+
close(): void;
|
|
58
35
|
|
|
59
36
|
/**
|
|
60
37
|
* Emit a new value
|
|
@@ -62,9 +39,7 @@ class Beacon<Value> {
|
|
|
62
39
|
* @param value Value to set and emit
|
|
63
40
|
* @param finish Finish the beacon after emitting? _(defaults to `false`)_
|
|
64
41
|
*/
|
|
65
|
-
emit(value: Value, finish?: boolean): void
|
|
66
|
-
this.#on(TYPE_NEXT, value, finish);
|
|
67
|
-
}
|
|
42
|
+
emit(value: Value, finish?: boolean): void;
|
|
68
43
|
|
|
69
44
|
/**
|
|
70
45
|
* Emit an error
|
|
@@ -72,44 +47,18 @@ class Beacon<Value> {
|
|
|
72
47
|
* @param value Error to emit
|
|
73
48
|
* @param finish Finish the beacon after emitting? _(defaults to `false`)_
|
|
74
49
|
*/
|
|
75
|
-
error(value: Error, finish?: boolean): void
|
|
76
|
-
this.#on(TYPE_ERROR, value, finish);
|
|
77
|
-
}
|
|
50
|
+
error(value: Error, finish?: boolean): void;
|
|
78
51
|
|
|
79
52
|
/**
|
|
80
53
|
* Finish the beacon
|
|
81
54
|
*/
|
|
82
|
-
finish(): void
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
#on(type: keyof Observer<never>, value: Error | Value, finish?: boolean): void {
|
|
87
|
-
if (!this.#state.active) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (type === TYPE_NEXT) {
|
|
92
|
-
if (this.#options.equal(this.#state.value, value as Value)) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
this.#state.value = value as Value;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
for (const [, observer] of this.#state.observers) {
|
|
100
|
-
observer[type]?.(value as never);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (finish === true) {
|
|
104
|
-
finishBeacon(this.#state, true);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
55
|
+
finish(): void;
|
|
56
|
+
};
|
|
108
57
|
|
|
109
58
|
/**
|
|
110
59
|
* Options for Beacon
|
|
111
60
|
*/
|
|
112
|
-
type BeaconOptions<Value> = {
|
|
61
|
+
export type BeaconOptions<Value> = {
|
|
113
62
|
/**
|
|
114
63
|
* Method for comparing values for equality
|
|
115
64
|
*
|
|
@@ -124,30 +73,26 @@ type BeaconOptions<Value> = {
|
|
|
124
73
|
type BeaconState<Value> = {
|
|
125
74
|
active: boolean;
|
|
126
75
|
observable: Observable<Value>;
|
|
127
|
-
observers: Map<Subscription
|
|
76
|
+
observers: Map<Subscription, Observer<Value>>;
|
|
77
|
+
options: Required<BeaconOptions<Value>>;
|
|
128
78
|
value: Value;
|
|
129
79
|
};
|
|
130
80
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
constructor(instance: Beacon<Value>, observers: Map<Subscription<Value>, Observer<Value>>) {
|
|
138
|
-
this.#state = {
|
|
139
|
-
observers,
|
|
140
|
-
beacon: instance,
|
|
141
|
-
closed: false,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
81
|
+
export type Observable<Value> = {
|
|
82
|
+
/**
|
|
83
|
+
* Is the observable active?
|
|
84
|
+
*/
|
|
85
|
+
get active(): boolean;
|
|
144
86
|
|
|
145
87
|
/**
|
|
146
|
-
*
|
|
88
|
+
* Is the observable closed?
|
|
147
89
|
*/
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
90
|
+
get closed(): boolean;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Close the observable
|
|
94
|
+
*/
|
|
95
|
+
close(): void;
|
|
151
96
|
|
|
152
97
|
/**
|
|
153
98
|
* Subscribe to value changes
|
|
@@ -161,7 +106,7 @@ class Observable<Value> {
|
|
|
161
106
|
onNext: (value: Value) => void,
|
|
162
107
|
onError?: (error: Error) => void,
|
|
163
108
|
onComplete?: () => void,
|
|
164
|
-
): Subscription
|
|
109
|
+
): Subscription;
|
|
165
110
|
|
|
166
111
|
/**
|
|
167
112
|
* Subscribe to value changes
|
|
@@ -169,32 +114,12 @@ class Observable<Value> {
|
|
|
169
114
|
* @param observer Observer for changes
|
|
170
115
|
* @returns Subscription to the observable
|
|
171
116
|
*/
|
|
172
|
-
subscribe(observer: Observer<Value>): Subscription
|
|
173
|
-
|
|
174
|
-
subscribe(
|
|
175
|
-
first: Observer<Value> | ((value: Value) => void),
|
|
176
|
-
second?: (error: Error) => void,
|
|
177
|
-
third?: () => void,
|
|
178
|
-
): Subscription<Value> {
|
|
179
|
-
if (this.#state.closed) {
|
|
180
|
-
throw new Error(MESSAGE_OBSERVABLE);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const observer = getObserver(first, second, third);
|
|
184
|
-
const instance = new Subscription(this.#state);
|
|
185
|
-
|
|
186
|
-
this.#state.observers.set(instance, observer);
|
|
187
|
-
|
|
188
|
-
observer.next?.(this.#state.beacon.value);
|
|
189
|
-
|
|
190
|
-
return instance;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
117
|
+
subscribe(observer: Observer<Value>): Subscription;
|
|
118
|
+
};
|
|
193
119
|
|
|
194
120
|
type ObservableState<Value> = {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
observers: Map<Subscription<Value>, Observer<Value>>;
|
|
121
|
+
active: boolean;
|
|
122
|
+
beacon: BeaconState<Value>;
|
|
198
123
|
};
|
|
199
124
|
|
|
200
125
|
/**
|
|
@@ -215,53 +140,26 @@ type Observer<Value> = {
|
|
|
215
140
|
next?: (value: Value) => void;
|
|
216
141
|
};
|
|
217
142
|
|
|
218
|
-
type
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
class Subscription<Value> {
|
|
224
|
-
readonly #state: SubscriptionState<Value>;
|
|
225
|
-
|
|
226
|
-
constructor(state: ObservableState<Value>) {
|
|
227
|
-
this.#state = {
|
|
228
|
-
...state,
|
|
229
|
-
closed: false,
|
|
230
|
-
};
|
|
231
|
-
}
|
|
143
|
+
export type Subscription = {
|
|
144
|
+
/**
|
|
145
|
+
* Is the subscription active?
|
|
146
|
+
*/
|
|
147
|
+
get active(): boolean;
|
|
232
148
|
|
|
233
149
|
/**
|
|
234
150
|
* Is the subscription closed?
|
|
235
151
|
*/
|
|
236
|
-
get closed(): boolean
|
|
237
|
-
return this.#state.closed || !this.#state.beacon.active;
|
|
238
|
-
}
|
|
152
|
+
get closed(): boolean;
|
|
239
153
|
|
|
240
154
|
/**
|
|
241
|
-
*
|
|
155
|
+
* Close the subscription
|
|
242
156
|
*/
|
|
243
|
-
|
|
244
|
-
if (!this.#state.closed) {
|
|
245
|
-
this.unsubscribe();
|
|
246
|
-
}
|
|
247
|
-
}
|
|
157
|
+
close(): void;
|
|
248
158
|
|
|
249
159
|
/**
|
|
250
160
|
* Unsubscribe from its observable
|
|
251
161
|
*/
|
|
252
|
-
unsubscribe(): void
|
|
253
|
-
if (!this.#state.closed) {
|
|
254
|
-
this.#state.closed = true;
|
|
255
|
-
|
|
256
|
-
this.#state.observers.delete(this);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
type SubscriptionState<Value> = {
|
|
262
|
-
closed: boolean;
|
|
263
|
-
beacon: Beacon<Value>;
|
|
264
|
-
observers: Map<Subscription<Value>, Observer<Value>>;
|
|
162
|
+
unsubscribe(): void;
|
|
265
163
|
};
|
|
266
164
|
|
|
267
165
|
// #endregion
|
|
@@ -276,7 +174,61 @@ type SubscriptionState<Value> = {
|
|
|
276
174
|
* @returns Beacon instance
|
|
277
175
|
*/
|
|
278
176
|
export function beacon<Value>(value: Value, options?: BeaconOptions<Value>): Beacon<Value> {
|
|
279
|
-
|
|
177
|
+
const state: BeaconState<Value> = {
|
|
178
|
+
value,
|
|
179
|
+
active: true,
|
|
180
|
+
observable: undefined as never,
|
|
181
|
+
observers: new Map(),
|
|
182
|
+
options: getBeaconOptions(options),
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const instance = {
|
|
186
|
+
close: (): void => {
|
|
187
|
+
finishBeacon(state, false);
|
|
188
|
+
},
|
|
189
|
+
emit: (value: Value, finish?: boolean): void => {
|
|
190
|
+
update(TYPE_NEXT, state, value, finish);
|
|
191
|
+
},
|
|
192
|
+
error: (value: Error, finish?: boolean): void => {
|
|
193
|
+
update(TYPE_ERROR, state, value, finish);
|
|
194
|
+
},
|
|
195
|
+
finish: (): void => {
|
|
196
|
+
finishBeacon(state, true);
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
Object.defineProperties(instance, {
|
|
201
|
+
[KEY_BEACON]: {
|
|
202
|
+
enumerable: false,
|
|
203
|
+
value: NAME_BEACON,
|
|
204
|
+
},
|
|
205
|
+
active: {
|
|
206
|
+
enumerable: true,
|
|
207
|
+
get: () => state.active,
|
|
208
|
+
},
|
|
209
|
+
closed: {
|
|
210
|
+
enumerable: true,
|
|
211
|
+
get: () => !state.active,
|
|
212
|
+
},
|
|
213
|
+
observable: {
|
|
214
|
+
enumerable: true,
|
|
215
|
+
get: () => {
|
|
216
|
+
if (!state.active) {
|
|
217
|
+
throw new Error(MESSAGE_BEACON);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
state.observable ??= observe(state);
|
|
221
|
+
|
|
222
|
+
return state.observable;
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
value: {
|
|
226
|
+
enumerable: true,
|
|
227
|
+
get: () => state.value,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
return Object.freeze(instance) as Beacon<Value>;
|
|
280
232
|
}
|
|
281
233
|
|
|
282
234
|
function finishBeacon<Value>(state: BeaconState<Value>, emit: boolean): void {
|
|
@@ -296,20 +248,21 @@ function finishBeacon<Value>(state: BeaconState<Value>, emit: boolean): void {
|
|
|
296
248
|
observer.complete?.();
|
|
297
249
|
}
|
|
298
250
|
|
|
299
|
-
subscription.
|
|
251
|
+
subscription.close();
|
|
300
252
|
}
|
|
301
253
|
|
|
302
|
-
state.observable?.
|
|
303
|
-
|
|
254
|
+
state.observable?.close();
|
|
304
255
|
state.observers.clear();
|
|
256
|
+
|
|
257
|
+
state.observable = undefined as never;
|
|
305
258
|
}
|
|
306
259
|
|
|
307
|
-
function getBeaconOptions(input?: BeaconOptions<
|
|
308
|
-
const options:
|
|
260
|
+
function getBeaconOptions<Value>(input?: BeaconOptions<Value>): Required<BeaconOptions<Value>> {
|
|
261
|
+
const options: BeaconOptions<Value> = isPlainObject(input) ? (input as PlainObject) : {};
|
|
309
262
|
|
|
310
263
|
options.equal = typeof options.equal === 'function' ? options.equal : Object.is;
|
|
311
264
|
|
|
312
|
-
return options as
|
|
265
|
+
return options as Required<BeaconOptions<Value>>;
|
|
313
266
|
}
|
|
314
267
|
|
|
315
268
|
function getObservableCallback<Callback>(value: Callback): Callback {
|
|
@@ -340,22 +293,171 @@ function getObserver<Value>(
|
|
|
340
293
|
return observer;
|
|
341
294
|
}
|
|
342
295
|
|
|
296
|
+
/**
|
|
297
|
+
* Is the value a beacon?
|
|
298
|
+
*
|
|
299
|
+
* @param value Value to check
|
|
300
|
+
* @returns `true` if the value is a beacon, otherwise `false`
|
|
301
|
+
*/
|
|
302
|
+
export function isBeacon<Value = unknown>(value: unknown): value is Beacon<Value> {
|
|
303
|
+
return isBeaconInstance<Beacon<Value>>(NAME_BEACON, value);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function isBeaconInstance<Instance>(name: string, value: unknown): value is Instance {
|
|
307
|
+
return isPlainObject(value) && (value as PlainObject)[KEY_BEACON] === name;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Is the value an observable?
|
|
312
|
+
*
|
|
313
|
+
* @param value Value to check
|
|
314
|
+
* @returns `true` if the value is an observable, otherwise `false`
|
|
315
|
+
*/
|
|
316
|
+
export function isObservable<Value = unknown>(value: unknown): value is Observable<Value> {
|
|
317
|
+
return isBeaconInstance<Observable<Value>>(NAME_OBSERVABLE, value);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Is the value a subscription?
|
|
322
|
+
*
|
|
323
|
+
* @param value Value to check
|
|
324
|
+
* @returns `true` if the value is a subscription, otherwise `false`
|
|
325
|
+
*/
|
|
326
|
+
export function isSubscription(value: unknown): value is Subscription {
|
|
327
|
+
return isBeaconInstance<Subscription>(NAME_SUBSCRIPTION, value);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function observe<Value>(beacon: BeaconState<Value>): Observable<Value> {
|
|
331
|
+
const state: ObservableState<Value> = {
|
|
332
|
+
beacon,
|
|
333
|
+
active: beacon.active,
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const instance = {
|
|
337
|
+
close: (): void => {
|
|
338
|
+
state.active = false;
|
|
339
|
+
},
|
|
340
|
+
subscribe(
|
|
341
|
+
first: Observer<Value> | ((value: Value) => void),
|
|
342
|
+
second?: (error: Error) => void,
|
|
343
|
+
third?: () => void,
|
|
344
|
+
): Subscription {
|
|
345
|
+
if (!beacon.active || !state.active) {
|
|
346
|
+
throw new Error(MESSAGE_OBSERVABLE);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const observer = getObserver(first, second, third);
|
|
350
|
+
const subscription = subscribe(state);
|
|
351
|
+
|
|
352
|
+
beacon.observers.set(subscription, observer);
|
|
353
|
+
|
|
354
|
+
observer.next?.(beacon.value);
|
|
355
|
+
|
|
356
|
+
return subscription;
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
Object.defineProperties(instance, {
|
|
361
|
+
[KEY_BEACON]: {
|
|
362
|
+
enumerable: false,
|
|
363
|
+
value: NAME_OBSERVABLE,
|
|
364
|
+
},
|
|
365
|
+
active: {
|
|
366
|
+
enumerable: true,
|
|
367
|
+
get: () => beacon.active && state.active,
|
|
368
|
+
},
|
|
369
|
+
closed: {
|
|
370
|
+
enumerable: true,
|
|
371
|
+
get: () => !beacon.active || !state.active,
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
return Object.freeze(instance) as Observable<Value>;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function subscribe<Value>(observable: ObservableState<Value>): Subscription {
|
|
379
|
+
function unsubscribe(): void {
|
|
380
|
+
if (active) {
|
|
381
|
+
active = false;
|
|
382
|
+
|
|
383
|
+
observable.beacon.observers.delete(instance as Subscription);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
let active = true;
|
|
388
|
+
|
|
389
|
+
const instance = {
|
|
390
|
+
close: (): void => {
|
|
391
|
+
unsubscribe();
|
|
392
|
+
},
|
|
393
|
+
unsubscribe: (): void => {
|
|
394
|
+
unsubscribe();
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
Object.defineProperties(instance, {
|
|
399
|
+
[KEY_BEACON]: {
|
|
400
|
+
enumerable: false,
|
|
401
|
+
value: NAME_SUBSCRIPTION,
|
|
402
|
+
},
|
|
403
|
+
active: {
|
|
404
|
+
enumerable: true,
|
|
405
|
+
get: () => observable.beacon.active && observable.active && active,
|
|
406
|
+
},
|
|
407
|
+
closed: {
|
|
408
|
+
enumerable: true,
|
|
409
|
+
get: () => !observable.beacon.active || !observable.active || !active,
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
return Object.freeze(instance) as Subscription;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function update<Value>(
|
|
417
|
+
type: keyof Observer<never>,
|
|
418
|
+
state: BeaconState<Value>,
|
|
419
|
+
value: Error | Value,
|
|
420
|
+
finish?: boolean,
|
|
421
|
+
): void {
|
|
422
|
+
if (!state.active) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (type === TYPE_NEXT) {
|
|
427
|
+
if (state.options.equal(state.value, value as Value)) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
state.value = value as Value;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
for (const [, observer] of state.observers) {
|
|
435
|
+
observer[type]?.(value as never);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (finish === true) {
|
|
439
|
+
finishBeacon(state, true);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
343
443
|
// #endregion
|
|
344
444
|
|
|
345
445
|
// #region Variables
|
|
346
446
|
|
|
347
|
-
const
|
|
447
|
+
const KEY_BEACON = '$beacon';
|
|
348
448
|
|
|
349
|
-
const
|
|
449
|
+
const MESSAGE_BEACON = 'Cannot retrieve observable from a closed beacon';
|
|
350
450
|
|
|
351
|
-
const
|
|
451
|
+
const MESSAGE_OBSERVABLE = 'Cannot subscribe to a closed observable';
|
|
352
452
|
|
|
353
|
-
const
|
|
453
|
+
const NAME_BEACON = 'beacon';
|
|
354
454
|
|
|
355
|
-
|
|
455
|
+
const NAME_OBSERVABLE = 'observable';
|
|
456
|
+
|
|
457
|
+
const NAME_SUBSCRIPTION = 'subscription';
|
|
356
458
|
|
|
357
|
-
|
|
459
|
+
const TYPE_ERROR = 'error';
|
|
358
460
|
|
|
359
|
-
|
|
461
|
+
const TYPE_NEXT = 'next';
|
|
360
462
|
|
|
361
463
|
// #endregion
|
package/src/color/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {color} from './instance';
|
|
2
2
|
import {isColor} from './misc/is';
|
|
3
|
-
import type {HSLAColor, HSLColor,
|
|
3
|
+
import type {Color, HSLAColor, HSLColor, HWBAColor, HWBColor, RGBAColor, RGBColor} from './models';
|
|
4
4
|
|
|
5
5
|
// #region Functions
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ import type {HSLAColor, HSLColor, HWBColor, HWBAColor, RGBAColor, RGBColor} from
|
|
|
14
14
|
* @returns _Color_ instance
|
|
15
15
|
*/
|
|
16
16
|
export function getColor(value: unknown): Color {
|
|
17
|
-
return isColor(value) ? value :
|
|
17
|
+
return isColor(value) ? value : color(value);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// #endregion
|
|
@@ -27,8 +27,8 @@ export {
|
|
|
27
27
|
getHexColor,
|
|
28
28
|
getHslaColor,
|
|
29
29
|
getHslColor,
|
|
30
|
-
getHwbColor,
|
|
31
30
|
getHwbaColor,
|
|
31
|
+
getHwbColor,
|
|
32
32
|
getRgbaColor,
|
|
33
33
|
getRgbColor,
|
|
34
34
|
} from './misc/get';
|
|
@@ -36,16 +36,16 @@ export {
|
|
|
36
36
|
export {
|
|
37
37
|
isColor,
|
|
38
38
|
isHexColor,
|
|
39
|
+
isHslaColor,
|
|
39
40
|
isHslColor,
|
|
40
41
|
isHslLike,
|
|
41
|
-
isHslaColor,
|
|
42
|
-
isHwbColor,
|
|
43
|
-
isHwbLike,
|
|
44
42
|
isHwbaColor,
|
|
45
43
|
isHwbaLike,
|
|
44
|
+
isHwbColor,
|
|
45
|
+
isHwbLike,
|
|
46
|
+
isRgbaColor,
|
|
46
47
|
isRgbColor,
|
|
47
48
|
isRgbLike,
|
|
48
|
-
isRgbaColor,
|
|
49
49
|
} from './misc/is';
|
|
50
50
|
|
|
51
51
|
export {
|