@bgord/tools 1.2.19 → 1.2.21
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/duration.service.d.ts +3 -0
- package/dist/duration.service.js +7 -0
- 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 -89
- 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/sum.service.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export class Sum {
|
|
2
|
-
static of(values: readonly number[]): number {
|
|
3
|
-
return values.reduce((sum, x) => sum + x, 0);
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
static precise(values: readonly number[]): number {
|
|
7
|
-
let sum = 0;
|
|
8
|
-
let compensation = 0;
|
|
9
|
-
|
|
10
|
-
for (const value of values) {
|
|
11
|
-
const adjusted = value - compensation;
|
|
12
|
-
const temporary = sum + adjusted;
|
|
13
|
-
compensation = temporary - sum - adjusted;
|
|
14
|
-
sum = temporary;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return sum;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export class ThousandsSeparator {
|
|
2
|
-
private static DEFAULT_SEPARATOR = " ";
|
|
3
|
-
|
|
4
|
-
static format(value: number, separator = ThousandsSeparator.DEFAULT_SEPARATOR): string {
|
|
5
|
-
// B - not a word boundary, prevents inserting at the very start
|
|
6
|
-
// (?=([0-9]{3})+(?![0-9])) - positive lookahead, find three digits
|
|
7
|
-
// (?![0-9]) - negative lookahead, the next character is not a digit
|
|
8
|
-
return value.toString().replace(/\B(?=([0-9]{3})+(?![0-9]))/g, separator);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export const TimeZoneOffsetValueError = {
|
|
4
|
-
Type: "time.zone.offset.value.type",
|
|
5
|
-
Min: "time.zone.offset.value.min",
|
|
6
|
-
Max: "time.zone.offset.value.max",
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
// Stryker disable all
|
|
10
|
-
export const TimeZoneOffsetValue = z.coerce
|
|
11
|
-
// Stryker restore all
|
|
12
|
-
.number(TimeZoneOffsetValueError.Type)
|
|
13
|
-
.int(TimeZoneOffsetValueError.Type)
|
|
14
|
-
// UTC+14 (Kiribati)
|
|
15
|
-
.min(-840, TimeZoneOffsetValueError.Min)
|
|
16
|
-
// UTC-12 (Baker Island)
|
|
17
|
-
.max(720, TimeZoneOffsetValueError.Max)
|
|
18
|
-
.default(0) // Default to UTC if missing or invalid
|
|
19
|
-
.brand("TimeZoneOffsetValue");
|
|
20
|
-
|
|
21
|
-
export type TimeZoneOffsetValueType = z.infer<typeof TimeZoneOffsetValue>;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export const TimestampValueError = { Invalid: "timestamp.invalid" };
|
|
4
|
-
|
|
5
|
-
// Stryker disable all
|
|
6
|
-
export const TimestampValue = z
|
|
7
|
-
// Stryker restore all
|
|
8
|
-
.number(TimestampValueError.Invalid)
|
|
9
|
-
.int(TimestampValueError.Invalid)
|
|
10
|
-
.gte(0, TimestampValueError.Invalid)
|
|
11
|
-
.brand("TimestampValue");
|
|
12
|
-
|
|
13
|
-
export type TimestampValueType = z.infer<typeof TimestampValue>;
|
package/src/timestamp.vo.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { Duration } from "./duration.service";
|
|
2
|
-
import { TimestampValue, type TimestampValueType } from "./timestamp-value.vo";
|
|
3
|
-
|
|
4
|
-
export class Timestamp {
|
|
5
|
-
constructor(private readonly value: TimestampValueType) {}
|
|
6
|
-
|
|
7
|
-
static fromValue(value: TimestampValueType): Timestamp {
|
|
8
|
-
return new Timestamp(value);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
static fromNumber(value: number): Timestamp {
|
|
12
|
-
return new Timestamp(TimestampValue.parse(value));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
static fromDate(value: Date): Timestamp {
|
|
16
|
-
return Timestamp.fromNumber(value.getTime());
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
static fromDateLike(value: string): Timestamp {
|
|
20
|
-
return Timestamp.fromNumber(new Date(value).getTime());
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
add(duration: Duration): Timestamp {
|
|
24
|
-
return Timestamp.fromNumber(this.value + duration.ms);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
subtract(duration: Duration): Timestamp {
|
|
28
|
-
return Timestamp.fromNumber(this.value - duration.ms);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
difference(another: Timestamp): Duration {
|
|
32
|
-
return Duration.Ms(this.value - another.value);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
isBefore(another: Timestamp): boolean {
|
|
36
|
-
return this.value < another.value;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
isBeforeOrEqual(another: Timestamp): boolean {
|
|
40
|
-
return this.value <= another.value;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
isAfter(another: Timestamp): boolean {
|
|
44
|
-
return this.value > another.value;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
isAfterOrEqual(another: Timestamp): boolean {
|
|
48
|
-
return this.value >= another.value;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
equals(another: Timestamp): boolean {
|
|
52
|
-
return this.value === another.value;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
get ms(): TimestampValueType {
|
|
56
|
-
return this.value;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
toJSON(): TimestampValueType {
|
|
60
|
-
return this.value;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
toString(): string {
|
|
64
|
-
return this.value.toString();
|
|
65
|
-
}
|
|
66
|
-
}
|
package/src/timezone.vo.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export const TimezoneError = {
|
|
4
|
-
Type: "timezone.type",
|
|
5
|
-
Empty: "timezone.empty",
|
|
6
|
-
TooLong: "timezone.too.long",
|
|
7
|
-
Invalid: "timezone.invalid",
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
// Stryker disable all
|
|
11
|
-
export const Timezone = z
|
|
12
|
-
// Stryker restore all
|
|
13
|
-
.string(TimezoneError.Type)
|
|
14
|
-
.min(1, TimezoneError.Empty)
|
|
15
|
-
.max(128, TimezoneError.TooLong)
|
|
16
|
-
.refine((value) => {
|
|
17
|
-
try {
|
|
18
|
-
new Intl.DateTimeFormat("en-US", { timeZone: value }).format(Date.now());
|
|
19
|
-
return true;
|
|
20
|
-
} catch {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}, TimezoneError.Invalid)
|
|
24
|
-
.brand("Timezone");
|
|
25
|
-
|
|
26
|
-
export type TimezoneType = z.infer<typeof Timezone>;
|
package/src/ts-utils.ts
DELETED
package/src/url-with-slash.vo.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export const UrlWithSlashError = { Invalid: "url.with.slash.invalid" };
|
|
4
|
-
|
|
5
|
-
// Stryker disable all
|
|
6
|
-
export const UrlWithSlash = z
|
|
7
|
-
// Stryker disable all
|
|
8
|
-
.url(UrlWithSlashError.Invalid)
|
|
9
|
-
.refine((value) => value.endsWith("/"), UrlWithSlashError.Invalid)
|
|
10
|
-
.brand("UrlWithSlash");
|
|
11
|
-
|
|
12
|
-
export type UrlWithSlashType = z.infer<typeof UrlWithSlash>;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export const UrlWithoutSlashError = { Invalid: "url.without.slash.invalid" };
|
|
4
|
-
|
|
5
|
-
// Stryker disable all
|
|
6
|
-
export const UrlWithoutSlash = z
|
|
7
|
-
// Stryker restore all
|
|
8
|
-
.url(UrlWithoutSlashError.Invalid)
|
|
9
|
-
.refine((value) => !value.endsWith("/"), UrlWithoutSlashError.Invalid)
|
|
10
|
-
.brand("UrlWithoutSlash");
|
|
11
|
-
|
|
12
|
-
export type UrlWithoutSlashType = z.infer<typeof UrlWithoutSlash>;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Random } from "./random.service";
|
|
2
|
-
|
|
3
|
-
export class VisuallyUnambiguousCharactersGenerator {
|
|
4
|
-
static chars = [
|
|
5
|
-
"a",
|
|
6
|
-
"b",
|
|
7
|
-
"c",
|
|
8
|
-
"d",
|
|
9
|
-
"e",
|
|
10
|
-
"f",
|
|
11
|
-
"h",
|
|
12
|
-
"i",
|
|
13
|
-
"j",
|
|
14
|
-
"k",
|
|
15
|
-
"m",
|
|
16
|
-
"n",
|
|
17
|
-
"o",
|
|
18
|
-
"p",
|
|
19
|
-
"r",
|
|
20
|
-
"s",
|
|
21
|
-
"t",
|
|
22
|
-
"w",
|
|
23
|
-
"x",
|
|
24
|
-
"y",
|
|
25
|
-
"3",
|
|
26
|
-
"4",
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
static generate(length = 1): string {
|
|
30
|
-
return Array.from({ length })
|
|
31
|
-
.map(
|
|
32
|
-
() =>
|
|
33
|
-
VisuallyUnambiguousCharactersGenerator.chars[
|
|
34
|
-
Random.generate({ min: 0, max: VisuallyUnambiguousCharactersGenerator.chars.length - 1 })
|
|
35
|
-
],
|
|
36
|
-
)
|
|
37
|
-
.join("");
|
|
38
|
-
}
|
|
39
|
-
}
|
package/src/week-iso-id.vo.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { getISOWeeksInYear } from "date-fns";
|
|
2
|
-
import { z } from "zod/v4";
|
|
3
|
-
|
|
4
|
-
export const WeekIsoIdError = {
|
|
5
|
-
Type: "week.iso.id.type",
|
|
6
|
-
BadChars: "week.iso.id.bad.chars",
|
|
7
|
-
Invalid: "week.iso.id.invalid",
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
// Four digits, hypen, W, followed by two digits
|
|
11
|
-
const WEEK_ISO_ID_CHARS_WHITELIST = /^[0-9]{4}-W[0-9]{2}$/;
|
|
12
|
-
|
|
13
|
-
// Stryker disable all
|
|
14
|
-
export const WeekIsoId = z
|
|
15
|
-
// Stryker restore all
|
|
16
|
-
.string(WeekIsoIdError.Type)
|
|
17
|
-
.regex(WEEK_ISO_ID_CHARS_WHITELIST, WeekIsoIdError.BadChars)
|
|
18
|
-
.refine((value) => {
|
|
19
|
-
const [year, week] = value.split("-W").map(Number);
|
|
20
|
-
// ISO-8601 rule: Jan 4 is always in week 01 of the ISO week-year.
|
|
21
|
-
const weeksInYear = getISOWeeksInYear(Date.UTC(year, 0, 4));
|
|
22
|
-
|
|
23
|
-
if (week < 1) return false;
|
|
24
|
-
return week <= weeksInYear;
|
|
25
|
-
}, WeekIsoIdError.Invalid)
|
|
26
|
-
.brand("WeekIsoId");
|
|
27
|
-
|
|
28
|
-
export type WeekIsoIdType = z.infer<typeof WeekIsoId>;
|
package/src/week.vo.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { addWeeks, endOfISOWeek, getISOWeek, getISOWeekYear, setISOWeek, startOfISOWeek } from "date-fns";
|
|
2
|
-
import { DateRange } from "./date-range.vo";
|
|
3
|
-
import { Integer, type IntegerType } from "./integer.vo";
|
|
4
|
-
import { Timestamp } from "./timestamp.vo";
|
|
5
|
-
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
6
|
-
import { WeekIsoId, type WeekIsoIdType } from "./week-iso-id.vo";
|
|
7
|
-
|
|
8
|
-
export class Week extends DateRange {
|
|
9
|
-
static fromTimestamp(timestamp: Timestamp): Week {
|
|
10
|
-
const start = Timestamp.fromNumber(startOfISOWeek(timestamp.ms).getTime());
|
|
11
|
-
const end = Timestamp.fromNumber(endOfISOWeek(timestamp.ms).getTime());
|
|
12
|
-
|
|
13
|
-
return new Week(start, end);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static fromTimestampValue(timestamp: TimestampValueType): Week {
|
|
17
|
-
return Week.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static fromNow(now: Timestamp): Week {
|
|
21
|
-
return Week.fromTimestamp(now);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static fromIsoId(isoId: WeekIsoIdType): Week {
|
|
25
|
-
const [year, week] = WeekIsoId.parse(isoId).split("-W").map(Number);
|
|
26
|
-
|
|
27
|
-
// ISO-8601 rule: Jan 4 is always in week 01 of the ISO week-year.
|
|
28
|
-
const reference = setISOWeek(Date.UTC(year, 0, 4), week).getTime();
|
|
29
|
-
|
|
30
|
-
return Week.fromTimestamp(Timestamp.fromNumber(reference));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
toIsoId(): WeekIsoIdType {
|
|
34
|
-
const year = getISOWeekYear(this.getStart().ms);
|
|
35
|
-
const week = getISOWeek(this.getStart().ms);
|
|
36
|
-
|
|
37
|
-
return WeekIsoId.parse(`${year}-W${String(week).padStart(2, "0")}`);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
previous(): Week {
|
|
41
|
-
return this.shift(Integer.parse(-1));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
next(): Week {
|
|
45
|
-
return this.shift(Integer.parse(1));
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
shift(count: IntegerType): Week {
|
|
49
|
-
const shifted = addWeeks(this.getStart().ms, count).getTime();
|
|
50
|
-
|
|
51
|
-
return Week.fromTimestamp(Timestamp.fromNumber(shifted));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
toString(): string {
|
|
55
|
-
return this.toIsoId();
|
|
56
|
-
}
|
|
57
|
-
}
|
package/src/weekday.vo.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { Timestamp } from "./timestamp.vo";
|
|
2
|
-
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
3
|
-
|
|
4
|
-
export type WeekdayFormatter = (value: Weekday["value"]) => string;
|
|
5
|
-
|
|
6
|
-
export enum WeekdayFormatterEnum {
|
|
7
|
-
FULL = "FULL", // "Sunday"
|
|
8
|
-
SHORT = "SHORT", // "Sun"
|
|
9
|
-
ISO_NUMBER = "ISO_NUMBER", // Monday=1 ... Sunday=7
|
|
10
|
-
ZERO_BASED_NUMBER = "ZERO_BASED_NUMBER", // Sunday=0 ... Saturday=6 (JS)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const WeekdayValueError = { Invalid: "weekday.invalid" };
|
|
14
|
-
|
|
15
|
-
const FULL_NAMES: readonly string[] = [
|
|
16
|
-
"Sunday",
|
|
17
|
-
"Monday",
|
|
18
|
-
"Tuesday",
|
|
19
|
-
"Wednesday",
|
|
20
|
-
"Thursday",
|
|
21
|
-
"Friday",
|
|
22
|
-
"Saturday",
|
|
23
|
-
] as const;
|
|
24
|
-
|
|
25
|
-
const SHORT_NAMES: readonly string[] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] as const;
|
|
26
|
-
|
|
27
|
-
export const WeekdayFormatters: Record<WeekdayFormatterEnum, WeekdayFormatter> = {
|
|
28
|
-
FULL: (value) => FULL_NAMES[value],
|
|
29
|
-
SHORT: (value) => SHORT_NAMES[value],
|
|
30
|
-
ISO_NUMBER: (value) => (value === 0 ? 7 : value).toString(), // ISO-8601: Mon=1..Sun=7
|
|
31
|
-
ZERO_BASED_NUMBER: (value) => value.toString(), // JS getUTCDay(): Sun=0..Sat=6
|
|
32
|
-
} as const;
|
|
33
|
-
|
|
34
|
-
export class Weekday {
|
|
35
|
-
// 0..6 (Sun..Sat)
|
|
36
|
-
private readonly value: number;
|
|
37
|
-
|
|
38
|
-
// default formatter used by toString()/format() when no runtime formatter given
|
|
39
|
-
private readonly formatter: WeekdayFormatter;
|
|
40
|
-
|
|
41
|
-
static readonly SUNDAY = new Weekday(0);
|
|
42
|
-
static readonly MONDAY = new Weekday(1);
|
|
43
|
-
static readonly TUESDAY = new Weekday(2);
|
|
44
|
-
static readonly WEDNESDAY = new Weekday(3);
|
|
45
|
-
static readonly THURSDAY = new Weekday(4);
|
|
46
|
-
static readonly FRIDAY = new Weekday(5);
|
|
47
|
-
static readonly SATURDAY = new Weekday(6);
|
|
48
|
-
|
|
49
|
-
constructor(candidate: number, formatter?: WeekdayFormatter) {
|
|
50
|
-
if (!Number.isInteger(candidate) || candidate < 0 || candidate > 6) {
|
|
51
|
-
throw new Error(WeekdayValueError.Invalid);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
this.value = candidate;
|
|
55
|
-
this.formatter = formatter ?? WeekdayFormatters.FULL;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
static fromTimestamp(timestamp: Timestamp, formatter?: WeekdayFormatter): Weekday {
|
|
59
|
-
const dayZeroBased = new Date(timestamp.ms).getUTCDay(); // 0..6
|
|
60
|
-
return new Weekday(dayZeroBased, formatter);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
static fromTimestampValue(timestamp: TimestampValueType): Weekday {
|
|
64
|
-
return Weekday.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
get(): number {
|
|
68
|
-
return this.value;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
format(): string {
|
|
72
|
-
return this.formatter(this.value);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
toString(): string {
|
|
76
|
-
return this.format();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
equals(another: Weekday): boolean {
|
|
80
|
-
return this.value === another.value;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** ISO-8601 weekday number: Monday=1 ... Sunday=7 */
|
|
84
|
-
toIsoNumber(): number {
|
|
85
|
-
return this.value === 0 ? 7 : this.value;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
isMonday(): boolean {
|
|
89
|
-
return this.value === 1;
|
|
90
|
-
}
|
|
91
|
-
isTuesday(): boolean {
|
|
92
|
-
return this.value === 2;
|
|
93
|
-
}
|
|
94
|
-
isWednesday(): boolean {
|
|
95
|
-
return this.value === 3;
|
|
96
|
-
}
|
|
97
|
-
isThursday(): boolean {
|
|
98
|
-
return this.value === 4;
|
|
99
|
-
}
|
|
100
|
-
isFriday(): boolean {
|
|
101
|
-
return this.value === 5;
|
|
102
|
-
}
|
|
103
|
-
isSaturday(): boolean {
|
|
104
|
-
return this.value === 6;
|
|
105
|
-
}
|
|
106
|
-
isSunday(): boolean {
|
|
107
|
-
return this.value === 0;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
static list(formatter?: WeekdayFormatter): readonly Weekday[] {
|
|
111
|
-
return Array.from({ length: 7 }, (_, index) => new Weekday(index, formatter));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
static listMondayFirst(formatter?: WeekdayFormatter): readonly Weekday[] {
|
|
115
|
-
const [Sunday, ...rest] = Weekday.list(formatter);
|
|
116
|
-
|
|
117
|
-
return [...rest, Sunday];
|
|
118
|
-
}
|
|
119
|
-
}
|
package/src/weight-grams.vo.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export const WeightGramsError = { Type: "weight.grams.type", Invalid: "weight.grams.invalid" };
|
|
4
|
-
|
|
5
|
-
// Stryker disable all
|
|
6
|
-
export const WeightGrams = z
|
|
7
|
-
// Stryker restore all
|
|
8
|
-
.number(WeightGramsError.Type)
|
|
9
|
-
.int(WeightGramsError.Type)
|
|
10
|
-
.gte(0, WeightGramsError.Invalid)
|
|
11
|
-
.brand("WeightGrams");
|
|
12
|
-
|
|
13
|
-
export type WeightGramsType = z.infer<typeof WeightGrams>;
|
package/src/weight.vo.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import type { DivisionFactorType } from "./division-factor.vo";
|
|
2
|
-
import type { MultiplicationFactorType } from "./multiplication-factor.vo";
|
|
3
|
-
import type { RoundingStrategy } from "./rounding.strategy";
|
|
4
|
-
import { RoundingToNearestStrategy } from "./rounding-to-nearest.strategy";
|
|
5
|
-
import { WeightGrams, type WeightGramsType } from "./weight-grams.vo";
|
|
6
|
-
|
|
7
|
-
export class Weight {
|
|
8
|
-
private static readonly GRAMS_PER_KILOGRAM = 1_000;
|
|
9
|
-
|
|
10
|
-
private constructor(
|
|
11
|
-
private readonly grams: WeightGramsType,
|
|
12
|
-
private readonly rounding: RoundingStrategy = new RoundingToNearestStrategy(),
|
|
13
|
-
) {}
|
|
14
|
-
|
|
15
|
-
static fromKilograms(
|
|
16
|
-
kilograms: number,
|
|
17
|
-
rounding: RoundingStrategy = new RoundingToNearestStrategy(),
|
|
18
|
-
): Weight {
|
|
19
|
-
const grams = rounding.round(kilograms * Weight.GRAMS_PER_KILOGRAM);
|
|
20
|
-
|
|
21
|
-
return new Weight(WeightGrams.parse(grams), rounding);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static fromGrams(grams: number, rounding: RoundingStrategy = new RoundingToNearestStrategy()): Weight {
|
|
25
|
-
return new Weight(WeightGrams.parse(grams), rounding);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static zero(): Weight {
|
|
29
|
-
return new Weight(WeightGrams.parse(0));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get(): number {
|
|
33
|
-
return this.grams;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
toKilograms(): number {
|
|
37
|
-
const kilograms = this.grams / Weight.GRAMS_PER_KILOGRAM;
|
|
38
|
-
|
|
39
|
-
return this.rounding.round(kilograms);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
format(): string {
|
|
43
|
-
return `${this.grams} g`;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
add(other: Weight): Weight {
|
|
47
|
-
return new Weight(WeightGrams.parse(this.grams + other.grams));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
subtract(other: Weight): Weight {
|
|
51
|
-
const result = this.grams - other.grams;
|
|
52
|
-
|
|
53
|
-
return new Weight(WeightGrams.parse(Math.max(0, result)), this.rounding);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
multiply(factor: MultiplicationFactorType): Weight {
|
|
57
|
-
const grams = this.rounding.round(this.grams * factor);
|
|
58
|
-
|
|
59
|
-
return new Weight(WeightGrams.parse(grams));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
divide(divisor: DivisionFactorType): Weight {
|
|
63
|
-
const grams = this.rounding.round(this.grams / divisor);
|
|
64
|
-
|
|
65
|
-
return new Weight(WeightGrams.parse(grams));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
equals(other: Weight): boolean {
|
|
69
|
-
return this.grams === other.grams;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
greaterThan(other: Weight): boolean {
|
|
73
|
-
return this.grams > other.grams;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
lessThan(other: Weight): boolean {
|
|
77
|
-
return this.grams < other.grams;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
isZero(): boolean {
|
|
81
|
-
return this.grams === 0;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
toString(): string {
|
|
85
|
-
return this.format();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
toJSON(): number {
|
|
89
|
-
return this.grams;
|
|
90
|
-
}
|
|
91
|
-
}
|
package/src/year-iso-id.vo.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
export const YearIsoIdError = { Type: "year.iso.id.type", BadChars: "year.iso.id.bad.chars" };
|
|
4
|
-
|
|
5
|
-
// Four digits
|
|
6
|
-
const YEAR_ISO_ID_CHARS_WHITELIST = /^[0-9]{4}$/;
|
|
7
|
-
|
|
8
|
-
// Stryker disable all
|
|
9
|
-
export const YearIsoId = z
|
|
10
|
-
// Stryker restore all
|
|
11
|
-
.string(YearIsoIdError.Type)
|
|
12
|
-
.regex(YEAR_ISO_ID_CHARS_WHITELIST, YearIsoIdError.BadChars)
|
|
13
|
-
.brand("YearIsoId");
|
|
14
|
-
|
|
15
|
-
export type YearIsoIdType = z.infer<typeof YearIsoId>;
|
package/src/year.vo.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { addYears, endOfYear, getYear, startOfYear } from "date-fns";
|
|
2
|
-
import { DateRange } from "./date-range.vo";
|
|
3
|
-
import { Integer, type IntegerType } from "./integer.vo";
|
|
4
|
-
import { Timestamp } from "./timestamp.vo";
|
|
5
|
-
import type { TimestampValueType } from "./timestamp-value.vo";
|
|
6
|
-
import { YearIsoId, type YearIsoIdType } from "./year-iso-id.vo";
|
|
7
|
-
|
|
8
|
-
export class Year extends DateRange {
|
|
9
|
-
static fromTimestamp(timestamp: Timestamp): Year {
|
|
10
|
-
const start = Timestamp.fromNumber(startOfYear(timestamp.ms).getTime());
|
|
11
|
-
const end = Timestamp.fromNumber(endOfYear(timestamp.ms).getTime());
|
|
12
|
-
|
|
13
|
-
return new Year(start, end);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static fromTimestampValue(timestamp: TimestampValueType): Year {
|
|
17
|
-
return Year.fromTimestamp(Timestamp.fromValue(timestamp));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static fromNow(now: Timestamp): Year {
|
|
21
|
-
return Year.fromTimestamp(now);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static fromNumber(candidate: number): Year {
|
|
25
|
-
return Year.fromIsoId(YearIsoId.parse(String(candidate)));
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static fromIsoId(isoId: YearIsoIdType): Year {
|
|
29
|
-
const reference = Date.UTC(Number(isoId));
|
|
30
|
-
|
|
31
|
-
return Year.fromTimestamp(Timestamp.fromNumber(reference));
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
toIsoId(): YearIsoIdType {
|
|
35
|
-
return YearIsoId.parse(String(getYear(this.getStart().ms)));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
isLeapYear(): boolean {
|
|
39
|
-
const year = getYear(this.getStart().ms);
|
|
40
|
-
|
|
41
|
-
if (year % 400 === 0) return true;
|
|
42
|
-
if (year % 100 === 0) return false;
|
|
43
|
-
return year % 4 === 0;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
previous(): Year {
|
|
47
|
-
return this.shift(Integer.parse(-1));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
next(): Year {
|
|
51
|
-
return this.shift(Integer.parse(1));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
shift(count: IntegerType): Year {
|
|
55
|
-
const shifted = addYears(this.getStart().ms, count).getTime();
|
|
56
|
-
|
|
57
|
-
return Year.fromTimestamp(Timestamp.fromNumber(shifted));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
toString(): string {
|
|
61
|
-
return this.toIsoId();
|
|
62
|
-
}
|
|
63
|
-
}
|
package/src/z-score.service.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Mean } from "./mean.service";
|
|
2
|
-
import { PopulationStandardDeviation } from "./population-standard-deviation.service";
|
|
3
|
-
import type { RoundingStrategy } from "./rounding.strategy";
|
|
4
|
-
import { RoundingDecimalStrategy } from "./rounding-decimal.strategy";
|
|
5
|
-
|
|
6
|
-
export const ZScoreError = { NotEnoughValues: "z.score.not.enough.values" };
|
|
7
|
-
|
|
8
|
-
export class ZScore {
|
|
9
|
-
private readonly mean: number;
|
|
10
|
-
private readonly standardDeviation: number;
|
|
11
|
-
|
|
12
|
-
constructor(
|
|
13
|
-
values: number[],
|
|
14
|
-
private readonly rounding: RoundingStrategy = new RoundingDecimalStrategy(2),
|
|
15
|
-
) {
|
|
16
|
-
if (values.length < 2) throw new Error(ZScoreError.NotEnoughValues);
|
|
17
|
-
|
|
18
|
-
this.mean = Mean.calculate(values);
|
|
19
|
-
this.standardDeviation = PopulationStandardDeviation.calculate(values);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
calculate(value: number): number {
|
|
23
|
-
return this.rounding.round((value - this.mean) / this.standardDeviation);
|
|
24
|
-
}
|
|
25
|
-
}
|