@bgord/tools 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clock.vo.d.ts +25 -0
- package/dist/clock.vo.js +45 -0
- package/dist/dll.service.d.ts +29 -0
- package/dist/dll.service.js +148 -0
- package/dist/email-mask.service.d.ts +6 -0
- package/dist/email-mask.service.js +14 -0
- package/dist/feature-flag.vo.d.ts +11 -0
- package/dist/feature-flag.vo.js +15 -0
- package/dist/filter.vo.d.ts +17 -0
- package/dist/filter.vo.js +21 -0
- package/dist/hour.vo.d.ts +24 -0
- package/dist/hour.vo.js +52 -0
- package/dist/image.vo.d.ts +5 -0
- package/dist/image.vo.js +3 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +27 -0
- package/dist/leap-year-checker.service.d.ts +4 -0
- package/dist/leap-year-checker.service.js +9 -0
- package/dist/mean.service.d.ts +4 -0
- package/dist/mean.service.js +11 -0
- package/dist/mime-types.vo.d.ts +2 -0
- package/dist/mime-types.vo.js +7 -0
- package/dist/mime.vo.d.ts +1 -1
- package/dist/min-max-scaler.service.d.ts +36 -0
- package/dist/min-max-scaler.service.js +58 -0
- package/dist/minute.vo.d.ts +14 -0
- package/dist/minute.vo.js +34 -0
- package/dist/money.vo.d.ts +24 -0
- package/dist/money.vo.js +64 -0
- package/dist/outlier-detector.service.d.ts +6 -0
- package/dist/outlier-detector.service.js +13 -0
- package/dist/pagination.service.d.ts +58 -0
- package/dist/pagination.service.js +56 -0
- package/dist/percentage.service.d.ts +4 -0
- package/dist/percentage.service.js +11 -0
- package/dist/population-standard-deviation.service.d.ts +4 -0
- package/dist/population-standard-deviation.service.js +16 -0
- package/dist/random.service.d.ts +8 -0
- package/dist/random.service.js +19 -0
- package/dist/reordering.service.d.ts +61 -0
- package/dist/reordering.service.js +121 -0
- package/dist/revision.vo.d.ts +20 -0
- package/dist/revision.vo.js +45 -0
- package/dist/simple-linear-regression.service.d.ts +18 -0
- package/dist/simple-linear-regression.service.js +50 -0
- package/dist/stepper.service.d.ts +23 -0
- package/dist/stepper.service.js +34 -0
- package/dist/streak-calculator.service.d.ts +14 -0
- package/dist/streak-calculator.service.js +27 -0
- package/dist/sum.service.d.ts +3 -0
- package/dist/sum.service.js +5 -0
- package/dist/thousands-separator.service.d.ts +4 -0
- package/dist/thousands-separator.service.js +6 -0
- package/dist/visually-unambiguous-characters-generator.service.d.ts +4 -0
- package/dist/visually-unambiguous-characters-generator.service.js +35 -0
- package/dist/z-score.service.d.ts +8 -0
- package/dist/z-score.service.js +16 -0
- package/package.json +2 -2
- package/src/api-key.vo.ts +1 -0
- package/src/clock.vo.ts +67 -0
- package/src/dll.service.ts +185 -0
- package/src/email-mask.service.ts +22 -0
- package/src/feature-flag.vo.ts +19 -0
- package/src/filter.vo.ts +38 -0
- package/src/hour.vo.ts +71 -0
- package/src/image.vo.ts +9 -0
- package/src/index.ts +27 -0
- package/src/leap-year-checker.service.ts +11 -0
- package/src/mean.service.ts +14 -0
- package/src/mime-types.vo.ts +9 -0
- package/src/mime.vo.ts +3 -1
- package/src/min-max-scaler.service.ts +94 -0
- package/src/minute.vo.ts +46 -0
- package/src/money.vo.ts +99 -0
- package/src/outlier-detector.service.ts +20 -0
- package/src/package-version.vo.ts +2 -0
- package/src/pagination.service.ts +111 -0
- package/src/percentage.service.ts +17 -0
- package/src/population-standard-deviation.service.ts +21 -0
- package/src/random.service.ts +29 -0
- package/src/rate-limiter.service.ts +1 -3
- package/src/reordering.service.ts +169 -0
- package/src/revision.vo.ts +61 -0
- package/src/simple-linear-regression.service.ts +74 -0
- package/src/stepper.service.ts +50 -0
- package/src/streak-calculator.service.ts +42 -0
- package/src/sum.service.ts +5 -0
- package/src/thousands-separator.service.ts +7 -0
- package/src/visually-unambiguous-characters-generator.service.ts +42 -0
- package/src/z-score.service.ts +24 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { RoundToDecimal } from "./rounding.service";
|
|
2
|
+
export class MinMaxScaler {
|
|
3
|
+
constructor(config) {
|
|
4
|
+
const rounding = config.rounding ?? new RoundToDecimal(2);
|
|
5
|
+
const lower = config.bound?.lower ?? 0;
|
|
6
|
+
const upper = config.bound?.upper ?? 1;
|
|
7
|
+
if (config.max - config.min < 0) {
|
|
8
|
+
throw new Error("Invalid MinMaxScaler min-max config");
|
|
9
|
+
}
|
|
10
|
+
if (upper - lower <= 0) {
|
|
11
|
+
throw new Error("Invalid MinMaxScaler bound config");
|
|
12
|
+
}
|
|
13
|
+
this.rounding = rounding;
|
|
14
|
+
this.min = config.min;
|
|
15
|
+
this.max = config.max;
|
|
16
|
+
this.lower = lower;
|
|
17
|
+
this.upper = upper;
|
|
18
|
+
}
|
|
19
|
+
scale(value) {
|
|
20
|
+
const { min, max, lower, upper } = this;
|
|
21
|
+
if (value < min || value > max) {
|
|
22
|
+
throw new Error("Value out of min/max range");
|
|
23
|
+
}
|
|
24
|
+
if (min === max)
|
|
25
|
+
return {
|
|
26
|
+
original: value,
|
|
27
|
+
scaled: (lower + upper) / 2,
|
|
28
|
+
isMin: value === min,
|
|
29
|
+
isMax: value === max,
|
|
30
|
+
};
|
|
31
|
+
const result = ((value - min) / (max - min)) * (upper - lower) + lower;
|
|
32
|
+
return {
|
|
33
|
+
original: value,
|
|
34
|
+
scaled: this.rounding.round(result),
|
|
35
|
+
isMin: value === min,
|
|
36
|
+
isMax: value === max,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
descale(scaled) {
|
|
40
|
+
const { min, max, lower, upper } = this;
|
|
41
|
+
if (scaled < lower || scaled > upper) {
|
|
42
|
+
throw new Error("Scaled value out of bounds");
|
|
43
|
+
}
|
|
44
|
+
const result = ((scaled - lower) / (upper - lower)) * (max - min) + min;
|
|
45
|
+
return {
|
|
46
|
+
original: this.rounding.round(result),
|
|
47
|
+
scaled,
|
|
48
|
+
isLowerBound: scaled === lower,
|
|
49
|
+
isUpperBound: scaled === upper,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
static getMinMax(values) {
|
|
53
|
+
if (values.length === 0) {
|
|
54
|
+
throw new Error("An empty array supplied");
|
|
55
|
+
}
|
|
56
|
+
return { min: Math.min(...values), max: Math.max(...values) };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class Minute {
|
|
2
|
+
private readonly value;
|
|
3
|
+
static readonly ZERO: Minute;
|
|
4
|
+
static readonly MAX: Minute;
|
|
5
|
+
constructor(candidate: number);
|
|
6
|
+
get(): {
|
|
7
|
+
raw: number;
|
|
8
|
+
formatted: string;
|
|
9
|
+
};
|
|
10
|
+
equals(another: Minute): boolean;
|
|
11
|
+
isAfter(another: Minute): boolean;
|
|
12
|
+
isBefore(another: Minute): boolean;
|
|
13
|
+
static list(): Minute[];
|
|
14
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export class Minute {
|
|
2
|
+
constructor(candidate) {
|
|
3
|
+
if (!Number.isInteger(candidate)) {
|
|
4
|
+
throw new Error("Invalid minute");
|
|
5
|
+
}
|
|
6
|
+
if (candidate < 0) {
|
|
7
|
+
throw new Error("Invalid minute");
|
|
8
|
+
}
|
|
9
|
+
if (candidate >= 60) {
|
|
10
|
+
throw new Error("Invalid minute");
|
|
11
|
+
}
|
|
12
|
+
this.value = candidate;
|
|
13
|
+
}
|
|
14
|
+
get() {
|
|
15
|
+
return {
|
|
16
|
+
raw: this.value,
|
|
17
|
+
formatted: this.value.toString().padStart(2, "0"),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
equals(another) {
|
|
21
|
+
return this.value === another.get().raw;
|
|
22
|
+
}
|
|
23
|
+
isAfter(another) {
|
|
24
|
+
return this.value > another.get().raw;
|
|
25
|
+
}
|
|
26
|
+
isBefore(another) {
|
|
27
|
+
return this.value < another.get().raw;
|
|
28
|
+
}
|
|
29
|
+
static list() {
|
|
30
|
+
return Array.from({ length: 60 }).map((_, index) => new Minute(index));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
Minute.ZERO = new Minute(0);
|
|
34
|
+
Minute.MAX = new Minute(59);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { RoundingStrategy } from "./rounding.service";
|
|
3
|
+
export declare const MoneyAmount: z.ZodNumber;
|
|
4
|
+
export type MoneyAmountType = z.infer<typeof MoneyAmount>;
|
|
5
|
+
export declare const MoneyMultiplicationFactor: z.ZodNumber;
|
|
6
|
+
export type MoneyMultiplicationFactorType = z.infer<typeof MoneyMultiplicationFactor>;
|
|
7
|
+
export declare const MoneyDivisionFactor: z.ZodNumber;
|
|
8
|
+
export type MoneyDivisionFactorType = z.infer<typeof MoneyDivisionFactor>;
|
|
9
|
+
export declare class Money {
|
|
10
|
+
private static readonly ZERO;
|
|
11
|
+
private readonly amount;
|
|
12
|
+
private readonly rounding;
|
|
13
|
+
constructor(value?: number, rounding?: RoundingStrategy);
|
|
14
|
+
getAmount(): MoneyAmountType;
|
|
15
|
+
add(money: Money): Money;
|
|
16
|
+
multiply(factor: MoneyMultiplicationFactorType): Money;
|
|
17
|
+
subtract(money: Money): Money;
|
|
18
|
+
divide(factor: MoneyDivisionFactorType): Money;
|
|
19
|
+
equals(another: Money): boolean;
|
|
20
|
+
isGreaterThan(another: Money): boolean;
|
|
21
|
+
isLessThan(another: Money): boolean;
|
|
22
|
+
isZero(): boolean;
|
|
23
|
+
format(): string;
|
|
24
|
+
}
|
package/dist/money.vo.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { RoundToNearest } from "./rounding.service";
|
|
3
|
+
export const MoneyAmount = z
|
|
4
|
+
.number()
|
|
5
|
+
.int({ message: "money.amount.invalid " })
|
|
6
|
+
.min(0, { message: "money.amount.invalid " });
|
|
7
|
+
export const MoneyMultiplicationFactor = z
|
|
8
|
+
.number()
|
|
9
|
+
.min(0, { message: "money.multiplication-factor.invalid" });
|
|
10
|
+
export const MoneyDivisionFactor = z
|
|
11
|
+
.number()
|
|
12
|
+
.min(0, { message: "money.division-factor.invalid" })
|
|
13
|
+
.refine((value) => value !== 0, { message: "money.division-factor.invalid" });
|
|
14
|
+
export class Money {
|
|
15
|
+
constructor(value = Money.ZERO, rounding) {
|
|
16
|
+
this.amount = MoneyAmount.parse(value);
|
|
17
|
+
this.rounding = rounding ?? new RoundToNearest();
|
|
18
|
+
}
|
|
19
|
+
getAmount() {
|
|
20
|
+
return this.amount;
|
|
21
|
+
}
|
|
22
|
+
add(money) {
|
|
23
|
+
const result = this.rounding.round(this.amount + money.getAmount());
|
|
24
|
+
return new Money(MoneyAmount.parse(result), this.rounding);
|
|
25
|
+
}
|
|
26
|
+
multiply(factor) {
|
|
27
|
+
const result = this.rounding.round(this.amount * factor);
|
|
28
|
+
return new Money(MoneyAmount.parse(result), this.rounding);
|
|
29
|
+
}
|
|
30
|
+
subtract(money) {
|
|
31
|
+
const result = this.rounding.round(this.amount - money.getAmount());
|
|
32
|
+
if (result < Money.ZERO) {
|
|
33
|
+
throw new Error("Less than zero");
|
|
34
|
+
}
|
|
35
|
+
return new Money(MoneyAmount.parse(result), this.rounding);
|
|
36
|
+
}
|
|
37
|
+
divide(factor) {
|
|
38
|
+
if (factor === 0) {
|
|
39
|
+
throw new Error("Cannot divide by zero");
|
|
40
|
+
}
|
|
41
|
+
const result = this.rounding.round(this.amount / factor);
|
|
42
|
+
return new Money(MoneyAmount.parse(result), this.rounding);
|
|
43
|
+
}
|
|
44
|
+
equals(another) {
|
|
45
|
+
return this.amount === another.getAmount();
|
|
46
|
+
}
|
|
47
|
+
isGreaterThan(another) {
|
|
48
|
+
return this.amount > another.getAmount();
|
|
49
|
+
}
|
|
50
|
+
isLessThan(another) {
|
|
51
|
+
return this.amount < another.getAmount();
|
|
52
|
+
}
|
|
53
|
+
isZero() {
|
|
54
|
+
return this.amount === Money.ZERO;
|
|
55
|
+
}
|
|
56
|
+
format() {
|
|
57
|
+
const result = this.amount / 100;
|
|
58
|
+
const whole = Math.floor(result);
|
|
59
|
+
const fraction = this.amount % 100;
|
|
60
|
+
const fractionFormatted = fraction.toString().padStart(2, "0");
|
|
61
|
+
return `${whole}.${fractionFormatted}`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
Money.ZERO = 0;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ZScore } from "./z-score.service";
|
|
2
|
+
export class OutlierDetector {
|
|
3
|
+
constructor(values, threshold) {
|
|
4
|
+
if (values.length < 2) {
|
|
5
|
+
throw new Error("At least two values are needed");
|
|
6
|
+
}
|
|
7
|
+
this.zScore = new ZScore(values);
|
|
8
|
+
this.threshold = Math.abs(threshold);
|
|
9
|
+
}
|
|
10
|
+
check(value) {
|
|
11
|
+
return this.zScore.calculate(value) <= this.threshold;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
declare const Take: z.ZodNumber;
|
|
3
|
+
type TakeType = z.infer<typeof Take>;
|
|
4
|
+
declare const Skip: z.ZodNumber;
|
|
5
|
+
type SkipType = z.infer<typeof Skip>;
|
|
6
|
+
declare const Page: z.ZodDefault<z.ZodPipe<z.ZodCoercedNumber<unknown>, z.ZodTransform<number, number>>>;
|
|
7
|
+
export type PageType = z.infer<typeof Page>;
|
|
8
|
+
export type PaginationType = {
|
|
9
|
+
values: {
|
|
10
|
+
take: TakeType;
|
|
11
|
+
skip: SkipType;
|
|
12
|
+
};
|
|
13
|
+
page: PageType;
|
|
14
|
+
};
|
|
15
|
+
export type PaginationValuesType = Record<string, unknown>;
|
|
16
|
+
export type TotalType = number;
|
|
17
|
+
export type ExhaustedType = boolean;
|
|
18
|
+
export type PaginationExhaustedConfig = {
|
|
19
|
+
total: TotalType;
|
|
20
|
+
pagination: PaginationType;
|
|
21
|
+
};
|
|
22
|
+
export type PaginationPrepareConfigType<T> = {
|
|
23
|
+
total: TotalType;
|
|
24
|
+
pagination: PaginationType;
|
|
25
|
+
result: T[];
|
|
26
|
+
};
|
|
27
|
+
export declare class Pagination {
|
|
28
|
+
static parse(values: PaginationValuesType, _take: TakeType): PaginationType;
|
|
29
|
+
static prepare<T>(config: PaginationPrepareConfigType<T>): Paged<T>;
|
|
30
|
+
static isExhausted(config: PaginationExhaustedConfig): ExhaustedType;
|
|
31
|
+
private static getLastPage;
|
|
32
|
+
static empty: {
|
|
33
|
+
result: never[];
|
|
34
|
+
meta: {
|
|
35
|
+
exhausted: boolean;
|
|
36
|
+
currentPage: number;
|
|
37
|
+
previousPage: undefined;
|
|
38
|
+
nextPage: undefined;
|
|
39
|
+
lastPage: number;
|
|
40
|
+
total: number;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
static getFirstPage({ take }: {
|
|
44
|
+
take: TakeType;
|
|
45
|
+
}): PaginationType;
|
|
46
|
+
}
|
|
47
|
+
export type Paged<T> = {
|
|
48
|
+
result: T[];
|
|
49
|
+
meta: {
|
|
50
|
+
exhausted: ExhaustedType;
|
|
51
|
+
currentPage: PageType;
|
|
52
|
+
previousPage: PageType | undefined;
|
|
53
|
+
nextPage: PageType | undefined;
|
|
54
|
+
lastPage: PageType;
|
|
55
|
+
total: TotalType;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
const Take = z.number().int().positive();
|
|
3
|
+
const Skip = z.number().int().positive();
|
|
4
|
+
const Page = z.coerce
|
|
5
|
+
.number()
|
|
6
|
+
.int()
|
|
7
|
+
.transform((value) => (value <= 0 ? 1 : value))
|
|
8
|
+
.default(1);
|
|
9
|
+
export class Pagination {
|
|
10
|
+
static parse(values, _take) {
|
|
11
|
+
const page = Page.parse(values.page);
|
|
12
|
+
const take = Take.parse(_take);
|
|
13
|
+
const skip = (page - 1) * take;
|
|
14
|
+
return { values: { take, skip }, page };
|
|
15
|
+
}
|
|
16
|
+
static prepare(config) {
|
|
17
|
+
const exhausted = Pagination.isExhausted(config);
|
|
18
|
+
const currentPage = config.pagination.page;
|
|
19
|
+
const lastPage = Pagination.getLastPage(config);
|
|
20
|
+
const previousPage = currentPage > 1 ? currentPage - 1 : undefined;
|
|
21
|
+
const nextPage = currentPage < lastPage ? currentPage + 1 : undefined;
|
|
22
|
+
return {
|
|
23
|
+
result: config.result,
|
|
24
|
+
meta: {
|
|
25
|
+
exhausted,
|
|
26
|
+
currentPage,
|
|
27
|
+
previousPage,
|
|
28
|
+
nextPage,
|
|
29
|
+
lastPage,
|
|
30
|
+
total: config.total,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
static isExhausted(config) {
|
|
35
|
+
const lastPage = Pagination.getLastPage(config);
|
|
36
|
+
const currentPage = config.pagination.page;
|
|
37
|
+
return lastPage <= currentPage;
|
|
38
|
+
}
|
|
39
|
+
static getLastPage(config) {
|
|
40
|
+
return Math.ceil(config.total / config.pagination.values.take);
|
|
41
|
+
}
|
|
42
|
+
static getFirstPage({ take }) {
|
|
43
|
+
return { values: { take, skip: 0 }, page: 1 };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
Pagination.empty = {
|
|
47
|
+
result: [],
|
|
48
|
+
meta: {
|
|
49
|
+
exhausted: true,
|
|
50
|
+
currentPage: 1,
|
|
51
|
+
previousPage: undefined,
|
|
52
|
+
nextPage: undefined,
|
|
53
|
+
lastPage: 1,
|
|
54
|
+
total: 0,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RoundToNearest } from "./rounding.service";
|
|
2
|
+
export class Percentage {
|
|
3
|
+
static of(numerator, denominator, rounding = new RoundToNearest()) {
|
|
4
|
+
if (denominator === 0) {
|
|
5
|
+
throw new Error("Invalid denominator");
|
|
6
|
+
}
|
|
7
|
+
if (numerator === 0)
|
|
8
|
+
return 0;
|
|
9
|
+
return rounding.round((numerator / denominator) * 100);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Mean } from "./mean.service";
|
|
2
|
+
import { RoundToDecimal } from "./rounding.service";
|
|
3
|
+
import { Sum } from "./sum.service";
|
|
4
|
+
export class PopulationStandardDeviation {
|
|
5
|
+
static calculate(values, rounding = new RoundToDecimal(2)) {
|
|
6
|
+
if (values.length < 2) {
|
|
7
|
+
throw new Error("At least two values are needed");
|
|
8
|
+
}
|
|
9
|
+
const mean = Mean.calculate(values);
|
|
10
|
+
const n = values.length;
|
|
11
|
+
const squaredDifferences = values.map((value) => (value - mean) ** 2);
|
|
12
|
+
const sumOfSquaredDifferences = Sum.of(squaredDifferences);
|
|
13
|
+
const variance = sumOfSquaredDifferences / n;
|
|
14
|
+
return rounding.round(Math.sqrt(variance));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export class Random {
|
|
2
|
+
static generate(config) {
|
|
3
|
+
const min = config?.min ?? 0;
|
|
4
|
+
const max = config?.max ?? 1;
|
|
5
|
+
if (!Number.isInteger(min)) {
|
|
6
|
+
throw new Error("Minimum value is not an integer");
|
|
7
|
+
}
|
|
8
|
+
if (!Number.isInteger(max)) {
|
|
9
|
+
throw new Error("Maximum value is not an integer");
|
|
10
|
+
}
|
|
11
|
+
if (min === max) {
|
|
12
|
+
throw new Error("Minimum and maximum values cannot be equal");
|
|
13
|
+
}
|
|
14
|
+
if (min > max) {
|
|
15
|
+
throw new Error("Minimum value cannot be greater than maximum value");
|
|
16
|
+
}
|
|
17
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
export declare const ReorderingItemPositionValue: z.ZodNumber;
|
|
3
|
+
export type ReorderingItemPositionValueType = z.infer<typeof ReorderingItemPositionValue>;
|
|
4
|
+
export declare const ReorderingCorrelationId: z.ZodString;
|
|
5
|
+
export type ReorderingCorrelationIdType = z.infer<typeof ReorderingCorrelationId>;
|
|
6
|
+
export declare const ReorderingItemId: z.ZodUUID;
|
|
7
|
+
export type ReorderingItemIdType = z.infer<typeof ReorderingItemId>;
|
|
8
|
+
export declare const Reordering: z.ZodObject<{
|
|
9
|
+
correlationId: z.ZodString;
|
|
10
|
+
id: z.ZodUUID;
|
|
11
|
+
position: z.ZodNumber;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
export type ReorderingType = z.infer<typeof Reordering>;
|
|
14
|
+
export type WithReorderingPositionValue<T> = T & {
|
|
15
|
+
position: ReorderingItemPositionValueType;
|
|
16
|
+
};
|
|
17
|
+
export declare class ReorderingPosition {
|
|
18
|
+
readonly value: ReorderingItemPositionValueType;
|
|
19
|
+
constructor(value: ReorderingItemPositionValueType);
|
|
20
|
+
eq(another: ReorderingPosition): boolean;
|
|
21
|
+
}
|
|
22
|
+
declare class ReorderingItem {
|
|
23
|
+
readonly id: ReorderingItemIdType;
|
|
24
|
+
readonly position: ReorderingPosition;
|
|
25
|
+
constructor(id: ReorderingItemIdType, position: ReorderingPosition);
|
|
26
|
+
eq(anotherItemId: ReorderingItem["id"]): boolean;
|
|
27
|
+
}
|
|
28
|
+
declare enum ReorderingTransferDirection {
|
|
29
|
+
upwards = "upwards",
|
|
30
|
+
downwards = "downwards",
|
|
31
|
+
noop = "noop"
|
|
32
|
+
}
|
|
33
|
+
export declare class ReorderingTransfer {
|
|
34
|
+
readonly id: ReorderingItem["id"];
|
|
35
|
+
readonly to: ReorderingPosition;
|
|
36
|
+
constructor(config: {
|
|
37
|
+
id: ReorderingItem["id"];
|
|
38
|
+
to: ReorderingItemPositionValueType;
|
|
39
|
+
});
|
|
40
|
+
getDirection(currentPosition: ReorderingPosition): ReorderingTransferDirection;
|
|
41
|
+
}
|
|
42
|
+
export declare class ReorderingCalculator {
|
|
43
|
+
private dll;
|
|
44
|
+
constructor();
|
|
45
|
+
static fromArray(ids: ReorderingItem["id"][]): ReorderingCalculator;
|
|
46
|
+
add(id: ReorderingItem["id"]): ReorderingItem;
|
|
47
|
+
delete(id: ReorderingItem["id"]): void;
|
|
48
|
+
transfer(transfer: ReorderingTransfer): ReturnType<ReorderingCalculator["read"]>;
|
|
49
|
+
read(): {
|
|
50
|
+
ids: string[];
|
|
51
|
+
items: ReorderingItem[];
|
|
52
|
+
};
|
|
53
|
+
private recalculate;
|
|
54
|
+
}
|
|
55
|
+
export declare class ReorderingIntegrator {
|
|
56
|
+
static appendPosition(reordering: ReorderingType[]): <T extends {
|
|
57
|
+
id: ReorderingItemIdType;
|
|
58
|
+
}>(item: T) => WithReorderingPositionValue<T>;
|
|
59
|
+
static sortByPosition(): (a: WithReorderingPositionValue<unknown>, b: WithReorderingPositionValue<unknown>) => number;
|
|
60
|
+
}
|
|
61
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { DoublyLinkedList, Node } from "./dll.service";
|
|
3
|
+
export const ReorderingItemPositionValue = z.number().int().min(0);
|
|
4
|
+
export const ReorderingCorrelationId = z.string().min(1);
|
|
5
|
+
export const ReorderingItemId = z.uuid();
|
|
6
|
+
export const Reordering = z.object({
|
|
7
|
+
correlationId: ReorderingCorrelationId,
|
|
8
|
+
id: ReorderingItemId,
|
|
9
|
+
position: ReorderingItemPositionValue,
|
|
10
|
+
});
|
|
11
|
+
export class ReorderingPosition {
|
|
12
|
+
constructor(value) {
|
|
13
|
+
if (!ReorderingItemPositionValue.safeParse(value).success) {
|
|
14
|
+
throw new Error("Position is not a positive integer");
|
|
15
|
+
}
|
|
16
|
+
this.value = value;
|
|
17
|
+
}
|
|
18
|
+
eq(another) {
|
|
19
|
+
return this.value === another.value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
class ReorderingItem {
|
|
23
|
+
constructor(id, position) {
|
|
24
|
+
this.id = id;
|
|
25
|
+
this.position = position;
|
|
26
|
+
}
|
|
27
|
+
eq(anotherItemId) {
|
|
28
|
+
return this.id === anotherItemId;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
var ReorderingTransferDirection;
|
|
32
|
+
(function (ReorderingTransferDirection) {
|
|
33
|
+
ReorderingTransferDirection["upwards"] = "upwards";
|
|
34
|
+
ReorderingTransferDirection["downwards"] = "downwards";
|
|
35
|
+
ReorderingTransferDirection["noop"] = "noop";
|
|
36
|
+
})(ReorderingTransferDirection || (ReorderingTransferDirection = {}));
|
|
37
|
+
export class ReorderingTransfer {
|
|
38
|
+
constructor(config) {
|
|
39
|
+
this.id = config.id;
|
|
40
|
+
this.to = new ReorderingPosition(config.to);
|
|
41
|
+
}
|
|
42
|
+
getDirection(currentPosition) {
|
|
43
|
+
if (this.to.value === currentPosition.value)
|
|
44
|
+
return ReorderingTransferDirection.noop;
|
|
45
|
+
if (this.to.value > currentPosition.value) {
|
|
46
|
+
return ReorderingTransferDirection.downwards;
|
|
47
|
+
}
|
|
48
|
+
return ReorderingTransferDirection.upwards;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export class ReorderingCalculator {
|
|
52
|
+
constructor() {
|
|
53
|
+
this.dll = DoublyLinkedList.fromArray([]);
|
|
54
|
+
}
|
|
55
|
+
static fromArray(ids) {
|
|
56
|
+
const reordering = new ReorderingCalculator();
|
|
57
|
+
for (const id of ids) {
|
|
58
|
+
reordering.add(id);
|
|
59
|
+
}
|
|
60
|
+
return reordering;
|
|
61
|
+
}
|
|
62
|
+
add(id) {
|
|
63
|
+
const position = new ReorderingPosition(this.dll.getSize());
|
|
64
|
+
const item = new ReorderingItem(id, position);
|
|
65
|
+
this.dll.append(new Node(item));
|
|
66
|
+
return item;
|
|
67
|
+
}
|
|
68
|
+
delete(id) {
|
|
69
|
+
const item = this.dll.find((x) => x.data.eq(id));
|
|
70
|
+
if (!item) {
|
|
71
|
+
throw new Error("Cannot find Item");
|
|
72
|
+
}
|
|
73
|
+
this.dll.remove(item);
|
|
74
|
+
this.recalculate();
|
|
75
|
+
}
|
|
76
|
+
transfer(transfer) {
|
|
77
|
+
const current = this.dll.find((node) => node.data.eq(transfer.id));
|
|
78
|
+
const target = this.dll.find((node) => node.data.position.eq(transfer.to));
|
|
79
|
+
if (!current) {
|
|
80
|
+
throw new Error("Cannot find current Item");
|
|
81
|
+
}
|
|
82
|
+
if (!target) {
|
|
83
|
+
throw new Error("Cannot find target Item");
|
|
84
|
+
}
|
|
85
|
+
const direction = transfer.getDirection(current.data.position);
|
|
86
|
+
if (direction === ReorderingTransferDirection.noop)
|
|
87
|
+
return this.read();
|
|
88
|
+
if (direction === ReorderingTransferDirection.upwards) {
|
|
89
|
+
this.dll.remove(current);
|
|
90
|
+
this.dll.insertBefore(current, target);
|
|
91
|
+
this.recalculate();
|
|
92
|
+
}
|
|
93
|
+
if (direction === ReorderingTransferDirection.downwards) {
|
|
94
|
+
this.dll.remove(current);
|
|
95
|
+
this.dll.insertAfter(current, target);
|
|
96
|
+
this.recalculate();
|
|
97
|
+
}
|
|
98
|
+
return this.read();
|
|
99
|
+
}
|
|
100
|
+
read() {
|
|
101
|
+
const ids = Array.from(this.dll).map((item) => item.data.id);
|
|
102
|
+
const items = Array.from(this.dll).map((item) => item.data);
|
|
103
|
+
return { ids, items };
|
|
104
|
+
}
|
|
105
|
+
recalculate() {
|
|
106
|
+
this.dll = ReorderingCalculator.fromArray(this.read().ids).dll;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export class ReorderingIntegrator {
|
|
110
|
+
static appendPosition(reordering) {
|
|
111
|
+
return function (item) {
|
|
112
|
+
return {
|
|
113
|
+
...item,
|
|
114
|
+
position: reordering.find((x) => x.id === item.id)?.position ?? 0,
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
static sortByPosition() {
|
|
119
|
+
return (a, b) => a.position - b.position;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import { ETag, WeakETag } from "./etags.vo";
|
|
3
|
+
export declare const RevisionValue: z.ZodNumber;
|
|
4
|
+
export type RevisionValueType = z.infer<typeof RevisionValue>;
|
|
5
|
+
export declare class Revision {
|
|
6
|
+
readonly value: RevisionValueType;
|
|
7
|
+
static initial: RevisionValueType;
|
|
8
|
+
constructor(value: unknown);
|
|
9
|
+
matches(another: RevisionValueType): boolean;
|
|
10
|
+
validate(another: RevisionValueType): void;
|
|
11
|
+
next(): Revision;
|
|
12
|
+
static fromETag(etag: ETag | null): Revision;
|
|
13
|
+
static fromWeakETag(weakEtag: WeakETag | null): Revision;
|
|
14
|
+
}
|
|
15
|
+
export declare class RevisionMismatchError extends Error {
|
|
16
|
+
constructor();
|
|
17
|
+
}
|
|
18
|
+
export declare class InvalidRevisionError extends Error {
|
|
19
|
+
constructor();
|
|
20
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
export const RevisionValue = z.number().int().min(0);
|
|
3
|
+
export class Revision {
|
|
4
|
+
constructor(value) {
|
|
5
|
+
const result = RevisionValue.safeParse(value);
|
|
6
|
+
if (!result.success)
|
|
7
|
+
throw new InvalidRevisionError();
|
|
8
|
+
this.value = result.data;
|
|
9
|
+
}
|
|
10
|
+
matches(another) {
|
|
11
|
+
return this.value === another;
|
|
12
|
+
}
|
|
13
|
+
validate(another) {
|
|
14
|
+
if (!this.matches(another))
|
|
15
|
+
throw new RevisionMismatchError();
|
|
16
|
+
}
|
|
17
|
+
next() {
|
|
18
|
+
return new Revision(this.value + 1);
|
|
19
|
+
}
|
|
20
|
+
static fromETag(etag) {
|
|
21
|
+
if (!etag) {
|
|
22
|
+
throw new InvalidRevisionError();
|
|
23
|
+
}
|
|
24
|
+
return new Revision(etag.revision);
|
|
25
|
+
}
|
|
26
|
+
static fromWeakETag(weakEtag) {
|
|
27
|
+
if (!weakEtag) {
|
|
28
|
+
throw new InvalidRevisionError();
|
|
29
|
+
}
|
|
30
|
+
return new Revision(weakEtag.revision);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
Revision.initial = 0;
|
|
34
|
+
export class RevisionMismatchError extends Error {
|
|
35
|
+
constructor() {
|
|
36
|
+
super();
|
|
37
|
+
Object.setPrototypeOf(this, RevisionMismatchError.prototype);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export class InvalidRevisionError extends Error {
|
|
41
|
+
constructor() {
|
|
42
|
+
super();
|
|
43
|
+
Object.setPrototypeOf(this, InvalidRevisionError.prototype);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { RoundingStrategy } from "./rounding.service";
|
|
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 class SimpleLinearRegression {
|
|
12
|
+
private readonly params;
|
|
13
|
+
private readonly rounding;
|
|
14
|
+
constructor(params: SLRParamsType, rounding?: RoundingStrategy);
|
|
15
|
+
static fromPairs(pairs: SLRPairType[], rounding?: RoundingStrategy): SimpleLinearRegression;
|
|
16
|
+
predict(x: SLRPairType["x"], strategy?: RoundingStrategy): SLRPredictionType;
|
|
17
|
+
inspect(): SimpleLinearRegression["params"];
|
|
18
|
+
}
|