@oscarpalmer/atoms 0.218.0 → 0.220.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/array/filter.d.mts +38 -4
- package/dist/array/find.d.mts +34 -0
- package/dist/array/first.d.mts +40 -4
- package/dist/array/last.d.mts +46 -10
- package/dist/array/partition.d.mts +24 -8
- package/dist/array/reverse.d.mts +6 -0
- package/dist/array/reverse.mjs +6 -0
- package/dist/array/select.d.mts +97 -116
- package/dist/array/select.mjs +19 -15
- package/dist/array/single.d.mts +22 -0
- package/dist/array/single.mjs +1 -1
- package/dist/array/sort.d.mts +54 -0
- package/dist/color/space/hex.d.mts +8 -0
- package/dist/color/space/hex.mjs +8 -0
- package/dist/index.d.mts +764 -189
- package/dist/index.mjs +508 -207
- package/dist/internal/array/callbacks.mjs +1 -1
- package/dist/internal/array/find.d.mts +3 -3
- package/dist/internal/array/find.mjs +71 -52
- package/dist/internal/array/shuffle.d.mts +5 -0
- package/dist/internal/array/shuffle.mjs +5 -0
- package/dist/internal/math/aggregate.d.mts +69 -21
- package/dist/internal/math/misc.d.mts +14 -0
- package/dist/internal/math/misc.mjs +14 -0
- package/dist/internal/number.d.mts +18 -0
- package/dist/internal/number.mjs +18 -0
- package/dist/internal/string/case.d.mts +63 -0
- package/dist/internal/string/case.mjs +63 -0
- package/dist/internal/string/misc.d.mts +20 -0
- package/dist/internal/string/misc.mjs +20 -0
- package/dist/logger.d.mts +12 -0
- package/dist/logger.mjs +12 -0
- package/dist/math.d.mts +90 -0
- package/dist/math.mjs +7 -0
- package/dist/models/array/array.find.model.d.mts +26 -0
- package/dist/models/array/array.misc.model.d.mts +2 -4
- package/dist/models/index.d.mts +1 -1
- package/dist/models/string/string.fuzzy.model.d.mts +46 -18
- package/dist/models/string/string.fuzzy.model.mjs +3 -1
- package/dist/models/value/value.merge.model.d.mts +3 -3
- package/dist/promise/misc.d.mts +6 -0
- package/dist/promise/misc.mjs +6 -0
- package/dist/promise/timed.d.mts +3 -0
- package/dist/promise/timed.mjs +3 -0
- package/dist/queue.d.mts +0 -1
- package/dist/queue.mjs +1 -1
- package/dist/string/fuzzy.d.mts +3 -3
- package/dist/string/fuzzy.mjs +171 -97
- package/dist/string/index.d.mts +15 -1
- package/dist/string/index.mjs +15 -1
- package/dist/string/match.d.mts +24 -0
- package/dist/string/match.mjs +24 -0
- package/dist/string/template.d.mts +4 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,7 @@ function getArrayCallback(value) {
|
|
|
8
8
|
switch (typeof value) {
|
|
9
9
|
case "function": return value;
|
|
10
10
|
case "number":
|
|
11
|
-
case "string": return
|
|
11
|
+
case "string": return (obj) => obj?.[value];
|
|
12
12
|
default: return;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -21,6 +21,15 @@ function getArrayCallbacks(bool, key, value) {
|
|
|
21
21
|
}
|
|
22
22
|
//#endregion
|
|
23
23
|
//#region src/internal/array/find.ts
|
|
24
|
+
function addResult(result, mapped, flat) {
|
|
25
|
+
if (!flat) {
|
|
26
|
+
result.matched.push(mapped);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const array = Array.isArray(mapped) ? mapped : [mapped];
|
|
30
|
+
const { length } = array;
|
|
31
|
+
for (let index = 0; index < length; index += 1) result.matched.push(array[index]);
|
|
32
|
+
}
|
|
24
33
|
function createFindParameters(original) {
|
|
25
34
|
const { length } = original;
|
|
26
35
|
return {
|
|
@@ -29,24 +38,27 @@ function createFindParameters(original) {
|
|
|
29
38
|
value: length === 1 && typeof original[0] !== "function" ? original[0] : original[1]
|
|
30
39
|
};
|
|
31
40
|
}
|
|
41
|
+
function findAbsoluteValueOrDefault(array, parameters, defaultValue, useDefaultValue, reversed) {
|
|
42
|
+
if (parameters.length === 0) {
|
|
43
|
+
if (Array.isArray(array) && array.length > 0) return reversed ? array.at(-1) : array[0];
|
|
44
|
+
return useDefaultValue ? defaultValue : void 0;
|
|
45
|
+
}
|
|
46
|
+
const index = findValue(ARRAY_FIND_VALUE_INDEX, array, parameters, reversed);
|
|
47
|
+
if (index === -1) return useDefaultValue ? defaultValue : void 0;
|
|
48
|
+
return array[index];
|
|
49
|
+
}
|
|
32
50
|
function findComplexValues(parameters) {
|
|
33
|
-
const { array,
|
|
51
|
+
const { array, arrayLength, callback, limit, result, type, value } = parameters;
|
|
34
52
|
const keys = /* @__PURE__ */ new Set();
|
|
35
|
-
for (let
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (mapBefore == null) {
|
|
40
|
-
keyed = keyCallback?.(item, index, array) ?? item;
|
|
41
|
-
transformed = item;
|
|
42
|
-
} else {
|
|
43
|
-
transformed = mapBefore(item, index, array);
|
|
44
|
-
keyed = keyCallback?.(transformed, index, array) ?? transformed;
|
|
45
|
-
}
|
|
53
|
+
for (let arrayIndex = 0; arrayIndex < arrayLength; arrayIndex += 1) {
|
|
54
|
+
const arrayItem = array[arrayIndex];
|
|
55
|
+
const keyed = callback == null ? arrayItem : callback(arrayItem, arrayIndex, array);
|
|
56
|
+
const mapped = arrayItem;
|
|
46
57
|
if (type === "all" && Object.is(keyed, value) || type === "unique" && !keys.has(keyed)) {
|
|
47
58
|
keys.add(keyed);
|
|
48
|
-
result.matched.push(
|
|
49
|
-
|
|
59
|
+
result.matched.push(mapped);
|
|
60
|
+
if (result.matched.length >= limit) return result;
|
|
61
|
+
} else result.notMatched.push(arrayItem);
|
|
50
62
|
}
|
|
51
63
|
return result;
|
|
52
64
|
}
|
|
@@ -54,13 +66,28 @@ function findSimpleValue(array, value, findIndex, reversed) {
|
|
|
54
66
|
if (findIndex) return reversed ? array.lastIndexOf(value) : array.indexOf(value);
|
|
55
67
|
return reversed ? array.findLast((item) => Object.is(item, value)) : array.find((item) => Object.is(item, value));
|
|
56
68
|
}
|
|
57
|
-
function findSimpleValues(
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
function findSimpleValues(parameters) {
|
|
70
|
+
const { array, arrayLength, callback, flat, limit, map, result, value } = parameters;
|
|
71
|
+
const { after, before } = map ?? {};
|
|
72
|
+
const handler = callback ?? ((item) => Object.is(item, value));
|
|
73
|
+
for (let arrayIndex = 0; arrayIndex < arrayLength; arrayIndex += 1) {
|
|
74
|
+
const arrayItem = array[arrayIndex];
|
|
75
|
+
let mapped = before == null ? arrayItem : before(arrayItem, arrayIndex, array);
|
|
76
|
+
if (!flat || after != null) {
|
|
77
|
+
if (handler(mapped, arrayIndex, array)) {
|
|
78
|
+
mapped = after == null ? mapped : after(arrayItem, arrayIndex, array);
|
|
79
|
+
addResult(result, mapped, flat);
|
|
80
|
+
if (result.matched.length >= limit) return result;
|
|
81
|
+
} else result.notMatched.push(arrayItem);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const flatItems = Array.isArray(mapped) ? mapped : [mapped];
|
|
85
|
+
const flatLength = flatItems.length;
|
|
86
|
+
for (let flatIndex = 0; flatIndex < flatLength; flatIndex += 1) {
|
|
87
|
+
const flatItem = flatItems[flatIndex];
|
|
88
|
+
if (handler(flatItem, arrayIndex, array)) result.matched.push(flatItem);
|
|
89
|
+
else result.notMatched.push(flatItem);
|
|
90
|
+
}
|
|
64
91
|
}
|
|
65
92
|
return result;
|
|
66
93
|
}
|
|
@@ -84,50 +111,42 @@ function findValueInArray(array, callback, value, findIndex, reversed) {
|
|
|
84
111
|
}
|
|
85
112
|
return findIndex ? -1 : void 0;
|
|
86
113
|
}
|
|
87
|
-
function
|
|
88
|
-
if (parameters.length === 0) {
|
|
89
|
-
if (Array.isArray(array) && array.length > 0) return reversed ? array.at(-1) : array[0];
|
|
90
|
-
return useDefaultValue ? defaultValue : void 0;
|
|
91
|
-
}
|
|
92
|
-
const index = findValue(ARRAY_FIND_VALUE_INDEX, array, parameters, reversed);
|
|
93
|
-
if (index === -1) return useDefaultValue ? defaultValue : void 0;
|
|
94
|
-
return array[index];
|
|
95
|
-
}
|
|
96
|
-
function findValues(type, array, parameters, mapper) {
|
|
114
|
+
function findValues(type, array, parameters, options) {
|
|
97
115
|
const result = {
|
|
98
116
|
matched: [],
|
|
99
117
|
notMatched: []
|
|
100
118
|
};
|
|
101
|
-
if (!Array.isArray(array)
|
|
102
|
-
const
|
|
119
|
+
if (!Array.isArray(array)) return result;
|
|
120
|
+
const arrayLength = array.length;
|
|
121
|
+
if (arrayLength === 0) return result;
|
|
103
122
|
const { bool, key, value } = createFindParameters(parameters);
|
|
104
123
|
const callbacks = getArrayCallbacks(bool, key);
|
|
105
|
-
if (type === "unique" && callbacks?.keyed == null &&
|
|
124
|
+
if (type === "unique" && callbacks?.keyed == null && arrayLength >= 100) {
|
|
106
125
|
result.matched = [...new Set(array)];
|
|
107
126
|
return result;
|
|
108
127
|
}
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (callbacks?.bool != null || type === "all" && key == null) return findSimpleValues(array, length, value, callbacks?.bool, mapBefore, mapAfter, result);
|
|
121
|
-
return findComplexValues({
|
|
128
|
+
const limit = options?.limit ?? Number.POSITIVE_INFINITY;
|
|
129
|
+
const flat = options?.map?.flat ?? false;
|
|
130
|
+
const mapCallback = getArrayCallback(options?.map?.callback);
|
|
131
|
+
const mapReverse = options?.map?.reverse ?? false;
|
|
132
|
+
let map;
|
|
133
|
+
if (mapCallback != null) map = {
|
|
134
|
+
before: mapReverse ? mapCallback : void 0,
|
|
135
|
+
after: mapReverse ? void 0 : mapCallback
|
|
136
|
+
};
|
|
137
|
+
const simple = callbacks?.bool != null || type === "all" && key == null;
|
|
138
|
+
const findParameters = {
|
|
122
139
|
array,
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
140
|
+
arrayLength,
|
|
141
|
+
flat,
|
|
142
|
+
limit,
|
|
143
|
+
map,
|
|
126
144
|
result,
|
|
127
145
|
type,
|
|
128
146
|
value,
|
|
129
|
-
|
|
130
|
-
}
|
|
147
|
+
callback: simple ? callbacks?.bool : callbacks?.keyed
|
|
148
|
+
};
|
|
149
|
+
return simple ? findSimpleValues(findParameters) : findComplexValues(findParameters);
|
|
131
150
|
}
|
|
132
151
|
//#endregion
|
|
133
152
|
//#region src/array/filter.ts
|
|
@@ -506,6 +525,13 @@ function startsWithArray(haystack, needle, key) {
|
|
|
506
525
|
* @param value Number to round down
|
|
507
526
|
* @param decimals Number of decimal places to round to _(defaults to `0`)_
|
|
508
527
|
* @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
|
|
528
|
+
*
|
|
529
|
+
* @example
|
|
530
|
+
* ```typescript
|
|
531
|
+
* floor(10.567, 2); // => 10.56
|
|
532
|
+
* floor(10.567); // => 10
|
|
533
|
+
* floor('abc'); // => Number.NaN
|
|
534
|
+
* ```
|
|
509
535
|
*/
|
|
510
536
|
function floor(value, decimals) {
|
|
511
537
|
return roundNumber(Math.floor, value, decimals);
|
|
@@ -516,6 +542,13 @@ function floor(value, decimals) {
|
|
|
516
542
|
* @param value Number to round
|
|
517
543
|
* @param decimals Number of decimal places to round to _(defaults to `0`)_
|
|
518
544
|
* @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
* ```typescript
|
|
548
|
+
* round(10.567, 2); // => 10.57
|
|
549
|
+
* round(10.567); // => 11
|
|
550
|
+
* round('abc'); // => Number.NaN
|
|
551
|
+
* ```
|
|
519
552
|
*/
|
|
520
553
|
function round(value, decimals) {
|
|
521
554
|
return roundNumber(Math.round, value, decimals);
|
|
@@ -573,6 +606,11 @@ const RANDOM_DIVISOR = 2 ** 32;
|
|
|
573
606
|
*
|
|
574
607
|
* @param array Original array
|
|
575
608
|
* @returns Shuffled array
|
|
609
|
+
*
|
|
610
|
+
* @example
|
|
611
|
+
* ```typescript
|
|
612
|
+
* shuffle([1, 2, 3]); // => [3, 1, 2] (maybe? it's random, you know)
|
|
613
|
+
* ```
|
|
576
614
|
*/
|
|
577
615
|
function shuffle(array) {
|
|
578
616
|
if (!Array.isArray(array)) return [];
|
|
@@ -805,6 +843,12 @@ function push(array, pushed) {
|
|
|
805
843
|
*
|
|
806
844
|
* @param array Array to reverse
|
|
807
845
|
* @returns Reversed array
|
|
846
|
+
*
|
|
847
|
+
* @example
|
|
848
|
+
* ```typescript
|
|
849
|
+
* reverse([1, 2, 3]); // => [3, 2, 1]
|
|
850
|
+
* reverse(['a', 'b', 'c']); // => ['c', 'b', 'a']
|
|
851
|
+
* ```
|
|
808
852
|
*/
|
|
809
853
|
function reverse(array) {
|
|
810
854
|
if (!Array.isArray(array)) return [];
|
|
@@ -822,7 +866,7 @@ function reverse(array) {
|
|
|
822
866
|
//#endregion
|
|
823
867
|
//#region src/array/single.ts
|
|
824
868
|
function single(array, ...parameters) {
|
|
825
|
-
const { matched } = findValues("all", array, parameters);
|
|
869
|
+
const { matched } = findValues("all", array, parameters, { limit: 2 });
|
|
826
870
|
if (matched.length > 1) throw new Error(SINGLE_MESSAGE);
|
|
827
871
|
return matched[0];
|
|
828
872
|
}
|
|
@@ -1053,22 +1097,28 @@ move.indices = moveIndices;
|
|
|
1053
1097
|
move.toIndex = moveToIndex;
|
|
1054
1098
|
//#endregion
|
|
1055
1099
|
//#region src/array/select.ts
|
|
1056
|
-
function
|
|
1057
|
-
return selectValues(array,
|
|
1100
|
+
function filterAndFlatMap(array, filter, mapper) {
|
|
1101
|
+
return selectValues(array, filter, mapper, true, false);
|
|
1102
|
+
}
|
|
1103
|
+
function filterAndMap(array, filter, mapper) {
|
|
1104
|
+
return selectValues(array, filter, mapper, false, false);
|
|
1058
1105
|
}
|
|
1059
|
-
function
|
|
1060
|
-
return
|
|
1061
|
-
callback: parameters.shift(),
|
|
1062
|
-
reverse: true
|
|
1063
|
-
}).matched;
|
|
1106
|
+
function flatMapAndFilter(array, mapper, filter) {
|
|
1107
|
+
return selectValues(array, filter, mapper, true, true);
|
|
1064
1108
|
}
|
|
1065
|
-
function
|
|
1066
|
-
return
|
|
1067
|
-
callback: parameters.pop(),
|
|
1068
|
-
reverse: false
|
|
1069
|
-
}).matched;
|
|
1109
|
+
function mapAndFilter(array, mapper, filter) {
|
|
1110
|
+
return selectValues(array, filter, mapper, false, true);
|
|
1070
1111
|
}
|
|
1112
|
+
function selectValues(array, filter, mapper, flat, reverse) {
|
|
1113
|
+
return findValues("all", array, [filter], { map: {
|
|
1114
|
+
flat,
|
|
1115
|
+
reverse,
|
|
1116
|
+
callback: mapper
|
|
1117
|
+
} }).matched;
|
|
1118
|
+
}
|
|
1119
|
+
filterAndMap.flat = filterAndFlatMap;
|
|
1071
1120
|
filterAndMap.reverse = mapAndFilter;
|
|
1121
|
+
mapAndFilter.flat = flatMapAndFilter;
|
|
1072
1122
|
//#endregion
|
|
1073
1123
|
//#region src/models/value/value.misc.model.ts
|
|
1074
1124
|
const COMPARE_NAME = "compare";
|
|
@@ -1194,9 +1244,15 @@ function getString(value) {
|
|
|
1194
1244
|
const asString = String(value.valueOf?.() ?? value);
|
|
1195
1245
|
return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
|
|
1196
1246
|
}
|
|
1247
|
+
/**
|
|
1248
|
+
* @internal
|
|
1249
|
+
*/
|
|
1197
1250
|
function ignoreKey(key) {
|
|
1198
1251
|
return STRING_EXPRESSION_IGNORED.test(key);
|
|
1199
1252
|
}
|
|
1253
|
+
/**
|
|
1254
|
+
* @internal
|
|
1255
|
+
*/
|
|
1200
1256
|
function interpolate(strings, values) {
|
|
1201
1257
|
const { length } = strings;
|
|
1202
1258
|
let interpolated = "";
|
|
@@ -1214,6 +1270,14 @@ function interpolate(strings, values) {
|
|
|
1214
1270
|
* @param array Array of values
|
|
1215
1271
|
* @param delimiter Delimiter to use between values
|
|
1216
1272
|
* @returns Joined string
|
|
1273
|
+
* @example
|
|
1274
|
+
* ```typescript
|
|
1275
|
+
* join(['a', 'b', 'c']); // => 'abc'
|
|
1276
|
+
* join(['a', 'b', 'c'], ', '); // => 'a, b, c'
|
|
1277
|
+
* join(['a', '', 'c']); // => 'ac'
|
|
1278
|
+
* join([null, 'b', undefined]); // => 'b'
|
|
1279
|
+
* join([]); // => ''
|
|
1280
|
+
* ```
|
|
1217
1281
|
*/
|
|
1218
1282
|
function join(array, delimiter) {
|
|
1219
1283
|
if (!Array.isArray(array)) return "";
|
|
@@ -1229,9 +1293,15 @@ function join(array, delimiter) {
|
|
|
1229
1293
|
function tryCallback(value, callback) {
|
|
1230
1294
|
return unwrap(attempt(() => callback(value)), value);
|
|
1231
1295
|
}
|
|
1296
|
+
/**
|
|
1297
|
+
* @internal
|
|
1298
|
+
*/
|
|
1232
1299
|
function tryDecode(value) {
|
|
1233
1300
|
return tryCallback(value, decodeURIComponent);
|
|
1234
1301
|
}
|
|
1302
|
+
/**
|
|
1303
|
+
* @internal
|
|
1304
|
+
*/
|
|
1235
1305
|
function tryEncode(value) {
|
|
1236
1306
|
return tryCallback(value, encodeURIComponent);
|
|
1237
1307
|
}
|
|
@@ -2219,6 +2289,13 @@ const EXPRESSION_WHITESPACE_ONLY = /^\s*$/;
|
|
|
2219
2289
|
* @param minimum Minimum value
|
|
2220
2290
|
* @param maximum Maximum value _(inclusive)_
|
|
2221
2291
|
* @returns `true` if the value is between the minimum and maximum, otherwise `false`
|
|
2292
|
+
*
|
|
2293
|
+
* @example
|
|
2294
|
+
* ```typescript
|
|
2295
|
+
* between(5, 1, 10); // => true
|
|
2296
|
+
* between(0, 1, 10); // => false
|
|
2297
|
+
* between(10, 10, 10); // => true
|
|
2298
|
+
* ```
|
|
2222
2299
|
*/
|
|
2223
2300
|
function between(value, minimum, maximum) {
|
|
2224
2301
|
if (![
|
|
@@ -2261,6 +2338,17 @@ function clamp(value, minimum, maximum, loop) {
|
|
|
2261
2338
|
*
|
|
2262
2339
|
* @param value Original value
|
|
2263
2340
|
* @returns Original value as a number, or `Number.NaN` if the value is unable to be parsed
|
|
2341
|
+
*
|
|
2342
|
+
* @example
|
|
2343
|
+
* ```typescript
|
|
2344
|
+
* getNumber(null) // => Number.NaN
|
|
2345
|
+
* getNumber('foo') // => Number.NaN
|
|
2346
|
+
* getNumber('123') // => 123
|
|
2347
|
+
* getNumber(true) // => 1
|
|
2348
|
+
* getNumber([1, 2, 3]) // => Number.NaN
|
|
2349
|
+
* getNumber({a: 1}) // => Number.NaN
|
|
2350
|
+
* getNumber(() => 123) // => 123
|
|
2351
|
+
* ```
|
|
2264
2352
|
*/
|
|
2265
2353
|
function getNumber(value) {
|
|
2266
2354
|
if (typeof value === "number") return value;
|
|
@@ -2493,6 +2581,14 @@ const STRING_REPLACEMENT_CAMEL_CASE = "$1-$2";
|
|
|
2493
2581
|
*
|
|
2494
2582
|
* @param value String to convert
|
|
2495
2583
|
* @returns Camel-cased string
|
|
2584
|
+
*
|
|
2585
|
+
* @example
|
|
2586
|
+
* ```typescript
|
|
2587
|
+
* camelCase('this is camel case'); // => 'thisIsCamelCase'
|
|
2588
|
+
* camelCase('ThisIsCamelCase'); // => 'thisIsCamelCase'
|
|
2589
|
+
* camelCase('this-is-camel-case'); // => 'thisIsCamelCase'
|
|
2590
|
+
* camelCase('this_is_camel_case'); // => 'thisIsCamelCase'
|
|
2591
|
+
* ```
|
|
2496
2592
|
*/
|
|
2497
2593
|
function camelCase(value) {
|
|
2498
2594
|
return toCase(STRING_CASE_CAMEL, value, true, false);
|
|
@@ -2502,6 +2598,14 @@ function camelCase(value) {
|
|
|
2502
2598
|
*
|
|
2503
2599
|
* @param value String to capitalize
|
|
2504
2600
|
* @returns Capitalized string
|
|
2601
|
+
*
|
|
2602
|
+
* @example
|
|
2603
|
+
* ```typescript
|
|
2604
|
+
* capitalize('this is a test'); // => 'This is a test'
|
|
2605
|
+
* capitalize('This Is A Test'); // => 'This is a test'
|
|
2606
|
+
* capitalize('t'); // => 'T'
|
|
2607
|
+
* capitalize(''); // => ''
|
|
2608
|
+
* ```
|
|
2505
2609
|
*/
|
|
2506
2610
|
function capitalize(value) {
|
|
2507
2611
|
if (typeof value !== "string" || value.length === 0) return "";
|
|
@@ -2513,6 +2617,14 @@ function capitalize(value) {
|
|
|
2513
2617
|
*
|
|
2514
2618
|
* @param value String to convert
|
|
2515
2619
|
* @returns Kebab-cased string
|
|
2620
|
+
*
|
|
2621
|
+
* @example
|
|
2622
|
+
* ```typescript
|
|
2623
|
+
* kebabCase('this is kebab case'); // => 'this-is-kebab-case'
|
|
2624
|
+
* kebabCase('ThisIsKebabCase'); // => 'this-is-kebab-case'
|
|
2625
|
+
* kebabCase('this-is-kebab-case'); // => 'this-is-kebab-case'
|
|
2626
|
+
* kebabCase('this_is_kebab_case'); // => 'this-is-kebab-case'
|
|
2627
|
+
* ```
|
|
2516
2628
|
*/
|
|
2517
2629
|
function kebabCase(value) {
|
|
2518
2630
|
return toCase(STRING_CASE_KEBAB, value, false, false);
|
|
@@ -2522,6 +2634,13 @@ function kebabCase(value) {
|
|
|
2522
2634
|
*
|
|
2523
2635
|
* @param value String to convert
|
|
2524
2636
|
* @returns Lower-cased string
|
|
2637
|
+
*
|
|
2638
|
+
* @example
|
|
2639
|
+
* ```typescript
|
|
2640
|
+
* lowerCase('THIS IS A TEST'); // => 'this is a test'
|
|
2641
|
+
* lowerCase('this is a test'); // => 'this is a test'
|
|
2642
|
+
* lowerCase('t'); // => 't'
|
|
2643
|
+
* ```
|
|
2525
2644
|
*/
|
|
2526
2645
|
function lowerCase(value) {
|
|
2527
2646
|
if (typeof value !== "string") return "";
|
|
@@ -2533,6 +2652,14 @@ function lowerCase(value) {
|
|
|
2533
2652
|
*
|
|
2534
2653
|
* @param value String to convert
|
|
2535
2654
|
* @returns Pascal-cased string
|
|
2655
|
+
*
|
|
2656
|
+
* @example
|
|
2657
|
+
* ```typescript
|
|
2658
|
+
* pascalCase('this is pascal case'); // => 'ThisIsPascalCase'
|
|
2659
|
+
* pascalCase('ThisIsPascalCase'); // => 'ThisIsPascalCase'
|
|
2660
|
+
* pascalCase('this-is-pascal-case'); // => 'ThisIsPascalCase'
|
|
2661
|
+
* pascalCase('this_is_pascal_case'); // => 'ThisIsPascalCase'
|
|
2662
|
+
* ```
|
|
2536
2663
|
*/
|
|
2537
2664
|
function pascalCase(value) {
|
|
2538
2665
|
return toCase(STRING_CASE_PASCAL, value, true, true);
|
|
@@ -2542,6 +2669,14 @@ function pascalCase(value) {
|
|
|
2542
2669
|
*
|
|
2543
2670
|
* @param value String to convert
|
|
2544
2671
|
* @returns Snake-cased string
|
|
2672
|
+
*
|
|
2673
|
+
* @example
|
|
2674
|
+
* ```typescript
|
|
2675
|
+
* snakeCase('this is snake case'); // => 'this_is_snake_case'
|
|
2676
|
+
* snakeCase('ThisIsSnakeCase'); // => 'this_is_snake_case'
|
|
2677
|
+
* snakeCase('this-is-snake-case'); // => 'this_is_snake_case'
|
|
2678
|
+
* snakeCase('this_is_snake_case'); // => 'this_is_snake_case'
|
|
2679
|
+
* ```
|
|
2545
2680
|
*/
|
|
2546
2681
|
function snakeCase(value) {
|
|
2547
2682
|
return toCase(STRING_CASE_SNAKE, value, false, false);
|
|
@@ -2551,6 +2686,14 @@ function snakeCase(value) {
|
|
|
2551
2686
|
*
|
|
2552
2687
|
* @param value String to convert
|
|
2553
2688
|
* @returns Title-cased string
|
|
2689
|
+
*
|
|
2690
|
+
* @example
|
|
2691
|
+
* ```typescript
|
|
2692
|
+
* titleCase('this is a test'); // => 'This Is A Test'
|
|
2693
|
+
* titleCase('This Is A Test'); // => 'This Is A Test'
|
|
2694
|
+
* titleCase('t'); // => 'T'
|
|
2695
|
+
* titleCase(''); // => ''
|
|
2696
|
+
* ```
|
|
2554
2697
|
*/
|
|
2555
2698
|
function titleCase(value) {
|
|
2556
2699
|
if (typeof value !== "string" || value.length === 0) return "";
|
|
@@ -2593,6 +2736,14 @@ function toCaseCallback(value) {
|
|
|
2593
2736
|
*
|
|
2594
2737
|
* @param value String to convert
|
|
2595
2738
|
* @returns Upper-cased string
|
|
2739
|
+
*
|
|
2740
|
+
* @example
|
|
2741
|
+
* ```typescript
|
|
2742
|
+
* upperCase('this is a test'); // => 'THIS IS A TEST'
|
|
2743
|
+
* upperCase('This Is A Test'); // => 'THIS IS A TEST'
|
|
2744
|
+
* upperCase('t'); // => 'T'
|
|
2745
|
+
* upperCase(''); // => ''
|
|
2746
|
+
* ```
|
|
2596
2747
|
*/
|
|
2597
2748
|
function upperCase(value) {
|
|
2598
2749
|
if (typeof value !== "string" || value.length === 0) return "";
|
|
@@ -3337,6 +3488,9 @@ function isRejected(value) {
|
|
|
3337
3488
|
function cancelable(executor) {
|
|
3338
3489
|
return new CancelablePromise(executor);
|
|
3339
3490
|
}
|
|
3491
|
+
/**
|
|
3492
|
+
* @internal
|
|
3493
|
+
*/
|
|
3340
3494
|
function handleResult(status, parameters) {
|
|
3341
3495
|
const { aborter, complete, data, handlers, index, key, value } = parameters;
|
|
3342
3496
|
if (aborter?.signal.aborted ?? false) return;
|
|
@@ -3360,6 +3514,9 @@ function handleResult(status, parameters) {
|
|
|
3360
3514
|
handlers.resolve(data.result);
|
|
3361
3515
|
}
|
|
3362
3516
|
}
|
|
3517
|
+
/**
|
|
3518
|
+
* @internal
|
|
3519
|
+
*/
|
|
3363
3520
|
function settlePromise(settler, value, aborter) {
|
|
3364
3521
|
aborter?.cancel();
|
|
3365
3522
|
settler(value);
|
|
@@ -3390,6 +3547,9 @@ function delay(options) {
|
|
|
3390
3547
|
}
|
|
3391
3548
|
//#endregion
|
|
3392
3549
|
//#region src/promise/timed.ts
|
|
3550
|
+
/**
|
|
3551
|
+
* @internal
|
|
3552
|
+
*/
|
|
3393
3553
|
async function getTimedPromise(promise, time, signal) {
|
|
3394
3554
|
const aborter = createAborter(signal, () => {
|
|
3395
3555
|
limiter.cancel();
|
|
@@ -3568,55 +3728,12 @@ function attemptPipe(initial, first, ...seconds) {
|
|
|
3568
3728
|
attemptPipe.async = attemptAsyncPipe;
|
|
3569
3729
|
//#endregion
|
|
3570
3730
|
//#region src/models/string/string.fuzzy.model.ts
|
|
3731
|
+
const FUZZY_BOUNDARY_SEPARATOR = /[\s./:\\_-]/;
|
|
3571
3732
|
const FUZZY_MESSAGE_ARRAY = "Fuzzy requires an array of items";
|
|
3572
3733
|
const FUZZY_MESSAGE_HANDLER = "Fuzzy requires a key or function to stringify items";
|
|
3573
3734
|
const FUZZY_PROPERTY = "$fuzzy";
|
|
3574
3735
|
const FUZZY_SYMBOL = Symbol(FUZZY_PROPERTY);
|
|
3575
3736
|
//#endregion
|
|
3576
|
-
//#region src/string/match.ts
|
|
3577
|
-
/**
|
|
3578
|
-
* Check if a string ends with a specified substring
|
|
3579
|
-
*
|
|
3580
|
-
* @param haystack String to look in
|
|
3581
|
-
* @param needle String to look for
|
|
3582
|
-
* @param ignoreCase Ignore case when matching? _(defaults to `false`)_
|
|
3583
|
-
* @returns `true` if the string ends with the given substring, otherwise `false`
|
|
3584
|
-
*/
|
|
3585
|
-
function endsWith(haystack, needle, ignoreCase) {
|
|
3586
|
-
return match(STRING_MATCH_ENDS_WITH, haystack, needle, ignoreCase === true);
|
|
3587
|
-
}
|
|
3588
|
-
/**
|
|
3589
|
-
* Check if a string includes a specified substring
|
|
3590
|
-
*
|
|
3591
|
-
* @param haystack String to look in
|
|
3592
|
-
* @param needle String to look for
|
|
3593
|
-
* @param ignoreCase Ignore case when matching? _(defaults to `false`)_
|
|
3594
|
-
* @returns `true` if the string includes the given substring, otherwise `false`
|
|
3595
|
-
*/
|
|
3596
|
-
function includes(haystack, needle, ignoreCase) {
|
|
3597
|
-
return match(STRING_MATCH_INCLUDES, haystack, needle, ignoreCase === true);
|
|
3598
|
-
}
|
|
3599
|
-
function match(type, haystack, needle, ignoreCase) {
|
|
3600
|
-
if (typeof haystack !== "string" || typeof needle !== "string") return false;
|
|
3601
|
-
matchMemoizers[type] ??= memoize(matchCallback.bind(type));
|
|
3602
|
-
return matchMemoizers[type].run(haystack, needle, ignoreCase);
|
|
3603
|
-
}
|
|
3604
|
-
function matchCallback(haystack, needle, ignoreCase) {
|
|
3605
|
-
return (ignoreCase ? haystack.toLocaleLowerCase() : haystack)[this](ignoreCase ? needle.toLocaleLowerCase() : needle);
|
|
3606
|
-
}
|
|
3607
|
-
/**
|
|
3608
|
-
* Check if a string starts with a specified substring
|
|
3609
|
-
*
|
|
3610
|
-
* @param haystack String to look in
|
|
3611
|
-
* @param needle String to look for
|
|
3612
|
-
* @param ignoreCase Ignore case when matching? _(defaults to `false`)_
|
|
3613
|
-
* @returns `true` if the string starts with the given substring, otherwise `false`
|
|
3614
|
-
*/
|
|
3615
|
-
function startsWith(haystack, needle, ignoreCase) {
|
|
3616
|
-
return match(STRING_MATCH_STARTS_WITH, haystack, needle, ignoreCase === true);
|
|
3617
|
-
}
|
|
3618
|
-
const matchMemoizers = {};
|
|
3619
|
-
//#endregion
|
|
3620
3737
|
//#region src/string/fuzzy.ts
|
|
3621
3738
|
function Fuzzy(state) {
|
|
3622
3739
|
this[FUZZY_SYMBOL] = state;
|
|
@@ -3626,39 +3743,76 @@ Fuzzy.prototype.search = search;
|
|
|
3626
3743
|
Object.defineProperties(Fuzzy.prototype, {
|
|
3627
3744
|
items: {
|
|
3628
3745
|
enumerable: true,
|
|
3629
|
-
get:
|
|
3630
|
-
set:
|
|
3746
|
+
get: getItems,
|
|
3747
|
+
set: setItems
|
|
3631
3748
|
},
|
|
3632
3749
|
strings: {
|
|
3633
3750
|
enumerable: true,
|
|
3634
|
-
get:
|
|
3751
|
+
get: getStrings
|
|
3635
3752
|
}
|
|
3636
3753
|
});
|
|
3637
|
-
function
|
|
3638
|
-
return
|
|
3754
|
+
function compareItem(sorter) {
|
|
3755
|
+
return (first, second) => sorter(first.string.original, second.string.original);
|
|
3639
3756
|
}
|
|
3640
|
-
function
|
|
3641
|
-
|
|
3642
|
-
|
|
3757
|
+
function compareRanked(sorter) {
|
|
3758
|
+
return (first, second) => first.rank - second.rank || first.position - second.position || sorter(first.string.original, second.string.original);
|
|
3759
|
+
}
|
|
3760
|
+
function createItems(state, items) {
|
|
3761
|
+
state.items.original = items.map((item) => ({
|
|
3762
|
+
data: item,
|
|
3763
|
+
string: createString(state.handler(item))
|
|
3764
|
+
}));
|
|
3765
|
+
state.items.sorted = void 0;
|
|
3766
|
+
}
|
|
3767
|
+
function createOptions(input, state) {
|
|
3768
|
+
const options = {};
|
|
3769
|
+
const original = isPlainObject(input) ? input : {};
|
|
3770
|
+
const limit = typeof input === "number" ? input : original.limit;
|
|
3643
3771
|
if (typeof limit === "number" && !Number.isNaN(limit) && limit >= 1) options.limit = floor(limit);
|
|
3644
|
-
else options.limit = state?.limit;
|
|
3645
|
-
options.tolerance = getTolerance(
|
|
3772
|
+
else options.limit = state?.limit ?? Number.POSITIVE_INFINITY;
|
|
3773
|
+
options.tolerance = getTolerance(original.tolerance, state);
|
|
3646
3774
|
return options;
|
|
3647
3775
|
}
|
|
3648
|
-
function
|
|
3649
|
-
|
|
3650
|
-
|
|
3776
|
+
function createRanked(item, needle, position) {
|
|
3777
|
+
let boundary = position;
|
|
3778
|
+
while (boundary > -1 && !isBoundary(item.string, boundary)) boundary = item.string.lowercase.indexOf(needle, boundary + 1);
|
|
3779
|
+
if (boundary === -1) return {
|
|
3780
|
+
...item,
|
|
3781
|
+
position,
|
|
3782
|
+
rank: 2
|
|
3783
|
+
};
|
|
3651
3784
|
return {
|
|
3785
|
+
...item,
|
|
3786
|
+
position: boundary,
|
|
3787
|
+
rank: boundary === 0 ? 0 : 1
|
|
3788
|
+
};
|
|
3789
|
+
}
|
|
3790
|
+
function createState(items, input) {
|
|
3791
|
+
const handler = getHandler(input);
|
|
3792
|
+
const options = createOptions(input);
|
|
3793
|
+
const sorter = getComparator(input);
|
|
3794
|
+
const state = {
|
|
3795
|
+
compare: {
|
|
3796
|
+
item: compareItem(sorter),
|
|
3797
|
+
ranked: compareRanked(sorter)
|
|
3798
|
+
},
|
|
3652
3799
|
handler,
|
|
3653
|
-
items:
|
|
3800
|
+
items: { original: [] },
|
|
3654
3801
|
limit: options.limit,
|
|
3655
|
-
strings: items.map(handler),
|
|
3656
3802
|
tolerance: options.tolerance
|
|
3657
3803
|
};
|
|
3804
|
+
createItems(state, items);
|
|
3805
|
+
return state;
|
|
3806
|
+
}
|
|
3807
|
+
function createString(original) {
|
|
3808
|
+
return {
|
|
3809
|
+
original,
|
|
3810
|
+
lowercase: lowerCase(original)
|
|
3811
|
+
};
|
|
3658
3812
|
}
|
|
3659
3813
|
function fuzzy(items, configuration) {
|
|
3660
3814
|
if (!Array.isArray(items)) throw new TypeError(FUZZY_MESSAGE_ARRAY);
|
|
3661
|
-
return new Fuzzy(
|
|
3815
|
+
return new Fuzzy(createState(items, configuration));
|
|
3662
3816
|
}
|
|
3663
3817
|
/**
|
|
3664
3818
|
* Does the needle match the haystack in a fuzzy way?
|
|
@@ -3672,53 +3826,117 @@ function fuzzy(items, configuration) {
|
|
|
3672
3826
|
function fuzzyMatch(haystack, needle) {
|
|
3673
3827
|
if (typeof haystack !== "string" || typeof needle !== "string") return false;
|
|
3674
3828
|
const trimmed = needle.trim();
|
|
3675
|
-
|
|
3676
|
-
|
|
3829
|
+
const lowercaseHaystack = lowerCase(haystack);
|
|
3830
|
+
const lowercaseNeedle = lowerCase(trimmed);
|
|
3831
|
+
if (lowercaseHaystack.includes(lowercaseNeedle)) return true;
|
|
3832
|
+
return getScore({
|
|
3833
|
+
lowercase: lowercaseHaystack,
|
|
3834
|
+
original: haystack
|
|
3835
|
+
}, lowercaseNeedle) > -1;
|
|
3836
|
+
}
|
|
3837
|
+
function getComparator(input) {
|
|
3838
|
+
if (isPlainObject(input) && typeof input.compare === "function") return input.compare;
|
|
3839
|
+
defaultSorter ??= Intl.Collator().compare;
|
|
3840
|
+
return defaultSorter;
|
|
3677
3841
|
}
|
|
3678
3842
|
function getHandler(input) {
|
|
3679
3843
|
if (input == null || input === getString) return getString;
|
|
3680
3844
|
switch (typeof input) {
|
|
3681
|
-
case "function": return input;
|
|
3682
|
-
case "
|
|
3845
|
+
case "function": return (item) => getString(input(item));
|
|
3846
|
+
case "number":
|
|
3847
|
+
case "string":
|
|
3848
|
+
case "symbol": return (item) => getString(item?.[input]);
|
|
3683
3849
|
default:
|
|
3684
3850
|
if (isPlainObject(input)) return getHandler(input.key ?? input.handler);
|
|
3685
3851
|
throw new TypeError(FUZZY_MESSAGE_HANDLER);
|
|
3686
3852
|
}
|
|
3687
3853
|
}
|
|
3688
|
-
function
|
|
3689
|
-
return this[FUZZY_SYMBOL].items.
|
|
3854
|
+
function getItems() {
|
|
3855
|
+
return this[FUZZY_SYMBOL].items.original.map((item) => item.data);
|
|
3690
3856
|
}
|
|
3691
|
-
function
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
function getScore(haystack, needle) {
|
|
3695
|
-
if (!isSubsequence(haystack, needle)) return -1;
|
|
3696
|
-
const lowerCaseHaystack = lowerCase(haystack);
|
|
3697
|
-
const lowerCaseNeedle = lowerCase(needle);
|
|
3698
|
-
const needleLength = lowerCaseNeedle.length;
|
|
3857
|
+
function getMatchEnd(haystack, needle, cursor) {
|
|
3858
|
+
const haystackLength = haystack.length;
|
|
3859
|
+
const needleLength = needle.length;
|
|
3699
3860
|
let needleIndex = 0;
|
|
3700
|
-
let
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3861
|
+
for (let index = cursor; index < haystackLength; index += 1) if (haystack[index] === needle[needleIndex]) {
|
|
3862
|
+
needleIndex += 1;
|
|
3863
|
+
if (needleIndex === needleLength) return index;
|
|
3864
|
+
}
|
|
3865
|
+
return -1;
|
|
3866
|
+
}
|
|
3867
|
+
function getResult(state, exact, included, scored, options) {
|
|
3868
|
+
const result = {
|
|
3869
|
+
exact: [],
|
|
3870
|
+
included: [],
|
|
3871
|
+
similar: []
|
|
3872
|
+
};
|
|
3873
|
+
exact.sort(state.compare.item);
|
|
3874
|
+
result.exact = exact.slice(0, options.limit).map((item) => item.data);
|
|
3875
|
+
included.sort(state.compare.ranked);
|
|
3876
|
+
result.included = included.slice(0, options.limit - result.exact.length).map((item) => item.data);
|
|
3877
|
+
const remaining = options.limit - result.exact.length - result.included.length;
|
|
3878
|
+
if (remaining === 0) return result;
|
|
3879
|
+
const keys = Object.keys(scored).map(Number).sort((first, second) => second - first);
|
|
3880
|
+
const keysLength = keys.length;
|
|
3881
|
+
if (keysLength === 0) return result;
|
|
3882
|
+
const maxScore = keys[0];
|
|
3883
|
+
outer: for (let index = 0; index < keysLength; index += 1) {
|
|
3884
|
+
const key = keys[index];
|
|
3885
|
+
if (maxScore - key > options.tolerance) break;
|
|
3886
|
+
const keyed = scored[key];
|
|
3887
|
+
const keyedLength = keyed.length;
|
|
3888
|
+
keyed.sort(state.compare.item);
|
|
3889
|
+
for (let keyedIndex = 0; keyedIndex < keyedLength; keyedIndex += 1) {
|
|
3890
|
+
result.similar.push(keyed[keyedIndex].data);
|
|
3891
|
+
if (result.similar.length >= remaining) break outer;
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3894
|
+
return result;
|
|
3895
|
+
}
|
|
3896
|
+
function getScore(item, needle) {
|
|
3897
|
+
const haystackLength = item.lowercase.length;
|
|
3898
|
+
const needleLength = needle.length;
|
|
3899
|
+
if (needleLength > haystackLength) return -1;
|
|
3900
|
+
let best = -1;
|
|
3901
|
+
let cursor = 0;
|
|
3902
|
+
while (cursor < haystackLength) {
|
|
3903
|
+
const end = getMatchEnd(item.lowercase, needle, cursor);
|
|
3904
|
+
if (end === -1) break;
|
|
3905
|
+
let index = end;
|
|
3906
|
+
let needleIndex = needleLength - 1;
|
|
3907
|
+
let next = -1;
|
|
3908
|
+
let score = 0;
|
|
3909
|
+
let start = end;
|
|
3910
|
+
while (needleIndex >= 0) {
|
|
3911
|
+
if (item.lowercase[index] === needle[needleIndex]) {
|
|
3912
|
+
score += 1;
|
|
3913
|
+
if (next !== -1) score += max([0, 5 - (next - index - 1)]);
|
|
3914
|
+
if (isBoundary(item, index)) score += 2;
|
|
3915
|
+
next = index;
|
|
3916
|
+
start = index;
|
|
3917
|
+
needleIndex -= 1;
|
|
3709
3918
|
}
|
|
3710
|
-
|
|
3711
|
-
needleIndex += 1;
|
|
3919
|
+
index -= 1;
|
|
3712
3920
|
}
|
|
3713
|
-
if (
|
|
3921
|
+
if (start === 0) score += 1;
|
|
3922
|
+
if (score > best) best = score;
|
|
3923
|
+
cursor = start + 1;
|
|
3714
3924
|
}
|
|
3715
|
-
|
|
3716
|
-
return max([0,
|
|
3925
|
+
if (best === -1) return -1;
|
|
3926
|
+
return max([0, best - floor(haystackLength / 3)]);
|
|
3927
|
+
}
|
|
3928
|
+
function getStrings() {
|
|
3929
|
+
return this[FUZZY_SYMBOL].items.original.map((item) => item.string.original);
|
|
3717
3930
|
}
|
|
3718
3931
|
function getTolerance(input, state) {
|
|
3719
3932
|
if (typeof input === "number" && !Number.isNaN(input)) return input < 0 ? 0 : floor(input);
|
|
3720
3933
|
return state?.tolerance ?? 5;
|
|
3721
3934
|
}
|
|
3935
|
+
function isBoundary(string, index) {
|
|
3936
|
+
if (index === 0 || FUZZY_BOUNDARY_SEPARATOR.test(string.lowercase[index - 1])) return true;
|
|
3937
|
+
if (string.original.length !== string.lowercase.length) return false;
|
|
3938
|
+
return string.original[index] !== string.lowercase[index] && string.original[index - 1] === string.lowercase[index - 1];
|
|
3939
|
+
}
|
|
3722
3940
|
/**
|
|
3723
3941
|
* Is the value a fuzzy searcher?
|
|
3724
3942
|
*
|
|
@@ -3730,74 +3948,48 @@ function getTolerance(input, state) {
|
|
|
3730
3948
|
function isFuzzy(value) {
|
|
3731
3949
|
return typeof value === "object" && value !== null && "$fuzzy" in value && value["$fuzzy"] === true;
|
|
3732
3950
|
}
|
|
3733
|
-
function isSubsequence(haystack, needle) {
|
|
3734
|
-
const lowerCaseHaystack = lowerCase(haystack);
|
|
3735
|
-
const lowerCaseNeedle = lowerCase(needle);
|
|
3736
|
-
const haystackLength = lowerCaseHaystack.length;
|
|
3737
|
-
const needleLength = lowerCaseNeedle.length;
|
|
3738
|
-
let needleIndex = 0;
|
|
3739
|
-
for (let haystackIndex = 0; haystackIndex < haystackLength; haystackIndex += 1) {
|
|
3740
|
-
if (lowerCaseHaystack[haystackIndex] === lowerCaseNeedle[needleIndex]) needleIndex += 1;
|
|
3741
|
-
if (needleIndex === needleLength) return true;
|
|
3742
|
-
}
|
|
3743
|
-
return false;
|
|
3744
|
-
}
|
|
3745
3951
|
function search(input, option) {
|
|
3746
3952
|
const state = this[FUZZY_SYMBOL];
|
|
3747
|
-
const options = option == null ? state :
|
|
3748
|
-
const result = {
|
|
3749
|
-
exact: [],
|
|
3750
|
-
similar: []
|
|
3751
|
-
};
|
|
3953
|
+
const options = option == null ? state : createOptions(option, state);
|
|
3752
3954
|
const value = typeof input === "string" ? input.trim() : "";
|
|
3955
|
+
const lowercaseValue = lowerCase(value);
|
|
3753
3956
|
if (value.length === 0) {
|
|
3754
|
-
|
|
3755
|
-
return
|
|
3957
|
+
state.items.sorted ??= state.items.original.toSorted(state.compare.item);
|
|
3958
|
+
return {
|
|
3959
|
+
exact: state.items.sorted.slice(0, options.limit).map((item) => item.data),
|
|
3960
|
+
included: [],
|
|
3961
|
+
similar: []
|
|
3962
|
+
};
|
|
3756
3963
|
}
|
|
3757
|
-
let { length } = state.items;
|
|
3758
3964
|
const exact = [];
|
|
3759
|
-
const
|
|
3965
|
+
const included = [];
|
|
3760
3966
|
const scored = {};
|
|
3967
|
+
const { length } = state.items.original;
|
|
3761
3968
|
for (let index = 0; index < length; index += 1) {
|
|
3762
|
-
const item = state.items[index];
|
|
3763
|
-
const
|
|
3764
|
-
if (
|
|
3765
|
-
exact.push(
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3969
|
+
const item = state.items.original[index];
|
|
3970
|
+
const { string } = item;
|
|
3971
|
+
if (string.lowercase === lowercaseValue) {
|
|
3972
|
+
exact.push(item);
|
|
3973
|
+
continue;
|
|
3974
|
+
}
|
|
3975
|
+
const position = string.lowercase.indexOf(lowercaseValue);
|
|
3976
|
+
if (position > -1) {
|
|
3977
|
+
included.push(createRanked(item, lowercaseValue, position));
|
|
3769
3978
|
continue;
|
|
3770
3979
|
}
|
|
3771
|
-
const score = getScore(
|
|
3980
|
+
const score = getScore(string, lowercaseValue);
|
|
3772
3981
|
if (score > -1) {
|
|
3773
3982
|
scored[score] ??= [];
|
|
3774
|
-
scored[score].push(
|
|
3775
|
-
item,
|
|
3776
|
-
haystack
|
|
3777
|
-
});
|
|
3778
|
-
}
|
|
3779
|
-
}
|
|
3780
|
-
const keys = Object.keys(scored).map(Number).sort((first, second) => second - first);
|
|
3781
|
-
length = keys.length;
|
|
3782
|
-
if (length > 0 && options.tolerance > 0) {
|
|
3783
|
-
const maxScore = keys[0];
|
|
3784
|
-
for (let index = 0; index < length; index += 1) {
|
|
3785
|
-
const key = keys[index];
|
|
3786
|
-
if (maxScore - key > options.tolerance) break;
|
|
3787
|
-
similar.push(...createFuzzyItems(scored[key]));
|
|
3983
|
+
scored[score].push(item);
|
|
3788
3984
|
}
|
|
3789
3985
|
}
|
|
3790
|
-
|
|
3791
|
-
if (options.limit == null) result.similar = similar;
|
|
3792
|
-
else result.similar = similar.slice(0, options.limit - result.exact.length);
|
|
3793
|
-
return result;
|
|
3986
|
+
return getResult(state, exact, included, scored, options);
|
|
3794
3987
|
}
|
|
3795
|
-
function
|
|
3988
|
+
function setItems(value) {
|
|
3796
3989
|
if (!Array.isArray(value)) throw new TypeError(FUZZY_MESSAGE_ARRAY);
|
|
3797
|
-
|
|
3798
|
-
state.items = value.slice();
|
|
3799
|
-
state.strings = value.map((item) => state.handler(item));
|
|
3990
|
+
createItems(this[FUZZY_SYMBOL], value);
|
|
3800
3991
|
}
|
|
3992
|
+
let defaultSorter;
|
|
3801
3993
|
fuzzy.is = isFuzzy;
|
|
3802
3994
|
fuzzy.match = fuzzyMatch;
|
|
3803
3995
|
//#endregion
|
|
@@ -3855,7 +4047,7 @@ function getUuid(html) {
|
|
|
3855
4047
|
*
|
|
3856
4048
|
* @param value JSON string to parse
|
|
3857
4049
|
* @param reviver Reviver function to transform the parsed values
|
|
3858
|
-
* @returns Parsed value or `undefined` if parsing fails
|
|
4050
|
+
* @returns Parsed value, or `undefined` if parsing fails
|
|
3859
4051
|
*/
|
|
3860
4052
|
function parse(value, reviver) {
|
|
3861
4053
|
try {
|
|
@@ -3869,6 +4061,13 @@ function parse(value, reviver) {
|
|
|
3869
4061
|
*
|
|
3870
4062
|
* @param value String to trim
|
|
3871
4063
|
* @returns Trimmed string
|
|
4064
|
+
* @example
|
|
4065
|
+
* ```typescript
|
|
4066
|
+
* trim(' this is a test '); // => 'this is a test'
|
|
4067
|
+
* trim('this is a test'); // => 'this is a test'
|
|
4068
|
+
* trim(' '); // => ''
|
|
4069
|
+
* trim(''); // => ''
|
|
4070
|
+
* ```
|
|
3872
4071
|
*/
|
|
3873
4072
|
function trim(value) {
|
|
3874
4073
|
return typeof value === "string" ? value.trim() : "";
|
|
@@ -3880,6 +4079,13 @@ function trim(value) {
|
|
|
3880
4079
|
* @param length Maximum length of the string after truncation
|
|
3881
4080
|
* @param suffix Suffix to append to the truncated string
|
|
3882
4081
|
* @returns Truncated string
|
|
4082
|
+
* @example
|
|
4083
|
+
* ```typescript
|
|
4084
|
+
* truncate('this is a test', 7); // => 'this is'
|
|
4085
|
+
* truncate('this is a test', 7, '...'); // => 'this ...'
|
|
4086
|
+
* truncate('this is a test', 20); // => 'this is a test'
|
|
4087
|
+
* truncate('this is a test', 0); // => ''
|
|
4088
|
+
* ```
|
|
3883
4089
|
*/
|
|
3884
4090
|
function truncate(value, length, suffix) {
|
|
3885
4091
|
if (typeof value !== "string" || typeof length !== "number" || length === 0) return "";
|
|
@@ -3891,6 +4097,74 @@ function truncate(value, length, suffix) {
|
|
|
3891
4097
|
return `${value.slice(0, truncatedLength)}${actualSuffix}`;
|
|
3892
4098
|
}
|
|
3893
4099
|
//#endregion
|
|
4100
|
+
//#region src/string/match.ts
|
|
4101
|
+
/**
|
|
4102
|
+
* Check if a string ends with a specified substring
|
|
4103
|
+
*
|
|
4104
|
+
* @param haystack String to look in
|
|
4105
|
+
* @param needle String to look for
|
|
4106
|
+
* @param ignoreCase Ignore case when matching? _(defaults to `false`)_
|
|
4107
|
+
* @returns `true` if the string ends with the given substring, otherwise `false`
|
|
4108
|
+
*
|
|
4109
|
+
* @example
|
|
4110
|
+
* ```typescript
|
|
4111
|
+
* endsWith('this is a test', 'test'); // => true
|
|
4112
|
+
* endsWith('this is a test', 'Test'); // => false
|
|
4113
|
+
* endsWith('this is a test', 'Test', true); // => true
|
|
4114
|
+
* endsWith('this is a test', 'not'); // => false
|
|
4115
|
+
* ```
|
|
4116
|
+
*/
|
|
4117
|
+
function endsWith(haystack, needle, ignoreCase) {
|
|
4118
|
+
return match(STRING_MATCH_ENDS_WITH, haystack, needle, ignoreCase === true);
|
|
4119
|
+
}
|
|
4120
|
+
/**
|
|
4121
|
+
* Check if a string includes a specified substring
|
|
4122
|
+
*
|
|
4123
|
+
* @param haystack String to look in
|
|
4124
|
+
* @param needle String to look for
|
|
4125
|
+
* @param ignoreCase Ignore case when matching? _(defaults to `false`)_
|
|
4126
|
+
* @returns `true` if the string includes the given substring, otherwise `false`
|
|
4127
|
+
*
|
|
4128
|
+
* @example
|
|
4129
|
+
* ```typescript
|
|
4130
|
+
* includes('this is a test', 'is'); // => true
|
|
4131
|
+
* includes('this is a test', 'Is'); // => false
|
|
4132
|
+
* includes('this is a test', 'Is', true); // => true
|
|
4133
|
+
* includes('this is a test', 'not'); // => false
|
|
4134
|
+
* ```
|
|
4135
|
+
*/
|
|
4136
|
+
function includes(haystack, needle, ignoreCase) {
|
|
4137
|
+
return match(STRING_MATCH_INCLUDES, haystack, needle, ignoreCase === true);
|
|
4138
|
+
}
|
|
4139
|
+
function match(type, haystack, needle, ignoreCase) {
|
|
4140
|
+
if (typeof haystack !== "string" || typeof needle !== "string") return false;
|
|
4141
|
+
matchMemoizers[type] ??= memoize(matchCallback.bind(type));
|
|
4142
|
+
return matchMemoizers[type].run(haystack, needle, ignoreCase);
|
|
4143
|
+
}
|
|
4144
|
+
function matchCallback(haystack, needle, ignoreCase) {
|
|
4145
|
+
return (ignoreCase ? haystack.toLocaleLowerCase() : haystack)[this](ignoreCase ? needle.toLocaleLowerCase() : needle);
|
|
4146
|
+
}
|
|
4147
|
+
/**
|
|
4148
|
+
* Check if a string starts with a specified substring
|
|
4149
|
+
*
|
|
4150
|
+
* @param haystack String to look in
|
|
4151
|
+
* @param needle String to look for
|
|
4152
|
+
* @param ignoreCase Ignore case when matching? _(defaults to `false`)_
|
|
4153
|
+
* @returns `true` if the string starts with the given substring, otherwise `false`
|
|
4154
|
+
*
|
|
4155
|
+
* @example
|
|
4156
|
+
* ```typescript
|
|
4157
|
+
* startsWith('this is a test', 'this'); // => true
|
|
4158
|
+
* startsWith('this is a test', 'This'); // => false
|
|
4159
|
+
* startsWith('this is a test', 'This', true); // => true
|
|
4160
|
+
* startsWith('this is a test', 'not'); // => false
|
|
4161
|
+
* ```
|
|
4162
|
+
*/
|
|
4163
|
+
function startsWith(haystack, needle, ignoreCase) {
|
|
4164
|
+
return match(STRING_MATCH_STARTS_WITH, haystack, needle, ignoreCase === true);
|
|
4165
|
+
}
|
|
4166
|
+
const matchMemoizers = {};
|
|
4167
|
+
//#endregion
|
|
3894
4168
|
//#region src/models/string/string.normalize.model.ts
|
|
3895
4169
|
const NORMALIZE_DEBURR_CHARACTERS = {
|
|
3896
4170
|
Æ: "AE",
|
|
@@ -5929,6 +6203,14 @@ function getHexaColor$1() {
|
|
|
5929
6203
|
* @param value Value to normalize
|
|
5930
6204
|
* @param alpha Include alpha channel _(opacity)_? _(defaults to `false`)_
|
|
5931
6205
|
* @returns Normalized hex color
|
|
6206
|
+
*
|
|
6207
|
+
* @example
|
|
6208
|
+
* ```typescript
|
|
6209
|
+
* getNormalizedHex('#abc'); // => '#aabbcc'
|
|
6210
|
+
* getNormalizedHex('#abc', true); // => '#aabbccff'
|
|
6211
|
+
* getNormalizedHex(123); // => '#000000'
|
|
6212
|
+
* getNormalizedHex(123, true); // => '#000000ff'
|
|
6213
|
+
* ```
|
|
5932
6214
|
*/
|
|
5933
6215
|
function getNormalizedHex(value, alpha) {
|
|
5934
6216
|
const includeAlpha = alpha === true;
|
|
@@ -6703,12 +6985,24 @@ function getTimeLoggerStop() {
|
|
|
6703
6985
|
}
|
|
6704
6986
|
return noop;
|
|
6705
6987
|
}
|
|
6988
|
+
/**
|
|
6989
|
+
* Is the value a _Logger_?
|
|
6990
|
+
*
|
|
6991
|
+
* @param value Value to check
|
|
6992
|
+
* @returns `true` if the value is a _Logger_, otherwise `false`
|
|
6993
|
+
*/
|
|
6706
6994
|
function isLogger(value) {
|
|
6707
6995
|
return isLoggerInstance(LOGGER_NAME, value);
|
|
6708
6996
|
}
|
|
6709
6997
|
function isLoggerInstance(name, value) {
|
|
6710
6998
|
return typeof value === "object" && value !== null && "$logger" in value && value["$logger"] === name;
|
|
6711
6999
|
}
|
|
7000
|
+
/**
|
|
7001
|
+
* Is the value a _TimeLogger_?
|
|
7002
|
+
*
|
|
7003
|
+
* @param value Value to check
|
|
7004
|
+
* @returns `true` if the value is a _TimeLogger_, otherwise `false`
|
|
7005
|
+
*/
|
|
6712
7006
|
function isTimeLogger(value) {
|
|
6713
7007
|
return isLoggerInstance(LOGGER_NAME_TIMED, value);
|
|
6714
7008
|
}
|
|
@@ -6734,6 +7028,13 @@ function average(array, key) {
|
|
|
6734
7028
|
* @param value Number to round up
|
|
6735
7029
|
* @param decimals Number of decimal places to round to _(defaults to `0`)_
|
|
6736
7030
|
* @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
|
|
7031
|
+
*
|
|
7032
|
+
* @example
|
|
7033
|
+
* ```typescript
|
|
7034
|
+
* ceil(1.234, 2); // => 1.24
|
|
7035
|
+
* ceil(1.234); // => 2
|
|
7036
|
+
* ceil('abc'); // => Number.NaN
|
|
7037
|
+
* ```
|
|
6737
7038
|
*/
|
|
6738
7039
|
function ceil(value, decimals) {
|
|
6739
7040
|
return roundNumber(Math.ceil, value, decimals);
|
|
@@ -7353,4 +7654,4 @@ var SizedSet = class extends Set {
|
|
|
7353
7654
|
}
|
|
7354
7655
|
};
|
|
7355
7656
|
//#endregion
|
|
7356
|
-
export { CancelablePromise, Logger, PromiseTimeoutError, RetryError, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, SizedMap, SizedSet, push as append, push, assert, assertCondition, assertDefined, assertInstanceOf, assertIs, assertProperty, assign, asyncAttempt, asyncAttemptRun, asyncDebounce, asyncFail, asyncFlow, asyncMatchResult, asyncOnce, asyncPipe, asyncRun, asyncSucceed, asyncThrottle, asyncUse, attempt, attemptAsyncFlow, attemptAsyncPipe, attemptFlow, attemptPipe, attemptPromise, attemptRun, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, copy, count, debounce, deburr, dedent, delay, deregisterCloner, deregisterComparator, deregisterEqualizer, diff, difference, drop, endsWith, endsWithArray, equal, error, exclude, exists, fail, filter, filterAndMap, filterAndMap as select, find, findLast, first, firstOrDefault, flatFreeze, flatten, floor, flow, freeze, fromQuery, toPromise as fromResult, toPromise, fuzzy, fuzzyMatch, getArray, getArrayComparison, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getHwbColor, getHwbaColor, getNormalizedHex, getNumber, getRandom, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloatingNumber as getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getSortedIndex, getString, getTimedPromise, getUuid, getValue, groupArraysBy, groupBy, handleResult, hasValue, hasValueResult, herald, hexToHsl, hexToHsla, hexToHwb, hexToHwba, hexToRgb, hexToRgba, hslToHex, hslToHwb, hslToHwba, hslToRgb, hslToRgba, hwbToHex, hwbToHsl, hwbToHsla, hwbToRgb, hwbToRgba, ignoreKey, inMap, inSet, includes, includesArray, indexOf, indexOfArray, initializeAssigner, initializeCloner, initializeEqualizer, initializeMerger, initializeNormalizer, initializeSorter, initializeTemplater, initializeTransformer, insert, interpolate, intersection, isArrayOrPlainObject, isAsyncFailure, isAsyncGenerator, isAsyncGeneratorFunction, isAsyncOnce, isAsyncPlan, isAsyncStep, isAsyncSuccess, isBeacon, isBeaconSubscription, isColor, isConstructor, isEmpty, isError, isFailure, isFrozen, isFulfilled, isFuzzy, isGenerator, isGeneratorFunction, isHerald, isHeraldEvents, isHeraldSubscription, isHexColor, isHslColor, isHslaColor, isHwbColor, isHwbaColor, isInstanceOf, isKey, isKeyedQueue, isLogger, isNonArrayOrPlainObject, isNonConstructor, isNonEmpty, isNonInstanceOf, isNonKey, isNonNullable, isNonNullableOrEmpty, isNonNullableOrWhitespace, isNonNumber, isNonNumerical, isNonObject, isNonPlainObject, isNonPrimitive, isNonTemplateStringsArray, isNonTypedArray, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isObservable, isOk, isOnce, isPlainObject, isPlan, isPrimitive, isQueue,
|
|
7657
|
+
export { CancelablePromise, Logger, PromiseTimeoutError, RetryError, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, SizedMap, SizedSet, push as append, push, assert, assertCondition, assertDefined, assertInstanceOf, assertIs, assertProperty, assign, asyncAttempt, asyncAttemptRun, asyncDebounce, asyncFail, asyncFlow, asyncMatchResult, asyncOnce, asyncPipe, asyncRun, asyncSucceed, asyncThrottle, asyncUse, attempt, attemptAsyncFlow, attemptAsyncPipe, attemptFlow, attemptPipe, attemptPromise, attemptRun, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, copy, count, debounce, deburr, dedent, delay, deregisterCloner, deregisterComparator, deregisterEqualizer, diff, difference, drop, endsWith, endsWithArray, equal, error, exclude, exists, fail, filter, filterAndFlatMap, filterAndMap, filterAndMap as select, find, findLast, first, firstOrDefault, flatFreeze, flatMapAndFilter, flatten, floor, flow, freeze, fromQuery, toPromise as fromResult, toPromise, fuzzy, fuzzyMatch, getArray, getArrayComparison, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getHwbColor, getHwbaColor, getNormalizedHex, getNumber, getRandom, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloatingNumber as getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getSortedIndex, getString, getTimedPromise, getUuid, getValue, groupArraysBy, groupBy, handleResult, hasValue, hasValueResult, herald, hexToHsl, hexToHsla, hexToHwb, hexToHwba, hexToRgb, hexToRgba, hslToHex, hslToHwb, hslToHwba, hslToRgb, hslToRgba, hwbToHex, hwbToHsl, hwbToHsla, hwbToRgb, hwbToRgba, ignoreKey, inMap, inSet, includes, includesArray, indexOf, indexOfArray, initializeAssigner, initializeCloner, initializeEqualizer, initializeMerger, initializeNormalizer, initializeSorter, initializeTemplater, initializeTransformer, insert, interpolate, intersection, isArrayOrPlainObject, isAsyncFailure, isAsyncGenerator, isAsyncGeneratorFunction, isAsyncOnce, isAsyncPlan, isAsyncStep, isAsyncSuccess, isBeacon, isBeaconSubscription, isColor, isConstructor, isEmpty, isError, isFailure, isFrozen, isFulfilled, isFuzzy, isGenerator, isGeneratorFunction, isHerald, isHeraldEvents, isHeraldSubscription, isHexColor, isHslColor, isHslaColor, isHwbColor, isHwbaColor, isInstanceOf, isKey, isKeyedQueue, isLogger, isNonArrayOrPlainObject, isNonConstructor, isNonEmpty, isNonInstanceOf, isNonKey, isNonNullable, isNonNullableOrEmpty, isNonNullableOrWhitespace, isNonNumber, isNonNumerical, isNonObject, isNonPlainObject, isNonPrimitive, isNonTemplateStringsArray, isNonTypedArray, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isObservable, isOk, isOnce, isPlainObject, isPlan, isPrimitive, isQueue, isRejected, isResult, isRgbColor, isRgbaColor, isSorted, isStep, isSubscription, isSubscriptions, isSuccess, isTemplateStringsArray, isTimeLogger, isTypedArray, join, kebabCase, keyedQueue, last, lastIndexOf, lastOrDefault, lowerCase, mapAndFilter, mapAndFilter as reverseSelect, matchResult, max, median, memoize, merge, min, move, moveIndices, moveToIndex, noop, normalize, ok, omit, once, parse, partition, pascalCase, pick, pipe, plan, promises, queue, range, registerCloner, registerComparator, registerEqualizer, resultPromises, retry, reverse, rgbToHex, rgbToHsl, rgbToHsla, rgbToHwb, rgbToHwba, round, run, setValue, settlePromise, shake, shuffle, single, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, subscriptions, succeed, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toMapArrays, toQuery, toRecord, toRecordArrays, toResult, toSet, toggle, transform, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, use, words };
|