@oscarpalmer/atoms 0.197.0 → 0.199.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.mjs +46 -43
- package/dist/color/instance.mjs +14 -10
- package/dist/function/retry.mjs +6 -8
- package/dist/index.d.mts +826 -710
- package/dist/index.mjs +381 -295
- package/dist/internal/array/find.d.mts +2 -2
- package/dist/internal/array/find.mjs +11 -11
- package/dist/internal/function/memoize.mjs +4 -3
- package/dist/internal/function/timer.mjs +3 -5
- package/dist/internal/herald.mjs +26 -23
- package/dist/internal/subscription.d.mts +72 -16
- package/dist/internal/subscription.mjs +94 -29
- package/dist/internal/value/compare.mjs +2 -2
- package/dist/internal/value/equal.mjs +30 -30
- package/dist/internal/value/handlers.d.mts +3 -3
- package/dist/internal/value/handlers.mjs +6 -6
- package/dist/promise/delay.mjs +2 -2
- package/dist/promise/helpers.d.mts +3 -3
- package/dist/promise/helpers.mjs +4 -4
- package/dist/promise/index.mjs +3 -3
- package/dist/promise/timed.mjs +2 -2
- package/dist/queue.mjs +3 -3
- package/dist/string/fuzzy.mjs +18 -18
- package/dist/string/normalize.mjs +12 -12
- package/dist/string/template.mjs +8 -8
- package/dist/subscription.d.mts +2 -2
- package/dist/subscription.mjs +2 -2
- package/dist/value/clone.d.mts +40 -13
- package/dist/value/clone.mjs +89 -72
- package/dist/value/merge.mjs +5 -5
- package/package.json +3 -2
|
@@ -10,14 +10,14 @@ type Parameters = {
|
|
|
10
10
|
key?: unknown;
|
|
11
11
|
value?: unknown;
|
|
12
12
|
};
|
|
13
|
+
declare function createFindParameters(original: unknown[]): Parameters;
|
|
13
14
|
declare function findValue(type: Exclude<FindValueType, 'item'>, array: unknown[], parameters: unknown[], reversed: boolean): number;
|
|
14
15
|
declare function findValue(type: Exclude<FindValueType, 'index'>, array: unknown[], parameters: unknown[], reversed: boolean): unknown;
|
|
15
16
|
declare function findAbsoluteValueOrDefault(array: unknown[], parameters: unknown[], defaultValue: unknown, useDefaultValue: boolean, reversed: boolean): unknown;
|
|
16
17
|
declare function findValues(type: FindValuesType, array: unknown[], parameters: unknown[], mapper?: unknown): FindValuesResult;
|
|
17
|
-
declare function getFindParameters(original: unknown[]): Parameters;
|
|
18
18
|
declare const FIND_VALUE_INDEX = "index";
|
|
19
19
|
declare const FIND_VALUE_ITEM = "item";
|
|
20
20
|
declare const FIND_VALUES_ALL: FindValuesType;
|
|
21
21
|
declare const FIND_VALUES_UNIQUE: FindValuesType;
|
|
22
22
|
//#endregion
|
|
23
|
-
export { FIND_VALUES_ALL, FIND_VALUES_UNIQUE, FIND_VALUE_INDEX, FIND_VALUE_ITEM, findAbsoluteValueOrDefault, findValue, findValues
|
|
23
|
+
export { FIND_VALUES_ALL, FIND_VALUES_UNIQUE, FIND_VALUE_INDEX, FIND_VALUE_ITEM, createFindParameters, findAbsoluteValueOrDefault, findValue, findValues };
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { getArrayCallback, getArrayCallbacks } from "./callbacks.mjs";
|
|
2
2
|
//#region src/internal/array/find.ts
|
|
3
|
+
function createFindParameters(original) {
|
|
4
|
+
const { length } = original;
|
|
5
|
+
return {
|
|
6
|
+
bool: length === 1 && typeof original[0] === "function" ? original[0] : void 0,
|
|
7
|
+
key: length === 2 ? original[0] : void 0,
|
|
8
|
+
value: length === 1 && typeof original[0] !== "function" ? original[0] : original[1]
|
|
9
|
+
};
|
|
10
|
+
}
|
|
3
11
|
function findValue(type, array, parameters, reversed) {
|
|
4
12
|
const findIndex = type === FIND_VALUE_INDEX;
|
|
5
13
|
if (!Array.isArray(array) || array.length === 0) return findIndex ? -1 : void 0;
|
|
6
|
-
const { bool, key, value } =
|
|
14
|
+
const { bool, key, value } = createFindParameters(parameters);
|
|
7
15
|
const callbacks = getArrayCallbacks(bool, key);
|
|
8
16
|
if (callbacks?.bool == null && callbacks?.keyed == null) {
|
|
9
17
|
if (findIndex) return reversed ? array.lastIndexOf(value) : array.indexOf(value);
|
|
@@ -38,7 +46,7 @@ function findValues(type, array, parameters, mapper) {
|
|
|
38
46
|
};
|
|
39
47
|
if (!Array.isArray(array) || array.length === 0) return result;
|
|
40
48
|
const { length } = array;
|
|
41
|
-
const { bool, key, value } =
|
|
49
|
+
const { bool, key, value } = createFindParameters(parameters);
|
|
42
50
|
const callbacks = getArrayCallbacks(bool, key);
|
|
43
51
|
if (type === "unique" && callbacks?.keyed == null && length >= FIND_UNIQUE_THRESHOLD) {
|
|
44
52
|
result.matched = [...new Set(array)];
|
|
@@ -65,18 +73,10 @@ function findValues(type, array, parameters, mapper) {
|
|
|
65
73
|
}
|
|
66
74
|
return result;
|
|
67
75
|
}
|
|
68
|
-
function getFindParameters(original) {
|
|
69
|
-
const { length } = original;
|
|
70
|
-
return {
|
|
71
|
-
bool: length === 1 && typeof original[0] === "function" ? original[0] : void 0,
|
|
72
|
-
key: length === 2 ? original[0] : void 0,
|
|
73
|
-
value: length === 1 && typeof original[0] !== "function" ? original[0] : original[1]
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
76
|
const FIND_VALUE_INDEX = "index";
|
|
77
77
|
const FIND_VALUE_ITEM = "item";
|
|
78
78
|
const FIND_VALUES_ALL = "all";
|
|
79
79
|
const FIND_VALUES_UNIQUE = "unique";
|
|
80
80
|
const FIND_UNIQUE_THRESHOLD = 100;
|
|
81
81
|
//#endregion
|
|
82
|
-
export { FIND_VALUES_ALL, FIND_VALUES_UNIQUE, FIND_VALUE_INDEX, FIND_VALUE_ITEM, findAbsoluteValueOrDefault, findValue, findValues
|
|
82
|
+
export { FIND_VALUES_ALL, FIND_VALUES_UNIQUE, FIND_VALUE_INDEX, FIND_VALUE_ITEM, createFindParameters, findAbsoluteValueOrDefault, findValue, findValues };
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { isPlainObject } from "../is.mjs";
|
|
2
2
|
import { getString, join } from "../string/misc.mjs";
|
|
3
|
+
import { getNumberOrDefault } from "../defaults.mjs";
|
|
3
4
|
import { SizedMap } from "../sized/map.mjs";
|
|
4
5
|
//#region src/internal/function/memoize.ts
|
|
5
|
-
function
|
|
6
|
+
function createMemoizationOptions(input) {
|
|
6
7
|
const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
|
|
7
8
|
return {
|
|
8
9
|
cacheKey: typeof cacheKey === "function" ? cacheKey : void 0,
|
|
9
|
-
cacheSize:
|
|
10
|
+
cacheSize: getNumberOrDefault(cacheSize, MEMOIZED_CACHE_SIZE_DEFAULT)
|
|
10
11
|
};
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
@@ -21,7 +22,7 @@ function memoize(callback, options) {
|
|
|
21
22
|
const state = {
|
|
22
23
|
cache: void 0,
|
|
23
24
|
getter: void 0,
|
|
24
|
-
options:
|
|
25
|
+
options: createMemoizationOptions(options)
|
|
25
26
|
};
|
|
26
27
|
state.cache = new SizedMap(state.options.cacheSize);
|
|
27
28
|
state.getter = (...parameters) => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getNumberOrDefault } from "../defaults.mjs";
|
|
1
2
|
//#region src/internal/function/timer.ts
|
|
2
3
|
function getAsyncTimer(type, callback, time) {
|
|
3
4
|
function cancel() {
|
|
@@ -24,7 +25,7 @@ function getAsyncTimer(type, callback, time) {
|
|
|
24
25
|
}
|
|
25
26
|
} else id = startTimer(() => run(item));
|
|
26
27
|
}
|
|
27
|
-
const interval =
|
|
28
|
+
const interval = getNumberOrDefault(time, 0);
|
|
28
29
|
const throttle = type === TIMER_THROTTLE;
|
|
29
30
|
let id;
|
|
30
31
|
let last;
|
|
@@ -47,9 +48,6 @@ function getAsyncTimer(type, callback, time) {
|
|
|
47
48
|
Object.defineProperty(timer, TIMER_CANCEL, { value: () => cancel() });
|
|
48
49
|
return timer;
|
|
49
50
|
}
|
|
50
|
-
function getInterval(value) {
|
|
51
|
-
return typeof value === "number" && value > 0 ? value : 0;
|
|
52
|
-
}
|
|
53
51
|
function getTimer(type, callback, time) {
|
|
54
52
|
function cancel() {
|
|
55
53
|
clearTimer(id);
|
|
@@ -62,7 +60,7 @@ function getTimer(type, callback, time) {
|
|
|
62
60
|
callback(...args);
|
|
63
61
|
} else id = startTimer(run);
|
|
64
62
|
}
|
|
65
|
-
const interval =
|
|
63
|
+
const interval = getNumberOrDefault(time, 0);
|
|
66
64
|
const throttle = type === TIMER_THROTTLE;
|
|
67
65
|
let args;
|
|
68
66
|
let id;
|
package/dist/internal/herald.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isPlainObject } from "./is.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { SUBSCRIPTION_NAME, isSubscription, subscriptions } from "./subscription.mjs";
|
|
3
3
|
//#region src/internal/herald.ts
|
|
4
4
|
function createEvents(herald, state) {
|
|
5
5
|
const events = {};
|
|
@@ -7,35 +7,35 @@ function createEvents(herald, state) {
|
|
|
7
7
|
for (const key of state.keys) events[key] = (callback, signal) => herald.subscribe(key, callback, signal);
|
|
8
8
|
return Object.freeze(events);
|
|
9
9
|
}
|
|
10
|
-
function
|
|
11
|
-
const items = state.subscriptions.state.values.from.keyed?.get(event);
|
|
12
|
-
if (items == null || items.size === 0) return;
|
|
13
|
-
for (const [callback] of items) callback(...parameters);
|
|
14
|
-
}
|
|
15
|
-
function getHeraldSubscriptionProperty(input) {
|
|
16
|
-
if (input == null) return heraldSubscription;
|
|
17
|
-
const property = isPlainObject(input) ? input : {};
|
|
18
|
-
if (typeof property.key !== "string" || property.value != null && typeof property.value !== "string") throw new Error(HERALD_MESSAGE_PROPERTY);
|
|
19
|
-
return {
|
|
20
|
-
key: property.key,
|
|
21
|
-
value: property.value
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function getHeraldState(input) {
|
|
10
|
+
function createHeraldState(input) {
|
|
25
11
|
const options = isPlainObject(input) ? input : {};
|
|
26
12
|
if (!Array.isArray(options.names) || options.names.length === 0 || !options.names.every((name) => typeof name === "string")) throw new Error(HERALD_MESSAGE_ARRAY);
|
|
27
13
|
if (options.onCreate != null && typeof options.onCreate !== "function") throw new Error(HERALD_MESSAGE_ONCREATE);
|
|
28
14
|
const keys = new Set(options.names);
|
|
29
|
-
const property =
|
|
15
|
+
const property = createHeraldSubscriptionProperty(options.property);
|
|
30
16
|
return {
|
|
31
17
|
keys,
|
|
32
|
-
|
|
18
|
+
store: subscriptions({
|
|
33
19
|
keys,
|
|
34
20
|
property
|
|
35
21
|
}),
|
|
36
22
|
onCreate: options.onCreate
|
|
37
23
|
};
|
|
38
24
|
}
|
|
25
|
+
function createHeraldSubscriptionProperty(input) {
|
|
26
|
+
if (input == null) return heraldSubscription;
|
|
27
|
+
const property = isPlainObject(input) ? input : {};
|
|
28
|
+
if (typeof property.key !== "string" || property.value != null && typeof property.value !== "string") throw new Error(HERALD_MESSAGE_PROPERTY);
|
|
29
|
+
return {
|
|
30
|
+
key: property.key,
|
|
31
|
+
value: property.value
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function emitForHerald(state, event, ...parameters) {
|
|
35
|
+
const items = state.store.values.from.keyed?.get(event);
|
|
36
|
+
if (items == null || items.size === 0) return;
|
|
37
|
+
for (const [callback] of items) callback(...parameters);
|
|
38
|
+
}
|
|
39
39
|
/**
|
|
40
40
|
* Create a _Herald_ for announcing named events
|
|
41
41
|
*
|
|
@@ -44,11 +44,11 @@ function getHeraldState(input) {
|
|
|
44
44
|
* @returns _Herald_ instance
|
|
45
45
|
*/
|
|
46
46
|
function herald(options) {
|
|
47
|
-
const state =
|
|
47
|
+
const state = createHeraldState(options);
|
|
48
48
|
const instance = {
|
|
49
|
-
clear: () => state.
|
|
49
|
+
clear: () => state.store.clear(),
|
|
50
50
|
emit: (event, ...parameters) => emitForHerald(state, event, ...parameters),
|
|
51
|
-
observed: (event) => (state.
|
|
51
|
+
observed: (event) => (state.store.items.keyed?.get(event)?.size ?? 0) > 0,
|
|
52
52
|
subscribe: (key, callback, signal) => subscribeToHerald(state, key, callback, signal)
|
|
53
53
|
};
|
|
54
54
|
Object.defineProperties(instance, {
|
|
@@ -91,7 +91,7 @@ function isHeraldSubscription(value) {
|
|
|
91
91
|
return isSubscription(value) && value[HERALD_PROPERTY] === "subscription";
|
|
92
92
|
}
|
|
93
93
|
function subscribeToHerald(state, key, callback, signal) {
|
|
94
|
-
const [subscription, existing] = state.
|
|
94
|
+
const [subscription, existing] = state.store.create({
|
|
95
95
|
key,
|
|
96
96
|
signal,
|
|
97
97
|
value: callback
|
|
@@ -105,6 +105,9 @@ const HERALD_MESSAGE_ONCREATE = `Herald requires a valid onCreate callback for s
|
|
|
105
105
|
const HERALD_MESSAGE_PROPERTY = `Herald requires valid property information for subscription identification`;
|
|
106
106
|
const HERALD_NAME_EVENTS = "events";
|
|
107
107
|
const HERALD_NAME_HERALD = "herald";
|
|
108
|
-
const heraldSubscription = {
|
|
108
|
+
const heraldSubscription = {
|
|
109
|
+
key: HERALD_PROPERTY,
|
|
110
|
+
value: SUBSCRIPTION_NAME
|
|
111
|
+
};
|
|
109
112
|
//#endregion
|
|
110
113
|
export { herald, isHerald, isHeraldEvents, isHeraldSubscription };
|
|
@@ -10,10 +10,25 @@ type Subscription = {
|
|
|
10
10
|
*/
|
|
11
11
|
unsubscribe(): void;
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Parameters for creating a subscription
|
|
15
|
+
*/
|
|
13
16
|
type SubscriptionParameters = {
|
|
17
|
+
/**
|
|
18
|
+
* Is the owner of the subscription alive? _(defaults to `true`)_
|
|
19
|
+
*/
|
|
14
20
|
isActive?: () => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Key used to identify a subscription _(defaults to `undefined`)_
|
|
23
|
+
*/
|
|
15
24
|
key?: unknown;
|
|
25
|
+
/**
|
|
26
|
+
* Signal used to abort the subscription _(defaults to `undefined`)_
|
|
27
|
+
*/
|
|
16
28
|
signal?: AbortSignal;
|
|
29
|
+
/**
|
|
30
|
+
* Value used to identify a subscription
|
|
31
|
+
*/
|
|
17
32
|
value: unknown;
|
|
18
33
|
};
|
|
19
34
|
/**
|
|
@@ -25,37 +40,64 @@ type SubscriptionProperty = {
|
|
|
25
40
|
*/
|
|
26
41
|
key: string;
|
|
27
42
|
/**
|
|
28
|
-
* Value of the property used to identify a subscription
|
|
43
|
+
* Value of the property used to identify a subscription
|
|
29
44
|
*/
|
|
30
|
-
value
|
|
45
|
+
value: unknown;
|
|
31
46
|
};
|
|
32
|
-
type Subscriptions
|
|
33
|
-
|
|
47
|
+
type Subscriptions = {
|
|
48
|
+
/**
|
|
49
|
+
* Items of the subscriptions store
|
|
50
|
+
*
|
|
51
|
+
* - `any` - Set of subscriptions _(for unkeyed subscriptions)_
|
|
52
|
+
* - `keyed` - Map of keys to sets of subscriptions _(for keyed subscriptions)_
|
|
53
|
+
*/
|
|
54
|
+
readonly items: Readonly<SubscriptionsItems>;
|
|
55
|
+
/**
|
|
56
|
+
* Values of the subscriptions store
|
|
57
|
+
*
|
|
58
|
+
* - `from.any` - Map of values to subscriptions _(for unkeyed subscriptions)_
|
|
59
|
+
* - `from.keyed` - Map of keys to maps of values to subscriptions _(for keyed subscriptions)_
|
|
60
|
+
* - `to.any` - Map of subscriptions to values _(for unkeyed subscriptions)_
|
|
61
|
+
* - `to.keyed` - Map of keys to maps of subscriptions to values _(for keyed subscriptions)_
|
|
62
|
+
*/
|
|
63
|
+
readonly values: Readonly<SubscriptionsValues>;
|
|
64
|
+
/**
|
|
65
|
+
* Clear all subscriptions
|
|
66
|
+
*/
|
|
34
67
|
clear: () => void;
|
|
68
|
+
/**
|
|
69
|
+
* Create _(or retrieve)_ a subscription
|
|
70
|
+
*
|
|
71
|
+
* @param parameters Subscription parameters
|
|
72
|
+
* @returns Tuple holding subsccription and existing boolean
|
|
73
|
+
*/
|
|
35
74
|
create: (parameters: SubscriptionParameters) => [Subscription, boolean];
|
|
36
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Parameters for creating a subscription store
|
|
78
|
+
*/
|
|
37
79
|
type SubscriptionsParameters = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Allow any or specific keys for subscriptions? _(defaults to `false`, which prevents keyed subscriptions)_
|
|
82
|
+
*/
|
|
83
|
+
keys?: boolean | Set<Key>;
|
|
84
|
+
/**
|
|
85
|
+
* Property information for subscription identification
|
|
86
|
+
*/
|
|
87
|
+
property?: SubscriptionProperty;
|
|
45
88
|
};
|
|
46
89
|
type SubscriptionsItems = {
|
|
47
90
|
any: Set<Subscription>;
|
|
48
91
|
keyed?: Map<Key, Set<Subscription>>;
|
|
49
92
|
};
|
|
50
|
-
type SubscriptionsValues
|
|
51
|
-
from: SubscriptionsValuesItem<
|
|
52
|
-
to: SubscriptionsValuesItem<Subscription,
|
|
93
|
+
type SubscriptionsValues = {
|
|
94
|
+
from: SubscriptionsValuesItem<unknown, Subscription>;
|
|
95
|
+
to: SubscriptionsValuesItem<Subscription, unknown>;
|
|
53
96
|
};
|
|
54
97
|
type SubscriptionsValuesItem<MapKey, MapValue> = {
|
|
55
98
|
any: Map<MapKey, MapValue>;
|
|
56
99
|
keyed?: Map<Key, Map<MapKey, MapValue>>;
|
|
57
100
|
};
|
|
58
|
-
declare function createSubscriptions<Value = unknown>(parameters: SubscriptionsParameters): Subscriptions<Value>;
|
|
59
101
|
/**
|
|
60
102
|
* Is the value a subscription?
|
|
61
103
|
*
|
|
@@ -63,6 +105,20 @@ declare function createSubscriptions<Value = unknown>(parameters: SubscriptionsP
|
|
|
63
105
|
* @returns `true` if the value is a subscription, otherwise `false`
|
|
64
106
|
*/
|
|
65
107
|
declare function isSubscription(value: unknown): value is Subscription;
|
|
108
|
+
/**
|
|
109
|
+
* Is the value a subscriptions store?
|
|
110
|
+
*
|
|
111
|
+
* @param value Value to check
|
|
112
|
+
* @returns `true` if the value is a subscriptions store, otherwise `false`
|
|
113
|
+
*/
|
|
114
|
+
declare function isSubscriptions(value: unknown): value is Subscriptions;
|
|
115
|
+
/**
|
|
116
|
+
* Create a subscription store
|
|
117
|
+
*
|
|
118
|
+
* @param parameters Store parameters
|
|
119
|
+
* @returns Subscription store
|
|
120
|
+
*/
|
|
121
|
+
declare function subscriptions(parameters?: SubscriptionsParameters): Subscriptions;
|
|
66
122
|
declare const SUBSCRIPTION_NAME = "subscription";
|
|
67
123
|
//#endregion
|
|
68
|
-
export { SUBSCRIPTION_NAME, Subscription, SubscriptionParameters, SubscriptionProperty, Subscriptions,
|
|
124
|
+
export { SUBSCRIPTION_NAME, Subscription, SubscriptionParameters, SubscriptionProperty, Subscriptions, SubscriptionsParameters, isSubscription, isSubscriptions, subscriptions };
|
|
@@ -2,8 +2,8 @@ import { isKey, isPlainObject } from "./is.mjs";
|
|
|
2
2
|
import { createAborter } from "./abort.mjs";
|
|
3
3
|
//#region src/internal/subscription.ts
|
|
4
4
|
function addSubscription(subscriptions, subscription, state) {
|
|
5
|
+
const { items, values } = subscriptions;
|
|
5
6
|
const { key, value } = state.parameters;
|
|
6
|
-
const { items, values } = subscriptions.state;
|
|
7
7
|
if (!isKey(key)) {
|
|
8
8
|
items.any.add(subscription);
|
|
9
9
|
values.from.any.set(value, subscription);
|
|
@@ -37,7 +37,8 @@ function clearSubscriptions(store) {
|
|
|
37
37
|
for (const susbcription of store.values.to.any.keys()) susbcription.unsubscribe();
|
|
38
38
|
if (store.values.to.keyed != null) for (const values of store.values.to.keyed.values()) for (const susbcription of values.keys()) susbcription.unsubscribe();
|
|
39
39
|
}
|
|
40
|
-
function createSubscription(subscriptions, property,
|
|
40
|
+
function createSubscription(subscriptions, property, params) {
|
|
41
|
+
const parameters = createSubscriptionParameters(params);
|
|
41
42
|
if (parameters.signal?.aborted ?? false) throw new Error(parameters.signal?.reason);
|
|
42
43
|
const state = {
|
|
43
44
|
parameters,
|
|
@@ -45,12 +46,15 @@ function createSubscription(subscriptions, property, parameters) {
|
|
|
45
46
|
};
|
|
46
47
|
const existing = getExistingSubscription(subscriptions, state);
|
|
47
48
|
if (existing != null) return [existing, true];
|
|
48
|
-
if (subscriptions.
|
|
49
|
+
if (subscriptions.keys != null && isKey(parameters.key)) {
|
|
50
|
+
if (subscriptions.keys === false) throw new Error(SUBSCRIPTION_DISALLOWED_KEY);
|
|
51
|
+
else if (subscriptions.keys !== true && !subscriptions.keys.has(parameters.key)) throw new Error(SUBSCRIPTION_INVALID_KEY);
|
|
52
|
+
}
|
|
49
53
|
state.aborter = createAborter(parameters.signal, () => unsubscribe(subscriptions, instance, state));
|
|
50
54
|
const instance = { unsubscribe: () => unsubscribe(subscriptions, instance, state) };
|
|
51
55
|
Object.defineProperties(instance, {
|
|
52
|
-
[SUBSCRIPTION_PROPERTY]: { value:
|
|
53
|
-
[property.key]: { value: property.value
|
|
56
|
+
[SUBSCRIPTION_PROPERTY]: { value: SUBSCRIPTION_NAME },
|
|
57
|
+
[property.key]: { value: property.value },
|
|
54
58
|
active: {
|
|
55
59
|
enumerable: true,
|
|
56
60
|
get: () => (parameters.isActive?.() ?? true) && state.active
|
|
@@ -59,36 +63,56 @@ function createSubscription(subscriptions, property, parameters) {
|
|
|
59
63
|
addSubscription(subscriptions, instance, state);
|
|
60
64
|
return [Object.freeze(instance), false];
|
|
61
65
|
}
|
|
62
|
-
function
|
|
63
|
-
const {
|
|
64
|
-
const
|
|
66
|
+
function getExistingSubscription(subscriptions, state) {
|
|
67
|
+
const { values } = subscriptions;
|
|
68
|
+
const { parameters } = state;
|
|
69
|
+
return isKey(parameters.key) ? values.from.keyed?.get(parameters.key)?.get(parameters.value) : values.from.any.get(parameters.value);
|
|
70
|
+
}
|
|
71
|
+
function createSubscriptionParameters(input) {
|
|
72
|
+
const values = isPlainObject(input) ? input : {};
|
|
73
|
+
if (values.value == null) throw new Error(SUBSCRIPTION_INVALID_VALUE);
|
|
74
|
+
return {
|
|
75
|
+
isActive: typeof values.isActive === "function" ? values.isActive : void 0,
|
|
76
|
+
key: isKey(values.key) ? values.key : void 0,
|
|
77
|
+
signal: values.signal instanceof AbortSignal ? values.signal : void 0,
|
|
78
|
+
value: values.value
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function createSubscriptionsParameters(input) {
|
|
82
|
+
const values = isPlainObject(input) ? input : {};
|
|
83
|
+
let keys;
|
|
84
|
+
if (values.keys instanceof Set) keys = values.keys;
|
|
85
|
+
else keys = typeof values.keys === "boolean" ? values.keys : false;
|
|
86
|
+
return {
|
|
87
|
+
keys,
|
|
88
|
+
property: createSubscriptionsProperty(values.property)
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function createSubscriptionsProperty(input) {
|
|
92
|
+
const values = isPlainObject(input) ? input : {};
|
|
93
|
+
return {
|
|
94
|
+
key: typeof values.key === "string" ? values.key : SUBSCRIPTION_PROPERTY,
|
|
95
|
+
value: values.value == null ? SUBSCRIPTION_NAME : values.value
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function createSubscriptionsState(keys) {
|
|
99
|
+
return {
|
|
65
100
|
keys,
|
|
66
101
|
items: {
|
|
67
102
|
any: /* @__PURE__ */ new Set(),
|
|
68
|
-
keyed: keys
|
|
103
|
+
keyed: keys === false ? void 0 : /* @__PURE__ */ new Map()
|
|
69
104
|
},
|
|
70
105
|
values: {
|
|
71
106
|
from: {
|
|
72
107
|
any: /* @__PURE__ */ new Map(),
|
|
73
|
-
keyed: keys
|
|
108
|
+
keyed: keys === false ? void 0 : /* @__PURE__ */ new Map()
|
|
74
109
|
},
|
|
75
110
|
to: {
|
|
76
111
|
any: /* @__PURE__ */ new Map(),
|
|
77
|
-
keyed: keys
|
|
112
|
+
keyed: keys === false ? void 0 : /* @__PURE__ */ new Map()
|
|
78
113
|
}
|
|
79
114
|
}
|
|
80
115
|
};
|
|
81
|
-
const instance = {
|
|
82
|
-
state,
|
|
83
|
-
clear: () => clearSubscriptions(state),
|
|
84
|
-
create: (parameters) => createSubscription(instance, property, parameters)
|
|
85
|
-
};
|
|
86
|
-
return instance;
|
|
87
|
-
}
|
|
88
|
-
function getExistingSubscription(subscriptions, state) {
|
|
89
|
-
const { parameters } = state;
|
|
90
|
-
const { values } = subscriptions.state;
|
|
91
|
-
return isKey(parameters.key) ? values.from.keyed?.get(parameters.key)?.get(parameters.value) : values.from.any.get(parameters.value);
|
|
92
116
|
}
|
|
93
117
|
/**
|
|
94
118
|
* Is the value a subscription?
|
|
@@ -97,7 +121,19 @@ function getExistingSubscription(subscriptions, state) {
|
|
|
97
121
|
* @returns `true` if the value is a subscription, otherwise `false`
|
|
98
122
|
*/
|
|
99
123
|
function isSubscription(value) {
|
|
100
|
-
return
|
|
124
|
+
return isSubscriptionInstance(value, SUBSCRIPTION_NAME);
|
|
125
|
+
}
|
|
126
|
+
function isSubscriptionInstance(value, name) {
|
|
127
|
+
return isPlainObject(value) && SUBSCRIPTION_PROPERTY in value && value[SUBSCRIPTION_PROPERTY] === name;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Is the value a subscriptions store?
|
|
131
|
+
*
|
|
132
|
+
* @param value Value to check
|
|
133
|
+
* @returns `true` if the value is a subscriptions store, otherwise `false`
|
|
134
|
+
*/
|
|
135
|
+
function isSubscriptions(value) {
|
|
136
|
+
return isSubscriptionInstance(value, SUBSCRIPTION_STORE);
|
|
101
137
|
}
|
|
102
138
|
function removeFromStore(items, values, subscription, value, key) {
|
|
103
139
|
items.delete(subscription);
|
|
@@ -109,14 +145,14 @@ function removeFromStore(items, values, subscription, value, key) {
|
|
|
109
145
|
values.to.keyed?.get(key)?.delete(subscription);
|
|
110
146
|
}
|
|
111
147
|
}
|
|
112
|
-
function removeSubscription(
|
|
148
|
+
function removeSubscription(subscriptionsState, subscription, state) {
|
|
113
149
|
if (!state.active) return;
|
|
114
150
|
state.aborter = void 0;
|
|
115
151
|
state.active = false;
|
|
116
152
|
state.parameters.isActive = void 0;
|
|
117
153
|
state.parameters.signal = void 0;
|
|
154
|
+
const { items, values } = subscriptionsState;
|
|
118
155
|
const { key, value } = state.parameters;
|
|
119
|
-
const { items, values } = subscriptions.state;
|
|
120
156
|
if (!isKey(key)) {
|
|
121
157
|
removeFromStore(items.any, values, subscription, value);
|
|
122
158
|
return;
|
|
@@ -129,12 +165,41 @@ function removeSubscription(subscriptions, subscription, state) {
|
|
|
129
165
|
removeFromStore(keyed, values, subscription, value, key);
|
|
130
166
|
if (keyed.size === 0) items.keyed.delete(key);
|
|
131
167
|
}
|
|
132
|
-
|
|
168
|
+
/**
|
|
169
|
+
* Create a subscription store
|
|
170
|
+
*
|
|
171
|
+
* @param parameters Store parameters
|
|
172
|
+
* @returns Subscription store
|
|
173
|
+
*/
|
|
174
|
+
function subscriptions(parameters) {
|
|
175
|
+
const { keys, property } = createSubscriptionsParameters(parameters);
|
|
176
|
+
const state = createSubscriptionsState(keys);
|
|
177
|
+
const instance = {
|
|
178
|
+
clear: () => clearSubscriptions(state),
|
|
179
|
+
create: (parameters) => createSubscription(state, property, parameters)
|
|
180
|
+
};
|
|
181
|
+
Object.defineProperties(instance, {
|
|
182
|
+
[SUBSCRIPTION_PROPERTY]: { value: SUBSCRIPTION_STORE },
|
|
183
|
+
items: {
|
|
184
|
+
enumerable: true,
|
|
185
|
+
value: state.items
|
|
186
|
+
},
|
|
187
|
+
values: {
|
|
188
|
+
enumerable: true,
|
|
189
|
+
value: state.values
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
return Object.freeze(instance);
|
|
193
|
+
}
|
|
194
|
+
function unsubscribe(subscriptionsState, subscription, state) {
|
|
133
195
|
state.aborter?.cancel();
|
|
134
|
-
removeSubscription(
|
|
196
|
+
removeSubscription(subscriptionsState, subscription, state);
|
|
135
197
|
}
|
|
198
|
+
const SUBSCRIPTION_DISALLOWED_KEY = "Disallowed key for subscription";
|
|
136
199
|
const SUBSCRIPTION_INVALID_KEY = "Invalid key for subscription";
|
|
200
|
+
const SUBSCRIPTION_INVALID_VALUE = "A subscription requires a non-null value to identify it";
|
|
137
201
|
const SUBSCRIPTION_NAME = "subscription";
|
|
138
|
-
const SUBSCRIPTION_PROPERTY = "$
|
|
202
|
+
const SUBSCRIPTION_PROPERTY = "$subscriptions";
|
|
203
|
+
const SUBSCRIPTION_STORE = "subscriptions";
|
|
139
204
|
//#endregion
|
|
140
|
-
export { SUBSCRIPTION_NAME,
|
|
205
|
+
export { SUBSCRIPTION_NAME, isSubscription, isSubscriptions, subscriptions };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { max } from "../math/aggregate.mjs";
|
|
2
2
|
import { getString, words } from "../string/misc.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { createCompareHandlers } from "./handlers.mjs";
|
|
4
4
|
//#region src/internal/value/compare.ts
|
|
5
5
|
const COMPARE_NAME = "compare";
|
|
6
6
|
/**
|
|
@@ -78,7 +78,7 @@ const comparators = {
|
|
|
78
78
|
number: compareNumbers,
|
|
79
79
|
symbol: compareSymbols
|
|
80
80
|
};
|
|
81
|
-
const compareHandlers =
|
|
81
|
+
const compareHandlers = createCompareHandlers(compare, {
|
|
82
82
|
callback: (first, second, compareStrings) => compareStrings ? getString(first).localeCompare(getString(second)) : void 0,
|
|
83
83
|
method: COMPARE_NAME
|
|
84
84
|
});
|
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
import { isNonPlainObject, isPlainObject, isPrimitive, isTypedArray } from "../is.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { createCompareHandlers } from "./handlers.mjs";
|
|
3
3
|
//#region src/internal/value/equal.ts
|
|
4
|
+
function createEqualOptions(input) {
|
|
5
|
+
const options = {
|
|
6
|
+
ignoreCase: false,
|
|
7
|
+
ignoreExpressions: {
|
|
8
|
+
enabled: false,
|
|
9
|
+
values: []
|
|
10
|
+
},
|
|
11
|
+
ignoreKeys: {
|
|
12
|
+
enabled: false,
|
|
13
|
+
values: /* @__PURE__ */ new Set()
|
|
14
|
+
},
|
|
15
|
+
relaxedNullish: false
|
|
16
|
+
};
|
|
17
|
+
if (typeof input === "boolean") {
|
|
18
|
+
options.ignoreCase = input;
|
|
19
|
+
return options;
|
|
20
|
+
}
|
|
21
|
+
if (isNonPlainObject(input)) return options;
|
|
22
|
+
options.ignoreCase = typeof input.ignoreCase === "boolean" ? input.ignoreCase : false;
|
|
23
|
+
options.ignoreExpressions.values = (Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => key instanceof RegExp);
|
|
24
|
+
options.ignoreKeys.values = new Set((Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => typeof key === "string"));
|
|
25
|
+
options.ignoreExpressions.enabled = options.ignoreExpressions.values.length > 0;
|
|
26
|
+
options.ignoreKeys.enabled = options.ignoreKeys.values.size > 0;
|
|
27
|
+
options.relaxedNullish = input.relaxedNullish === true;
|
|
28
|
+
return options;
|
|
29
|
+
}
|
|
4
30
|
/**
|
|
5
31
|
* Deregister a equality comparison handler for a specific class
|
|
6
32
|
*
|
|
@@ -18,9 +44,9 @@ function filterKey(key, options) {
|
|
|
18
44
|
return true;
|
|
19
45
|
}
|
|
20
46
|
function equal(first, second, options) {
|
|
21
|
-
return equalValue(first, second,
|
|
47
|
+
return equalValue(first, second, createEqualOptions(options));
|
|
22
48
|
}
|
|
23
|
-
equal.handlers =
|
|
49
|
+
equal.handlers = createCompareHandlers(equal, { callback: Object.is });
|
|
24
50
|
equal.deregister = deregisterEqualizer;
|
|
25
51
|
equal.initialize = initializeEqualizer;
|
|
26
52
|
equal.register = registerEqualizer;
|
|
@@ -115,32 +141,6 @@ function equalValue(first, second, options) {
|
|
|
115
141
|
default: return equal.handlers.handle(first, second, options);
|
|
116
142
|
}
|
|
117
143
|
}
|
|
118
|
-
function getEqualOptions(input) {
|
|
119
|
-
const options = {
|
|
120
|
-
ignoreCase: false,
|
|
121
|
-
ignoreExpressions: {
|
|
122
|
-
enabled: false,
|
|
123
|
-
values: []
|
|
124
|
-
},
|
|
125
|
-
ignoreKeys: {
|
|
126
|
-
enabled: false,
|
|
127
|
-
values: /* @__PURE__ */ new Set()
|
|
128
|
-
},
|
|
129
|
-
relaxedNullish: false
|
|
130
|
-
};
|
|
131
|
-
if (typeof input === "boolean") {
|
|
132
|
-
options.ignoreCase = input;
|
|
133
|
-
return options;
|
|
134
|
-
}
|
|
135
|
-
if (isNonPlainObject(input)) return options;
|
|
136
|
-
options.ignoreCase = typeof input.ignoreCase === "boolean" ? input.ignoreCase : false;
|
|
137
|
-
options.ignoreExpressions.values = (Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => key instanceof RegExp);
|
|
138
|
-
options.ignoreKeys.values = new Set((Array.isArray(input.ignoreKeys) ? input.ignoreKeys : [input.ignoreKeys]).filter((key) => typeof key === "string"));
|
|
139
|
-
options.ignoreExpressions.enabled = options.ignoreExpressions.values.length > 0;
|
|
140
|
-
options.ignoreKeys.enabled = options.ignoreKeys.values.size > 0;
|
|
141
|
-
options.relaxedNullish = input.relaxedNullish === true;
|
|
142
|
-
return options;
|
|
143
|
-
}
|
|
144
144
|
/**
|
|
145
145
|
* Create an equalizer with predefined options
|
|
146
146
|
*
|
|
@@ -150,7 +150,7 @@ function getEqualOptions(input) {
|
|
|
150
150
|
* @returns Equalizer function
|
|
151
151
|
*/
|
|
152
152
|
function initializeEqualizer(options) {
|
|
153
|
-
const actual =
|
|
153
|
+
const actual = createEqualOptions(options);
|
|
154
154
|
const equalizer = (first, second) => equalValue(first, second, actual);
|
|
155
155
|
equalizer.deregister = deregisterEqualizer;
|
|
156
156
|
equalizer.register = registerEqualizer;
|
|
@@ -4,15 +4,15 @@ type Options = {
|
|
|
4
4
|
callback: GenericCallback;
|
|
5
5
|
method?: string;
|
|
6
6
|
};
|
|
7
|
-
declare function
|
|
7
|
+
declare function createCompareHandlers<Value>(owner: GenericCallback, options: Options): {
|
|
8
8
|
deregister(constructor: Constructor): void;
|
|
9
9
|
handle(first: unknown, second: unknown, ...parameters: unknown[]): Value;
|
|
10
10
|
register(constructor: Constructor, handler?: string | GenericCallback): void;
|
|
11
11
|
};
|
|
12
|
-
declare function
|
|
12
|
+
declare function createSelfHandlers(owner: GenericCallback, options: Options): {
|
|
13
13
|
deregister(constructor: Constructor): void;
|
|
14
14
|
handle(value: unknown, ...parameters: unknown[]): unknown;
|
|
15
15
|
register(constructor: Constructor, handler?: string | GenericCallback): void;
|
|
16
16
|
};
|
|
17
17
|
//#endregion
|
|
18
|
-
export {
|
|
18
|
+
export { createCompareHandlers, createSelfHandlers };
|