@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.
- package/dist/datetime/localDate.d.ts +4 -0
- package/dist/datetime/localDate.js +12 -0
- package/dist/datetime/localTime.d.ts +7 -0
- package/dist/datetime/localTime.js +21 -0
- package/dist/semver.d.ts +29 -8
- package/dist/semver.js +54 -26
- package/dist-esm/datetime/localDate.js +12 -0
- package/dist-esm/datetime/localTime.js +21 -0
- package/dist-esm/semver.js +52 -23
- package/package.json +2 -1
- package/src/datetime/localDate.ts +13 -0
- package/src/datetime/localTime.ts +22 -0
- package/src/semver.ts +66 -27
|
@@ -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
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
|
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.
|
|
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 } =
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
package/dist-esm/semver.js
CHANGED
|
@@ -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 } =
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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 } =
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
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)
|