@naturalcycles/js-lib 14.96.0 → 14.97.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.
@@ -1,11 +1,11 @@
1
1
  import { _assert } from '../error/assert'
2
2
  import { _ms } from '../time/time.util'
3
- import { IsoDate, IsoDateTime, UnixTimestamp } from '../types'
3
+ import { IsoDateString, IsoDateTimeString, UnixTimestampNumber } from '../types'
4
4
  import { Inclusiveness, LocalDate } from './localDate'
5
5
 
6
6
  export type LocalTimeUnit = 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second'
7
7
 
8
- export type LocalTimeConfig = LocalTime | Date | IsoDateTime | UnixTimestamp
8
+ export type LocalTimeConfig = LocalTime | Date | IsoDateTimeString | UnixTimestampNumber
9
9
 
10
10
  export interface LocalTimeComponents {
11
11
  year: number
@@ -62,7 +62,7 @@ export class LocalTime {
62
62
  } else if (typeof d === 'number') {
63
63
  date = new Date(d * 1000)
64
64
  } else {
65
- date = new Date(d)
65
+ date = new Date(d.slice(0, 19))
66
66
  }
67
67
 
68
68
  // validation
@@ -78,6 +78,32 @@ export class LocalTime {
78
78
  return new LocalTime(date, false)
79
79
  }
80
80
 
81
+ static parseToDate(d: LocalTimeConfig): Date {
82
+ if (d instanceof LocalTime) return d.$date
83
+ if (d instanceof Date) return d
84
+
85
+ const date = typeof d === 'number' ? new Date(d * 1000) : new Date(d)
86
+
87
+ if (isNaN(date.getDate())) {
88
+ throw new TypeError(`Cannot parse "${d}" to Date`)
89
+ }
90
+
91
+ return date
92
+ }
93
+
94
+ static parseToUnixTimestamp(d: LocalTimeConfig): UnixTimestampNumber {
95
+ if (typeof d === 'number') return d
96
+ if (d instanceof LocalTime) return d.unix()
97
+
98
+ const date = d instanceof Date ? d : new Date(d)
99
+
100
+ if (isNaN(date.getDate())) {
101
+ throw new TypeError(`Cannot parse "${d}" to UnixTimestamp`)
102
+ }
103
+
104
+ return date.valueOf() / 1000
105
+ }
106
+
81
107
  static isValid(d: LocalTimeConfig | undefined | null): boolean {
82
108
  return this.parseOrNull(d) !== null
83
109
  }
@@ -144,9 +170,9 @@ export class LocalTime {
144
170
  month(v?: number): number | LocalTime {
145
171
  return v === undefined ? this.get('month') : this.set('month', v)
146
172
  }
147
- date(): number
148
- date(v: number): LocalTime
149
- date(v?: number): number | LocalTime {
173
+ day(): number
174
+ day(v: number): LocalTime
175
+ day(v?: number): number | LocalTime {
150
176
  return v === undefined ? this.get('day') : this.set('day', v)
151
177
  }
152
178
  hour(): number
@@ -205,7 +231,7 @@ export class LocalTime {
205
231
  }
206
232
 
207
233
  diff(other: LocalTimeConfig, unit: LocalTimeUnit): number {
208
- const date2 = LocalTime.of(other).$date
234
+ const date2 = LocalTime.parseToDate(other)
209
235
 
210
236
  if (unit === 'year') {
211
237
  return this.$date.getFullYear() - date2.getFullYear()
@@ -295,16 +321,18 @@ export class LocalTime {
295
321
  return this.cmp(d) === 0
296
322
  }
297
323
 
298
- isBefore(d: LocalTimeConfig): boolean {
299
- return this.cmp(d) === -1
324
+ isBefore(d: LocalTimeConfig, inclusive = false): boolean {
325
+ const r = this.cmp(d)
326
+ return r === -1 || (r === 0 && inclusive)
300
327
  }
301
328
 
302
329
  isSameOrBefore(d: LocalTimeConfig): boolean {
303
330
  return this.cmp(d) <= 0
304
331
  }
305
332
 
306
- isAfter(d: LocalTimeConfig): boolean {
307
- return this.cmp(d) === 1
333
+ isAfter(d: LocalTimeConfig, inclusive = false): boolean {
334
+ const r = this.cmp(d)
335
+ return r === 1 || (r === 0 && inclusive)
308
336
  }
309
337
 
310
338
  isSameOrAfter(d: LocalTimeConfig): boolean {
@@ -326,7 +354,7 @@ export class LocalTime {
326
354
  */
327
355
  cmp(d: LocalTimeConfig): -1 | 0 | 1 {
328
356
  const t1 = this.$date.valueOf()
329
- const t2 = LocalTime.of(d).$date.valueOf()
357
+ const t2 = LocalTime.parseToDate(d).valueOf()
330
358
  if (t1 === t2) return 0
331
359
  return t1 < t2 ? -1 : 1
332
360
  }
@@ -355,8 +383,8 @@ export class LocalTime {
355
383
  }
356
384
  }
357
385
 
358
- fromNow(now: LocalTimeConfig = LocalTime.now()): string {
359
- const msDiff = LocalTime.of(now).unixMillis() - this.unixMillis()
386
+ fromNow(now: LocalTimeConfig = new Date()): string {
387
+ const msDiff = LocalTime.parseToDate(now).valueOf() - this.$date.valueOf()
360
388
 
361
389
  if (msDiff === 0) return 'now'
362
390
 
@@ -375,7 +403,7 @@ export class LocalTime {
375
403
  return new LocalTime(new Date(this.$date), this.utcMode)
376
404
  }
377
405
 
378
- unix(): UnixTimestamp {
406
+ unix(): UnixTimestampNumber {
379
407
  return Math.floor(this.$date.valueOf() / 1000)
380
408
  }
381
409
 
@@ -383,7 +411,7 @@ export class LocalTime {
383
411
  return this.$date.valueOf()
384
412
  }
385
413
 
386
- valueOf(): UnixTimestamp {
414
+ valueOf(): UnixTimestampNumber {
387
415
  return Math.floor(this.$date.valueOf() / 1000)
388
416
  }
389
417
 
@@ -403,7 +431,7 @@ export class LocalTime {
403
431
  )
404
432
  }
405
433
 
406
- toPretty(seconds = true): IsoDateTime {
434
+ toPretty(seconds = true): IsoDateTimeString {
407
435
  const { year, month, day, hour, minute, second } = this.components()
408
436
 
409
437
  return (
@@ -432,14 +460,14 @@ export class LocalTime {
432
460
  /**
433
461
  * Returns e.g: `1984-06-21T17:56:21`, only the date part of DateTime
434
462
  */
435
- toISODateTime(): IsoDateTime {
463
+ toISODateTime(): IsoDateTimeString {
436
464
  return this.$date.toISOString().slice(0, 19)
437
465
  }
438
466
 
439
467
  /**
440
468
  * Returns e.g: `1984-06-21`, only the date part of DateTime
441
469
  */
442
- toISODate(): IsoDate {
470
+ toISODate(): IsoDateString {
443
471
  const { year, month, day } = this.components()
444
472
 
445
473
  return [
@@ -488,7 +516,7 @@ export class LocalTime {
488
516
  return String(this.unix())
489
517
  }
490
518
 
491
- toJSON(): UnixTimestamp {
519
+ toJSON(): UnixTimestampNumber {
492
520
  return this.unix()
493
521
  }
494
522
  }
@@ -499,5 +527,3 @@ export class LocalTime {
499
527
  export function localTime(d?: LocalTimeConfig): LocalTime {
500
528
  return d ? LocalTime.of(d) : LocalTime.now()
501
529
  }
502
-
503
- // todo: range
@@ -0,0 +1,104 @@
1
+ import { UnixTimestampNumber } from '../types'
2
+ import { Inclusiveness } from './localDate'
3
+ import { LocalTime, LocalTimeConfig } from './localTime'
4
+
5
+ export type TimeIntervalConfig = TimeInterval | TimeIntervalString
6
+ export type TimeIntervalString = string
7
+
8
+ /**
9
+ * Class that supports an "interval of time" between 2 timestamps - start and end.
10
+ * Example: `1649267185/1649267187`.
11
+ *
12
+ * @experimental
13
+ */
14
+ export class TimeInterval {
15
+ private constructor(private $start: UnixTimestampNumber, private $end: UnixTimestampNumber) {}
16
+
17
+ static of(start: LocalTimeConfig, end: LocalTimeConfig): TimeInterval {
18
+ return new TimeInterval(
19
+ LocalTime.parseToUnixTimestamp(start),
20
+ LocalTime.parseToUnixTimestamp(end),
21
+ )
22
+ }
23
+
24
+ get start(): UnixTimestampNumber {
25
+ return this.$start
26
+ }
27
+
28
+ get end(): UnixTimestampNumber {
29
+ return this.$end
30
+ }
31
+
32
+ get startTime(): LocalTime {
33
+ return LocalTime.of(this.$start)
34
+ }
35
+
36
+ get endTime(): LocalTime {
37
+ return LocalTime.of(this.$end)
38
+ }
39
+
40
+ /**
41
+ * Parses string like `1649267185/1649267187` into a TimeInterval.
42
+ */
43
+ static parse(d: TimeIntervalConfig): TimeInterval {
44
+ if (d instanceof TimeInterval) return d
45
+
46
+ const [start, end] = d.split('/').map(Number)
47
+
48
+ if (!end || !start) {
49
+ throw new Error(`Cannot parse "${d}" into TimeInterval`)
50
+ }
51
+
52
+ return new TimeInterval(start, end)
53
+ }
54
+
55
+ isSame(d: TimeIntervalConfig): boolean {
56
+ return this.cmp(d) === 0
57
+ }
58
+
59
+ isBefore(d: TimeIntervalConfig, inclusive = false): boolean {
60
+ const r = this.cmp(d)
61
+ return r === -1 || (r === 0 && inclusive)
62
+ }
63
+
64
+ isSameOrBefore(d: TimeIntervalConfig): boolean {
65
+ return this.cmp(d) <= 0
66
+ }
67
+
68
+ isAfter(d: TimeIntervalConfig, inclusive = false): boolean {
69
+ const r = this.cmp(d)
70
+ return r === 1 || (r === 0 && inclusive)
71
+ }
72
+
73
+ isSameOrAfter(d: TimeIntervalConfig): boolean {
74
+ return this.cmp(d) >= 0
75
+ }
76
+
77
+ includes(d: LocalTimeConfig, incl: Inclusiveness = '[)'): boolean {
78
+ d = LocalTime.parseToUnixTimestamp(d)
79
+ if (d < this.$start || (d === this.$start && incl[0] === '(')) return false
80
+ if (d > this.$end || (d === this.$end && incl[1] === ')')) return false
81
+ return true
82
+ }
83
+
84
+ /**
85
+ * TimeIntervals compare by start date.
86
+ * If it's the same - then by end date.
87
+ */
88
+ cmp(d: TimeIntervalConfig): -1 | 0 | 1 {
89
+ d = TimeInterval.parse(d)
90
+ if (this.$start > d.$start) return 1
91
+ if (this.$start < d.$start) return -1
92
+ if (this.$end > d.$end) return 1
93
+ if (this.$end < d.$end) return -1
94
+ return 0
95
+ }
96
+
97
+ toString(): TimeIntervalString {
98
+ return [this.$start, this.$end].join('/')
99
+ }
100
+
101
+ toJSON(): TimeIntervalString {
102
+ return this.toString()
103
+ }
104
+ }
package/src/error/try.ts CHANGED
@@ -11,13 +11,19 @@ import { AppError } from './app.error'
11
11
  * For convenience, second argument type is non-optional,
12
12
  * so you can use it without `!`. But you SHOULD always check `if (err)` first!
13
13
  *
14
+ * ERR is typed as Error, not `unknown`. While unknown would be more correct,
15
+ * according to recent TypeScript, Error gives more developer convenience.
16
+ * In our code we NEVER throw non-errors.
17
+ * Only possibility of non-error is in the 3rd-party library code, in these cases it
18
+ * can be manually cast to `unknown` for extra safety.
19
+ *
14
20
  * @example
15
21
  *
16
22
  * const [err, v] = _try(() => someFunction())
17
23
  * if (err) ...do something...
18
24
  * v // go ahead and use v
19
25
  */
20
- export function _try<ERR = unknown, RETURN = void>(
26
+ export function _try<ERR = Error, RETURN = void>(
21
27
  fn: () => RETURN,
22
28
  ): [err: ERR | null, value: RETURN] {
23
29
  try {
@@ -33,7 +39,7 @@ export function _try<ERR = unknown, RETURN = void>(
33
39
  * Also, intentionally types second return item as non-optional,
34
40
  * but you should check for `err` presense first!
35
41
  */
36
- export async function pTry<ERR = unknown, RETURN = void>(
42
+ export async function pTry<ERR = Error, RETURN = void>(
37
43
  promise: Promise<RETURN>,
38
44
  ): Promise<[err: ERR | null, value: Awaited<RETURN>]> {
39
45
  try {
@@ -50,7 +56,7 @@ export async function pTry<ERR = unknown, RETURN = void>(
50
56
  */
51
57
  export class UnexpectedPassError extends AppError {
52
58
  constructor() {
53
- super('_expectedError passed unexpectedly')
59
+ super('expected error was not thrown')
54
60
  }
55
61
  }
56
62
 
@@ -1,4 +1,4 @@
1
- import { _since, _stringifyAny, CommonLogger } from '../index'
1
+ import { _anyToError, _since, _stringifyAny, CommonLogger } from '../index'
2
2
  import { AnyFunction } from '../types'
3
3
 
4
4
  export interface TryCatchOptions {
@@ -6,7 +6,7 @@ export interface TryCatchOptions {
6
6
  * The value returned from the function will be returned from the wrapped method (!).
7
7
  * onError function may be asynchronous.
8
8
  */
9
- onError?: (err: unknown) => any
9
+ onError?: (err: Error) => any
10
10
 
11
11
  /**
12
12
  * @default false
@@ -59,7 +59,7 @@ export function _tryCatch<T extends AnyFunction>(fn: T, opt: TryCatchOptions = {
59
59
 
60
60
  if (onError) {
61
61
  try {
62
- return await onError(err) // eslint-disable-line @typescript-eslint/return-await
62
+ return await onError(_anyToError(err)) // eslint-disable-line @typescript-eslint/return-await
63
63
  } catch {}
64
64
  }
65
65
  // returns undefined, but doesn't rethrow
package/src/index.ts CHANGED
@@ -105,7 +105,8 @@ import {
105
105
  BatchResult,
106
106
  InstanceId,
107
107
  IsoDate,
108
- IsoDateTime,
108
+ IsoDateString,
109
+ IsoDateTimeString,
109
110
  KeyValueTuple,
110
111
  Mapper,
111
112
  ObjectMapper,
@@ -117,6 +118,7 @@ import {
117
118
  Reviver,
118
119
  SavedDBEntity,
119
120
  StringMap,
121
+ UnixTimestampNumber,
120
122
  UnixTimestamp,
121
123
  Integer,
122
124
  ValueOf,
@@ -158,13 +160,17 @@ export * from './string/leven'
158
160
  export * from './datetime/localDate'
159
161
  export * from './datetime/localTime'
160
162
  export * from './datetime/dateInterval'
163
+ export * from './datetime/timeInterval'
161
164
  import { LocalDateConfig, LocalDateUnit, Inclusiveness } from './datetime/localDate'
162
165
  import { LocalTimeConfig, LocalTimeUnit, LocalTimeComponents } from './datetime/localTime'
163
166
  import { DateIntervalConfig, DateIntervalString } from './datetime/dateInterval'
167
+ import { TimeIntervalConfig, TimeIntervalString } from './datetime/timeInterval'
164
168
 
165
169
  export type {
166
170
  DateIntervalConfig,
167
171
  DateIntervalString,
172
+ TimeIntervalConfig,
173
+ TimeIntervalString,
168
174
  LocalDateConfig,
169
175
  LocalDateUnit,
170
176
  Inclusiveness,
@@ -197,7 +203,8 @@ export type {
197
203
  ObjectPredicate,
198
204
  InstanceId,
199
205
  IsoDate,
200
- IsoDateTime,
206
+ IsoDateString,
207
+ IsoDateTimeString,
201
208
  Reviver,
202
209
  PMapOptions,
203
210
  Mapper,
@@ -218,6 +225,7 @@ export type {
218
225
  ConditionalPick,
219
226
  ConditionalExcept,
220
227
  Class,
228
+ UnixTimestampNumber,
221
229
  UnixTimestamp,
222
230
  Integer,
223
231
  BaseDBEntity,
package/src/types.ts CHANGED
@@ -150,6 +150,11 @@ export interface InstanceId {
150
150
  *
151
151
  * @example '2019-06-21'
152
152
  */
153
+ export type IsoDateString = string
154
+
155
+ /**
156
+ * @deprecated use IsoDateString
157
+ */
153
158
  export type IsoDate = string
154
159
 
155
160
  /**
@@ -157,13 +162,18 @@ export type IsoDate = string
157
162
  *
158
163
  * @example '2019-06-21T05:21:73Z'
159
164
  */
160
- export type IsoDateTime = string
165
+ export type IsoDateTimeString = string
161
166
 
162
167
  /**
163
168
  * Interface explicitly states that the value is a Unix timestamp (in seconds).
164
169
  *
165
170
  * @example 1628945450
166
171
  */
172
+ export type UnixTimestampNumber = number
173
+
174
+ /**
175
+ * @deprecated use UnixTimestampNumber
176
+ */
167
177
  export type UnixTimestamp = number
168
178
 
169
179
  /**
@@ -180,12 +190,12 @@ export interface SavedDBEntity<ID = string> {
180
190
  /**
181
191
  * unixTimestamp of when the entity was first created (in the DB).
182
192
  */
183
- created: UnixTimestamp
193
+ created: UnixTimestampNumber
184
194
 
185
195
  /**
186
196
  * unixTimestamp of when the entity was last updated (in the DB).
187
197
  */
188
- updated: UnixTimestamp
198
+ updated: UnixTimestampNumber
189
199
  }
190
200
 
191
201
  /**