@bgord/tools 1.2.20 → 1.2.22
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/age-years.vo.d.ts +1 -1
- package/dist/age-years.vo.js +1 -1
- package/dist/api-key.vo.d.ts +1 -1
- package/dist/api-key.vo.js +1 -1
- package/dist/basename.vo.d.ts +1 -1
- package/dist/basename.vo.js +1 -1
- package/dist/day-iso-id.vo.d.ts +1 -1
- package/dist/day-iso-id.vo.js +1 -1
- package/dist/directory-path-absolute.vo.d.ts +1 -1
- package/dist/directory-path-absolute.vo.js +1 -1
- package/dist/directory-path-relative.vo.d.ts +1 -1
- package/dist/directory-path-relative.vo.js +1 -1
- package/dist/distance-value.vo.d.ts +1 -1
- package/dist/distance-value.vo.js +1 -1
- package/dist/division-factor.vo.d.ts +1 -1
- package/dist/division-factor.vo.js +1 -1
- package/dist/duration-ms.vo.d.ts +1 -1
- package/dist/duration-ms.vo.js +1 -1
- package/dist/email.vo.d.ts +1 -1
- package/dist/email.vo.js +1 -1
- package/dist/extension.vo.d.ts +1 -1
- package/dist/extension.vo.js +1 -1
- package/dist/feature-flag-value.vo.d.ts +1 -1
- package/dist/feature-flag-value.vo.js +1 -1
- package/dist/file-path-absolute-schema.vo.d.ts +1 -1
- package/dist/file-path-absolute-schema.vo.js +1 -1
- package/dist/file-path-relative-schema.vo.d.ts +1 -1
- package/dist/file-path-relative-schema.vo.js +1 -1
- package/dist/filename-affix.vo.d.ts +1 -1
- package/dist/filename-affix.vo.js +1 -1
- package/dist/filename-from-string.vo.d.ts +1 -1
- package/dist/filename-from-string.vo.js +1 -1
- package/dist/height-milimiters.vo.d.ts +1 -1
- package/dist/height-milimiters.vo.js +1 -1
- package/dist/hour-schema.vo.d.ts +1 -1
- package/dist/hour-schema.vo.js +1 -1
- package/dist/iban-schema.vo.d.ts +1 -1
- package/dist/iban-schema.vo.js +1 -1
- package/dist/image.vo.d.ts +1 -1
- package/dist/image.vo.js +1 -1
- package/dist/integer-non-negative.vo.d.ts +1 -1
- package/dist/integer-non-negative.vo.js +1 -1
- package/dist/integer-positive.vo.d.ts +1 -1
- package/dist/integer-positive.vo.js +1 -1
- package/dist/integer.vo.d.ts +1 -1
- package/dist/integer.vo.js +1 -1
- package/dist/language.vo.d.ts +1 -1
- package/dist/language.vo.js +1 -1
- package/dist/mime-value.vo.d.ts +1 -1
- package/dist/mime-value.vo.js +1 -1
- package/dist/minute-schema.vo.d.ts +1 -1
- package/dist/minute-schema.vo.js +1 -1
- package/dist/money-amount.vo.d.ts +1 -1
- package/dist/money-amount.vo.js +1 -1
- package/dist/month-iso-id.vo.d.ts +1 -1
- package/dist/month-iso-id.vo.js +1 -1
- package/dist/multiplication-factor.vo.d.ts +1 -1
- package/dist/multiplication-factor.vo.js +1 -1
- package/dist/object-key.vo.d.ts +1 -1
- package/dist/object-key.vo.js +1 -1
- package/dist/package-version-schema.vo.d.ts +1 -1
- package/dist/package-version-schema.vo.js +1 -1
- package/dist/pagination-page.vo.d.ts +1 -1
- package/dist/pagination-page.vo.js +1 -1
- package/dist/pagination-skip.vo.d.ts +1 -1
- package/dist/pagination-skip.vo.js +1 -1
- package/dist/pagination-take.vo.d.ts +1 -1
- package/dist/pagination-take.vo.js +1 -1
- package/dist/quarter-iso-id.vo.d.ts +1 -1
- package/dist/quarter-iso-id.vo.js +1 -1
- package/dist/reordering-item-position-value.vo.d.ts +1 -1
- package/dist/reordering-item-position-value.vo.js +1 -1
- package/dist/reordering.service.d.ts +1 -1
- package/dist/reordering.service.js +1 -1
- package/dist/revision-value.vo.d.ts +1 -1
- package/dist/revision-value.vo.js +1 -1
- package/dist/rounding-decimal.strategy.d.ts +1 -1
- package/dist/rounding-decimal.strategy.js +1 -1
- package/dist/size-bytes.vo.d.ts +1 -1
- package/dist/size-bytes.vo.js +1 -1
- package/dist/time-zone-offset-value.vo.d.ts +1 -1
- package/dist/time-zone-offset-value.vo.js +1 -1
- package/dist/timestamp-value.vo.d.ts +1 -1
- package/dist/timestamp-value.vo.js +1 -1
- package/dist/timezone.vo.d.ts +1 -1
- package/dist/timezone.vo.js +1 -1
- package/dist/url-with-slash.vo.d.ts +1 -1
- package/dist/url-with-slash.vo.js +1 -1
- package/dist/url-without-slash.vo.d.ts +1 -1
- package/dist/url-without-slash.vo.js +1 -1
- package/dist/week-iso-id.vo.d.ts +1 -1
- package/dist/week-iso-id.vo.js +1 -1
- package/dist/weight-grams.vo.d.ts +1 -1
- package/dist/weight-grams.vo.js +1 -1
- package/dist/year-iso-id.vo.d.ts +1 -1
- package/dist/year-iso-id.vo.js +1 -1
- package/package.json +2 -3
- package/src/age-years.vo.ts +0 -16
- package/src/age.vo.ts +0 -60
- package/src/api-key.vo.ts +0 -16
- package/src/basename.vo.ts +0 -33
- package/src/clock-format.service.ts +0 -15
- package/src/clock.vo.ts +0 -55
- package/src/date-calculator.service.ts +0 -18
- package/src/date-formatter.service.ts +0 -21
- package/src/date-range.vo.ts +0 -36
- package/src/day-iso-id.vo.ts +0 -21
- package/src/day.vo.ts +0 -59
- package/src/directory-path-absolute.vo.ts +0 -36
- package/src/directory-path-relative.vo.ts +0 -34
- package/src/distance-value.vo.ts +0 -13
- package/src/distance.vo.ts +0 -76
- package/src/division-factor.vo.ts +0 -12
- package/src/dll.service.ts +0 -177
- package/src/duration-ms.vo.ts +0 -9
- package/src/duration.service.ts +0 -94
- package/src/email-mask.service.ts +0 -17
- package/src/email.vo.ts +0 -9
- package/src/etags.vo.ts +0 -47
- package/src/extension.vo.ts +0 -27
- package/src/feature-flag-value.vo.ts +0 -12
- package/src/feature-flag.vo.ts +0 -11
- package/src/file-path-absolute-schema.vo.ts +0 -34
- package/src/file-path-relative-schema.vo.ts +0 -34
- package/src/file-path.vo.ts +0 -100
- package/src/filename-affix.vo.ts +0 -27
- package/src/filename-from-string.vo.ts +0 -27
- package/src/filename.vo.ts +0 -92
- package/src/height-milimiters.vo.ts +0 -16
- package/src/height.vo.ts +0 -79
- package/src/hour-format.service.ts +0 -22
- package/src/hour-schema.vo.ts +0 -14
- package/src/hour.vo.ts +0 -64
- package/src/iban-mask.service.ts +0 -18
- package/src/iban-schema.vo.ts +0 -17
- package/src/iban.vo.ts +0 -28
- package/src/image.vo.ts +0 -28
- package/src/index.ts +0 -105
- package/src/integer-non-negative.vo.ts +0 -16
- package/src/integer-positive.vo.ts +0 -13
- package/src/integer.vo.ts +0 -9
- package/src/language.vo.ts +0 -13
- package/src/linear-regression.service.ts +0 -73
- package/src/mean.service.ts +0 -18
- package/src/mime-types.vo.ts +0 -7
- package/src/mime-value.vo.ts +0 -14
- package/src/mime.vo.ts +0 -50
- package/src/min-max-scaler.service.ts +0 -96
- package/src/minute-schema.vo.ts +0 -14
- package/src/minute.vo.ts +0 -59
- package/src/money-amount.vo.ts +0 -13
- package/src/money.vo.ts +0 -83
- package/src/month-iso-id.vo.ts +0 -24
- package/src/month.vo.ts +0 -53
- package/src/multiplication-factor.vo.ts +0 -15
- package/src/noop.service.ts +0 -3
- package/src/notification-template.vo.ts +0 -10
- package/src/object-key.vo.ts +0 -36
- package/src/outlier-detector.service.ts +0 -21
- package/src/package-version-schema.vo.ts +0 -23
- package/src/package-version.vo.ts +0 -66
- package/src/pagination-page.vo.ts +0 -11
- package/src/pagination-skip.vo.ts +0 -10
- package/src/pagination-take.vo.ts +0 -10
- package/src/pagination.service.ts +0 -73
- package/src/percentage.service.ts +0 -15
- package/src/population-standard-deviation.service.ts +0 -23
- package/src/quarter-iso-id.vo.ts +0 -15
- package/src/quarter.vo.ts +0 -41
- package/src/random.service.ts +0 -19
- package/src/rate-limiter.service.ts +0 -30
- package/src/relative-date.vo.ts +0 -21
- package/src/reordering-item-position-value.vo.ts +0 -10
- package/src/reordering.service.ts +0 -163
- package/src/revision-value.vo.ts +0 -10
- package/src/revision.vo.ts +0 -44
- package/src/rounding-decimal.strategy.ts +0 -25
- package/src/rounding-down.strategy.ts +0 -7
- package/src/rounding-to-nearest.strategy.ts +0 -7
- package/src/rounding-up.strategy.ts +0 -7
- package/src/rounding.strategy.ts +0 -3
- package/src/size-bytes.vo.ts +0 -13
- package/src/size.vo.ts +0 -113
- package/src/slug.service.ts +0 -18
- package/src/sum.service.ts +0 -19
- package/src/thousands-separator.service.ts +0 -10
- package/src/time-zone-offset-value.vo.ts +0 -21
- package/src/timestamp-value.vo.ts +0 -13
- package/src/timestamp.vo.ts +0 -66
- package/src/timezone.vo.ts +0 -26
- package/src/ts-utils.ts +0 -3
- package/src/url-with-slash.vo.ts +0 -12
- package/src/url-without-slash.vo.ts +0 -12
- package/src/visually-unambiguous-characters-generator.service.ts +0 -39
- package/src/week-iso-id.vo.ts +0 -28
- package/src/week.vo.ts +0 -57
- package/src/weekday.vo.ts +0 -119
- package/src/weight-grams.vo.ts +0 -13
- package/src/weight.vo.ts +0 -91
- package/src/year-iso-id.vo.ts +0 -15
- package/src/year.vo.ts +0 -63
- package/src/z-score.service.ts +0 -25
package/src/dll.service.ts
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
export class Node<T> {
|
|
2
|
-
data: T;
|
|
3
|
-
prev: Node<T> | null = null;
|
|
4
|
-
next: Node<T> | null = null;
|
|
5
|
-
|
|
6
|
-
constructor(data: Node<T>["data"]) {
|
|
7
|
-
this.data = data;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
forward(n: number): Node<T> | null {
|
|
11
|
-
let currentNode: Node<T> | null = this;
|
|
12
|
-
let steps = n;
|
|
13
|
-
|
|
14
|
-
while (steps > 0 && currentNode) {
|
|
15
|
-
currentNode = currentNode.next;
|
|
16
|
-
steps -= 1;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return currentNode;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
backward(n: number): Node<T> | null {
|
|
23
|
-
let currentNode: Node<T> | null = this;
|
|
24
|
-
let steps = n;
|
|
25
|
-
|
|
26
|
-
while (steps > 0 && currentNode) {
|
|
27
|
-
currentNode = currentNode.prev;
|
|
28
|
-
steps -= 1;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return currentNode;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export class DoublyLinkedList<T> {
|
|
36
|
-
static EMPTY_SIZE = 0;
|
|
37
|
-
private size = DoublyLinkedList.EMPTY_SIZE;
|
|
38
|
-
private head: Node<T> | null = null;
|
|
39
|
-
private tail: Node<T> | null = null;
|
|
40
|
-
|
|
41
|
-
getSize(): DoublyLinkedList<T>["size"] {
|
|
42
|
-
return this.size;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
isEmpty(): boolean {
|
|
46
|
-
return this.size === 0;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
getHead(): DoublyLinkedList<T>["head"] {
|
|
50
|
-
return this.head;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
getTail(): DoublyLinkedList<T>["tail"] {
|
|
54
|
-
return this.tail;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
append(node: Node<T>): void {
|
|
58
|
-
if (this.tail === null) {
|
|
59
|
-
this.head = node;
|
|
60
|
-
this.tail = node;
|
|
61
|
-
} else {
|
|
62
|
-
this.tail.next = node;
|
|
63
|
-
node.prev = this.tail;
|
|
64
|
-
this.tail = node;
|
|
65
|
-
}
|
|
66
|
-
this.size += 1;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
prepend(node: Node<T>): void {
|
|
70
|
-
if (this.head === null) {
|
|
71
|
-
this.head = node;
|
|
72
|
-
this.tail = node;
|
|
73
|
-
} else {
|
|
74
|
-
node.next = this.head;
|
|
75
|
-
this.head.prev = node;
|
|
76
|
-
this.head = node;
|
|
77
|
-
}
|
|
78
|
-
this.size += 1;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
clear(): void {
|
|
82
|
-
this.size = 0;
|
|
83
|
-
this.head = null;
|
|
84
|
-
this.tail = null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
remove(node: Node<T>): void {
|
|
88
|
-
if (node.prev) {
|
|
89
|
-
node.prev.next = node.next;
|
|
90
|
-
} else {
|
|
91
|
-
this.head = node.next;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (node.next) {
|
|
95
|
-
node.next.prev = node.prev;
|
|
96
|
-
} else {
|
|
97
|
-
this.tail = node.prev;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
this.size -= 1;
|
|
101
|
-
node.prev = null;
|
|
102
|
-
node.next = null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
insertAfter(node: Node<T>, target: Node<T>): void {
|
|
106
|
-
if (target === this.tail) {
|
|
107
|
-
this.append(node);
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const nextNode = target.next!;
|
|
112
|
-
this.size += 1;
|
|
113
|
-
|
|
114
|
-
node.prev = target;
|
|
115
|
-
node.next = nextNode;
|
|
116
|
-
|
|
117
|
-
nextNode.prev = node;
|
|
118
|
-
|
|
119
|
-
target.next = node;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
insertBefore(node: Node<T>, target: Node<T>): void {
|
|
123
|
-
if (target === this.head) {
|
|
124
|
-
this.prepend(node);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const prevNode = target.prev!;
|
|
129
|
-
this.size += 1;
|
|
130
|
-
|
|
131
|
-
node.next = target;
|
|
132
|
-
node.prev = prevNode;
|
|
133
|
-
|
|
134
|
-
prevNode.next = node;
|
|
135
|
-
|
|
136
|
-
target.prev = node;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
find(callback: (node: Node<T>) => boolean): Node<T> | null {
|
|
140
|
-
let current = this.head;
|
|
141
|
-
while (current) {
|
|
142
|
-
if (callback(current)) return current;
|
|
143
|
-
current = current.next;
|
|
144
|
-
}
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
reverse(): void {
|
|
149
|
-
[this.head, this.tail] = [this.tail, this.head];
|
|
150
|
-
|
|
151
|
-
for (const node of this) {
|
|
152
|
-
const originalNext = node.next;
|
|
153
|
-
node.next = node.prev;
|
|
154
|
-
node.prev = originalNext;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
toArray(): Node<T>[] {
|
|
159
|
-
return Array.from(this);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
static fromArray<T>(array: T[]): DoublyLinkedList<T> {
|
|
163
|
-
const dll = new DoublyLinkedList<T>();
|
|
164
|
-
for (const item of array) {
|
|
165
|
-
dll.append(new Node<T>(item));
|
|
166
|
-
}
|
|
167
|
-
return dll;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
*[Symbol.iterator](): IterableIterator<Node<T>> {
|
|
171
|
-
let current: Node<T> | null = this.head;
|
|
172
|
-
while (current) {
|
|
173
|
-
yield current;
|
|
174
|
-
current = current.next;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
package/src/duration-ms.vo.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export const DurationMsError = { Invalid: "duration.invalid" };
|
|
4
|
-
|
|
5
|
-
// Stryker disable all
|
|
6
|
-
export const DurationMs = z.number(DurationMsError.Invalid).int(DurationMsError.Invalid).brand("DurationMs");
|
|
7
|
-
// Stryker restore all
|
|
8
|
-
|
|
9
|
-
export type DurationMsType = z.infer<typeof DurationMs>;
|
package/src/duration.service.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { DurationMs, type DurationMsType } from "./duration-ms.vo";
|
|
2
|
-
import type { MultiplicationFactorType } from "./multiplication-factor.vo";
|
|
3
|
-
import type { RoundingStrategy } from "./rounding.strategy";
|
|
4
|
-
import { RoundingDecimalStrategy } from "./rounding-decimal.strategy";
|
|
5
|
-
import { RoundingToNearestStrategy } from "./rounding-to-nearest.strategy";
|
|
6
|
-
|
|
7
|
-
export class Duration {
|
|
8
|
-
private static readonly rounding: RoundingStrategy = new RoundingDecimalStrategy(2);
|
|
9
|
-
private readonly internal: DurationMsType;
|
|
10
|
-
|
|
11
|
-
static readonly MIN = Duration.Ms(1);
|
|
12
|
-
|
|
13
|
-
private static readonly NS_IN_MS = 1000000;
|
|
14
|
-
private static readonly MS_IN_SECOND = 1_000;
|
|
15
|
-
private static readonly MS_IN_MINUTE = 60 * Duration.MS_IN_SECOND;
|
|
16
|
-
private static readonly MS_IN_HOUR = 60 * Duration.MS_IN_MINUTE;
|
|
17
|
-
private static readonly MS_IN_DAY = 24 * Duration.MS_IN_HOUR;
|
|
18
|
-
private static readonly MS_IN_WEEK = 7 * Duration.MS_IN_DAY;
|
|
19
|
-
|
|
20
|
-
private constructor(candidateMs: number) {
|
|
21
|
-
this.internal = DurationMs.parse(candidateMs);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static Weeks(value: number): Duration {
|
|
25
|
-
return new Duration(value * Duration.MS_IN_WEEK);
|
|
26
|
-
}
|
|
27
|
-
static Days(value: number): Duration {
|
|
28
|
-
return new Duration(value * Duration.MS_IN_DAY);
|
|
29
|
-
}
|
|
30
|
-
static Hours(value: number): Duration {
|
|
31
|
-
return new Duration(value * Duration.MS_IN_HOUR);
|
|
32
|
-
}
|
|
33
|
-
static Minutes(value: number): Duration {
|
|
34
|
-
return new Duration(value * Duration.MS_IN_MINUTE);
|
|
35
|
-
}
|
|
36
|
-
static Seconds(value: number): Duration {
|
|
37
|
-
return new Duration(value * Duration.MS_IN_SECOND);
|
|
38
|
-
}
|
|
39
|
-
static Ms(value: number): Duration {
|
|
40
|
-
return new Duration(value);
|
|
41
|
-
}
|
|
42
|
-
static Ns(value: number): Duration {
|
|
43
|
-
return new Duration(new RoundingToNearestStrategy().round(value / Duration.NS_IN_MS));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
get weeks(): number {
|
|
47
|
-
return Duration.rounding.round(this.internal / Duration.MS_IN_WEEK);
|
|
48
|
-
}
|
|
49
|
-
get days(): number {
|
|
50
|
-
return Duration.rounding.round(this.internal / Duration.MS_IN_DAY);
|
|
51
|
-
}
|
|
52
|
-
get hours(): number {
|
|
53
|
-
return Duration.rounding.round(this.internal / Duration.MS_IN_HOUR);
|
|
54
|
-
}
|
|
55
|
-
get minutes(): number {
|
|
56
|
-
return Duration.rounding.round(this.internal / Duration.MS_IN_MINUTE);
|
|
57
|
-
}
|
|
58
|
-
get seconds(): number {
|
|
59
|
-
return Duration.rounding.round(this.internal / Duration.MS_IN_SECOND);
|
|
60
|
-
}
|
|
61
|
-
get ms(): DurationMsType {
|
|
62
|
-
return this.internal;
|
|
63
|
-
}
|
|
64
|
-
get ns(): number {
|
|
65
|
-
return this.internal * Duration.NS_IN_MS;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
isLongerThan(another: Duration): boolean {
|
|
69
|
-
return this.internal > another.internal;
|
|
70
|
-
}
|
|
71
|
-
isShorterThan(another: Duration): boolean {
|
|
72
|
-
return this.internal < another.internal;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
equals(other: Duration): boolean {
|
|
76
|
-
return this.internal === other.internal;
|
|
77
|
-
}
|
|
78
|
-
add(another: Duration): Duration {
|
|
79
|
-
return Duration.Ms(this.internal + another.internal);
|
|
80
|
-
}
|
|
81
|
-
subtract(another: Duration): Duration {
|
|
82
|
-
return Duration.Ms(this.internal - another.internal);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
times(factor: MultiplicationFactorType): Duration {
|
|
86
|
-
const rounding = new RoundingToNearestStrategy();
|
|
87
|
-
|
|
88
|
-
return Duration.Ms(rounding.round(this.internal * factor));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
toAbsolute(): Duration {
|
|
92
|
-
return Duration.Ms(Math.abs(this.internal));
|
|
93
|
-
}
|
|
94
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { EmailType } from "./email.vo";
|
|
2
|
-
|
|
3
|
-
export class EmailMask {
|
|
4
|
-
static censor(email: EmailType): string {
|
|
5
|
-
const [local, domain] = email.split("@");
|
|
6
|
-
|
|
7
|
-
if (local.length <= 2) return `${"*".repeat(local.length)}@${domain}`;
|
|
8
|
-
|
|
9
|
-
const firstCharacter = local.at(0);
|
|
10
|
-
const censoredPart = "*".repeat(local.length - 2);
|
|
11
|
-
const lastCharacter = local.at(-1);
|
|
12
|
-
|
|
13
|
-
const censoredLocal = `${firstCharacter}${censoredPart}${lastCharacter}`;
|
|
14
|
-
|
|
15
|
-
return `${censoredLocal}@${domain}`;
|
|
16
|
-
}
|
|
17
|
-
}
|
package/src/email.vo.ts
DELETED
package/src/etags.vo.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { RevisionValue, type RevisionValueType } from "./revision-value.vo";
|
|
2
|
-
|
|
3
|
-
type ETagValueType = string;
|
|
4
|
-
|
|
5
|
-
export class ETag {
|
|
6
|
-
static HEADER_NAME = "ETag";
|
|
7
|
-
|
|
8
|
-
static IF_MATCH_HEADER_NAME = "if-match";
|
|
9
|
-
|
|
10
|
-
readonly value: ETagValueType;
|
|
11
|
-
|
|
12
|
-
private constructor(readonly revision: RevisionValueType) {
|
|
13
|
-
this.value = revision.toString();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static fromHeader(value?: ETagValueType): ETag | null {
|
|
17
|
-
const candidate = Number(value);
|
|
18
|
-
|
|
19
|
-
if (Number.isNaN(candidate)) return null;
|
|
20
|
-
return new ETag(RevisionValue.parse(candidate));
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export type WeakETagValueType = string;
|
|
25
|
-
|
|
26
|
-
export const WeakETagError = { Invalid: "weak.etag.invalid" };
|
|
27
|
-
|
|
28
|
-
export class WeakETag {
|
|
29
|
-
static HEADER_NAME = "ETag";
|
|
30
|
-
|
|
31
|
-
static IF_MATCH_HEADER_NAME = "if-match";
|
|
32
|
-
|
|
33
|
-
readonly value: WeakETagValueType;
|
|
34
|
-
|
|
35
|
-
private constructor(readonly revision: RevisionValueType) {
|
|
36
|
-
this.value = `W/${revision.toString()}`;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
static fromHeader(value?: WeakETagValueType): WeakETag | null {
|
|
40
|
-
if (!value?.startsWith("W/")) throw new Error(WeakETagError.Invalid);
|
|
41
|
-
|
|
42
|
-
const candidate = Number(value.split("W/")[1]);
|
|
43
|
-
|
|
44
|
-
if (Number.isNaN(candidate)) return null;
|
|
45
|
-
return new WeakETag(RevisionValue.parse(candidate));
|
|
46
|
-
}
|
|
47
|
-
}
|
package/src/extension.vo.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export const ExtensionError = {
|
|
4
|
-
Type: "extension.type",
|
|
5
|
-
Empty: "extension.empty",
|
|
6
|
-
TooLong: "extension.too.long",
|
|
7
|
-
BadChars: "extension.bad.chars",
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
// Lowercase letters and digits allowed
|
|
11
|
-
const EXTENSION_WHITELIST = /^[a-z0-9]+$/;
|
|
12
|
-
|
|
13
|
-
const LEADING_DOT_FILE = /^\./;
|
|
14
|
-
|
|
15
|
-
// Stryker disable all
|
|
16
|
-
export const Extension = z
|
|
17
|
-
// Stryker restore all
|
|
18
|
-
.string(ExtensionError.Type)
|
|
19
|
-
.toLowerCase()
|
|
20
|
-
.min(2, ExtensionError.Empty)
|
|
21
|
-
.max(16, ExtensionError.TooLong)
|
|
22
|
-
// Transform ".png" -> "png"
|
|
23
|
-
.transform((value) => value.replace(LEADING_DOT_FILE, ""))
|
|
24
|
-
.refine((value) => EXTENSION_WHITELIST.test(value), ExtensionError.BadChars)
|
|
25
|
-
.brand("Extension");
|
|
26
|
-
|
|
27
|
-
export type ExtensionType = z.infer<typeof Extension>;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export const FeatureFlagValueError = { Invalid: "feature.flag.value.invalid" };
|
|
4
|
-
|
|
5
|
-
export enum FeatureFlagEnum {
|
|
6
|
-
yes = "yes",
|
|
7
|
-
no = "no",
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const FeatureFlagValue = z.enum(FeatureFlagEnum, FeatureFlagValueError.Invalid);
|
|
11
|
-
|
|
12
|
-
export type FeatureFlagValueType = z.infer<typeof FeatureFlagValue>;
|
package/src/feature-flag.vo.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { FeatureFlagEnum, type FeatureFlagValueType } from "./feature-flag-value.vo";
|
|
2
|
-
|
|
3
|
-
export class FeatureFlag {
|
|
4
|
-
static isEnabled(flag: FeatureFlagValueType): boolean {
|
|
5
|
-
return flag === FeatureFlagEnum.yes;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
static isDisabled(flag: FeatureFlagValueType): boolean {
|
|
9
|
-
return flag === FeatureFlagEnum.no;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
import { DirectoryPathAbsoluteSchema } from "./directory-path-absolute.vo";
|
|
3
|
-
import { Filename } from "./filename.vo";
|
|
4
|
-
|
|
5
|
-
export const FilePathAbsoluteSchemaError = {
|
|
6
|
-
Type: "file.path.absolute.type",
|
|
7
|
-
LeadingSlash: "file.path.absolute.leading.slash",
|
|
8
|
-
TrailingSlash: "file.path.absolute.trailing.slash",
|
|
9
|
-
BackslashForbidden: "file.path.absolute.backslash.forbidden",
|
|
10
|
-
Empty: "file.path.absolute.empty",
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// Stryker disable all
|
|
14
|
-
export const FilePathAbsoluteSchema = z
|
|
15
|
-
// Stryker restore all
|
|
16
|
-
.string(FilePathAbsoluteSchemaError.Type)
|
|
17
|
-
.min(1, FilePathAbsoluteSchemaError.Empty)
|
|
18
|
-
.refine((value) => value.startsWith("/"), FilePathAbsoluteSchemaError.LeadingSlash)
|
|
19
|
-
.refine((value) => !value.endsWith("/"), FilePathAbsoluteSchemaError.TrailingSlash)
|
|
20
|
-
.refine((value) => !value.includes("\\"), FilePathAbsoluteSchemaError.BackslashForbidden)
|
|
21
|
-
.transform((normalized) => {
|
|
22
|
-
const index = normalized.lastIndexOf("/");
|
|
23
|
-
|
|
24
|
-
const directoryCandidate = index === 0 ? "/" : normalized.slice(0, index);
|
|
25
|
-
const filenameCandidate = normalized.slice(index + 1);
|
|
26
|
-
|
|
27
|
-
const directory = DirectoryPathAbsoluteSchema.parse(directoryCandidate);
|
|
28
|
-
const filename = Filename.fromString(filenameCandidate);
|
|
29
|
-
|
|
30
|
-
return { directory, filename };
|
|
31
|
-
})
|
|
32
|
-
.brand("FilePathAbsoluteSchema");
|
|
33
|
-
|
|
34
|
-
export type FilePathAbsoluteType = z.infer<typeof FilePathAbsoluteSchema>;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
import { DirectoryPathRelativeSchema } from "./directory-path-relative.vo";
|
|
3
|
-
import { Filename } from "./filename.vo";
|
|
4
|
-
|
|
5
|
-
export const FilePathRelativeSchemaError = {
|
|
6
|
-
Type: "file.path.relative.type",
|
|
7
|
-
LeadingSlash: "file.path.relative.leading.slash",
|
|
8
|
-
BackslashForbidden: "file.path.relative.backslash.forbidden",
|
|
9
|
-
RequiresDirectory: "file.path.relative.requires.directory",
|
|
10
|
-
Empty: "file.path.relative.empty",
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// Stryker disable all
|
|
14
|
-
export const FilePathRelativeSchema = z
|
|
15
|
-
// Stryker restore all
|
|
16
|
-
.string(FilePathRelativeSchemaError.Type)
|
|
17
|
-
.min(1, FilePathRelativeSchemaError.Empty)
|
|
18
|
-
.refine((value) => !value.startsWith("/"), FilePathRelativeSchemaError.LeadingSlash)
|
|
19
|
-
.refine((value) => !value.includes("\\"), FilePathRelativeSchemaError.BackslashForbidden)
|
|
20
|
-
.refine((value) => value.includes("/"), FilePathRelativeSchemaError.RequiresDirectory)
|
|
21
|
-
.transform((normalized) => {
|
|
22
|
-
const lastSlashIndex = normalized.lastIndexOf("/");
|
|
23
|
-
|
|
24
|
-
const directoryCandidate = normalized.slice(0, lastSlashIndex);
|
|
25
|
-
const filenameCandidate = normalized.slice(lastSlashIndex + 1);
|
|
26
|
-
|
|
27
|
-
const directory = DirectoryPathRelativeSchema.parse(directoryCandidate);
|
|
28
|
-
const filename = Filename.fromString(filenameCandidate);
|
|
29
|
-
|
|
30
|
-
return { directory, filename };
|
|
31
|
-
})
|
|
32
|
-
.brand("FilePathRelativeSchema");
|
|
33
|
-
|
|
34
|
-
export type FilePathRelativeType = z.infer<typeof FilePathRelativeSchema>;
|
package/src/file-path.vo.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { DirectoryPathAbsoluteSchema, type DirectoryPathAbsoluteType } from "./directory-path-absolute.vo";
|
|
2
|
-
import { DirectoryPathRelativeSchema, type DirectoryPathRelativeType } from "./directory-path-relative.vo";
|
|
3
|
-
import { FilePathAbsoluteSchema } from "./file-path-absolute-schema.vo";
|
|
4
|
-
import { FilePathRelativeSchema } from "./file-path-relative-schema.vo";
|
|
5
|
-
import type { Filename } from "./filename.vo";
|
|
6
|
-
|
|
7
|
-
export class FilePathRelative {
|
|
8
|
-
private constructor(
|
|
9
|
-
private readonly directory: DirectoryPathRelativeType,
|
|
10
|
-
private readonly filename: Filename,
|
|
11
|
-
) {}
|
|
12
|
-
|
|
13
|
-
static fromParts(directoryCandidate: string, filename: Filename): FilePathRelative {
|
|
14
|
-
const directory = DirectoryPathRelativeSchema.parse(directoryCandidate);
|
|
15
|
-
|
|
16
|
-
return new FilePathRelative(directory, filename);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
static fromPartsSafe(directory: DirectoryPathRelativeType, filename: Filename): FilePathRelative {
|
|
20
|
-
return new FilePathRelative(directory, filename);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static fromString(candidate: string): FilePathRelative {
|
|
24
|
-
const schema = FilePathRelativeSchema.parse(candidate);
|
|
25
|
-
|
|
26
|
-
return new FilePathRelative(schema.directory, schema.filename);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
get(): string {
|
|
30
|
-
return `${this.directory}/${this.filename.get()}`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
getDirectory(): DirectoryPathRelativeType {
|
|
34
|
-
return this.directory;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
getFilename(): Filename {
|
|
38
|
-
return this.filename;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
withDirectory(newDirectory: DirectoryPathRelativeType): FilePathRelative {
|
|
42
|
-
return new FilePathRelative(newDirectory, this.filename);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
withFilename(newFilename: Filename): FilePathRelative {
|
|
46
|
-
return new FilePathRelative(this.directory, newFilename);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
toAbsolute(newDirectory: DirectoryPathAbsoluteType): FilePathAbsolute {
|
|
50
|
-
return FilePathAbsolute.fromPartsSafe(newDirectory, this.filename);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export class FilePathAbsolute {
|
|
55
|
-
private constructor(
|
|
56
|
-
private readonly directory: DirectoryPathAbsoluteType,
|
|
57
|
-
private readonly filename: Filename,
|
|
58
|
-
) {}
|
|
59
|
-
|
|
60
|
-
static fromParts(directoryCandidate: string, filename: Filename): FilePathAbsolute {
|
|
61
|
-
const directory = DirectoryPathAbsoluteSchema.parse(directoryCandidate);
|
|
62
|
-
|
|
63
|
-
return new FilePathAbsolute(directory, filename);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
static fromPartsSafe(directory: DirectoryPathAbsoluteType, filename: Filename): FilePathAbsolute {
|
|
67
|
-
return new FilePathAbsolute(directory, filename);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
static fromString(candidate: string): FilePathAbsolute {
|
|
71
|
-
const schema = FilePathAbsoluteSchema.parse(candidate);
|
|
72
|
-
|
|
73
|
-
return new FilePathAbsolute(schema.directory, schema.filename);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
get(): string {
|
|
77
|
-
if (this.directory === "/") return `/${this.filename.get()}`;
|
|
78
|
-
return `${this.directory}/${this.filename.get()}`;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
getDirectory(): DirectoryPathAbsoluteType {
|
|
82
|
-
return this.directory;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
getFilename(): Filename {
|
|
86
|
-
return this.filename;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
withDirectory(newDirectory: DirectoryPathAbsoluteType): FilePathAbsolute {
|
|
90
|
-
return new FilePathAbsolute(newDirectory, this.filename);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
withFilename(newFilename: Filename): FilePathAbsolute {
|
|
94
|
-
return new FilePathAbsolute(this.directory, newFilename);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
toRelative(newDirectory: DirectoryPathRelativeType): FilePathRelative {
|
|
98
|
-
return FilePathRelative.fromPartsSafe(newDirectory, this.filename);
|
|
99
|
-
}
|
|
100
|
-
}
|
package/src/filename-affix.vo.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export enum FilenameAffixStrategy {
|
|
4
|
-
prefix = "prefix",
|
|
5
|
-
suffix = "suffix",
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export const FilenameAffixError = {
|
|
9
|
-
Type: "affix.type",
|
|
10
|
-
Empty: "affix.empty",
|
|
11
|
-
TooLong: "affix.too.long",
|
|
12
|
-
BadChars: "affix.bad.chars",
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
// Letters, digits, underscores, and hyphens allowed
|
|
16
|
-
const FILENAME_AFFIX_WHITELIST = /^[a-zA-Z0-9_-]+$/;
|
|
17
|
-
|
|
18
|
-
// Stryker disable all
|
|
19
|
-
export const FilenameAffix = z
|
|
20
|
-
// Stryker restore all
|
|
21
|
-
.string(FilenameAffixError.Type)
|
|
22
|
-
.min(1, FilenameAffixError.Empty)
|
|
23
|
-
.max(32, FilenameAffixError.TooLong)
|
|
24
|
-
.regex(FILENAME_AFFIX_WHITELIST, FilenameAffixError.BadChars)
|
|
25
|
-
.brand("FilenameAffix");
|
|
26
|
-
|
|
27
|
-
export type FilenameAffixType = z.infer<typeof FilenameAffix>;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
import { Basename } from "./basename.vo";
|
|
3
|
-
import { Extension } from "./extension.vo";
|
|
4
|
-
|
|
5
|
-
export const FilenameFromStringError = {
|
|
6
|
-
Type: "filename.from.string.type",
|
|
7
|
-
Invalid: "filename.from.string.invalid",
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
// .+ at least one character, advances to the last dot
|
|
11
|
-
// .
|
|
12
|
-
// .+ at least one character
|
|
13
|
-
const DOT_WITH_SIDES = /^.+\..+$/;
|
|
14
|
-
|
|
15
|
-
export const FilenameFromString = z
|
|
16
|
-
.string(FilenameFromStringError.Type)
|
|
17
|
-
.regex(DOT_WITH_SIDES, FilenameFromStringError.Invalid)
|
|
18
|
-
.transform((value) => {
|
|
19
|
-
const index = value.lastIndexOf(".");
|
|
20
|
-
|
|
21
|
-
const basename = Basename.parse(value.slice(0, index));
|
|
22
|
-
const extension = Extension.parse(value.slice(index + 1));
|
|
23
|
-
|
|
24
|
-
return { basename, extension };
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
export type FilenameFromStringType = z.infer<typeof FilenameFromString>;
|