@actuarial-ts/core 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/README.md +12 -3
- package/dist/canonical.d.ts +11 -0
- package/dist/canonical.d.ts.map +1 -1
- package/dist/canonical.js +136 -26
- package/dist/canonical.js.map +1 -1
- package/dist/capping.d.ts.map +1 -1
- package/dist/capping.js +39 -6
- package/dist/capping.js.map +1 -1
- package/dist/diagnosticAggregation.d.ts +3 -0
- package/dist/diagnosticAggregation.d.ts.map +1 -1
- package/dist/diagnosticAggregation.js +30 -7
- package/dist/diagnosticAggregation.js.map +1 -1
- package/dist/diagnosticDefinitions.d.ts +3 -0
- package/dist/diagnosticDefinitions.d.ts.map +1 -1
- package/dist/diagnosticDefinitions.js +844 -182
- package/dist/diagnosticDefinitions.js.map +1 -1
- package/dist/diagnosticDerivations.d.ts +23 -0
- package/dist/diagnosticDerivations.d.ts.map +1 -1
- package/dist/diagnosticDerivations.js +187 -43
- package/dist/diagnosticDerivations.js.map +1 -1
- package/dist/diagnosticEvidenceIntern.d.ts +16 -0
- package/dist/diagnosticEvidenceIntern.d.ts.map +1 -0
- package/dist/diagnosticEvidenceIntern.js +139 -0
- package/dist/diagnosticEvidenceIntern.js.map +1 -0
- package/dist/diagnosticExposure.d.ts +2 -2
- package/dist/diagnosticExposure.d.ts.map +1 -1
- package/dist/diagnosticExposure.js +319 -21
- package/dist/diagnosticExposure.js.map +1 -1
- package/dist/diagnosticExpressions.d.ts +1 -1
- package/dist/diagnosticExpressions.d.ts.map +1 -1
- package/dist/diagnosticExpressions.js +35 -15
- package/dist/diagnosticExpressions.js.map +1 -1
- package/dist/diagnosticFormulas.d.ts +3 -0
- package/dist/diagnosticFormulas.d.ts.map +1 -1
- package/dist/diagnosticFormulas.js +160 -26
- package/dist/diagnosticFormulas.js.map +1 -1
- package/dist/diagnosticIdentity.d.ts +15 -1
- package/dist/diagnosticIdentity.d.ts.map +1 -1
- package/dist/diagnosticIdentity.js +321 -51
- package/dist/diagnosticIdentity.js.map +1 -1
- package/dist/diagnosticIdentityStream.d.ts +56 -0
- package/dist/diagnosticIdentityStream.d.ts.map +1 -0
- package/dist/diagnosticIdentityStream.js +472 -0
- package/dist/diagnosticIdentityStream.js.map +1 -0
- package/dist/diagnosticOrdering.d.ts +8 -0
- package/dist/diagnosticOrdering.d.ts.map +1 -0
- package/dist/diagnosticOrdering.js +73 -0
- package/dist/diagnosticOrdering.js.map +1 -0
- package/dist/diagnosticPeriodAxis.d.ts +9 -0
- package/dist/diagnosticPeriodAxis.d.ts.map +1 -0
- package/dist/diagnosticPeriodAxis.js +69 -0
- package/dist/diagnosticPeriodAxis.js.map +1 -0
- package/dist/diagnosticPeriods.d.ts +2 -3
- package/dist/diagnosticPeriods.d.ts.map +1 -1
- package/dist/diagnosticPeriods.js +20 -68
- package/dist/diagnosticPeriods.js.map +1 -1
- package/dist/diagnosticPreparation.d.ts +75 -14
- package/dist/diagnosticPreparation.d.ts.map +1 -1
- package/dist/diagnosticPreparation.js +1606 -112
- package/dist/diagnosticPreparation.js.map +1 -1
- package/dist/diagnosticReview.d.ts +40 -15
- package/dist/diagnosticReview.d.ts.map +1 -1
- package/dist/diagnosticReview.js +600 -42
- package/dist/diagnosticReview.js.map +1 -1
- package/dist/diagnosticReviewSources.d.ts +18 -0
- package/dist/diagnosticReviewSources.d.ts.map +1 -0
- package/dist/diagnosticReviewSources.js +76 -0
- package/dist/diagnosticReviewSources.js.map +1 -0
- package/dist/diagnosticReviewStore.d.ts +88 -0
- package/dist/diagnosticReviewStore.d.ts.map +1 -0
- package/dist/diagnosticReviewStore.js +455 -0
- package/dist/diagnosticReviewStore.js.map +1 -0
- package/dist/diagnosticRunner.d.ts +27 -2
- package/dist/diagnosticRunner.d.ts.map +1 -1
- package/dist/diagnosticRunner.js +764 -70
- package/dist/diagnosticRunner.js.map +1 -1
- package/dist/diagnosticRuntime.d.ts +26 -0
- package/dist/diagnosticRuntime.d.ts.map +1 -0
- package/dist/diagnosticRuntime.js +243 -0
- package/dist/diagnosticRuntime.js.map +1 -0
- package/dist/diagnosticSourceOrdering.d.ts +6 -0
- package/dist/diagnosticSourceOrdering.d.ts.map +1 -0
- package/dist/diagnosticSourceOrdering.js +38 -0
- package/dist/diagnosticSourceOrdering.js.map +1 -0
- package/dist/fnvAccumulator.d.ts +6 -0
- package/dist/fnvAccumulator.d.ts.map +1 -0
- package/dist/fnvAccumulator.js +21 -0
- package/dist/fnvAccumulator.js.map +1 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/mack.d.ts +4 -0
- package/dist/mack.d.ts.map +1 -1
- package/dist/mack.js +32 -4
- package/dist/mack.js.map +1 -1
- package/dist/triangle.d.ts.map +1 -1
- package/dist/triangle.js +59 -9
- package/dist/triangle.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +22 -8
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
- package/src/canonical.ts +144 -26
- package/src/capping.ts +109 -18
- package/src/diagnosticAggregation.ts +69 -20
- package/src/diagnosticDefinitions.ts +2675 -426
- package/src/diagnosticDerivations.ts +281 -49
- package/src/diagnosticEvidenceIntern.ts +151 -0
- package/src/diagnosticExposure.ts +550 -50
- package/src/diagnosticExpressions.ts +99 -17
- package/src/diagnosticFormulas.ts +239 -39
- package/src/diagnosticIdentity.ts +700 -191
- package/src/diagnosticIdentityStream.ts +553 -0
- package/src/diagnosticOrdering.ts +106 -0
- package/src/diagnosticPeriodAxis.ts +92 -0
- package/src/diagnosticPeriods.ts +67 -82
- package/src/diagnosticPreparation.ts +2558 -132
- package/src/diagnosticReview.ts +1072 -58
- package/src/diagnosticReviewSources.ts +85 -0
- package/src/diagnosticReviewStore.ts +692 -0
- package/src/diagnosticRunner.ts +1273 -72
- package/src/diagnosticRuntime.ts +264 -0
- package/src/diagnosticSourceOrdering.ts +50 -0
- package/src/fnvAccumulator.ts +20 -0
- package/src/index.ts +69 -4
- package/src/mack.ts +72 -9
- package/src/triangle.ts +103 -13
- package/src/types.ts +55 -20
- package/src/version.ts +1 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { DiagnosticPeriodAxis } from "./diagnosticDefinitions.js";
|
|
2
|
+
|
|
3
|
+
export interface NormalizedDiagnosticAxisPeriod {
|
|
4
|
+
readonly label: string;
|
|
5
|
+
readonly coordinate: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type DiagnosticPeriodSide = "origin" | "valuation";
|
|
9
|
+
|
|
10
|
+
function calendarCoordinate(
|
|
11
|
+
label: string,
|
|
12
|
+
cadence: "month" | "quarter" | "year",
|
|
13
|
+
anchor: "start" | "end",
|
|
14
|
+
): number | null {
|
|
15
|
+
let year: number;
|
|
16
|
+
let start: number;
|
|
17
|
+
let width: number;
|
|
18
|
+
if (cadence === "year") {
|
|
19
|
+
const match = /^(\d{4})$/.exec(label);
|
|
20
|
+
if (!match) return null;
|
|
21
|
+
year = Number(match[1]);
|
|
22
|
+
start = year * 12;
|
|
23
|
+
width = 12;
|
|
24
|
+
} else if (cadence === "month") {
|
|
25
|
+
const match = /^(\d{4})-(0[1-9]|1[0-2])$/.exec(label);
|
|
26
|
+
if (!match) return null;
|
|
27
|
+
year = Number(match[1]);
|
|
28
|
+
start = year * 12 + Number(match[2]) - 1;
|
|
29
|
+
width = 1;
|
|
30
|
+
} else {
|
|
31
|
+
const compact = /^(\d{4})Q([1-4])$/.exec(label);
|
|
32
|
+
const hyphenated = /^(\d{4})-Q([1-4])$/.exec(label);
|
|
33
|
+
const first = /^Q([1-4]) (\d{4})$/.exec(label);
|
|
34
|
+
const match = compact ?? hyphenated ?? first;
|
|
35
|
+
if (!match) return null;
|
|
36
|
+
const quarterFirst = match === first;
|
|
37
|
+
year = Number(match[quarterFirst ? 2 : 1]);
|
|
38
|
+
const quarter = Number(match[quarterFirst ? 1 : 2]);
|
|
39
|
+
start = year * 12 + (quarter - 1) * 3;
|
|
40
|
+
width = 3;
|
|
41
|
+
}
|
|
42
|
+
if (year < 1 || year > 9999) return null;
|
|
43
|
+
return start + (anchor === "end" ? width : 0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Pure axis-level period normalization shared by compilation and execution. */
|
|
47
|
+
export function normalizeDiagnosticPeriodWithAxis(
|
|
48
|
+
axis: DiagnosticPeriodAxis,
|
|
49
|
+
side: DiagnosticPeriodSide,
|
|
50
|
+
label: unknown,
|
|
51
|
+
): NormalizedDiagnosticAxisPeriod | null {
|
|
52
|
+
if (typeof label !== "string" || axis === null || typeof axis !== "object")
|
|
53
|
+
return null;
|
|
54
|
+
if (axis.kind === "calendar") {
|
|
55
|
+
const cadence =
|
|
56
|
+
side === "origin" ? axis.originCadence : axis.valuationCadence;
|
|
57
|
+
const anchor = side === "origin" ? axis.originAnchor : axis.valuationAnchor;
|
|
58
|
+
if (
|
|
59
|
+
!["month", "quarter", "year"].includes(cadence) ||
|
|
60
|
+
!["start", "end"].includes(anchor)
|
|
61
|
+
)
|
|
62
|
+
return null;
|
|
63
|
+
const coordinate = calendarCoordinate(label, cadence, anchor);
|
|
64
|
+
if (coordinate === null) return null;
|
|
65
|
+
const canonicalLabel =
|
|
66
|
+
cadence === "quarter"
|
|
67
|
+
? (() => {
|
|
68
|
+
const startCoordinate = calendarCoordinate(
|
|
69
|
+
label,
|
|
70
|
+
cadence,
|
|
71
|
+
"start",
|
|
72
|
+
)!;
|
|
73
|
+
const year = Math.floor(startCoordinate / 12);
|
|
74
|
+
return `${String(year).padStart(4, "0")}-Q${Math.floor((startCoordinate % 12) / 3) + 1}`;
|
|
75
|
+
})()
|
|
76
|
+
: label;
|
|
77
|
+
return { label: canonicalLabel, coordinate };
|
|
78
|
+
}
|
|
79
|
+
if (
|
|
80
|
+
axis.kind !== "ordered" ||
|
|
81
|
+
!Array.isArray(axis[side === "origin" ? "origins" : "valuations"])
|
|
82
|
+
)
|
|
83
|
+
return null;
|
|
84
|
+
const catalog = side === "origin" ? axis.origins : axis.valuations;
|
|
85
|
+
const item = catalog.find(
|
|
86
|
+
(coordinate) =>
|
|
87
|
+
coordinate?.label === label || coordinate?.aliases?.includes(label),
|
|
88
|
+
);
|
|
89
|
+
return item && typeof item.coordinate === "number"
|
|
90
|
+
? { label: item.label, coordinate: item.coordinate }
|
|
91
|
+
: null;
|
|
92
|
+
}
|
package/src/diagnosticPeriods.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
CompiledDiagnosticDefinition,
|
|
3
|
+
DiagnosticPeriodAxis,
|
|
4
|
+
} from "./diagnosticDefinitions.js";
|
|
2
5
|
import { assertCompiledDiagnosticDefinition } from "./diagnosticDefinitions.js";
|
|
6
|
+
import {
|
|
7
|
+
normalizeDiagnosticPeriodWithAxis,
|
|
8
|
+
type DiagnosticPeriodSide,
|
|
9
|
+
} from "./diagnosticPeriodAxis.js";
|
|
3
10
|
import { DiagnosticValidationError } from "./types.js";
|
|
4
11
|
|
|
5
12
|
export interface DiagnosticNormalizedPeriod {
|
|
@@ -7,103 +14,75 @@ export interface DiagnosticNormalizedPeriod {
|
|
|
7
14
|
readonly coordinate: number;
|
|
8
15
|
}
|
|
9
16
|
|
|
10
|
-
type PeriodSide = "origin" | "valuation";
|
|
11
|
-
|
|
12
|
-
function calendarCoordinate(
|
|
13
|
-
label: string,
|
|
14
|
-
cadence: "month" | "quarter" | "year",
|
|
15
|
-
anchor: "start" | "end",
|
|
16
|
-
): number | null {
|
|
17
|
-
let year: number;
|
|
18
|
-
let start: number;
|
|
19
|
-
let width: number;
|
|
20
|
-
if (cadence === "year") {
|
|
21
|
-
const match = /^(\d{4})$/.exec(label);
|
|
22
|
-
if (!match) return null;
|
|
23
|
-
year = Number(match[1]);
|
|
24
|
-
start = year * 12;
|
|
25
|
-
width = 12;
|
|
26
|
-
} else if (cadence === "month") {
|
|
27
|
-
const match = /^(\d{4})-(0[1-9]|1[0-2])$/.exec(label);
|
|
28
|
-
if (!match) return null;
|
|
29
|
-
year = Number(match[1]);
|
|
30
|
-
start = year * 12 + Number(match[2]) - 1;
|
|
31
|
-
width = 1;
|
|
32
|
-
} else {
|
|
33
|
-
const compact = /^(\d{4})Q([1-4])$/.exec(label);
|
|
34
|
-
const hyphenated = /^(\d{4})-Q([1-4])$/.exec(label);
|
|
35
|
-
const first = /^Q([1-4]) (\d{4})$/.exec(label);
|
|
36
|
-
const match = compact ?? hyphenated ?? first;
|
|
37
|
-
if (!match) return null;
|
|
38
|
-
const quarterFirst = match === first;
|
|
39
|
-
year = Number(match[quarterFirst ? 2 : 1]);
|
|
40
|
-
const quarter = Number(match[quarterFirst ? 1 : 2]);
|
|
41
|
-
start = year * 12 + (quarter - 1) * 3;
|
|
42
|
-
width = 3;
|
|
43
|
-
}
|
|
44
|
-
if (year < 1 || year > 9999) return null;
|
|
45
|
-
return start + (anchor === "end" ? width : 0);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
17
|
function normalizeWithAxis(
|
|
49
18
|
axis: DiagnosticPeriodAxis,
|
|
50
|
-
side:
|
|
19
|
+
side: DiagnosticPeriodSide,
|
|
51
20
|
label: string,
|
|
52
21
|
): DiagnosticNormalizedPeriod {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return `${String(year).padStart(4, "0")}Q${Math.floor((startCoordinate % 12) / 3) + 1}`;
|
|
68
|
-
})()
|
|
69
|
-
: label;
|
|
70
|
-
return Object.freeze({ label: canonicalLabel, coordinate });
|
|
71
|
-
}
|
|
72
|
-
const catalog = side === "origin" ? axis.origins : axis.valuations;
|
|
73
|
-
const item = catalog.find((coordinate) => coordinate.label === label || coordinate.aliases?.includes(label));
|
|
74
|
-
if (!item) throw new DiagnosticValidationError([{
|
|
75
|
-
domain: "input",
|
|
76
|
-
code: "invalid-period",
|
|
77
|
-
path: `$.${side}`,
|
|
78
|
-
message: `Unknown ordered-axis ${side} label ${JSON.stringify(label)}`,
|
|
79
|
-
}]);
|
|
80
|
-
return Object.freeze({ label: item.label, coordinate: item.coordinate });
|
|
22
|
+
const normalized = normalizeDiagnosticPeriodWithAxis(axis, side, label);
|
|
23
|
+
if (!normalized)
|
|
24
|
+
throw new DiagnosticValidationError([
|
|
25
|
+
{
|
|
26
|
+
domain: "input",
|
|
27
|
+
code: "invalid-period",
|
|
28
|
+
path: `$.${side}`,
|
|
29
|
+
message:
|
|
30
|
+
axis.kind === "calendar"
|
|
31
|
+
? `Invalid ${side === "origin" ? axis.originCadence : axis.valuationCadence} ${side} label ${JSON.stringify(label)}`
|
|
32
|
+
: `Unknown ordered-axis ${side} label ${JSON.stringify(label)}`,
|
|
33
|
+
},
|
|
34
|
+
]);
|
|
35
|
+
return Object.freeze(normalized);
|
|
81
36
|
}
|
|
82
37
|
|
|
83
38
|
export function normalizeDiagnosticPeriod(
|
|
84
39
|
definition: CompiledDiagnosticDefinition,
|
|
85
|
-
side:
|
|
40
|
+
side: DiagnosticPeriodSide,
|
|
86
41
|
label: string,
|
|
87
42
|
): DiagnosticNormalizedPeriod {
|
|
88
43
|
assertCompiledDiagnosticDefinition(definition);
|
|
89
|
-
return normalizeWithAxis(
|
|
44
|
+
return normalizeWithAxis(
|
|
45
|
+
definition.definition.periodAxis as DiagnosticPeriodAxis,
|
|
46
|
+
side,
|
|
47
|
+
label,
|
|
48
|
+
);
|
|
90
49
|
}
|
|
91
50
|
|
|
92
51
|
export function diagnosticDevelopmentAge(
|
|
93
52
|
definition: CompiledDiagnosticDefinition,
|
|
94
53
|
origin: string,
|
|
95
54
|
valuation: string,
|
|
96
|
-
): {
|
|
97
|
-
|
|
98
|
-
|
|
55
|
+
): {
|
|
56
|
+
readonly origin: DiagnosticNormalizedPeriod;
|
|
57
|
+
readonly valuation: DiagnosticNormalizedPeriod;
|
|
58
|
+
readonly developmentAge: number;
|
|
59
|
+
readonly ageUnit: string;
|
|
60
|
+
} {
|
|
61
|
+
const normalizedOrigin = normalizeDiagnosticPeriod(
|
|
62
|
+
definition,
|
|
63
|
+
"origin",
|
|
64
|
+
origin,
|
|
65
|
+
);
|
|
66
|
+
const normalizedValuation = normalizeDiagnosticPeriod(
|
|
67
|
+
definition,
|
|
68
|
+
"valuation",
|
|
69
|
+
valuation,
|
|
70
|
+
);
|
|
99
71
|
const axis = definition.definition.periodAxis;
|
|
100
|
-
const developmentAge =
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
72
|
+
const developmentAge =
|
|
73
|
+
normalizedValuation.coordinate -
|
|
74
|
+
normalizedOrigin.coordinate +
|
|
75
|
+
axis.ageOffset;
|
|
76
|
+
if (!Number.isSafeInteger(developmentAge) || developmentAge < 0)
|
|
77
|
+
throw new DiagnosticValidationError([
|
|
78
|
+
{
|
|
79
|
+
domain: "input",
|
|
80
|
+
code: "invalid-period",
|
|
81
|
+
path: "$.valuation",
|
|
82
|
+
message:
|
|
83
|
+
"Valuation period precedes origin period or development age is unsafe",
|
|
84
|
+
},
|
|
85
|
+
]);
|
|
107
86
|
return Object.freeze({
|
|
108
87
|
origin: normalizedOrigin,
|
|
109
88
|
valuation: normalizedValuation,
|
|
@@ -112,6 +91,12 @@ export function diagnosticDevelopmentAge(
|
|
|
112
91
|
});
|
|
113
92
|
}
|
|
114
93
|
|
|
115
|
-
export function compareDiagnosticPeriods(
|
|
116
|
-
|
|
94
|
+
export function compareDiagnosticPeriods(
|
|
95
|
+
left: DiagnosticNormalizedPeriod,
|
|
96
|
+
right: DiagnosticNormalizedPeriod,
|
|
97
|
+
): number {
|
|
98
|
+
return (
|
|
99
|
+
left.coordinate - right.coordinate ||
|
|
100
|
+
(left.label < right.label ? -1 : left.label > right.label ? 1 : 0)
|
|
101
|
+
);
|
|
117
102
|
}
|