@naturalcycles/js-lib 14.237.0 → 14.239.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.
@@ -57,6 +57,10 @@ export declare class LocalDate {
57
57
  * Checks if this localDate is same or younger (>=) than "today" by X units.
58
58
  */
59
59
  isSameOrYoungerThan(n: number, unit: LocalDateUnit, today?: LocalDateInput): boolean;
60
+ getAgeInYears(today?: LocalDateInput): number;
61
+ getAgeInMonths(today?: LocalDateInput): number;
62
+ getAgeInDays(today?: LocalDateInput): number;
63
+ getAgeIn(unit: LocalDateUnit, today?: LocalDateInput): number;
60
64
  /**
61
65
  * Returns 1 if this > d
62
66
  * returns 0 if they are equal
@@ -108,6 +108,18 @@ class LocalDate {
108
108
  isSameOrYoungerThan(n, unit, today) {
109
109
  return this.isSameOrAfter(exports.localDate.of(today || new Date()).plus(-n, unit));
110
110
  }
111
+ getAgeInYears(today) {
112
+ return this.getAgeIn('year', today);
113
+ }
114
+ getAgeInMonths(today) {
115
+ return this.getAgeIn('month', today);
116
+ }
117
+ getAgeInDays(today) {
118
+ return this.getAgeIn('day', today);
119
+ }
120
+ getAgeIn(unit, today) {
121
+ return exports.localDate.of(today || new Date()).diff(this, unit);
122
+ }
111
123
  /**
112
124
  * Returns 1 if this > d
113
125
  * returns 0 if they are equal
@@ -163,6 +163,13 @@ export declare class LocalTime {
163
163
  * Checks if this localTime is same or younger (>=) than "now" by X units.
164
164
  */
165
165
  isSameOrYoungerThan(n: number, unit: LocalTimeUnit, now?: LocalTimeInput): boolean;
166
+ getAgeInYears(now?: LocalTimeInput): number;
167
+ getAgeInMonths(now?: LocalTimeInput): number;
168
+ getAgeInDays(now?: LocalTimeInput): number;
169
+ getAgeInHours(now?: LocalTimeInput): number;
170
+ getAgeInMinutes(now?: LocalTimeInput): number;
171
+ getAgeInSeconds(now?: LocalTimeInput): number;
172
+ getAgeIn(unit: LocalTimeUnit, now?: LocalTimeInput): number;
166
173
  /**
167
174
  * Returns 1 if this > d
168
175
  * returns 0 if they are equal
@@ -418,6 +418,27 @@ class LocalTime {
418
418
  isSameOrYoungerThan(n, unit, now) {
419
419
  return this.isSameOrAfter(exports.localTime.of(now ?? new Date()).plus(-n, unit));
420
420
  }
421
+ getAgeInYears(now) {
422
+ return this.getAgeIn('year', now);
423
+ }
424
+ getAgeInMonths(now) {
425
+ return this.getAgeIn('month', now);
426
+ }
427
+ getAgeInDays(now) {
428
+ return this.getAgeIn('day', now);
429
+ }
430
+ getAgeInHours(now) {
431
+ return this.getAgeIn('hour', now);
432
+ }
433
+ getAgeInMinutes(now) {
434
+ return this.getAgeIn('minute', now);
435
+ }
436
+ getAgeInSeconds(now) {
437
+ return this.getAgeIn('second', now);
438
+ }
439
+ getAgeIn(unit, now) {
440
+ return exports.localTime.of(now ?? new Date()).diff(this, unit);
441
+ }
421
442
  /**
422
443
  * Returns 1 if this > d
423
444
  * returns 0 if they are equal
package/dist/semver.d.ts CHANGED
@@ -18,12 +18,10 @@ export type SemverTokens = [major: number, minor: number, patch: number];
18
18
  */
19
19
  export declare class Semver {
20
20
  tokens: SemverTokens;
21
- private constructor();
21
+ constructor(tokens: SemverTokens);
22
22
  get major(): number;
23
23
  get minor(): number;
24
24
  get patch(): number;
25
- static of(input: SemverInput): Semver;
26
- static parseOrNull(input: SemverInput | undefined | null): Semver | null;
27
25
  isAfter: (other: SemverInput) => boolean;
28
26
  isSameOrAfter: (other: SemverInput) => boolean;
29
27
  isBefore: (other: SemverInput) => boolean;
@@ -38,10 +36,32 @@ export declare class Semver {
38
36
  toJSON: () => string;
39
37
  toString(): string;
40
38
  }
41
- /**
42
- * Shortcut for Semver.of(input)
43
- */
44
- export declare function _semver(input: SemverInput): Semver;
39
+ declare class SemverFactory {
40
+ of(input: SemverInput): Semver;
41
+ parseOrNull(input: SemverInput | undefined | null): Semver | null;
42
+ /**
43
+ * Returns the highest (max) Semver from the array, or undefined if the array is empty.
44
+ */
45
+ maxOrUndefined(items: SemverInput[]): Semver | undefined;
46
+ /**
47
+ * Returns the highest Semver from the array.
48
+ * Throws if the array is empty.
49
+ */
50
+ max(items: SemverInput[]): Semver;
51
+ /**
52
+ * Returns the lowest (min) Semver from the array, or undefined if the array is empty.
53
+ */
54
+ minOrUndefined(items: SemverInput[]): Semver | undefined;
55
+ /**
56
+ * Returns the lowest Semver from the array.
57
+ * Throws if the array is empty.
58
+ */
59
+ min(items: SemverInput[]): Semver;
60
+ }
61
+ interface SemverFn extends SemverFactory {
62
+ (input: SemverInput): Semver;
63
+ }
64
+ export declare const semver2: SemverFn;
45
65
  /**
46
66
  * Returns 1 if a > b
47
67
  * returns 0 if they are equal
@@ -51,4 +71,5 @@ export declare function _semver(input: SemverInput): Semver;
51
71
  *
52
72
  * Credit: https://stackoverflow.com/a/47159772/4919972
53
73
  */
54
- export declare function _semverCompare(a: string, b: string): -1 | 0 | 1;
74
+ export declare function _quickSemverCompare(a: string, b: string): -1 | 0 | 1;
75
+ export {};
package/dist/semver.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._semverCompare = exports._semver = exports.Semver = void 0;
3
+ exports._quickSemverCompare = exports.semver2 = exports.Semver = void 0;
4
4
  const range_1 = require("./array/range");
5
5
  const assert_1 = require("./error/assert");
6
6
  /**
@@ -38,29 +38,13 @@ class Semver {
38
38
  get patch() {
39
39
  return this.tokens[2];
40
40
  }
41
- static of(input) {
42
- const s = this.parseOrNull(input);
43
- (0, assert_1._assert)(s !== null, `Cannot parse "${input}" into Semver`, {
44
- userFriendly: true,
45
- input,
46
- });
47
- return s;
48
- }
49
- static parseOrNull(input) {
50
- if (!input)
51
- return null;
52
- if (input instanceof Semver)
53
- return input;
54
- const t = input.split('.');
55
- return new Semver((0, range_1._range)(3).map(i => parseInt(t[i]) || 0));
56
- }
57
41
  /**
58
42
  * Returns 1 if this > other
59
43
  * returns 0 if they are equal
60
44
  * returns -1 if this < other
61
45
  */
62
46
  cmp(other) {
63
- const { tokens } = Semver.of(other);
47
+ const { tokens } = exports.semver2.of(other);
64
48
  for (let i = 0; i < 3; i++) {
65
49
  if (this.tokens[i] < tokens[i])
66
50
  return -1;
@@ -74,13 +58,57 @@ class Semver {
74
58
  }
75
59
  }
76
60
  exports.Semver = Semver;
77
- /**
78
- * Shortcut for Semver.of(input)
79
- */
80
- function _semver(input) {
81
- return Semver.of(input);
61
+ class SemverFactory {
62
+ of(input) {
63
+ const s = this.parseOrNull(input);
64
+ (0, assert_1._assert)(s !== null, `Cannot parse "${input}" into Semver`, {
65
+ userFriendly: true,
66
+ input,
67
+ });
68
+ return s;
69
+ }
70
+ parseOrNull(input) {
71
+ if (!input)
72
+ return null;
73
+ if (input instanceof Semver)
74
+ return input;
75
+ const t = input.split('.');
76
+ return new Semver((0, range_1._range)(3).map(i => parseInt(t[i]) || 0));
77
+ }
78
+ /**
79
+ * Returns the highest (max) Semver from the array, or undefined if the array is empty.
80
+ */
81
+ maxOrUndefined(items) {
82
+ return items.length ? this.max(items) : undefined;
83
+ }
84
+ /**
85
+ * Returns the highest Semver from the array.
86
+ * Throws if the array is empty.
87
+ */
88
+ max(items) {
89
+ (0, assert_1._assert)(items.length, 'semver.max called on empty array');
90
+ return items.map(i => this.of(i)).reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
91
+ }
92
+ /**
93
+ * Returns the lowest (min) Semver from the array, or undefined if the array is empty.
94
+ */
95
+ minOrUndefined(items) {
96
+ return items.length ? this.min(items) : undefined;
97
+ }
98
+ /**
99
+ * Returns the lowest Semver from the array.
100
+ * Throws if the array is empty.
101
+ */
102
+ min(items) {
103
+ (0, assert_1._assert)(items.length, 'semver.min called on empty array');
104
+ return items.map(i => this.of(i)).reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
105
+ }
82
106
  }
83
- exports._semver = _semver;
107
+ const semverFactory = new SemverFactory();
108
+ exports.semver2 = semverFactory.of.bind(semverFactory);
109
+ // The line below is the blackest of black magic I have ever written in 2024.
110
+ // And probably 2023 as well.
111
+ Object.setPrototypeOf(exports.semver2, semverFactory);
84
112
  /**
85
113
  * Returns 1 if a > b
86
114
  * returns 0 if they are equal
@@ -90,7 +118,7 @@ exports._semver = _semver;
90
118
  *
91
119
  * Credit: https://stackoverflow.com/a/47159772/4919972
92
120
  */
93
- function _semverCompare(a, b) {
121
+ function _quickSemverCompare(a, b) {
94
122
  const t1 = a.split('.');
95
123
  const t2 = b.split('.');
96
124
  const s1 = (0, range_1._range)(3)
@@ -101,4 +129,4 @@ function _semverCompare(a, b) {
101
129
  .join('');
102
130
  return s1 < s2 ? -1 : s1 > s2 ? 1 : 0;
103
131
  }
104
- exports._semverCompare = _semverCompare;
132
+ exports._quickSemverCompare = _quickSemverCompare;
@@ -105,6 +105,18 @@ export class LocalDate {
105
105
  isSameOrYoungerThan(n, unit, today) {
106
106
  return this.isSameOrAfter(localDate.of(today || new Date()).plus(-n, unit));
107
107
  }
108
+ getAgeInYears(today) {
109
+ return this.getAgeIn('year', today);
110
+ }
111
+ getAgeInMonths(today) {
112
+ return this.getAgeIn('month', today);
113
+ }
114
+ getAgeInDays(today) {
115
+ return this.getAgeIn('day', today);
116
+ }
117
+ getAgeIn(unit, today) {
118
+ return localDate.of(today || new Date()).diff(this, unit);
119
+ }
108
120
  /**
109
121
  * Returns 1 if this > d
110
122
  * returns 0 if they are equal
@@ -415,6 +415,27 @@ export class LocalTime {
415
415
  isSameOrYoungerThan(n, unit, now) {
416
416
  return this.isSameOrAfter(localTime.of(now ?? new Date()).plus(-n, unit));
417
417
  }
418
+ getAgeInYears(now) {
419
+ return this.getAgeIn('year', now);
420
+ }
421
+ getAgeInMonths(now) {
422
+ return this.getAgeIn('month', now);
423
+ }
424
+ getAgeInDays(now) {
425
+ return this.getAgeIn('day', now);
426
+ }
427
+ getAgeInHours(now) {
428
+ return this.getAgeIn('hour', now);
429
+ }
430
+ getAgeInMinutes(now) {
431
+ return this.getAgeIn('minute', now);
432
+ }
433
+ getAgeInSeconds(now) {
434
+ return this.getAgeIn('second', now);
435
+ }
436
+ getAgeIn(unit, now) {
437
+ return localTime.of(now ?? new Date()).diff(this, unit);
438
+ }
418
439
  /**
419
440
  * Returns 1 if this > d
420
441
  * returns 0 if they are equal
@@ -35,29 +35,13 @@ export class Semver {
35
35
  get patch() {
36
36
  return this.tokens[2];
37
37
  }
38
- static of(input) {
39
- const s = this.parseOrNull(input);
40
- _assert(s !== null, `Cannot parse "${input}" into Semver`, {
41
- userFriendly: true,
42
- input,
43
- });
44
- return s;
45
- }
46
- static parseOrNull(input) {
47
- if (!input)
48
- return null;
49
- if (input instanceof Semver)
50
- return input;
51
- const t = input.split('.');
52
- return new Semver(_range(3).map(i => parseInt(t[i]) || 0));
53
- }
54
38
  /**
55
39
  * Returns 1 if this > other
56
40
  * returns 0 if they are equal
57
41
  * returns -1 if this < other
58
42
  */
59
43
  cmp(other) {
60
- const { tokens } = Semver.of(other);
44
+ const { tokens } = semver2.of(other);
61
45
  for (let i = 0; i < 3; i++) {
62
46
  if (this.tokens[i] < tokens[i])
63
47
  return -1;
@@ -70,12 +54,57 @@ export class Semver {
70
54
  return this.tokens.join('.');
71
55
  }
72
56
  }
73
- /**
74
- * Shortcut for Semver.of(input)
75
- */
76
- export function _semver(input) {
77
- return Semver.of(input);
57
+ class SemverFactory {
58
+ of(input) {
59
+ const s = this.parseOrNull(input);
60
+ _assert(s !== null, `Cannot parse "${input}" into Semver`, {
61
+ userFriendly: true,
62
+ input,
63
+ });
64
+ return s;
65
+ }
66
+ parseOrNull(input) {
67
+ if (!input)
68
+ return null;
69
+ if (input instanceof Semver)
70
+ return input;
71
+ const t = input.split('.');
72
+ return new Semver(_range(3).map(i => parseInt(t[i]) || 0));
73
+ }
74
+ /**
75
+ * Returns the highest (max) Semver from the array, or undefined if the array is empty.
76
+ */
77
+ maxOrUndefined(items) {
78
+ return items.length ? this.max(items) : undefined;
79
+ }
80
+ /**
81
+ * Returns the highest Semver from the array.
82
+ * Throws if the array is empty.
83
+ */
84
+ max(items) {
85
+ _assert(items.length, 'semver.max called on empty array');
86
+ return items.map(i => this.of(i)).reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
87
+ }
88
+ /**
89
+ * Returns the lowest (min) Semver from the array, or undefined if the array is empty.
90
+ */
91
+ minOrUndefined(items) {
92
+ return items.length ? this.min(items) : undefined;
93
+ }
94
+ /**
95
+ * Returns the lowest Semver from the array.
96
+ * Throws if the array is empty.
97
+ */
98
+ min(items) {
99
+ _assert(items.length, 'semver.min called on empty array');
100
+ return items.map(i => this.of(i)).reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
101
+ }
78
102
  }
103
+ const semverFactory = new SemverFactory();
104
+ export const semver2 = semverFactory.of.bind(semverFactory);
105
+ // The line below is the blackest of black magic I have ever written in 2024.
106
+ // And probably 2023 as well.
107
+ Object.setPrototypeOf(semver2, semverFactory);
79
108
  /**
80
109
  * Returns 1 if a > b
81
110
  * returns 0 if they are equal
@@ -85,7 +114,7 @@ export function _semver(input) {
85
114
  *
86
115
  * Credit: https://stackoverflow.com/a/47159772/4919972
87
116
  */
88
- export function _semverCompare(a, b) {
117
+ export function _quickSemverCompare(a, b) {
89
118
  const t1 = a.split('.');
90
119
  const t2 = b.split('.');
91
120
  const s1 = _range(3)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.237.0",
3
+ "version": "14.239.0",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -21,6 +21,7 @@
21
21
  "@naturalcycles/time-lib": "^3.5.1",
22
22
  "@types/crypto-js": "^4.1.1",
23
23
  "@types/node": "^20.1.0",
24
+ "@types/semver": "^7.5.8",
24
25
  "crypto-js": "^4.1.1",
25
26
  "jest": "^29.0.0",
26
27
  "prettier": "^3.0.0",
@@ -141,6 +141,19 @@ export class LocalDate {
141
141
  return this.isSameOrAfter(localDate.of(today || new Date()).plus(-n, unit))
142
142
  }
143
143
 
144
+ getAgeInYears(today?: LocalDateInput): number {
145
+ return this.getAgeIn('year', today)
146
+ }
147
+ getAgeInMonths(today?: LocalDateInput): number {
148
+ return this.getAgeIn('month', today)
149
+ }
150
+ getAgeInDays(today?: LocalDateInput): number {
151
+ return this.getAgeIn('day', today)
152
+ }
153
+ getAgeIn(unit: LocalDateUnit, today?: LocalDateInput): number {
154
+ return localDate.of(today || new Date()).diff(this, unit)
155
+ }
156
+
144
157
  /**
145
158
  * Returns 1 if this > d
146
159
  * returns 0 if they are equal
@@ -500,6 +500,28 @@ export class LocalTime {
500
500
  return this.isSameOrAfter(localTime.of(now ?? new Date()).plus(-n, unit))
501
501
  }
502
502
 
503
+ getAgeInYears(now?: LocalTimeInput): number {
504
+ return this.getAgeIn('year', now)
505
+ }
506
+ getAgeInMonths(now?: LocalTimeInput): number {
507
+ return this.getAgeIn('month', now)
508
+ }
509
+ getAgeInDays(now?: LocalTimeInput): number {
510
+ return this.getAgeIn('day', now)
511
+ }
512
+ getAgeInHours(now?: LocalTimeInput): number {
513
+ return this.getAgeIn('hour', now)
514
+ }
515
+ getAgeInMinutes(now?: LocalTimeInput): number {
516
+ return this.getAgeIn('minute', now)
517
+ }
518
+ getAgeInSeconds(now?: LocalTimeInput): number {
519
+ return this.getAgeIn('second', now)
520
+ }
521
+ getAgeIn(unit: LocalTimeUnit, now?: LocalTimeInput): number {
522
+ return localTime.of(now ?? new Date()).diff(this, unit)
523
+ }
524
+
503
525
  /**
504
526
  * Returns 1 if this > d
505
527
  * returns 0 if they are equal
package/src/semver.ts CHANGED
@@ -21,7 +21,7 @@ export type SemverTokens = [major: number, minor: number, patch: number]
21
21
  * @experimental
22
22
  */
23
23
  export class Semver {
24
- private constructor(public tokens: SemverTokens) {}
24
+ constructor(public tokens: SemverTokens) {}
25
25
 
26
26
  get major(): number {
27
27
  return this.tokens[0]
@@ -33,25 +33,6 @@ export class Semver {
33
33
  return this.tokens[2]
34
34
  }
35
35
 
36
- static of(input: SemverInput): Semver {
37
- const s = this.parseOrNull(input)
38
-
39
- _assert(s !== null, `Cannot parse "${input}" into Semver`, {
40
- userFriendly: true,
41
- input,
42
- })
43
-
44
- return s
45
- }
46
-
47
- static parseOrNull(input: SemverInput | undefined | null): Semver | null {
48
- if (!input) return null
49
- if (input instanceof Semver) return input
50
-
51
- const t = input.split('.')
52
- return new Semver(_range(3).map(i => parseInt(t[i]!) || 0) as SemverTokens)
53
- }
54
-
55
36
  isAfter = (other: SemverInput): boolean => this.cmp(other) > 0
56
37
  isSameOrAfter = (other: SemverInput): boolean => this.cmp(other) >= 0
57
38
  isBefore = (other: SemverInput): boolean => this.cmp(other) < 0
@@ -64,7 +45,7 @@ export class Semver {
64
45
  * returns -1 if this < other
65
46
  */
66
47
  cmp(other: SemverInput): -1 | 0 | 1 {
67
- const { tokens } = Semver.of(other)
48
+ const { tokens } = semver2.of(other)
68
49
  for (let i = 0; i < 3; i++) {
69
50
  if (this.tokens[i]! < tokens[i]!) return -1
70
51
  if (this.tokens[i]! > tokens[i]!) return 1
@@ -79,13 +60,71 @@ export class Semver {
79
60
  }
80
61
  }
81
62
 
82
- /**
83
- * Shortcut for Semver.of(input)
84
- */
85
- export function _semver(input: SemverInput): Semver {
86
- return Semver.of(input)
63
+ class SemverFactory {
64
+ of(input: SemverInput): Semver {
65
+ const s = this.parseOrNull(input)
66
+
67
+ _assert(s !== null, `Cannot parse "${input}" into Semver`, {
68
+ userFriendly: true,
69
+ input,
70
+ })
71
+
72
+ return s
73
+ }
74
+
75
+ parseOrNull(input: SemverInput | undefined | null): Semver | null {
76
+ if (!input) return null
77
+ if (input instanceof Semver) return input
78
+
79
+ const t = input.split('.')
80
+ return new Semver(_range(3).map(i => parseInt(t[i]!) || 0) as SemverTokens)
81
+ }
82
+
83
+ /**
84
+ * Returns the highest (max) Semver from the array, or undefined if the array is empty.
85
+ */
86
+ maxOrUndefined(items: SemverInput[]): Semver | undefined {
87
+ return items.length ? this.max(items) : undefined
88
+ }
89
+
90
+ /**
91
+ * Returns the highest Semver from the array.
92
+ * Throws if the array is empty.
93
+ */
94
+ max(items: SemverInput[]): Semver {
95
+ _assert(items.length, 'semver.max called on empty array')
96
+ return items.map(i => this.of(i)).reduce((max, item) => (max.isSameOrAfter(item) ? max : item))
97
+ }
98
+
99
+ /**
100
+ * Returns the lowest (min) Semver from the array, or undefined if the array is empty.
101
+ */
102
+ minOrUndefined(items: SemverInput[]): Semver | undefined {
103
+ return items.length ? this.min(items) : undefined
104
+ }
105
+
106
+ /**
107
+ * Returns the lowest Semver from the array.
108
+ * Throws if the array is empty.
109
+ */
110
+ min(items: SemverInput[]): Semver {
111
+ _assert(items.length, 'semver.min called on empty array')
112
+ return items.map(i => this.of(i)).reduce((min, item) => (min.isSameOrBefore(item) ? min : item))
113
+ }
114
+ }
115
+
116
+ interface SemverFn extends SemverFactory {
117
+ (input: SemverInput): Semver
87
118
  }
88
119
 
120
+ const semverFactory = new SemverFactory()
121
+
122
+ export const semver2 = semverFactory.of.bind(semverFactory) as SemverFn
123
+
124
+ // The line below is the blackest of black magic I have ever written in 2024.
125
+ // And probably 2023 as well.
126
+ Object.setPrototypeOf(semver2, semverFactory)
127
+
89
128
  /**
90
129
  * Returns 1 if a > b
91
130
  * returns 0 if they are equal
@@ -95,7 +134,7 @@ export function _semver(input: SemverInput): Semver {
95
134
  *
96
135
  * Credit: https://stackoverflow.com/a/47159772/4919972
97
136
  */
98
- export function _semverCompare(a: string, b: string): -1 | 0 | 1 {
137
+ export function _quickSemverCompare(a: string, b: string): -1 | 0 | 1 {
99
138
  const t1 = a.split('.')
100
139
  const t2 = b.split('.')
101
140
  const s1 = _range(3)