iso-price 1.0.3
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/LICENSE +21 -0
- package/dist/contract/index.d.ts +25 -0
- package/dist/contract/index.js +60 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/domain.objects/IsoCurrency.d.ts +63 -0
- package/dist/domain.objects/IsoCurrency.js +70 -0
- package/dist/domain.objects/IsoCurrency.js.map +1 -0
- package/dist/domain.objects/IsoPrice.d.ts +16 -0
- package/dist/domain.objects/IsoPrice.js +3 -0
- package/dist/domain.objects/IsoPrice.js.map +1 -0
- package/dist/domain.objects/IsoPriceExponent.d.ts +28 -0
- package/dist/domain.objects/IsoPriceExponent.js +33 -0
- package/dist/domain.objects/IsoPriceExponent.js.map +1 -0
- package/dist/domain.objects/IsoPriceHuman.d.ts +19 -0
- package/dist/domain.objects/IsoPriceHuman.js +3 -0
- package/dist/domain.objects/IsoPriceHuman.js.map +1 -0
- package/dist/domain.objects/IsoPriceRoundMode.d.ts +23 -0
- package/dist/domain.objects/IsoPriceRoundMode.js +28 -0
- package/dist/domain.objects/IsoPriceRoundMode.js.map +1 -0
- package/dist/domain.objects/IsoPriceShape.d.ts +30 -0
- package/dist/domain.objects/IsoPriceShape.js +3 -0
- package/dist/domain.objects/IsoPriceShape.js.map +1 -0
- package/dist/domain.objects/IsoPriceWords.d.ts +20 -0
- package/dist/domain.objects/IsoPriceWords.js +3 -0
- package/dist/domain.objects/IsoPriceWords.js.map +1 -0
- package/dist/domain.operations/arithmetic/allocatePrice.d.ts +48 -0
- package/dist/domain.operations/arithmetic/allocatePrice.js +167 -0
- package/dist/domain.operations/arithmetic/allocatePrice.js.map +1 -0
- package/dist/domain.operations/arithmetic/dividePrice.d.ts +40 -0
- package/dist/domain.operations/arithmetic/dividePrice.js +127 -0
- package/dist/domain.operations/arithmetic/dividePrice.js.map +1 -0
- package/dist/domain.operations/arithmetic/multiplyPrice.d.ts +38 -0
- package/dist/domain.operations/arithmetic/multiplyPrice.js +89 -0
- package/dist/domain.operations/arithmetic/multiplyPrice.js.map +1 -0
- package/dist/domain.operations/arithmetic/subPrices.d.ts +28 -0
- package/dist/domain.operations/arithmetic/subPrices.js +62 -0
- package/dist/domain.operations/arithmetic/subPrices.js.map +1 -0
- package/dist/domain.operations/arithmetic/sumPrices.d.ts +44 -0
- package/dist/domain.operations/arithmetic/sumPrices.js +88 -0
- package/dist/domain.operations/arithmetic/sumPrices.js.map +1 -0
- package/dist/domain.operations/cast/asIsoPrice.d.ts +35 -0
- package/dist/domain.operations/cast/asIsoPrice.js +117 -0
- package/dist/domain.operations/cast/asIsoPrice.js.map +1 -0
- package/dist/domain.operations/cast/asIsoPriceHuman.d.ts +25 -0
- package/dist/domain.operations/cast/asIsoPriceHuman.js +106 -0
- package/dist/domain.operations/cast/asIsoPriceHuman.js.map +1 -0
- package/dist/domain.operations/cast/asIsoPriceShape.d.ts +25 -0
- package/dist/domain.operations/cast/asIsoPriceShape.js +164 -0
- package/dist/domain.operations/cast/asIsoPriceShape.js.map +1 -0
- package/dist/domain.operations/cast/asIsoPriceWords.d.ts +25 -0
- package/dist/domain.operations/cast/asIsoPriceWords.js +103 -0
- package/dist/domain.operations/cast/asIsoPriceWords.js.map +1 -0
- package/dist/domain.operations/guard/isIsoPrice.d.ts +18 -0
- package/dist/domain.operations/guard/isIsoPrice.js +29 -0
- package/dist/domain.operations/guard/isIsoPrice.js.map +1 -0
- package/dist/domain.operations/guard/isIsoPriceHuman.d.ts +24 -0
- package/dist/domain.operations/guard/isIsoPriceHuman.js +76 -0
- package/dist/domain.operations/guard/isIsoPriceHuman.js.map +1 -0
- package/dist/domain.operations/guard/isIsoPriceShape.d.ts +29 -0
- package/dist/domain.operations/guard/isIsoPriceShape.js +50 -0
- package/dist/domain.operations/guard/isIsoPriceShape.js.map +1 -0
- package/dist/domain.operations/guard/isIsoPriceWords.d.ts +24 -0
- package/dist/domain.operations/guard/isIsoPriceWords.js +48 -0
- package/dist/domain.operations/guard/isIsoPriceWords.js.map +1 -0
- package/dist/domain.operations/precision/getIsoPriceExponentByCurrency.d.ts +15 -0
- package/dist/domain.operations/precision/getIsoPriceExponentByCurrency.js +49 -0
- package/dist/domain.operations/precision/getIsoPriceExponentByCurrency.js.map +1 -0
- package/dist/domain.operations/precision/roundPrice.d.ts +25 -0
- package/dist/domain.operations/precision/roundPrice.js +24 -0
- package/dist/domain.operations/precision/roundPrice.js.map +1 -0
- package/dist/domain.operations/precision/setPricePrecision.d.ts +29 -0
- package/dist/domain.operations/precision/setPricePrecision.js +119 -0
- package/dist/domain.operations/precision/setPricePrecision.js.map +1 -0
- package/dist/domain.operations/statistics/calcPriceAvg.d.ts +21 -0
- package/dist/domain.operations/statistics/calcPriceAvg.js +92 -0
- package/dist/domain.operations/statistics/calcPriceAvg.js.map +1 -0
- package/dist/domain.operations/statistics/calcPriceStdev.d.ts +23 -0
- package/dist/domain.operations/statistics/calcPriceStdev.js +137 -0
- package/dist/domain.operations/statistics/calcPriceStdev.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/license.md +21 -0
- package/package.json +102 -0
- package/readme.md +373 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.priceAllocate = exports.allocatePrice = void 0;
|
|
4
|
+
const helpful_errors_1 = require("helpful-errors");
|
|
5
|
+
const IsoPriceExponent_1 = require("../../domain.objects/IsoPriceExponent");
|
|
6
|
+
const asIsoPriceShape_1 = require("../cast/asIsoPriceShape");
|
|
7
|
+
const asIsoPriceWords_1 = require("../cast/asIsoPriceWords");
|
|
8
|
+
function allocatePrice(input, options) {
|
|
9
|
+
const shape = (0, asIsoPriceShape_1.asIsoPriceShape)(input.of);
|
|
10
|
+
const exponent = shape.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI;
|
|
11
|
+
// handle equal parts allocation
|
|
12
|
+
if ('parts' in input.into) {
|
|
13
|
+
const parts = input.into.parts;
|
|
14
|
+
if (parts < 1) {
|
|
15
|
+
throw new helpful_errors_1.BadRequestError('cannot allocate into less than 1 part', {
|
|
16
|
+
input,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return allocateEqualParts(shape.amount, shape.currency, exponent, parts, input.remainder, options?.format);
|
|
20
|
+
}
|
|
21
|
+
// handle ratio allocation
|
|
22
|
+
const ratios = input.into.ratios;
|
|
23
|
+
if (ratios.length < 1) {
|
|
24
|
+
throw new helpful_errors_1.BadRequestError('cannot allocate into less than 1 part', {
|
|
25
|
+
input,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return allocateByRatios(shape.amount, shape.currency, exponent, ratios, input.remainder, options?.format);
|
|
29
|
+
}
|
|
30
|
+
exports.allocatePrice = allocatePrice;
|
|
31
|
+
/**
|
|
32
|
+
* .what = allocates amount into equal parts
|
|
33
|
+
* .why = splits evenly with remainder distribution
|
|
34
|
+
*/
|
|
35
|
+
const allocateEqualParts = (amount, currency, exponent, parts, remainderMode, format) => {
|
|
36
|
+
const divisor = BigInt(parts);
|
|
37
|
+
const baseAmount = amount / divisor;
|
|
38
|
+
const remainder = amount % divisor;
|
|
39
|
+
// create base allocations
|
|
40
|
+
const allocations = Array(parts).fill(baseAmount);
|
|
41
|
+
// distribute remainder
|
|
42
|
+
distributeRemainder(allocations, remainder, remainderMode, baseAmount);
|
|
43
|
+
return formatAllocations(allocations, currency, exponent, format);
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* .what = allocates amount by ratios
|
|
47
|
+
* .why = splits proportionally with remainder distribution
|
|
48
|
+
*/
|
|
49
|
+
const allocateByRatios = (amount, currency, exponent, ratios, remainderMode, format) => {
|
|
50
|
+
// validate ratios
|
|
51
|
+
if (ratios.some((r) => r < 0)) {
|
|
52
|
+
throw new helpful_errors_1.BadRequestError('ratios must be non-negative', { ratios });
|
|
53
|
+
}
|
|
54
|
+
const totalRatio = ratios.reduce((sum, r) => sum + r, 0);
|
|
55
|
+
if (totalRatio === 0) {
|
|
56
|
+
throw new helpful_errors_1.BadRequestError('total ratio cannot be zero', { ratios });
|
|
57
|
+
}
|
|
58
|
+
// calculate base allocations via largest remainder method
|
|
59
|
+
const totalRatioBigInt = BigInt(totalRatio);
|
|
60
|
+
const allocations = [];
|
|
61
|
+
let allocated = 0n;
|
|
62
|
+
for (let i = 0; i < ratios.length; i++) {
|
|
63
|
+
const ratio = BigInt(ratios[i]);
|
|
64
|
+
const allocation = (amount * ratio) / totalRatioBigInt;
|
|
65
|
+
allocations.push(allocation);
|
|
66
|
+
allocated += allocation;
|
|
67
|
+
}
|
|
68
|
+
// calculate remainder from truncation
|
|
69
|
+
const remainder = amount - allocated;
|
|
70
|
+
// distribute remainder
|
|
71
|
+
distributeRemainder(allocations, remainder, remainderMode, 0n, // for ratio mode, pass 0 as baseAmount (not used for largest)
|
|
72
|
+
ratios);
|
|
73
|
+
return formatAllocations(allocations, currency, exponent, format);
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* .what = distributes remainder per mode
|
|
77
|
+
* .why = ensures no cent is lost in allocation
|
|
78
|
+
*/
|
|
79
|
+
const distributeRemainder = (allocations, remainder, mode, baseAmount, ratios) => {
|
|
80
|
+
// handle negative remainder (can happen with negative amounts)
|
|
81
|
+
const isNegative = remainder < 0n;
|
|
82
|
+
const absRemainder = isNegative ? -remainder : remainder;
|
|
83
|
+
const increment = isNegative ? -1n : 1n;
|
|
84
|
+
// get indices for distribution
|
|
85
|
+
const indices = getDistributionIndices(allocations.length, Number(absRemainder), mode, allocations, ratios);
|
|
86
|
+
// apply remainder distribution
|
|
87
|
+
for (const idx of indices) {
|
|
88
|
+
allocations[idx] = allocations[idx] + increment;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* .what = determines which indices receive remainder cents
|
|
93
|
+
* .why = implements different distribution strategies
|
|
94
|
+
*/
|
|
95
|
+
const getDistributionIndices = (length, count, mode, allocations, ratios) => {
|
|
96
|
+
if (count === 0)
|
|
97
|
+
return [];
|
|
98
|
+
if (count >= length) {
|
|
99
|
+
// each gets at least one
|
|
100
|
+
const indices = Array.from({ length }, (_, i) => i);
|
|
101
|
+
// distribute extra to first positions
|
|
102
|
+
const extra = count - length;
|
|
103
|
+
for (let i = 0; i < extra; i++) {
|
|
104
|
+
indices.push(i % length);
|
|
105
|
+
}
|
|
106
|
+
return indices;
|
|
107
|
+
}
|
|
108
|
+
switch (mode) {
|
|
109
|
+
case 'first':
|
|
110
|
+
return Array.from({ length: count }, (_, i) => i);
|
|
111
|
+
case 'last':
|
|
112
|
+
return Array.from({ length: count }, (_, i) => length - 1 - i);
|
|
113
|
+
case 'largest': {
|
|
114
|
+
// hamilton/largest remainder method: give to those with largest fractional parts
|
|
115
|
+
// for equal parts, all have same fractional part, so fall back to first
|
|
116
|
+
// for ratios, calculate fractional remainders
|
|
117
|
+
if (!ratios) {
|
|
118
|
+
return Array.from({ length: count }, (_, i) => i);
|
|
119
|
+
}
|
|
120
|
+
// calculate fractional remainders for each ratio
|
|
121
|
+
const totalRatio = ratios.reduce((sum, r) => sum + r, 0);
|
|
122
|
+
const fractions = ratios.map((r, i) => ({
|
|
123
|
+
index: i,
|
|
124
|
+
fraction: (r / totalRatio) * Number(allocations.reduce((a, b) => a + b, 0n)) -
|
|
125
|
+
Number(allocations[i]),
|
|
126
|
+
}));
|
|
127
|
+
// sort by fraction (largest first)
|
|
128
|
+
fractions.sort((a, b) => b.fraction - a.fraction);
|
|
129
|
+
return fractions.slice(0, count).map((f) => f.index);
|
|
130
|
+
}
|
|
131
|
+
case 'random': {
|
|
132
|
+
// pseudo-random but deterministic based on allocation values
|
|
133
|
+
const indices = Array.from({ length }, (_, i) => i);
|
|
134
|
+
// use a simple deterministic shuffle based on allocation sum
|
|
135
|
+
const seed = Number(allocations.reduce((a, b) => a + b, 0n) % 1000000n);
|
|
136
|
+
indices.sort((a, b) => {
|
|
137
|
+
const hashA = (a * 31 + seed) % 1000;
|
|
138
|
+
const hashB = (b * 31 + seed) % 1000;
|
|
139
|
+
return hashA - hashB;
|
|
140
|
+
});
|
|
141
|
+
return indices.slice(0, count);
|
|
142
|
+
}
|
|
143
|
+
default:
|
|
144
|
+
return Array.from({ length: count }, (_, i) => i);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* .what = converts bigint allocations to output format
|
|
149
|
+
* .why = enables both words and shape output
|
|
150
|
+
*/
|
|
151
|
+
const formatAllocations = (allocations, currency, exponent, format) => {
|
|
152
|
+
const shapes = allocations.map((amount) => ({
|
|
153
|
+
amount,
|
|
154
|
+
currency,
|
|
155
|
+
exponent: exponent,
|
|
156
|
+
}));
|
|
157
|
+
if (format === 'shape') {
|
|
158
|
+
return shapes;
|
|
159
|
+
}
|
|
160
|
+
return shapes.map((s) => (0, asIsoPriceWords_1.asIsoPriceWords)(s));
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* .what = alias for allocatePrice
|
|
164
|
+
* .why = provides price-prefixed variant
|
|
165
|
+
*/
|
|
166
|
+
exports.priceAllocate = allocatePrice;
|
|
167
|
+
//# sourceMappingURL=allocatePrice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allocatePrice.js","sourceRoot":"","sources":["../../../src/domain.operations/arithmetic/allocatePrice.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { IsoPrice } from '../../domain.objects/IsoPrice';
|
|
2
|
+
import { IsoPriceRoundMode } from '../../domain.objects/IsoPriceRoundMode';
|
|
3
|
+
import type { IsoPriceShape } from '../../domain.objects/IsoPriceShape';
|
|
4
|
+
import type { IsoPriceWords } from '../../domain.objects/IsoPriceWords';
|
|
5
|
+
/**
|
|
6
|
+
* .what = divides a price by a scalar
|
|
7
|
+
* .why = enables per-unit calculations and cost breakdowns
|
|
8
|
+
*
|
|
9
|
+
* auto-scales precision when divisors are large.
|
|
10
|
+
* for small divisors, maintains input precision with round.
|
|
11
|
+
*
|
|
12
|
+
* @throws BadRequestError if divisor is zero
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* dividePrice({ of: 'USD 10.00', by: 4 })
|
|
16
|
+
* // => 'USD 2.50'
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* dividePrice({ of: '$0.25', by: 1_000_000 })
|
|
20
|
+
* // => 'USD 0.000_000_250' (nano precision)
|
|
21
|
+
*/
|
|
22
|
+
export declare function dividePrice<TCurrency extends string = string>(input: {
|
|
23
|
+
of: IsoPrice<TCurrency> | string;
|
|
24
|
+
by: number;
|
|
25
|
+
}, options?: {
|
|
26
|
+
format?: 'words';
|
|
27
|
+
round?: IsoPriceRoundMode;
|
|
28
|
+
}): IsoPriceWords<TCurrency>;
|
|
29
|
+
export declare function dividePrice<TCurrency extends string = string>(input: {
|
|
30
|
+
of: IsoPrice<TCurrency> | string;
|
|
31
|
+
by: number;
|
|
32
|
+
}, options: {
|
|
33
|
+
format: 'shape';
|
|
34
|
+
round?: IsoPriceRoundMode;
|
|
35
|
+
}): IsoPriceShape<TCurrency>;
|
|
36
|
+
/**
|
|
37
|
+
* .what = alias for dividePrice
|
|
38
|
+
* .why = provides price-prefixed variant
|
|
39
|
+
*/
|
|
40
|
+
export declare const priceDivide: typeof dividePrice;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.priceDivide = exports.dividePrice = void 0;
|
|
4
|
+
const helpful_errors_1 = require("helpful-errors");
|
|
5
|
+
const IsoPriceExponent_1 = require("../../domain.objects/IsoPriceExponent");
|
|
6
|
+
const IsoPriceRoundMode_1 = require("../../domain.objects/IsoPriceRoundMode");
|
|
7
|
+
const asIsoPriceShape_1 = require("../cast/asIsoPriceShape");
|
|
8
|
+
const asIsoPriceWords_1 = require("../cast/asIsoPriceWords");
|
|
9
|
+
/**
|
|
10
|
+
* .what = gets the numeric exponent value from exponent string
|
|
11
|
+
* .why = needed for precision calculation
|
|
12
|
+
*/
|
|
13
|
+
const getExponentValue = (exponent) => {
|
|
14
|
+
const match = exponent.match(/\^(-?\d+)$/);
|
|
15
|
+
if (!match)
|
|
16
|
+
return -2; // default to centi
|
|
17
|
+
return parseInt(match[1], 10);
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* .what = determines required precision based on divisor
|
|
21
|
+
* .why = ensures result has meaningful precision for large divisors
|
|
22
|
+
*/
|
|
23
|
+
const getRequiredExponent = (inputExponent, divisor) => {
|
|
24
|
+
const absDivisor = Math.abs(divisor);
|
|
25
|
+
// for small divisors (< 100), maintain input precision with round
|
|
26
|
+
if (absDivisor < 100)
|
|
27
|
+
return inputExponent;
|
|
28
|
+
// for medium divisors (100 - 999,999), use milli precision
|
|
29
|
+
if (absDivisor < 1000000)
|
|
30
|
+
return IsoPriceExponent_1.IsoPriceExponent.MILLI;
|
|
31
|
+
// for large divisors (1M - 999M), use nano precision
|
|
32
|
+
if (absDivisor < 1000000000)
|
|
33
|
+
return IsoPriceExponent_1.IsoPriceExponent.NANO;
|
|
34
|
+
// for huge divisors, use pico precision
|
|
35
|
+
return IsoPriceExponent_1.IsoPriceExponent.PICO;
|
|
36
|
+
};
|
|
37
|
+
function dividePrice(input, options) {
|
|
38
|
+
if (input.by === 0) {
|
|
39
|
+
throw new helpful_errors_1.BadRequestError('cannot divide by zero', { input });
|
|
40
|
+
}
|
|
41
|
+
const shape = (0, asIsoPriceShape_1.asIsoPriceShape)(input.of);
|
|
42
|
+
const inputExponent = shape.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI;
|
|
43
|
+
const roundMode = options?.round ?? IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_UP;
|
|
44
|
+
// determine output precision based on divisor
|
|
45
|
+
const outputExponent = getRequiredExponent(inputExponent, input.by);
|
|
46
|
+
const outputExpValue = getExponentValue(outputExponent);
|
|
47
|
+
const inputExpValue = getExponentValue(inputExponent);
|
|
48
|
+
// scale amount to output precision
|
|
49
|
+
const scaleDiff = inputExpValue - outputExpValue;
|
|
50
|
+
const scaledAmount = shape.amount * 10n ** BigInt(scaleDiff);
|
|
51
|
+
// perform division with round
|
|
52
|
+
const divisor = BigInt(Math.round(Math.abs(input.by)));
|
|
53
|
+
const sign = input.by < 0 ? -1n : 1n;
|
|
54
|
+
let quotient;
|
|
55
|
+
const remainder = scaledAmount % divisor;
|
|
56
|
+
// apply round mode
|
|
57
|
+
if (remainder === 0n) {
|
|
58
|
+
quotient = scaledAmount / divisor;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const baseQuotient = scaledAmount / divisor;
|
|
62
|
+
const isNegative = scaledAmount < 0n;
|
|
63
|
+
const absRemainder = remainder < 0n ? -remainder : remainder;
|
|
64
|
+
// use doubled remainder for accurate half comparison (avoids truncation from divisor/2)
|
|
65
|
+
const doubledRemainder = absRemainder * 2n;
|
|
66
|
+
const isExactlyHalf = doubledRemainder === divisor;
|
|
67
|
+
const isMoreThanHalf = doubledRemainder > divisor;
|
|
68
|
+
switch (roundMode) {
|
|
69
|
+
case IsoPriceRoundMode_1.IsoPriceRoundMode.FLOOR:
|
|
70
|
+
quotient = isNegative ? baseQuotient - 1n : baseQuotient;
|
|
71
|
+
break;
|
|
72
|
+
case IsoPriceRoundMode_1.IsoPriceRoundMode.CEIL:
|
|
73
|
+
quotient = isNegative ? baseQuotient : baseQuotient + 1n;
|
|
74
|
+
break;
|
|
75
|
+
case IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_UP:
|
|
76
|
+
quotient =
|
|
77
|
+
isExactlyHalf || isMoreThanHalf
|
|
78
|
+
? isNegative
|
|
79
|
+
? baseQuotient - 1n
|
|
80
|
+
: baseQuotient + 1n
|
|
81
|
+
: baseQuotient;
|
|
82
|
+
break;
|
|
83
|
+
case IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_DOWN:
|
|
84
|
+
quotient = isMoreThanHalf
|
|
85
|
+
? isNegative
|
|
86
|
+
? baseQuotient - 1n
|
|
87
|
+
: baseQuotient + 1n
|
|
88
|
+
: baseQuotient;
|
|
89
|
+
break;
|
|
90
|
+
case IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_EVEN: {
|
|
91
|
+
const isEven = baseQuotient % 2n === 0n;
|
|
92
|
+
if (isExactlyHalf) {
|
|
93
|
+
quotient = isEven ? baseQuotient : baseQuotient + 1n;
|
|
94
|
+
}
|
|
95
|
+
else if (isMoreThanHalf) {
|
|
96
|
+
quotient = isNegative ? baseQuotient - 1n : baseQuotient + 1n;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
quotient = baseQuotient;
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
default:
|
|
104
|
+
quotient = baseQuotient;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// apply divisor sign
|
|
108
|
+
quotient = quotient * sign;
|
|
109
|
+
// build result shape
|
|
110
|
+
const resultShape = {
|
|
111
|
+
amount: quotient,
|
|
112
|
+
currency: shape.currency,
|
|
113
|
+
exponent: outputExponent,
|
|
114
|
+
};
|
|
115
|
+
// return in requested format
|
|
116
|
+
if (options?.format === 'shape') {
|
|
117
|
+
return resultShape;
|
|
118
|
+
}
|
|
119
|
+
return (0, asIsoPriceWords_1.asIsoPriceWords)(resultShape);
|
|
120
|
+
}
|
|
121
|
+
exports.dividePrice = dividePrice;
|
|
122
|
+
/**
|
|
123
|
+
* .what = alias for dividePrice
|
|
124
|
+
* .why = provides price-prefixed variant
|
|
125
|
+
*/
|
|
126
|
+
exports.priceDivide = dividePrice;
|
|
127
|
+
//# sourceMappingURL=dividePrice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dividePrice.js","sourceRoot":"","sources":["../../../src/domain.operations/arithmetic/dividePrice.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { IsoPrice } from '../../domain.objects/IsoPrice';
|
|
2
|
+
import { IsoPriceRoundMode } from '../../domain.objects/IsoPriceRoundMode';
|
|
3
|
+
import type { IsoPriceShape } from '../../domain.objects/IsoPriceShape';
|
|
4
|
+
import type { IsoPriceWords } from '../../domain.objects/IsoPriceWords';
|
|
5
|
+
/**
|
|
6
|
+
* .what = multiplies a price by a scalar
|
|
7
|
+
* .why = enables quantity calculations and percentage markups
|
|
8
|
+
*
|
|
9
|
+
* maintains input precision by default. uses higher internal precision
|
|
10
|
+
* to avoid intermediate loss, then rounds back to input precision.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* multiplyPrice({ of: 'USD 10.00', by: 3 })
|
|
14
|
+
* // => 'USD 30.00'
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* multiplyPrice({ of: 'USD 100.00', by: 1.08 })
|
|
18
|
+
* // => 'USD 108.00' (tax markup)
|
|
19
|
+
*/
|
|
20
|
+
export declare function multiplyPrice<TCurrency extends string = string>(input: {
|
|
21
|
+
of: IsoPrice<TCurrency> | string;
|
|
22
|
+
by: number;
|
|
23
|
+
}, options?: {
|
|
24
|
+
format?: 'words';
|
|
25
|
+
round?: IsoPriceRoundMode;
|
|
26
|
+
}): IsoPriceWords<TCurrency>;
|
|
27
|
+
export declare function multiplyPrice<TCurrency extends string = string>(input: {
|
|
28
|
+
of: IsoPrice<TCurrency> | string;
|
|
29
|
+
by: number;
|
|
30
|
+
}, options: {
|
|
31
|
+
format: 'shape';
|
|
32
|
+
round?: IsoPriceRoundMode;
|
|
33
|
+
}): IsoPriceShape<TCurrency>;
|
|
34
|
+
/**
|
|
35
|
+
* .what = alias for multiplyPrice
|
|
36
|
+
* .why = provides price-prefixed variant
|
|
37
|
+
*/
|
|
38
|
+
export declare const priceMultiply: typeof multiplyPrice;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.priceMultiply = exports.multiplyPrice = void 0;
|
|
4
|
+
const IsoPriceExponent_1 = require("../../domain.objects/IsoPriceExponent");
|
|
5
|
+
const IsoPriceRoundMode_1 = require("../../domain.objects/IsoPriceRoundMode");
|
|
6
|
+
const asIsoPriceShape_1 = require("../cast/asIsoPriceShape");
|
|
7
|
+
const asIsoPriceWords_1 = require("../cast/asIsoPriceWords");
|
|
8
|
+
/**
|
|
9
|
+
* .what = gets the numeric exponent value from exponent string
|
|
10
|
+
* .why = needed for precision scale
|
|
11
|
+
*/
|
|
12
|
+
const getExponentValue = (exponent) => {
|
|
13
|
+
const match = exponent.match(/\^(-?\d+)$/);
|
|
14
|
+
if (!match)
|
|
15
|
+
return -2; // default to centi
|
|
16
|
+
return parseInt(match[1], 10);
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* .what = applies round mode to a bigint
|
|
20
|
+
* .why = needed to round back to input precision
|
|
21
|
+
*/
|
|
22
|
+
const applyRound = (amount, divisor, mode) => {
|
|
23
|
+
const quotient = amount / divisor;
|
|
24
|
+
const remainder = amount % divisor;
|
|
25
|
+
if (remainder === 0n)
|
|
26
|
+
return quotient;
|
|
27
|
+
const isNegative = amount < 0n;
|
|
28
|
+
const absRemainder = remainder < 0n ? -remainder : remainder;
|
|
29
|
+
const halfDivisor = divisor / 2n;
|
|
30
|
+
switch (mode) {
|
|
31
|
+
case IsoPriceRoundMode_1.IsoPriceRoundMode.FLOOR:
|
|
32
|
+
return isNegative ? quotient - 1n : quotient;
|
|
33
|
+
case IsoPriceRoundMode_1.IsoPriceRoundMode.CEIL:
|
|
34
|
+
return isNegative ? quotient : quotient + 1n;
|
|
35
|
+
case IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_UP:
|
|
36
|
+
return absRemainder >= halfDivisor
|
|
37
|
+
? isNegative
|
|
38
|
+
? quotient - 1n
|
|
39
|
+
: quotient + 1n
|
|
40
|
+
: quotient;
|
|
41
|
+
case IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_DOWN:
|
|
42
|
+
return absRemainder > halfDivisor
|
|
43
|
+
? isNegative
|
|
44
|
+
? quotient - 1n
|
|
45
|
+
: quotient + 1n
|
|
46
|
+
: quotient;
|
|
47
|
+
case IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_EVEN: {
|
|
48
|
+
const isEven = quotient % 2n === 0n;
|
|
49
|
+
if (absRemainder === halfDivisor) {
|
|
50
|
+
return isEven ? quotient : quotient + 1n;
|
|
51
|
+
}
|
|
52
|
+
return absRemainder > halfDivisor
|
|
53
|
+
? isNegative
|
|
54
|
+
? quotient - 1n
|
|
55
|
+
: quotient + 1n
|
|
56
|
+
: quotient;
|
|
57
|
+
}
|
|
58
|
+
default:
|
|
59
|
+
return quotient;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function multiplyPrice(input, options) {
|
|
63
|
+
const shape = (0, asIsoPriceShape_1.asIsoPriceShape)(input.of);
|
|
64
|
+
const inputExponent = shape.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI;
|
|
65
|
+
const roundMode = options?.round ?? IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_UP;
|
|
66
|
+
// scale multiplier to avoid float precision issues (use 12 decimal places)
|
|
67
|
+
const scaleFactor = BigInt(Math.round(input.by * 1e12));
|
|
68
|
+
const multiplied = shape.amount * scaleFactor;
|
|
69
|
+
// round back to original precision
|
|
70
|
+
const rounded = applyRound(multiplied, BigInt(1e12), roundMode);
|
|
71
|
+
// build result shape
|
|
72
|
+
const resultShape = {
|
|
73
|
+
amount: rounded,
|
|
74
|
+
currency: shape.currency,
|
|
75
|
+
exponent: inputExponent,
|
|
76
|
+
};
|
|
77
|
+
// return in requested format
|
|
78
|
+
if (options?.format === 'shape') {
|
|
79
|
+
return resultShape;
|
|
80
|
+
}
|
|
81
|
+
return (0, asIsoPriceWords_1.asIsoPriceWords)(resultShape);
|
|
82
|
+
}
|
|
83
|
+
exports.multiplyPrice = multiplyPrice;
|
|
84
|
+
/**
|
|
85
|
+
* .what = alias for multiplyPrice
|
|
86
|
+
* .why = provides price-prefixed variant
|
|
87
|
+
*/
|
|
88
|
+
exports.priceMultiply = multiplyPrice;
|
|
89
|
+
//# sourceMappingURL=multiplyPrice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multiplyPrice.js","sourceRoot":"","sources":["../../../src/domain.operations/arithmetic/multiplyPrice.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { IsoPrice } from '../../domain.objects/IsoPrice';
|
|
2
|
+
import type { IsoPriceShape } from '../../domain.objects/IsoPriceShape';
|
|
3
|
+
import type { IsoPriceWords } from '../../domain.objects/IsoPriceWords';
|
|
4
|
+
/**
|
|
5
|
+
* .what = subtracts second price from first
|
|
6
|
+
* .why = enables price difference computation
|
|
7
|
+
*
|
|
8
|
+
* @throws BadRequestError if currencies do not match
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* subPrices('USD 50.00', 'USD 20.00')
|
|
12
|
+
* // => 'USD 30.00'
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* subPrices('USD 10.00', 'USD 50.00')
|
|
16
|
+
* // => 'USD -40.00' (negative allowed)
|
|
17
|
+
*/
|
|
18
|
+
export declare function subPrices<TCurrency extends string = string>(minuend: IsoPrice<TCurrency> | string, subtrahend: IsoPrice<TCurrency> | string, options?: {
|
|
19
|
+
format?: 'words';
|
|
20
|
+
}): IsoPriceWords<TCurrency>;
|
|
21
|
+
export declare function subPrices<TCurrency extends string = string>(minuend: IsoPrice<TCurrency> | string, subtrahend: IsoPrice<TCurrency> | string, options: {
|
|
22
|
+
format: 'shape';
|
|
23
|
+
}): IsoPriceShape<TCurrency>;
|
|
24
|
+
/**
|
|
25
|
+
* .what = alias for subPrices
|
|
26
|
+
* .why = provides price-prefixed variant
|
|
27
|
+
*/
|
|
28
|
+
export declare const priceSub: typeof subPrices;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.priceSub = exports.subPrices = void 0;
|
|
4
|
+
const helpful_errors_1 = require("helpful-errors");
|
|
5
|
+
const IsoPriceExponent_1 = require("../../domain.objects/IsoPriceExponent");
|
|
6
|
+
const asIsoPriceShape_1 = require("../cast/asIsoPriceShape");
|
|
7
|
+
const asIsoPriceWords_1 = require("../cast/asIsoPriceWords");
|
|
8
|
+
/**
|
|
9
|
+
* .what = gets the numeric exponent value from exponent string
|
|
10
|
+
* .why = needed for precision comparison and normalization
|
|
11
|
+
*/
|
|
12
|
+
const getExponentValue = (exponent) => {
|
|
13
|
+
const match = exponent.match(/\^(-?\d+)$/);
|
|
14
|
+
if (!match)
|
|
15
|
+
return -2; // default to centi
|
|
16
|
+
return parseInt(match[1], 10);
|
|
17
|
+
};
|
|
18
|
+
function subPrices(minuend, subtrahend, options) {
|
|
19
|
+
// convert to shapes
|
|
20
|
+
const minuendShape = (0, asIsoPriceShape_1.asIsoPriceShape)(minuend);
|
|
21
|
+
const subtrahendShape = (0, asIsoPriceShape_1.asIsoPriceShape)(subtrahend);
|
|
22
|
+
// verify currencies match
|
|
23
|
+
if (minuendShape.currency !== subtrahendShape.currency) {
|
|
24
|
+
throw new helpful_errors_1.BadRequestError('currency mismatch in price subtraction', {
|
|
25
|
+
minuend: minuendShape.currency,
|
|
26
|
+
subtrahend: subtrahendShape.currency,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const currency = minuendShape.currency;
|
|
30
|
+
// find the highest precision (lowest exponent value)
|
|
31
|
+
const minuendExp = getExponentValue(minuendShape.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI);
|
|
32
|
+
const subtrahendExp = getExponentValue(subtrahendShape.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI);
|
|
33
|
+
const targetExponentValue = Math.min(minuendExp, subtrahendExp);
|
|
34
|
+
const targetExponent = minuendExp <= subtrahendExp
|
|
35
|
+
? (minuendShape.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI)
|
|
36
|
+
: (subtrahendShape.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI);
|
|
37
|
+
// normalize amounts to target precision
|
|
38
|
+
const minuendShift = minuendExp - targetExponentValue;
|
|
39
|
+
const subtrahendShift = subtrahendExp - targetExponentValue;
|
|
40
|
+
const normalizedMinuend = minuendShape.amount * 10n ** BigInt(minuendShift);
|
|
41
|
+
const normalizedSubtrahend = subtrahendShape.amount * 10n ** BigInt(subtrahendShift);
|
|
42
|
+
// compute difference
|
|
43
|
+
const difference = normalizedMinuend - normalizedSubtrahend;
|
|
44
|
+
// build result shape
|
|
45
|
+
const resultShape = {
|
|
46
|
+
amount: difference,
|
|
47
|
+
currency,
|
|
48
|
+
exponent: targetExponent,
|
|
49
|
+
};
|
|
50
|
+
// return in requested format
|
|
51
|
+
if (options?.format === 'shape') {
|
|
52
|
+
return resultShape;
|
|
53
|
+
}
|
|
54
|
+
return (0, asIsoPriceWords_1.asIsoPriceWords)(resultShape);
|
|
55
|
+
}
|
|
56
|
+
exports.subPrices = subPrices;
|
|
57
|
+
/**
|
|
58
|
+
* .what = alias for subPrices
|
|
59
|
+
* .why = provides price-prefixed variant
|
|
60
|
+
*/
|
|
61
|
+
exports.priceSub = subPrices;
|
|
62
|
+
//# sourceMappingURL=subPrices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subPrices.js","sourceRoot":"","sources":["../../../src/domain.operations/arithmetic/subPrices.ts"],"names":[],"mappings":";;;AAAA,mDAAiD;AAGjD,4EAAyE;AAGzE,6DAA0D;AAC1D,6DAA0D;AAE1D;;;GAGG;AACH,MAAM,gBAAgB,GAAG,CAAC,QAAmC,EAAU,EAAE;IACvE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3C,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC,mBAAmB;IAC1C,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC,CAAC;AA0BF,SAAgB,SAAS,CACvB,OAAqC,EACrC,UAAwC,EACxC,OAAwC;IAExC,oBAAoB;IACpB,MAAM,YAAY,GAAG,IAAA,iCAAe,EAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,eAAe,GAAG,IAAA,iCAAe,EAAC,UAAU,CAAC,CAAC;IAEpD,0BAA0B;IAC1B,IAAI,YAAY,CAAC,QAAQ,KAAK,eAAe,CAAC,QAAQ,EAAE,CAAC;QACvD,MAAM,IAAI,gCAAe,CAAC,wCAAwC,EAAE;YAClE,OAAO,EAAE,YAAY,CAAC,QAAQ;YAC9B,UAAU,EAAE,eAAe,CAAC,QAAQ;SACrC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAqB,CAAC;IAEpD,qDAAqD;IACrD,MAAM,UAAU,GAAG,gBAAgB,CACjC,YAAY,CAAC,QAAQ,IAAI,mCAAgB,CAAC,KAAK,CAChD,CAAC;IACF,MAAM,aAAa,GAAG,gBAAgB,CACpC,eAAe,CAAC,QAAQ,IAAI,mCAAgB,CAAC,KAAK,CACnD,CAAC;IACF,MAAM,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAChE,MAAM,cAAc,GAClB,UAAU,IAAI,aAAa;QACzB,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,IAAI,mCAAgB,CAAC,KAAK,CAAC;QACnD,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,IAAI,mCAAgB,CAAC,KAAK,CAAC,CAAC;IAE3D,wCAAwC;IACxC,MAAM,YAAY,GAAG,UAAU,GAAG,mBAAmB,CAAC;IACtD,MAAM,eAAe,GAAG,aAAa,GAAG,mBAAmB,CAAC;IAC5D,MAAM,iBAAiB,GAAG,YAAY,CAAC,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC;IAC5E,MAAM,oBAAoB,GACxB,eAAe,CAAC,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,eAAe,CAAC,CAAC;IAE1D,qBAAqB;IACrB,MAAM,UAAU,GAAG,iBAAiB,GAAG,oBAAoB,CAAC;IAE5D,qBAAqB;IACrB,MAAM,WAAW,GAA6B;QAC5C,MAAM,EAAE,UAAU;QAClB,QAAQ;QACR,QAAQ,EAAE,cAAkC;KAC7C,CAAC;IAEF,6BAA6B;IAC7B,IAAI,OAAO,EAAE,MAAM,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,OAAO,IAAA,iCAAe,EAAC,WAAW,CAAC,CAAC;AACtC,CAAC;AAtDD,8BAsDC;AAED;;;GAGG;AACU,QAAA,QAAQ,GAAG,SAAS,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { IsoPrice } from '../../domain.objects/IsoPrice';
|
|
2
|
+
import type { IsoPriceShape } from '../../domain.objects/IsoPriceShape';
|
|
3
|
+
import type { IsoPriceWords } from '../../domain.objects/IsoPriceWords';
|
|
4
|
+
/**
|
|
5
|
+
* .what = sums multiple prices
|
|
6
|
+
* .why = enables price aggregation with mixed precision support
|
|
7
|
+
*
|
|
8
|
+
* supports two call signatures:
|
|
9
|
+
* - spread: `sumPrices('USD 10.00', 'USD 20.00')`
|
|
10
|
+
* - array: `sumPrices(['USD 10.00', 'USD 20.00'])`
|
|
11
|
+
* - with options: `sumPrices(['USD 10.00'], { format: 'shape' })`
|
|
12
|
+
*
|
|
13
|
+
* @throws BadRequestError if currencies do not match
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* sumPrices('USD 10.00', 'USD 20.00')
|
|
17
|
+
* // => 'USD 30.00'
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* sumPrices(['USD 10.00', 'USD 20.00'], { format: 'shape' })
|
|
21
|
+
* // => { amount: 3000n, currency: 'USD' }
|
|
22
|
+
*/
|
|
23
|
+
export declare function sumPrices<TCurrency extends string = string>(...args: (IsoPrice<TCurrency> | string)[]): IsoPriceWords<TCurrency>;
|
|
24
|
+
export declare function sumPrices<TCurrency extends string = string>(prices: (IsoPrice<TCurrency> | string)[], options?: {
|
|
25
|
+
format?: 'words';
|
|
26
|
+
}): IsoPriceWords<TCurrency>;
|
|
27
|
+
export declare function sumPrices<TCurrency extends string = string>(prices: (IsoPrice<TCurrency> | string)[], options: {
|
|
28
|
+
format: 'shape';
|
|
29
|
+
}): IsoPriceShape<TCurrency>;
|
|
30
|
+
/**
|
|
31
|
+
* .what = alias for sumPrices
|
|
32
|
+
* .why = provides semantic name for binary addition
|
|
33
|
+
*/
|
|
34
|
+
export declare const addPrices: typeof sumPrices;
|
|
35
|
+
/**
|
|
36
|
+
* .what = alias for sumPrices
|
|
37
|
+
* .why = provides price-prefixed variant
|
|
38
|
+
*/
|
|
39
|
+
export declare const priceSum: typeof sumPrices;
|
|
40
|
+
/**
|
|
41
|
+
* .what = alias for sumPrices
|
|
42
|
+
* .why = provides price-prefixed variant
|
|
43
|
+
*/
|
|
44
|
+
export declare const priceAdd: typeof sumPrices;
|