@f-o-t/money 1.1.1 → 1.2.1

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 (58) hide show
  1. package/CHANGELOG.md +258 -0
  2. package/LICENSE +21 -0
  3. package/README.md +147 -0
  4. package/__tests__/money.test.ts +1287 -0
  5. package/__tests__/rounding.test.ts +104 -0
  6. package/biome.json +39 -0
  7. package/fot.config.ts +6 -0
  8. package/package.json +30 -57
  9. package/src/core/assertions.d.ts +13 -0
  10. package/src/core/assertions.ts +40 -0
  11. package/src/core/internal.d.ts +35 -0
  12. package/src/core/internal.ts +60 -0
  13. package/src/core/money.d.ts +80 -0
  14. package/src/core/money.ts +179 -0
  15. package/src/core/rounding.ts +35 -0
  16. package/src/currency/currencies.d.ts +11 -0
  17. package/src/currency/currencies.ts +389 -0
  18. package/src/currency/registry.d.ts +34 -0
  19. package/src/currency/registry.ts +70 -0
  20. package/src/currency/types.d.ts +6 -0
  21. package/src/currency/types.ts +6 -0
  22. package/src/errors.d.ts +50 -0
  23. package/src/errors.ts +105 -0
  24. package/src/exports/core.d.ts +5 -0
  25. package/src/exports/core.ts +14 -0
  26. package/src/exports/formatting.d.ts +2 -0
  27. package/src/exports/formatting.ts +9 -0
  28. package/src/exports/operations.d.ts +4 -0
  29. package/src/exports/operations.ts +16 -0
  30. package/src/exports/serialization.d.ts +3 -0
  31. package/src/exports/serialization.ts +12 -0
  32. package/src/formatting/format.d.ts +57 -0
  33. package/src/formatting/format.ts +234 -0
  34. package/src/formatting/parse.d.ts +22 -0
  35. package/src/formatting/parse.ts +109 -0
  36. package/src/index.d.ts +10 -0
  37. package/src/index.ts +44 -0
  38. package/src/operations/aggregation.d.ts +80 -0
  39. package/src/operations/aggregation.ts +182 -0
  40. package/src/operations/allocation.d.ts +40 -0
  41. package/src/operations/allocation.ts +171 -0
  42. package/src/operations/arithmetic.d.ts +89 -0
  43. package/src/operations/arithmetic.ts +150 -0
  44. package/src/operations/comparison.ts +99 -0
  45. package/src/plugins/operators/index.ts +177 -0
  46. package/src/schemas.ts +260 -0
  47. package/src/serialization/conversion.d.ts +68 -0
  48. package/src/serialization/conversion.ts +109 -0
  49. package/src/serialization/json.d.ts +68 -0
  50. package/src/serialization/json.ts +126 -0
  51. package/src/types.d.ts +8 -0
  52. package/src/types.ts +16 -0
  53. package/tsconfig.json +30 -0
  54. package/dist/index.d.ts +0 -863
  55. package/dist/index.js +0 -521
  56. package/dist/operators/index.d.ts +0 -69
  57. package/dist/operators/index.js +0 -39
  58. package/dist/shared/chunk-jf6gzvp1.js +0 -852
package/CHANGELOG.md ADDED
@@ -0,0 +1,258 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.2.1] - 2026-02-02
9
+
10
+ ### Fixed
11
+
12
+ - Fixed TypeScript declaration generation OOM (exit code 134) by decoupling operators from comparison module
13
+ - Root cause: duplicate Zod installations caused exponential type expansion during structural compatibility checks
14
+
15
+ ### Changed
16
+
17
+ - Moved condition-evaluator operators from `operations/comparison.ts` to `plugins/operators/`
18
+ - Made `@f-o-t/condition-evaluator` an optional peer dependency
19
+ - Main library no longer imports from `@f-o-t/condition-evaluator`
20
+ - Removed `isolatedDeclarations` and `maxMemory` workaround from build config
21
+
22
+ ## [1.2.0] - 2026-02-01
23
+
24
+ ### Changed
25
+
26
+ - **Internal refactor**: Migrated to `@f-o-t/bigint` ^1.0.0 for bigint operations
27
+ - `parseDecimalToMinorUnits` now uses `parseToBigInt` from @f-o-t/bigint
28
+ - `minorUnitsToDecimal` now uses `formatFromBigInt` from @f-o-t/bigint
29
+ - `bankersRound` now imported from @f-o-t/bigint
30
+ - `roundToScale` now uses `convertScale` from @f-o-t/bigint
31
+ - **Note**: This is an internal refactor with no breaking changes to public APIs
32
+ - **Benefit**: Standardized bigint operations across all FOT libraries
33
+
34
+ ### Dependencies
35
+
36
+ - Added `@f-o-t/bigint` ^1.0.0
37
+
38
+ ## [1.1.1] - 2026-01-25
39
+
40
+ ### Changed
41
+
42
+ - Updated dependencies to latest versions
43
+
44
+ ## [1.1.0] - 2025-12-25
45
+
46
+ ### Added
47
+
48
+ #### Rounding Mode Support
49
+ - `ofRounded()` - New factory function that rounds excess decimal places using banker's rounding
50
+ - `RoundingMode` type - `"truncate" | "round"` for controlling decimal handling
51
+ - Optional third parameter for `of()` to specify rounding mode: `of("10.999", "USD", "round")`
52
+
53
+ #### Precision-Safe Conversion
54
+ - `toMajorUnitsString()` - Convert Money to major units as a string without precision loss
55
+ - Safe formatting for very large amounts (>15 significant digits) that would lose precision with float conversion
56
+
57
+ #### Scale Validation
58
+ - `ScaleMismatchError` - New error thrown when operating on Money values with inconsistent scales
59
+ - `assertSameCurrency()` now validates both currency AND scale consistency
60
+ - `assertAllSameCurrency()` now validates scale consistency across all values
61
+
62
+ ### Changed
63
+
64
+ #### Banker's Rounding Fix
65
+ - Fixed banker's rounding algorithm for odd divisors
66
+ - Previously used truncated half comparison which could produce incorrect results
67
+ - Now uses `remainder * 2 === divisor` for accurate halfway detection
68
+
69
+ #### Allocation Precision
70
+ - Improved ratio precision in `allocate()` by using string-based parsing instead of `Math.round`
71
+ - Eliminates floating-point errors for extreme ratio values (very small or very large)
72
+
73
+ #### Parse Validation
74
+ - `parse()` now throws `InvalidAmountError` on malformed input with multiple decimal separators
75
+ - Previously would silently accept invalid formats like "1.234.56"
76
+
77
+ #### Input Precision Warnings
78
+ - `of()` now warns when passed a number with likely floating-point precision issues
79
+ - Detects patterns like `0.1 + 0.2` that produce imprecise results
80
+ - Encourages use of string amounts for precision-critical values
81
+
82
+ ### Deprecated
83
+
84
+ - `toMajorUnits()` - Use `toMajorUnitsString()` for precision-safe conversion
85
+ - Still works but logs a warning for amounts exceeding safe integer range
86
+
87
+ ### Fixed
88
+
89
+ - Banker's rounding for odd divisors now correctly rounds to even
90
+ - Large amount formatting no longer loses precision due to float conversion
91
+ - Allocation with extreme ratios now preserves full precision
92
+
93
+ ---
94
+
95
+ ## [1.0.0] - 2024-12-24
96
+
97
+ ### Added
98
+
99
+ #### Core Features
100
+ - BigInt-based money representation for exact precision arithmetic
101
+ - Immutable `Money` type with `amount` (BigInt), `currency` (string), and `scale` (number) properties
102
+ - Support for all ISO 4217 currencies with correct decimal places
103
+ - Type-safe operations with full TypeScript support
104
+
105
+ #### Factory Functions
106
+ - `of()` - Create Money from major units (dollars, euros, etc.) as string or number
107
+ - `fromMajorUnits()` - Alias for `of()` for semantic clarity
108
+ - `fromMinorUnits()` - Create Money from minor units (cents, pence, etc.)
109
+ - `zero()` - Create zero-value Money for a given currency
110
+
111
+ #### Arithmetic Operations
112
+ - `add()` - Add two Money values (throws on currency mismatch)
113
+ - `subtract()` - Subtract Money values
114
+ - `multiply()` - Multiply Money by scalar (number or string for precision)
115
+ - `divide()` - Divide Money by scalar using banker's rounding
116
+ - `percentage()` - Calculate percentage of Money value
117
+ - `negate()` - Negate Money value
118
+ - `absolute()` - Get absolute value of Money
119
+
120
+ #### Comparison Operations
121
+ - `equals()` - Check equality
122
+ - `greaterThan()`, `greaterThanOrEqual()` - Greater than comparisons
123
+ - `lessThan()`, `lessThanOrEqual()` - Less than comparisons
124
+ - `isPositive()`, `isNegative()`, `isZero()` - Value state checks
125
+ - `compare()` - Three-way comparison (-1, 0, 1)
126
+
127
+ #### Allocation
128
+ - `allocate()` - Distribute Money by ratios using largest remainder method
129
+ - `split()` - Split Money evenly into N parts with fair remainder distribution
130
+ - Guarantees sum of allocated parts equals original amount
131
+
132
+ #### Aggregation
133
+ - `sum()` - Sum array of Money values
134
+ - `sumOrZero()` - Sum with safe handling of empty arrays
135
+ - `min()`, `max()` - Find minimum/maximum values
136
+ - `average()` - Calculate average with banker's rounding
137
+ - `median()` - Calculate median value
138
+
139
+ #### Formatting
140
+ - `format()` - Format Money with locale support (Intl.NumberFormat)
141
+ - `formatCompact()` - Format with compact notation for large amounts
142
+ - `formatAmount()` - Format amount only without currency symbol
143
+ - `toDecimal()` - Convert to plain decimal string
144
+ - Support for locale-specific formatting (en-US, pt-BR, ja-JP, etc.)
145
+ - Configurable format options (notation, sign display, currency display, etc.)
146
+
147
+ #### Parsing
148
+ - `parse()` - Parse formatted strings to Money values
149
+ - Support for multiple locale formats
150
+ - Handle negative amounts (both parentheses and minus sign notation)
151
+ - Automatic removal of currency symbols and thousands separators
152
+
153
+ #### Serialization
154
+ - `toJSON()`, `fromJSON()` - JSON serialization with `{ amount: string, currency: string }` format
155
+ - `toDatabase()`, `fromDatabase()` - Database storage (alias for JSON methods)
156
+ - `serialize()`, `deserialize()` - String serialization with "amount currency" format
157
+ - `toMinorUnits()` - Convert to number (throws on overflow)
158
+ - `toMinorUnitsBigInt()` - Convert to BigInt
159
+ - `toMajorUnits()` - Convert to decimal number
160
+ - `toMinorUnitsString()` - Convert to string representation
161
+
162
+ #### Currency Registry
163
+ - `getCurrency()` - Get currency metadata (symbol, decimal places, name)
164
+ - `hasCurrency()` - Check if currency exists
165
+ - `registerCurrency()` - Register custom currencies
166
+ - `getAllCurrencies()` - Get all registered currencies
167
+ - `clearCustomCurrencies()` - Clear custom currencies (useful for testing)
168
+ - `ISO_4217_CURRENCIES` - Complete ISO 4217 currency data
169
+ - Case-insensitive currency code handling
170
+
171
+ #### Validation
172
+ - Zod schemas for all types:
173
+ - `MoneySchema` - JSON representation validation
174
+ - `MoneyInputSchema` - User input validation (accepts string or number)
175
+ - `MoneyInternalSchema` - Internal Money representation
176
+ - `CurrencyCodeSchema` - ISO 4217 currency code validation
177
+ - `CurrencySchema` - Currency definition validation
178
+ - `DatabaseMoneySchema` - Database storage validation
179
+ - `AllocationRatiosSchema` - Allocation ratios validation
180
+ - `FormatOptionsSchema` - Format options validation
181
+
182
+ #### Error Handling
183
+ - `MoneyError` - Base error class
184
+ - `CurrencyMismatchError` - Thrown when operating on different currencies
185
+ - `InvalidAmountError` - Thrown for invalid amount values
186
+ - `DivisionByZeroError` - Thrown when dividing by zero
187
+ - `UnknownCurrencyError` - Thrown for unregistered currencies
188
+ - `OverflowError` - Thrown when converting BigInt to unsafe number
189
+
190
+ #### Condition Evaluator Integration
191
+ - `@f-o-t/money/operators` export for condition evaluator integration
192
+ - Money operators:
193
+ - `money_eq`, `money_neq` - Equality checks
194
+ - `money_gt`, `money_gte`, `money_lt`, `money_lte` - Comparisons
195
+ - `money_between` - Range checks
196
+ - `money_positive`, `money_negative`, `money_zero` - State checks
197
+ - Seamless integration with `@f-o-t/condition-evaluator` package
198
+
199
+ #### Low-Level Utilities
200
+ - `bankersRound()` - Banker's rounding (round half to even)
201
+ - `createMoney()` - Direct Money creation (bypasses validation)
202
+ - `parseDecimalToMinorUnits()` - Parse decimal string to BigInt
203
+ - `minorUnitsToDecimal()` - Convert BigInt to decimal string
204
+ - `assertSameCurrency()` - Assert two Money values have same currency
205
+ - `assertAllSameCurrency()` - Assert all Money values in array have same currency
206
+ - Constants: `EXTENDED_PRECISION`, `PRECISION_FACTOR`
207
+
208
+ #### Developer Experience
209
+ - Zero runtime dependencies (only Zod for validation)
210
+ - Full TypeScript type safety
211
+ - Immutable data structures (frozen objects)
212
+ - Comprehensive test suite with 100% coverage
213
+ - Performance benchmarks included
214
+ - JSDoc comments for all public APIs
215
+
216
+ ### Technical Details
217
+
218
+ #### Precision
219
+ - Uses BigInt for all internal calculations
220
+ - Extended precision for intermediate calculations (6 decimal places)
221
+ - Banker's rounding (IEEE 754) for division and averaging
222
+ - Guarantees exact results for all arithmetic operations
223
+
224
+ #### Currency Handling
225
+ - Automatic decimal place handling based on ISO 4217
226
+ - Support for 0-decimal currencies (JPY, KRW)
227
+ - Support for 3-decimal currencies (KWD, BHD, OMR)
228
+ - Support for 4-decimal currencies (CLF)
229
+ - Case-insensitive currency code input (normalized to uppercase)
230
+
231
+ #### Performance
232
+ - Optimized for high-frequency operations
233
+ - Formatter caching for repeated format operations
234
+ - Minimal object allocations
235
+ - Benchmarks included in test suite:
236
+ - 10,000 Money creations: < 500ms
237
+ - 10,000 additions: < 200ms
238
+ - 10,000 comparisons: < 100ms
239
+
240
+ #### Package Exports
241
+ - Main export: `@f-o-t/money` - All core functionality
242
+ - Operators export: `@f-o-t/money/operators` - Condition evaluator operators
243
+ - Package.json export: `@f-o-t/money/package.json`
244
+
245
+ ### Dependencies
246
+
247
+ - `zod` (^4.1.13) - Schema validation
248
+ - `@f-o-t/condition-evaluator` (workspace) - Operator integration
249
+
250
+ ### Peer Dependencies
251
+
252
+ - `typescript` (>=4.5.0) - Optional for type checking
253
+
254
+ [1.2.1]: https://github.com/F-O-T/libraries/releases/tag/@f-o-t/money@1.2.1
255
+ [1.2.0]: https://github.com/F-O-T/libraries/releases/tag/@f-o-t/money@1.2.0
256
+ [1.1.1]: https://github.com/F-O-T/libraries/releases/tag/@f-o-t/money@1.1.1
257
+ [1.1.0]: https://github.com/F-O-T/libraries/releases/tag/@f-o-t/money@1.1.0
258
+ [1.0.0]: https://github.com/F-O-T/libraries/releases/tag/@f-o-t/money@1.0.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FOT (F-O-T)
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/README.md CHANGED
@@ -482,6 +482,153 @@ const result = evaluator.evaluate(
482
482
  // - money_positive, money_negative, money_zero
483
483
  ```
484
484
 
485
+ ### Rules Engine Integration
486
+
487
+ Use money operators with `@f-o-t/rules-engine` to build complex financial business rules:
488
+
489
+ ```typescript
490
+ import { createEngine } from "@f-o-t/rules-engine";
491
+ import { moneyOperators } from "@f-o-t/money/plugins/operators";
492
+ import { z } from "zod";
493
+
494
+ // Define consequence types for your rules
495
+ const TransactionConsequences = {
496
+ approve: z.object({ approved: z.boolean() }),
497
+ require_review: z.object({ reason: z.string() }),
498
+ reject: z.object({ reason: z.string() }),
499
+ apply_fee: z.object({ amount: z.string(), currency: z.string() }),
500
+ };
501
+
502
+ // Create engine with money operators
503
+ const engine = createEngine({
504
+ operators: moneyOperators,
505
+ consequences: TransactionConsequences,
506
+ });
507
+
508
+ // Add rules for high-value transactions
509
+ engine.addRule({
510
+ name: "high-value-transaction-review",
511
+ priority: 100,
512
+ conditions: {
513
+ id: "g1",
514
+ operator: "AND",
515
+ conditions: [
516
+ {
517
+ id: "c1",
518
+ type: "custom",
519
+ field: "amount",
520
+ operator: "money_gt",
521
+ value: { amount: "10000.00", currency: "BRL" },
522
+ },
523
+ ],
524
+ },
525
+ consequences: [
526
+ {
527
+ type: "require_review",
528
+ payload: { reason: "High value transaction requires approval" },
529
+ },
530
+ ],
531
+ });
532
+
533
+ // Add rules for transaction fees
534
+ engine.addRule({
535
+ name: "pix-fee-waiver",
536
+ priority: 50,
537
+ conditions: {
538
+ id: "g2",
539
+ operator: "AND",
540
+ conditions: [
541
+ {
542
+ id: "c1",
543
+ type: "string",
544
+ field: "paymentMethod",
545
+ operator: "eq",
546
+ value: "pix",
547
+ },
548
+ {
549
+ id: "c2",
550
+ type: "custom",
551
+ field: "amount",
552
+ operator: "money_lt",
553
+ value: { amount: "100.00", currency: "BRL" },
554
+ },
555
+ ],
556
+ },
557
+ consequences: [
558
+ {
559
+ type: "apply_fee",
560
+ payload: { amount: "0.00", currency: "BRL" },
561
+ },
562
+ ],
563
+ });
564
+
565
+ // Evaluate rules
566
+ const result = await engine.evaluate({
567
+ amount: { amount: "15000.00", currency: "BRL" },
568
+ paymentMethod: "pix",
569
+ });
570
+
571
+ console.log(result.matchedRules); // Rules that matched
572
+ console.log(result.consequences); // Actions to take
573
+ ```
574
+
575
+ **Complex multi-condition rules:**
576
+
577
+ ```typescript
578
+ // Discount eligibility with money conditions
579
+ engine.addRule({
580
+ name: "volume-discount",
581
+ conditions: {
582
+ id: "g1",
583
+ operator: "AND",
584
+ conditions: [
585
+ {
586
+ id: "c1",
587
+ type: "custom",
588
+ field: "cartTotal",
589
+ operator: "money_between",
590
+ value: [
591
+ { amount: "500.00", currency: "BRL" },
592
+ { amount: "2000.00", currency: "BRL" },
593
+ ],
594
+ },
595
+ {
596
+ id: "c2",
597
+ type: "custom",
598
+ field: "customerLifetimeValue",
599
+ operator: "money_gt",
600
+ value: { amount: "5000.00", currency: "BRL" },
601
+ },
602
+ {
603
+ id: "c3",
604
+ type: "boolean",
605
+ field: "isPremiumMember",
606
+ operator: "eq",
607
+ value: true,
608
+ },
609
+ ],
610
+ },
611
+ consequences: [
612
+ {
613
+ type: "apply_discount",
614
+ payload: { percentage: 15 },
615
+ },
616
+ ],
617
+ });
618
+ ```
619
+
620
+ **Available money operators for rules:**
621
+ - `money_eq` - Equal to
622
+ - `money_neq` - Not equal to
623
+ - `money_gt` - Greater than
624
+ - `money_gte` - Greater than or equal
625
+ - `money_lt` - Less than
626
+ - `money_lte` - Less than or equal
627
+ - `money_between` - Between two values (inclusive)
628
+ - `money_positive` - Is positive (> 0)
629
+ - `money_negative` - Is negative (< 0)
630
+ - `money_zero` - Is zero
631
+
485
632
  ### Custom Currencies
486
633
 
487
634
  Register currencies not in ISO 4217: