@oscarpalmer/atoms 0.129.0 → 0.130.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/atoms.full.js +76 -35
- package/dist/internal/value/compare.js +12 -1
- package/dist/internal/value/equal.js +7 -14
- package/dist/internal/value/handlers.js +47 -0
- package/dist/string/case.js +3 -3
- package/dist/string/misc.js +3 -3
- package/dist/value/clone.js +11 -16
- package/package.json +2 -2
- package/src/internal/value/compare.ts +37 -4
- package/src/internal/value/equal.ts +24 -36
- package/src/internal/value/handlers.ts +87 -0
- package/src/string/case.ts +3 -3
- package/src/string/misc.ts +3 -3
- package/src/value/clone.ts +17 -42
- package/types/internal/value/compare.d.ts +10 -0
- package/types/internal/value/equal.d.ts +14 -7
- package/types/internal/value/handlers.d.ts +16 -0
- package/types/value/clone.d.ts +6 -3
package/dist/atoms.full.js
CHANGED
|
@@ -325,6 +325,51 @@ function words(value) {
|
|
|
325
325
|
}
|
|
326
326
|
const EXPRESSION_IGNORED = /(^|\.)(__proto__|constructor|prototype)(\.|$)/i;
|
|
327
327
|
const EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
|
|
328
|
+
function getCompareHandlers(owner, options) {
|
|
329
|
+
const { get, register, unregister } = getHandlers(owner, options);
|
|
330
|
+
return {
|
|
331
|
+
register,
|
|
332
|
+
unregister,
|
|
333
|
+
handle(first, second, ...parameters) {
|
|
334
|
+
const handler = get(first, second);
|
|
335
|
+
if (handler == null) return options.callback(first, second, ...parameters);
|
|
336
|
+
return typeof handler === "function" ? handler(first, second) : first[handler](second);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function getHandlers(owner, options) {
|
|
341
|
+
const handlers = /* @__PURE__ */ new WeakMap();
|
|
342
|
+
return {
|
|
343
|
+
get(first, second) {
|
|
344
|
+
if (isConstructable(first) && isConstructable(second) && first.constructor === second.constructor) return handlers.get(first.constructor);
|
|
345
|
+
},
|
|
346
|
+
register(constructor, handler) {
|
|
347
|
+
if (!isConstructor(constructor) || handler === owner) return;
|
|
348
|
+
let actual = handler ?? options.method;
|
|
349
|
+
if (typeof actual !== "function" && typeof actual !== "string") return;
|
|
350
|
+
if (typeof actual === "string") actual = typeof constructor.prototype[actual] === "function" ? actual : void 0;
|
|
351
|
+
if (actual != null) handlers.set(constructor, actual);
|
|
352
|
+
},
|
|
353
|
+
unregister(constructor) {
|
|
354
|
+
handlers.delete(constructor);
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function getSelfHandlers(owner, options) {
|
|
359
|
+
const { get, register, unregister } = getHandlers(owner, options);
|
|
360
|
+
return {
|
|
361
|
+
register,
|
|
362
|
+
unregister,
|
|
363
|
+
handle(value, ...parameters) {
|
|
364
|
+
const handler = get(value, value);
|
|
365
|
+
if (handler == null) return options.callback(value, ...parameters);
|
|
366
|
+
return typeof handler === "function" ? handler(value) : value[handler]();
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function isConstructable(value) {
|
|
371
|
+
return typeof value === "object" && value !== null;
|
|
372
|
+
}
|
|
328
373
|
function compare(first, second) {
|
|
329
374
|
if (Object.is(first, second)) return 0;
|
|
330
375
|
if (first == null) return -1;
|
|
@@ -347,6 +392,16 @@ function compare(first, second) {
|
|
|
347
392
|
}
|
|
348
393
|
return 0;
|
|
349
394
|
}
|
|
395
|
+
compare.handlers = getCompareHandlers(compare, {
|
|
396
|
+
callback: (first, second, compareStrings) => {
|
|
397
|
+
if (compareStrings) return getString(first).localeCompare(getString(second));
|
|
398
|
+
},
|
|
399
|
+
method: "compare"
|
|
400
|
+
});
|
|
401
|
+
compare.register = function(constructor, handler) {
|
|
402
|
+
compare.handlers.register(constructor, handler);
|
|
403
|
+
};
|
|
404
|
+
compare.unregister = compare.handlers.unregister;
|
|
350
405
|
function compareNumbers(first, second) {
|
|
351
406
|
const firstNumber = Number(first);
|
|
352
407
|
const secondNumber = Number(second);
|
|
@@ -360,7 +415,7 @@ function compareValue(first, second, compareStrings) {
|
|
|
360
415
|
const firstType = typeof first;
|
|
361
416
|
if (firstType === typeof second && firstType in comparators) return comparators[firstType](first, second);
|
|
362
417
|
if (first instanceof Date && second instanceof Date) return compareNumbers(first.getTime(), second.getTime());
|
|
363
|
-
|
|
418
|
+
return compare.handlers.handle(first, second, compareStrings);
|
|
364
419
|
}
|
|
365
420
|
function getComparisonParts(value) {
|
|
366
421
|
if (Array.isArray(value)) return value;
|
|
@@ -1626,12 +1681,12 @@ function titleCase(value) {
|
|
|
1626
1681
|
return memoizedTitleCase.run(value);
|
|
1627
1682
|
}
|
|
1628
1683
|
function toCase(type, value, capitalizeAny, capitalizeFirst) {
|
|
1629
|
-
|
|
1684
|
+
caseMemoizers[type] ??= memoize(toCaseCallback.bind({
|
|
1630
1685
|
type,
|
|
1631
1686
|
capitalizeAny,
|
|
1632
1687
|
capitalizeFirst
|
|
1633
1688
|
}));
|
|
1634
|
-
return
|
|
1689
|
+
return caseMemoizers[type].run(value);
|
|
1635
1690
|
}
|
|
1636
1691
|
function toCaseCallback(value) {
|
|
1637
1692
|
if (typeof value !== "string") return "";
|
|
@@ -1667,7 +1722,7 @@ const delimiters = {
|
|
|
1667
1722
|
};
|
|
1668
1723
|
const EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
|
|
1669
1724
|
const EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
|
|
1670
|
-
const
|
|
1725
|
+
const caseMemoizers = {};
|
|
1671
1726
|
const REPLACEMENT_CAMEL_CASE = "$1-$2";
|
|
1672
1727
|
let memoizedCapitalize;
|
|
1673
1728
|
let memoizedTitleCase;
|
|
@@ -1696,8 +1751,8 @@ function includes(haystack, needle, ignoreCase) {
|
|
|
1696
1751
|
}
|
|
1697
1752
|
function match(type, haystack, needle, ignoreCase) {
|
|
1698
1753
|
if (typeof haystack !== "string" || typeof needle !== "string") return false;
|
|
1699
|
-
|
|
1700
|
-
return
|
|
1754
|
+
matchMemoizers[type] ??= memoize(matchCallback.bind(type));
|
|
1755
|
+
return matchMemoizers[type].run(haystack, needle, ignoreCase);
|
|
1701
1756
|
}
|
|
1702
1757
|
function matchCallback(haystack, needle, ignoreCase) {
|
|
1703
1758
|
return (ignoreCase ? haystack.toLocaleLowerCase() : haystack)[this](ignoreCase ? needle.toLocaleLowerCase() : needle);
|
|
@@ -1724,7 +1779,7 @@ function truncate(value, length, suffix) {
|
|
|
1724
1779
|
const truncatedLength = length - actualSuffixLength;
|
|
1725
1780
|
return `${value.slice(0, truncatedLength)}${actualSuffix}`;
|
|
1726
1781
|
}
|
|
1727
|
-
const
|
|
1782
|
+
const matchMemoizers = {};
|
|
1728
1783
|
function getValue(data, path, ignoreCase) {
|
|
1729
1784
|
if (typeof data !== "object" || data === null || typeof path !== "string" || path.trim().length === 0) return;
|
|
1730
1785
|
const shouldIgnoreCase = ignoreCase === true;
|
|
@@ -1807,11 +1862,6 @@ function equalMap(first, second, options) {
|
|
|
1807
1862
|
}
|
|
1808
1863
|
return true;
|
|
1809
1864
|
}
|
|
1810
|
-
function equalObject(first, second) {
|
|
1811
|
-
const comparison = comparisons.get(first.constructor);
|
|
1812
|
-
if (comparison == null) return Object.is(first, second);
|
|
1813
|
-
return second instanceof first.constructor && comparison(first, second);
|
|
1814
|
-
}
|
|
1815
1865
|
function equalPlainObject(first, second, options) {
|
|
1816
1866
|
let firstKeys = [...Object.keys(first), ...Object.getOwnPropertySymbols(first)];
|
|
1817
1867
|
let secondKeys = [...Object.keys(second), ...Object.getOwnPropertySymbols(second)];
|
|
@@ -1870,10 +1920,10 @@ function equalValue(first, second, options) {
|
|
|
1870
1920
|
case Array.isArray(first) && Array.isArray(second): return equalArray(first, second, options);
|
|
1871
1921
|
case isPlainObject(first) && isPlainObject(second): return equalPlainObject(first, second, options);
|
|
1872
1922
|
case isTypedArray(first) && isTypedArray(second): return equalTypedArray(first, second);
|
|
1873
|
-
|
|
1874
|
-
default: return Object.is(first, second);
|
|
1923
|
+
default: return equal.handlers.handle(first, second, options);
|
|
1875
1924
|
}
|
|
1876
1925
|
}
|
|
1926
|
+
equal.handlers = getCompareHandlers(equal, { callback: Object.is });
|
|
1877
1927
|
equal.initialize = function(options) {
|
|
1878
1928
|
const actual = getEqualOptions(options);
|
|
1879
1929
|
const equalizer = (first, second) => equalValue(first, second, actual);
|
|
@@ -1881,12 +1931,10 @@ equal.initialize = function(options) {
|
|
|
1881
1931
|
equalizer.unregister = equal.unregister;
|
|
1882
1932
|
return equalizer;
|
|
1883
1933
|
};
|
|
1884
|
-
equal.register = function(constructor,
|
|
1885
|
-
|
|
1886
|
-
};
|
|
1887
|
-
equal.unregister = function(constructor) {
|
|
1888
|
-
if (isConstructor(constructor)) comparisons.delete(constructor);
|
|
1934
|
+
equal.register = function(constructor, fn) {
|
|
1935
|
+
equal.handlers.register(constructor, fn);
|
|
1889
1936
|
};
|
|
1937
|
+
equal.unregister = equal.handlers.unregister;
|
|
1890
1938
|
function filterKey(key, options) {
|
|
1891
1939
|
if (typeof key !== "string") return true;
|
|
1892
1940
|
if (options.ignoreExpressions.enabled && options.ignoreExpressions.values.some((expression) => expression.test(key))) return false;
|
|
@@ -1921,18 +1969,17 @@ function getEqualOptions(input) {
|
|
|
1921
1969
|
}
|
|
1922
1970
|
const ARRAY_PEEK_PERCENTAGE = 10;
|
|
1923
1971
|
const ARRAY_THRESHOLD = 100;
|
|
1924
|
-
const comparisons = /* @__PURE__ */ new WeakMap();
|
|
1925
1972
|
function clone(value) {
|
|
1926
1973
|
return cloneValue(value, 0, /* @__PURE__ */ new WeakMap());
|
|
1927
1974
|
}
|
|
1928
|
-
clone.
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
clone.
|
|
1934
|
-
if (isConstructor(constructor)) cloners.delete(constructor);
|
|
1975
|
+
clone.handlers = getSelfHandlers(clone, {
|
|
1976
|
+
callback: tryStructuredClone,
|
|
1977
|
+
method: "clone"
|
|
1978
|
+
});
|
|
1979
|
+
clone.register = function(constructor, handler) {
|
|
1980
|
+
clone.handlers.register(constructor, handler);
|
|
1935
1981
|
};
|
|
1982
|
+
clone.unregister = clone.handlers.unregister;
|
|
1936
1983
|
function cloneArrayBuffer(value, depth, references) {
|
|
1937
1984
|
if (typeof depth === "number" && depth >= MAX_CLONE_DEPTH) return value;
|
|
1938
1985
|
const cloned = new ArrayBuffer(value.byteLength);
|
|
@@ -1967,12 +2014,6 @@ function cloneNode(node, depth, references) {
|
|
|
1967
2014
|
references.set(node, cloned);
|
|
1968
2015
|
return cloned;
|
|
1969
2016
|
}
|
|
1970
|
-
function cloneObject(value, depth, references) {
|
|
1971
|
-
const cloner = cloners.get(value.constructor);
|
|
1972
|
-
if (typeof cloner === "function") return cloner(value);
|
|
1973
|
-
if (cloner == null) return tryStructuredClone(value, depth, references);
|
|
1974
|
-
return value[cloner]();
|
|
1975
|
-
}
|
|
1976
2017
|
function clonePlainObject(value, depth, references) {
|
|
1977
2018
|
if (depth >= MAX_CLONE_DEPTH) return Array.isArray(value) ? [...value] : { ...value };
|
|
1978
2019
|
const cloned = Array.isArray(value) ? [] : {};
|
|
@@ -2010,13 +2051,14 @@ function cloneValue(value, depth, references) {
|
|
|
2010
2051
|
case references.has(value): return references.get(value);
|
|
2011
2052
|
case value instanceof ArrayBuffer: return cloneArrayBuffer(value, depth, references);
|
|
2012
2053
|
case value instanceof DataView: return cloneDataView(value, depth, references);
|
|
2054
|
+
case value instanceof Date: return new Date(value.getTime());
|
|
2013
2055
|
case value instanceof RegExp: return cloneRegularExpression(value, depth, references);
|
|
2014
2056
|
case value instanceof Map:
|
|
2015
2057
|
case value instanceof Set: return cloneMapOrSet(value, depth, references);
|
|
2016
2058
|
case value instanceof Node: return cloneNode(value, depth, references);
|
|
2017
2059
|
case isArrayOrPlainObject(value): return clonePlainObject(value, depth, references);
|
|
2018
2060
|
case isTypedArray(value): return cloneTypedArray(value, depth, references);
|
|
2019
|
-
default: return
|
|
2061
|
+
default: return clone.handlers.handle(value, depth, references);
|
|
2020
2062
|
}
|
|
2021
2063
|
}
|
|
2022
2064
|
function tryStructuredClone(value, depth, references) {
|
|
@@ -2030,7 +2072,6 @@ function tryStructuredClone(value, depth, references) {
|
|
|
2030
2072
|
return value;
|
|
2031
2073
|
}
|
|
2032
2074
|
}
|
|
2033
|
-
const cloners = /* @__PURE__ */ new WeakMap();
|
|
2034
2075
|
const MAX_CLONE_DEPTH = 100;
|
|
2035
2076
|
function diff(first, second, options) {
|
|
2036
2077
|
const relaxedNullish = typeof options === "object" && options?.relaxedNullish === true;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { max } from "../math/aggregate.js";
|
|
2
2
|
import { getString, words } from "../string.js";
|
|
3
|
+
import { getCompareHandlers } from "./handlers.js";
|
|
3
4
|
function compare(first, second) {
|
|
4
5
|
if (Object.is(first, second)) return 0;
|
|
5
6
|
if (first == null) return -1;
|
|
@@ -22,6 +23,16 @@ function compare(first, second) {
|
|
|
22
23
|
}
|
|
23
24
|
return 0;
|
|
24
25
|
}
|
|
26
|
+
compare.handlers = getCompareHandlers(compare, {
|
|
27
|
+
callback: (first, second, compareStrings) => {
|
|
28
|
+
if (compareStrings) return getString(first).localeCompare(getString(second));
|
|
29
|
+
},
|
|
30
|
+
method: "compare"
|
|
31
|
+
});
|
|
32
|
+
compare.register = function(constructor, handler) {
|
|
33
|
+
compare.handlers.register(constructor, handler);
|
|
34
|
+
};
|
|
35
|
+
compare.unregister = compare.handlers.unregister;
|
|
25
36
|
function compareNumbers(first, second) {
|
|
26
37
|
const firstNumber = Number(first);
|
|
27
38
|
const secondNumber = Number(second);
|
|
@@ -35,7 +46,7 @@ function compareValue(first, second, compareStrings) {
|
|
|
35
46
|
const firstType = typeof first;
|
|
36
47
|
if (firstType === typeof second && firstType in comparators) return comparators[firstType](first, second);
|
|
37
48
|
if (first instanceof Date && second instanceof Date) return compareNumbers(first.getTime(), second.getTime());
|
|
38
|
-
|
|
49
|
+
return compare.handlers.handle(first, second, compareStrings);
|
|
39
50
|
}
|
|
40
51
|
function getComparisonParts(value) {
|
|
41
52
|
if (Array.isArray(value)) return value;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isPlainObject, isTypedArray } from "../is.js";
|
|
2
2
|
import { chunk } from "../array/chunk.js";
|
|
3
|
+
import { getCompareHandlers } from "./handlers.js";
|
|
3
4
|
function equal(first, second, options) {
|
|
4
5
|
return equalValue(first, second, getEqualOptions(options));
|
|
5
6
|
}
|
|
@@ -41,11 +42,6 @@ function equalMap(first, second, options) {
|
|
|
41
42
|
}
|
|
42
43
|
return true;
|
|
43
44
|
}
|
|
44
|
-
function equalObject(first, second) {
|
|
45
|
-
const comparison = comparisons.get(first.constructor);
|
|
46
|
-
if (comparison == null) return Object.is(first, second);
|
|
47
|
-
return second instanceof first.constructor && comparison(first, second);
|
|
48
|
-
}
|
|
49
45
|
function equalPlainObject(first, second, options) {
|
|
50
46
|
let firstKeys = [...Object.keys(first), ...Object.getOwnPropertySymbols(first)];
|
|
51
47
|
let secondKeys = [...Object.keys(second), ...Object.getOwnPropertySymbols(second)];
|
|
@@ -104,10 +100,10 @@ function equalValue(first, second, options) {
|
|
|
104
100
|
case Array.isArray(first) && Array.isArray(second): return equalArray(first, second, options);
|
|
105
101
|
case isPlainObject(first) && isPlainObject(second): return equalPlainObject(first, second, options);
|
|
106
102
|
case isTypedArray(first) && isTypedArray(second): return equalTypedArray(first, second);
|
|
107
|
-
|
|
108
|
-
default: return Object.is(first, second);
|
|
103
|
+
default: return equal.handlers.handle(first, second, options);
|
|
109
104
|
}
|
|
110
105
|
}
|
|
106
|
+
equal.handlers = getCompareHandlers(equal, { callback: Object.is });
|
|
111
107
|
equal.initialize = function(options) {
|
|
112
108
|
const actual = getEqualOptions(options);
|
|
113
109
|
const equalizer = (first, second) => equalValue(first, second, actual);
|
|
@@ -115,12 +111,10 @@ equal.initialize = function(options) {
|
|
|
115
111
|
equalizer.unregister = equal.unregister;
|
|
116
112
|
return equalizer;
|
|
117
113
|
};
|
|
118
|
-
equal.register = function(constructor,
|
|
119
|
-
|
|
120
|
-
};
|
|
121
|
-
equal.unregister = function(constructor) {
|
|
122
|
-
if (isConstructor(constructor)) comparisons.delete(constructor);
|
|
114
|
+
equal.register = function(constructor, fn) {
|
|
115
|
+
equal.handlers.register(constructor, fn);
|
|
123
116
|
};
|
|
117
|
+
equal.unregister = equal.handlers.unregister;
|
|
124
118
|
function filterKey(key, options) {
|
|
125
119
|
if (typeof key !== "string") return true;
|
|
126
120
|
if (options.ignoreExpressions.enabled && options.ignoreExpressions.values.some((expression) => expression.test(key))) return false;
|
|
@@ -155,5 +149,4 @@ function getEqualOptions(input) {
|
|
|
155
149
|
}
|
|
156
150
|
var ARRAY_PEEK_PERCENTAGE = 10;
|
|
157
151
|
var ARRAY_THRESHOLD = 100;
|
|
158
|
-
var comparisons = /* @__PURE__ */ new WeakMap();
|
|
159
152
|
export { equal };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { isConstructor } from "../is.js";
|
|
2
|
+
function getCompareHandlers(owner, options) {
|
|
3
|
+
const { get, register, unregister } = getHandlers(owner, options);
|
|
4
|
+
return {
|
|
5
|
+
register,
|
|
6
|
+
unregister,
|
|
7
|
+
handle(first, second, ...parameters) {
|
|
8
|
+
const handler = get(first, second);
|
|
9
|
+
if (handler == null) return options.callback(first, second, ...parameters);
|
|
10
|
+
return typeof handler === "function" ? handler(first, second) : first[handler](second);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function getHandlers(owner, options) {
|
|
15
|
+
const handlers = /* @__PURE__ */ new WeakMap();
|
|
16
|
+
return {
|
|
17
|
+
get(first, second) {
|
|
18
|
+
if (isConstructable(first) && isConstructable(second) && first.constructor === second.constructor) return handlers.get(first.constructor);
|
|
19
|
+
},
|
|
20
|
+
register(constructor, handler) {
|
|
21
|
+
if (!isConstructor(constructor) || handler === owner) return;
|
|
22
|
+
let actual = handler ?? options.method;
|
|
23
|
+
if (typeof actual !== "function" && typeof actual !== "string") return;
|
|
24
|
+
if (typeof actual === "string") actual = typeof constructor.prototype[actual] === "function" ? actual : void 0;
|
|
25
|
+
if (actual != null) handlers.set(constructor, actual);
|
|
26
|
+
},
|
|
27
|
+
unregister(constructor) {
|
|
28
|
+
handlers.delete(constructor);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function getSelfHandlers(owner, options) {
|
|
33
|
+
const { get, register, unregister } = getHandlers(owner, options);
|
|
34
|
+
return {
|
|
35
|
+
register,
|
|
36
|
+
unregister,
|
|
37
|
+
handle(value, ...parameters) {
|
|
38
|
+
const handler = get(value, value);
|
|
39
|
+
if (handler == null) return options.callback(value, ...parameters);
|
|
40
|
+
return typeof handler === "function" ? handler(value) : value[handler]();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function isConstructable(value) {
|
|
45
|
+
return typeof value === "object" && value !== null;
|
|
46
|
+
}
|
|
47
|
+
export { getCompareHandlers, getSelfHandlers };
|
package/dist/string/case.js
CHANGED
|
@@ -26,12 +26,12 @@ function titleCase(value) {
|
|
|
26
26
|
return memoizedTitleCase.run(value);
|
|
27
27
|
}
|
|
28
28
|
function toCase(type, value, capitalizeAny, capitalizeFirst) {
|
|
29
|
-
|
|
29
|
+
caseMemoizers[type] ??= memoize(toCaseCallback.bind({
|
|
30
30
|
type,
|
|
31
31
|
capitalizeAny,
|
|
32
32
|
capitalizeFirst
|
|
33
33
|
}));
|
|
34
|
-
return
|
|
34
|
+
return caseMemoizers[type].run(value);
|
|
35
35
|
}
|
|
36
36
|
function toCaseCallback(value) {
|
|
37
37
|
if (typeof value !== "string") return "";
|
|
@@ -67,7 +67,7 @@ var delimiters = {
|
|
|
67
67
|
};
|
|
68
68
|
var EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
|
|
69
69
|
var EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
|
|
70
|
-
var
|
|
70
|
+
var caseMemoizers = {};
|
|
71
71
|
var REPLACEMENT_CAMEL_CASE = "$1-$2";
|
|
72
72
|
var memoizedCapitalize;
|
|
73
73
|
var memoizedTitleCase;
|
package/dist/string/misc.js
CHANGED
|
@@ -24,8 +24,8 @@ function includes(haystack, needle, ignoreCase) {
|
|
|
24
24
|
}
|
|
25
25
|
function match(type, haystack, needle, ignoreCase) {
|
|
26
26
|
if (typeof haystack !== "string" || typeof needle !== "string") return false;
|
|
27
|
-
|
|
28
|
-
return
|
|
27
|
+
matchMemoizers[type] ??= memoize(matchCallback.bind(type));
|
|
28
|
+
return matchMemoizers[type].run(haystack, needle, ignoreCase);
|
|
29
29
|
}
|
|
30
30
|
function matchCallback(haystack, needle, ignoreCase) {
|
|
31
31
|
return (ignoreCase ? haystack.toLocaleLowerCase() : haystack)[this](ignoreCase ? needle.toLocaleLowerCase() : needle);
|
|
@@ -52,5 +52,5 @@ function truncate(value, length, suffix) {
|
|
|
52
52
|
const truncatedLength = length - actualSuffixLength;
|
|
53
53
|
return `${value.slice(0, truncatedLength)}${actualSuffix}`;
|
|
54
54
|
}
|
|
55
|
-
var
|
|
55
|
+
var matchMemoizers = {};
|
|
56
56
|
export { createUuid, endsWith, getUuid, includes, parse, startsWith, trim, truncate };
|
package/dist/value/clone.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { isArrayOrPlainObject,
|
|
1
|
+
import { isArrayOrPlainObject, isTypedArray } from "../internal/is.js";
|
|
2
|
+
import { getSelfHandlers } from "../internal/value/handlers.js";
|
|
2
3
|
function clone(value) {
|
|
3
4
|
return cloneValue(value, 0, /* @__PURE__ */ new WeakMap());
|
|
4
5
|
}
|
|
5
|
-
clone.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
clone.
|
|
11
|
-
if (isConstructor(constructor)) cloners.delete(constructor);
|
|
6
|
+
clone.handlers = getSelfHandlers(clone, {
|
|
7
|
+
callback: tryStructuredClone,
|
|
8
|
+
method: "clone"
|
|
9
|
+
});
|
|
10
|
+
clone.register = function(constructor, handler) {
|
|
11
|
+
clone.handlers.register(constructor, handler);
|
|
12
12
|
};
|
|
13
|
+
clone.unregister = clone.handlers.unregister;
|
|
13
14
|
function cloneArrayBuffer(value, depth, references) {
|
|
14
15
|
if (typeof depth === "number" && depth >= MAX_CLONE_DEPTH) return value;
|
|
15
16
|
const cloned = new ArrayBuffer(value.byteLength);
|
|
@@ -44,12 +45,6 @@ function cloneNode(node, depth, references) {
|
|
|
44
45
|
references.set(node, cloned);
|
|
45
46
|
return cloned;
|
|
46
47
|
}
|
|
47
|
-
function cloneObject(value, depth, references) {
|
|
48
|
-
const cloner = cloners.get(value.constructor);
|
|
49
|
-
if (typeof cloner === "function") return cloner(value);
|
|
50
|
-
if (cloner == null) return tryStructuredClone(value, depth, references);
|
|
51
|
-
return value[cloner]();
|
|
52
|
-
}
|
|
53
48
|
function clonePlainObject(value, depth, references) {
|
|
54
49
|
if (depth >= MAX_CLONE_DEPTH) return Array.isArray(value) ? [...value] : { ...value };
|
|
55
50
|
const cloned = Array.isArray(value) ? [] : {};
|
|
@@ -87,13 +82,14 @@ function cloneValue(value, depth, references) {
|
|
|
87
82
|
case references.has(value): return references.get(value);
|
|
88
83
|
case value instanceof ArrayBuffer: return cloneArrayBuffer(value, depth, references);
|
|
89
84
|
case value instanceof DataView: return cloneDataView(value, depth, references);
|
|
85
|
+
case value instanceof Date: return new Date(value.getTime());
|
|
90
86
|
case value instanceof RegExp: return cloneRegularExpression(value, depth, references);
|
|
91
87
|
case value instanceof Map:
|
|
92
88
|
case value instanceof Set: return cloneMapOrSet(value, depth, references);
|
|
93
89
|
case value instanceof Node: return cloneNode(value, depth, references);
|
|
94
90
|
case isArrayOrPlainObject(value): return clonePlainObject(value, depth, references);
|
|
95
91
|
case isTypedArray(value): return cloneTypedArray(value, depth, references);
|
|
96
|
-
default: return
|
|
92
|
+
default: return clone.handlers.handle(value, depth, references);
|
|
97
93
|
}
|
|
98
94
|
}
|
|
99
95
|
function tryStructuredClone(value, depth, references) {
|
|
@@ -107,6 +103,5 @@ function tryStructuredClone(value, depth, references) {
|
|
|
107
103
|
return value;
|
|
108
104
|
}
|
|
109
105
|
}
|
|
110
|
-
var cloners = /* @__PURE__ */ new WeakMap();
|
|
111
106
|
var MAX_CLONE_DEPTH = 100;
|
|
112
107
|
export { clone };
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"rolldown": "1.0.0-rc.1",
|
|
14
14
|
"tslib": "^2.8",
|
|
15
15
|
"typescript": "^5.9",
|
|
16
|
-
"vite": "8.0.0-beta.
|
|
16
|
+
"vite": "8.0.0-beta.10",
|
|
17
17
|
"vitest": "^4"
|
|
18
18
|
},
|
|
19
19
|
"exports": {
|
|
@@ -105,5 +105,5 @@
|
|
|
105
105
|
},
|
|
106
106
|
"type": "module",
|
|
107
107
|
"types": "./types/index.d.ts",
|
|
108
|
-
"version": "0.
|
|
108
|
+
"version": "0.130.0"
|
|
109
109
|
}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import type {Constructor} from '../../models';
|
|
1
2
|
import {max} from '../math/aggregate';
|
|
2
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
|
|
3
11
|
|
|
4
12
|
// #region Functions
|
|
5
13
|
|
|
@@ -53,6 +61,33 @@ export function compare(first: unknown, second: unknown): number {
|
|
|
53
61
|
return 0;
|
|
54
62
|
}
|
|
55
63
|
|
|
64
|
+
compare.handlers = getCompareHandlers<number>(compare, {
|
|
65
|
+
callback: (first, second, compareStrings) => {
|
|
66
|
+
if (compareStrings) {
|
|
67
|
+
return getString(first).localeCompare(getString(second));
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
method: 'compare',
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Register a custom comparison handler for a class
|
|
75
|
+
* @param constructor Class constructor
|
|
76
|
+
* @param handler Method name or comparison function _(defaults to `compare`)_
|
|
77
|
+
*/
|
|
78
|
+
compare.register = function <Instance>(
|
|
79
|
+
constructor: Constructor<Instance>,
|
|
80
|
+
handler?: string | ((first: Instance, second: Instance) => number),
|
|
81
|
+
): void {
|
|
82
|
+
compare.handlers.register(constructor, handler);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Unregister a custom comparison handler for a class
|
|
87
|
+
* @param constructor Class constructor
|
|
88
|
+
*/
|
|
89
|
+
compare.unregister = compare.handlers.unregister;
|
|
90
|
+
|
|
56
91
|
function compareNumbers(
|
|
57
92
|
first: bigint | boolean | number,
|
|
58
93
|
second: bigint | boolean | number,
|
|
@@ -89,9 +124,7 @@ function compareValue(
|
|
|
89
124
|
return compareNumbers(first.getTime(), second.getTime());
|
|
90
125
|
}
|
|
91
126
|
|
|
92
|
-
|
|
93
|
-
return getString(first).localeCompare(getString(second));
|
|
94
|
-
}
|
|
127
|
+
return compare.handlers.handle(first, second, compareStrings);
|
|
95
128
|
}
|
|
96
129
|
|
|
97
130
|
function getComparisonParts(value: unknown): unknown[] {
|
|
@@ -106,7 +139,7 @@ function getComparisonParts(value: unknown): unknown[] {
|
|
|
106
139
|
|
|
107
140
|
// #region Constants
|
|
108
141
|
|
|
109
|
-
const comparators: Record<string,
|
|
142
|
+
const comparators: Record<string, Comparator> = {
|
|
110
143
|
bigint: compareNumbers,
|
|
111
144
|
boolean: compareNumbers,
|
|
112
145
|
number: compareNumbers,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type {ArrayOrPlainObject, Constructor, PlainObject, TypedArray} from '../../models';
|
|
2
2
|
import {chunk} from '../array/chunk';
|
|
3
|
-
import {
|
|
3
|
+
import {isPlainObject, isTypedArray} from '../is';
|
|
4
|
+
import {getCompareHandlers} from './handlers';
|
|
4
5
|
|
|
5
6
|
// #region Types
|
|
6
7
|
|
|
7
|
-
type Comparison<Instance> = (first: Instance, second: Instance) => boolean;
|
|
8
|
-
|
|
9
8
|
/**
|
|
10
9
|
* Options for value equality comparison
|
|
11
10
|
*/
|
|
@@ -34,14 +33,20 @@ type Equalizer = {
|
|
|
34
33
|
(first: unknown, second: unknown): boolean;
|
|
35
34
|
|
|
36
35
|
/**
|
|
37
|
-
*
|
|
36
|
+
* Register a equality comparison handler for a specific class
|
|
37
|
+
* @param constructor Class constructor
|
|
38
|
+
* @param handler Equality comparison handler
|
|
38
39
|
*/
|
|
39
|
-
register:
|
|
40
|
+
register: <Instance>(
|
|
41
|
+
constructor: Constructor<Instance>,
|
|
42
|
+
handler?: string | ((first: Instance, second: Instance) => boolean),
|
|
43
|
+
) => void;
|
|
40
44
|
|
|
41
45
|
/**
|
|
42
|
-
*
|
|
46
|
+
* Unregister a equality comparison handler for a specific class
|
|
47
|
+
* @param constructor Class constructor
|
|
43
48
|
*/
|
|
44
|
-
unregister:
|
|
49
|
+
unregister: (constructor: Constructor) => void;
|
|
45
50
|
};
|
|
46
51
|
|
|
47
52
|
type Options = {
|
|
@@ -169,16 +174,6 @@ function equalMap(
|
|
|
169
174
|
return true;
|
|
170
175
|
}
|
|
171
176
|
|
|
172
|
-
function equalObject(first: object, second: object): boolean {
|
|
173
|
-
const comparison = comparisons.get(first.constructor as Constructor);
|
|
174
|
-
|
|
175
|
-
if (comparison == null) {
|
|
176
|
-
return Object.is(first, second);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return second instanceof first.constructor && comparison(first, second);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
177
|
function equalPlainObject(
|
|
183
178
|
first: ArrayOrPlainObject,
|
|
184
179
|
second: ArrayOrPlainObject,
|
|
@@ -317,14 +312,15 @@ function equalValue(first: unknown, second: unknown, options: Options): boolean
|
|
|
317
312
|
case isTypedArray(first) && isTypedArray(second):
|
|
318
313
|
return equalTypedArray(first as TypedArray, second as TypedArray);
|
|
319
314
|
|
|
320
|
-
case typeof first === 'object':
|
|
321
|
-
return equalObject(first, second);
|
|
322
|
-
|
|
323
315
|
default:
|
|
324
|
-
return
|
|
316
|
+
return equal.handlers.handle(first, second, options);
|
|
325
317
|
}
|
|
326
318
|
}
|
|
327
319
|
|
|
320
|
+
equal.handlers = getCompareHandlers<boolean>(equal, {
|
|
321
|
+
callback: Object.is,
|
|
322
|
+
});
|
|
323
|
+
|
|
328
324
|
/**
|
|
329
325
|
* Create an equalizer with predefined options
|
|
330
326
|
* @param options Comparison options
|
|
@@ -338,32 +334,26 @@ equal.initialize = function (options?: EqualOptions): Equalizer {
|
|
|
338
334
|
equalizer.register = equal.register;
|
|
339
335
|
equalizer.unregister = equal.unregister;
|
|
340
336
|
|
|
341
|
-
return equalizer;
|
|
337
|
+
return equalizer as Equalizer;
|
|
342
338
|
};
|
|
343
339
|
|
|
344
340
|
/**
|
|
345
|
-
* Register a
|
|
341
|
+
* Register a equality comparison function for a specific class
|
|
346
342
|
* @param constructor Class constructor
|
|
347
|
-
* @param
|
|
343
|
+
* @param fn Comparison function
|
|
348
344
|
*/
|
|
349
345
|
equal.register = function <Instance>(
|
|
350
346
|
constructor: Constructor<Instance>,
|
|
351
|
-
|
|
347
|
+
fn: (first: Instance, second: Instance) => boolean,
|
|
352
348
|
): void {
|
|
353
|
-
|
|
354
|
-
comparisons.set(constructor, comparison as Comparison<unknown>);
|
|
355
|
-
}
|
|
349
|
+
equal.handlers.register(constructor, fn);
|
|
356
350
|
};
|
|
357
351
|
|
|
358
352
|
/**
|
|
359
|
-
* Unregister a
|
|
353
|
+
* Unregister a equality comparison handler for a specific class
|
|
360
354
|
* @param constructor Class constructor
|
|
361
355
|
*/
|
|
362
|
-
equal.unregister =
|
|
363
|
-
if (isConstructor(constructor)) {
|
|
364
|
-
comparisons.delete(constructor);
|
|
365
|
-
}
|
|
366
|
-
};
|
|
356
|
+
equal.unregister = equal.handlers.unregister;
|
|
367
357
|
|
|
368
358
|
function filterKey(key: string | symbol, options: Options): boolean {
|
|
369
359
|
if (typeof key !== 'string') {
|
|
@@ -437,6 +427,4 @@ const ARRAY_PEEK_PERCENTAGE = 10;
|
|
|
437
427
|
|
|
438
428
|
const ARRAY_THRESHOLD = 100;
|
|
439
429
|
|
|
440
|
-
const comparisons = new WeakMap<Constructor, Comparison<unknown>>();
|
|
441
|
-
|
|
442
430
|
// #endregion
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type {Constructor, GenericCallback} from '../../models';
|
|
2
|
+
import {isConstructor} from '../is';
|
|
3
|
+
|
|
4
|
+
type Options = {
|
|
5
|
+
callback: GenericCallback;
|
|
6
|
+
method?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function getCompareHandlers<Value>(owner: GenericCallback, options: Options) {
|
|
10
|
+
const {get, register, unregister} = getHandlers(owner, options);
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
register,
|
|
14
|
+
unregister,
|
|
15
|
+
handle(first: unknown, second: unknown, ...parameters: unknown[]): Value {
|
|
16
|
+
const handler = get(first, second);
|
|
17
|
+
|
|
18
|
+
if (handler == null) {
|
|
19
|
+
return options.callback(first, second, ...parameters);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return typeof handler === 'function'
|
|
23
|
+
? handler(first, second)
|
|
24
|
+
: (first as any)[handler](second);
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getHandlers(owner: GenericCallback, options: Options) {
|
|
30
|
+
const handlers = new WeakMap<Constructor, string | GenericCallback>();
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
get(first: unknown, second: unknown): string | GenericCallback | undefined {
|
|
34
|
+
if (
|
|
35
|
+
isConstructable(first) &&
|
|
36
|
+
isConstructable(second) &&
|
|
37
|
+
(first as object).constructor === (second as object).constructor
|
|
38
|
+
) {
|
|
39
|
+
return handlers.get((first as object).constructor as Constructor);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
register(constructor: Constructor, handler?: string | GenericCallback) {
|
|
43
|
+
if (!isConstructor(constructor) || handler === owner) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let actual: string | GenericCallback | undefined = handler ?? options.method;
|
|
48
|
+
|
|
49
|
+
if (typeof actual !== 'function' && typeof actual !== 'string') {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (typeof actual === 'string') {
|
|
54
|
+
actual = typeof constructor.prototype[actual] === 'function' ? actual : undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (actual != null) {
|
|
58
|
+
handlers.set(constructor, actual);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
unregister(constructor: Constructor) {
|
|
62
|
+
handlers.delete(constructor);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getSelfHandlers(owner: GenericCallback, options: Options) {
|
|
68
|
+
const {get, register, unregister} = getHandlers(owner, options);
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
register,
|
|
72
|
+
unregister,
|
|
73
|
+
handle(value: unknown, ...parameters: unknown[]) {
|
|
74
|
+
const handler = get(value, value);
|
|
75
|
+
|
|
76
|
+
if (handler == null) {
|
|
77
|
+
return options.callback(value, ...parameters);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return typeof handler === 'function' ? handler(value) : (value as any)[handler]();
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function isConstructable(value: unknown): boolean {
|
|
86
|
+
return typeof value === 'object' && value !== null;
|
|
87
|
+
}
|
package/src/string/case.ts
CHANGED
|
@@ -102,9 +102,9 @@ function toCase(
|
|
|
102
102
|
capitalizeAny: boolean,
|
|
103
103
|
capitalizeFirst: boolean,
|
|
104
104
|
): string {
|
|
105
|
-
|
|
105
|
+
caseMemoizers[type] ??= memoize(toCaseCallback.bind({type, capitalizeAny, capitalizeFirst}));
|
|
106
106
|
|
|
107
|
-
return
|
|
107
|
+
return caseMemoizers[type].run(value);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
function toCaseCallback(this: Options, value: string): string {
|
|
@@ -185,7 +185,7 @@ const EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
|
|
|
185
185
|
|
|
186
186
|
const EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
|
|
187
187
|
|
|
188
|
-
const
|
|
188
|
+
const caseMemoizers: Partial<Record<string, Memoized<typeof toCaseCallback>>> = {};
|
|
189
189
|
|
|
190
190
|
const REPLACEMENT_CAMEL_CASE = '$1-$2';
|
|
191
191
|
|
package/src/string/misc.ts
CHANGED
|
@@ -68,9 +68,9 @@ function match(type: Match, haystack: string, needle: string, ignoreCase: boolea
|
|
|
68
68
|
return false;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
matchMemoizers[type] ??= memoize(matchCallback.bind(type));
|
|
72
72
|
|
|
73
|
-
return
|
|
73
|
+
return matchMemoizers[type].run(haystack, needle, ignoreCase);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
function matchCallback(
|
|
@@ -153,6 +153,6 @@ export function truncate(value: string, length: number, suffix?: string): string
|
|
|
153
153
|
|
|
154
154
|
// #region Constants
|
|
155
155
|
|
|
156
|
-
const
|
|
156
|
+
const matchMemoizers: Partial<Record<Match, Memoized<typeof matchCallback>>> = {};
|
|
157
157
|
|
|
158
158
|
// #endregion
|
package/src/value/clone.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {isArrayOrPlainObject,
|
|
1
|
+
import {isArrayOrPlainObject, isTypedArray} from '../internal/is';
|
|
2
|
+
import {getSelfHandlers} from '../internal/value/handlers';
|
|
2
3
|
import type {ArrayOrPlainObject, Constructor, PlainObject, TypedArray} from '../models';
|
|
3
4
|
|
|
4
|
-
// #region Types
|
|
5
|
-
|
|
6
|
-
type Cloner<Instance> = (original: Instance) => Instance;
|
|
7
|
-
|
|
8
|
-
// #endregion
|
|
9
|
-
|
|
10
5
|
// #region Functions
|
|
11
6
|
|
|
12
7
|
/**
|
|
@@ -20,35 +15,28 @@ export function clone(value: unknown): unknown {
|
|
|
20
15
|
return cloneValue(value, 0, new WeakMap());
|
|
21
16
|
}
|
|
22
17
|
|
|
18
|
+
clone.handlers = getSelfHandlers(clone, {
|
|
19
|
+
callback: tryStructuredClone,
|
|
20
|
+
method: 'clone',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
23
|
/**
|
|
24
|
-
* Register a
|
|
24
|
+
* Register a clone handler for a specific class
|
|
25
25
|
* @param constructor Class constructor
|
|
26
|
-
* @param
|
|
26
|
+
* @param handler Method name or clone function _(defaults to `clone`)_
|
|
27
27
|
*/
|
|
28
28
|
clone.register = function <Instance>(
|
|
29
29
|
constructor: Constructor<Instance>,
|
|
30
|
-
|
|
30
|
+
handler?: string | ((value: Instance) => Instance),
|
|
31
31
|
): void {
|
|
32
|
-
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const actual = cloner ?? 'clone';
|
|
37
|
-
|
|
38
|
-
if (typeof actual === 'function' || typeof constructor.prototype[actual] === 'function') {
|
|
39
|
-
cloners.set(constructor, actual as string | Cloner<unknown>);
|
|
40
|
-
}
|
|
32
|
+
clone.handlers.register(constructor, handler);
|
|
41
33
|
};
|
|
42
34
|
|
|
43
35
|
/**
|
|
44
|
-
* Unregister a
|
|
36
|
+
* Unregister a clone handler for a specific class
|
|
45
37
|
* @param constructor Class constructor
|
|
46
38
|
*/
|
|
47
|
-
clone.unregister =
|
|
48
|
-
if (isConstructor(constructor)) {
|
|
49
|
-
cloners.delete(constructor);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
39
|
+
clone.unregister = clone.handlers.unregister;
|
|
52
40
|
|
|
53
41
|
function cloneArrayBuffer(
|
|
54
42
|
value: ArrayBuffer,
|
|
@@ -130,20 +118,6 @@ function cloneNode(node: Node, depth: number, references: WeakMap<WeakKey, unkno
|
|
|
130
118
|
return cloned;
|
|
131
119
|
}
|
|
132
120
|
|
|
133
|
-
function cloneObject(value: object, depth: number, references: WeakMap<WeakKey, unknown>): unknown {
|
|
134
|
-
const cloner = cloners.get(value.constructor as Constructor);
|
|
135
|
-
|
|
136
|
-
if (typeof cloner === 'function') {
|
|
137
|
-
return cloner(value);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (cloner == null) {
|
|
141
|
-
return tryStructuredClone(value, depth, references);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return ((value as unknown as PlainObject)[cloner] as Function)();
|
|
145
|
-
}
|
|
146
|
-
|
|
147
121
|
function clonePlainObject(
|
|
148
122
|
value: ArrayOrPlainObject,
|
|
149
123
|
depth: number,
|
|
@@ -234,6 +208,9 @@ function cloneValue(value: unknown, depth: number, references: WeakMap<WeakKey,
|
|
|
234
208
|
case value instanceof DataView:
|
|
235
209
|
return cloneDataView(value, depth, references);
|
|
236
210
|
|
|
211
|
+
case value instanceof Date:
|
|
212
|
+
return new Date(value.getTime());
|
|
213
|
+
|
|
237
214
|
case value instanceof RegExp:
|
|
238
215
|
return cloneRegularExpression(value, depth, references);
|
|
239
216
|
|
|
@@ -251,7 +228,7 @@ function cloneValue(value: unknown, depth: number, references: WeakMap<WeakKey,
|
|
|
251
228
|
return cloneTypedArray(value, depth, references);
|
|
252
229
|
|
|
253
230
|
default:
|
|
254
|
-
return
|
|
231
|
+
return clone.handlers.handle(value, depth, references);
|
|
255
232
|
}
|
|
256
233
|
}
|
|
257
234
|
|
|
@@ -281,8 +258,6 @@ function tryStructuredClone(
|
|
|
281
258
|
|
|
282
259
|
// #region Constants
|
|
283
260
|
|
|
284
|
-
const cloners = new WeakMap<Constructor, string | Cloner<unknown>>();
|
|
285
|
-
|
|
286
261
|
const MAX_CLONE_DEPTH = 100;
|
|
287
262
|
|
|
288
263
|
// #endregion
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Constructor } from '../../models';
|
|
1
2
|
/**
|
|
2
3
|
* Compare two values _(for sorting purposes)_
|
|
3
4
|
* @param first First value
|
|
@@ -5,3 +6,12 @@
|
|
|
5
6
|
* @returns `0` if equal; `-1` first comes before second; `1` first comes after second
|
|
6
7
|
*/
|
|
7
8
|
export declare function compare(first: unknown, second: unknown): number;
|
|
9
|
+
export declare namespace compare {
|
|
10
|
+
var handlers: {
|
|
11
|
+
register: (constructor: Constructor, handler?: string | import("../..").GenericCallback) => void;
|
|
12
|
+
unregister: (constructor: Constructor) => void;
|
|
13
|
+
handle(first: unknown, second: unknown, ...parameters: unknown[]): number;
|
|
14
|
+
};
|
|
15
|
+
var register: <Instance>(constructor: Constructor<Instance>, handler?: string | ((first: Instance, second: Instance) => number)) => void;
|
|
16
|
+
var unregister: (constructor: Constructor) => void;
|
|
17
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Constructor } from '../../models';
|
|
2
|
-
type Comparison<Instance> = (first: Instance, second: Instance) => boolean;
|
|
3
2
|
/**
|
|
4
3
|
* Options for value equality comparison
|
|
5
4
|
*/
|
|
@@ -26,13 +25,16 @@ type Equalizer = {
|
|
|
26
25
|
*/
|
|
27
26
|
(first: unknown, second: unknown): boolean;
|
|
28
27
|
/**
|
|
29
|
-
*
|
|
28
|
+
* Register a equality comparison handler for a specific class
|
|
29
|
+
* @param constructor Class constructor
|
|
30
|
+
* @param handler Equality comparison handler
|
|
30
31
|
*/
|
|
31
|
-
register:
|
|
32
|
+
register: <Instance>(constructor: Constructor<Instance>, handler?: string | ((first: Instance, second: Instance) => boolean)) => void;
|
|
32
33
|
/**
|
|
33
|
-
*
|
|
34
|
+
* Unregister a equality comparison handler for a specific class
|
|
35
|
+
* @param constructor Class constructor
|
|
34
36
|
*/
|
|
35
|
-
unregister:
|
|
37
|
+
unregister: (constructor: Constructor) => void;
|
|
36
38
|
};
|
|
37
39
|
/**
|
|
38
40
|
* Are two strings equal?
|
|
@@ -51,8 +53,13 @@ export declare function equal(first: string, second: string, ignoreCase?: boolea
|
|
|
51
53
|
*/
|
|
52
54
|
export declare function equal(first: unknown, second: unknown, options?: EqualOptions): boolean;
|
|
53
55
|
export declare namespace equal {
|
|
56
|
+
var handlers: {
|
|
57
|
+
register: (constructor: Constructor, handler?: string | import("../..").GenericCallback) => void;
|
|
58
|
+
unregister: (constructor: Constructor) => void;
|
|
59
|
+
handle(first: unknown, second: unknown, ...parameters: unknown[]): boolean;
|
|
60
|
+
};
|
|
54
61
|
var initialize: (options?: EqualOptions) => Equalizer;
|
|
55
|
-
var register: <Instance>(constructor: Constructor<Instance>,
|
|
56
|
-
var unregister:
|
|
62
|
+
var register: <Instance>(constructor: Constructor<Instance>, fn: (first: Instance, second: Instance) => boolean) => void;
|
|
63
|
+
var unregister: (constructor: Constructor) => void;
|
|
57
64
|
}
|
|
58
65
|
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Constructor, GenericCallback } from '../../models';
|
|
2
|
+
type Options = {
|
|
3
|
+
callback: GenericCallback;
|
|
4
|
+
method?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function getCompareHandlers<Value>(owner: GenericCallback, options: Options): {
|
|
7
|
+
register: (constructor: Constructor, handler?: string | GenericCallback) => void;
|
|
8
|
+
unregister: (constructor: Constructor) => void;
|
|
9
|
+
handle(first: unknown, second: unknown, ...parameters: unknown[]): Value;
|
|
10
|
+
};
|
|
11
|
+
export declare function getSelfHandlers(owner: GenericCallback, options: Options): {
|
|
12
|
+
register: (constructor: Constructor, handler?: string | GenericCallback) => void;
|
|
13
|
+
unregister: (constructor: Constructor) => void;
|
|
14
|
+
handle(value: unknown, ...parameters: unknown[]): any;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
package/types/value/clone.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Constructor } from '../models';
|
|
2
|
-
type Cloner<Instance> = (original: Instance) => Instance;
|
|
3
2
|
/**
|
|
4
3
|
* Clone any kind of value _(deeply, if needed)_
|
|
5
4
|
* @param value Value to clone
|
|
@@ -7,7 +6,11 @@ type Cloner<Instance> = (original: Instance) => Instance;
|
|
|
7
6
|
*/
|
|
8
7
|
export declare function clone<Value>(value: Value): Value;
|
|
9
8
|
export declare namespace clone {
|
|
10
|
-
var
|
|
9
|
+
var handlers: {
|
|
10
|
+
register: (constructor: Constructor, handler?: string | import("..").GenericCallback) => void;
|
|
11
|
+
unregister: (constructor: Constructor) => void;
|
|
12
|
+
handle(value: unknown, ...parameters: unknown[]): any;
|
|
13
|
+
};
|
|
14
|
+
var register: <Instance>(constructor: Constructor<Instance>, handler?: string | ((value: Instance) => Instance)) => void;
|
|
11
15
|
var unregister: (constructor: Constructor) => void;
|
|
12
16
|
}
|
|
13
|
-
export {};
|