@oscarpalmer/atoms 0.192.0 → 0.193.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/dist/index.d.mts +25 -23
- package/dist/index.mjs +30 -31
- package/dist/queue.d.mts +25 -23
- package/dist/queue.mjs +27 -28
- package/package.json +3 -4
- package/src/array/difference.ts +0 -73
- package/src/array/exists.ts +0 -93
- package/src/array/filter.ts +0 -182
- package/src/array/find.ts +0 -183
- package/src/array/first.ts +0 -196
- package/src/array/flatten.ts +0 -20
- package/src/array/from.ts +0 -129
- package/src/array/get.ts +0 -131
- package/src/array/group-by.ts +0 -369
- package/src/array/index.ts +0 -26
- package/src/array/insert.ts +0 -52
- package/src/array/intersection.ts +0 -72
- package/src/array/last.ts +0 -194
- package/src/array/match.ts +0 -436
- package/src/array/move.ts +0 -315
- package/src/array/partition.ts +0 -91
- package/src/array/push.ts +0 -23
- package/src/array/reverse.ts +0 -33
- package/src/array/select.ts +0 -260
- package/src/array/single.ts +0 -93
- package/src/array/slice.ts +0 -335
- package/src/array/sort.ts +0 -607
- package/src/array/splice.ts +0 -106
- package/src/array/swap.ts +0 -322
- package/src/array/to-map.ts +0 -371
- package/src/array/to-record.ts +0 -351
- package/src/array/to-set.ts +0 -80
- package/src/array/toggle.ts +0 -79
- package/src/array/union.ts +0 -72
- package/src/array/unique.ts +0 -67
- package/src/array/update.ts +0 -75
- package/src/beacon.ts +0 -378
- package/src/color/constants.ts +0 -137
- package/src/color/index.ts +0 -83
- package/src/color/instance.ts +0 -162
- package/src/color/misc/alpha.ts +0 -56
- package/src/color/misc/format.ts +0 -29
- package/src/color/misc/get.ts +0 -210
- package/src/color/misc/is.ts +0 -221
- package/src/color/misc/state.ts +0 -243
- package/src/color/models.ts +0 -389
- package/src/color/space/hex.ts +0 -184
- package/src/color/space/hsl.ts +0 -174
- package/src/color/space/hwb.ts +0 -153
- package/src/color/space/rgb.ts +0 -240
- package/src/function/assert.ts +0 -174
- package/src/function/index.ts +0 -2
- package/src/function/limit.ts +0 -83
- package/src/function/memoize.ts +0 -202
- package/src/function/once.ts +0 -200
- package/src/function/retry.ts +0 -175
- package/src/function/work.ts +0 -1007
- package/src/herald.ts +0 -216
- package/src/index.ts +0 -68
- package/src/internal/array/callbacks.ts +0 -46
- package/src/internal/array/chunk.ts +0 -51
- package/src/internal/array/compact.ts +0 -56
- package/src/internal/array/find.ts +0 -200
- package/src/internal/array/group.ts +0 -42
- package/src/internal/array/index-of.ts +0 -182
- package/src/internal/array/insert.ts +0 -80
- package/src/internal/array/overlap.ts +0 -35
- package/src/internal/array/sets.ts +0 -74
- package/src/internal/array/shuffle.ts +0 -33
- package/src/internal/array/update.ts +0 -52
- package/src/internal/function/misc.ts +0 -8
- package/src/internal/function/timer.ts +0 -168
- package/src/internal/is.ts +0 -244
- package/src/internal/math/aggregate.ts +0 -164
- package/src/internal/math/misc.ts +0 -28
- package/src/internal/number.ts +0 -129
- package/src/internal/random.ts +0 -49
- package/src/internal/result.ts +0 -92
- package/src/internal/sized.ts +0 -25
- package/src/internal/string.ts +0 -128
- package/src/internal/subscription.ts +0 -264
- package/src/internal/value/compare.ts +0 -170
- package/src/internal/value/equal.ts +0 -465
- package/src/internal/value/get.ts +0 -57
- package/src/internal/value/handlers.ts +0 -95
- package/src/internal/value/has.ts +0 -118
- package/src/internal/value/misc.ts +0 -125
- package/src/internal/value/partial.ts +0 -46
- package/src/internal/value/set.ts +0 -132
- package/src/is.ts +0 -182
- package/src/logger.ts +0 -230
- package/src/math.ts +0 -281
- package/src/models.ts +0 -286
- package/src/number.ts +0 -1
- package/src/promise/delay.ts +0 -62
- package/src/promise/helpers.ts +0 -96
- package/src/promise/index.ts +0 -300
- package/src/promise/misc.ts +0 -96
- package/src/promise/models.ts +0 -195
- package/src/promise/timed.ts +0 -91
- package/src/query.ts +0 -147
- package/src/queue.ts +0 -814
- package/src/random.ts +0 -125
- package/src/result/index.ts +0 -105
- package/src/result/match.ts +0 -124
- package/src/result/misc.ts +0 -129
- package/src/result/models.ts +0 -83
- package/src/result/work/flow.ts +0 -488
- package/src/result/work/pipe.ts +0 -496
- package/src/sized/map.ts +0 -110
- package/src/sized/set.ts +0 -107
- package/src/string/case.ts +0 -236
- package/src/string/fuzzy.ts +0 -444
- package/src/string/index.ts +0 -199
- package/src/string/match.ts +0 -80
- package/src/string/normalize.ts +0 -205
- package/src/string/template.ts +0 -161
- package/src/value/clone.ts +0 -319
- package/src/value/collection.ts +0 -63
- package/src/value/diff.ts +0 -232
- package/src/value/freeze.ts +0 -322
- package/src/value/handle.ts +0 -3
- package/src/value/index.ts +0 -5
- package/src/value/merge.ts +0 -278
- package/src/value/omit.ts +0 -20
- package/src/value/pick.ts +0 -20
- package/src/value/shake.ts +0 -45
- package/src/value/smush.ts +0 -89
- package/src/value/transform.ts +0 -153
- package/src/value/unsmush.ts +0 -84
package/src/internal/sized.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// #region Functions
|
|
2
|
-
|
|
3
|
-
import {clamp} from './number';
|
|
4
|
-
|
|
5
|
-
export function getSizedMaximum(first?: unknown, second?: unknown): number {
|
|
6
|
-
let actual: number;
|
|
7
|
-
|
|
8
|
-
if (typeof first === 'number') {
|
|
9
|
-
actual = first;
|
|
10
|
-
} else {
|
|
11
|
-
actual = typeof second === 'number' ? second : MAXIMUM_DEFAULT;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return clamp(actual, 1, MAXIMUM_ABSOLUTE);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// #endregion
|
|
18
|
-
|
|
19
|
-
// #region Variables
|
|
20
|
-
|
|
21
|
-
const MAXIMUM_ABSOLUTE = 16_777_216; // 2^24
|
|
22
|
-
|
|
23
|
-
const MAXIMUM_DEFAULT = 1_048_576; // 2^20
|
|
24
|
-
|
|
25
|
-
// #endregion
|
package/src/internal/string.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
// #region Functions
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Get the string value from any value
|
|
5
|
-
*
|
|
6
|
-
* @param value Original value
|
|
7
|
-
* @returns String representation of the value
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```typescript
|
|
11
|
-
* getString(null) // => ''
|
|
12
|
-
* getString('foo') // => 'foo'
|
|
13
|
-
* getString(123) // => '123'
|
|
14
|
-
* getString(true) // => 'true'
|
|
15
|
-
* getString([1, 2, 3]) // => '1,2,3'
|
|
16
|
-
* getString({a: 1}) // => '{"a":1}'
|
|
17
|
-
* getString(() => 123) // => '123'
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export function getString(value: unknown): string {
|
|
21
|
-
if (typeof value === 'string') {
|
|
22
|
-
return value;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (value == null) {
|
|
26
|
-
return '';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (typeof value === 'function') {
|
|
30
|
-
return getString(value());
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (typeof value !== 'object') {
|
|
34
|
-
return String(value);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const asString = String(value.valueOf?.() ?? value);
|
|
38
|
-
|
|
39
|
-
return asString.startsWith('[object ') ? JSON.stringify(value) : asString;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function ignoreKey(key: string): boolean {
|
|
43
|
-
return EXPRESSION_IGNORED.test(key);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function interpolate(strings: TemplateStringsArray, values: unknown[]): string {
|
|
47
|
-
const {length} = strings;
|
|
48
|
-
|
|
49
|
-
let interpolated = '';
|
|
50
|
-
|
|
51
|
-
for (let index = 0; index < length; index += 1) {
|
|
52
|
-
const value = values[index];
|
|
53
|
-
|
|
54
|
-
interpolated += `${strings[index]}${Array.isArray(value) ? join(value.map(getString)) : getString(value)}`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return interpolated;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Join an array of values into a string _(while ignoring empty values)_
|
|
62
|
-
*
|
|
63
|
-
* _(`null`, `undefined`, and any values that become whitespace-only strings are considered empty)_
|
|
64
|
-
*
|
|
65
|
-
* @param array Array of values
|
|
66
|
-
* @param delimiter Delimiter to use between values
|
|
67
|
-
* @returns Joined string
|
|
68
|
-
*/
|
|
69
|
-
export function join(array: unknown[], delimiter?: string): string {
|
|
70
|
-
if (!Array.isArray(array)) {
|
|
71
|
-
return '';
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const {length} = array;
|
|
75
|
-
|
|
76
|
-
if (length === 0) {
|
|
77
|
-
return '';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const values: string[] = [];
|
|
81
|
-
|
|
82
|
-
for (let index = 0; index < length; index += 1) {
|
|
83
|
-
const item = getString(array[index]);
|
|
84
|
-
|
|
85
|
-
if (item.length > 0) {
|
|
86
|
-
values.push(item);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return values.join(typeof delimiter === 'string' ? delimiter : '');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function tryCallback<T, U>(value: T, callback: (value: T) => U): U {
|
|
94
|
-
try {
|
|
95
|
-
return callback(value);
|
|
96
|
-
} catch {
|
|
97
|
-
return value as never;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function tryDecode(value: string): string {
|
|
102
|
-
return tryCallback(value, decodeURIComponent);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export function tryEncode(value: boolean | number | string): unknown {
|
|
106
|
-
return tryCallback(value, encodeURIComponent);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Split a string into words _(and other readable parts)_
|
|
111
|
-
*
|
|
112
|
-
* @param value Original string
|
|
113
|
-
* @returns Array of words found in the string
|
|
114
|
-
*/
|
|
115
|
-
export function words(value: string): string[] {
|
|
116
|
-
return typeof value === 'string' ? (value.match(EXPRESSION_WORDS) ?? []) : [];
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// #endregion
|
|
120
|
-
|
|
121
|
-
// #region Variables
|
|
122
|
-
|
|
123
|
-
const EXPRESSION_IGNORED = /(^|\.)(__proto__|constructor|prototype)(\.|$)/i;
|
|
124
|
-
|
|
125
|
-
// oxlint-disable-next-line no-control-regex: Lodash uses it, so it's fine ;-)
|
|
126
|
-
const EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
|
|
127
|
-
|
|
128
|
-
// #endregion
|
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
import type {Key} from '../models';
|
|
2
|
-
import {isPlainObject} from './is';
|
|
3
|
-
|
|
4
|
-
// #region Types
|
|
5
|
-
|
|
6
|
-
export type Subscription = {
|
|
7
|
-
/**
|
|
8
|
-
* Is the subscription active?
|
|
9
|
-
*/
|
|
10
|
-
get active(): boolean;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Unsubscribe from changes
|
|
14
|
-
*/
|
|
15
|
-
unsubscribe(): void;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export type SubscriptionParameters = {
|
|
19
|
-
isActive?: () => boolean;
|
|
20
|
-
key?: Key;
|
|
21
|
-
property: SubscriptionProperty;
|
|
22
|
-
subscriptions: Subscriptions;
|
|
23
|
-
value: unknown;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export type SubscriptionProperty = {
|
|
27
|
-
key: string;
|
|
28
|
-
value: unknown;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type SubscriptionState = {
|
|
32
|
-
active: boolean;
|
|
33
|
-
parameters: SubscriptionParameters;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export type Subscriptions<Value = unknown> = {
|
|
37
|
-
items: SubscriptionsItems;
|
|
38
|
-
keys?: Set<Key>;
|
|
39
|
-
values: SubscriptionsValues<Value>;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
type SubscriptionsItems = {
|
|
43
|
-
any: Set<Subscription>;
|
|
44
|
-
keyed?: Map<Key, Set<Subscription>>;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
type SubscriptionsValues<Value = unknown> = {
|
|
48
|
-
from: SubscriptionsValuesItem<Value, Subscription>;
|
|
49
|
-
to: SubscriptionsValuesItem<Subscription, Value>;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
type SubscriptionsValuesItem<MapKey, MapValue> = {
|
|
53
|
-
any: Map<MapKey, MapValue>;
|
|
54
|
-
keyed?: Map<Key, Map<MapKey, MapValue>>;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// #endregion
|
|
58
|
-
|
|
59
|
-
// #region Functions
|
|
60
|
-
|
|
61
|
-
function addSubscription(subscription: Subscription, state: SubscriptionState): void {
|
|
62
|
-
const {key, subscriptions, value} = state.parameters;
|
|
63
|
-
const {items, values} = subscriptions;
|
|
64
|
-
|
|
65
|
-
if (key == null) {
|
|
66
|
-
items.any.add(subscription);
|
|
67
|
-
values.from.any.set(value, subscription);
|
|
68
|
-
values.to.any.set(subscription, value);
|
|
69
|
-
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (items.keyed == null || values.from.keyed == null || values.to.keyed == null) {
|
|
74
|
-
// TODO: fix tests or document
|
|
75
|
-
// istanbul ignore next
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let keyedItems = items.keyed.get(key);
|
|
80
|
-
|
|
81
|
-
if (keyedItems == null) {
|
|
82
|
-
keyedItems = new Set();
|
|
83
|
-
|
|
84
|
-
items.keyed.set(key, keyedItems);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
keyedItems.add(subscription);
|
|
88
|
-
|
|
89
|
-
let keyedFrom = values.from.keyed.get(key);
|
|
90
|
-
|
|
91
|
-
if (keyedFrom == null) {
|
|
92
|
-
keyedFrom = new Map();
|
|
93
|
-
|
|
94
|
-
values.from.keyed.set(key, keyedFrom);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
keyedFrom.set(value, subscription);
|
|
98
|
-
|
|
99
|
-
let keyedTo = values.to.keyed.get(key);
|
|
100
|
-
|
|
101
|
-
if (keyedTo == null) {
|
|
102
|
-
keyedTo = new Map();
|
|
103
|
-
|
|
104
|
-
values.to.keyed.set(key, keyedTo);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
keyedTo.set(subscription, value);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function clearSubscriptions(store: Subscriptions): void {
|
|
111
|
-
for (const susbcription of store.values.to.any.keys()) {
|
|
112
|
-
susbcription.unsubscribe();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (store.values.to.keyed != null) {
|
|
116
|
-
for (const values of store.values.to.keyed.values()) {
|
|
117
|
-
for (const susbcription of values.keys()) {
|
|
118
|
-
susbcription.unsubscribe();
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function getExistingSubscription(state: SubscriptionState): Subscription | undefined {
|
|
125
|
-
const {parameters} = state;
|
|
126
|
-
const {values} = parameters.subscriptions;
|
|
127
|
-
|
|
128
|
-
return parameters.key == null
|
|
129
|
-
? values.from.any.get(parameters.value)
|
|
130
|
-
: values.from.keyed?.get(parameters.key)?.get(parameters.value);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export function getSubscription(parameters: SubscriptionParameters): Subscription {
|
|
134
|
-
const state: SubscriptionState = {
|
|
135
|
-
parameters,
|
|
136
|
-
active: true,
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const existing = getExistingSubscription(state);
|
|
140
|
-
|
|
141
|
-
if (existing != null) {
|
|
142
|
-
return existing;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (
|
|
146
|
-
parameters.subscriptions.keys != null &&
|
|
147
|
-
parameters.key != null &&
|
|
148
|
-
!parameters.subscriptions.keys.has(parameters.key)
|
|
149
|
-
) {
|
|
150
|
-
throw new Error();
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const instance = {
|
|
154
|
-
unsubscribe: () => {
|
|
155
|
-
removeSubscription(instance as Subscription, state);
|
|
156
|
-
},
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
Object.defineProperties(instance, {
|
|
160
|
-
[PROPERTY]: {
|
|
161
|
-
enumerable: false,
|
|
162
|
-
value: true,
|
|
163
|
-
},
|
|
164
|
-
[parameters.property.key]: {
|
|
165
|
-
enumerable: false,
|
|
166
|
-
value: parameters.property.value,
|
|
167
|
-
},
|
|
168
|
-
active: {
|
|
169
|
-
enumerable: true,
|
|
170
|
-
get: () => (parameters.isActive?.() ?? true) && state.active,
|
|
171
|
-
},
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
addSubscription(instance as Subscription, state);
|
|
175
|
-
|
|
176
|
-
return Object.freeze(instance) as Subscription;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export function getSubscriptions<Value = unknown>(keys?: Set<Key>): Subscriptions<Value> {
|
|
180
|
-
return {
|
|
181
|
-
keys,
|
|
182
|
-
items: {
|
|
183
|
-
any: new Set(),
|
|
184
|
-
keyed: keys == null ? undefined : new Map(),
|
|
185
|
-
},
|
|
186
|
-
values: {
|
|
187
|
-
from: {
|
|
188
|
-
any: new Map(),
|
|
189
|
-
keyed: keys == null ? undefined : new Map(),
|
|
190
|
-
},
|
|
191
|
-
to: {
|
|
192
|
-
any: new Map(),
|
|
193
|
-
keyed: keys == null ? undefined : new Map(),
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Is the value a subscription?
|
|
201
|
-
*
|
|
202
|
-
* @param value Value to check
|
|
203
|
-
* @returns `true` if the value is a subscription, otherwise `false`
|
|
204
|
-
*/
|
|
205
|
-
export function isSubscription(value: unknown): value is Subscription {
|
|
206
|
-
return isPlainObject(value) && PROPERTY in value && value[PROPERTY] === true;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function removeFromStore(
|
|
210
|
-
items: Set<Subscription>,
|
|
211
|
-
values: SubscriptionsValues,
|
|
212
|
-
subscription: Subscription,
|
|
213
|
-
value: unknown,
|
|
214
|
-
key?: Key,
|
|
215
|
-
): void {
|
|
216
|
-
items.delete(subscription);
|
|
217
|
-
|
|
218
|
-
if (key == null) {
|
|
219
|
-
values.from.any.delete(value);
|
|
220
|
-
values.to.any.delete(subscription);
|
|
221
|
-
} else {
|
|
222
|
-
values.from.keyed?.get(key)?.delete(value);
|
|
223
|
-
values.to.keyed?.get(key)?.delete(subscription);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function removeSubscription(subscription: Subscription, state: SubscriptionState): void {
|
|
228
|
-
if (!state.active) {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
state.active = false;
|
|
233
|
-
|
|
234
|
-
const {key, subscriptions, value} = state.parameters;
|
|
235
|
-
const {items, values} = subscriptions;
|
|
236
|
-
|
|
237
|
-
if (key == null) {
|
|
238
|
-
removeFromStore(items.any, values, subscription, value);
|
|
239
|
-
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const keyed = items.keyed?.get(key);
|
|
244
|
-
|
|
245
|
-
if (items.keyed == null || keyed == null) {
|
|
246
|
-
// TODO, fix tests or document
|
|
247
|
-
// istanbul ignore next
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
removeFromStore(keyed, values, subscription, value, key);
|
|
252
|
-
|
|
253
|
-
if (keyed.size === 0) {
|
|
254
|
-
items.keyed.delete(key);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// #endregion
|
|
259
|
-
|
|
260
|
-
// #region Variables
|
|
261
|
-
|
|
262
|
-
const PROPERTY = '$subscription';
|
|
263
|
-
|
|
264
|
-
// #endregion
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import type {Constructor} from '../../models';
|
|
2
|
-
import {max} from '../math/aggregate';
|
|
3
|
-
import {getString, words} from '../string';
|
|
4
|
-
import {getCompareHandlers} from './handlers';
|
|
5
|
-
|
|
6
|
-
// #region Types
|
|
7
|
-
|
|
8
|
-
type Comparator<Value = any> = (first: Value, second: Value) => number;
|
|
9
|
-
|
|
10
|
-
// #endregion
|
|
11
|
-
|
|
12
|
-
// #region Special variables
|
|
13
|
-
|
|
14
|
-
const COMPARE_NAME: string = 'compare';
|
|
15
|
-
|
|
16
|
-
// #endregion
|
|
17
|
-
|
|
18
|
-
// #region Functions
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Compare two values _(for sorting purposes)_
|
|
22
|
-
*
|
|
23
|
-
* @param first First value
|
|
24
|
-
* @param second Second value
|
|
25
|
-
* @returns `0` if equal; `-1` first comes before second; `1` first comes after second
|
|
26
|
-
*/
|
|
27
|
-
export function compare(first: unknown, second: unknown): number {
|
|
28
|
-
if (Object.is(first, second)) {
|
|
29
|
-
return 0;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (first == null) {
|
|
33
|
-
return -1;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (second == null) {
|
|
37
|
-
return 1;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
let comparison = compareValue(first, second, false);
|
|
41
|
-
|
|
42
|
-
if (comparison != null) {
|
|
43
|
-
return comparison;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const firstParts = getComparisonParts(first);
|
|
47
|
-
const secondParts = getComparisonParts(second);
|
|
48
|
-
const length = max([firstParts.length, secondParts.length]);
|
|
49
|
-
|
|
50
|
-
const lastIndex = length - 1;
|
|
51
|
-
|
|
52
|
-
for (let index = 0; index < length; index += 1) {
|
|
53
|
-
const firstPart = firstParts[index];
|
|
54
|
-
const secondPart = secondParts[index];
|
|
55
|
-
|
|
56
|
-
comparison = compareValue(firstPart, secondPart, true);
|
|
57
|
-
|
|
58
|
-
if (comparison === 0) {
|
|
59
|
-
if (index === lastIndex) {
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return comparison as number;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return 0;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
compare.handlers = getCompareHandlers<number>(compare, {
|
|
73
|
-
callback: (first, second, compareStrings) => {
|
|
74
|
-
if (compareStrings) {
|
|
75
|
-
return getString(first).localeCompare(getString(second));
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
method: COMPARE_NAME,
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
compare.deregister = deregisterComparator;
|
|
82
|
-
compare.register = registerComparator;
|
|
83
|
-
|
|
84
|
-
function compareNumbers(first: bigint | number, second: bigint | number): number {
|
|
85
|
-
if (Object.is(first, second)) {
|
|
86
|
-
return 0;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (Number.isNaN(first)) {
|
|
90
|
-
return -1;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (Number.isNaN(second)) {
|
|
94
|
-
return 1;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return first > second ? 1 : -1;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function compareSymbols(first: symbol, second: symbol): number {
|
|
101
|
-
return getString(first.description ?? first).localeCompare(
|
|
102
|
-
getString(second.description ?? second),
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function compareValue(
|
|
107
|
-
first: unknown,
|
|
108
|
-
second: unknown,
|
|
109
|
-
compareStrings: boolean,
|
|
110
|
-
): number | undefined {
|
|
111
|
-
const firstType = typeof first;
|
|
112
|
-
const secondType = typeof second;
|
|
113
|
-
|
|
114
|
-
if (firstType === secondType && firstType in comparators) {
|
|
115
|
-
return comparators[firstType as keyof typeof comparators](first as never, second as never);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (first instanceof Date && second instanceof Date) {
|
|
119
|
-
return compareNumbers(first.getTime(), second.getTime());
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return compare.handlers.handle(first, second, compareStrings);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Deregister a custom comparison handler for a class
|
|
127
|
-
*
|
|
128
|
-
* _Available as `deregisterComparator` and `compare.deregister`_
|
|
129
|
-
*
|
|
130
|
-
* @param constructor Class constructor
|
|
131
|
-
*/
|
|
132
|
-
export function deregisterComparator<Instance>(constructor: Constructor<Instance>): void {
|
|
133
|
-
compare.handlers.deregister(constructor);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function getComparisonParts(value: unknown): unknown[] {
|
|
137
|
-
if (Array.isArray(value)) {
|
|
138
|
-
return value;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return typeof value === 'object' ? [value] : words(getString(value));
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Register a custom comparison handler for a class
|
|
146
|
-
*
|
|
147
|
-
* _Available as `registerComparator` and `compare.register`_
|
|
148
|
-
*
|
|
149
|
-
* @param constructor Class constructor
|
|
150
|
-
* @param handler Method name or comparison function _(defaults to `compare`)_
|
|
151
|
-
*/
|
|
152
|
-
export function registerComparator<Instance>(
|
|
153
|
-
constructor: Constructor<Instance>,
|
|
154
|
-
handler?: string | Comparator<Instance>,
|
|
155
|
-
): void {
|
|
156
|
-
compare.handlers.register(constructor, handler);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// #endregion
|
|
160
|
-
|
|
161
|
-
// #region Variables
|
|
162
|
-
|
|
163
|
-
const comparators: Record<string, Comparator> = {
|
|
164
|
-
bigint: compareNumbers,
|
|
165
|
-
boolean: (first, second) => compareNumbers(first ? 1 : 0, second ? 1 : 0),
|
|
166
|
-
number: compareNumbers,
|
|
167
|
-
symbol: compareSymbols,
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
// #endregion
|