@bgord/tools 0.12.26 → 0.13.1

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.
Files changed (106) hide show
  1. package/dist/clock.vo.d.ts +4 -2
  2. package/dist/clock.vo.js +7 -1
  3. package/dist/directory-path-absolute.vo.d.ts +1 -1
  4. package/dist/directory-path-absolute.vo.js +1 -1
  5. package/dist/file-path-absolute-schema.vo.d.ts +1 -1
  6. package/dist/hour.vo.d.ts +2 -0
  7. package/dist/hour.vo.js +11 -11
  8. package/dist/index.d.ts +7 -3
  9. package/dist/index.js +7 -3
  10. package/dist/mean.service.js +1 -2
  11. package/dist/mime.vo.js +2 -4
  12. package/dist/min-max-scaler.service.js +5 -10
  13. package/dist/minute.vo.d.ts +2 -0
  14. package/dist/minute.vo.js +8 -10
  15. package/dist/money.vo.js +3 -7
  16. package/dist/month-iso-id.vo.d.ts +3 -0
  17. package/dist/month-iso-id.vo.js +15 -0
  18. package/dist/month.vo.d.ts +9 -0
  19. package/dist/month.vo.js +22 -0
  20. package/dist/outlier-detector.service.js +1 -2
  21. package/dist/package-version.vo.js +0 -5
  22. package/dist/pagination.service.js +1 -8
  23. package/dist/percentage.service.js +1 -2
  24. package/dist/population-standard-deviation.service.js +1 -2
  25. package/dist/quarter-iso-id.vo.d.ts +3 -0
  26. package/dist/quarter-iso-id.vo.js +10 -0
  27. package/dist/quarter.vo.d.ts +9 -0
  28. package/dist/quarter.vo.js +24 -0
  29. package/dist/random.service.js +4 -8
  30. package/dist/reordering.service.js +3 -6
  31. package/dist/revision.vo.js +2 -4
  32. package/dist/simple-linear-regression.service.js +6 -12
  33. package/dist/stepper.service.js +2 -4
  34. package/dist/stopwatch.service.js +2 -3
  35. package/dist/timezone.vo.js +2 -6
  36. package/dist/tsconfig.tsbuildinfo +1 -1
  37. package/dist/visually-unambiguous-characters-generator.service.js +2 -4
  38. package/dist/weekday.vo.d.ts +37 -0
  39. package/dist/weekday.vo.js +86 -0
  40. package/dist/year-iso-id.vo.d.ts +3 -0
  41. package/dist/year-iso-id.vo.js +8 -0
  42. package/dist/year.vo.d.ts +11 -0
  43. package/dist/year.vo.js +32 -0
  44. package/dist/z-score.service.js +1 -2
  45. package/package.json +3 -3
  46. package/readme.md +7 -3
  47. package/src/api-key.vo.ts +0 -1
  48. package/src/basename.vo.ts +0 -1
  49. package/src/clock.vo.ts +9 -2
  50. package/src/date-calculator.service.ts +1 -4
  51. package/src/date-formatter.service.ts +0 -1
  52. package/src/directory-path-absolute.vo.ts +1 -1
  53. package/src/dll.service.ts +0 -5
  54. package/src/email-mask.service.ts +0 -1
  55. package/src/etags.vo.ts +0 -1
  56. package/src/extension.vo.ts +0 -1
  57. package/src/feature-flag.vo.ts +1 -1
  58. package/src/filename-from-string.vo.ts +0 -1
  59. package/src/filename-suffix.vo.ts +0 -1
  60. package/src/hour.vo.ts +15 -13
  61. package/src/image.vo.ts +0 -2
  62. package/src/index.ts +7 -3
  63. package/src/language.vo.ts +0 -1
  64. package/src/mean.service.ts +1 -3
  65. package/src/mime.vo.ts +2 -9
  66. package/src/min-max-scaler.service.ts +6 -21
  67. package/src/minute.vo.ts +11 -15
  68. package/src/money.vo.ts +3 -9
  69. package/src/month-iso-id.vo.ts +25 -0
  70. package/src/month.vo.ts +26 -0
  71. package/src/object-key.vo.ts +0 -1
  72. package/src/outlier-detector.service.ts +1 -3
  73. package/src/package-version.vo.ts +0 -12
  74. package/src/pagination.service.ts +4 -29
  75. package/src/percentage.service.ts +1 -5
  76. package/src/population-standard-deviation.service.ts +1 -3
  77. package/src/quarter-iso-id.vo.ts +18 -0
  78. package/src/quarter.vo.ts +28 -0
  79. package/src/random.service.ts +5 -19
  80. package/src/rate-limiter.service.ts +0 -3
  81. package/src/reordering.service.ts +6 -19
  82. package/src/revision.vo.ts +2 -8
  83. package/src/simple-linear-regression.service.ts +6 -21
  84. package/src/size.vo.ts +0 -1
  85. package/src/stepper.service.ts +2 -9
  86. package/src/stopwatch.service.ts +2 -4
  87. package/src/streak-calculator.service.ts +1 -6
  88. package/src/time-zone-offset-value.vo.ts +0 -1
  89. package/src/timestamp.vo.ts +0 -1
  90. package/src/timezone.vo.ts +2 -9
  91. package/src/ts-utils.ts +0 -2
  92. package/src/visually-unambiguous-characters-generator.service.ts +2 -4
  93. package/src/week-iso-id.vo.ts +0 -1
  94. package/src/weekday.vo.ts +101 -0
  95. package/src/year-iso-id.vo.ts +13 -0
  96. package/src/year.vo.ts +36 -0
  97. package/src/z-score.service.ts +1 -3
  98. package/dist/build-version.vo.d.ts +0 -3
  99. package/dist/build-version.vo.js +0 -2
  100. package/dist/filter.vo.d.ts +0 -17
  101. package/dist/filter.vo.js +0 -22
  102. package/dist/leap-year-checker.service.d.ts +0 -4
  103. package/dist/leap-year-checker.service.js +0 -9
  104. package/src/build-version.vo.ts +0 -5
  105. package/src/filter.vo.ts +0 -38
  106. package/src/leap-year-checker.service.ts +0 -11
@@ -1,5 +1,6 @@
1
- import { type Hour } from "./hour.vo";
2
- import type { Minute } from "./minute.vo";
1
+ import { Hour } from "./hour.vo";
2
+ import { Minute } from "./minute.vo";
3
+ import type { TimestampType } from "./timestamp.vo";
3
4
  export type ClockFormatter = (hour: Hour, minute: Minute) => string;
4
5
  declare enum ClockFormatterEnum {
5
6
  TWENTY_FOUR_HOURS = "TWENTY_FOUR_HOURS",
@@ -11,6 +12,7 @@ export declare class Clock {
11
12
  private readonly minute;
12
13
  private readonly formatter;
13
14
  constructor(hour: Hour, minute: Minute, formatter?: ClockFormatter);
15
+ static fromUtcTimestamp(timestamp: TimestampType, formatter?: ClockFormatter): Clock;
14
16
  get(formatter?: ClockFormatter): {
15
17
  raw: {
16
18
  hour: number;
package/dist/clock.vo.js CHANGED
@@ -1,4 +1,5 @@
1
- import { HourFormatters } from "./hour.vo";
1
+ import { Hour, HourFormatters } from "./hour.vo";
2
+ import { Minute } from "./minute.vo";
2
3
  var ClockFormatterEnum;
3
4
  (function (ClockFormatterEnum) {
4
5
  ClockFormatterEnum["TWENTY_FOUR_HOURS"] = "TWENTY_FOUR_HOURS";
@@ -17,6 +18,11 @@ export class Clock {
17
18
  this.minute = minute;
18
19
  this.formatter = formatter ?? ClockFormatters.TWENTY_FOUR_HOURS;
19
20
  }
21
+ static fromUtcTimestamp(timestamp, formatter) {
22
+ const hour = Hour.fromUtcTimestamp(timestamp);
23
+ const minute = Minute.fromUtcTimestamp(timestamp);
24
+ return new Clock(hour, minute, formatter);
25
+ }
20
26
  get(formatter) {
21
27
  const format = formatter ?? this.formatter;
22
28
  return {
@@ -1,3 +1,3 @@
1
1
  import { z } from "zod/v4";
2
- export declare const DirectoryPathAbsoluteSchema: z.core.$ZodBranded<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<string, string>>, "directory_path_absolute_">;
2
+ export declare const DirectoryPathAbsoluteSchema: z.core.$ZodBranded<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<string, string>>, "directory_path_absolute">;
3
3
  export type DirectoryPathAbsoluteType = z.infer<typeof DirectoryPathAbsoluteSchema>;
@@ -14,4 +14,4 @@ export const DirectoryPathAbsoluteSchema = z
14
14
  const segments = value.slice(1).split("/");
15
15
  return segments.every((segment) => segment.length > 0 && /^[A-Za-z0-9._-]+$/.test(segment) && segment !== "." && segment !== "..");
16
16
  }, "abs_dir_bad_segments")
17
- .brand("directory_path_absolute_");
17
+ .brand("directory_path_absolute");
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod/v4";
2
2
  import { Filename } from "./filename.vo";
3
3
  export declare const FilePathAbsoluteSchema: z.ZodPipe<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodTransform<string, string>>, z.ZodTransform<{
4
- directory: string & z.core.$brand<"directory_path_absolute_">;
4
+ directory: string & z.core.$brand<"directory_path_absolute">;
5
5
  filename: Filename;
6
6
  }, string>>;
package/dist/hour.vo.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { TimestampType } from "./timestamp.vo";
1
2
  export type HourFormatter = (value: Hour["value"]) => string;
2
3
  export declare enum HourFormatterEnum {
3
4
  TWENTY_FOUR_HOURS = "TWENTY_FOUR_HOURS",
@@ -20,5 +21,6 @@ export declare class Hour {
20
21
  equals(another: Hour): boolean;
21
22
  isAfter(another: Hour): boolean;
22
23
  isBefore(another: Hour): boolean;
24
+ static fromUtcTimestamp(timestamp: TimestampType, formatter?: HourFormatter): Hour;
23
25
  static list(formatter?: HourFormatter): Hour[];
24
26
  }
package/dist/hour.vo.js CHANGED
@@ -10,12 +10,11 @@ export const HourFormatters = {
10
10
  TWENTY_FOUR_HOURS: (value) => value.toString().padStart(2, "0"),
11
11
  TWENTY_FOUR_HOURS_WO_PADDING: (value) => value.toString(),
12
12
  AM_PM: (value) => {
13
- if (value < 12)
14
- return `${value.toString()} a.m.`;
15
- return `${value.toString()} p.m.`;
13
+ const twelveHour = value % 12 || 12;
14
+ return `${twelveHour.toString()} ${value < 12 ? "a.m." : "p.m."}`;
16
15
  },
17
- TWELVE_HOURS: (value) => (value % 12).toString().padStart(2, "0"),
18
- TWELVE_HOURS_WO_PADDING: (value) => (value % 12).toString(),
16
+ TWELVE_HOURS: (value) => (value % 12 || 12).toString().padStart(2, "0"),
17
+ TWELVE_HOURS_WO_PADDING: (value) => (value % 12 || 12).toString(),
19
18
  };
20
19
  export class Hour {
21
20
  value;
@@ -23,15 +22,12 @@ export class Hour {
23
22
  static ZERO = new Hour(0);
24
23
  static MAX = new Hour(23);
25
24
  constructor(candidate, formatter) {
26
- if (!Number.isInteger(candidate)) {
25
+ if (!Number.isInteger(candidate))
27
26
  throw new Error("Invalid hour");
28
- }
29
- if (candidate < 0) {
27
+ if (candidate < 0)
30
28
  throw new Error("Invalid hour");
31
- }
32
- if (candidate >= 24) {
29
+ if (candidate >= 24)
33
30
  throw new Error("Invalid hour");
34
- }
35
31
  this.value = candidate;
36
32
  this.formatter = formatter ?? HourFormatters.TWENTY_FOUR_HOURS;
37
33
  }
@@ -48,6 +44,10 @@ export class Hour {
48
44
  isBefore(another) {
49
45
  return this.value < another.get().raw;
50
46
  }
47
+ static fromUtcTimestamp(timestamp, formatter) {
48
+ const hours = new Date(timestamp).getUTCHours();
49
+ return new Hour(hours, formatter);
50
+ }
51
51
  static list(formatter) {
52
52
  return Array.from({ length: 24 }).map((_, index) => new Hour(index, formatter));
53
53
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from "./api-key.vo";
2
2
  export * from "./basename.vo";
3
- export * from "./build-version.vo";
4
3
  export * from "./clock.vo";
5
4
  export * from "./date-calculator.service";
6
5
  export * from "./date-formatter.service";
@@ -21,19 +20,19 @@ export * from "./file-path-relative-schema.vo";
21
20
  export * from "./filename.vo";
22
21
  export * from "./filename-from-string.vo";
23
22
  export * from "./filename-suffix.vo";
24
- export * from "./filter.vo";
25
23
  export * from "./hour.vo";
26
24
  export * from "./iban.vo";
27
25
  export * from "./iban-mask.service";
28
26
  export * from "./image.vo";
29
27
  export * from "./language.vo";
30
- export * from "./leap-year-checker.service";
31
28
  export * from "./mean.service";
32
29
  export * from "./mime.vo";
33
30
  export * from "./mime-types.vo";
34
31
  export * from "./min-max-scaler.service";
35
32
  export * from "./minute.vo";
36
33
  export * from "./money.vo";
34
+ export * from "./month.vo";
35
+ export * from "./month-iso-id.vo";
37
36
  export * from "./noop.service";
38
37
  export * from "./notification-template.vo";
39
38
  export * from "./object-key.vo";
@@ -42,6 +41,8 @@ export * from "./package-version.vo";
42
41
  export * from "./pagination.service";
43
42
  export * from "./percentage.service";
44
43
  export * from "./population-standard-deviation.service";
44
+ export * from "./quarter.vo";
45
+ export * from "./quarter-iso-id.vo";
45
46
  export * from "./random.service";
46
47
  export * from "./rate-limiter.service";
47
48
  export * from "./relative-date.vo";
@@ -63,4 +64,7 @@ export * from "./ts-utils";
63
64
  export * from "./visually-unambiguous-characters-generator.service";
64
65
  export * from "./week.vo";
65
66
  export * from "./week-iso-id.vo";
67
+ export * from "./weekday.vo";
68
+ export * from "./year.vo";
69
+ export * from "./year-iso-id.vo";
66
70
  export * from "./z-score.service";
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from "./api-key.vo";
2
2
  export * from "./basename.vo";
3
- export * from "./build-version.vo";
4
3
  export * from "./clock.vo";
5
4
  export * from "./date-calculator.service";
6
5
  export * from "./date-formatter.service";
@@ -21,19 +20,19 @@ export * from "./file-path-relative-schema.vo";
21
20
  export * from "./filename.vo";
22
21
  export * from "./filename-from-string.vo";
23
22
  export * from "./filename-suffix.vo";
24
- export * from "./filter.vo";
25
23
  export * from "./hour.vo";
26
24
  export * from "./iban.vo";
27
25
  export * from "./iban-mask.service";
28
26
  export * from "./image.vo";
29
27
  export * from "./language.vo";
30
- export * from "./leap-year-checker.service";
31
28
  export * from "./mean.service";
32
29
  export * from "./mime.vo";
33
30
  export * from "./mime-types.vo";
34
31
  export * from "./min-max-scaler.service";
35
32
  export * from "./minute.vo";
36
33
  export * from "./money.vo";
34
+ export * from "./month.vo";
35
+ export * from "./month-iso-id.vo";
37
36
  export * from "./noop.service";
38
37
  export * from "./notification-template.vo";
39
38
  export * from "./object-key.vo";
@@ -42,6 +41,8 @@ export * from "./package-version.vo";
42
41
  export * from "./pagination.service";
43
42
  export * from "./percentage.service";
44
43
  export * from "./population-standard-deviation.service";
44
+ export * from "./quarter.vo";
45
+ export * from "./quarter-iso-id.vo";
45
46
  export * from "./random.service";
46
47
  export * from "./rate-limiter.service";
47
48
  export * from "./relative-date.vo";
@@ -63,4 +64,7 @@ export * from "./ts-utils";
63
64
  export * from "./visually-unambiguous-characters-generator.service";
64
65
  export * from "./week.vo";
65
66
  export * from "./week-iso-id.vo";
67
+ export * from "./weekday.vo";
68
+ export * from "./year.vo";
69
+ export * from "./year-iso-id.vo";
66
70
  export * from "./z-score.service";
@@ -2,9 +2,8 @@ import { RoundToDecimal } from "./rounding.service";
2
2
  import { Sum } from "./sum.service";
3
3
  export class Mean {
4
4
  static calculate(values, rounding = new RoundToDecimal(2)) {
5
- if (values.length === 0) {
5
+ if (values.length === 0)
6
6
  throw new Error("Values should not be empty");
7
- }
8
7
  const mean = Sum.of(values) / values.length;
9
8
  return rounding.round(mean);
10
9
  }
package/dist/mime.vo.js CHANGED
@@ -6,12 +6,10 @@ export class Mime {
6
6
  subtype;
7
7
  constructor(value) {
8
8
  const [type, subtype] = value.split("/");
9
- if (typeof type !== "string" || type.length === 0) {
9
+ if (typeof type !== "string" || type.length === 0)
10
10
  throw new InvalidMimeError();
11
- }
12
- if (typeof subtype !== "string" || subtype.length === 0) {
11
+ if (typeof subtype !== "string" || subtype.length === 0)
13
12
  throw new InvalidMimeError();
14
- }
15
13
  this.raw = value;
16
14
  this.type = type;
17
15
  this.subtype = subtype;
@@ -9,12 +9,10 @@ export class MinMaxScaler {
9
9
  const rounding = config.rounding ?? new RoundToDecimal(2);
10
10
  const lower = config.bound?.lower ?? 0;
11
11
  const upper = config.bound?.upper ?? 1;
12
- if (config.max - config.min < 0) {
12
+ if (config.max - config.min < 0)
13
13
  throw new Error("Invalid MinMaxScaler min-max config");
14
- }
15
- if (upper - lower <= 0) {
14
+ if (upper - lower <= 0)
16
15
  throw new Error("Invalid MinMaxScaler bound config");
17
- }
18
16
  this.rounding = rounding;
19
17
  this.min = config.min;
20
18
  this.max = config.max;
@@ -23,9 +21,8 @@ export class MinMaxScaler {
23
21
  }
24
22
  scale(value) {
25
23
  const { min, max, lower, upper } = this;
26
- if (value < min || value > max) {
24
+ if (value < min || value > max)
27
25
  throw new Error("Value out of min/max range");
28
- }
29
26
  if (min === max)
30
27
  return {
31
28
  original: value,
@@ -43,9 +40,8 @@ export class MinMaxScaler {
43
40
  }
44
41
  descale(scaled) {
45
42
  const { min, max, lower, upper } = this;
46
- if (scaled < lower || scaled > upper) {
43
+ if (scaled < lower || scaled > upper)
47
44
  throw new Error("Scaled value out of bounds");
48
- }
49
45
  const result = ((scaled - lower) / (upper - lower)) * (max - min) + min;
50
46
  return {
51
47
  original: this.rounding.round(result),
@@ -55,9 +51,8 @@ export class MinMaxScaler {
55
51
  };
56
52
  }
57
53
  static getMinMax(values) {
58
- if (values.length === 0) {
54
+ if (values.length === 0)
59
55
  throw new Error("An empty array supplied");
60
- }
61
56
  return { min: Math.min(...values), max: Math.max(...values) };
62
57
  }
63
58
  }
@@ -1,8 +1,10 @@
1
+ import type { TimestampType } from "./timestamp.vo";
1
2
  export declare class Minute {
2
3
  private readonly value;
3
4
  static readonly ZERO: Minute;
4
5
  static readonly MAX: Minute;
5
6
  constructor(candidate: number);
7
+ static fromUtcTimestamp(timestamp: TimestampType): Minute;
6
8
  get(): {
7
9
  raw: number;
8
10
  formatted: string;
package/dist/minute.vo.js CHANGED
@@ -3,22 +3,20 @@ export class Minute {
3
3
  static ZERO = new Minute(0);
4
4
  static MAX = new Minute(59);
5
5
  constructor(candidate) {
6
- if (!Number.isInteger(candidate)) {
6
+ if (!Number.isInteger(candidate))
7
7
  throw new Error("Invalid minute");
8
- }
9
- if (candidate < 0) {
8
+ if (candidate < 0)
10
9
  throw new Error("Invalid minute");
11
- }
12
- if (candidate >= 60) {
10
+ if (candidate >= 60)
13
11
  throw new Error("Invalid minute");
14
- }
15
12
  this.value = candidate;
16
13
  }
14
+ static fromUtcTimestamp(timestamp) {
15
+ const minutes = new Date(timestamp).getUTCMinutes();
16
+ return new Minute(minutes);
17
+ }
17
18
  get() {
18
- return {
19
- raw: this.value,
20
- formatted: this.value.toString().padStart(2, "0"),
21
- };
19
+ return { raw: this.value, formatted: this.value.toString().padStart(2, "0") };
22
20
  }
23
21
  equals(another) {
24
22
  return this.value === another.get().raw;
package/dist/money.vo.js CHANGED
@@ -2,8 +2,8 @@ import { z } from "zod/v4";
2
2
  import { RoundToNearest } from "./rounding.service";
3
3
  export const MoneyAmount = z
4
4
  .number()
5
- .int({ message: "money.amount.invalid " })
6
- .min(0, { message: "money.amount.invalid " })
5
+ .int({ message: "money.amount.invalid" })
6
+ .min(0, { message: "money.amount.invalid" })
7
7
  .brand("MoneyAmount");
8
8
  export const MoneyMultiplicationFactor = z
9
9
  .number()
@@ -35,15 +35,11 @@ export class Money {
35
35
  }
36
36
  subtract(money) {
37
37
  const result = this.rounding.round(this.amount - money.getAmount());
38
- if (result < Money.ZERO) {
38
+ if (result < Money.ZERO)
39
39
  throw new Error("Less than zero");
40
- }
41
40
  return new Money(MoneyAmount.parse(result), this.rounding);
42
41
  }
43
42
  divide(factor) {
44
- if (factor === 0) {
45
- throw new Error("Cannot divide by zero");
46
- }
47
43
  const result = this.rounding.round(this.amount / factor);
48
44
  return new Money(MoneyAmount.parse(result), this.rounding);
49
45
  }
@@ -0,0 +1,3 @@
1
+ import { z } from "zod/v4";
2
+ export declare const MonthIsoId: z.ZodString;
3
+ export type MonthIsoIdType = z.infer<typeof MonthIsoId>;
@@ -0,0 +1,15 @@
1
+ import { z } from "zod/v4";
2
+ export const MonthIsoId = z
3
+ .string()
4
+ .regex(/^\d{4}-\d{2}$/)
5
+ .refine((value) => {
6
+ const [y, m] = value.split("-");
7
+ const year = Number(y);
8
+ const month = Number(m);
9
+ return (y.length === 4 &&
10
+ m.length === 2 &&
11
+ Number.isInteger(year) &&
12
+ Number.isInteger(month) &&
13
+ month >= 1 &&
14
+ month <= 12);
15
+ }, { message: "month-iso-id.invalid" });
@@ -0,0 +1,9 @@
1
+ import { DateRange } from "./date-range.vo";
2
+ import { type MonthIsoIdType } from "./month-iso-id.vo";
3
+ import { type TimestampType } from "./timestamp.vo";
4
+ export declare class Month extends DateRange {
5
+ toIsoId(): MonthIsoIdType;
6
+ static fromTimestamp(timestamp: TimestampType): Month;
7
+ static fromNow(now: TimestampType): Month;
8
+ static fromIsoId(iso: MonthIsoIdType): Month;
9
+ }
@@ -0,0 +1,22 @@
1
+ import { endOfMonth, startOfMonth } from "date-fns";
2
+ import { DateRange } from "./date-range.vo";
3
+ import { MonthIsoId } from "./month-iso-id.vo";
4
+ import { Timestamp } from "./timestamp.vo";
5
+ export class Month extends DateRange {
6
+ toIsoId() {
7
+ return new Date(this.getStart()).toISOString().slice(0, 7);
8
+ }
9
+ static fromTimestamp(timestamp) {
10
+ const start = Timestamp.parse(startOfMonth(timestamp).getTime());
11
+ const end = Timestamp.parse(endOfMonth(timestamp).getTime());
12
+ return new Month(start, end);
13
+ }
14
+ static fromNow(now) {
15
+ return Month.fromTimestamp(now);
16
+ }
17
+ static fromIsoId(iso) {
18
+ const [year, month] = MonthIsoId.parse(iso).split("-").map(Number);
19
+ const reference = new Date(Date.UTC(year, month - 1, 1));
20
+ return Month.fromTimestamp(Timestamp.parse(reference.getTime()));
21
+ }
22
+ }
@@ -3,9 +3,8 @@ export class OutlierDetector {
3
3
  zScore;
4
4
  threshold;
5
5
  constructor(values, threshold) {
6
- if (values.length < 2) {
6
+ if (values.length < 2)
7
7
  throw new Error("At least two values are needed");
8
- }
9
8
  this.zScore = new ZScore(values);
10
9
  this.threshold = Math.abs(threshold);
11
10
  }
@@ -17,11 +17,6 @@ export const PackageVersionValue = z
17
17
  Number.isInteger(Number(patch)))) {
18
18
  return false;
19
19
  }
20
- if (!(Number.isInteger(Number(major)) &&
21
- Number.isInteger(Number(minor)) &&
22
- Number.isInteger(Number(patch)))) {
23
- return false;
24
- }
25
20
  return true;
26
21
  }
27
22
  catch (_error) {
@@ -21,14 +21,7 @@ export class Pagination {
21
21
  const nextPage = currentPage < lastPage ? Page.parse(currentPage + 1) : undefined;
22
22
  return {
23
23
  result: config.result,
24
- meta: {
25
- exhausted,
26
- currentPage,
27
- previousPage,
28
- nextPage,
29
- lastPage,
30
- total: config.total,
31
- },
24
+ meta: { exhausted, currentPage, previousPage, nextPage, lastPage, total: config.total },
32
25
  };
33
26
  }
34
27
  static isExhausted(config) {
@@ -1,9 +1,8 @@
1
1
  import { RoundToNearest } from "./rounding.service";
2
2
  export class Percentage {
3
3
  static of(numerator, denominator, rounding = new RoundToNearest()) {
4
- if (denominator === 0) {
4
+ if (denominator === 0)
5
5
  throw new Error("Invalid denominator");
6
- }
7
6
  if (numerator === 0)
8
7
  return 0;
9
8
  return rounding.round((numerator / denominator) * 100);
@@ -3,9 +3,8 @@ import { RoundToDecimal } from "./rounding.service";
3
3
  import { Sum } from "./sum.service";
4
4
  export class PopulationStandardDeviation {
5
5
  static calculate(values, rounding = new RoundToDecimal(2)) {
6
- if (values.length < 2) {
6
+ if (values.length < 2)
7
7
  throw new Error("At least two values are needed");
8
- }
9
8
  const mean = Mean.calculate(values);
10
9
  const n = values.length;
11
10
  const squaredDifferences = values.map((value) => (value - mean) ** 2);
@@ -0,0 +1,3 @@
1
+ import { z } from "zod/v4";
2
+ export declare const QuarterIsoId: z.ZodString;
3
+ export type QuarterIsoIdType = z.infer<typeof QuarterIsoId>;
@@ -0,0 +1,10 @@
1
+ import { z } from "zod/v4";
2
+ export const QuarterIsoId = z
3
+ .string()
4
+ .regex(/^\d{4}-Q[1-4]$/)
5
+ .refine((value) => {
6
+ const [y, q] = value.split("-Q");
7
+ const year = Number(y);
8
+ const quarter = Number(q);
9
+ return (y.length === 4 && Number.isInteger(year) && Number.isInteger(quarter) && quarter >= 1 && quarter <= 4);
10
+ }, { message: "quarter-iso-id.invalid" });
@@ -0,0 +1,9 @@
1
+ import { DateRange } from "./date-range.vo";
2
+ import { type QuarterIsoIdType } from "./quarter-iso-id.vo";
3
+ import { type TimestampType } from "./timestamp.vo";
4
+ export declare class Quarter extends DateRange {
5
+ toIsoId(): QuarterIsoIdType;
6
+ static fromTimestamp(timestamp: TimestampType): Quarter;
7
+ static fromNow(now: TimestampType): Quarter;
8
+ static fromIsoId(isoId: QuarterIsoIdType): Quarter;
9
+ }
@@ -0,0 +1,24 @@
1
+ import { endOfQuarter, getQuarter, getYear, setQuarter, startOfQuarter } from "date-fns";
2
+ import { DateRange } from "./date-range.vo";
3
+ import { QuarterIsoId } from "./quarter-iso-id.vo";
4
+ import { Timestamp } from "./timestamp.vo";
5
+ export class Quarter extends DateRange {
6
+ toIsoId() {
7
+ const year = getYear(this.getStart());
8
+ const quarter = getQuarter(this.getStart());
9
+ return `${year}-Q${quarter}`;
10
+ }
11
+ static fromTimestamp(timestamp) {
12
+ const start = Timestamp.parse(startOfQuarter(timestamp).getTime());
13
+ const end = Timestamp.parse(endOfQuarter(timestamp).getTime());
14
+ return new Quarter(start, end);
15
+ }
16
+ static fromNow(now) {
17
+ return Quarter.fromTimestamp(now);
18
+ }
19
+ static fromIsoId(isoId) {
20
+ const [year, quarter] = QuarterIsoId.parse(isoId).split("-Q").map(Number);
21
+ const reference = setQuarter(new Date(Date.UTC(year, 0, 1)), quarter);
22
+ return Quarter.fromTimestamp(Timestamp.parse(reference.getTime()));
23
+ }
24
+ }
@@ -2,18 +2,14 @@ export class Random {
2
2
  static generate(config) {
3
3
  const min = config?.min ?? 0;
4
4
  const max = config?.max ?? 1;
5
- if (!Number.isInteger(min)) {
5
+ if (!Number.isInteger(min))
6
6
  throw new Error("Minimum value is not an integer");
7
- }
8
- if (!Number.isInteger(max)) {
7
+ if (!Number.isInteger(max))
9
8
  throw new Error("Maximum value is not an integer");
10
- }
11
- if (min === max) {
9
+ if (min === max)
12
10
  throw new Error("Minimum and maximum values cannot be equal");
13
- }
14
- if (min > max) {
11
+ if (min > max)
15
12
  throw new Error("Minimum value cannot be greater than maximum value");
16
- }
17
13
  return Math.floor(Math.random() * (max - min + 1)) + min;
18
14
  }
19
15
  }
@@ -73,21 +73,18 @@ export class ReorderingCalculator {
73
73
  }
74
74
  delete(id) {
75
75
  const item = this.dll.find((x) => x.data.eq(id));
76
- if (!item) {
76
+ if (!item)
77
77
  throw new Error("Cannot find Item");
78
- }
79
78
  this.dll.remove(item);
80
79
  this.recalculate();
81
80
  }
82
81
  transfer(transfer) {
83
82
  const current = this.dll.find((node) => node.data.eq(transfer.id));
84
83
  const target = this.dll.find((node) => node.data.position.eq(transfer.to));
85
- if (!current) {
84
+ if (!current)
86
85
  throw new Error("Cannot find current Item");
87
- }
88
- if (!target) {
86
+ if (!target)
89
87
  throw new Error("Cannot find target Item");
90
- }
91
88
  const direction = transfer.getDirection(current.data.position);
92
89
  if (direction === ReorderingTransferDirection.noop)
93
90
  return this.read();
@@ -20,15 +20,13 @@ export class Revision {
20
20
  return new Revision(this.value + 1);
21
21
  }
22
22
  static fromETag(etag) {
23
- if (!etag) {
23
+ if (!etag)
24
24
  throw new InvalidRevisionError();
25
- }
26
25
  return new Revision(etag.revision);
27
26
  }
28
27
  static fromWeakETag(weakEtag) {
29
- if (!weakEtag) {
28
+ if (!weakEtag)
30
29
  throw new InvalidRevisionError();
31
- }
32
30
  return new Revision(weakEtag.revision);
33
31
  }
34
32
  }
@@ -9,33 +9,27 @@ export class SimpleLinearRegression {
9
9
  }
10
10
  static fromPairs(pairs, rounding) {
11
11
  const n = pairs.length;
12
- if (n < 2) {
12
+ if (n < 2)
13
13
  throw new Error("At least two pairs needed");
14
- }
15
14
  const x = pairs.map((pair) => pair.x);
16
15
  const y = pairs.map((pair) => pair.y);
17
16
  const xx = x.map((x) => x ** 2);
18
17
  const xy = pairs.map((pair) => pair.x * pair.y);
19
18
  const sX = Sum.of(x);
20
- if (sX >= Number.MAX_SAFE_INTEGER) {
19
+ if (sX >= Number.MAX_SAFE_INTEGER)
21
20
  throw new Error("Sum of x values is too big");
22
- }
23
21
  const sY = Sum.of(y);
24
- if (sY >= Number.MAX_SAFE_INTEGER) {
22
+ if (sY >= Number.MAX_SAFE_INTEGER)
25
23
  throw new Error("Sum of y values is too big");
26
- }
27
24
  const sSX = Sum.of(xx);
28
- if (sSX >= Number.MAX_SAFE_INTEGER) {
25
+ if (sSX >= Number.MAX_SAFE_INTEGER)
29
26
  throw new Error("Sum of x squared values is too big");
30
- }
31
27
  const sXY = Sum.of(xy);
32
- if (sXY >= Number.MAX_SAFE_INTEGER) {
28
+ if (sXY >= Number.MAX_SAFE_INTEGER)
33
29
  throw new Error("Sum of x times y values is too big");
34
- }
35
30
  const bDenominator = sSX - sX ** 2 / n;
36
- if (bDenominator === 0) {
31
+ if (bDenominator === 0)
37
32
  throw new Error("Unable to create the model");
38
- }
39
33
  const b = (sXY - (sX * sY) / n) / bDenominator;
40
34
  const a = (sY - b * sX) / n;
41
35
  return new SimpleLinearRegression({ a, b }, rounding);