@naturalcycles/js-lib 15.8.1 → 15.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -61,9 +61,9 @@ export function _pushUniq<T>(a: T[], ...items: T[]): T[] {
61
61
  * Mutates the array (same as normal `push`).
62
62
  */
63
63
  export function _pushUniqBy<T>(a: T[], mapper: Mapper<T, any>, ...items: T[]): T[] {
64
- const mappedSet = new Set(a.map((item, i) => mapper(item, i)))
65
- items.forEach((item, i) => {
66
- const mapped = mapper(item, i)
64
+ const mappedSet = new Set(a.map(mapper))
65
+ items.forEach(item => {
66
+ const mapped = mapper(item)
67
67
  if (!mappedSet.has(mapped)) {
68
68
  a.push(item)
69
69
  mappedSet.add(mapped)
@@ -91,8 +91,9 @@ export function _pushUniqBy<T>(a: T[], mapper: Mapper<T, any>, ...items: T[]): T
91
91
  */
92
92
  export function _uniqBy<T>(arr: readonly T[], mapper: Mapper<T, any>): T[] {
93
93
  const map = new Map<any, T>()
94
- for (const [i, item] of arr.entries()) {
95
- const key = item === undefined || item === null ? item : mapper(item, i)
94
+ for (let i = 0; i < arr.length; i++) {
95
+ const item = arr[i]!
96
+ const key = item === undefined || item === null ? item : mapper(item)
96
97
  if (!map.has(key)) map.set(key, item)
97
98
  }
98
99
  return [...map.values()]
@@ -119,9 +120,16 @@ export function _uniqBy<T>(arr: readonly T[], mapper: Mapper<T, any>): T[] {
119
120
  * Returning `undefined` from the Mapper will EXCLUDE the item.
120
121
  */
121
122
  export function _by<T>(items: readonly T[], mapper: Mapper<T, any>): StringMap<T> {
122
- return Object.fromEntries(
123
- items.map((item, i) => [mapper(item, i), item]).filter(([k]) => k !== undefined) as [any, T][],
124
- )
123
+ const map: StringMap<T> = {}
124
+ for (let i = 0; i < items.length; i++) {
125
+ const v = items[i]!
126
+ const k = mapper(v)
127
+ if (k !== undefined) {
128
+ map[k] = v
129
+ }
130
+ }
131
+
132
+ return map
125
133
  }
126
134
 
127
135
  /**
@@ -131,12 +139,15 @@ export function _mapBy<ITEM, KEY>(
131
139
  items: readonly ITEM[],
132
140
  mapper: Mapper<ITEM, KEY>,
133
141
  ): Map<KEY, ITEM> {
134
- return new Map(
135
- items.map((item, i) => [mapper(item, i), item]).filter(([k]) => k !== undefined) as [
136
- KEY,
137
- ITEM,
138
- ][],
139
- )
142
+ const map = new Map<KEY, ITEM>()
143
+ for (let i = 0; i < items.length; i++) {
144
+ const item = items[i]!
145
+ const key = mapper(item)
146
+ if (key !== undefined) {
147
+ map.set(key, item)
148
+ }
149
+ }
150
+ return map
140
151
  }
141
152
 
142
153
  /**
@@ -152,14 +163,31 @@ export function _mapBy<ITEM, KEY>(
152
163
  */
153
164
  export function _groupBy<T>(items: readonly T[], mapper: Mapper<T, any>): StringMap<T[]> {
154
165
  const map: StringMap<T[]> = {}
155
- for (const [i, item] of items.entries()) {
156
- const key = mapper(item, i)
157
- if (key === undefined) continue
158
- ;(map[key] ||= []).push(item)
166
+
167
+ for (let i = 0; i < items.length; i++) {
168
+ const item = items[i]!
169
+ const key = mapper(item)
170
+ if (key !== undefined) {
171
+ ;(map[key] ||= []).push(item)
172
+ }
159
173
  }
160
174
  return map
161
175
  }
162
176
 
177
+ export interface MutateOptions {
178
+ /**
179
+ * Defaults to false.
180
+ */
181
+ mutate?: boolean
182
+ }
183
+
184
+ export interface SortOptions extends MutateOptions {
185
+ /**
186
+ * Defaults to 'asc'.
187
+ */
188
+ dir?: SortDirection
189
+ }
190
+
163
191
  /**
164
192
  * _sortBy([{age: 20}, {age: 10}], 'age')
165
193
  * // => [{age: 10}, {age: 20}]
@@ -167,34 +195,34 @@ export function _groupBy<T>(items: readonly T[], mapper: Mapper<T, any>): String
167
195
  * Same:
168
196
  * _sortBy([{age: 20}, {age: 10}], o => o.age)
169
197
  */
170
- export function _sortBy<T>(
198
+ export function _sortBy<T, COMPARE_TYPE extends string | number>(
171
199
  items: T[],
172
- mapper: Mapper<T, any>,
173
- mutate = false,
174
- dir: SortDirection = 'asc',
200
+ mapper: Mapper<T, COMPARE_TYPE>,
201
+ opt: SortOptions = {},
175
202
  ): T[] {
176
- const mod = dir === 'desc' ? -1 : 1
177
- return (mutate ? items : [...items]).sort((_a, _b) => {
178
- const [a, b] = [_a, _b].map(mapper)
179
- if (typeof a === 'number' && typeof b === 'number') return (a - b) * mod
180
- return String(a).localeCompare(String(b)) * mod
203
+ const mod = opt.dir === 'desc' ? -1 : 1
204
+
205
+ return (opt.mutate ? items : [...items]).sort((_a, _b) => {
206
+ // This implementation may call mapper more than once per item,
207
+ // but the benchmarks show no significant difference in performance.
208
+ const a = mapper(_a)
209
+ const b = mapper(_b)
210
+ // if (typeof a === 'number' && typeof b === 'number') return (a - b) * mod
211
+ // return String(a).localeCompare(String(b)) * mod
212
+ if (a > b) return mod
213
+ if (a < b) return -mod
214
+ return 0
181
215
  })
182
216
  }
183
217
 
184
- /**
185
- * Alias for _sortBy with descending order.
186
- */
187
- export function _sortDescBy<T>(items: T[], mapper: Mapper<T, any>, mutate = false): T[] {
188
- return _sortBy(items, mapper, mutate, 'desc')
189
- }
190
-
191
218
  /**
192
219
  * Similar to `Array.find`, but the `predicate` may return `END` to stop the iteration early.
193
220
  *
194
221
  * Use `Array.find` if you don't need to stop the iteration early.
195
222
  */
196
223
  export function _find<T>(items: readonly T[], predicate: AbortablePredicate<T>): T | undefined {
197
- for (const [i, item] of items.entries()) {
224
+ for (let i = 0; i < items.length; i++) {
225
+ const item = items[i]!
198
226
  const result = predicate(item, i)
199
227
  if (result === END) return
200
228
  if (result) return item
@@ -290,9 +318,8 @@ export function _count<T>(
290
318
  export function _countBy<T>(items: Iterable<T>, mapper: Mapper<T, any>): StringMap<number> {
291
319
  const map: StringMap<number> = {}
292
320
 
293
- let i = 0
294
321
  for (const item of items) {
295
- const key = mapper(item, i++)
322
+ const key = mapper(item)
296
323
  map[key] = (map[key] || 0) + 1
297
324
  }
298
325
 
@@ -360,10 +387,9 @@ export function _sumBy<T, N extends number>(
360
387
  mapper: Mapper<T, N | undefined>,
361
388
  ): N {
362
389
  let sum = 0 as N
363
- let i = 0
364
390
 
365
391
  for (const n of items) {
366
- const v = mapper(n, i++)
392
+ const v = mapper(n)
367
393
  if (typeof v === 'number') {
368
394
  // count only numbers, nothing else
369
395
  sum = (sum + v) as N
@@ -407,8 +433,8 @@ export function _mapToObject<T, V>(
407
433
  * Fisher–Yates algorithm.
408
434
  * Based on: https://stackoverflow.com/a/12646864/4919972
409
435
  */
410
- export function _shuffle<T>(array: T[], mutate = false): T[] {
411
- const a = mutate ? array : [...array]
436
+ export function _shuffle<T>(array: T[], opt: MutateOptions = {}): T[] {
437
+ const a = opt.mutate ? array : [...array]
412
438
 
413
439
  for (let i = a.length - 1; i > 0; i--) {
414
440
  const j = Math.floor(Math.random() * (i + 1))
@@ -505,8 +531,9 @@ export function _maxByOrUndefined<T>(
505
531
  let maxItem: T | undefined
506
532
  let max: number | string | undefined
507
533
 
508
- for (const [i, item] of array.entries()) {
509
- const v = mapper(item, i)
534
+ for (let i = 0; i < array.length; i++) {
535
+ const item = array[i]!
536
+ const v = mapper(item)
510
537
  if (v !== undefined && (max === undefined || v > max)) {
511
538
  maxItem = item
512
539
  max = v
@@ -524,8 +551,9 @@ export function _minByOrUndefined<T>(
524
551
  let minItem: T | undefined
525
552
  let min: number | string | undefined
526
553
 
527
- for (const [i, item] of array.entries()) {
528
- const v = mapper(item, i)
554
+ for (let i = 0; i < array.length; i++) {
555
+ const item = array[i]!
556
+ const v = mapper(item)
529
557
  if (v !== undefined && (min === undefined || v < min)) {
530
558
  minItem = item
531
559
  min = v
@@ -1,4 +1,4 @@
1
- import type { Inclusiveness, IsoDate } from '../types.js'
1
+ import type { IsoDate } from '../types.js'
2
2
  import type { LocalDate, LocalDateInput, LocalDateUnit } from './localDate.js'
3
3
  import { localDate } from './localDate.js'
4
4
 
@@ -60,16 +60,13 @@ export class DateInterval {
60
60
  /**
61
61
  * Ranges of DateInterval (start, end) are INCLUSIVE.
62
62
  */
63
- includes(d: LocalDateInput, incl: Inclusiveness = '[]'): boolean {
64
- d = localDate(d)
65
- // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
66
- return d.isAfter(this.start, incl[0] === '[') && d.isBefore(this.end, incl[1] === ']')
63
+ includes(d: LocalDateInput): boolean {
64
+ return localDate(d).isBetween(this.start, this.end, '[]')
67
65
  }
68
66
 
69
- intersects(int: DateIntervalConfig, inclusive = true): boolean {
67
+ intersects(int: DateIntervalConfig): boolean {
70
68
  const $int = DateInterval.parse(int)
71
- const incl = inclusive ? '[]' : '()'
72
- return this.includes($int.start, incl) || this.includes($int.end, incl)
69
+ return this.includes($int.start) || this.includes($int.end)
73
70
  }
74
71
 
75
72
  /**
@@ -81,15 +78,15 @@ export class DateInterval {
81
78
  return this.start.compare(d.start) || this.end.compare(d.end)
82
79
  }
83
80
 
84
- getDays(incl: Inclusiveness = '[]'): LocalDate[] {
85
- return localDate.range(this.start, this.end, incl, 1, 'day')
81
+ getDays(): LocalDate[] {
82
+ return localDate.range(this.start, this.end, '[]', 1, 'day')
86
83
  }
87
84
 
88
85
  /**
89
86
  * Returns an array of LocalDates that are included in the interval.
90
87
  */
91
- range(incl: Inclusiveness = '[]', step = 1, stepUnit: LocalDateUnit = 'day'): LocalDate[] {
92
- return localDate.range(this.start, this.end, incl, step, stepUnit)
88
+ range(step = 1, stepUnit: LocalDateUnit = 'day'): LocalDate[] {
89
+ return localDate.range(this.start, this.end, '[]', step, stepUnit)
93
90
  }
94
91
 
95
92
  toString(): DateIntervalString {
@@ -1,3 +1,4 @@
1
+ import type { MutateOptions, SortOptions } from '../array/array.util.js'
1
2
  import { _assert } from '../error/assert.js'
2
3
  import { Iterable2 } from '../iter/iterable2.js'
3
4
  import type {
@@ -5,7 +6,6 @@ import type {
5
6
  IsoDate,
6
7
  IsoDateTime,
7
8
  MonthId,
8
- SortDirection,
9
9
  UnixTimestamp,
10
10
  UnixTimestampMillis,
11
11
  } from '../types.js'
@@ -41,8 +41,8 @@ export class LocalDate {
41
41
  return unit === 'year' ? this.year : unit === 'month' ? this.month : this.day
42
42
  }
43
43
 
44
- set(unit: LocalDateUnitStrict, v: number, mutate = false): LocalDate {
45
- const t = mutate ? this : this.clone()
44
+ set(unit: LocalDateUnitStrict, v: number, opt: MutateOptions = {}): LocalDate {
45
+ const t = opt.mutate ? this : this.clone()
46
46
 
47
47
  if (unit === 'year') {
48
48
  t.year = v
@@ -117,10 +117,9 @@ export class LocalDate {
117
117
  return this.compare(d) >= 0
118
118
  }
119
119
 
120
- isBetween(min: LocalDateInput, max: LocalDateInput, incl: Inclusiveness = '[)'): boolean {
120
+ isBetween(min: LocalDateInput, max: LocalDateInput, incl: Inclusiveness): boolean {
121
121
  let r = this.compare(min)
122
- // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
123
- if (r < 0 || (r === 0 && incl[0] === '(')) return false
122
+ if (r < 0) return false
124
123
  r = this.compare(max)
125
124
  if (r > 0 || (r === 0 && incl[1] === ')')) return false
126
125
  return true
@@ -326,7 +325,7 @@ export class LocalDate {
326
325
  return this.plus(-num, 'year')
327
326
  }
328
327
 
329
- plus(num: number, unit: LocalDateUnit, mutate = false): LocalDate {
328
+ plus(num: number, unit: LocalDateUnit, opt: MutateOptions = {}): LocalDate {
330
329
  num = Math.floor(num) // if a fractional number like 0.5 is passed - it will be floored, as LocalDate only deals with "whole days" as minimal unit
331
330
  let { day, month, year } = this
332
331
 
@@ -387,7 +386,7 @@ export class LocalDate {
387
386
  }
388
387
  }
389
388
 
390
- if (mutate) {
389
+ if (opt.mutate) {
391
390
  this.year = year
392
391
  this.month = month
393
392
  this.day = day
@@ -397,8 +396,8 @@ export class LocalDate {
397
396
  return new LocalDate(year, month, day)
398
397
  }
399
398
 
400
- minus(num: number, unit: LocalDateUnit, mutate = false): LocalDate {
401
- return this.plus(-num, unit, mutate)
399
+ minus(num: number, unit: LocalDateUnit, opt: MutateOptions = {}): LocalDate {
400
+ return this.plus(-num, unit, opt)
402
401
  }
403
402
 
404
403
  startOf(unit: LocalDateUnitStrict): LocalDate {
@@ -717,9 +716,9 @@ class LocalDateFactory {
717
716
  /**
718
717
  * Sorts an array of LocalDates in `dir` order (ascending by default).
719
718
  */
720
- sort(items: LocalDate[], dir: SortDirection = 'asc', mutate = false): LocalDate[] {
721
- const mod = dir === 'desc' ? -1 : 1
722
- return (mutate ? items : [...items]).sort((a, b) => a.compare(b) * mod)
719
+ sort(items: LocalDate[], opt: SortOptions = {}): LocalDate[] {
720
+ const mod = opt.dir === 'desc' ? -1 : 1
721
+ return (opt.mutate ? items : [...items]).sort((a, b) => a.compare(b) * mod)
723
722
  }
724
723
 
725
724
  /**
@@ -779,7 +778,7 @@ class LocalDateFactory {
779
778
  range(
780
779
  min: LocalDateInput,
781
780
  max: LocalDateInput,
782
- incl: Inclusiveness = '[)',
781
+ incl: Inclusiveness,
783
782
  step = 1,
784
783
  stepUnit: LocalDateUnit = 'day',
785
784
  ): LocalDate[] {
@@ -793,7 +792,7 @@ class LocalDateFactory {
793
792
  rangeIterable(
794
793
  min: LocalDateInput,
795
794
  max: LocalDateInput,
796
- incl: Inclusiveness = '[)',
795
+ incl: Inclusiveness,
797
796
  step = 1,
798
797
  stepUnit: LocalDateUnit = 'day',
799
798
  ): Iterable2<LocalDate> {
@@ -806,11 +805,11 @@ class LocalDateFactory {
806
805
  const $max = this.fromInput(max).startOf(stepUnit)
807
806
 
808
807
  let value = $min
809
- // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
810
- if (value.isAfter($min, incl[0] === '[')) {
808
+
809
+ if (value.isSameOrAfter($min)) {
811
810
  // ok
812
811
  } else {
813
- value.plus(1, stepUnit, true)
812
+ value.plus(1, stepUnit, { mutate: true })
814
813
  }
815
814
 
816
815
  const rightInclusive = incl[1] === ']'
@@ -1,3 +1,4 @@
1
+ import type { MutateOptions } from '../array/array.util.js'
1
2
  import { _assert } from '../error/assert.js'
2
3
  import { _ms } from '../time/time.util.js'
3
4
  import type {
@@ -189,8 +190,8 @@ export class LocalTime {
189
190
  return this.$date.getSeconds()
190
191
  }
191
192
 
192
- set(unit: LocalTimeUnit, v: number, mutate = false): LocalTime {
193
- const t = mutate ? this : this.clone()
193
+ set(unit: LocalTimeUnit, v: number, opt: MutateOptions = {}): LocalTime {
194
+ const t = opt.mutate ? this : this.clone()
194
195
 
195
196
  if (unit === 'year') {
196
197
  t.$date.setFullYear(v)
@@ -205,7 +206,7 @@ export class LocalTime {
205
206
  } else if (unit === 'second') {
206
207
  t.$date.setSeconds(v)
207
208
  } else if (unit === 'week') {
208
- setWeek(t.$date, v, true)
209
+ setWeek(t.$date, v, { mutate: true })
209
210
  }
210
211
 
211
212
  return t
@@ -297,8 +298,8 @@ export class LocalTime {
297
298
  return this.plus(delta, 'day')
298
299
  }
299
300
 
300
- setComponents(c: Partial<DateTimeObject>, mutate = false): LocalTime {
301
- const d = mutate ? this.$date : new Date(this.$date)
301
+ setComponents(c: Partial<DateTimeObject>, opt: MutateOptions = {}): LocalTime {
302
+ const d = opt.mutate ? this.$date : new Date(this.$date)
302
303
 
303
304
  // Year, month and day set all-at-once, to avoid 30/31 (and 28/29) mishap
304
305
  if (c.day || c.month !== undefined || c.year !== undefined) {
@@ -319,7 +320,7 @@ export class LocalTime {
319
320
  d.setSeconds(c.second)
320
321
  }
321
322
 
322
- return mutate ? this : new LocalTime(d)
323
+ return opt.mutate ? this : new LocalTime(d)
323
324
  }
324
325
 
325
326
  plusSeconds(num: number): LocalTime {
@@ -378,22 +379,22 @@ export class LocalTime {
378
379
  return this.plus(-num, 'year')
379
380
  }
380
381
 
381
- plus(num: number, unit: LocalTimeUnit, mutate = false): LocalTime {
382
+ plus(num: number, unit: LocalTimeUnit, opt: MutateOptions = {}): LocalTime {
382
383
  if (unit === 'week') {
383
384
  num *= 7
384
385
  unit = 'day'
385
386
  }
386
387
 
387
388
  if (unit === 'year' || unit === 'month') {
388
- const d = addMonths(this.$date, unit === 'month' ? num : num * 12, mutate)
389
- return mutate ? this : localTime.fromInput(d)
389
+ const d = addMonths(this.$date, unit === 'month' ? num : num * 12, opt)
390
+ return opt.mutate ? this : localTime.fromInput(d)
390
391
  }
391
392
 
392
- return this.set(unit, this.get(unit) + num, mutate)
393
+ return this.set(unit, this.get(unit) + num, opt)
393
394
  }
394
395
 
395
- minus(num: number, unit: LocalTimeUnit, mutate = false): LocalTime {
396
- return this.plus(num * -1, unit, mutate)
396
+ minus(num: number, unit: LocalTimeUnit, opt: MutateOptions = {}): LocalTime {
397
+ return this.plus(num * -1, unit, opt)
397
398
  }
398
399
 
399
400
  absDiff(other: LocalTimeInput, unit: LocalTimeUnit): number {
@@ -429,9 +430,9 @@ export class LocalTime {
429
430
  return Math.trunc(r) || 0
430
431
  }
431
432
 
432
- startOf(unit: LocalTimeUnit, mutate = false): LocalTime {
433
+ startOf(unit: LocalTimeUnit, opt: MutateOptions = {}): LocalTime {
433
434
  if (unit === 'second') return this
434
- const d = mutate ? this.$date : new Date(this.$date)
435
+ const d = opt.mutate ? this.$date : new Date(this.$date)
435
436
  d.setSeconds(0, 0)
436
437
 
437
438
  if (unit !== 'minute') {
@@ -448,18 +449,18 @@ export class LocalTime {
448
449
  d.setDate(1)
449
450
  } else {
450
451
  // week
451
- startOfWeek(d, true)
452
+ startOfWeek(d, { mutate: true })
452
453
  }
453
454
  }
454
455
  }
455
456
  }
456
457
 
457
- return mutate ? this : new LocalTime(d)
458
+ return opt.mutate ? this : new LocalTime(d)
458
459
  }
459
460
 
460
- endOf(unit: LocalTimeUnit, mutate = false): LocalTime {
461
+ endOf(unit: LocalTimeUnit, opt: MutateOptions = {}): LocalTime {
461
462
  if (unit === 'second') return this
462
- const d = mutate ? this.$date : new Date(this.$date)
463
+ const d = opt.mutate ? this.$date : new Date(this.$date)
463
464
  d.setSeconds(59, 0)
464
465
 
465
466
  if (unit !== 'minute') {
@@ -474,7 +475,7 @@ export class LocalTime {
474
475
  }
475
476
 
476
477
  if (unit === 'week') {
477
- endOfWeek(d, true)
478
+ endOfWeek(d, { mutate: true })
478
479
  } else {
479
480
  // year or month
480
481
  const lastDay = localDate.getMonthLength(d.getFullYear(), d.getMonth() + 1)
@@ -484,7 +485,7 @@ export class LocalTime {
484
485
  }
485
486
  }
486
487
 
487
- return mutate ? this : new LocalTime(d)
488
+ return opt.mutate ? this : new LocalTime(d)
488
489
  }
489
490
 
490
491
  /**
@@ -517,10 +518,9 @@ export class LocalTime {
517
518
  return this.compare(d) >= 0
518
519
  }
519
520
 
520
- isBetween(min: LocalTimeInput, max: LocalTimeInput, incl: Inclusiveness = '[)'): boolean {
521
+ isBetween(min: LocalTimeInput, max: LocalTimeInput, incl: Inclusiveness): boolean {
521
522
  let r = this.compare(min)
522
- // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
523
- if (r < 0 || (r === 0 && incl[0] === '(')) return false
523
+ if (r < 0) return false
524
524
  r = this.compare(max)
525
525
  if (r > 0 || (r === 0 && incl[1] === ')')) return false
526
526
  return true
@@ -1004,9 +1004,9 @@ class LocalTimeFactory {
1004
1004
  return Intl.supportedValuesOf('timeZone').includes(tz)
1005
1005
  }
1006
1006
 
1007
- sort(items: LocalTime[], dir: SortDirection = 'asc', mutate = false): LocalTime[] {
1007
+ sort(items: LocalTime[], dir: SortDirection = 'asc', opt: MutateOptions = {}): LocalTime[] {
1008
1008
  const mod = dir === 'desc' ? -1 : 1
1009
- return (mutate ? items : [...items]).sort((a, b) => {
1009
+ return (opt.mutate ? items : [...items]).sort((a, b) => {
1010
1010
  const v1 = a.$date.valueOf()
1011
1011
  const v2 = b.$date.valueOf()
1012
1012
  if (v1 === v2) return 0
@@ -1057,8 +1057,8 @@ function getWeek(date: Date): number {
1057
1057
  return Math.round(diff / MILLISECONDS_IN_WEEK) + 1
1058
1058
  }
1059
1059
 
1060
- function setWeek(date: Date, week: number, mutate = false): Date {
1061
- const d = mutate ? date : new Date(date)
1060
+ function setWeek(date: Date, week: number, opt: MutateOptions = {}): Date {
1061
+ const d = opt.mutate ? date : new Date(date)
1062
1062
  const diff = getWeek(d) - week
1063
1063
  d.setDate(d.getDate() - diff * 7)
1064
1064
  return d
@@ -1070,7 +1070,7 @@ function startOfWeekYear(date: Date): Date {
1070
1070
  const fourthOfJanuary = new Date(0)
1071
1071
  fourthOfJanuary.setFullYear(year, 0, 4)
1072
1072
  fourthOfJanuary.setHours(0, 0, 0, 0)
1073
- return startOfWeek(fourthOfJanuary, true)
1073
+ return startOfWeek(fourthOfJanuary, { mutate: true })
1074
1074
  }
1075
1075
 
1076
1076
  // based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/getISOWeekYear/index.ts
@@ -1080,12 +1080,12 @@ function getWeekYear(date: Date): number {
1080
1080
  const fourthOfJanuaryOfNextYear = new Date(0)
1081
1081
  fourthOfJanuaryOfNextYear.setFullYear(year + 1, 0, 4)
1082
1082
  fourthOfJanuaryOfNextYear.setHours(0, 0, 0, 0)
1083
- const startOfNextYear = startOfWeek(fourthOfJanuaryOfNextYear, true)
1083
+ const startOfNextYear = startOfWeek(fourthOfJanuaryOfNextYear, { mutate: true })
1084
1084
 
1085
1085
  const fourthOfJanuaryOfThisYear = new Date(0)
1086
1086
  fourthOfJanuaryOfThisYear.setFullYear(year, 0, 4)
1087
1087
  fourthOfJanuaryOfThisYear.setHours(0, 0, 0, 0)
1088
- const startOfThisYear = startOfWeek(fourthOfJanuaryOfThisYear, true)
1088
+ const startOfThisYear = startOfWeek(fourthOfJanuaryOfThisYear, { mutate: true })
1089
1089
 
1090
1090
  if (date.getTime() >= startOfNextYear.getTime()) {
1091
1091
  return year + 1
@@ -1097,8 +1097,8 @@ function getWeekYear(date: Date): number {
1097
1097
  }
1098
1098
 
1099
1099
  // based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
1100
- function startOfWeek(date: Date, mutate = false): Date {
1101
- const d = mutate ? date : new Date(date)
1100
+ function startOfWeek(date: Date, opt: MutateOptions = {}): Date {
1101
+ const d = opt.mutate ? date : new Date(date)
1102
1102
 
1103
1103
  const day = d.getDay()
1104
1104
  const diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn
@@ -1109,8 +1109,8 @@ function startOfWeek(date: Date, mutate = false): Date {
1109
1109
  }
1110
1110
 
1111
1111
  // based on: https://github.com/date-fns/date-fns/blob/master/src/endOfWeek/index.ts
1112
- function endOfWeek(date: Date, mutate = false): Date {
1113
- const d = mutate ? date : new Date(date)
1112
+ function endOfWeek(date: Date, opt: MutateOptions = {}): Date {
1113
+ const d = opt.mutate ? date : new Date(date)
1114
1114
 
1115
1115
  const day = d.getDay()
1116
1116
  const diff = (day < weekStartsOn ? -7 : 0) + 6 - (day - weekStartsOn)
@@ -1119,8 +1119,8 @@ function endOfWeek(date: Date, mutate = false): Date {
1119
1119
  return d
1120
1120
  }
1121
1121
 
1122
- function addMonths(d: Date, num: number, mutate = false): Date {
1123
- if (!mutate) d = new Date(d)
1122
+ function addMonths(d: Date, num: number, opt: MutateOptions = {}): Date {
1123
+ if (!opt.mutate) d = new Date(d)
1124
1124
 
1125
1125
  let day = d.getDate()
1126
1126
  let month = d.getMonth() + 1 + num
@@ -1,4 +1,4 @@
1
- import type { Inclusiveness, UnixTimestamp } from '../types.js'
1
+ import type { UnixTimestamp } from '../types.js'
2
2
  import type { LocalTime, LocalTimeInput } from './localTime.js'
3
3
  import { localTime } from './localTime.js'
4
4
 
@@ -74,11 +74,10 @@ export class TimeInterval {
74
74
  return this.cmp(d) >= 0
75
75
  }
76
76
 
77
- includes(d: LocalTimeInput, incl: Inclusiveness = '[)'): boolean {
77
+ includes(d: LocalTimeInput): boolean {
78
78
  d = localTime.fromInput(d).unix
79
- // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
80
- if (d < this.$start || (d === this.$start && incl[0] === '(')) return false
81
- if (d > this.$end || (d === this.$end && incl[1] === ')')) return false
79
+ if (d < this.$start) return false
80
+ if (d > this.$end) return false
82
81
  return true
83
82
  }
84
83
 
@@ -803,7 +803,7 @@ export class Fetcher {
803
803
  }
804
804
 
805
805
  // Because all header values are stringified, so `a: undefined` becomes `undefined` as a string
806
- _filterNullishValues(req.init.headers, true)
806
+ _filterNullishValues(req.init.headers, { mutate: true })
807
807
 
808
808
  // setup url
809
809
  const baseUrl = opt.baseUrl || this.cfg.baseUrl
@@ -32,5 +32,5 @@ export function mergeJsonSchemaObjects<T1 extends AnyObject, T2 extends AnyObjec
32
32
 
33
33
  // `additionalProperties` remains the same
34
34
 
35
- return _filterNullishValues(s1, true) as any
35
+ return _filterNullishValues(s1, { mutate: true }) as any
36
36
  }
@@ -1,4 +1,6 @@
1
1
  // copy-pasted to avoid weird circular dependency
2
+ import type { MutateOptions } from '../array/array.util.js'
3
+
2
4
  const _noop = (..._args: any[]): undefined => undefined
3
5
 
4
6
  /**
@@ -57,10 +59,10 @@ export const commonLoggerNoop: CommonLogger = {
57
59
  export function commonLoggerMinLevel(
58
60
  logger: CommonLogger,
59
61
  minLevel: CommonLogLevel,
60
- mutate = false,
62
+ opt: MutateOptions = {},
61
63
  ): CommonLogger {
62
64
  const level = commonLogLevelNumber[minLevel]
63
- if (mutate) {
65
+ if (opt.mutate) {
64
66
  if (level > commonLogLevelNumber['log']) {
65
67
  logger.log = _noop
66
68
  if (level > commonLogLevelNumber['warn']) {
@@ -29,7 +29,6 @@ export function _averageOrNull(values: number[] | undefined | null): number | nu
29
29
  export function _averageWeighted(values: number[], weights: number[]): number {
30
30
  let numerator = 0
31
31
  let denominator = 0
32
- // eslint-disable-next-line unicorn/no-for-loop
33
32
  for (let i = 0; i < values.length; i++) {
34
33
  numerator += values[i]! * weights[i]!
35
34
  denominator += weights[i]!