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.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/dist/contract/index.d.ts +25 -0
  3. package/dist/contract/index.js +60 -0
  4. package/dist/contract/index.js.map +1 -0
  5. package/dist/domain.objects/IsoCurrency.d.ts +63 -0
  6. package/dist/domain.objects/IsoCurrency.js +70 -0
  7. package/dist/domain.objects/IsoCurrency.js.map +1 -0
  8. package/dist/domain.objects/IsoPrice.d.ts +16 -0
  9. package/dist/domain.objects/IsoPrice.js +3 -0
  10. package/dist/domain.objects/IsoPrice.js.map +1 -0
  11. package/dist/domain.objects/IsoPriceExponent.d.ts +28 -0
  12. package/dist/domain.objects/IsoPriceExponent.js +33 -0
  13. package/dist/domain.objects/IsoPriceExponent.js.map +1 -0
  14. package/dist/domain.objects/IsoPriceHuman.d.ts +19 -0
  15. package/dist/domain.objects/IsoPriceHuman.js +3 -0
  16. package/dist/domain.objects/IsoPriceHuman.js.map +1 -0
  17. package/dist/domain.objects/IsoPriceRoundMode.d.ts +23 -0
  18. package/dist/domain.objects/IsoPriceRoundMode.js +28 -0
  19. package/dist/domain.objects/IsoPriceRoundMode.js.map +1 -0
  20. package/dist/domain.objects/IsoPriceShape.d.ts +30 -0
  21. package/dist/domain.objects/IsoPriceShape.js +3 -0
  22. package/dist/domain.objects/IsoPriceShape.js.map +1 -0
  23. package/dist/domain.objects/IsoPriceWords.d.ts +20 -0
  24. package/dist/domain.objects/IsoPriceWords.js +3 -0
  25. package/dist/domain.objects/IsoPriceWords.js.map +1 -0
  26. package/dist/domain.operations/arithmetic/allocatePrice.d.ts +48 -0
  27. package/dist/domain.operations/arithmetic/allocatePrice.js +167 -0
  28. package/dist/domain.operations/arithmetic/allocatePrice.js.map +1 -0
  29. package/dist/domain.operations/arithmetic/dividePrice.d.ts +40 -0
  30. package/dist/domain.operations/arithmetic/dividePrice.js +127 -0
  31. package/dist/domain.operations/arithmetic/dividePrice.js.map +1 -0
  32. package/dist/domain.operations/arithmetic/multiplyPrice.d.ts +38 -0
  33. package/dist/domain.operations/arithmetic/multiplyPrice.js +89 -0
  34. package/dist/domain.operations/arithmetic/multiplyPrice.js.map +1 -0
  35. package/dist/domain.operations/arithmetic/subPrices.d.ts +28 -0
  36. package/dist/domain.operations/arithmetic/subPrices.js +62 -0
  37. package/dist/domain.operations/arithmetic/subPrices.js.map +1 -0
  38. package/dist/domain.operations/arithmetic/sumPrices.d.ts +44 -0
  39. package/dist/domain.operations/arithmetic/sumPrices.js +88 -0
  40. package/dist/domain.operations/arithmetic/sumPrices.js.map +1 -0
  41. package/dist/domain.operations/cast/asIsoPrice.d.ts +35 -0
  42. package/dist/domain.operations/cast/asIsoPrice.js +117 -0
  43. package/dist/domain.operations/cast/asIsoPrice.js.map +1 -0
  44. package/dist/domain.operations/cast/asIsoPriceHuman.d.ts +25 -0
  45. package/dist/domain.operations/cast/asIsoPriceHuman.js +106 -0
  46. package/dist/domain.operations/cast/asIsoPriceHuman.js.map +1 -0
  47. package/dist/domain.operations/cast/asIsoPriceShape.d.ts +25 -0
  48. package/dist/domain.operations/cast/asIsoPriceShape.js +164 -0
  49. package/dist/domain.operations/cast/asIsoPriceShape.js.map +1 -0
  50. package/dist/domain.operations/cast/asIsoPriceWords.d.ts +25 -0
  51. package/dist/domain.operations/cast/asIsoPriceWords.js +103 -0
  52. package/dist/domain.operations/cast/asIsoPriceWords.js.map +1 -0
  53. package/dist/domain.operations/guard/isIsoPrice.d.ts +18 -0
  54. package/dist/domain.operations/guard/isIsoPrice.js +29 -0
  55. package/dist/domain.operations/guard/isIsoPrice.js.map +1 -0
  56. package/dist/domain.operations/guard/isIsoPriceHuman.d.ts +24 -0
  57. package/dist/domain.operations/guard/isIsoPriceHuman.js +76 -0
  58. package/dist/domain.operations/guard/isIsoPriceHuman.js.map +1 -0
  59. package/dist/domain.operations/guard/isIsoPriceShape.d.ts +29 -0
  60. package/dist/domain.operations/guard/isIsoPriceShape.js +50 -0
  61. package/dist/domain.operations/guard/isIsoPriceShape.js.map +1 -0
  62. package/dist/domain.operations/guard/isIsoPriceWords.d.ts +24 -0
  63. package/dist/domain.operations/guard/isIsoPriceWords.js +48 -0
  64. package/dist/domain.operations/guard/isIsoPriceWords.js.map +1 -0
  65. package/dist/domain.operations/precision/getIsoPriceExponentByCurrency.d.ts +15 -0
  66. package/dist/domain.operations/precision/getIsoPriceExponentByCurrency.js +49 -0
  67. package/dist/domain.operations/precision/getIsoPriceExponentByCurrency.js.map +1 -0
  68. package/dist/domain.operations/precision/roundPrice.d.ts +25 -0
  69. package/dist/domain.operations/precision/roundPrice.js +24 -0
  70. package/dist/domain.operations/precision/roundPrice.js.map +1 -0
  71. package/dist/domain.operations/precision/setPricePrecision.d.ts +29 -0
  72. package/dist/domain.operations/precision/setPricePrecision.js +119 -0
  73. package/dist/domain.operations/precision/setPricePrecision.js.map +1 -0
  74. package/dist/domain.operations/statistics/calcPriceAvg.d.ts +21 -0
  75. package/dist/domain.operations/statistics/calcPriceAvg.js +92 -0
  76. package/dist/domain.operations/statistics/calcPriceAvg.js.map +1 -0
  77. package/dist/domain.operations/statistics/calcPriceStdev.d.ts +23 -0
  78. package/dist/domain.operations/statistics/calcPriceStdev.js +137 -0
  79. package/dist/domain.operations/statistics/calcPriceStdev.js.map +1 -0
  80. package/dist/index.d.ts +1 -0
  81. package/dist/index.js +18 -0
  82. package/dist/index.js.map +1 -0
  83. package/license.md +21 -0
  84. package/package.json +102 -0
  85. package/readme.md +373 -0
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setPricePrecision = 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 = extracts numeric exponent from exponent string
10
+ * .why = enables arithmetic on exponent values
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 value
20
+ * .why = enables precision decrease with correct round behavior
21
+ */
22
+ const applyRoundMode = (value, divisor, mode) => {
23
+ const quotient = value / divisor;
24
+ const remainder = value % divisor;
25
+ // no remainder = no need to round
26
+ if (remainder === 0n)
27
+ return quotient;
28
+ const isNegative = value < 0n;
29
+ const absRemainder = isNegative ? -remainder : remainder;
30
+ const halfDivisor = divisor / 2n;
31
+ switch (mode) {
32
+ case IsoPriceRoundMode_1.IsoPriceRoundMode.FLOOR:
33
+ // always toward negative infinity
34
+ return isNegative ? quotient - 1n : quotient;
35
+ case IsoPriceRoundMode_1.IsoPriceRoundMode.CEIL:
36
+ // always toward positive infinity
37
+ return isNegative ? quotient : quotient + 1n;
38
+ case IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_UP:
39
+ // round half toward positive infinity
40
+ if (absRemainder >= halfDivisor) {
41
+ return isNegative ? quotient - 1n : quotient + 1n;
42
+ }
43
+ return quotient;
44
+ case IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_DOWN:
45
+ // round half toward zero
46
+ if (absRemainder > halfDivisor) {
47
+ return isNegative ? quotient - 1n : quotient + 1n;
48
+ }
49
+ return quotient;
50
+ case IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_EVEN:
51
+ // round half to nearest even (bankers round)
52
+ if (absRemainder > halfDivisor) {
53
+ return isNegative ? quotient - 1n : quotient + 1n;
54
+ }
55
+ if (absRemainder === halfDivisor) {
56
+ // round to even
57
+ const absQuotient = isNegative ? -quotient : quotient;
58
+ if (absQuotient % 2n !== 0n) {
59
+ return isNegative ? quotient - 1n : quotient + 1n;
60
+ }
61
+ }
62
+ return quotient;
63
+ default:
64
+ return quotient;
65
+ }
66
+ };
67
+ /**
68
+ * .what = changes the precision of a price to a target exponent
69
+ * .why = enables precision increase (lossless) and decrease (with round)
70
+ *
71
+ * @example
72
+ * // increase precision (lossless)
73
+ * setPricePrecision({ of: 'USD 50.37', to: 'micro.x10^-6' })
74
+ * // => 'USD 50.370000'
75
+ *
76
+ * @example
77
+ * // decrease precision (requires round)
78
+ * setPricePrecision({ of: 'USD 5.555', to: 'centi.x10^-2' })
79
+ * // => 'USD 5.56' (default half-up)
80
+ *
81
+ * @example
82
+ * // decrease precision with explicit round mode
83
+ * setPricePrecision({ of: 'USD 5.555', to: 'centi.x10^-2' }, { round: 'floor' })
84
+ * // => 'USD 5.55'
85
+ */
86
+ const setPricePrecision = (input, options) => {
87
+ // parse the input price
88
+ const shape = (0, asIsoPriceShape_1.asIsoPriceShape)(input.of);
89
+ // get current and target exponent values
90
+ const currentExp = getExponentValue(shape.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI);
91
+ const targetExp = getExponentValue(input.to);
92
+ // calculate the scale difference
93
+ const scaleDiff = currentExp - targetExp;
94
+ let newAmount;
95
+ if (scaleDiff > 0) {
96
+ // precision increase — multiply (lossless)
97
+ const multiplier = 10n ** BigInt(scaleDiff);
98
+ newAmount = shape.amount * multiplier;
99
+ }
100
+ else if (scaleDiff < 0) {
101
+ // precision decrease — divide with round
102
+ const divisor = 10n ** BigInt(-scaleDiff);
103
+ const mode = options?.round ?? IsoPriceRoundMode_1.IsoPriceRoundMode.HALF_UP;
104
+ newAmount = applyRoundMode(shape.amount, divisor, mode);
105
+ }
106
+ else {
107
+ // same precision
108
+ newAmount = shape.amount;
109
+ }
110
+ // build new shape with target exponent
111
+ const newShape = {
112
+ amount: newAmount,
113
+ currency: shape.currency,
114
+ exponent: input.to,
115
+ };
116
+ return (0, asIsoPriceWords_1.asIsoPriceWords)(newShape);
117
+ };
118
+ exports.setPricePrecision = setPricePrecision;
119
+ //# sourceMappingURL=setPricePrecision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setPricePrecision.js","sourceRoot":"","sources":["../../../src/domain.operations/precision/setPricePrecision.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
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 = calculates the average of an array of prices
6
+ * .why = enables statistical analysis of price data with precision safety
7
+ *
8
+ * @example
9
+ * calcPriceAvg(['USD 10.00', 'USD 20.00', 'USD 30.00'])
10
+ * // => 'USD 20.00'
11
+ *
12
+ * @example
13
+ * calcPriceAvg(['USD 10.00', 'USD 20.00'], { format: 'shape' })
14
+ * // => { amount: 1500n, currency: 'USD', exponent: 'centi.x10^-2' }
15
+ */
16
+ export declare function calcPriceAvg<TCurrency extends string = string>(prices: (IsoPrice<TCurrency> | string)[], options?: {
17
+ format?: 'words';
18
+ }): IsoPriceWords<TCurrency>;
19
+ export declare function calcPriceAvg<TCurrency extends string = string>(prices: (IsoPrice<TCurrency> | string)[], options: {
20
+ format: 'shape';
21
+ }): IsoPriceShape<TCurrency>;
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calcPriceAvg = 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 calcPriceAvg(prices, options) {
9
+ // validate input
10
+ if (prices.length === 0) {
11
+ throw new helpful_errors_1.BadRequestError('cannot calculate average of empty array', {
12
+ prices,
13
+ });
14
+ }
15
+ // convert all prices to shapes
16
+ const shapes = prices.map((p) => (0, asIsoPriceShape_1.asIsoPriceShape)(p));
17
+ // validate all currencies match
18
+ const currency = shapes[0].currency;
19
+ const mismatch = shapes.find((s) => s.currency !== currency);
20
+ if (mismatch) {
21
+ throw new helpful_errors_1.BadRequestError('cannot calculate average of mixed currencies', {
22
+ expected: currency,
23
+ found: mismatch.currency,
24
+ });
25
+ }
26
+ // find highest precision exponent (most negative = highest precision)
27
+ const exponents = shapes.map((s) => s.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI);
28
+ const targetExponent = findHighestPrecisionExponent(exponents);
29
+ // normalize all amounts to target exponent
30
+ const normalizedAmounts = shapes.map((s) => normalizeAmount(s.amount, s.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI, targetExponent));
31
+ // calculate sum
32
+ const sum = normalizedAmounts.reduce((acc, amt) => acc + amt, 0n);
33
+ // calculate average via bigint division (truncates toward zero)
34
+ const count = BigInt(prices.length);
35
+ const avgAmount = sum / count;
36
+ // build result shape
37
+ const resultShape = {
38
+ amount: avgAmount,
39
+ currency,
40
+ exponent: targetExponent,
41
+ };
42
+ if (options?.format === 'shape') {
43
+ return resultShape;
44
+ }
45
+ return (0, asIsoPriceWords_1.asIsoPriceWords)(resultShape);
46
+ }
47
+ exports.calcPriceAvg = calcPriceAvg;
48
+ /**
49
+ * .what = finds the highest precision exponent from an array
50
+ * .why = ensures no precision loss when amounts are normalized
51
+ */
52
+ const findHighestPrecisionExponent = (exponents) => {
53
+ let highestPrecision = exponents[0];
54
+ let highestValue = getExponentValue(highestPrecision);
55
+ for (const exp of exponents) {
56
+ const value = getExponentValue(exp);
57
+ if (value < highestValue) {
58
+ highestValue = value;
59
+ highestPrecision = exp;
60
+ }
61
+ }
62
+ return highestPrecision;
63
+ };
64
+ /**
65
+ * .what = extracts numeric exponent value from exponent string
66
+ * .why = enables comparison of exponent precision
67
+ */
68
+ const getExponentValue = (exponent) => {
69
+ const match = exponent.match(/\^(-?\d+)$/);
70
+ if (!match)
71
+ return -2; // default to centi
72
+ return parseInt(match[1], 10);
73
+ };
74
+ /**
75
+ * .what = normalizes amount from source exponent to target exponent
76
+ * .why = enables arithmetic on amounts with different precisions
77
+ */
78
+ const normalizeAmount = (amount, sourceExponent, targetExponent) => {
79
+ const sourceValue = getExponentValue(sourceExponent);
80
+ const targetValue = getExponentValue(targetExponent);
81
+ const diff = sourceValue - targetValue;
82
+ if (diff > 0) {
83
+ // source has lower precision, multiply to increase
84
+ return amount * 10n ** BigInt(diff);
85
+ }
86
+ if (diff < 0) {
87
+ // source has higher precision, divide to decrease (should not happen if target is highest)
88
+ return amount / 10n ** BigInt(-diff);
89
+ }
90
+ return amount;
91
+ };
92
+ //# sourceMappingURL=calcPriceAvg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calcPriceAvg.js","sourceRoot":"","sources":["../../../src/domain.operations/statistics/calcPriceAvg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
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 = calculates the standard deviation of an array of prices
6
+ * .why = enables statistical analysis of price variance with precision safety
7
+ *
8
+ * uses population standard deviation formula: sqrt(sum((x - mean)^2) / n)
9
+ *
10
+ * @example
11
+ * calcPriceStdev(['USD 10.00', 'USD 20.00', 'USD 30.00'])
12
+ * // => 'USD 8.16' (approx)
13
+ *
14
+ * @example
15
+ * calcPriceStdev(['USD 10.00', 'USD 20.00'], { format: 'shape' })
16
+ * // => { amount: 500n, currency: 'USD', exponent: 'centi.x10^-2' }
17
+ */
18
+ export declare function calcPriceStdev<TCurrency extends string = string>(prices: (IsoPrice<TCurrency> | string)[], options?: {
19
+ format?: 'words';
20
+ }): IsoPriceWords<TCurrency>;
21
+ export declare function calcPriceStdev<TCurrency extends string = string>(prices: (IsoPrice<TCurrency> | string)[], options: {
22
+ format: 'shape';
23
+ }): IsoPriceShape<TCurrency>;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calcPriceStdev = 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 calcPriceStdev(prices, options) {
9
+ // validate input
10
+ if (prices.length === 0) {
11
+ throw new helpful_errors_1.BadRequestError('cannot calculate stdev of empty array', {
12
+ prices,
13
+ });
14
+ }
15
+ // single value has zero variance
16
+ if (prices.length === 1) {
17
+ const shape = (0, asIsoPriceShape_1.asIsoPriceShape)(prices[0]);
18
+ const resultShape = {
19
+ amount: 0n,
20
+ currency: shape.currency,
21
+ exponent: (shape.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI),
22
+ };
23
+ if (options?.format === 'shape')
24
+ return resultShape;
25
+ return (0, asIsoPriceWords_1.asIsoPriceWords)(resultShape);
26
+ }
27
+ // convert all prices to shapes
28
+ const shapes = prices.map((p) => (0, asIsoPriceShape_1.asIsoPriceShape)(p));
29
+ // validate all currencies match
30
+ const currency = shapes[0].currency;
31
+ const mismatch = shapes.find((s) => s.currency !== currency);
32
+ if (mismatch) {
33
+ throw new helpful_errors_1.BadRequestError('cannot calculate stdev of mixed currencies', {
34
+ expected: currency,
35
+ found: mismatch.currency,
36
+ });
37
+ }
38
+ // find highest precision exponent
39
+ const exponents = shapes.map((s) => s.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI);
40
+ const targetExponent = findHighestPrecisionExponent(exponents);
41
+ // normalize all amounts to target exponent
42
+ const normalizedAmounts = shapes.map((s) => normalizeAmount(s.amount, s.exponent ?? IsoPriceExponent_1.IsoPriceExponent.CENTI, targetExponent));
43
+ // calculate mean
44
+ const sum = normalizedAmounts.reduce((acc, amt) => acc + amt, 0n);
45
+ const count = BigInt(prices.length);
46
+ const mean = sum / count;
47
+ // calculate sum of squared deviations
48
+ // note: we use number for intermediate sqrt calculation, then convert back
49
+ let sumSquaredDev = 0n;
50
+ for (const amt of normalizedAmounts) {
51
+ const dev = amt - mean;
52
+ sumSquaredDev += dev * dev;
53
+ }
54
+ // calculate variance and stdev
55
+ // variance = sumSquaredDev / n (population stdev)
56
+ const variance = sumSquaredDev / count;
57
+ // sqrt via Newton's method for bigint (integer sqrt)
58
+ const stdevAmount = bigintSqrt(variance);
59
+ // build result shape
60
+ const resultShape = {
61
+ amount: stdevAmount,
62
+ currency,
63
+ exponent: targetExponent,
64
+ };
65
+ if (options?.format === 'shape') {
66
+ return resultShape;
67
+ }
68
+ return (0, asIsoPriceWords_1.asIsoPriceWords)(resultShape);
69
+ }
70
+ exports.calcPriceStdev = calcPriceStdev;
71
+ /**
72
+ * .what = integer square root via Newton's method
73
+ * .why = enables sqrt calculation for bigint values
74
+ */
75
+ const bigintSqrt = (n) => {
76
+ if (n < 0n) {
77
+ throw new helpful_errors_1.BadRequestError('cannot calculate sqrt of negative number', {
78
+ n,
79
+ });
80
+ }
81
+ if (n === 0n)
82
+ return 0n;
83
+ if (n === 1n)
84
+ return 1n;
85
+ // initial guess
86
+ let x = n;
87
+ let y = (x + 1n) / 2n;
88
+ // Newton's method iteration
89
+ while (y < x) {
90
+ x = y;
91
+ y = (x + n / x) / 2n;
92
+ }
93
+ return x;
94
+ };
95
+ /**
96
+ * .what = finds the highest precision exponent from an array
97
+ * .why = ensures no precision loss when amounts are normalized
98
+ */
99
+ const findHighestPrecisionExponent = (exponents) => {
100
+ let highestPrecision = exponents[0];
101
+ let highestValue = getExponentValue(highestPrecision);
102
+ for (const exp of exponents) {
103
+ const value = getExponentValue(exp);
104
+ if (value < highestValue) {
105
+ highestValue = value;
106
+ highestPrecision = exp;
107
+ }
108
+ }
109
+ return highestPrecision;
110
+ };
111
+ /**
112
+ * .what = extracts numeric exponent value from exponent string
113
+ * .why = enables comparison of exponent precision
114
+ */
115
+ const getExponentValue = (exponent) => {
116
+ const match = exponent.match(/\^(-?\d+)$/);
117
+ if (!match)
118
+ return -2; // default to centi
119
+ return parseInt(match[1], 10);
120
+ };
121
+ /**
122
+ * .what = normalizes amount from source exponent to target exponent
123
+ * .why = enables arithmetic on amounts with different precisions
124
+ */
125
+ const normalizeAmount = (amount, sourceExponent, targetExponent) => {
126
+ const sourceValue = getExponentValue(sourceExponent);
127
+ const targetValue = getExponentValue(targetExponent);
128
+ const diff = sourceValue - targetValue;
129
+ if (diff > 0) {
130
+ return amount * 10n ** BigInt(diff);
131
+ }
132
+ if (diff < 0) {
133
+ return amount / 10n ** BigInt(-diff);
134
+ }
135
+ return amount;
136
+ };
137
+ //# sourceMappingURL=calcPriceStdev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calcPriceStdev.js","sourceRoot":"","sources":["../../../src/domain.operations/statistics/calcPriceStdev.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export * from './contract/index';
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./contract/index"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC"}
package/license.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 ehmpathy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json ADDED
@@ -0,0 +1,102 @@
1
+ {
2
+ "name": "iso-price",
3
+ "author": "ehmpathy",
4
+ "description": "type-safe price representation with sub-cent precision, iso 4217 currency support, and lossless arithmetic",
5
+ "version": "1.0.3",
6
+ "repository": "ehmpathy/iso-price",
7
+ "homepage": "https://github.com/ehmpathy/iso-price",
8
+ "keywords": [
9
+ "price",
10
+ "currency",
11
+ "money",
12
+ "iso-4217",
13
+ "bigint",
14
+ "precision",
15
+ "arithmetic",
16
+ "typescript"
17
+ ],
18
+ "bugs": "https://github.com/ehmpathy/iso-price/issues",
19
+ "license": "MIT",
20
+ "main": "dist/index.js",
21
+ "engines": {
22
+ "node": ">=8.0.0"
23
+ },
24
+ "files": [
25
+ "/dist"
26
+ ],
27
+ "dependencies": {
28
+ "domain-glossaries": "1.0.0",
29
+ "helpful-errors": "1.5.3"
30
+ },
31
+ "peerDependencies": {
32
+ "domain-objects": ">=0.24.2"
33
+ },
34
+ "devDependencies": {
35
+ "@biomejs/biome": "2.3.8",
36
+ "@commitlint/cli": "19.5.0",
37
+ "@commitlint/config-conventional": "19.5.0",
38
+ "@swc/core": "1.15.3",
39
+ "@swc/jest": "0.2.39",
40
+ "@tsconfig/node20": "20.1.5",
41
+ "@tsconfig/strictest": "2.0.5",
42
+ "@types/jest": "30.0.0",
43
+ "@types/node": "22.15.21",
44
+ "cz-conventional-changelog": "3.3.0",
45
+ "declapract": "0.13.14",
46
+ "declapract-typescript-ehmpathy": "0.47.27",
47
+ "declastruct": "1.7.3",
48
+ "declastruct-github": "1.3.0",
49
+ "depcheck": "1.4.3",
50
+ "esbuild-register": "3.6.0",
51
+ "husky": "8.0.3",
52
+ "jest": "30.2.0",
53
+ "rhachet": "1.22.7",
54
+ "rhachet-roles-bhrain": "0.5.11",
55
+ "rhachet-roles-bhuild": "0.6.6",
56
+ "rhachet-roles-ehmpathy": "1.17.20",
57
+ "test-fns": "1.4.2",
58
+ "tsc-alias": "1.8.10",
59
+ "tsx": "4.20.6",
60
+ "typescript": "5.4.5",
61
+ "yalc": "1.0.0-pre.53"
62
+ },
63
+ "config": {
64
+ "commitizen": {
65
+ "path": "./node_modules/cz-conventional-changelog"
66
+ }
67
+ },
68
+ "scripts": {
69
+ "build:ts": "tsc -p ./tsconfig.build.json",
70
+ "commit:with-cli": "npx cz",
71
+ "fix:format:biome": "biome check --write",
72
+ "fix:format": "npm run fix:format:biome",
73
+ "fix:lint": "biome check --write",
74
+ "fix": "npm run fix:format && npm run fix:lint",
75
+ "build:clean:bun": "rm -f ./bin/*.bc",
76
+ "build:clean:tsc": "(chmod -R u+w dist 2>/dev/null || true) && rm -rf dist/",
77
+ "build:clean": "npm run build:clean:tsc && npm run build:clean:bun",
78
+ "build:compile:tsc": "tsc -p ./tsconfig.build.json && tsc-alias -p ./tsconfig.build.json",
79
+ "build:compile": "npm run build:compile:tsc && npm run build:compile:bun --if-present",
80
+ "build": "npm run build:clean && npm run build:compile && npm run build:complete --if-present",
81
+ "test:auth": "[ \"$ECHO\" = 'true' ] && echo '. .agent/repo=.this/role=any/skills/use.apikeys.sh' || . .agent/repo=.this/role=any/skills/use.apikeys.sh",
82
+ "test:commits": "LAST_TAG=$(git describe --tags --abbrev=0 @^ 2> /dev/null || git rev-list --max-parents=0 HEAD) && npx commitlint --from $LAST_TAG --to HEAD --verbose",
83
+ "test:types": "tsc -p ./tsconfig.json --noEmit",
84
+ "test:format:biome": "biome format",
85
+ "test:format": "npm run test:format:biome",
86
+ "test:lint:deps": "npx depcheck -c ./.depcheckrc.yml",
87
+ "test:lint:biome": "biome check --diagnostic-level=error",
88
+ "test:lint:biome:all": "biome check",
89
+ "test:lint": "npm run test:lint:biome && npm run test:lint:deps",
90
+ "test:unit": "jest -c ./jest.unit.config.ts --forceExit --verbose --passWithNoTests $([ -z $THOROUGH ] && echo '--changedSince=main') $([ -n $RESNAP ] && echo '--updateSnapshot')",
91
+ "test:integration": "jest -c ./jest.integration.config.ts --forceExit --verbose --passWithNoTests $([ -z $THOROUGH ] && echo '--changedSince=main') $([ -n $RESNAP ] && echo '--updateSnapshot')",
92
+ "test:acceptance:locally": "npm run build && LOCALLY=true jest -c ./jest.acceptance.config.ts --forceExit --verbose --runInBand --passWithNoTests $([ -n $RESNAP ] && echo '--updateSnapshot')",
93
+ "test": "eval $(ECHO=true npm run --silent test:auth) && npm run test:commits && npm run test:types && npm run test:format && npm run test:lint && npm run test:unit && npm run test:integration && npm run test:acceptance:locally",
94
+ "test:acceptance": "npm run build && jest -c ./jest.acceptance.config.ts --forceExit --verbose --runInBand --passWithNoTests $([ -n $RESNAP ] && echo '--updateSnapshot')",
95
+ "prepush": "npm run test && npm run build",
96
+ "prepublish": "npm run build",
97
+ "preversion": "npm run prepush",
98
+ "postversion": "git push origin HEAD --tags --no-verify",
99
+ "prepare:husky": "husky install && chmod ug+x .husky/*",
100
+ "prepare:rhachet": "rhachet init --roles behaver mechanic reviewer"
101
+ }
102
+ }