@naturalcycles/js-lib 14.248.0 → 14.250.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/array.util.js +52 -42
- package/dist/datetime/localDate.js +30 -17
- package/dist/datetime/localTime.js +31 -18
- package/dist/error/assert.js +2 -1
- package/dist/http/fetcher.js +5 -5
- package/dist/json-schema/jsonSchemaBuilder.js +2 -2
- package/dist/math/math.util.js +14 -4
- package/dist/math/sma.js +4 -1
- package/dist/number/createDeterministicRandom.js +1 -1
- package/dist/number/number.util.js +2 -2
- package/dist/object/deepEquals.d.ts +2 -2
- package/dist/object/deepEquals.js +10 -3
- package/dist/object/object.util.d.ts +1 -2
- package/dist/object/object.util.js +59 -34
- package/dist/promise/pDelay.d.ts +3 -3
- package/dist/promise/pDelay.js +1 -1
- package/dist/promise/pRetry.js +3 -1
- package/dist/semver.js +22 -13
- package/dist/string/case.js +15 -6
- package/dist/string/lodash/words.js +1 -0
- package/dist/string/safeJsonStringify.js +1 -1
- package/dist-esm/array/array.util.js +52 -42
- package/dist-esm/datetime/localDate.js +30 -17
- package/dist-esm/datetime/localTime.js +31 -18
- package/dist-esm/error/assert.js +2 -1
- package/dist-esm/http/fetcher.js +5 -5
- package/dist-esm/json-schema/jsonSchemaBuilder.js +2 -2
- package/dist-esm/math/math.util.js +14 -4
- package/dist-esm/math/sma.js +4 -1
- package/dist-esm/number/createDeterministicRandom.js +1 -1
- package/dist-esm/number/number.util.js +2 -2
- package/dist-esm/object/deepEquals.js +10 -3
- package/dist-esm/object/object.util.js +60 -35
- package/dist-esm/promise/pDelay.js +1 -1
- package/dist-esm/promise/pRetry.js +3 -1
- package/dist-esm/semver.js +22 -13
- package/dist-esm/string/case.js +15 -6
- package/dist-esm/string/lodash/words.js +1 -0
- package/dist-esm/string/safeJsonStringify.js +1 -1
- package/package.json +1 -1
- package/src/array/array.util.ts +48 -40
- package/src/datetime/localDate.ts +34 -19
- package/src/datetime/localTime.ts +34 -21
- package/src/error/assert.ts +2 -1
- package/src/http/fetcher.ts +8 -6
- package/src/json-schema/jsonSchemaBuilder.ts +2 -2
- package/src/math/math.util.ts +13 -6
- package/src/math/sma.ts +3 -1
- package/src/number/createDeterministicRandom.ts +1 -1
- package/src/number/number.util.ts +4 -2
- package/src/object/deepEquals.ts +17 -15
- package/src/object/object.util.ts +77 -52
- package/src/promise/pDelay.ts +6 -3
- package/src/promise/pRetry.ts +3 -1
- package/src/semver.ts +22 -13
- package/src/string/case.ts +15 -12
- package/src/string/leven.ts +1 -1
- package/src/string/lodash/words.ts +1 -0
- package/src/string/safeJsonStringify.ts +1 -1
- package/src/string/string.util.ts +2 -2
|
@@ -35,28 +35,37 @@ const types_1 = require("../types");
|
|
|
35
35
|
function _pick(obj, props, mutate = false) {
|
|
36
36
|
if (mutate) {
|
|
37
37
|
// Start as original object (mutable), DELETE properties that are not whitelisted
|
|
38
|
-
|
|
38
|
+
for (const prop of Object.keys(obj)) {
|
|
39
39
|
if (!props.includes(prop))
|
|
40
|
-
delete
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
delete obj[prop];
|
|
41
|
+
}
|
|
42
|
+
return obj;
|
|
43
43
|
}
|
|
44
44
|
// Start as empty object, pick/add needed properties
|
|
45
|
-
|
|
45
|
+
const r = {};
|
|
46
|
+
for (const prop of props) {
|
|
46
47
|
if (prop in obj)
|
|
47
48
|
r[prop] = obj[prop];
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
}
|
|
50
|
+
return r;
|
|
50
51
|
}
|
|
51
52
|
/**
|
|
52
53
|
* Returns clone of `obj` with `props` omitted.
|
|
53
54
|
* Opposite of Pick.
|
|
54
55
|
*/
|
|
55
56
|
function _omit(obj, props, mutate = false) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
if (mutate) {
|
|
58
|
+
for (const prop of props) {
|
|
59
|
+
delete obj[prop];
|
|
60
|
+
}
|
|
61
|
+
return obj;
|
|
62
|
+
}
|
|
63
|
+
const r = {};
|
|
64
|
+
for (const prop of Object.keys(obj)) {
|
|
65
|
+
if (!props.includes(prop))
|
|
66
|
+
r[prop] = obj[prop];
|
|
67
|
+
}
|
|
68
|
+
return r;
|
|
60
69
|
}
|
|
61
70
|
/**
|
|
62
71
|
* Returns object with filtered keys from `props` array.
|
|
@@ -67,10 +76,11 @@ function _omit(obj, props, mutate = false) {
|
|
|
67
76
|
* ])
|
|
68
77
|
*/
|
|
69
78
|
function _mask(obj, props, mutate = false) {
|
|
70
|
-
|
|
79
|
+
const r = mutate ? obj : _deepCopy(obj);
|
|
80
|
+
for (const prop of props) {
|
|
71
81
|
_unset(r, prop);
|
|
72
|
-
|
|
73
|
-
|
|
82
|
+
}
|
|
83
|
+
return r;
|
|
74
84
|
}
|
|
75
85
|
/**
|
|
76
86
|
* Removes "falsy" values from the object.
|
|
@@ -99,11 +109,21 @@ function _filterEmptyArrays(obj, mutate = false) {
|
|
|
99
109
|
* Allows filtering by both key and value.
|
|
100
110
|
*/
|
|
101
111
|
function _filterObject(obj, predicate, mutate = false) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
112
|
+
if (mutate) {
|
|
113
|
+
for (const [k, v] of (0, types_1._objectEntries)(obj)) {
|
|
114
|
+
if (!predicate(k, v, obj)) {
|
|
115
|
+
delete obj[k];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return obj;
|
|
119
|
+
}
|
|
120
|
+
const r = {};
|
|
121
|
+
for (const [k, v] of (0, types_1._objectEntries)(obj)) {
|
|
122
|
+
if (predicate(k, v, obj)) {
|
|
123
|
+
r[k] = v;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return r;
|
|
107
127
|
}
|
|
108
128
|
/**
|
|
109
129
|
* var users = {
|
|
@@ -117,10 +137,11 @@ function _filterObject(obj, predicate, mutate = false) {
|
|
|
117
137
|
* To skip some key-value pairs - use _mapObject instead.
|
|
118
138
|
*/
|
|
119
139
|
function _mapValues(obj, mapper, mutate = false) {
|
|
120
|
-
|
|
140
|
+
const map = mutate ? obj : {};
|
|
141
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
121
142
|
map[k] = mapper(k, v, obj);
|
|
122
|
-
|
|
123
|
-
|
|
143
|
+
}
|
|
144
|
+
return map;
|
|
124
145
|
}
|
|
125
146
|
/**
|
|
126
147
|
* _.mapKeys({ 'a': 1, 'b': 2 }, (key, value) => key + value)
|
|
@@ -131,10 +152,11 @@ function _mapValues(obj, mapper, mutate = false) {
|
|
|
131
152
|
* To skip some key-value pairs - use _mapObject instead.
|
|
132
153
|
*/
|
|
133
154
|
function _mapKeys(obj, mapper) {
|
|
134
|
-
|
|
155
|
+
const map = {};
|
|
156
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
135
157
|
map[mapper(k, v, obj)] = v;
|
|
136
|
-
|
|
137
|
-
|
|
158
|
+
}
|
|
159
|
+
return map;
|
|
138
160
|
}
|
|
139
161
|
/**
|
|
140
162
|
* Maps object through predicate - a function that receives (k, v, obj)
|
|
@@ -153,13 +175,14 @@ function _mapKeys(obj, mapper) {
|
|
|
153
175
|
* Non-string keys are passed via String(...)
|
|
154
176
|
*/
|
|
155
177
|
function _mapObject(obj, mapper) {
|
|
156
|
-
|
|
178
|
+
const map = {};
|
|
179
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
157
180
|
const r = mapper(k, v, obj);
|
|
158
|
-
if (r
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
181
|
+
if (r === types_1.SKIP)
|
|
182
|
+
continue;
|
|
183
|
+
map[r[0]] = r[1];
|
|
184
|
+
}
|
|
185
|
+
return map;
|
|
163
186
|
}
|
|
164
187
|
function _findKeyByValue(obj, v) {
|
|
165
188
|
return Object.entries(obj).find(([_, value]) => value === v)?.[0];
|
|
@@ -246,7 +269,7 @@ function _deepTrim(o) {
|
|
|
246
269
|
if (typeof o === 'string') {
|
|
247
270
|
return o.trim();
|
|
248
271
|
}
|
|
249
|
-
|
|
272
|
+
if (typeof o === 'object') {
|
|
250
273
|
Object.keys(o).forEach(k => {
|
|
251
274
|
o[k] = _deepTrim(o[k]);
|
|
252
275
|
});
|
|
@@ -300,10 +323,11 @@ function _invertMap(m) {
|
|
|
300
323
|
* _get(obj, 'unknown.path') // undefined
|
|
301
324
|
*/
|
|
302
325
|
function _get(obj = {}, path = '') {
|
|
303
|
-
return path
|
|
326
|
+
return (path
|
|
304
327
|
.replaceAll(/\[([^\]]+)]/g, '.$1')
|
|
305
328
|
.split('.')
|
|
306
|
-
|
|
329
|
+
// eslint-disable-next-line unicorn/no-array-reduce
|
|
330
|
+
.reduce((o, p) => o?.[p], obj));
|
|
307
331
|
}
|
|
308
332
|
/**
|
|
309
333
|
* Sets the value at path of object. If a portion of path doesn’t exist it’s created. Arrays are created for
|
|
@@ -326,6 +350,7 @@ function _set(obj, path, value) {
|
|
|
326
350
|
else if (!path.length) {
|
|
327
351
|
return obj;
|
|
328
352
|
}
|
|
353
|
+
// eslint-disable-next-line unicorn/no-array-reduce
|
|
329
354
|
;
|
|
330
355
|
path.slice(0, -1).reduce((a, c, i) => Object(a[c]) === a[c] // Does the key exist and is its value an object?
|
|
331
356
|
? // Yes: then follow that path
|
package/dist/promise/pDelay.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PromisableFunction } from '../types';
|
|
1
|
+
import type { NumberOfMilliseconds, PromisableFunction } from '../types';
|
|
2
2
|
import { DeferredPromise } from './pDefer';
|
|
3
3
|
/**
|
|
4
4
|
* Promisified version of setTimeout.
|
|
@@ -6,7 +6,7 @@ import { DeferredPromise } from './pDefer';
|
|
|
6
6
|
* Can return a value.
|
|
7
7
|
* If value is instanceof Error - rejects the Promise instead of resolving.
|
|
8
8
|
*/
|
|
9
|
-
export declare function pDelay<T>(ms?:
|
|
9
|
+
export declare function pDelay<T>(ms?: NumberOfMilliseconds, value?: T): Promise<T>;
|
|
10
10
|
/**
|
|
11
11
|
* Promisified version of setTimeout.
|
|
12
12
|
*
|
|
@@ -16,4 +16,4 @@ export declare function pDelay<T>(ms?: number, value?: T): Promise<T>;
|
|
|
16
16
|
*
|
|
17
17
|
* On abort() - clears the Timeout and immediately resolves the Promise with void.
|
|
18
18
|
*/
|
|
19
|
-
export declare function pDelayFn<T>(ms:
|
|
19
|
+
export declare function pDelayFn<T>(ms: NumberOfMilliseconds, fn: PromisableFunction<T>): DeferredPromise<T>;
|
package/dist/promise/pDelay.js
CHANGED
|
@@ -22,7 +22,7 @@ async function pDelay(ms = 0, value) {
|
|
|
22
22
|
*
|
|
23
23
|
* On abort() - clears the Timeout and immediately resolves the Promise with void.
|
|
24
24
|
*/
|
|
25
|
-
function pDelayFn(ms
|
|
25
|
+
function pDelayFn(ms, fn) {
|
|
26
26
|
const p = (0, pDefer_1.pDefer)();
|
|
27
27
|
const timer = setTimeout(async () => {
|
|
28
28
|
try {
|
package/dist/promise/pRetry.js
CHANGED
|
@@ -51,7 +51,9 @@ async function pRetry(fn, opt = {}) {
|
|
|
51
51
|
}
|
|
52
52
|
catch (err) {
|
|
53
53
|
if (logFailures) {
|
|
54
|
-
|
|
54
|
+
// Logger at warn (not error) level, because it's not a fatal error, but a retriable one
|
|
55
|
+
// Fatal one is not logged either, because it's been thrown instead
|
|
56
|
+
logger.warn(`${fname} attempt #${attempt} error in ${(0, __1._since)(started)}:`, err);
|
|
55
57
|
}
|
|
56
58
|
if (attempt >= maxAttempts || (predicate && !predicate(err, attempt, maxAttempts))) {
|
|
57
59
|
// Give up
|
package/dist/semver.js
CHANGED
|
@@ -4,7 +4,6 @@ exports.semver2 = exports.Semver = void 0;
|
|
|
4
4
|
exports._quickSemverCompare = _quickSemverCompare;
|
|
5
5
|
const range_1 = require("./array/range");
|
|
6
6
|
const assert_1 = require("./error/assert");
|
|
7
|
-
const is_util_1 = require("./is.util");
|
|
8
7
|
/**
|
|
9
8
|
* Simple Semver implementation.
|
|
10
9
|
*
|
|
@@ -80,35 +79,45 @@ class SemverFactory {
|
|
|
80
79
|
* Returns the highest (max) Semver from the array, or undefined if the array is empty.
|
|
81
80
|
*/
|
|
82
81
|
maxOrUndefined(items) {
|
|
83
|
-
|
|
82
|
+
let max;
|
|
83
|
+
for (const item of items) {
|
|
84
|
+
const input = this.fromInputOrUndefined(item);
|
|
85
|
+
if (!max || input?.isAfter(max)) {
|
|
86
|
+
max = input;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return max;
|
|
84
90
|
}
|
|
85
91
|
/**
|
|
86
92
|
* Returns the highest Semver from the array.
|
|
87
93
|
* Throws if the array is empty.
|
|
88
94
|
*/
|
|
89
95
|
max(items) {
|
|
90
|
-
const
|
|
91
|
-
(0, assert_1._assert)(
|
|
92
|
-
return
|
|
93
|
-
.map(i => this.fromInput(i))
|
|
94
|
-
.reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
|
|
96
|
+
const max = this.maxOrUndefined(items);
|
|
97
|
+
(0, assert_1._assert)(max, 'semver.max called on empty array');
|
|
98
|
+
return max;
|
|
95
99
|
}
|
|
96
100
|
/**
|
|
97
101
|
* Returns the lowest (min) Semver from the array, or undefined if the array is empty.
|
|
98
102
|
*/
|
|
99
103
|
minOrUndefined(items) {
|
|
100
|
-
|
|
104
|
+
let min;
|
|
105
|
+
for (const item of items) {
|
|
106
|
+
const input = this.fromInputOrUndefined(item);
|
|
107
|
+
if (!min || input?.isBefore(min)) {
|
|
108
|
+
min = input;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return min;
|
|
101
112
|
}
|
|
102
113
|
/**
|
|
103
114
|
* Returns the lowest Semver from the array.
|
|
104
115
|
* Throws if the array is empty.
|
|
105
116
|
*/
|
|
106
117
|
min(items) {
|
|
107
|
-
const
|
|
108
|
-
(0, assert_1._assert)(
|
|
109
|
-
return
|
|
110
|
-
.map(i => this.fromInput(i))
|
|
111
|
-
.reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
|
|
118
|
+
const min = this.minOrUndefined(items);
|
|
119
|
+
(0, assert_1._assert)(min, 'semver.min called on empty array');
|
|
120
|
+
return min;
|
|
112
121
|
}
|
|
113
122
|
/**
|
|
114
123
|
* Sorts an array of Semvers in `dir` order (ascending by default).
|
package/dist/string/case.js
CHANGED
|
@@ -6,15 +6,24 @@ exports._kebabCase = _kebabCase;
|
|
|
6
6
|
const words_1 = require("./lodash/words");
|
|
7
7
|
const string_util_1 = require("./string.util");
|
|
8
8
|
function _camelCase(s) {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
let r = '';
|
|
10
|
+
for (let word of (0, words_1.words)(s.replaceAll(/['\u2019]/g, ''))) {
|
|
11
11
|
word = word.toLowerCase();
|
|
12
|
-
|
|
13
|
-
}
|
|
12
|
+
r += r ? (0, string_util_1._upperFirst)(word) : word;
|
|
13
|
+
}
|
|
14
|
+
return r;
|
|
14
15
|
}
|
|
15
16
|
function _snakeCase(s) {
|
|
16
|
-
|
|
17
|
+
let r = '';
|
|
18
|
+
for (const word of (0, words_1.words)(s.replaceAll(/['\u2019]/g, ''))) {
|
|
19
|
+
r += (r ? '_' : '') + word.toLowerCase();
|
|
20
|
+
}
|
|
21
|
+
return r;
|
|
17
22
|
}
|
|
18
23
|
function _kebabCase(s) {
|
|
19
|
-
|
|
24
|
+
let r = '';
|
|
25
|
+
for (const word of (0, words_1.words)(s.replaceAll(/['\u2019]/g, ''))) {
|
|
26
|
+
r += (r ? '-' : '') + word.toLowerCase();
|
|
27
|
+
}
|
|
28
|
+
return r;
|
|
20
29
|
}
|
|
@@ -6,6 +6,7 @@ exports.words = words;
|
|
|
6
6
|
const unicodeWords_1 = require("./unicodeWords");
|
|
7
7
|
const hasUnicodeWord = RegExp.prototype.test.bind(/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/);
|
|
8
8
|
/** Used to match words composed of alphanumeric characters. */
|
|
9
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: ok
|
|
9
10
|
const reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
|
|
10
11
|
function asciiWords(s) {
|
|
11
12
|
return s.match(reAsciiWord);
|
|
@@ -20,7 +20,7 @@ function _safeJsonStringify(obj, replacer, spaces, cycleReplacer) {
|
|
|
20
20
|
function serializer(replacer, cycleReplacer) {
|
|
21
21
|
const stack = [];
|
|
22
22
|
const keys = [];
|
|
23
|
-
cycleReplacer ??=
|
|
23
|
+
cycleReplacer ??= (key, value) => {
|
|
24
24
|
if (stack[0] === value)
|
|
25
25
|
return '[Circular ~]';
|
|
26
26
|
return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _assert } from '../error/assert';
|
|
2
2
|
import { END, } from '../types';
|
|
3
3
|
/**
|
|
4
4
|
* Creates an array of elements split into groups the length of size. If collection can’t be split evenly, the
|
|
@@ -13,9 +13,11 @@ import { END, } from '../types';
|
|
|
13
13
|
* Based on: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_chunk
|
|
14
14
|
*/
|
|
15
15
|
export function _chunk(array, size = 1) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const a = [];
|
|
17
|
+
for (let i = 0; i < array.length; i += size) {
|
|
18
|
+
a.push(array.slice(i, i + size));
|
|
19
|
+
}
|
|
20
|
+
return a;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* Removes duplicates from given array.
|
|
@@ -76,16 +78,13 @@ export function _pushUniqBy(a, mapper, ...items) {
|
|
|
76
78
|
* Based on: https://stackoverflow.com/a/40808569/4919972
|
|
77
79
|
*/
|
|
78
80
|
export function _uniqBy(arr, mapper) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}, new Map())
|
|
87
|
-
.values(),
|
|
88
|
-
];
|
|
81
|
+
const map = new Map();
|
|
82
|
+
for (const [i, item] of arr.entries()) {
|
|
83
|
+
const key = item === undefined || item === null ? item : mapper(item, i);
|
|
84
|
+
if (!map.has(key))
|
|
85
|
+
map.set(key, item);
|
|
86
|
+
}
|
|
87
|
+
return [...map.values()];
|
|
89
88
|
}
|
|
90
89
|
/**
|
|
91
90
|
* const a = [
|
|
@@ -128,13 +127,14 @@ export function _mapBy(items, mapper) {
|
|
|
128
127
|
* Returning `undefined` from the Mapper will EXCLUDE the item.
|
|
129
128
|
*/
|
|
130
129
|
export function _groupBy(items, mapper) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
130
|
+
const map = {};
|
|
131
|
+
for (const [i, item] of items.entries()) {
|
|
132
|
+
const key = mapper(item, i);
|
|
133
|
+
if (key === undefined)
|
|
134
|
+
continue;
|
|
135
|
+
(map[key] || (map[key] = [])).push(item);
|
|
136
|
+
}
|
|
137
|
+
return map;
|
|
138
138
|
}
|
|
139
139
|
/**
|
|
140
140
|
* _sortBy([{age: 20}, {age: 10}], 'age')
|
|
@@ -282,7 +282,11 @@ export function _intersectsWith(a1, a2) {
|
|
|
282
282
|
* // [1]
|
|
283
283
|
*/
|
|
284
284
|
export function _difference(source, ...diffs) {
|
|
285
|
-
|
|
285
|
+
let a = source;
|
|
286
|
+
for (const b of diffs) {
|
|
287
|
+
a = a.filter(c => !b.includes(c));
|
|
288
|
+
}
|
|
289
|
+
return a;
|
|
286
290
|
}
|
|
287
291
|
/**
|
|
288
292
|
* Returns the sum of items, or 0 for empty array.
|
|
@@ -367,45 +371,51 @@ export function _first(array) {
|
|
|
367
371
|
return array[0];
|
|
368
372
|
}
|
|
369
373
|
export function _minOrUndefined(array) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
+
let min;
|
|
375
|
+
for (const item of array) {
|
|
376
|
+
if (item === undefined || item === null)
|
|
377
|
+
continue;
|
|
378
|
+
if (min === undefined || item < min) {
|
|
379
|
+
min = item;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return min;
|
|
374
383
|
}
|
|
375
384
|
/**
|
|
376
385
|
* Filters out nullish values (undefined and null).
|
|
377
386
|
*/
|
|
378
387
|
export function _min(array) {
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
return a.reduce((min, item) => (min <= item ? min : item));
|
|
388
|
+
const min = _minOrUndefined(array);
|
|
389
|
+
_assert(min !== undefined, '_min called on empty array');
|
|
390
|
+
return min;
|
|
383
391
|
}
|
|
384
392
|
export function _maxOrUndefined(array) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
393
|
+
let max;
|
|
394
|
+
for (const item of array) {
|
|
395
|
+
if (item === undefined || item === null)
|
|
396
|
+
continue;
|
|
397
|
+
if (max === undefined || item > max) {
|
|
398
|
+
max = item;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return max;
|
|
389
402
|
}
|
|
390
403
|
/**
|
|
391
404
|
* Filters out nullish values (undefined and null).
|
|
392
405
|
*/
|
|
393
406
|
export function _max(array) {
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
return a.reduce((max, item) => (max >= item ? max : item));
|
|
407
|
+
const max = _maxOrUndefined(array);
|
|
408
|
+
_assert(max !== undefined, '_max called on empty array');
|
|
409
|
+
return max;
|
|
398
410
|
}
|
|
399
411
|
export function _maxBy(array, mapper) {
|
|
400
412
|
const max = _maxByOrUndefined(array, mapper);
|
|
401
|
-
|
|
402
|
-
throw new Error(`_maxBy returned undefined`);
|
|
413
|
+
_assert(max !== undefined, '_maxBy returned undefined');
|
|
403
414
|
return max;
|
|
404
415
|
}
|
|
405
416
|
export function _minBy(array, mapper) {
|
|
406
417
|
const min = _minByOrUndefined(array, mapper);
|
|
407
|
-
|
|
408
|
-
throw new Error(`_minBy returned undefined`);
|
|
418
|
+
_assert(min !== undefined, '_minBy returned undefined');
|
|
409
419
|
return min;
|
|
410
420
|
}
|
|
411
421
|
// todo: looks like it _maxByOrUndefined/_minByOrUndefined can be DRYer
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { _assert } from '../error/assert';
|
|
2
|
-
import { _isTruthy } from '../is.util';
|
|
3
2
|
import { Iterable2 } from '../iter/iterable2';
|
|
4
3
|
import { localTime } from './localTime';
|
|
5
4
|
const MDAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
@@ -492,7 +491,7 @@ class LocalDateFactory {
|
|
|
492
491
|
if (input instanceof LocalDate)
|
|
493
492
|
return true;
|
|
494
493
|
if (input instanceof Date)
|
|
495
|
-
return !isNaN(input.getDate());
|
|
494
|
+
return !Number.isNaN(input.getDate());
|
|
496
495
|
return this.isValidString(input);
|
|
497
496
|
}
|
|
498
497
|
/**
|
|
@@ -512,7 +511,7 @@ class LocalDateFactory {
|
|
|
512
511
|
if (input instanceof LocalDate)
|
|
513
512
|
return input;
|
|
514
513
|
if (input instanceof Date) {
|
|
515
|
-
if (isNaN(input.getDate()))
|
|
514
|
+
if (Number.isNaN(input.getDate()))
|
|
516
515
|
return;
|
|
517
516
|
return new LocalDate(input.getFullYear(), input.getMonth() + 1, input.getDate());
|
|
518
517
|
}
|
|
@@ -570,7 +569,7 @@ class LocalDateFactory {
|
|
|
570
569
|
* Takes Date as-is, in its timezone - local or UTC.
|
|
571
570
|
*/
|
|
572
571
|
fromDate(d) {
|
|
573
|
-
_assert(!isNaN(d.getDate()),
|
|
572
|
+
_assert(!Number.isNaN(d.getDate()), 'localDate.fromDate is called on Date object that is invalid');
|
|
574
573
|
return new LocalDate(d.getFullYear(), d.getMonth() + 1, d.getDate());
|
|
575
574
|
}
|
|
576
575
|
/**
|
|
@@ -578,7 +577,7 @@ class LocalDateFactory {
|
|
|
578
577
|
* Takes Date's year/month/day components in UTC, using getUTCFullYear, getUTCMonth, getUTCDate.
|
|
579
578
|
*/
|
|
580
579
|
fromDateInUTC(d) {
|
|
581
|
-
_assert(!isNaN(d.getDate()),
|
|
580
|
+
_assert(!Number.isNaN(d.getDate()), 'localDate.fromDateInUTC is called on Date object that is invalid');
|
|
582
581
|
return new LocalDate(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
|
|
583
582
|
}
|
|
584
583
|
fromDateObject(o) {
|
|
@@ -596,35 +595,49 @@ class LocalDateFactory {
|
|
|
596
595
|
* Returns the earliest (min) LocalDate from the array, or undefined if the array is empty.
|
|
597
596
|
*/
|
|
598
597
|
minOrUndefined(items) {
|
|
599
|
-
|
|
598
|
+
let min;
|
|
599
|
+
for (const item of items) {
|
|
600
|
+
if (!item)
|
|
601
|
+
continue;
|
|
602
|
+
const ld = this.fromInput(item);
|
|
603
|
+
if (!min || ld.isBefore(min)) {
|
|
604
|
+
min = ld;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return min;
|
|
600
608
|
}
|
|
601
609
|
/**
|
|
602
610
|
* Returns the earliest LocalDate from the array.
|
|
603
611
|
* Throws if the array is empty.
|
|
604
612
|
*/
|
|
605
613
|
min(items) {
|
|
606
|
-
const
|
|
607
|
-
_assert(
|
|
608
|
-
return
|
|
609
|
-
.map(i => this.fromInput(i))
|
|
610
|
-
.reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
|
|
614
|
+
const min = this.minOrUndefined(items);
|
|
615
|
+
_assert(min, 'localDate.min called on empty array');
|
|
616
|
+
return min;
|
|
611
617
|
}
|
|
612
618
|
/**
|
|
613
619
|
* Returns the latest (max) LocalDate from the array, or undefined if the array is empty.
|
|
614
620
|
*/
|
|
615
621
|
maxOrUndefined(items) {
|
|
616
|
-
|
|
622
|
+
let max;
|
|
623
|
+
for (const item of items) {
|
|
624
|
+
if (!item)
|
|
625
|
+
continue;
|
|
626
|
+
const ld = this.fromInput(item);
|
|
627
|
+
if (!max || ld.isAfter(max)) {
|
|
628
|
+
max = ld;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return max;
|
|
617
632
|
}
|
|
618
633
|
/**
|
|
619
634
|
* Returns the latest LocalDate from the array.
|
|
620
635
|
* Throws if the array is empty.
|
|
621
636
|
*/
|
|
622
637
|
max(items) {
|
|
623
|
-
const
|
|
624
|
-
_assert(
|
|
625
|
-
return
|
|
626
|
-
.map(i => this.fromInput(i))
|
|
627
|
-
.reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
|
|
638
|
+
const max = this.maxOrUndefined(items);
|
|
639
|
+
_assert(max, 'localDate.max called on empty array');
|
|
640
|
+
return max;
|
|
628
641
|
}
|
|
629
642
|
/**
|
|
630
643
|
* Returns the range (array) of LocalDates between min and max.
|