@bgord/tools 0.17.2 → 1.0.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 (257) hide show
  1. package/dist/age-years.vo.d.ts +11 -0
  2. package/dist/age-years.vo.js +9 -0
  3. package/dist/age.vo.d.ts +11 -16
  4. package/dist/age.vo.js +20 -31
  5. package/dist/api-key.vo.d.ts +3 -1
  6. package/dist/api-key.vo.js +10 -5
  7. package/dist/basename.vo.d.ts +9 -9
  8. package/dist/basename.vo.js +22 -22
  9. package/dist/clock.vo.d.ts +10 -4
  10. package/dist/clock.vo.js +12 -14
  11. package/dist/date-calculator.service.d.ts +2 -1
  12. package/dist/date-formatter.service.d.ts +3 -4
  13. package/dist/date-range.vo.d.ts +7 -1
  14. package/dist/date-range.vo.js +5 -2
  15. package/dist/day-iso-id.vo.d.ts +5 -2
  16. package/dist/day-iso-id.vo.js +11 -7
  17. package/dist/day.vo.d.ts +4 -3
  18. package/dist/day.vo.js +18 -16
  19. package/dist/directory-path-absolute.vo.d.ts +10 -6
  20. package/dist/directory-path-absolute.vo.js +19 -17
  21. package/dist/directory-path-relative.vo.d.ts +10 -7
  22. package/dist/directory-path-relative.vo.js +18 -17
  23. package/dist/division-factor.vo.d.ts +7 -0
  24. package/dist/division-factor.vo.js +9 -0
  25. package/dist/duration-ms.vo.d.ts +6 -0
  26. package/dist/duration-ms.vo.js +3 -0
  27. package/dist/duration.service.d.ts +2 -14
  28. package/dist/duration.service.js +16 -35
  29. package/dist/email-mask.service.d.ts +1 -6
  30. package/dist/email-mask.service.js +6 -8
  31. package/dist/etags.vo.d.ts +4 -3
  32. package/dist/etags.vo.js +3 -3
  33. package/dist/extension.vo.d.ts +6 -4
  34. package/dist/extension.vo.js +15 -10
  35. package/dist/feature-flag-value.vo.d.ts +10 -0
  36. package/dist/feature-flag-value.vo.js +8 -0
  37. package/dist/feature-flag.vo.d.ts +1 -7
  38. package/dist/feature-flag.vo.js +1 -7
  39. package/dist/file-path-absolute-schema.vo.d.ts +10 -7
  40. package/dist/file-path-absolute-schema.vo.js +17 -17
  41. package/dist/file-path-relative-schema.vo.d.ts +10 -7
  42. package/dist/file-path-relative-schema.vo.js +14 -12
  43. package/dist/file-path.vo.d.ts +4 -4
  44. package/dist/file-path.vo.js +8 -8
  45. package/dist/filename-from-string.vo.d.ts +4 -2
  46. package/dist/filename-from-string.vo.js +10 -8
  47. package/dist/filename-suffix.vo.d.ts +7 -3
  48. package/dist/filename-suffix.vo.js +13 -7
  49. package/dist/filename.vo.d.ts +2 -0
  50. package/dist/filename.vo.js +8 -2
  51. package/dist/height-milimiters.vo.d.ts +6 -0
  52. package/dist/height-milimiters.vo.js +10 -0
  53. package/dist/height.vo.d.ts +3 -20
  54. package/dist/height.vo.js +11 -62
  55. package/dist/hour-format.service.js +1 -1
  56. package/dist/hour-schema.vo.d.ts +7 -0
  57. package/dist/hour-schema.vo.js +8 -0
  58. package/dist/hour.vo.d.ts +4 -3
  59. package/dist/hour.vo.js +8 -8
  60. package/dist/iban-mask.service.d.ts +1 -3
  61. package/dist/iban-mask.service.js +2 -2
  62. package/dist/iban-schema.vo.d.ts +7 -0
  63. package/dist/iban-schema.vo.js +10 -0
  64. package/dist/iban.vo.d.ts +4 -10
  65. package/dist/iban.vo.js +6 -13
  66. package/dist/image.vo.d.ts +6 -4
  67. package/dist/image.vo.js +13 -12
  68. package/dist/index.d.ts +24 -2
  69. package/dist/index.js +24 -2
  70. package/dist/language.vo.d.ts +2 -1
  71. package/dist/language.vo.js +6 -4
  72. package/dist/linear-regression.service.d.ts +27 -0
  73. package/dist/{simple-linear-regression.service.js → linear-regression.service.js} +17 -15
  74. package/dist/mean.service.d.ts +3 -1
  75. package/dist/mean.service.js +3 -4
  76. package/dist/mime-types.vo.d.ts +1 -2
  77. package/dist/mime-value.vo.d.ts +9 -0
  78. package/dist/mime-value.vo.js +9 -0
  79. package/dist/mime.vo.d.ts +11 -17
  80. package/dist/mime.vo.js +10 -27
  81. package/dist/min-max-scaler.service.d.ts +7 -5
  82. package/dist/min-max-scaler.service.js +12 -10
  83. package/dist/minute-schema.vo.d.ts +7 -0
  84. package/dist/minute-schema.vo.js +8 -0
  85. package/dist/minute.vo.d.ts +4 -3
  86. package/dist/minute.vo.js +8 -8
  87. package/dist/money-amount.vo.d.ts +7 -0
  88. package/dist/money-amount.vo.js +7 -0
  89. package/dist/money.vo.d.ts +9 -18
  90. package/dist/money.vo.js +14 -27
  91. package/dist/month-iso-id.vo.d.ts +4 -2
  92. package/dist/month-iso-id.vo.js +13 -7
  93. package/dist/month.vo.d.ts +4 -3
  94. package/dist/month.vo.js +21 -21
  95. package/dist/multiplication-factor.vo.d.ts +7 -0
  96. package/dist/multiplication-factor.vo.js +9 -0
  97. package/dist/object-key.vo.d.ts +9 -6
  98. package/dist/object-key.vo.js +20 -19
  99. package/dist/outlier-detector.service.d.ts +3 -1
  100. package/dist/outlier-detector.service.js +2 -2
  101. package/dist/package-version-schema.vo.d.ts +11 -0
  102. package/dist/package-version-schema.vo.js +15 -0
  103. package/dist/package-version.vo.d.ts +11 -20
  104. package/dist/package-version.vo.js +11 -20
  105. package/dist/pagination-page.vo.d.ts +6 -0
  106. package/dist/pagination-page.vo.js +7 -0
  107. package/dist/pagination-skip.vo.d.ts +7 -0
  108. package/dist/pagination-skip.vo.js +9 -0
  109. package/dist/pagination-take.vo.d.ts +7 -0
  110. package/dist/pagination-take.vo.js +9 -0
  111. package/dist/pagination.service.d.ts +3 -8
  112. package/dist/pagination.service.js +5 -12
  113. package/dist/percentage.service.d.ts +3 -1
  114. package/dist/percentage.service.js +2 -2
  115. package/dist/population-standard-deviation.service.d.ts +3 -1
  116. package/dist/population-standard-deviation.service.js +5 -4
  117. package/dist/quarter-iso-id.vo.d.ts +3 -2
  118. package/dist/quarter-iso-id.vo.js +7 -9
  119. package/dist/quarter.vo.d.ts +2 -1
  120. package/dist/quarter.vo.js +10 -7
  121. package/dist/random.service.d.ts +3 -4
  122. package/dist/random.service.js +5 -11
  123. package/dist/rate-limiter.service.d.ts +2 -2
  124. package/dist/rate-limiter.service.js +8 -8
  125. package/dist/reordering-item-position-value.vo.d.ts +6 -0
  126. package/dist/reordering-item-position-value.vo.js +6 -0
  127. package/dist/reordering.service.d.ts +7 -23
  128. package/dist/reordering.service.js +15 -24
  129. package/dist/revision-value.vo.d.ts +7 -0
  130. package/dist/revision-value.vo.js +6 -0
  131. package/dist/revision.vo.d.ts +6 -13
  132. package/dist/revision.vo.js +10 -22
  133. package/dist/rounding.adapter.d.ts +7 -2
  134. package/dist/rounding.adapter.js +13 -5
  135. package/dist/size-bytes.vo.d.ts +6 -0
  136. package/dist/size-bytes.vo.js +7 -0
  137. package/dist/size.vo.d.ts +15 -15
  138. package/dist/size.vo.js +41 -51
  139. package/dist/stopwatch.service.d.ts +3 -1
  140. package/dist/stopwatch.service.js +2 -2
  141. package/dist/sum.service.js +8 -8
  142. package/dist/thousands-separator.service.js +4 -1
  143. package/dist/time.service.d.ts +8 -0
  144. package/dist/time.service.js +13 -0
  145. package/dist/timestamp.vo.d.ts +1 -1
  146. package/dist/timestamp.vo.js +4 -5
  147. package/dist/timezone.vo.d.ts +4 -1
  148. package/dist/timezone.vo.js +12 -6
  149. package/dist/tsconfig.tsbuildinfo +1 -1
  150. package/dist/week-iso-id.vo.d.ts +4 -2
  151. package/dist/week-iso-id.vo.js +15 -9
  152. package/dist/week.vo.d.ts +4 -3
  153. package/dist/week.vo.js +21 -22
  154. package/dist/weekday.vo.d.ts +1 -1
  155. package/dist/weekday.vo.js +6 -8
  156. package/dist/weight-grams.vo.d.ts +7 -0
  157. package/dist/weight-grams.vo.js +7 -0
  158. package/dist/weight.vo.d.ts +12 -35
  159. package/dist/weight.vo.js +23 -72
  160. package/dist/year-iso-id.vo.d.ts +3 -2
  161. package/dist/year-iso-id.vo.js +6 -4
  162. package/dist/year.vo.d.ts +5 -6
  163. package/dist/year.vo.js +21 -26
  164. package/dist/z-score.service.d.ts +3 -1
  165. package/dist/z-score.service.js +2 -2
  166. package/package.json +4 -4
  167. package/readme.md +21 -2
  168. package/src/age-years.vo.ts +14 -0
  169. package/src/age.vo.ts +22 -35
  170. package/src/api-key.vo.ts +11 -5
  171. package/src/basename.vo.ts +24 -22
  172. package/src/clock.vo.ts +16 -17
  173. package/src/date-calculator.service.ts +2 -1
  174. package/src/date-formatter.service.ts +4 -5
  175. package/src/date-range.vo.ts +6 -2
  176. package/src/day-iso-id.vo.ts +12 -8
  177. package/src/day.vo.ts +27 -24
  178. package/src/directory-path-absolute.vo.ts +23 -18
  179. package/src/directory-path-relative.vo.ts +21 -18
  180. package/src/division-factor.vo.ts +13 -0
  181. package/src/duration-ms.vo.ts +7 -0
  182. package/src/duration.service.ts +16 -40
  183. package/src/email-mask.service.ts +7 -15
  184. package/src/etags.vo.ts +4 -5
  185. package/src/extension.vo.ts +17 -10
  186. package/src/feature-flag-value.vo.ts +12 -0
  187. package/src/feature-flag.vo.ts +1 -9
  188. package/src/file-path-absolute-schema.vo.ts +18 -17
  189. package/src/file-path-relative-schema.vo.ts +15 -12
  190. package/src/file-path.vo.ts +8 -8
  191. package/src/filename-from-string.vo.ts +12 -9
  192. package/src/filename-suffix.vo.ts +14 -7
  193. package/src/filename.vo.ts +11 -2
  194. package/src/height-milimiters.vo.ts +12 -0
  195. package/src/height.vo.ts +12 -83
  196. package/src/hour-format.service.ts +2 -1
  197. package/src/hour-schema.vo.ts +12 -0
  198. package/src/hour.vo.ts +12 -12
  199. package/src/iban-mask.service.ts +3 -5
  200. package/src/iban-schema.vo.ts +15 -0
  201. package/src/iban.vo.ts +9 -22
  202. package/src/image.vo.ts +14 -12
  203. package/src/index.ts +24 -2
  204. package/src/language.vo.ts +7 -4
  205. package/src/linear-regression.service.ts +71 -0
  206. package/src/mean.service.ts +3 -5
  207. package/src/mime-types.vo.ts +1 -3
  208. package/src/mime-value.vo.ts +12 -0
  209. package/src/mime.vo.ts +12 -33
  210. package/src/min-max-scaler.service.ts +13 -11
  211. package/src/minute-schema.vo.ts +12 -0
  212. package/src/minute.vo.ts +12 -12
  213. package/src/money-amount.vo.ts +11 -0
  214. package/src/money.vo.ts +20 -38
  215. package/src/month-iso-id.vo.ts +14 -7
  216. package/src/month.vo.ts +25 -24
  217. package/src/multiplication-factor.vo.ts +13 -0
  218. package/src/object-key.vo.ts +25 -21
  219. package/src/outlier-detector.service.ts +2 -2
  220. package/src/package-version-schema.vo.ts +21 -0
  221. package/src/package-version.vo.ts +17 -33
  222. package/src/pagination-page.vo.ts +11 -0
  223. package/src/pagination-skip.vo.ts +13 -0
  224. package/src/pagination-take.vo.ts +13 -0
  225. package/src/pagination.service.ts +5 -22
  226. package/src/percentage.service.ts +2 -2
  227. package/src/population-standard-deviation.service.ts +5 -4
  228. package/src/quarter-iso-id.vo.ts +7 -10
  229. package/src/quarter.vo.ts +14 -9
  230. package/src/random.service.ts +6 -9
  231. package/src/rate-limiter.service.ts +9 -8
  232. package/src/reordering-item-position-value.vo.ts +10 -0
  233. package/src/reordering.service.ts +19 -28
  234. package/src/revision-value.vo.ts +10 -0
  235. package/src/revision.vo.ts +10 -25
  236. package/src/rounding.adapter.ts +16 -3
  237. package/src/size-bytes.vo.ts +11 -0
  238. package/src/size.vo.ts +43 -54
  239. package/src/stopwatch.service.ts +3 -3
  240. package/src/sum.service.ts +8 -8
  241. package/src/thousands-separator.service.ts +4 -1
  242. package/src/time.service.ts +15 -0
  243. package/src/timestamp.vo.ts +4 -5
  244. package/src/timezone.vo.ts +12 -6
  245. package/src/week-iso-id.vo.ts +16 -12
  246. package/src/week.vo.ts +26 -28
  247. package/src/weekday.vo.ts +6 -9
  248. package/src/weight-grams.vo.ts +11 -0
  249. package/src/weight.vo.ts +28 -85
  250. package/src/year-iso-id.vo.ts +7 -4
  251. package/src/year.vo.ts +27 -33
  252. package/src/z-score.service.ts +2 -2
  253. package/dist/simple-linear-regression.service.d.ts +0 -25
  254. package/dist/streak-calculator.service.d.ts +0 -13
  255. package/dist/streak-calculator.service.js +0 -22
  256. package/src/simple-linear-regression.service.ts +0 -69
  257. package/src/streak-calculator.service.ts +0 -32
package/src/weight.vo.ts CHANGED
@@ -1,87 +1,43 @@
1
- import { z } from "zod/v4";
2
- import { RoundToDecimal } from "./rounding.adapter";
1
+ import type { DivisionFactorType } from "./division-factor.vo";
2
+ import type { MultiplicationFactorType } from "./multiplication-factor.vo";
3
+ import { RoundToNearest } from "./rounding.adapter";
3
4
  import type { RoundingPort } from "./rounding.port";
4
-
5
- export enum WeightUnit {
6
- kg = "kg",
7
- lb = "lb",
8
- }
9
-
10
- export const WeightNonFiniteError = { error: "weight.non_finite" } as const;
11
- export const WeightNegativeError = { error: "weight.negative" } as const;
12
- export const WeightNonPositiveError = { error: "weight.non_positive" } as const;
13
- export const WeightGramsNonNegativeError = { error: "weight.grams_non_negative" } as const;
14
-
15
- const WeightQuantityNumber = z
16
- .number(WeightNonFiniteError)
17
- .refine(Number.isFinite, WeightNonFiniteError)
18
- .min(0, WeightNegativeError);
19
-
20
- const DivisionScalarNumber = z
21
- .number(WeightNonFiniteError)
22
- .refine(Number.isFinite, WeightNonFiniteError)
23
- .gt(0, WeightNonPositiveError);
24
-
25
- const CanonicalGramsInteger = z
26
- .number(WeightGramsNonNegativeError)
27
- .int(WeightGramsNonNegativeError)
28
- .min(0, WeightGramsNonNegativeError);
5
+ import { WeightGrams } from "./weight-grams.vo";
29
6
 
30
7
  export class Weight {
31
8
  private static readonly GRAMS_PER_KILOGRAM = 1_000;
32
- private static readonly POUNDS_PER_KILOGRAM = 2.2046226218487757;
33
- private static readonly KILOGRAMS_PER_POUND = 1 / Weight.POUNDS_PER_KILOGRAM;
34
9
 
35
- private constructor(private readonly grams: number) {}
10
+ private constructor(
11
+ private readonly grams: number,
12
+ private readonly rounding: RoundingPort = new RoundToNearest(),
13
+ ) {}
36
14
 
37
- static fromKilograms(kilograms: number): Weight {
38
- const kilogramsParsed = WeightQuantityNumber.parse(kilograms);
39
- const gramsRounded = Math.round(kilogramsParsed * Weight.GRAMS_PER_KILOGRAM);
40
- const grams = CanonicalGramsInteger.parse(gramsRounded);
15
+ static fromKilograms(kilograms: number, rounding: RoundingPort = new RoundToNearest()): Weight {
16
+ const grams = rounding.round(kilograms * Weight.GRAMS_PER_KILOGRAM);
41
17
 
42
- return new Weight(grams);
18
+ return new Weight(WeightGrams.parse(grams), rounding);
43
19
  }
44
20
 
45
- static fromPounds(pounds: number): Weight {
46
- const poundsParsed = WeightQuantityNumber.parse(pounds);
47
- const gramsRounded = Math.round(poundsParsed * Weight.KILOGRAMS_PER_POUND * Weight.GRAMS_PER_KILOGRAM);
48
- const grams = CanonicalGramsInteger.parse(gramsRounded);
49
-
50
- return new Weight(grams);
51
- }
52
-
53
- static fromGrams(grams: number): Weight {
54
- const gramsParsed = WeightQuantityNumber.parse(grams);
55
- const gramsRounded = Math.round(gramsParsed);
56
- const integerGrams = CanonicalGramsInteger.parse(gramsRounded);
57
-
58
- return new Weight(integerGrams);
21
+ static fromGrams(grams: number, rounding: RoundingPort = new RoundToNearest()): Weight {
22
+ return new Weight(WeightGrams.parse(grams), rounding);
59
23
  }
60
24
 
61
25
  static zero(): Weight {
62
26
  return new Weight(0);
63
27
  }
64
28
 
65
- toGrams(): number {
29
+ get(): number {
66
30
  return this.grams;
67
31
  }
68
32
 
69
- toKilograms(rounding?: RoundingPort): number {
33
+ toKilograms(): number {
70
34
  const kilograms = this.grams / Weight.GRAMS_PER_KILOGRAM;
71
35
 
72
- return rounding ? rounding.round(kilograms) : kilograms;
36
+ return this.rounding.round(kilograms);
73
37
  }
74
38
 
75
- toPounds(rounding?: RoundingPort): number {
76
- const pounds = (this.grams / Weight.GRAMS_PER_KILOGRAM) * Weight.POUNDS_PER_KILOGRAM;
77
-
78
- return rounding ? rounding.round(pounds) : pounds;
79
- }
80
-
81
- format(unit: WeightUnit, rounding: RoundingPort = new RoundToDecimal(2)): string {
82
- const value = unit === WeightUnit.kg ? this.toKilograms(rounding) : this.toPounds(rounding);
83
-
84
- return `${value.toString()} ${unit}`;
39
+ format(): string {
40
+ return `${this.grams} g`;
85
41
  }
86
42
 
87
43
  add(other: Weight): Weight {
@@ -94,31 +50,22 @@ export class Weight {
94
50
  return new Weight(result < 0 ? 0 : result);
95
51
  }
96
52
 
97
- multiply(factor: number): Weight {
98
- const factorParsed = WeightQuantityNumber.parse(factor);
99
- const gramsRounded = Math.round(this.grams * factorParsed);
100
- const grams = CanonicalGramsInteger.parse(gramsRounded);
53
+ multiply(factor: MultiplicationFactorType): Weight {
54
+ const grams = this.rounding.round(this.grams * factor);
101
55
 
102
- return new Weight(grams);
56
+ return new Weight(WeightGrams.parse(grams));
103
57
  }
104
58
 
105
- divideByScalar(divisor: number): Weight {
106
- const divisorParsed = DivisionScalarNumber.parse(divisor);
107
- const gramsRounded = Math.round(this.grams / divisorParsed);
108
- const grams = CanonicalGramsInteger.parse(gramsRounded);
59
+ divide(divisor: DivisionFactorType): Weight {
60
+ const grams = this.rounding.round(this.grams / divisor);
109
61
 
110
- return new Weight(grams);
62
+ return new Weight(WeightGrams.parse(grams));
111
63
  }
112
64
 
113
65
  equals(other: Weight): boolean {
114
66
  return this.grams === other.grams;
115
67
  }
116
68
 
117
- compare(other: Weight): -1 | 0 | 1 {
118
- if (this.grams === other.grams) return 0;
119
- return this.grams < other.grams ? -1 : 1;
120
- }
121
-
122
69
  greaterThan(other: Weight): boolean {
123
70
  return this.grams > other.grams;
124
71
  }
@@ -139,15 +86,11 @@ export class Weight {
139
86
  return this.grams === 0;
140
87
  }
141
88
 
142
- isPositive(): boolean {
143
- return this.grams > 0;
144
- }
145
-
146
- toJSON(): { g: number } {
147
- return { g: this.grams };
89
+ toString(): string {
90
+ return this.format();
148
91
  }
149
92
 
150
- static fromJSON(input: { g: number }): Weight {
151
- return Weight.fromGrams(input.g);
93
+ toJSON(): number {
94
+ return this.grams;
152
95
  }
153
96
  }
@@ -1,10 +1,13 @@
1
1
  import { z } from "zod/v4";
2
2
 
3
- export const YearIsoIdError = { error: "year-iso-id.invalid" } as const;
3
+ export const YearIsoIdError = { Type: "year.iso.id.type", BadChars: "year.iso.id.bad.chars" } as const;
4
+
5
+ // Four digits
6
+ const YEAR_ISO_ID_CHARS_WHITELIST = /^[0-9]{4}$/;
4
7
 
5
8
  export const YearIsoId = z
6
- .string(YearIsoIdError)
7
- .regex(/^\d{4}$/, YearIsoIdError)
8
- .refine((value) => Number.isInteger(Number(value)), YearIsoIdError);
9
+ .string(YearIsoIdError.Type)
10
+ .regex(YEAR_ISO_ID_CHARS_WHITELIST, YearIsoIdError.BadChars)
11
+ .brand("YearIsoId");
9
12
 
10
13
  export type YearIsoIdType = z.infer<typeof YearIsoId>;
package/src/year.vo.ts CHANGED
@@ -3,59 +3,53 @@ import { DateRange } from "./date-range.vo";
3
3
  import { Timestamp, type TimestampType } from "./timestamp.vo";
4
4
  import { YearIsoId, type YearIsoIdType } from "./year-iso-id.vo";
5
5
 
6
- export const YearInvalidIntegerError = "year.invalid_integer" as const;
7
- export const YearOutOfRangeError = "year.out_of_range" as const;
8
-
9
6
  export class Year extends DateRange {
10
- toIsoId(): YearIsoIdType {
11
- return String(getYear(this.getStart())) as YearIsoIdType;
12
- }
13
-
14
- isLeapYear(): boolean {
15
- const year = getYear(this.getStart());
7
+ static fromTimestamp(timestamp: TimestampType): Year {
8
+ const start = Timestamp.parse(startOfYear(timestamp).getTime());
9
+ const end = Timestamp.parse(endOfYear(timestamp).getTime());
16
10
 
17
- return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
11
+ return new Year(start, end);
18
12
  }
19
13
 
20
- previous(): Year {
21
- const shifted = addYears(new Date(this.getStart()), -1).getTime();
14
+ static fromNow(now: TimestampType): Year {
15
+ return Year.fromTimestamp(now);
16
+ }
22
17
 
23
- return Year.fromTimestamp(Timestamp.parse(shifted));
18
+ static fromNumber(candidate: number): Year {
19
+ return Year.fromIsoId(YearIsoId.parse(String(candidate)));
24
20
  }
25
21
 
26
- next(): Year {
27
- const shifted = addYears(new Date(this.getStart()), 1).getTime();
22
+ static fromIsoId(isoId: YearIsoIdType): Year {
23
+ const reference = Date.UTC(Number(isoId));
28
24
 
29
- return Year.fromTimestamp(Timestamp.parse(shifted));
25
+ return Year.fromTimestamp(Timestamp.parse(reference));
30
26
  }
31
27
 
32
- shift(count: number): Year {
33
- const shifted = addYears(new Date(this.getStart()), count).getTime();
34
-
35
- return Year.fromTimestamp(Timestamp.parse(shifted));
28
+ toIsoId(): YearIsoIdType {
29
+ return YearIsoId.parse(String(getYear(this.getStart())));
36
30
  }
37
31
 
38
- static fromTimestamp(timestamp: TimestampType): Year {
39
- const start = Timestamp.parse(startOfYear(timestamp).getTime());
40
- const end = Timestamp.parse(endOfYear(timestamp).getTime());
32
+ isLeapYear(): boolean {
33
+ const year = getYear(this.getStart());
41
34
 
42
- return new Year(start, end);
35
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
43
36
  }
44
37
 
45
- static fromNow(now: TimestampType): Year {
46
- return Year.fromTimestamp(now);
38
+ previous(): Year {
39
+ return this.shift(-1);
47
40
  }
48
41
 
49
- static fromNumber(value: number): Year {
50
- if (!Number.isInteger(value)) throw new Error(YearInvalidIntegerError);
51
- if (value < 0 || value > 9999) throw new Error(YearOutOfRangeError);
42
+ next(): Year {
43
+ return this.shift(1);
44
+ }
52
45
 
53
- const reference = Timestamp.parse(Date.UTC(value, 0, 1, 0, 0, 0, 0));
46
+ shift(count: number): Year {
47
+ const shifted = addYears(this.getStart(), count).getTime();
54
48
 
55
- return Year.fromTimestamp(reference);
49
+ return Year.fromTimestamp(Timestamp.parse(shifted));
56
50
  }
57
51
 
58
- static fromIsoId(isoId: YearIsoIdType): Year {
59
- return Year.fromNumber(Number(YearIsoId.parse(isoId)));
52
+ toString(): string {
53
+ return this.toIsoId();
60
54
  }
61
55
  }
@@ -3,7 +3,7 @@ import { PopulationStandardDeviation } from "./population-standard-deviation.ser
3
3
  import { RoundToDecimal } from "./rounding.adapter";
4
4
  import type { RoundingPort } from "./rounding.port";
5
5
 
6
- export const ZScoreMinValuesError = "zscore.min.values" as const;
6
+ export const ZScoreError = { NotEnoughValues: "z.score.not.enough.values" } as const;
7
7
 
8
8
  export class ZScore {
9
9
  private readonly mean: number;
@@ -13,7 +13,7 @@ export class ZScore {
13
13
  values: number[],
14
14
  private readonly rounding: RoundingPort = new RoundToDecimal(2),
15
15
  ) {
16
- if (values.length < 2) throw new Error(ZScoreMinValuesError);
16
+ if (values.length < 2) throw new Error(ZScoreError.NotEnoughValues);
17
17
 
18
18
  this.mean = Mean.calculate(values);
19
19
  this.standardDeviation = PopulationStandardDeviation.calculate(values);
@@ -1,25 +0,0 @@
1
- import type { RoundingPort } from "./rounding.port";
2
- export type SLRPairType = {
3
- x: number;
4
- y: number;
5
- };
6
- export type SLRParamsType = {
7
- a: number;
8
- b: number;
9
- };
10
- export type SLRPredictionType = number;
11
- export declare const SLRMinPairsError: "slr.min.pairs";
12
- export declare const SLRSumXTooBigError: "slr.sum.x.too.big";
13
- export declare const SLRSumYTooBigError: "slr.sum.y.too.big";
14
- export declare const SLRSumXSquaredTooBigError: "slr.sum.x.squared.too.big";
15
- export declare const SLRSumXTimesYTooBigError: "slr.sum.x.times.y.too.big";
16
- export declare const SLRModelCreationError: "slr.model.creation";
17
- export declare class SimpleLinearRegression {
18
- private static readonly DEFAULT_ROUNDING;
19
- private readonly params;
20
- private readonly rounding;
21
- constructor(params: SLRParamsType, rounding?: RoundingPort);
22
- static fromPairs(pairs: SLRPairType[], rounding?: RoundingPort): SimpleLinearRegression;
23
- predict(x: SLRPairType["x"], rounding?: RoundingPort): SLRPredictionType;
24
- inspect(): SimpleLinearRegression["params"];
25
- }
@@ -1,13 +0,0 @@
1
- type DateType = string;
2
- export type StreakType = {
3
- cutoff: DateType;
4
- dates: DateType[];
5
- streak: number;
6
- };
7
- export declare class StreakCalculator {
8
- private readonly cutoff;
9
- constructor(now?: Date);
10
- calculate(inputDates: DateType[]): StreakType;
11
- static format(date: Date | number): DateType;
12
- }
13
- export {};
@@ -1,22 +0,0 @@
1
- import { format, subDays } from "date-fns";
2
- export class StreakCalculator {
3
- cutoff;
4
- constructor(now = new Date()) {
5
- this.cutoff = StreakCalculator.format(now);
6
- }
7
- calculate(inputDates) {
8
- const dates = Array.from(new Set(inputDates));
9
- const datesSet = new Set(dates);
10
- let streak = 0;
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));
16
- }
17
- return { cutoff: this.cutoff, dates, streak };
18
- }
19
- static format(date) {
20
- return format(date, "yyyy-MM-dd");
21
- }
22
- }
@@ -1,69 +0,0 @@
1
- import { RoundToNearest } from "./rounding.adapter";
2
- import type { RoundingPort } from "./rounding.port";
3
-
4
- export type SLRPairType = { x: number; y: number };
5
- export type SLRParamsType = { a: number; b: number };
6
- export type SLRPredictionType = number;
7
-
8
- export const SLRMinPairsError = "slr.min.pairs" as const;
9
- export const SLRSumXTooBigError = "slr.sum.x.too.big" as const;
10
- export const SLRSumYTooBigError = "slr.sum.y.too.big" as const;
11
- export const SLRSumXSquaredTooBigError = "slr.sum.x.squared.too.big" as const;
12
- export const SLRSumXTimesYTooBigError = "slr.sum.x.times.y.too.big" as const;
13
- export const SLRModelCreationError = "slr.model.creation" as const;
14
-
15
- export class SimpleLinearRegression {
16
- private static readonly DEFAULT_ROUNDING: RoundingPort = new RoundToNearest();
17
-
18
- private readonly params: SLRParamsType;
19
- private readonly rounding: RoundingPort;
20
-
21
- constructor(params: SLRParamsType, rounding?: RoundingPort) {
22
- this.params = params;
23
- this.rounding = rounding ?? SimpleLinearRegression.DEFAULT_ROUNDING;
24
- }
25
-
26
- static fromPairs(pairs: SLRPairType[], rounding?: RoundingPort): SimpleLinearRegression {
27
- const count = pairs.length;
28
-
29
- if (count < 2) throw new Error(SLRMinPairsError);
30
-
31
- let sumX = 0;
32
- let sumY = 0;
33
- let sumXX = 0;
34
- let sumXY = 0;
35
-
36
- for (let index = 0; index < count; index++) {
37
- const pair = pairs[index];
38
- sumX += pair.x;
39
- sumY += pair.y;
40
- sumXX += pair.x * pair.x;
41
- sumXY += pair.x * pair.y;
42
- }
43
-
44
- if (Math.abs(sumX) >= Number.MAX_SAFE_INTEGER) throw new Error(SLRSumXTooBigError);
45
- if (Math.abs(sumY) >= Number.MAX_SAFE_INTEGER) throw new Error(SLRSumYTooBigError);
46
- if (Math.abs(sumXY) >= Number.MAX_SAFE_INTEGER) throw new Error(SLRSumXTimesYTooBigError);
47
- if (Math.abs(sumXX) >= Number.MAX_SAFE_INTEGER) throw new Error(SLRSumXSquaredTooBigError);
48
-
49
- const bDenominator = sumXX - sumX ** 2 / count;
50
-
51
- if (bDenominator === 0) throw new Error(SLRModelCreationError);
52
-
53
- const b = (sumXY - (sumX * sumY) / count) / bDenominator;
54
- const a = (sumY - b * sumX) / count;
55
-
56
- return new SimpleLinearRegression({ a, b }, rounding);
57
- }
58
-
59
- predict(x: SLRPairType["x"], rounding?: RoundingPort): SLRPredictionType {
60
- const chosen = rounding ?? this.rounding;
61
- const prediction = this.params.b * x + this.params.a;
62
-
63
- return chosen.round(prediction);
64
- }
65
-
66
- inspect(): SimpleLinearRegression["params"] {
67
- return this.params;
68
- }
69
- }
@@ -1,32 +0,0 @@
1
- import { format, subDays } from "date-fns";
2
-
3
- type DateType = string;
4
- export type StreakType = { cutoff: DateType; dates: DateType[]; streak: number };
5
-
6
- export class StreakCalculator {
7
- private readonly cutoff: DateType;
8
-
9
- constructor(now: Date = new Date()) {
10
- this.cutoff = StreakCalculator.format(now);
11
- }
12
-
13
- calculate(inputDates: DateType[]): StreakType {
14
- const dates = Array.from(new Set(inputDates));
15
- const datesSet = new Set(dates);
16
-
17
- let streak = 0;
18
- let cursor = this.cutoff;
19
-
20
- while (datesSet.has(cursor)) {
21
- streak++;
22
- const cursorDate = new Date(`${cursor}T00:00:00Z`);
23
- cursor = StreakCalculator.format(subDays(cursorDate, 1));
24
- }
25
-
26
- return { cutoff: this.cutoff, dates, streak };
27
- }
28
-
29
- static format(date: Date | number): DateType {
30
- return format(date, "yyyy-MM-dd");
31
- }
32
- }