calculation-breakdown 0.0.0-stage → 0.1.2
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/CHANGELOG-ARCHIVE.md +3 -0
- package/CHANGELOG.md +19 -0
- package/LICENSE +21 -0
- package/README.md +179 -2
- package/dist/calculation-breakdown-builder.d.ts +56 -0
- package/dist/calculation-breakdown-builder.d.ts.map +1 -0
- package/dist/calculation-breakdown-builder.js +242 -0
- package/dist/calculation-breakdown-builder.js.map +1 -0
- package/dist/calculation-breakdown-human-string.d.ts +24 -0
- package/dist/calculation-breakdown-human-string.d.ts.map +1 -0
- package/dist/calculation-breakdown-human-string.js +86 -0
- package/dist/calculation-breakdown-human-string.js.map +1 -0
- package/dist/calculation-breakdown.error.d.ts +14 -0
- package/dist/calculation-breakdown.error.d.ts.map +1 -0
- package/dist/calculation-breakdown.error.js +16 -0
- package/dist/calculation-breakdown.error.js.map +1 -0
- package/dist/calculation-breakdown.interface.d.ts +134 -0
- package/dist/calculation-breakdown.interface.d.ts.map +1 -0
- package/dist/calculation-breakdown.interface.js +2 -0
- package/dist/calculation-breakdown.interface.js.map +1 -0
- package/dist/calculation-breakdown.type.d.ts +20 -0
- package/dist/calculation-breakdown.type.d.ts.map +1 -0
- package/dist/calculation-breakdown.type.js +2 -0
- package/dist/calculation-breakdown.type.js.map +1 -0
- package/dist/cjs/calculation-breakdown-builder.d.ts +55 -0
- package/dist/cjs/calculation-breakdown-builder.js +245 -0
- package/dist/cjs/calculation-breakdown-human-string.d.ts +23 -0
- package/dist/cjs/calculation-breakdown-human-string.js +88 -0
- package/dist/cjs/calculation-breakdown.error.d.ts +13 -0
- package/dist/cjs/calculation-breakdown.error.js +19 -0
- package/dist/cjs/calculation-breakdown.interface.d.ts +133 -0
- package/dist/cjs/calculation-breakdown.interface.js +2 -0
- package/dist/cjs/calculation-breakdown.type.d.ts +19 -0
- package/dist/cjs/calculation-breakdown.type.js +2 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +9 -0
- package/dist/cjs/package.json +3 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/docs/_config.yml +19 -0
- package/docs/assets/calculation-breakdown/calculation-breakdown-builder.js +242 -0
- package/docs/assets/calculation-breakdown/calculation-breakdown-human-string.js +86 -0
- package/docs/assets/calculation-breakdown/calculation-breakdown.error.js +16 -0
- package/docs/assets/calculation-breakdown/calculation-breakdown.interface.js +2 -0
- package/docs/assets/calculation-breakdown/calculation-breakdown.type.js +2 -0
- package/docs/assets/calculation-breakdown/index.js +4 -0
- package/docs/changelog-archive.md +9 -0
- package/docs/changelog.md +25 -0
- package/docs/index.md +13 -0
- package/docs/playground/index.html +110 -0
- package/docs/playground/playground.css +407 -0
- package/docs/playground/playground.js +1303 -0
- package/package.json +66 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculation-breakdown-human-string.js","sourceRoot":"","sources":["../src/calculation-breakdown-human-string.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Machine-readable codes emitted when breakdown construction fails. */
|
|
2
|
+
export type TCalculationBreakdownErrorCode = 'INVALID_SEMANTIC' | 'INVALID_DECIMAL' | 'INVALID_CURRENCY' | 'INVALID_DURATION_UNIT' | 'INVALID_OPERATOR' | 'INVALID_ROUNDING' | 'INVALID_ROUNDING_STEP' | 'INVALID_GROUP_ROLE' | 'INVALID_GROUP_ORIENTATION' | 'MISSING_BREAKDOWN' | 'MISSING_RESULT';
|
|
3
|
+
/** Error thrown when a calculation breakdown contains invalid or incomplete input. */
|
|
4
|
+
export declare class CalculationBreakdownError extends Error {
|
|
5
|
+
readonly code: TCalculationBreakdownErrorCode;
|
|
6
|
+
/**
|
|
7
|
+
* Creates a calculation breakdown error.
|
|
8
|
+
*
|
|
9
|
+
* @param code - Stable code suitable for programmatic error handling.
|
|
10
|
+
* @param message - Human-readable explanation of the failure.
|
|
11
|
+
*/
|
|
12
|
+
constructor(code: TCalculationBreakdownErrorCode, message: string);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=calculation-breakdown.error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculation-breakdown.error.d.ts","sourceRoot":"","sources":["../src/calculation-breakdown.error.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,MAAM,8BAA8B,GACpC,kBAAkB,GAClB,iBAAiB,GACjB,kBAAkB,GAClB,uBAAuB,GACvB,kBAAkB,GAClB,kBAAkB,GAClB,uBAAuB,GACvB,oBAAoB,GACpB,2BAA2B,GAC3B,mBAAmB,GACnB,gBAAgB,CAAC;AAEvB,sFAAsF;AACtF,qBAAa,yBAA0B,SAAQ,KAAK;IAQ5C,QAAQ,CAAC,IAAI,EAAE,8BAA8B;IAPjD;;;;;OAKG;gBAEU,IAAI,EAAE,8BAA8B,EAC7C,OAAO,EAAE,MAAM;CAKtB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Error thrown when a calculation breakdown contains invalid or incomplete input. */
|
|
2
|
+
export class CalculationBreakdownError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
/**
|
|
5
|
+
* Creates a calculation breakdown error.
|
|
6
|
+
*
|
|
7
|
+
* @param code - Stable code suitable for programmatic error handling.
|
|
8
|
+
* @param message - Human-readable explanation of the failure.
|
|
9
|
+
*/
|
|
10
|
+
constructor(code, message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.name = 'CalculationBreakdownError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=calculation-breakdown.error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculation-breakdown.error.js","sourceRoot":"","sources":["../src/calculation-breakdown.error.ts"],"names":[],"mappings":"AAcA,sFAAsF;AACtF,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAQnC;IAPb;;;;;OAKG;IACH,YACa,IAAoC,EAC7C,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHN,SAAI,GAAJ,IAAI,CAAgC;QAI7C,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC5C,CAAC;CACJ"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { TCalculationBreakdownDurationUnit, TCalculationBreakdownGroupRole, TCalculationBreakdownGroupOrientation, TCalculationBreakdownNode, TCalculationBreakdownOperator, TCalculationBreakdownOperatorInput, TCalculationBreakdownRounding, TCalculationBreakdownValue } from './calculation-breakdown.type.js';
|
|
2
|
+
/** Optional rounding rules for a duration value. */
|
|
3
|
+
export interface ICalculationBreakdownDurationOptions {
|
|
4
|
+
/** Direction in which the duration is rounded. Must be used with `step`. */
|
|
5
|
+
rounding?: TCalculationBreakdownRounding;
|
|
6
|
+
/** Positive interval to which the duration is rounded. Must be used with `rounding`. */
|
|
7
|
+
step?: number;
|
|
8
|
+
}
|
|
9
|
+
/** A monetary value represented by an exact decimal string and currency code. */
|
|
10
|
+
export interface ICalculationBreakdownMoneyValue<Semantic extends string> {
|
|
11
|
+
/** Discriminator for a monetary value. */
|
|
12
|
+
readonly type: 'money';
|
|
13
|
+
/** Domain-specific meaning of the value. */
|
|
14
|
+
readonly semantic: Semantic;
|
|
15
|
+
/** Exact decimal amount. */
|
|
16
|
+
readonly amount: string;
|
|
17
|
+
/** Three-letter uppercase currency code, such as `USD`. */
|
|
18
|
+
readonly currency: string;
|
|
19
|
+
}
|
|
20
|
+
/** A duration represented by an exact decimal string and unit. */
|
|
21
|
+
export interface ICalculationBreakdownDurationValue<Semantic extends string> extends ICalculationBreakdownDurationOptions {
|
|
22
|
+
/** Discriminator for a duration value. */
|
|
23
|
+
readonly type: 'duration';
|
|
24
|
+
/** Domain-specific meaning of the value. */
|
|
25
|
+
readonly semantic: Semantic;
|
|
26
|
+
/** Exact decimal duration. */
|
|
27
|
+
readonly amount: string;
|
|
28
|
+
/** Unit in which the duration is expressed. */
|
|
29
|
+
readonly unit: TCalculationBreakdownDurationUnit;
|
|
30
|
+
}
|
|
31
|
+
/** A dimensionless semantic number represented by an exact decimal string. */
|
|
32
|
+
export interface ICalculationBreakdownNumberValue<Semantic extends string> {
|
|
33
|
+
/** Discriminator for a semantic number. */
|
|
34
|
+
readonly type: 'number';
|
|
35
|
+
/** Domain-specific meaning of the value. */
|
|
36
|
+
readonly semantic: Semantic;
|
|
37
|
+
/** Exact decimal value. */
|
|
38
|
+
readonly value: string;
|
|
39
|
+
}
|
|
40
|
+
/** A percentage represented as an exact fractional decimal string. */
|
|
41
|
+
export interface ICalculationBreakdownPercentValue<Semantic extends string> {
|
|
42
|
+
/** Discriminator for a percentage value. */
|
|
43
|
+
readonly type: 'percent';
|
|
44
|
+
/** Domain-specific meaning of the value. */
|
|
45
|
+
readonly semantic: Semantic;
|
|
46
|
+
/** Exact fractional value, where `0.20` represents 20%. */
|
|
47
|
+
readonly value: string;
|
|
48
|
+
}
|
|
49
|
+
/** A dimensionless numeric literal used inside an expression. */
|
|
50
|
+
export interface ICalculationBreakdownConstantValue {
|
|
51
|
+
/** Discriminator for a constant. */
|
|
52
|
+
readonly type: 'constant';
|
|
53
|
+
/** Exact decimal value. */
|
|
54
|
+
readonly value: string;
|
|
55
|
+
}
|
|
56
|
+
/** A binary operation recorded in a calculation breakdown. */
|
|
57
|
+
export interface ICalculationBreakdownOperation<Semantic extends string> {
|
|
58
|
+
/** Discriminator for an operation. */
|
|
59
|
+
readonly type: 'operation';
|
|
60
|
+
/** Operation applied to the two operands. */
|
|
61
|
+
readonly operator: TCalculationBreakdownOperator;
|
|
62
|
+
/** Left and right operands, in evaluation order. */
|
|
63
|
+
readonly operands: readonly [
|
|
64
|
+
TCalculationBreakdownNode<Semantic>,
|
|
65
|
+
TCalculationBreakdownNode<Semantic>
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
/** Optional presentation hints for an explicitly grouped expression. */
|
|
69
|
+
export interface ICalculationBreakdownGroupOptions<Semantic extends string = string> {
|
|
70
|
+
/** Suggests that renderers place this group on its own visual line. */
|
|
71
|
+
readonly wrap?: boolean;
|
|
72
|
+
/** Domain-specific meaning of the grouped expression. */
|
|
73
|
+
readonly semantic?: Semantic;
|
|
74
|
+
/** Authoritative result of the grouped expression, such as a line subtotal. */
|
|
75
|
+
readonly result?: TCalculationBreakdownValue<Semantic>;
|
|
76
|
+
/** Identifies a roll-up whose authoritative result may be emphasized by renderers. */
|
|
77
|
+
readonly role?: TCalculationBreakdownGroupRole;
|
|
78
|
+
/** Preferred flow for detail values. Omitted groups default to horizontal. */
|
|
79
|
+
readonly orientation?: TCalculationBreakdownGroupOrientation;
|
|
80
|
+
}
|
|
81
|
+
/** An explicitly grouped subexpression. */
|
|
82
|
+
export interface ICalculationBreakdownGroup<Semantic extends string> extends ICalculationBreakdownGroupOptions<Semantic> {
|
|
83
|
+
/** Discriminator for a group. */
|
|
84
|
+
readonly type: 'group';
|
|
85
|
+
/** Expression enclosed by the group. */
|
|
86
|
+
readonly expression: TCalculationBreakdownNode<Semantic>;
|
|
87
|
+
}
|
|
88
|
+
/** Serializable, immutable record of how an externally calculated result was derived. */
|
|
89
|
+
export interface ICalculationBreakdown<Semantic extends string> {
|
|
90
|
+
/** Root node describing the operations and values in the calculation. */
|
|
91
|
+
readonly breakdown: TCalculationBreakdownNode<Semantic>;
|
|
92
|
+
/** Authoritative result supplied by the calling application. */
|
|
93
|
+
readonly result: TCalculationBreakdownValue<Semantic>;
|
|
94
|
+
}
|
|
95
|
+
/** Factory methods available inside breakdown and result callbacks. */
|
|
96
|
+
export interface ICalculationBreakdownNodeBuilder<Semantic extends string> {
|
|
97
|
+
/** Creates a monetary value. */
|
|
98
|
+
money(semantic: Semantic, amount: string, currency: string): ICalculationBreakdownMoneyValue<Semantic>;
|
|
99
|
+
/** Creates a duration value, optionally with a rounding rule. */
|
|
100
|
+
duration(semantic: Semantic, amount: string, unit: TCalculationBreakdownDurationUnit, options?: ICalculationBreakdownDurationOptions): ICalculationBreakdownDurationValue<Semantic>;
|
|
101
|
+
/** Creates a semantic, dimensionless number. */
|
|
102
|
+
number(semantic: Semantic, value: string): ICalculationBreakdownNumberValue<Semantic>;
|
|
103
|
+
/** Creates a percentage from a fractional decimal, such as `0.20` for 20%. */
|
|
104
|
+
percent(semantic: Semantic, value: string): ICalculationBreakdownPercentValue<Semantic>;
|
|
105
|
+
/** Creates a dimensionless numeric literal. */
|
|
106
|
+
constant(value: string): ICalculationBreakdownConstantValue;
|
|
107
|
+
/** Preserves an explicit grouping and optional presentation hints. */
|
|
108
|
+
group(expression: TCalculationBreakdownNode<Semantic>, options?: ICalculationBreakdownGroupOptions<Semantic>): ICalculationBreakdownGroup<Semantic>;
|
|
109
|
+
/** Creates a binary operation using any supported operator. */
|
|
110
|
+
operator(left: TCalculationBreakdownNode<Semantic>, operator: TCalculationBreakdownOperatorInput, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
111
|
+
/** Adds two expressions. */
|
|
112
|
+
add(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
113
|
+
/** Subtracts the right expression from the left expression. */
|
|
114
|
+
subtract(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
115
|
+
/** Decimal.js-style alias for `subtract`. */
|
|
116
|
+
sub(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
117
|
+
/** Multiplies two expressions. */
|
|
118
|
+
multiply(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
119
|
+
/** Decimal.js-style alias for `multiply`. */
|
|
120
|
+
mul(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
121
|
+
/** Divides the left expression by the right expression. */
|
|
122
|
+
divide(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
123
|
+
/** Decimal.js-style alias for `divide`. */
|
|
124
|
+
div(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
125
|
+
/** Selects the smaller of two expressions. */
|
|
126
|
+
minimum(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
127
|
+
/** Decimal.js-style alias for `minimum`. */
|
|
128
|
+
min(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
129
|
+
/** Selects the larger of two expressions. */
|
|
130
|
+
maximum(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
131
|
+
/** Decimal.js-style alias for `maximum`. */
|
|
132
|
+
max(left: TCalculationBreakdownNode<Semantic>, right: TCalculationBreakdownNode<Semantic>): ICalculationBreakdownOperation<Semantic>;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=calculation-breakdown.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculation-breakdown.interface.d.ts","sourceRoot":"","sources":["../src/calculation-breakdown.interface.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculation-breakdown.interface.js","sourceRoot":"","sources":["../src/calculation-breakdown.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ICalculationBreakdownConstantValue, ICalculationBreakdownDurationValue, ICalculationBreakdownGroup, ICalculationBreakdownMoneyValue, ICalculationBreakdownNumberValue, ICalculationBreakdownOperation, ICalculationBreakdownPercentValue } from './calculation-breakdown.interface.js';
|
|
2
|
+
/** Binary operations that can be recorded in a calculation breakdown. */
|
|
3
|
+
export type TCalculationBreakdownOperator = 'add' | 'subtract' | 'multiply' | 'divide' | 'minimum' | 'maximum';
|
|
4
|
+
/** Decimal.js-style aliases accepted when constructing an operation. */
|
|
5
|
+
export type TCalculationBreakdownOperatorAlias = 'sub' | 'mul' | 'div' | 'min' | 'max';
|
|
6
|
+
/** Any operator name accepted by the builder. */
|
|
7
|
+
export type TCalculationBreakdownOperatorInput = TCalculationBreakdownOperator | TCalculationBreakdownOperatorAlias;
|
|
8
|
+
/** Units available for duration values. */
|
|
9
|
+
export type TCalculationBreakdownDurationUnit = 'milliseconds' | 'seconds' | 'minutes' | 'hours' | 'days';
|
|
10
|
+
/** Direction used when rounding a duration to a step. */
|
|
11
|
+
export type TCalculationBreakdownRounding = 'up' | 'down' | 'nearest';
|
|
12
|
+
/** Semantic role of a grouped expression. */
|
|
13
|
+
export type TCalculationBreakdownGroupRole = 'detail' | 'summary';
|
|
14
|
+
/** Preferred flow of a detail group in structured renderers. */
|
|
15
|
+
export type TCalculationBreakdownGroupOrientation = 'horizontal' | 'vertical';
|
|
16
|
+
/** A semantic value that can be recorded as the authoritative result. */
|
|
17
|
+
export type TCalculationBreakdownValue<Semantic extends string> = ICalculationBreakdownMoneyValue<Semantic> | ICalculationBreakdownDurationValue<Semantic> | ICalculationBreakdownNumberValue<Semantic> | ICalculationBreakdownPercentValue<Semantic>;
|
|
18
|
+
/** Any node that can appear in a calculation breakdown tree. */
|
|
19
|
+
export type TCalculationBreakdownNode<Semantic extends string> = TCalculationBreakdownValue<Semantic> | ICalculationBreakdownConstantValue | ICalculationBreakdownOperation<Semantic> | ICalculationBreakdownGroup<Semantic>;
|
|
20
|
+
//# sourceMappingURL=calculation-breakdown.type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculation-breakdown.type.d.ts","sourceRoot":"","sources":["../src/calculation-breakdown.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,kCAAkC,EAClC,kCAAkC,EAClC,0BAA0B,EAC1B,+BAA+B,EAC/B,gCAAgC,EAChC,8BAA8B,EAC9B,iCAAiC,EACpC,MAAM,sCAAsC,CAAC;AAE9C,yEAAyE;AACzE,MAAM,MAAM,6BAA6B,GACnC,KAAK,GACL,UAAU,GACV,UAAU,GACV,QAAQ,GACR,SAAS,GACT,SAAS,CAAC;AAEhB,wEAAwE;AACxE,MAAM,MAAM,kCAAkC,GACxC,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,CAAC;AAEZ,iDAAiD;AACjD,MAAM,MAAM,kCAAkC,GACxC,6BAA6B,GAC7B,kCAAkC,CAAC;AAEzC,2CAA2C;AAC3C,MAAM,MAAM,iCAAiC,GACvC,cAAc,GACd,SAAS,GACT,SAAS,GACT,OAAO,GACP,MAAM,CAAC;AAEb,yDAAyD;AACzD,MAAM,MAAM,6BAA6B,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;AAEtE,6CAA6C;AAC7C,MAAM,MAAM,8BAA8B,GAAG,QAAQ,GAAG,SAAS,CAAC;AAElE,gEAAgE;AAChE,MAAM,MAAM,qCAAqC,GAC3C,YAAY,GACZ,UAAU,CAAC;AAEjB,yEAAyE;AACzE,MAAM,MAAM,0BAA0B,CAAC,QAAQ,SAAS,MAAM,IACxD,+BAA+B,CAAC,QAAQ,CAAC,GACzC,kCAAkC,CAAC,QAAQ,CAAC,GAC5C,gCAAgC,CAAC,QAAQ,CAAC,GAC1C,iCAAiC,CAAC,QAAQ,CAAC,CAAC;AAElD,gEAAgE;AAChE,MAAM,MAAM,yBAAyB,CAAC,QAAQ,SAAS,MAAM,IACvD,0BAA0B,CAAC,QAAQ,CAAC,GACpC,kCAAkC,GAClC,8BAA8B,CAAC,QAAQ,CAAC,GACxC,0BAA0B,CAAC,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculation-breakdown.type.js","sourceRoot":"","sources":["../src/calculation-breakdown.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type ICalculationBreakdownHumanStringOptions } from './calculation-breakdown-human-string.js';
|
|
2
|
+
import type { ICalculationBreakdown, ICalculationBreakdownNodeBuilder } from './calculation-breakdown.interface.js';
|
|
3
|
+
import type { TCalculationBreakdownNode, TCalculationBreakdownValue } from './calculation-breakdown.type.js';
|
|
4
|
+
/**
|
|
5
|
+
* Records a typed, serializable breakdown of a calculation performed elsewhere.
|
|
6
|
+
*
|
|
7
|
+
* This builder does not evaluate operations or calculate the result. The calling
|
|
8
|
+
* application supplies every value, including the authoritative result.
|
|
9
|
+
*
|
|
10
|
+
* @typeParam Semantic - String union used to label the domain meaning of values.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const breakdown = new CalculationBreakdownBuilder<'price' | 'total'>()
|
|
15
|
+
* .breakdown(({ money, constant, multiply }) =>
|
|
16
|
+
* multiply(money('price', '100.00', 'USD'), constant('0.9')),
|
|
17
|
+
* )
|
|
18
|
+
* .result(({ money }) => money('total', '90.00', 'USD'))
|
|
19
|
+
* .build();
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare class CalculationBreakdownBuilder<Semantic extends string> {
|
|
23
|
+
private breakdownValue?;
|
|
24
|
+
private resultValue?;
|
|
25
|
+
private readonly nodeBuilder;
|
|
26
|
+
/**
|
|
27
|
+
* Sets the root node that describes the calculation.
|
|
28
|
+
*
|
|
29
|
+
* @param create - Callback that describes the calculation using typed factories.
|
|
30
|
+
* @returns This builder for fluent chaining.
|
|
31
|
+
*/
|
|
32
|
+
breakdown(create: (builder: ICalculationBreakdownNodeBuilder<Semantic>) => TCalculationBreakdownNode<Semantic>): this;
|
|
33
|
+
/**
|
|
34
|
+
* Sets the authoritative result calculated by the calling application.
|
|
35
|
+
*
|
|
36
|
+
* @param create - Callback that constructs a money, duration, or number value.
|
|
37
|
+
* @returns This builder for fluent chaining.
|
|
38
|
+
*/
|
|
39
|
+
result(create: (builder: ICalculationBreakdownNodeBuilder<Semantic>) => TCalculationBreakdownValue<Semantic>): this;
|
|
40
|
+
/**
|
|
41
|
+
* Produces a detached, deeply frozen calculation breakdown.
|
|
42
|
+
*
|
|
43
|
+
* @throws {CalculationBreakdownError} If either the breakdown or result is missing.
|
|
44
|
+
*/
|
|
45
|
+
build(): ICalculationBreakdown<Semantic>;
|
|
46
|
+
/** Builds and renders the calculation using localized semantic labels. */
|
|
47
|
+
toHumanString(options: ICalculationBreakdownHumanStringOptions<Semantic>): string;
|
|
48
|
+
private createMoney;
|
|
49
|
+
private createDuration;
|
|
50
|
+
private createNumber;
|
|
51
|
+
private createPercent;
|
|
52
|
+
private createConstant;
|
|
53
|
+
private createGroup;
|
|
54
|
+
private createOperation;
|
|
55
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CalculationBreakdownBuilder = void 0;
|
|
4
|
+
const calculation_breakdown_error_js_1 = require("./calculation-breakdown.error.js");
|
|
5
|
+
const calculation_breakdown_human_string_js_1 = require("./calculation-breakdown-human-string.js");
|
|
6
|
+
const DECIMAL_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
7
|
+
const CURRENCY_PATTERN = /^[A-Z]{3}$/;
|
|
8
|
+
const DURATION_UNITS = new Set([
|
|
9
|
+
'milliseconds',
|
|
10
|
+
'seconds',
|
|
11
|
+
'minutes',
|
|
12
|
+
'hours',
|
|
13
|
+
'days',
|
|
14
|
+
]);
|
|
15
|
+
const ROUNDING_MODES = new Set([
|
|
16
|
+
'up',
|
|
17
|
+
'down',
|
|
18
|
+
'nearest',
|
|
19
|
+
]);
|
|
20
|
+
const GROUP_ROLES = new Set([
|
|
21
|
+
'detail',
|
|
22
|
+
'summary',
|
|
23
|
+
]);
|
|
24
|
+
const GROUP_ORIENTATIONS = new Set([
|
|
25
|
+
'horizontal',
|
|
26
|
+
'vertical',
|
|
27
|
+
]);
|
|
28
|
+
const OPERATORS = new Set([
|
|
29
|
+
'add',
|
|
30
|
+
'subtract',
|
|
31
|
+
'multiply',
|
|
32
|
+
'divide',
|
|
33
|
+
'minimum',
|
|
34
|
+
'maximum',
|
|
35
|
+
]);
|
|
36
|
+
const OPERATOR_ALIASES = {
|
|
37
|
+
sub: 'subtract',
|
|
38
|
+
mul: 'multiply',
|
|
39
|
+
div: 'divide',
|
|
40
|
+
min: 'minimum',
|
|
41
|
+
max: 'maximum',
|
|
42
|
+
};
|
|
43
|
+
function assertSemantic(semantic) {
|
|
44
|
+
if (semantic.trim().length === 0) {
|
|
45
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('INVALID_SEMANTIC', 'Semantic must be a non-empty string.');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function assertDecimal(value) {
|
|
49
|
+
if (!DECIMAL_PATTERN.test(value)) {
|
|
50
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('INVALID_DECIMAL', `Invalid decimal string: ${value}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function assertDurationOptions(options) {
|
|
54
|
+
if (!options)
|
|
55
|
+
return;
|
|
56
|
+
const hasRounding = options.rounding !== undefined;
|
|
57
|
+
const hasStep = options.step !== undefined;
|
|
58
|
+
const step = options.step;
|
|
59
|
+
if (hasRounding &&
|
|
60
|
+
!ROUNDING_MODES.has(options.rounding)) {
|
|
61
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('INVALID_ROUNDING', `Invalid rounding mode: ${String(options.rounding)}`);
|
|
62
|
+
}
|
|
63
|
+
if (hasRounding !== hasStep) {
|
|
64
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('INVALID_ROUNDING_STEP', 'Rounding and step must be provided together.');
|
|
65
|
+
}
|
|
66
|
+
if (hasStep &&
|
|
67
|
+
(step === undefined || !Number.isFinite(step) || step <= 0)) {
|
|
68
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('INVALID_ROUNDING_STEP', 'Rounding step must be a positive finite number.');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function deepFreeze(value) {
|
|
72
|
+
if (typeof value !== 'object' || value === null || Object.isFrozen(value)) {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
Object.freeze(value);
|
|
76
|
+
for (const child of Object.values(value))
|
|
77
|
+
deepFreeze(child);
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
function cloneJson(value) {
|
|
81
|
+
return JSON.parse(JSON.stringify(value));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Records a typed, serializable breakdown of a calculation performed elsewhere.
|
|
85
|
+
*
|
|
86
|
+
* This builder does not evaluate operations or calculate the result. The calling
|
|
87
|
+
* application supplies every value, including the authoritative result.
|
|
88
|
+
*
|
|
89
|
+
* @typeParam Semantic - String union used to label the domain meaning of values.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* const breakdown = new CalculationBreakdownBuilder<'price' | 'total'>()
|
|
94
|
+
* .breakdown(({ money, constant, multiply }) =>
|
|
95
|
+
* multiply(money('price', '100.00', 'USD'), constant('0.9')),
|
|
96
|
+
* )
|
|
97
|
+
* .result(({ money }) => money('total', '90.00', 'USD'))
|
|
98
|
+
* .build();
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
class CalculationBreakdownBuilder {
|
|
102
|
+
breakdownValue;
|
|
103
|
+
resultValue;
|
|
104
|
+
nodeBuilder = {
|
|
105
|
+
money: (semantic, amount, currency) => this.createMoney(semantic, amount, currency),
|
|
106
|
+
duration: (semantic, amount, unit, options) => this.createDuration(semantic, amount, unit, options),
|
|
107
|
+
number: (semantic, value) => this.createNumber(semantic, value),
|
|
108
|
+
percent: (semantic, value) => this.createPercent(semantic, value),
|
|
109
|
+
constant: (value) => this.createConstant(value),
|
|
110
|
+
group: (expression, options) => this.createGroup(expression, options),
|
|
111
|
+
operator: (left, operator, right) => this.createOperation(left, operator, right),
|
|
112
|
+
add: (left, right) => this.createOperation(left, 'add', right),
|
|
113
|
+
subtract: (left, right) => this.createOperation(left, 'subtract', right),
|
|
114
|
+
sub: (left, right) => this.createOperation(left, 'sub', right),
|
|
115
|
+
multiply: (left, right) => this.createOperation(left, 'multiply', right),
|
|
116
|
+
mul: (left, right) => this.createOperation(left, 'mul', right),
|
|
117
|
+
divide: (left, right) => this.createOperation(left, 'divide', right),
|
|
118
|
+
div: (left, right) => this.createOperation(left, 'div', right),
|
|
119
|
+
minimum: (left, right) => this.createOperation(left, 'minimum', right),
|
|
120
|
+
min: (left, right) => this.createOperation(left, 'min', right),
|
|
121
|
+
maximum: (left, right) => this.createOperation(left, 'maximum', right),
|
|
122
|
+
max: (left, right) => this.createOperation(left, 'max', right),
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Sets the root node that describes the calculation.
|
|
126
|
+
*
|
|
127
|
+
* @param create - Callback that describes the calculation using typed factories.
|
|
128
|
+
* @returns This builder for fluent chaining.
|
|
129
|
+
*/
|
|
130
|
+
breakdown(create) {
|
|
131
|
+
this.breakdownValue = create(this.nodeBuilder);
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Sets the authoritative result calculated by the calling application.
|
|
136
|
+
*
|
|
137
|
+
* @param create - Callback that constructs a money, duration, or number value.
|
|
138
|
+
* @returns This builder for fluent chaining.
|
|
139
|
+
*/
|
|
140
|
+
result(create) {
|
|
141
|
+
this.resultValue = create(this.nodeBuilder);
|
|
142
|
+
return this;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Produces a detached, deeply frozen calculation breakdown.
|
|
146
|
+
*
|
|
147
|
+
* @throws {CalculationBreakdownError} If either the breakdown or result is missing.
|
|
148
|
+
*/
|
|
149
|
+
build() {
|
|
150
|
+
if (!this.breakdownValue) {
|
|
151
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('MISSING_BREAKDOWN', 'A breakdown is required before building.');
|
|
152
|
+
}
|
|
153
|
+
if (!this.resultValue) {
|
|
154
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('MISSING_RESULT', 'A result is required before building.');
|
|
155
|
+
}
|
|
156
|
+
return deepFreeze(cloneJson({
|
|
157
|
+
breakdown: this.breakdownValue,
|
|
158
|
+
result: this.resultValue,
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
/** Builds and renders the calculation using localized semantic labels. */
|
|
162
|
+
toHumanString(options) {
|
|
163
|
+
return (0, calculation_breakdown_human_string_js_1.toHumanString)(this.build(), options);
|
|
164
|
+
}
|
|
165
|
+
createMoney(semantic, amount, currency) {
|
|
166
|
+
assertSemantic(semantic);
|
|
167
|
+
assertDecimal(amount);
|
|
168
|
+
if (!CURRENCY_PATTERN.test(currency)) {
|
|
169
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('INVALID_CURRENCY', `Currency must be a three-letter uppercase code: ${currency}`);
|
|
170
|
+
}
|
|
171
|
+
return deepFreeze({ type: 'money', semantic, amount, currency });
|
|
172
|
+
}
|
|
173
|
+
createDuration(semantic, amount, unit, options) {
|
|
174
|
+
assertSemantic(semantic);
|
|
175
|
+
assertDecimal(amount);
|
|
176
|
+
if (!DURATION_UNITS.has(unit)) {
|
|
177
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('INVALID_DURATION_UNIT', `Unsupported duration unit: ${unit}`);
|
|
178
|
+
}
|
|
179
|
+
assertDurationOptions(options);
|
|
180
|
+
return deepFreeze({
|
|
181
|
+
type: 'duration',
|
|
182
|
+
semantic,
|
|
183
|
+
amount,
|
|
184
|
+
unit,
|
|
185
|
+
...(options?.rounding ? { rounding: options.rounding } : {}),
|
|
186
|
+
...(options?.step !== undefined ? { step: options.step } : {}),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
createNumber(semantic, value) {
|
|
190
|
+
assertSemantic(semantic);
|
|
191
|
+
assertDecimal(value);
|
|
192
|
+
return deepFreeze({ type: 'number', semantic, value });
|
|
193
|
+
}
|
|
194
|
+
createPercent(semantic, value) {
|
|
195
|
+
assertSemantic(semantic);
|
|
196
|
+
assertDecimal(value);
|
|
197
|
+
return deepFreeze({ type: 'percent', semantic, value });
|
|
198
|
+
}
|
|
199
|
+
createConstant(value) {
|
|
200
|
+
assertDecimal(value);
|
|
201
|
+
return deepFreeze({ type: 'constant', value });
|
|
202
|
+
}
|
|
203
|
+
createGroup(expression, options) {
|
|
204
|
+
if (options?.semantic !== undefined) {
|
|
205
|
+
assertSemantic(options.semantic);
|
|
206
|
+
}
|
|
207
|
+
if (options?.role !== undefined &&
|
|
208
|
+
!GROUP_ROLES.has(options.role)) {
|
|
209
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('INVALID_GROUP_ROLE', `Unsupported group role: ${String(options.role)}`);
|
|
210
|
+
}
|
|
211
|
+
if (options?.orientation !== undefined &&
|
|
212
|
+
!GROUP_ORIENTATIONS.has(options.orientation)) {
|
|
213
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('INVALID_GROUP_ORIENTATION', `Unsupported group orientation: ${String(options.orientation)}`);
|
|
214
|
+
}
|
|
215
|
+
return deepFreeze({
|
|
216
|
+
type: 'group',
|
|
217
|
+
expression,
|
|
218
|
+
...(options?.wrap === true ? { wrap: true } : {}),
|
|
219
|
+
...(options?.semantic !== undefined
|
|
220
|
+
? { semantic: options.semantic }
|
|
221
|
+
: {}),
|
|
222
|
+
...(options?.result !== undefined
|
|
223
|
+
? { result: options.result }
|
|
224
|
+
: {}),
|
|
225
|
+
...(options?.role !== undefined
|
|
226
|
+
? { role: options.role }
|
|
227
|
+
: {}),
|
|
228
|
+
...(options?.orientation !== undefined
|
|
229
|
+
? { orientation: options.orientation }
|
|
230
|
+
: {}),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
createOperation(left, operator, right) {
|
|
234
|
+
const normalizedOperator = OPERATOR_ALIASES[operator] ?? operator;
|
|
235
|
+
if (!OPERATORS.has(normalizedOperator)) {
|
|
236
|
+
throw new calculation_breakdown_error_js_1.CalculationBreakdownError('INVALID_OPERATOR', `Unsupported operator: ${operator}`);
|
|
237
|
+
}
|
|
238
|
+
return deepFreeze({
|
|
239
|
+
type: 'operation',
|
|
240
|
+
operator: normalizedOperator,
|
|
241
|
+
operands: [left, right],
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
exports.CalculationBreakdownBuilder = CalculationBreakdownBuilder;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ICalculationBreakdown } from './calculation-breakdown.interface.js';
|
|
2
|
+
/** Locales supported by the built-in human-readable renderer. */
|
|
3
|
+
export type TCalculationBreakdownLocale = 'en' | 'cs';
|
|
4
|
+
/** A semantic label with optional explanatory copy for richer UIs. */
|
|
5
|
+
export interface ICalculationBreakdownDictionaryEntry {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly description: string;
|
|
8
|
+
}
|
|
9
|
+
/** A short label or a label with explanatory copy. */
|
|
10
|
+
export type TCalculationBreakdownDictionaryEntry = string | ICalculationBreakdownDictionaryEntry;
|
|
11
|
+
/** Semantic labels grouped by supported locale. */
|
|
12
|
+
export type TCalculationBreakdownDictionary<Semantic extends string> = Partial<Record<TCalculationBreakdownLocale, Partial<Record<Semantic, TCalculationBreakdownDictionaryEntry>>>>;
|
|
13
|
+
/** Options for rendering a calculation breakdown as human-readable text. */
|
|
14
|
+
export interface ICalculationBreakdownHumanStringOptions<Semantic extends string> {
|
|
15
|
+
/** Language and decimal separator used by the renderer. */
|
|
16
|
+
readonly locale: TCalculationBreakdownLocale;
|
|
17
|
+
/** Localized labels for domain semantics. Missing labels use the semantic key. */
|
|
18
|
+
readonly dictionary: TCalculationBreakdownDictionary<Semantic>;
|
|
19
|
+
/** Whether semantic names are appended to values. Defaults to true. */
|
|
20
|
+
readonly includeNames?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Renders a plain calculation breakdown without changing its serialized form. */
|
|
23
|
+
export declare function toHumanString<Semantic extends string>(calculation: ICalculationBreakdown<Semantic>, options: ICalculationBreakdownHumanStringOptions<Semantic>): string;
|