@bgord/tools 0.15.1 → 0.16.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/basename.vo.d.ts +11 -2
- package/dist/basename.vo.js +22 -13
- package/dist/date-calculator.service.d.ts +2 -2
- package/dist/date-calculator.service.js +10 -11
- package/dist/date-range.vo.d.ts +1 -0
- package/dist/date-range.vo.js +2 -1
- package/dist/day-iso-id.vo.d.ts +3 -0
- package/dist/day-iso-id.vo.js +4 -4
- package/dist/day.vo.js +12 -10
- package/dist/directory-path-absolute.vo.d.ts +5 -0
- package/dist/directory-path-absolute.vo.js +11 -5
- package/dist/directory-path-relative.vo.d.ts +6 -0
- package/dist/directory-path-relative.vo.js +12 -6
- package/dist/dll.service.js +37 -31
- package/dist/extension.vo.d.ts +6 -2
- package/dist/extension.vo.js +11 -9
- package/dist/file-path-absolute-schema.vo.d.ts +5 -0
- package/dist/file-path-absolute-schema.vo.js +12 -6
- package/dist/file-path-relative-schema.vo.d.ts +6 -1
- package/dist/file-path-relative-schema.vo.js +10 -6
- package/dist/file-path.vo.js +4 -4
- package/dist/filename-from-string.vo.d.ts +6 -4
- package/dist/filename-from-string.vo.js +15 -14
- package/dist/filename-suffix.vo.d.ts +4 -2
- package/dist/filename-suffix.vo.js +5 -3
- package/dist/filename.vo.d.ts +2 -2
- package/dist/filename.vo.js +9 -9
- package/dist/height.vo.d.ts +6 -4
- package/dist/height.vo.js +56 -51
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/language.vo.d.ts +1 -1
- package/dist/language.vo.js +1 -2
- package/dist/mime.vo.d.ts +3 -1
- package/dist/mime.vo.js +8 -6
- package/dist/month-iso-id.vo.d.ts +3 -0
- package/dist/month-iso-id.vo.js +7 -12
- package/dist/month.vo.js +15 -13
- package/dist/object-key.vo.d.ts +5 -0
- package/dist/object-key.vo.js +16 -6
- package/dist/package-version.vo.d.ts +3 -0
- package/dist/package-version.vo.js +12 -34
- package/dist/pagination.service.d.ts +1 -1
- package/dist/pagination.service.js +11 -11
- package/dist/quarter-iso-id.vo.d.ts +3 -0
- package/dist/quarter-iso-id.vo.js +8 -7
- package/dist/rate-limiter.service.d.ts +3 -2
- package/dist/rate-limiter.service.js +4 -2
- package/dist/reordering.service.d.ts +20 -2
- package/dist/reordering.service.js +49 -29
- package/dist/revision.vo.d.ts +8 -3
- package/dist/revision.vo.js +13 -6
- package/dist/rounding.adapter.js +1 -2
- package/dist/size.vo.d.ts +1 -0
- package/dist/size.vo.js +4 -7
- package/dist/streak-calculator.service.d.ts +3 -4
- package/dist/streak-calculator.service.js +11 -17
- package/dist/time-zone-offset-value.vo.d.ts +1 -1
- package/dist/time-zone-offset-value.vo.js +1 -7
- package/dist/time.service.d.ts +11 -6
- package/dist/time.service.js +31 -18
- package/dist/timezone.vo.js +1 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/week-iso-id.vo.d.ts +3 -0
- package/dist/week-iso-id.vo.js +4 -4
- package/dist/week.vo.js +1 -1
- package/dist/weekday.vo.d.ts +7 -6
- package/dist/weekday.vo.js +20 -13
- package/dist/weight.vo.d.ts +12 -0
- package/dist/weight.vo.js +37 -27
- package/dist/year-iso-id.vo.d.ts +3 -0
- package/dist/year-iso-id.vo.js +4 -6
- package/dist/year.vo.d.ts +2 -0
- package/dist/year.vo.js +4 -2
- package/package.json +1 -1
- package/readme.md +0 -1
- package/src/basename.vo.ts +25 -14
- package/src/clock.vo.ts +1 -0
- package/src/date-calculator.service.ts +10 -15
- package/src/date-range.vo.ts +3 -1
- package/src/day-iso-id.vo.ts +9 -10
- package/src/day.vo.ts +17 -10
- package/src/directory-path-absolute.vo.ts +12 -5
- package/src/directory-path-relative.vo.ts +13 -6
- package/src/dll.service.ts +45 -43
- package/src/extension.vo.ts +14 -12
- package/src/file-path-absolute-schema.vo.ts +15 -6
- package/src/file-path-relative-schema.vo.ts +13 -6
- package/src/file-path.vo.ts +15 -11
- package/src/filename-from-string.vo.ts +20 -15
- package/src/filename-suffix.vo.ts +8 -4
- package/src/filename.vo.ts +14 -15
- package/src/height.vo.ts +71 -53
- package/src/index.ts +0 -1
- package/src/language.vo.ts +1 -2
- package/src/mime.vo.ts +10 -7
- package/src/month-iso-id.vo.ts +10 -20
- package/src/month.vo.ts +19 -13
- package/src/object-key.vo.ts +21 -7
- package/src/outlier-detector.service.ts +1 -0
- package/src/package-version.vo.ts +18 -47
- package/src/pagination.service.ts +15 -13
- package/src/quarter-iso-id.vo.ts +11 -13
- package/src/quarter.vo.ts +3 -0
- package/src/rate-limiter.service.ts +7 -7
- package/src/reordering.service.ts +52 -38
- package/src/revision.vo.ts +17 -8
- package/src/rounding.adapter.ts +1 -3
- package/src/size.vo.ts +6 -16
- package/src/streak-calculator.service.ts +12 -17
- package/src/time-zone-offset-value.vo.ts +2 -7
- package/src/time.service.ts +43 -45
- package/src/timezone.vo.ts +1 -3
- package/src/week-iso-id.vo.ts +13 -14
- package/src/week.vo.ts +4 -2
- package/src/weekday.vo.ts +27 -13
- package/src/weight.vo.ts +49 -30
- package/src/year-iso-id.vo.ts +6 -9
- package/src/year.vo.ts +12 -2
- package/dist/stepper.service.d.ts +0 -23
- package/dist/stepper.service.js +0 -33
- package/src/stepper.service.ts +0 -43
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
+
export declare const ReorderingPositionError: {
|
|
3
|
+
readonly error: "reordering.position.invalid";
|
|
4
|
+
};
|
|
5
|
+
export declare const ReorderingCannotFindItemError: {
|
|
6
|
+
readonly error: "reordering.item.not_found";
|
|
7
|
+
};
|
|
8
|
+
export declare const ReorderingCannotFindCurrentError: {
|
|
9
|
+
readonly error: "reordering.current_item.not_found";
|
|
10
|
+
};
|
|
11
|
+
export declare const ReorderingCannotFindTargetError: {
|
|
12
|
+
readonly error: "reordering.target_item.not_found";
|
|
13
|
+
};
|
|
14
|
+
export declare const ReorderingCorrelationIdError: {
|
|
15
|
+
readonly error: "reordering.correlation_id.invalid";
|
|
16
|
+
};
|
|
17
|
+
export declare const ReorderingItemIdError: {
|
|
18
|
+
readonly error: "reordering.item_id.invalid";
|
|
19
|
+
};
|
|
2
20
|
export declare const ReorderingItemPositionValue: z.ZodNumber;
|
|
3
21
|
export type ReorderingItemPositionValueType = z.infer<typeof ReorderingItemPositionValue>;
|
|
4
22
|
export declare const ReorderingCorrelationId: z.ZodString;
|
|
5
23
|
export type ReorderingCorrelationIdType = z.infer<typeof ReorderingCorrelationId>;
|
|
6
|
-
export declare const ReorderingItemId: z.
|
|
24
|
+
export declare const ReorderingItemId: z.ZodString;
|
|
7
25
|
export type ReorderingItemIdType = z.infer<typeof ReorderingItemId>;
|
|
8
26
|
export declare const Reordering: z.ZodObject<{
|
|
9
27
|
correlationId: z.ZodString;
|
|
10
|
-
id: z.
|
|
28
|
+
id: z.ZodString;
|
|
11
29
|
position: z.ZodNumber;
|
|
12
30
|
}, z.core.$strip>;
|
|
13
31
|
export type ReorderingType = z.infer<typeof Reordering>;
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { DoublyLinkedList, Node } from "./dll.service";
|
|
3
|
-
export const
|
|
4
|
-
export const
|
|
5
|
-
export const
|
|
3
|
+
export const ReorderingPositionError = { error: "reordering.position.invalid" };
|
|
4
|
+
export const ReorderingCannotFindItemError = { error: "reordering.item.not_found" };
|
|
5
|
+
export const ReorderingCannotFindCurrentError = { error: "reordering.current_item.not_found" };
|
|
6
|
+
export const ReorderingCannotFindTargetError = { error: "reordering.target_item.not_found" };
|
|
7
|
+
export const ReorderingCorrelationIdError = { error: "reordering.correlation_id.invalid" };
|
|
8
|
+
export const ReorderingItemIdError = { error: "reordering.item_id.invalid" };
|
|
9
|
+
export const ReorderingItemPositionValue = z
|
|
10
|
+
.number(ReorderingPositionError)
|
|
11
|
+
.int(ReorderingPositionError)
|
|
12
|
+
.min(0, ReorderingPositionError);
|
|
13
|
+
export const ReorderingCorrelationId = z
|
|
14
|
+
.string(ReorderingCorrelationIdError)
|
|
15
|
+
.min(1, ReorderingCorrelationIdError);
|
|
16
|
+
export const ReorderingItemId = z.string(ReorderingItemIdError);
|
|
6
17
|
export const Reordering = z.object({
|
|
7
18
|
correlationId: ReorderingCorrelationId,
|
|
8
19
|
id: ReorderingItemId,
|
|
@@ -11,9 +22,9 @@ export const Reordering = z.object({
|
|
|
11
22
|
export class ReorderingPosition {
|
|
12
23
|
value;
|
|
13
24
|
constructor(value) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
const parsed = ReorderingItemPositionValue.safeParse(value);
|
|
26
|
+
if (!parsed.success)
|
|
27
|
+
throw new Error(ReorderingPositionError.error);
|
|
17
28
|
this.value = value;
|
|
18
29
|
}
|
|
19
30
|
eq(another) {
|
|
@@ -41,15 +52,16 @@ export class ReorderingTransfer {
|
|
|
41
52
|
id;
|
|
42
53
|
to;
|
|
43
54
|
constructor(config) {
|
|
44
|
-
|
|
45
|
-
|
|
55
|
+
const id = config.id;
|
|
56
|
+
const to = new ReorderingPosition(config.to);
|
|
57
|
+
this.id = id;
|
|
58
|
+
this.to = to;
|
|
46
59
|
}
|
|
47
60
|
getDirection(currentPosition) {
|
|
48
61
|
if (this.to.value === currentPosition.value)
|
|
49
62
|
return ReorderingTransferDirection.noop;
|
|
50
|
-
if (this.to.value > currentPosition.value)
|
|
63
|
+
if (this.to.value > currentPosition.value)
|
|
51
64
|
return ReorderingTransferDirection.downwards;
|
|
52
|
-
}
|
|
53
65
|
return ReorderingTransferDirection.upwards;
|
|
54
66
|
}
|
|
55
67
|
}
|
|
@@ -66,54 +78,62 @@ export class ReorderingCalculator {
|
|
|
66
78
|
return reordering;
|
|
67
79
|
}
|
|
68
80
|
add(id) {
|
|
69
|
-
const
|
|
81
|
+
const size = this.dll.getSize();
|
|
82
|
+
const position = new ReorderingPosition(ReorderingItemPositionValue.parse(size));
|
|
70
83
|
const item = new ReorderingItem(id, position);
|
|
71
|
-
|
|
84
|
+
const node = new Node(item);
|
|
85
|
+
this.dll.append(node);
|
|
72
86
|
return item;
|
|
73
87
|
}
|
|
74
88
|
delete(id) {
|
|
75
|
-
const
|
|
76
|
-
if (!
|
|
77
|
-
throw new Error(
|
|
78
|
-
this.dll.remove(
|
|
89
|
+
const node = this.dll.find((x) => x.data.eq(id));
|
|
90
|
+
if (!node)
|
|
91
|
+
throw new Error(ReorderingCannotFindItemError.error);
|
|
92
|
+
this.dll.remove(node);
|
|
79
93
|
this.recalculate();
|
|
80
94
|
}
|
|
81
95
|
transfer(transfer) {
|
|
82
96
|
const current = this.dll.find((node) => node.data.eq(transfer.id));
|
|
83
|
-
const target = this.dll.find((node) => node.data.position.eq(transfer.to));
|
|
84
97
|
if (!current)
|
|
85
|
-
throw new Error(
|
|
98
|
+
throw new Error(ReorderingCannotFindCurrentError.error);
|
|
99
|
+
const target = this.dll.find((node) => node.data.position.eq(transfer.to));
|
|
86
100
|
if (!target)
|
|
87
|
-
throw new Error(
|
|
101
|
+
throw new Error(ReorderingCannotFindTargetError.error);
|
|
88
102
|
const direction = transfer.getDirection(current.data.position);
|
|
89
103
|
if (direction === ReorderingTransferDirection.noop)
|
|
90
104
|
return this.read();
|
|
105
|
+
// remove first to avoid temporary invalid duplicates of positions
|
|
106
|
+
this.dll.remove(current);
|
|
91
107
|
if (direction === ReorderingTransferDirection.upwards) {
|
|
92
|
-
this.dll.remove(current);
|
|
93
108
|
this.dll.insertBefore(current, target);
|
|
94
|
-
this.recalculate();
|
|
95
109
|
}
|
|
96
|
-
|
|
97
|
-
this.dll.remove(current);
|
|
110
|
+
else {
|
|
98
111
|
this.dll.insertAfter(current, target);
|
|
99
|
-
this.recalculate();
|
|
100
112
|
}
|
|
113
|
+
this.recalculate();
|
|
101
114
|
return this.read();
|
|
102
115
|
}
|
|
103
116
|
read() {
|
|
104
|
-
const ids = Array.from(this.dll).map((
|
|
105
|
-
const items = Array.from(this.dll).map((
|
|
117
|
+
const ids = Array.from(this.dll).map((node) => node.data.id);
|
|
118
|
+
const items = Array.from(this.dll).map((node) => node.data);
|
|
106
119
|
return { ids, items };
|
|
107
120
|
}
|
|
108
121
|
recalculate() {
|
|
109
|
-
|
|
122
|
+
let index = 0;
|
|
123
|
+
for (const node of this.dll) {
|
|
124
|
+
const id = node.data.id;
|
|
125
|
+
const position = new ReorderingPosition(index);
|
|
126
|
+
node.data = new ReorderingItem(id, position);
|
|
127
|
+
index += 1;
|
|
128
|
+
}
|
|
110
129
|
}
|
|
111
130
|
}
|
|
112
131
|
export class ReorderingIntegrator {
|
|
113
132
|
static appendPosition(reordering) {
|
|
114
133
|
return function (item) {
|
|
115
|
-
const
|
|
116
|
-
|
|
134
|
+
const found = reordering.find((x) => x.id === item.id);
|
|
135
|
+
const positionValue = ReorderingItemPositionValue.parse(found?.position ?? 0);
|
|
136
|
+
return { ...item, position: positionValue };
|
|
117
137
|
};
|
|
118
138
|
}
|
|
119
139
|
static sortByPosition() {
|
package/dist/revision.vo.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import type { ETag, WeakETag } from "./etags.vo";
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const RevisionValueError: {
|
|
4
|
+
readonly error: "invalid.revision.value";
|
|
5
|
+
};
|
|
6
|
+
export declare const RevisionValue: z.core.$ZodBranded<z.ZodNumber, "RevisionValue">;
|
|
4
7
|
export type RevisionValueType = z.infer<typeof RevisionValue>;
|
|
8
|
+
export declare const RevisionInvalidErrorMessage: "revision.invalid";
|
|
9
|
+
export declare const RevisionMismatchErrorMessage: "revision.mismatch";
|
|
5
10
|
export declare class Revision {
|
|
11
|
+
static readonly INITIAL: RevisionValueType;
|
|
6
12
|
readonly value: RevisionValueType;
|
|
7
|
-
static initial: RevisionValueType;
|
|
8
13
|
constructor(value: unknown);
|
|
9
|
-
|
|
14
|
+
equals(another: RevisionValueType): boolean;
|
|
10
15
|
validate(another: RevisionValueType): void;
|
|
11
16
|
next(): Revision;
|
|
12
17
|
static fromETag(etag: ETag | null): Revision;
|
package/dist/revision.vo.js
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
export const
|
|
2
|
+
export const RevisionValueError = { error: "invalid.revision.value" };
|
|
3
|
+
export const RevisionValue = z
|
|
4
|
+
.number(RevisionValueError)
|
|
5
|
+
.int(RevisionValueError)
|
|
6
|
+
.min(0, RevisionValueError)
|
|
7
|
+
.brand("RevisionValue");
|
|
8
|
+
export const RevisionInvalidErrorMessage = "revision.invalid";
|
|
9
|
+
export const RevisionMismatchErrorMessage = "revision.mismatch";
|
|
3
10
|
export class Revision {
|
|
11
|
+
static INITIAL = RevisionValue.parse(0);
|
|
4
12
|
value;
|
|
5
|
-
static initial = 0;
|
|
6
13
|
constructor(value) {
|
|
7
14
|
const result = RevisionValue.safeParse(value);
|
|
8
15
|
if (!result.success)
|
|
9
16
|
throw new InvalidRevisionError();
|
|
10
17
|
this.value = result.data;
|
|
11
18
|
}
|
|
12
|
-
|
|
19
|
+
equals(another) {
|
|
13
20
|
return this.value === another;
|
|
14
21
|
}
|
|
15
22
|
validate(another) {
|
|
16
|
-
if (!this.
|
|
23
|
+
if (!this.equals(another))
|
|
17
24
|
throw new RevisionMismatchError();
|
|
18
25
|
}
|
|
19
26
|
next() {
|
|
@@ -32,13 +39,13 @@ export class Revision {
|
|
|
32
39
|
}
|
|
33
40
|
export class RevisionMismatchError extends Error {
|
|
34
41
|
constructor() {
|
|
35
|
-
super();
|
|
42
|
+
super(RevisionMismatchErrorMessage);
|
|
36
43
|
Object.setPrototypeOf(this, RevisionMismatchError.prototype);
|
|
37
44
|
}
|
|
38
45
|
}
|
|
39
46
|
export class InvalidRevisionError extends Error {
|
|
40
47
|
constructor() {
|
|
41
|
-
super();
|
|
48
|
+
super(RevisionInvalidErrorMessage);
|
|
42
49
|
Object.setPrototypeOf(this, InvalidRevisionError.prototype);
|
|
43
50
|
}
|
|
44
51
|
}
|
package/dist/rounding.adapter.js
CHANGED
|
@@ -18,9 +18,8 @@ export class RoundToDecimal {
|
|
|
18
18
|
decimals;
|
|
19
19
|
constructor(decimals) {
|
|
20
20
|
this.decimals = decimals;
|
|
21
|
-
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 100)
|
|
21
|
+
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 100)
|
|
22
22
|
throw new Error(RoundingDecimalsError);
|
|
23
|
-
}
|
|
24
23
|
}
|
|
25
24
|
round(value) {
|
|
26
25
|
return Number.parseFloat(value.toFixed(this.decimals));
|
package/dist/size.vo.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export declare class Size {
|
|
|
18
18
|
private static readonly KB_MULTIPLIER;
|
|
19
19
|
private static readonly MB_MULTIPLIER;
|
|
20
20
|
private static readonly GB_MULTIPLIER;
|
|
21
|
+
private static readonly ROUNDER;
|
|
21
22
|
constructor(config: SizeConfigType);
|
|
22
23
|
static fromBytes(candidate: number): Size;
|
|
23
24
|
static fromKb(candidate: number): Size;
|
package/dist/size.vo.js
CHANGED
|
@@ -15,6 +15,7 @@ export class Size {
|
|
|
15
15
|
static KB_MULTIPLIER = 1024;
|
|
16
16
|
static MB_MULTIPLIER = 1024 * Size.KB_MULTIPLIER;
|
|
17
17
|
static GB_MULTIPLIER = 1024 * Size.MB_MULTIPLIER;
|
|
18
|
+
static ROUNDER = new RoundToDecimal(2);
|
|
18
19
|
constructor(config) {
|
|
19
20
|
this.unit = config.unit;
|
|
20
21
|
this.value = SizeValue.parse(config.value);
|
|
@@ -46,19 +47,15 @@ export class Size {
|
|
|
46
47
|
return this.bytes > another.toBytes();
|
|
47
48
|
}
|
|
48
49
|
format(unit) {
|
|
49
|
-
const rounding = new RoundToDecimal(2);
|
|
50
50
|
switch (unit) {
|
|
51
51
|
case SizeUnit.kB: {
|
|
52
|
-
|
|
53
|
-
return `${kbs} ${SizeUnit.kB}`;
|
|
52
|
+
return `${Size.ROUNDER.round(this.bytes / Size.KB_MULTIPLIER)} ${SizeUnit.kB}`;
|
|
54
53
|
}
|
|
55
54
|
case SizeUnit.MB: {
|
|
56
|
-
|
|
57
|
-
return `${mbs} ${SizeUnit.MB}`;
|
|
55
|
+
return `${Size.ROUNDER.round(this.bytes / Size.MB_MULTIPLIER)} ${SizeUnit.MB}`;
|
|
58
56
|
}
|
|
59
57
|
case SizeUnit.GB: {
|
|
60
|
-
|
|
61
|
-
return `${gbs} ${SizeUnit.GB}`;
|
|
58
|
+
return `${Size.ROUNDER.round(this.bytes / Size.GB_MULTIPLIER)} ${SizeUnit.GB}`;
|
|
62
59
|
}
|
|
63
60
|
default: {
|
|
64
61
|
// SizeUnit.b
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { format } from "date-fns";
|
|
2
1
|
type DateType = string;
|
|
3
2
|
export type StreakType = {
|
|
4
3
|
cutoff: DateType;
|
|
@@ -7,8 +6,8 @@ export type StreakType = {
|
|
|
7
6
|
};
|
|
8
7
|
export declare class StreakCalculator {
|
|
9
8
|
private readonly cutoff;
|
|
10
|
-
constructor();
|
|
11
|
-
calculate(
|
|
12
|
-
static format(date:
|
|
9
|
+
constructor(now?: Date);
|
|
10
|
+
calculate(inputDates: DateType[]): StreakType;
|
|
11
|
+
static format(date: Date | number): DateType;
|
|
13
12
|
}
|
|
14
13
|
export {};
|
|
@@ -1,24 +1,18 @@
|
|
|
1
|
-
import { format,
|
|
1
|
+
import { format, subDays } from "date-fns";
|
|
2
2
|
export class StreakCalculator {
|
|
3
3
|
cutoff;
|
|
4
|
-
constructor() {
|
|
5
|
-
|
|
6
|
-
this.cutoff = StreakCalculator.format(today);
|
|
4
|
+
constructor(now = new Date()) {
|
|
5
|
+
this.cutoff = StreakCalculator.format(now);
|
|
7
6
|
}
|
|
8
|
-
calculate(
|
|
9
|
-
const dates = Array.from(new Set(
|
|
7
|
+
calculate(inputDates) {
|
|
8
|
+
const dates = Array.from(new Set(inputDates));
|
|
9
|
+
const datesSet = new Set(dates);
|
|
10
10
|
let streak = 0;
|
|
11
|
-
let
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (isEqual(streakTail, date) || isAfter(date, streakTail)) {
|
|
17
|
-
streakTail = StreakCalculator.format(subDays(date, 1));
|
|
18
|
-
streak++;
|
|
19
|
-
}
|
|
20
|
-
else
|
|
21
|
-
break;
|
|
11
|
+
let cursor = this.cutoff;
|
|
12
|
+
while (datesSet.has(cursor)) {
|
|
13
|
+
streak++;
|
|
14
|
+
const cursorDate = new Date(`${cursor}T00:00:00Z`);
|
|
15
|
+
cursor = StreakCalculator.format(subDays(cursorDate, 1));
|
|
22
16
|
}
|
|
23
17
|
return { cutoff: this.cutoff, dates, streak };
|
|
24
18
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
export declare const TimeZoneOffsetValue: z.core.$ZodBranded<z.
|
|
2
|
+
export declare const TimeZoneOffsetValue: z.core.$ZodBranded<z.ZodCatch<z.ZodCoercedNumber<unknown>>, "TimeZoneOffsetValue">;
|
|
3
3
|
export type TimeZoneOffsetValueType = z.infer<typeof TimeZoneOffsetValue>;
|
|
@@ -1,8 +1,2 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
export const TimeZoneOffsetValue = z
|
|
3
|
-
.string()
|
|
4
|
-
.trim()
|
|
5
|
-
.or(z.undefined())
|
|
6
|
-
.transform((value) => Number(value))
|
|
7
|
-
.transform((value) => (Number.isNaN(value) ? 0 : value))
|
|
8
|
-
.brand("TimeZoneOffsetValue");
|
|
2
|
+
export const TimeZoneOffsetValue = z.coerce.number().catch(0).brand("TimeZoneOffsetValue");
|
package/dist/time.service.d.ts
CHANGED
|
@@ -7,16 +7,21 @@ interface TimeResultInterface {
|
|
|
7
7
|
readonly ms: TimestampType;
|
|
8
8
|
isAfter(another: TimeResultInterface): boolean;
|
|
9
9
|
isBefore(another: TimeResultInterface): boolean;
|
|
10
|
+
add(another: TimeResultInterface): TimeResultInterface;
|
|
11
|
+
subtract(another: TimeResultInterface): TimeResultInterface;
|
|
10
12
|
}
|
|
11
13
|
export declare class TimeResult implements TimeResultInterface {
|
|
12
|
-
readonly
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
private readonly valueMs;
|
|
15
|
+
constructor(ms: TimestampType);
|
|
16
|
+
get days(): number;
|
|
17
|
+
get hours(): number;
|
|
18
|
+
get minutes(): number;
|
|
19
|
+
get seconds(): number;
|
|
20
|
+
get ms(): TimestampType;
|
|
18
21
|
isAfter(another: TimeResultInterface): boolean;
|
|
19
22
|
isBefore(another: TimeResultInterface): boolean;
|
|
23
|
+
add(another: TimeResultInterface): TimeResultInterface;
|
|
24
|
+
subtract(another: TimeResultInterface): TimeResultInterface;
|
|
20
25
|
}
|
|
21
26
|
export declare class Time {
|
|
22
27
|
static Days(value: number): TimeResultInterface;
|
package/dist/time.service.js
CHANGED
|
@@ -1,40 +1,53 @@
|
|
|
1
1
|
import { RoundToDecimal } from "./rounding.adapter";
|
|
2
2
|
const rounding = new RoundToDecimal(2);
|
|
3
3
|
export class TimeResult {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
this.
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
valueMs;
|
|
5
|
+
constructor(ms) {
|
|
6
|
+
this.valueMs = ms;
|
|
7
|
+
}
|
|
8
|
+
get days() {
|
|
9
|
+
return rounding.round(this.valueMs / 86_400_000);
|
|
10
|
+
}
|
|
11
|
+
get hours() {
|
|
12
|
+
return rounding.round(this.valueMs / 3_600_000);
|
|
13
|
+
}
|
|
14
|
+
get minutes() {
|
|
15
|
+
return rounding.round(this.valueMs / 60_000);
|
|
16
|
+
}
|
|
17
|
+
get seconds() {
|
|
18
|
+
return rounding.round(this.valueMs / 1_000);
|
|
19
|
+
}
|
|
20
|
+
get ms() {
|
|
21
|
+
return this.valueMs;
|
|
15
22
|
}
|
|
16
23
|
isAfter(another) {
|
|
17
|
-
return this.
|
|
24
|
+
return this.valueMs > another.ms;
|
|
18
25
|
}
|
|
19
26
|
isBefore(another) {
|
|
20
|
-
return this.
|
|
27
|
+
return this.valueMs < another.ms;
|
|
28
|
+
}
|
|
29
|
+
add(another) {
|
|
30
|
+
return new TimeResult((this.valueMs + another.ms));
|
|
31
|
+
}
|
|
32
|
+
subtract(another) {
|
|
33
|
+
return new TimeResult((this.valueMs - another.ms));
|
|
21
34
|
}
|
|
22
35
|
}
|
|
23
36
|
export class Time {
|
|
24
37
|
static Days(value) {
|
|
25
|
-
return new TimeResult(
|
|
38
|
+
return new TimeResult((value * 86_400_000));
|
|
26
39
|
}
|
|
27
40
|
static Hours(value) {
|
|
28
|
-
return new TimeResult(
|
|
41
|
+
return new TimeResult((value * 3_600_000));
|
|
29
42
|
}
|
|
30
43
|
static Minutes(value) {
|
|
31
|
-
return new TimeResult(
|
|
44
|
+
return new TimeResult((value * 60_000));
|
|
32
45
|
}
|
|
33
46
|
static Seconds(value) {
|
|
34
|
-
return new TimeResult(
|
|
47
|
+
return new TimeResult((value * 1_000));
|
|
35
48
|
}
|
|
36
49
|
static Ms(value) {
|
|
37
|
-
return new TimeResult(
|
|
50
|
+
return new TimeResult(value);
|
|
38
51
|
}
|
|
39
52
|
static Now(now) {
|
|
40
53
|
return {
|
package/dist/timezone.vo.js
CHANGED
|
@@ -5,9 +5,7 @@ export const Timezone = z
|
|
|
5
5
|
.min(1, TimezoneError)
|
|
6
6
|
.refine((value) => {
|
|
7
7
|
try {
|
|
8
|
-
|
|
9
|
-
const formatter = new Intl.DateTimeFormat("en-US", { timeZone: value });
|
|
10
|
-
formatter.format(date);
|
|
8
|
+
new Intl.DateTimeFormat("en-US", { timeZone: value }).format(new Date());
|
|
11
9
|
return true;
|
|
12
10
|
}
|
|
13
11
|
catch (_error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/age.vo.ts","../src/api-key.vo.ts","../src/basename.vo.ts","../src/clock-format.service.ts","../src/clock.vo.ts","../src/date-calculator.service.ts","../src/date-formatter.service.ts","../src/date-range.vo.ts","../src/day-iso-id.vo.ts","../src/day.vo.ts","../src/directory-path-absolute.vo.ts","../src/directory-path-relative.vo.ts","../src/dll.service.ts","../src/email-mask.service.ts","../src/etags.vo.ts","../src/extension.vo.ts","../src/feature-flag.vo.ts","../src/file-path-absolute-schema.vo.ts","../src/file-path-relative-schema.vo.ts","../src/file-path.vo.ts","../src/filename-from-string.vo.ts","../src/filename-suffix.vo.ts","../src/filename.vo.ts","../src/height.vo.ts","../src/hour-format.service.ts","../src/hour.vo.ts","../src/iban-mask.service.ts","../src/iban.vo.ts","../src/image.vo.ts","../src/index.ts","../src/language.vo.ts","../src/mean.service.ts","../src/mime-types.vo.ts","../src/mime.vo.ts","../src/min-max-scaler.service.ts","../src/minute.vo.ts","../src/money.vo.ts","../src/month-iso-id.vo.ts","../src/month.vo.ts","../src/noop.service.ts","../src/notification-template.vo.ts","../src/object-key.vo.ts","../src/outlier-detector.service.ts","../src/package-version.vo.ts","../src/pagination.service.ts","../src/percentage.service.ts","../src/population-standard-deviation.service.ts","../src/quarter-iso-id.vo.ts","../src/quarter.vo.ts","../src/random.service.ts","../src/rate-limiter.service.ts","../src/relative-date.vo.ts","../src/reordering.service.ts","../src/revision.vo.ts","../src/rounding.adapter.ts","../src/rounding.port.ts","../src/simple-linear-regression.service.ts","../src/size.vo.ts","../src/
|
|
1
|
+
{"root":["../src/age.vo.ts","../src/api-key.vo.ts","../src/basename.vo.ts","../src/clock-format.service.ts","../src/clock.vo.ts","../src/date-calculator.service.ts","../src/date-formatter.service.ts","../src/date-range.vo.ts","../src/day-iso-id.vo.ts","../src/day.vo.ts","../src/directory-path-absolute.vo.ts","../src/directory-path-relative.vo.ts","../src/dll.service.ts","../src/email-mask.service.ts","../src/etags.vo.ts","../src/extension.vo.ts","../src/feature-flag.vo.ts","../src/file-path-absolute-schema.vo.ts","../src/file-path-relative-schema.vo.ts","../src/file-path.vo.ts","../src/filename-from-string.vo.ts","../src/filename-suffix.vo.ts","../src/filename.vo.ts","../src/height.vo.ts","../src/hour-format.service.ts","../src/hour.vo.ts","../src/iban-mask.service.ts","../src/iban.vo.ts","../src/image.vo.ts","../src/index.ts","../src/language.vo.ts","../src/mean.service.ts","../src/mime-types.vo.ts","../src/mime.vo.ts","../src/min-max-scaler.service.ts","../src/minute.vo.ts","../src/money.vo.ts","../src/month-iso-id.vo.ts","../src/month.vo.ts","../src/noop.service.ts","../src/notification-template.vo.ts","../src/object-key.vo.ts","../src/outlier-detector.service.ts","../src/package-version.vo.ts","../src/pagination.service.ts","../src/percentage.service.ts","../src/population-standard-deviation.service.ts","../src/quarter-iso-id.vo.ts","../src/quarter.vo.ts","../src/random.service.ts","../src/rate-limiter.service.ts","../src/relative-date.vo.ts","../src/reordering.service.ts","../src/revision.vo.ts","../src/rounding.adapter.ts","../src/rounding.port.ts","../src/simple-linear-regression.service.ts","../src/size.vo.ts","../src/stopwatch.service.ts","../src/streak-calculator.service.ts","../src/sum.service.ts","../src/thousands-separator.service.ts","../src/time-zone-offset-value.vo.ts","../src/time.service.ts","../src/timestamp.vo.ts","../src/timezone.vo.ts","../src/ts-utils.ts","../src/visually-unambiguous-characters-generator.service.ts","../src/week-iso-id.vo.ts","../src/week.vo.ts","../src/weekday.vo.ts","../src/weight.vo.ts","../src/year-iso-id.vo.ts","../src/year.vo.ts","../src/z-score.service.ts"],"version":"5.9.3"}
|
package/dist/week-iso-id.vo.d.ts
CHANGED
package/dist/week-iso-id.vo.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { getISOWeeksInYear } from "date-fns";
|
|
2
2
|
import { z } from "zod/v4";
|
|
3
|
+
export const WeekIsoIdError = { error: "week-iso-id.invalid" };
|
|
3
4
|
export const WeekIsoId = z
|
|
4
|
-
.string()
|
|
5
|
-
.regex(/^\d{4}-W\d{2}
|
|
5
|
+
.string(WeekIsoIdError)
|
|
6
|
+
.regex(/^\d{4}-W\d{2}$/, WeekIsoIdError)
|
|
6
7
|
.refine((value) => {
|
|
7
8
|
const [yearPart, weekPart] = value.split("-W");
|
|
8
9
|
const year = Number(yearPart);
|
|
9
10
|
const week = Number(weekPart);
|
|
10
11
|
if (!(Number.isInteger(year) && Number.isInteger(week)) || week < 1)
|
|
11
12
|
return false;
|
|
12
|
-
// Does this ISO week-year actually have that many weeks?
|
|
13
13
|
const weeksInYear = getISOWeeksInYear(new Date(Date.UTC(year, 0, 4)));
|
|
14
14
|
return week <= weeksInYear;
|
|
15
|
-
},
|
|
15
|
+
}, WeekIsoIdError);
|
package/dist/week.vo.js
CHANGED
|
@@ -6,7 +6,7 @@ export class Week extends DateRange {
|
|
|
6
6
|
toIsoId() {
|
|
7
7
|
const year = getISOWeekYear(this.getStart());
|
|
8
8
|
const week = getISOWeek(this.getStart()).toString().padStart(2, "0");
|
|
9
|
-
return `${year}-W${week}
|
|
9
|
+
return WeekIsoId.parse(`${year}-W${week}`);
|
|
10
10
|
}
|
|
11
11
|
previous() {
|
|
12
12
|
const shifted = addWeeks(new Date(this.getStart()), -1).getTime();
|
package/dist/weekday.vo.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare enum WeekdayFormatterEnum {
|
|
|
6
6
|
ISO_NUMBER = "ISO_NUMBER",// Monday=1 ... Sunday=7
|
|
7
7
|
ZERO_BASED_NUMBER = "ZERO_BASED_NUMBER"
|
|
8
8
|
}
|
|
9
|
+
export declare const WeekdayValueError: "invalid.weekday";
|
|
9
10
|
export declare const WeekdayFormatters: Record<WeekdayFormatterEnum, WeekdayFormatter>;
|
|
10
11
|
export declare class Weekday {
|
|
11
12
|
private readonly value;
|
|
@@ -19,11 +20,11 @@ export declare class Weekday {
|
|
|
19
20
|
static readonly SATURDAY: Weekday;
|
|
20
21
|
constructor(candidate: number, formatter?: WeekdayFormatter);
|
|
21
22
|
static fromUtcTimestamp(timestamp: TimestampType, formatter?: WeekdayFormatter): Weekday;
|
|
22
|
-
get(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
23
|
+
get(): number;
|
|
24
|
+
format(formatter?: WeekdayFormatter): string;
|
|
25
|
+
toString(): string;
|
|
26
26
|
equals(another: Weekday): boolean;
|
|
27
|
+
/** ISO-8601 weekday number: Monday=1 ... Sunday=7 */
|
|
27
28
|
toIsoNumber(): number;
|
|
28
29
|
isMonday(): boolean;
|
|
29
30
|
isTuesday(): boolean;
|
|
@@ -32,6 +33,6 @@ export declare class Weekday {
|
|
|
32
33
|
isFriday(): boolean;
|
|
33
34
|
isSaturday(): boolean;
|
|
34
35
|
isSunday(): boolean;
|
|
35
|
-
static list(formatter?: WeekdayFormatter): Weekday[];
|
|
36
|
-
static listMondayFirst(formatter?: WeekdayFormatter): Weekday[];
|
|
36
|
+
static list(formatter?: WeekdayFormatter): readonly Weekday[];
|
|
37
|
+
static listMondayFirst(formatter?: WeekdayFormatter): readonly Weekday[];
|
|
37
38
|
}
|
package/dist/weekday.vo.js
CHANGED
|
@@ -5,6 +5,7 @@ export var WeekdayFormatterEnum;
|
|
|
5
5
|
WeekdayFormatterEnum["ISO_NUMBER"] = "ISO_NUMBER";
|
|
6
6
|
WeekdayFormatterEnum["ZERO_BASED_NUMBER"] = "ZERO_BASED_NUMBER";
|
|
7
7
|
})(WeekdayFormatterEnum || (WeekdayFormatterEnum = {}));
|
|
8
|
+
export const WeekdayValueError = "invalid.weekday";
|
|
8
9
|
const FULL_NAMES = [
|
|
9
10
|
"Sunday",
|
|
10
11
|
"Monday",
|
|
@@ -22,7 +23,9 @@ export const WeekdayFormatters = {
|
|
|
22
23
|
ZERO_BASED_NUMBER: (value) => value.toString(), // JS getUTCDay(): Sun=0..Sat=6
|
|
23
24
|
};
|
|
24
25
|
export class Weekday {
|
|
26
|
+
// 0..6 (Sun..Sat)
|
|
25
27
|
value;
|
|
28
|
+
// default formatter used by toString()/format() when no runtime formatter given
|
|
26
29
|
formatter;
|
|
27
30
|
static SUNDAY = new Weekday(0);
|
|
28
31
|
static MONDAY = new Weekday(1);
|
|
@@ -32,26 +35,29 @@ export class Weekday {
|
|
|
32
35
|
static FRIDAY = new Weekday(5);
|
|
33
36
|
static SATURDAY = new Weekday(6);
|
|
34
37
|
constructor(candidate, formatter) {
|
|
35
|
-
if (!Number.isInteger(candidate))
|
|
36
|
-
throw new Error(
|
|
37
|
-
if (candidate < 0)
|
|
38
|
-
throw new Error("Invalid weekday");
|
|
39
|
-
if (candidate > 6)
|
|
40
|
-
throw new Error("Invalid weekday");
|
|
38
|
+
if (!Number.isInteger(candidate) || candidate < 0 || candidate > 6)
|
|
39
|
+
throw new Error(WeekdayValueError);
|
|
41
40
|
this.value = candidate;
|
|
42
41
|
this.formatter = formatter ?? WeekdayFormatters.FULL;
|
|
43
42
|
}
|
|
44
43
|
static fromUtcTimestamp(timestamp, formatter) {
|
|
45
|
-
const
|
|
46
|
-
return new Weekday(
|
|
44
|
+
const dayZeroBased = new Date(timestamp).getUTCDay(); // 0..6
|
|
45
|
+
return new Weekday(dayZeroBased, formatter);
|
|
47
46
|
}
|
|
48
|
-
get(
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
get() {
|
|
48
|
+
return this.value;
|
|
49
|
+
}
|
|
50
|
+
format(formatter) {
|
|
51
|
+
const chosen = formatter ?? this.formatter;
|
|
52
|
+
return chosen(this.value);
|
|
53
|
+
}
|
|
54
|
+
toString() {
|
|
55
|
+
return this.format(WeekdayFormatters.FULL);
|
|
51
56
|
}
|
|
52
57
|
equals(another) {
|
|
53
|
-
return this.value === another.
|
|
58
|
+
return this.value === another.value;
|
|
54
59
|
}
|
|
60
|
+
/** ISO-8601 weekday number: Monday=1 ... Sunday=7 */
|
|
55
61
|
toIsoNumber() {
|
|
56
62
|
return this.value === 0 ? 7 : this.value;
|
|
57
63
|
}
|
|
@@ -77,7 +83,8 @@ export class Weekday {
|
|
|
77
83
|
return this.value === 0;
|
|
78
84
|
}
|
|
79
85
|
static list(formatter) {
|
|
80
|
-
|
|
86
|
+
const chosen = formatter ?? undefined;
|
|
87
|
+
return Array.from({ length: 7 }, (_, index) => new Weekday(index, chosen));
|
|
81
88
|
}
|
|
82
89
|
static listMondayFirst(formatter) {
|
|
83
90
|
const days = Weekday.list(formatter);
|