@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.
Files changed (60) hide show
  1. package/dist/array/array.util.js +52 -42
  2. package/dist/datetime/localDate.js +30 -17
  3. package/dist/datetime/localTime.js +31 -18
  4. package/dist/error/assert.js +2 -1
  5. package/dist/http/fetcher.js +5 -5
  6. package/dist/json-schema/jsonSchemaBuilder.js +2 -2
  7. package/dist/math/math.util.js +14 -4
  8. package/dist/math/sma.js +4 -1
  9. package/dist/number/createDeterministicRandom.js +1 -1
  10. package/dist/number/number.util.js +2 -2
  11. package/dist/object/deepEquals.d.ts +2 -2
  12. package/dist/object/deepEquals.js +10 -3
  13. package/dist/object/object.util.d.ts +1 -2
  14. package/dist/object/object.util.js +59 -34
  15. package/dist/promise/pDelay.d.ts +3 -3
  16. package/dist/promise/pDelay.js +1 -1
  17. package/dist/promise/pRetry.js +3 -1
  18. package/dist/semver.js +22 -13
  19. package/dist/string/case.js +15 -6
  20. package/dist/string/lodash/words.js +1 -0
  21. package/dist/string/safeJsonStringify.js +1 -1
  22. package/dist-esm/array/array.util.js +52 -42
  23. package/dist-esm/datetime/localDate.js +30 -17
  24. package/dist-esm/datetime/localTime.js +31 -18
  25. package/dist-esm/error/assert.js +2 -1
  26. package/dist-esm/http/fetcher.js +5 -5
  27. package/dist-esm/json-schema/jsonSchemaBuilder.js +2 -2
  28. package/dist-esm/math/math.util.js +14 -4
  29. package/dist-esm/math/sma.js +4 -1
  30. package/dist-esm/number/createDeterministicRandom.js +1 -1
  31. package/dist-esm/number/number.util.js +2 -2
  32. package/dist-esm/object/deepEquals.js +10 -3
  33. package/dist-esm/object/object.util.js +60 -35
  34. package/dist-esm/promise/pDelay.js +1 -1
  35. package/dist-esm/promise/pRetry.js +3 -1
  36. package/dist-esm/semver.js +22 -13
  37. package/dist-esm/string/case.js +15 -6
  38. package/dist-esm/string/lodash/words.js +1 -0
  39. package/dist-esm/string/safeJsonStringify.js +1 -1
  40. package/package.json +1 -1
  41. package/src/array/array.util.ts +48 -40
  42. package/src/datetime/localDate.ts +34 -19
  43. package/src/datetime/localTime.ts +34 -21
  44. package/src/error/assert.ts +2 -1
  45. package/src/http/fetcher.ts +8 -6
  46. package/src/json-schema/jsonSchemaBuilder.ts +2 -2
  47. package/src/math/math.util.ts +13 -6
  48. package/src/math/sma.ts +3 -1
  49. package/src/number/createDeterministicRandom.ts +1 -1
  50. package/src/number/number.util.ts +4 -2
  51. package/src/object/deepEquals.ts +17 -15
  52. package/src/object/object.util.ts +77 -52
  53. package/src/promise/pDelay.ts +6 -3
  54. package/src/promise/pRetry.ts +3 -1
  55. package/src/semver.ts +22 -13
  56. package/src/string/case.ts +15 -12
  57. package/src/string/leven.ts +1 -1
  58. package/src/string/lodash/words.ts +1 -0
  59. package/src/string/safeJsonStringify.ts +1 -1
  60. 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
- return Object.keys(obj).reduce((r, prop) => {
38
+ for (const prop of Object.keys(obj)) {
39
39
  if (!props.includes(prop))
40
- delete r[prop];
41
- return r;
42
- }, obj);
40
+ delete obj[prop];
41
+ }
42
+ return obj;
43
43
  }
44
44
  // Start as empty object, pick/add needed properties
45
- return props.reduce((r, prop) => {
45
+ const r = {};
46
+ for (const prop of props) {
46
47
  if (prop in obj)
47
48
  r[prop] = obj[prop];
48
- return r;
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
- return props.reduce((r, prop) => {
57
- delete r[prop];
58
- return r;
59
- }, mutate ? obj : { ...obj });
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
- return props.reduce((r, prop) => {
79
+ const r = mutate ? obj : _deepCopy(obj);
80
+ for (const prop of props) {
71
81
  _unset(r, prop);
72
- return r;
73
- }, mutate ? obj : _deepCopy(obj));
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
- return Object.keys(obj).reduce((r, k) => {
103
- if (!predicate(k, r[k], obj))
104
- delete r[k];
105
- return r;
106
- }, mutate ? obj : { ...obj });
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
- return (0, types_1._objectEntries)(obj).reduce((map, [k, v]) => {
140
+ const map = mutate ? obj : {};
141
+ for (const [k, v] of Object.entries(obj)) {
121
142
  map[k] = mapper(k, v, obj);
122
- return map;
123
- }, mutate ? obj : {});
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
- return (0, types_1._objectEntries)(obj).reduce((map, [k, v]) => {
155
+ const map = {};
156
+ for (const [k, v] of Object.entries(obj)) {
135
157
  map[mapper(k, v, obj)] = v;
136
- return map;
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
- return Object.entries(obj).reduce((map, [k, v]) => {
178
+ const map = {};
179
+ for (const [k, v] of Object.entries(obj)) {
157
180
  const r = mapper(k, v, obj);
158
- if (r !== types_1.SKIP) {
159
- map[r[0]] = r[1];
160
- }
161
- return map;
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
- else if (typeof o === 'object') {
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
- .reduce((o, p) => o?.[p], obj);
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
@@ -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?: number, value?: T): Promise<T>;
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: number | undefined, fn: PromisableFunction<T>): DeferredPromise<T>;
19
+ export declare function pDelayFn<T>(ms: NumberOfMilliseconds, fn: PromisableFunction<T>): DeferredPromise<T>;
@@ -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 = 0, fn) {
25
+ function pDelayFn(ms, fn) {
26
26
  const p = (0, pDefer_1.pDefer)();
27
27
  const timer = setTimeout(async () => {
28
28
  try {
@@ -51,7 +51,9 @@ async function pRetry(fn, opt = {}) {
51
51
  }
52
52
  catch (err) {
53
53
  if (logFailures) {
54
- logger.error(`${fname} attempt #${attempt} error in ${(0, __1._since)(started)}:`, err);
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
- return items.length ? this.max(items) : undefined;
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 items2 = items.filter(is_util_1._isTruthy);
91
- (0, assert_1._assert)(items2.length, 'semver.max called on empty array');
92
- return items2
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
- return items.length ? this.min(items) : undefined;
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 items2 = items.filter(is_util_1._isTruthy);
108
- (0, assert_1._assert)(items2.length, 'semver.min called on empty array');
109
- return items2
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).
@@ -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
- // return s.replace(/(_\w)/g, m => m[1]!.toUpperCase())
10
- return (0, words_1.words)(s.replaceAll(/['\u2019]/g, '')).reduce((result, word, index) => {
9
+ let r = '';
10
+ for (let word of (0, words_1.words)(s.replaceAll(/['\u2019]/g, ''))) {
11
11
  word = word.toLowerCase();
12
- return result + (index ? (0, string_util_1._upperFirst)(word) : word);
13
- }, '');
12
+ r += r ? (0, string_util_1._upperFirst)(word) : word;
13
+ }
14
+ return r;
14
15
  }
15
16
  function _snakeCase(s) {
16
- return (0, words_1.words)(s.replaceAll(/['\u2019]/g, '')).reduce((result, word, index) => result + (index ? '_' : '') + word.toLowerCase(), '');
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
- return (0, words_1.words)(s.replaceAll(/['\u2019]/g, '')).reduce((result, word, index) => result + (index ? '-' : '') + word.toLowerCase(), '');
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 ??= function (key, value) {
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 { _isNotNullish } from '../is.util';
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
- return array.reduce((arr, item, idx) => {
17
- return idx % size === 0 ? [...arr, [item]] : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]];
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
- return [
80
- ...arr
81
- .reduce((map, item, index) => {
82
- const key = item === null || item === undefined ? item : mapper(item, index);
83
- if (!map.has(key))
84
- map.set(key, item);
85
- return map;
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
- return items.reduce((map, item, index) => {
132
- const res = mapper(item, index);
133
- if (res !== undefined) {
134
- map[res] = [...(map[res] || []), item];
135
- }
136
- return map;
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
- return diffs.reduce((a, b) => a.filter(c => !b.includes(c)), source);
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
- const a = array.filter(_isNotNullish);
371
- if (!a.length)
372
- return;
373
- return a.reduce((min, item) => (min <= item ? min : item));
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 a = array.filter(_isNotNullish);
380
- if (!a.length)
381
- throw new Error('_min called on empty array');
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
- const a = array.filter(_isNotNullish);
386
- if (!a.length)
387
- return;
388
- return a.reduce((max, item) => (max >= item ? max : item));
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 a = array.filter(_isNotNullish);
395
- if (!a.length)
396
- throw new Error('_max called on empty array');
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
- if (max === undefined)
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
- if (min === undefined)
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()), `localDate.fromDate is called on Date object that is invalid`);
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()), `localDate.fromDateInUTC is called on Date object that is invalid`);
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
- return items.length ? this.min(items) : undefined;
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 items2 = items.filter(_isTruthy);
607
- _assert(items2.length, 'localDate.min called on empty array');
608
- return items2
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
- return items.length ? this.max(items) : undefined;
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 items2 = items.filter(_isTruthy);
624
- _assert(items2.length, 'localDate.max called on empty array');
625
- return items2
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.