UNPKG

dinero.js

Version:

Create, calculate, and format money in JavaScript and TypeScript

1,936 lines (1,853 loc) 67.7 kB
/*! dinero.js 2.0.2 (UNRELEASED cc7df3e) | MIT License | © Sarah Dayan and contributors | https://dinerojs.com */ (function(global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.dinerojs = {}))); })(this, function(exports) { //#region src/core/checks/messages.ts const INVALID_AMOUNT_MESSAGE = "Amount is invalid."; const INVALID_SCALE_MESSAGE = "Scale is invalid."; const INVALID_RATIOS_MESSAGE = "Ratios are invalid."; const UNEQUAL_CURRENCIES_MESSAGE = "Objects must have the same currency."; const NON_DECIMAL_CURRENCY_MESSAGE = "Currency is not decimal."; const MISMATCHED_BASES_MESSAGE = "Objects must have the same currency base."; //#endregion //#region src/core/helpers/assert.ts /** * Assert a condition. * * @param condition - The condition to verify. * @param message - The error message to throw. * * @throws If the condition isn't met. */ function assert(condition, message) { if (!condition) throw new Error(`[Dinero.js] ${message}`); } //#endregion //#region src/core/helpers/createDinero.ts function createDinero({ calculator, onCreate, formatter = { toNumber: Number, toString: String } }) { return function dinero({ amount, currency: { code, base, exponent }, scale = exponent }) { const currency = { code, base, exponent }; onCreate?.({ amount, currency, scale }); return { calculator, formatter, create: dinero, toJSON() { return { amount, currency, scale }; } }; }; } //#endregion //#region src/core/types/DineroCalculator.ts let DineroComparisonOperator = /* @__PURE__ */ function(DineroComparisonOperator) { DineroComparisonOperator[DineroComparisonOperator["LT"] = -1] = "LT"; DineroComparisonOperator[DineroComparisonOperator["EQ"] = 0] = "EQ"; DineroComparisonOperator[DineroComparisonOperator["GT"] = 1] = "GT"; return DineroComparisonOperator; }({}); //#endregion //#region src/core/utils/equal.ts /** * Returns an equal function. * * @param calculator - The calculator to use. * * @returns The equal function. */ function equal$2(calculator) { return (subject, comparator) => { return calculator.compare(subject, comparator) === DineroComparisonOperator.EQ; }; } //#endregion //#region src/core/utils/lessThan.ts /** * Returns a lessThan function. * * @param calculator - The calculator to use. * * @returns The lessThan function. */ function lessThan$1(calculator) { return (subject, comparator) => { return calculator.compare(subject, comparator) === DineroComparisonOperator.LT; }; } //#endregion //#region src/core/utils/absolute.ts function absolute(calculator) { const equalFn = equal$2(calculator); const lessThanFn = lessThan$1(calculator); const zero = calculator.zero(); return (input) => { if (equalFn(input, zero)) return zero; if (lessThanFn(input, zero)) { const minusOne = calculator.decrement(zero); return calculator.multiply(minusOne, input); } return input; }; } //#endregion //#region src/core/utils/compare.ts /** * Returns a compare function. * * @param calculator - The calculator to use. * * @returns The compare function. */ function compare$2(calculator) { return (subject, comparator) => { return calculator.compare(subject, comparator); }; } //#endregion //#region src/core/utils/isArray.ts function isArray(maybeArray) { return Array.isArray(maybeArray); } //#endregion //#region src/core/utils/computeBase.ts function computeBase(calculator) { return (base) => { if (isArray(base)) return base.reduce((acc, curr) => calculator.multiply(acc, curr)); return base; }; } //#endregion //#region src/core/utils/countTrailingZeros.ts function countTrailingZeros(calculator) { const equalFn = equal$2(calculator); return (input, base) => { const zero = calculator.zero(); if (equalFn(zero, input)) return calculator.zero(); let i = zero; let temp = input; while (equalFn(calculator.modulo(temp, base), zero)) { temp = calculator.integerDivide(temp, base); i = calculator.increment(i); } return i; }; } //#endregion //#region src/core/utils/greaterThan.ts /** * Returns a greaterThan function. * * @param calculator - The calculator to use. * * @returns The greaterThan function. */ function greaterThan$1(calculator) { return (subject, comparator) => { return calculator.compare(subject, comparator) === DineroComparisonOperator.GT; }; } //#endregion //#region src/core/utils/greaterThanOrEqual.ts /** * Returns a greaterThanOrEqual function. * * @param calculator - The calculator to use. * * @returns The greaterThanOrEqual function. */ function greaterThanOrEqual$1(calculator) { return (subject, comparator) => { return greaterThan$1(calculator)(subject, comparator) || equal$2(calculator)(subject, comparator); }; } //#endregion //#region src/core/utils/distribute.ts /** * Returns a distribute function. * * @param calculator - The calculator to use. * * @returns The distribute function. */ function distribute(calculator) { return (value, ratios) => { const equalFn = equal$2(calculator); const greaterThanFn = greaterThan$1(calculator); const lessThanFn = lessThan$1(calculator); const greaterThanOrEqualFn = greaterThanOrEqual$1(calculator); const zero = calculator.zero(); const one = calculator.increment(zero); const total = ratios.reduce((a, b) => calculator.add(a, b), zero); if (equalFn(total, zero)) return ratios; let remainder = value; const shares = ratios.map((ratio) => { const share = calculator.integerDivide(calculator.multiply(value, ratio), total) || zero; remainder = calculator.subtract(remainder, share); return share; }); const isPositive = greaterThanOrEqualFn(value, zero); const compare = isPositive ? greaterThanFn : lessThanFn; const amount = isPositive ? one : calculator.decrement(zero); const sortedIndices = ratios.map((ratio, index) => ({ ratio, index })).filter(({ ratio }) => !equalFn(ratio, zero)).sort((a, b) => greaterThanFn(a.ratio, b.ratio) ? -1 : 1).map(({ index }) => index); let i = 0; while (compare(remainder, zero)) { const index = sortedIndices[i % sortedIndices.length]; shares[index] = calculator.add(shares[index], amount); const newRemainder = calculator.subtract(remainder, amount); if (equalFn(newRemainder, remainder)) break; remainder = newRemainder; i++; } return shares; }; } //#endregion //#region src/core/utils/isScaledAmount.ts function isScaledAmount(amount) { return amount?.hasOwnProperty("amount"); } //#endregion //#region src/core/utils/getAmountAndScale.ts function getAmountAndScale(value, zero) { if (isScaledAmount(value)) return { amount: value.amount, scale: value?.scale ?? zero }; return { amount: value, scale: zero }; } //#endregion //#region src/core/utils/getDivisors.ts function getDivisors(calculator) { const { multiply } = calculator; return (bases) => { return bases.reduce((divisors, _, i) => { const divisor = bases.slice(i).reduce((acc, curr) => multiply(acc, curr)); return [...divisors, divisor]; }, []); }; } //#endregion //#region src/core/utils/isEven.ts function isEven(calculator) { const equalFn = equal$2(calculator); const zero = calculator.zero(); const two = calculator.increment(calculator.increment(zero)); return (input) => { return equalFn(calculator.modulo(input, two), zero); }; } //#endregion //#region src/core/utils/isHalf.ts function isHalf(calculator) { const equalFn = equal$2(calculator); const absoluteFn = absolute(calculator); return (input, total) => { const remainder = absoluteFn(calculator.modulo(input, total)); return equalFn(calculator.subtract(total, remainder), remainder); }; } //#endregion //#region src/core/utils/lessThanOrEqual.ts /** * Returns a lessThanOrEqual function. * * @param calculator - The calculator to use. * * @returns The lessThanOrEqual function. */ function lessThanOrEqual$1(calculator) { return (subject, comparator) => { return lessThan$1(calculator)(subject, comparator) || equal$2(calculator)(subject, comparator); }; } //#endregion //#region src/core/utils/maximum.ts /** * Returns a maximum function. * * @param calculator - The calculator to use. * * @returns The maximum function. */ function maximum$1(calculator) { const lessThanFn = lessThan$1(calculator); return (values) => { return values.reduce((acc, curr) => { return lessThanFn(acc, curr) ? curr : acc; }); }; } //#endregion //#region src/core/utils/minimum.ts /** * Returns a minimum function. * * @param calculator - The calculator to use. * * @returns The minimum function. */ function minimum$1(calculator) { const greaterThanFn = greaterThan$1(calculator); return (values) => { return values.reduce((acc, curr) => { return greaterThanFn(acc, curr) ? curr : acc; }); }; } //#endregion //#region src/core/utils/sign.ts function sign(calculator) { const equalFn = equal$2(calculator); const lessThanFn = lessThan$1(calculator); const zero = calculator.zero(); return (input) => { if (equalFn(input, zero)) return zero; const one = calculator.increment(zero); const minusOne = calculator.decrement(zero); return lessThanFn(input, zero) ? minusOne : one; }; } //#endregion //#region src/core/api/haveSameCurrency.ts function haveSameCurrency$1(dineroObjects) { const [firstDinero, ...otherDineros] = dineroObjects; const computeBaseFn = computeBase(firstDinero.calculator); const { currency: comparator } = firstDinero.toJSON(); const equalFn = equal$2(firstDinero.calculator); const comparatorBase = computeBaseFn(comparator.base); return otherDineros.every((d) => { const { currency: subject } = d.toJSON(); const subjectBase = computeBaseFn(subject.base); return subject.code === comparator.code && equalFn(subjectBase, comparatorBase) && equalFn(subject.exponent, comparator.exponent); }); } //#endregion //#region src/core/divide/down.ts /** * Divide and round down. * * Rounding down happens whenever the quotient is not an integer. * * @param amount - The amount to divide. * @param factor - The factor to divide by. * @param calculator - The calculator to use. * * @returns The rounded amount. */ const down = (amount, factor, calculator) => { const greaterThanFn = greaterThan$1(calculator); const equalFn = equal$2(calculator); const zero = calculator.zero(); const isPositive = greaterThanFn(amount, zero); const quotient = calculator.integerDivide(amount, factor); const isInteger = equalFn(calculator.modulo(amount, factor), zero); if (isPositive || isInteger) return quotient; return calculator.decrement(quotient); }; //#endregion //#region src/core/divide/halfAwayFromZero.ts /** * Divide and round towards "nearest neighbor" unless both neighbors are * equidistant, in which case round away from zero. * * @param amount - The amount to divide. * @param factor - The factor to divide by. * @param calculator - The calculator to use. * * @returns The rounded amount. */ const halfAwayFromZero = (amount, factor, calculator) => { const signFn = sign(calculator); const isHalfFn = isHalf(calculator); const absoluteFn = absolute(calculator); if (!isHalfFn(amount, factor)) return halfUp(amount, factor, calculator); return calculator.multiply(signFn(amount), up(absoluteFn(amount), factor, calculator)); }; //#endregion //#region src/core/divide/halfDown.ts /** * Divide and round towards "nearest neighbor" unless both neighbors are * equidistant, in which case round down. * * Rounding down happens when: * - The quotient is half (e.g., -1.5, 1.5). * - The quotient is positive and less than half (e.g., 1.4). * - The quotient is negative and greater than half (e.g., -1.6). * * @param amount - The amount to divide. * @param factor - The factor to divide by. * @param calculator - The calculator to use. * * @returns The rounded amount. */ const halfDown = (amount, factor, calculator) => { if (isHalf(calculator)(amount, factor)) return down(amount, factor, calculator); return halfUp(amount, factor, calculator); }; //#endregion //#region src/core/divide/halfEven.ts /** * Divide and round towards "nearest neighbor" unless both neighbors are * equidistant, in which case round to the nearest even integer. * * @param amount - The amount to divide. * @param factor - The factor to divide by. * @param calculator - The calculator to use. * * @returns The rounded amount. */ const halfEven = (amount, factor, calculator) => { const isEvenFn = isEven(calculator); const isHalfFn = isHalf(calculator); const rounded = halfUp(amount, factor, calculator); if (!isHalfFn(amount, factor)) return rounded; return isEvenFn(rounded) ? rounded : calculator.decrement(rounded); }; //#endregion //#region src/core/divide/halfOdd.ts /** * Divide and round towards "nearest neighbor" unless both neighbors are * equidistant, in which case round to the nearest odd integer. * * @param amount - The amount to divide. * @param factor - The factor to divide by. * @param calculator - The calculator to use. * * @returns The rounded amount. */ const halfOdd = (amount, factor, calculator) => { const isEvenFn = isEven(calculator); const isHalfFn = isHalf(calculator); const rounded = halfUp(amount, factor, calculator); if (!isHalfFn(amount, factor)) return rounded; return isEvenFn(rounded) ? calculator.decrement(rounded) : rounded; }; //#endregion //#region src/core/divide/halfTowardsZero.ts /** * Divide and round towards "nearest neighbor" unless both neighbors are * equidistant, in which case round towards zero. * * @param amount - The amount to divide. * @param factor - The factor to divide by. * @param calculator - The calculator to use. * * @returns The rounded amount. */ const halfTowardsZero = (amount, factor, calculator) => { const signFn = sign(calculator); const isHalfFn = isHalf(calculator); const absoluteFn = absolute(calculator); if (!isHalfFn(amount, factor)) return halfUp(amount, factor, calculator); return calculator.multiply(signFn(amount), down(absoluteFn(amount), factor, calculator)); }; //#endregion //#region src/core/divide/halfUp.ts /** * Divide and round towards "nearest neighbor" unless both neighbors are * equidistant, in which case round up. * * Rounding up happens when: * - The quotient is half (e.g., -1.5, 1.5). * - The quotient is positive and greater than half (e.g., 1.6). * - The quotient is negative and less than half (e.g., -1.4). * * @param amount - The amount to divide. * @param factor - The factor to divide by. * @param calculator - The calculator to use. * * @returns The rounded amount. */ const halfUp = (amount, factor, calculator) => { const greaterThanFn = greaterThan$1(calculator); const isHalfFn = isHalf(calculator); const absoluteFn = absolute(calculator); const zero = calculator.zero(); const remainder = absoluteFn(calculator.modulo(amount, factor)); const isLessThanHalf = greaterThanFn(calculator.subtract(factor, remainder), remainder); const isPositive = greaterThanFn(amount, zero); if (isHalfFn(amount, factor) || isPositive && !isLessThanHalf || !isPositive && isLessThanHalf) return up(amount, factor, calculator); return down(amount, factor, calculator); }; //#endregion //#region src/core/divide/up.ts /** * Divide and round up. * * Rounding up happens whenever the quotient is not an integer. * * @param amount - The amount to divide. * @param factor - The factor to divide by. * @param calculator - The calculator to use. * * @returns The rounded amount. */ const up = (amount, factor, calculator) => { const greaterThanFn = greaterThan$1(calculator); const equalFn = equal$2(calculator); const zero = calculator.zero(); const isPositive = greaterThanFn(amount, zero); const quotient = calculator.integerDivide(amount, factor); if (!equalFn(calculator.modulo(amount, factor), zero) && isPositive) return calculator.increment(quotient); return quotient; }; //#endregion //#region src/core/api/transformScale.ts function transformScale$1(calculator) { const greaterThanFn = greaterThan$1(calculator); const computeBaseFn = computeBase(calculator); return function transformScaleFn(...[dineroObject, newScale, divide = down]) { const { amount, currency, scale } = dineroObject.toJSON(); const isLarger = greaterThanFn(newScale, scale); const operation = isLarger ? calculator.multiply : divide; const [a, b] = isLarger ? [newScale, scale] : [scale, newScale]; const base = computeBaseFn(currency.base); const factor = calculator.power(base, calculator.subtract(a, b)); return dineroObject.create({ amount: operation(amount, factor, calculator), currency, scale: newScale }); }; } //#endregion //#region src/core/api/normalizeScale.ts function normalizeScale$1(calculator) { const maximumFn = maximum$1(calculator); const convertScaleFn = transformScale$1(calculator); const equalFn = equal$2(calculator); return function _normalizeScale(...[dineroObjects]) { const highestScale = dineroObjects.reduce((highest, current) => { const { scale } = current.toJSON(); return maximumFn([highest, scale]); }, calculator.zero()); return dineroObjects.map((d) => { const { scale } = d.toJSON(); return !equalFn(scale, highestScale) ? convertScaleFn(d, highestScale) : d; }); }; } //#endregion //#region src/core/api/add.ts function unsafeAdd(calculator) { return function add(...[augend, addend]) { const { amount: augendAmount, currency, scale } = augend.toJSON(); const { amount: addendAmount } = addend.toJSON(); const amount = calculator.add(augendAmount, addendAmount); return augend.create({ amount, currency, scale }); }; } function safeAdd(calculator) { const normalizeFn = normalizeScale$1(calculator); const addFn = unsafeAdd(calculator); return function add(...[augend, addend]) { assert(haveSameCurrency$1([augend, addend]), UNEQUAL_CURRENCIES_MESSAGE); const [newAugend, newAddend] = normalizeFn([augend, addend]); return addFn(newAugend, newAddend); }; } //#endregion //#region src/core/api/allocate.ts function unsafeAllocate(calculator) { return function allocate(...[dineroObject, ratios]) { const { amount, currency, scale } = dineroObject.toJSON(); return distribute(calculator)(amount, ratios.map((ratio) => ratio.amount)).map((share) => { return dineroObject.create({ amount: share, currency, scale }); }); }; } function safeAllocate(calculator) { const allocateFn = unsafeAllocate(calculator); const greaterThanOrEqualFn = greaterThanOrEqual$1(calculator); const greaterThanFn = greaterThan$1(calculator); const convertScaleFn = transformScale$1(calculator); const maximumFn = maximum$1(calculator); const equalFn = equal$2(calculator); const zero = calculator.zero(); const ten = new Array(10).fill(null).reduce(calculator.increment, zero); return function allocate(...[dineroObject, ratios]) { const hasRatios = ratios.length > 0; const scaledRatios = ratios.map((ratio) => getAmountAndScale(ratio, zero)); const highestRatioScale = hasRatios ? maximumFn(scaledRatios.map(({ scale }) => scale)) : zero; const normalizedRatios = scaledRatios.map(({ amount, scale }) => { const factor = equalFn(scale, highestRatioScale) ? zero : calculator.subtract(highestRatioScale, scale); return { amount: calculator.multiply(amount, calculator.power(ten, factor)), scale }; }); const hasOnlyPositiveRatios = normalizedRatios.every(({ amount }) => greaterThanOrEqualFn(amount, zero)); const hasOneNonZeroRatio = normalizedRatios.some(({ amount }) => greaterThanFn(amount, zero)); assert(hasRatios && hasOnlyPositiveRatios && hasOneNonZeroRatio, INVALID_RATIOS_MESSAGE); const { scale } = dineroObject.toJSON(); return allocateFn(convertScaleFn(dineroObject, calculator.add(scale, highestRatioScale)), normalizedRatios); }; } //#endregion //#region src/core/api/compare.ts function unsafeCompare(calculator) { const compareFn = compare$2(calculator); return function compare(...[dineroObject, comparator]) { const [subjectAmount, comparatorAmount] = [dineroObject, comparator].map((d) => { const { amount } = d.toJSON(); return amount; }); return compareFn(subjectAmount, comparatorAmount); }; } function safeCompare(calculator) { const normalizeFn = normalizeScale$1(calculator); const compareFn = unsafeCompare(calculator); return function compare(...[dineroObject, comparator]) { assert(haveSameCurrency$1([dineroObject, comparator]), UNEQUAL_CURRENCIES_MESSAGE); const [subjectAmount, comparatorAmount] = normalizeFn([dineroObject, comparator]); return compareFn(subjectAmount, comparatorAmount); }; } //#endregion //#region src/core/api/convert.ts function convert$1(calculator) { const convertScaleFn = transformScale$1(calculator); const maximumFn = maximum$1(calculator); const computeBaseFn = computeBase(calculator); const equalFn = equal$2(calculator); const zero = calculator.zero(); return function convertFn(...[dineroObject, newCurrency, rates]) { const rate = rates[newCurrency.code]; const { amount, currency, scale } = dineroObject.toJSON(); assert(equalFn(computeBaseFn(currency.base), computeBaseFn(newCurrency.base)), MISMATCHED_BASES_MESSAGE); const { amount: rateAmount, scale: rateScale } = getAmountAndScale(rate, zero); const newScale = calculator.add(scale, rateScale); return convertScaleFn(dineroObject.create({ amount: calculator.multiply(amount, rateAmount), currency: newCurrency, scale: newScale }), maximumFn([newScale, newCurrency.exponent])); }; } //#endregion //#region src/core/api/haveSameAmount.ts function haveSameAmount$1(calculator) { const normalizeFn = normalizeScale$1(calculator); const equalFn = equal$2(calculator); return function _haveSameAmount(...[dineroObjects]) { const [firstDinero, ...otherDineros] = normalizeFn(dineroObjects); const { amount: comparatorAmount } = firstDinero.toJSON(); return otherDineros.every((d) => { const { amount: subjectAmount } = d.toJSON(); return equalFn(subjectAmount, comparatorAmount); }); }; } //#endregion //#region src/core/api/equal.ts function equal$1(calculator) { return function _equal(...[dineroObject, comparator]) { return haveSameAmount$1(calculator)([dineroObject, comparator]) && haveSameCurrency$1([dineroObject, comparator]); }; } //#endregion //#region src/core/api/greaterThan.ts function unsafeGreaterThan(calculator) { const greaterThanFn = greaterThan$1(calculator); return function greaterThan(...[dineroObject, comparator]) { const [subjectAmount, comparatorAmount] = [dineroObject, comparator].map((d) => { const { amount } = d.toJSON(); return amount; }); return greaterThanFn(subjectAmount, comparatorAmount); }; } function safeGreaterThan(calculator) { const normalizeFn = normalizeScale$1(calculator); const greaterThanFn = unsafeGreaterThan(calculator); return function greaterThan(...[dineroObject, comparator]) { assert(haveSameCurrency$1([dineroObject, comparator]), UNEQUAL_CURRENCIES_MESSAGE); const [subjectAmount, comparatorAmount] = normalizeFn([dineroObject, comparator]); return greaterThanFn(subjectAmount, comparatorAmount); }; } //#endregion //#region src/core/api/greaterThanOrEqual.ts function unsafeGreaterThanOrEqual(calculator) { const greaterThanOrEqualFn = greaterThanOrEqual$1(calculator); return function greaterThanOrEqual(...[dineroObject, comparator]) { const [subjectAmount, comparatorAmount] = [dineroObject, comparator].map((d) => { const { amount } = d.toJSON(); return amount; }); return greaterThanOrEqualFn(subjectAmount, comparatorAmount); }; } function safeGreaterThanOrEqual(calculator) { const normalizeFn = normalizeScale$1(calculator); const greaterThanOrEqualFn = unsafeGreaterThanOrEqual(calculator); return function greaterThanOrEqual(...[dineroObject, comparator]) { assert(haveSameCurrency$1([dineroObject, comparator]), UNEQUAL_CURRENCIES_MESSAGE); const [subjectAmount, comparatorAmount] = normalizeFn([dineroObject, comparator]); return greaterThanOrEqualFn(subjectAmount, comparatorAmount); }; } //#endregion //#region src/core/api/hasSubUnits.ts function hasSubUnits$1(calculator) { const equalFn = equal$2(calculator); const computeBaseFn = computeBase(calculator); return function _hasSubUnits(...[dineroObject]) { const { amount, currency, scale } = dineroObject.toJSON(); const base = computeBaseFn(currency.base); return !equalFn(calculator.modulo(amount, calculator.power(base, scale)), calculator.zero()); }; } //#endregion //#region src/core/api/isNegative.ts function isNegative$1(calculator) { const lessThanFn = lessThan$1(calculator); return function _isNegative(...[dineroObject]) { const { amount } = dineroObject.toJSON(); return lessThanFn(amount, calculator.zero()); }; } //#endregion //#region src/core/api/isPositive.ts function isPositive$1(calculator) { const greaterThanFn = greaterThan$1(calculator); return function _isPositive(...[dineroObject]) { const { amount } = dineroObject.toJSON(); return greaterThanFn(amount, calculator.zero()); }; } //#endregion //#region src/core/api/isZero.ts function isZero$1(calculator) { const equalFn = equal$2(calculator); return function _isZero(...[dineroObject]) { const { amount } = dineroObject.toJSON(); return equalFn(amount, calculator.zero()); }; } //#endregion //#region src/core/api/lessThan.ts function unsafeLessThan(calculator) { const lessThanFn = lessThan$1(calculator); return function lessThan(...[dineroObject, comparator]) { const [subjectAmount, comparatorAmount] = [dineroObject, comparator].map((d) => { const { amount } = d.toJSON(); return amount; }); return lessThanFn(subjectAmount, comparatorAmount); }; } function safeLessThan(calculator) { const normalizeFn = normalizeScale$1(calculator); const lessThanFn = unsafeLessThan(calculator); return function lessThan(...[dineroObject, comparator]) { assert(haveSameCurrency$1([dineroObject, comparator]), UNEQUAL_CURRENCIES_MESSAGE); const [subjectAmount, comparatorAmount] = normalizeFn([dineroObject, comparator]); return lessThanFn(subjectAmount, comparatorAmount); }; } //#endregion //#region src/core/api/lessThanOrEqual.ts function unsafeLessThanOrEqual(calculator) { const lessThanOrEqualFn = lessThanOrEqual$1(calculator); return function lessThanOrEqual(...[dineroObject, comparator]) { const [subjectAmount, comparatorAmount] = [dineroObject, comparator].map((d) => { const { amount } = d.toJSON(); return amount; }); return lessThanOrEqualFn(subjectAmount, comparatorAmount); }; } function safeLessThanOrEqual(calculator) { const normalizeFn = normalizeScale$1(calculator); const lessThanOrEqualFn = unsafeLessThanOrEqual(calculator); return function lessThanOrEqual(...[dineroObject, comparator]) { assert(haveSameCurrency$1([dineroObject, comparator]), UNEQUAL_CURRENCIES_MESSAGE); const [subjectAmount, comparatorAmount] = normalizeFn([dineroObject, comparator]); return lessThanOrEqualFn(subjectAmount, comparatorAmount); }; } //#endregion //#region src/core/api/maximum.ts function unsafeMaximum(calculator) { const maxFn = maximum$1(calculator); return function maximum(dineroObjects) { const [firstDinero] = dineroObjects; const { currency, scale } = firstDinero.toJSON(); const amount = maxFn(dineroObjects.map((subject) => { const { amount: subjectAmount } = subject.toJSON(); return subjectAmount; })); return firstDinero.create({ amount, currency, scale }); }; } function safeMaximum(calculator) { const normalizeFn = normalizeScale$1(calculator); const maxFn = unsafeMaximum(calculator); return function maximum(...[dineroObjects]) { assert(haveSameCurrency$1(dineroObjects), UNEQUAL_CURRENCIES_MESSAGE); return maxFn(normalizeFn([...dineroObjects])); }; } //#endregion //#region src/core/api/minimum.ts function unsafeMinimum(calculator) { const minFn = minimum$1(calculator); return function minimum(dineroObjects) { const [firstDinero] = dineroObjects; const { currency, scale } = firstDinero.toJSON(); const amount = minFn(dineroObjects.map((subject) => { const { amount: subjectAmount } = subject.toJSON(); return subjectAmount; })); return firstDinero.create({ amount, currency, scale }); }; } function safeMinimum(calculator) { const normalizeFn = normalizeScale$1(calculator); const minFn = unsafeMinimum(calculator); return function minimum(...[dineroObjects]) { assert(haveSameCurrency$1(dineroObjects), UNEQUAL_CURRENCIES_MESSAGE); return minFn(normalizeFn([...dineroObjects])); }; } //#endregion //#region src/core/api/multiply.ts function multiply$2(calculator) { const convertScaleFn = transformScale$1(calculator); const zero = calculator.zero(); return function multiplyFn(...[multiplicand, multiplier]) { const { amount, currency, scale } = multiplicand.toJSON(); const { amount: multiplierAmount, scale: multiplierScale } = getAmountAndScale(multiplier, zero); const newScale = calculator.add(scale, multiplierScale); return convertScaleFn(multiplicand.create({ amount: calculator.multiply(amount, multiplierAmount), currency, scale: newScale }), newScale); }; } //#endregion //#region src/core/api/subtract.ts function unsafeSubtract(calculator) { return function subtract(...[minuend, subtrahend]) { const { amount: minuendAmount, currency, scale } = minuend.toJSON(); const { amount: subtrahendAmount } = subtrahend.toJSON(); const amount = calculator.subtract(minuendAmount, subtrahendAmount); return minuend.create({ amount, currency, scale }); }; } function safeSubtract(calculator) { const normalizeFn = normalizeScale$1(calculator); const subtractFn = unsafeSubtract(calculator); return function subtract(...[minuend, subtrahend]) { assert(haveSameCurrency$1([minuend, subtrahend]), UNEQUAL_CURRENCIES_MESSAGE); const [newMinuend, newSubtrahend] = normalizeFn([minuend, subtrahend]); return subtractFn(newMinuend, newSubtrahend); }; } //#endregion //#region src/core/api/toUnits.ts function toUnits$1(calculator) { const getDivisorsFn = getDivisors(calculator); return function toUnitsFn(...[dineroObject, transformer]) { const { amount, currency, scale } = dineroObject.toJSON(); const { power, integerDivide, modulo } = calculator; const value = getDivisorsFn((isArray(currency.base) ? currency.base : [currency.base]).map((base) => power(base, scale))).reduce((amounts, divisor, index) => { const amountLeft = amounts[index]; const quotient = integerDivide(amountLeft, divisor); const remainder = modulo(amountLeft, divisor); return [ ...amounts.filter((_, i) => i !== index), quotient, remainder ]; }, [amount]); if (!transformer) return value; return transformer({ value, currency }); }; } //#endregion //#region src/core/api/toDecimal.ts function toDecimal$1(calculator) { const toUnitsFn = toUnits$1(calculator); const computeBaseFn = computeBase(calculator); const equalFn = equal$2(calculator); return function toDecimalFn(...[dineroObject, transformer]) { const { currency, scale } = dineroObject.toJSON(); const base = computeBaseFn(currency.base); const zero = calculator.zero(); const ten = new Array(10).fill(null).reduce(calculator.increment, zero); const isMultiBase = isArray(currency.base); const isBaseTen = equalFn(calculator.modulo(base, ten), zero); assert(!isMultiBase && isBaseTen, NON_DECIMAL_CURRENCY_MESSAGE); const units = toUnitsFn(dineroObject); const value = getDecimal(calculator, dineroObject.formatter)(units, scale); if (!transformer) return value; return transformer({ value, currency }); }; } function getDecimal(calculator, formatter) { const absoluteFn = absolute(calculator); const equalFn = equal$2(calculator); const lessThanFn = lessThan$1(calculator); const zero = calculator.zero(); return (units, scale) => { const whole = formatter.toString(units[0]); const fractional = formatter.toString(absoluteFn(units[1])); const scaleNumber = formatter.toNumber(scale); const decimal = `${whole}${scaleNumber > 0 ? `.${fractional.padStart(scaleNumber, "0")}` : ""}`; const leadsWithZero = equalFn(units[0], zero); const isNegative = lessThanFn(units[1], zero); return leadsWithZero && isNegative ? `-${decimal}` : decimal; }; } //#endregion //#region src/core/api/toSnapshot.ts function toSnapshot$1(dineroObject) { return dineroObject.toJSON(); } //#endregion //#region src/core/api/trimScale.ts function trimScale$1(calculator) { const countTrailingZerosFn = countTrailingZeros(calculator); const equalFn = equal$2(calculator); const maximumFn = maximum$1(calculator); const transformScaleFn = transformScale$1(calculator); const computeBaseFn = computeBase(calculator); return function trimScaleFn(...[dineroObject]) { const { amount, currency, scale } = dineroObject.toJSON(); const trailingZerosLength = countTrailingZerosFn(amount, computeBaseFn(currency.base)); const newScale = maximumFn([calculator.subtract(scale, trailingZerosLength), currency.exponent]); if (equalFn(newScale, scale)) return dineroObject; return transformScaleFn(dineroObject, newScale); }; } //#endregion //#region src/api/add.ts /** * Add up the passed Dinero objects. * * @param augend - The Dinero object to add to. * @param addend - The Dinero object to add. * * @returns A new Dinero object. * * @public */ function add(...[augend, addend]) { const { calculator } = augend; return safeAdd(calculator)(augend, addend); } //#endregion //#region src/api/allocate.ts /** * Distribute the amount of a Dinero object across a list of ratios. * * @param dineroObject - The Dinero object to allocate from. * @param ratios - The ratios to allocate the amount to. * * @returns A new Dinero object. * * @public */ function allocate(...[dineroObject, ratios]) { const { calculator } = dineroObject; return safeAllocate(calculator)(dineroObject, ratios); } //#endregion //#region src/api/compare.ts /** * Compare the value of a Dinero object relative to another. * * @param dineroObject - The Dinero object to compare. * @param comparator - The Dinero object to compare to. * * @returns One of -1, 0, or 1 depending on whether the first Dinero object is less than, equal to, or greater than the other. * * @public */ function compare(...[dineroObject, comparator]) { const { calculator } = dineroObject; return safeCompare(calculator)(dineroObject, comparator); } //#endregion //#region src/api/convert.ts /** * Convert a Dinero object to another currency. * * @param dineroObject - The Dinero object to format. * @param newCurrency - The currency to convert to. * @param rates - The rates to convert with. * * @returns A converted Dinero object. * * @public */ function convert(...[dineroObject, newCurrency, rates]) { const { calculator } = dineroObject; return convert$1(calculator)(dineroObject, newCurrency, rates); } //#endregion //#region src/api/equal.ts /** * Check whether the value of a Dinero object is equal to another. * * @param dineroObject - The first Dinero object to compare. * @param comparator - The second Dinero object to compare. * * @returns Whether the Dinero objects are equal. * * @public */ function equal(...[dineroObject, comparator]) { const { calculator } = dineroObject; return equal$1(calculator)(dineroObject, comparator); } //#endregion //#region src/api/greaterThan.ts /** * Check whether the value of a Dinero object is greater than another. * * @param dineroObject - The Dinero object to compare. * @param comparator - The Dinero object to compare to. * * @returns Whether the Dinero to compare is greater than the other. * * @public */ function greaterThan(...[dineroObject, comparator]) { const { calculator } = dineroObject; return safeGreaterThan(calculator)(dineroObject, comparator); } //#endregion //#region src/api/greaterThanOrEqual.ts /** * Check whether the value of a Dinero object is greater than or equal another. * * @param dineroObject - The Dinero object to compare. * @param comparator - The Dinero object to compare to. * * @returns Whether the Dinero to compare is greater than or equal the other. * * @public */ function greaterThanOrEqual(...[dineroObject, comparator]) { const { calculator } = dineroObject; return safeGreaterThanOrEqual(calculator)(dineroObject, comparator); } //#endregion //#region src/api/hasSubUnits.ts /** * Check whether a Dinero object has minor currency units. * * @param dineroObject - The Dinero object to check. * * @returns Whether the Dinero object has minor currency units. * * @public */ function hasSubUnits(...[dineroObject]) { const { calculator } = dineroObject; return hasSubUnits$1(calculator)(dineroObject); } //#endregion //#region src/api/haveSameAmount.ts /** * Check whether a set of Dinero objects have the same amount. * * @param dineroObjects - The Dinero objects to compare. * * @returns Whether the Dinero objects have the same amount. * * @public */ function haveSameAmount(...[dineroObjects]) { const { calculator } = dineroObjects[0]; return haveSameAmount$1(calculator)(dineroObjects); } //#endregion //#region src/api/haveSameCurrency.ts /** * Check whether a set of Dinero objects have the same currency. * * @param dineroObjects - The Dinero objects to compare. * * @returns Whether the Dinero objects have the same currency. * * @public */ const haveSameCurrency = haveSameCurrency$1; //#endregion //#region src/api/isNegative.ts /** * Check whether a Dinero object is negative. * * @param dineroObject - The Dinero object to check. * * @returns Whether the Dinero object is negative. * * @public */ function isNegative(...[dineroObject]) { const { calculator } = dineroObject; return isNegative$1(calculator)(dineroObject); } //#endregion //#region src/api/isPositive.ts /** * Check whether a Dinero object is positive. * * @param dineroObject - The Dinero object to check. * * @returns Whether the Dinero object is positive. * * @public */ function isPositive(...[dineroObject]) { const { calculator } = dineroObject; return isPositive$1(calculator)(dineroObject); } //#endregion //#region src/api/isZero.ts /** * Check whether the value of a Dinero object is zero. * * @param dineroObject - The Dinero object to check. * * @returns Whether the value of a Dinero object is zero. * * @public */ function isZero(...[dineroObject]) { const { calculator } = dineroObject; return isZero$1(calculator)(dineroObject); } //#endregion //#region src/api/lessThan.ts /** * Check whether the value of a Dinero object is lesser than another. * * @param dineroObject - The Dinero object to compare. * @param comparator - The Dinero object to compare to. * * @returns Whether the Dinero to compare is lesser than the other. * * @public */ function lessThan(...[dineroObject, comparator]) { const { calculator } = dineroObject; return safeLessThan(calculator)(dineroObject, comparator); } //#endregion //#region src/api/lessThanOrEqual.ts /** * Check whether the value of a Dinero object is lesser than or equal to another. * * @param dineroObject - The Dinero object to compare. * @param comparator - The Dinero object to compare to. * * @returns Whether the Dinero to compare is lesser than or equal to the other. * * @public */ function lessThanOrEqual(...[dineroObject, comparator]) { const { calculator } = dineroObject; return safeLessThanOrEqual(calculator)(dineroObject, comparator); } //#endregion //#region src/api/maximum.ts /** * Get the greatest of the passed Dinero objects. * * @param dineroObjects - The Dinero objects to maximum. * * @returns A new Dinero object. * * @public */ function maximum(...[dineroObjects]) { const { calculator } = dineroObjects[0]; return safeMaximum(calculator)(dineroObjects); } //#endregion //#region src/api/minimum.ts /** * Get the lowest of the passed Dinero objects. * * @param dineroObjects - The Dinero objects to minimum. * * @returns A new Dinero object. * * @public */ function minimum(...[dineroObjects]) { const { calculator } = dineroObjects[0]; return safeMinimum(calculator)(dineroObjects); } //#endregion //#region src/api/multiply.ts /** * Multiply the passed Dinero object. * * @param multiplicand - The Dinero object to multiply. * @param multiplier - The number to multiply with. * * @returns A new Dinero object. * * @public */ function multiply(...[multiplicand, multiplier]) { const { calculator } = multiplicand; return multiply$2(calculator)(multiplicand, multiplier); } //#endregion //#region src/api/normalizeScale.ts /** * Normalize a set of Dinero objects to the highest scale of the set. * * @param dineroObjects - The Dinero objects to normalize. * * @returns A new set of Dinero objects. * * @public */ function normalizeScale(...[dineroObjects]) { const { calculator } = dineroObjects[0]; return normalizeScale$1(calculator)(dineroObjects); } //#endregion //#region src/api/subtract.ts /** * Subtract the passed Dinero objects. * * @param minuend - The Dinero object to subtract from. * @param subtrahend - The Dinero object to subtract. * * @returns A new Dinero object. * * @public */ function subtract(...[minuend, subtrahend]) { const { calculator } = minuend; return safeSubtract(calculator)(minuend, subtrahend); } //#endregion //#region src/api/toDecimal.ts /** * Get the amount of a Dinero object in decimal form. * * @param dineroObject - The Dinero object to format. * @param transformer - A transformer function. * * @returns The amount in decimal form. * * @public */ function toDecimal(...[dineroObject, transformer]) { const { calculator } = dineroObject; return toDecimal$1(calculator)(dineroObject, transformer); } //#endregion //#region src/api/toSnapshot.ts /** * Get a snapshot of a Dinero object. * * @param dineroObject - The Dinero object to format. * @param transformer - A transformer function. * * @returns A snapshot of the object. * * @public */ const toSnapshot = toSnapshot$1; //#endregion //#region src/api/toUnits.ts /** * Get the amount of a Dinero object in units. * * @param dineroObject - The Dinero object to format. * @param transformer - A transformer function. * * @returns The amount in units. * * @public */ function toUnits(...[dineroObject, transformer]) { const { calculator } = dineroObject; return toUnits$1(calculator)(dineroObject, transformer); } //#endregion //#region src/api/transformScale.ts /** * Transform a Dinero object to a new scale. * * @param dineroObject - The Dinero object to transform. * @param newScale - The new scale. * @param divide - A custom divide function. * * @returns A new Dinero object. * * @public */ function transformScale(...[dineroObject, newScale, divide]) { const { calculator } = dineroObject; return transformScale$1(calculator)(dineroObject, newScale, divide); } //#endregion //#region src/api/trimScale.ts /** * Trim a Dinero object's scale as much as possible, down to the currency exponent. * * @param dineroObject - The Dinero object which scale to trim. * * @returns A new Dinero object. * * @public */ function trimScale(...[dineroObject]) { const { calculator } = dineroObject; return trimScale$1(calculator)(dineroObject); } //#endregion //#region src/currencies/iso4217.ts /** * United Arab Emirates dirham. */ const AED = { code: "AED", base: 10, exponent: 2 }; /** * Afghan afghani. */ const AFN = { code: "AFN", base: 10, exponent: 2 }; /** * Albanian lek. */ const ALL = { code: "ALL", base: 10, exponent: 2 }; /** * Armenian dram. */ const AMD = { code: "AMD", base: 10, exponent: 2 }; /** * Angolan kwanza. */ const AOA = { code: "AOA", base: 10, exponent: 2 }; /** * Argentine peso. */ const ARS = { code: "ARS", base: 10, exponent: 2 }; /** * Australian dollar. */ const AUD = { code: "AUD", base: 10, exponent: 2 }; /** * Aruban florin. */ const AWG = { code: "AWG", base: 10, exponent: 2 }; /** * Azerbaijani manat. */ const AZN = { code: "AZN", base: 10, exponent: 2 }; /** * Bosnia and Herzegovina convertible mark. */ const BAM = { code: "BAM", base: 10, exponent: 2 }; /** * Barbados dollar. */ const BBD = { code: "BBD", base: 10, exponent: 2 }; /** * Bangladeshi taka. */ const BDT = { code: "BDT", base: 10, exponent: 2 }; /** * Bulgarian lev. */ const BGN = { code: "BGN", base: 10, exponent: 2 }; /** * Bahraini dinar. */ const BHD = { code: "BHD", base: 10, exponent: 3 }; /** * Burundian franc. */ const BIF = { code: "BIF", base: 10, exponent: 0 }; /** * Bermudian dollar. */ const BMD = { code: "BMD", base: 10, exponent: 2 }; /** * Brunei dollar. */ const BND = { code: "BND", base: 10, exponent: 2 }; /** * Bolivian boliviano. */ const BOB = { code: "BOB", base: 10, exponent: 2 }; /** * Bolivian Mvdol. */ const BOV = { code: "BOV", base: 10, exponent: 2 }; /** * Brazilian real. */ const BRL = { code: "BRL", base: 10, exponent: 2 }; /** * Bahamian dollar. */ const BSD = { code: "BSD", base: 10, exponent: 2 }; /** * Bhutanese ngultrum. */ const BTN = { code: "BTN", base: 10, exponent: 2 }; /** * Botswana pula. */ const BWP = { code: "BWP", base: 10, exponent: 2 }; /** * Belarusian ruble. */ const BYN = { code: "BYN", base: 10, exponent: 2 }; /** * Belize dollar. */ const BZD = { code: "BZD", base: 10, exponent: 2 }; /** * Canadian dollar. */ const CAD = { code: "CAD", base: 10, exponent: 2 }; /** * Congolese franc. */ const CDF = { code: "CDF", base: 10, exponent: 2 }; /** * WIR Euro. */ const CHE = { code: "CHE", base: 10, exponent: 2 }; /** * Swiss franc. */ const CHF = { code: "CHF", base: 10, exponent: 2 }; /** * WIR Franc. */ const CHW = { code: "CHW", base: 10, exponent: 2 }; /** * Unidad de Fomento. */ const CLF = { code: "CLF", base: 10, exponent: 4 }; /** * Chilean peso. */ const CLP = { code: "CLP", base: 10, exponent: 0 }; /** * Renminbi (Chinese) yuan. */ const CNY = { code: "CNY", base: 10, exponent: 2 }; /** * Colombian peso. */ const COP = { code: "COP", base: 10, exponent: 2 }; /** * Unidad de Valor Real. */ const COU = { code: "COU", base: 10, exponent: 2 }; /** * Costa Rican colón. */ const CRC = { code: "CRC", base: 10, exponent: 2 }; /** * Cuban peso. */ const CUP = { code: "CUP", base: 10, exponent: 2 }; /** * Cape Verdean escudo. */ const CVE = { code: "CVE", base: 10, exponent: 2 }; /** * Czech koruna. */ const CZK = { code: "CZK", base: 10, exponent: 2 }; /** * Djiboutian franc. */ const DJF = { code: "DJF", base: 10, exponent: 0 }; /** * Danish krone. */ const DKK = { code: "DKK", base: 10, exponent: 2 }; /** * Dominican peso. */ const DOP = { code: "DOP", base: 10, exponent: 2 }; /** * Algerian dinar. */ const DZD = { code: "DZD", base: 10, exponent: 2 }; /** * Egyptian pound. */ const EGP = { code: "EGP", base: 10, exponent: 2 }; /** * Eritrean nakfa. */ const ERN = { code: "ERN", base: 10, exponent: 2 }; /** * Ethiopian birr. */ const ETB = { code: "ETB", base: 10, exponent: 2 }; /** * Euro. */ const EUR = { code: "EUR", base: 10, exponent: 2 }; /** * Fiji dollar. */ const FJD = { code: "FJD", base: 10, exponent: 2 }; /** * Falkland Islands pound. */ const FKP = { code: "FKP", base: 10, exponent: 2 }; /** * Pound sterling. */ const GBP = { code: "GBP", base: 10, exponent: 2 }; /** * Georgian lari. */ const GEL = { code: "GEL", base: 10, exponent: 2 }; /** * Ghanaian cedi. */ const GHS = { code: "GHS", base: 10, exponent: 2 }; /** * Gibraltar pound. */ const GIP = { code: "GIP", base: 10, exponent: 2 }; /** * Gambian dalasi. */ const GMD = { code: "GMD", base: 10, exponent: 2 }; /** * Guinean franc. */ const GNF = { code: "GNF", base: 10, exponent: 0 }; /** * Guatemalan quetzal. */ const GTQ = { code: "GTQ", base: 10, exponent: 2 }; /** * Guyanese dollar. */ const GYD = { code: "GYD", base: 10, exponent: 2 }; /** * Hong Kong dollar. */ const HKD = { code: "HKD", base: 10, exponent: 2 }; /** * Honduran lempira. */ const HNL = { code: "HNL", base: 10, exponent: 2 }; /** * Haitian gourde. */ const HTG = { code: "HTG", base: 10, exponent: 2 }; /** * Hungarian forint. */ const HUF = { code: "HUF", base: 10, exponent: 2 }; /** * Indonesian rupiah.