@vielzeug/coins 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -5
- package/dist/aggregate.cjs +1 -1
- package/dist/aggregate.cjs.map +1 -1
- package/dist/aggregate.d.ts +1 -4
- package/dist/aggregate.d.ts.map +1 -1
- package/dist/aggregate.js +22 -24
- package/dist/aggregate.js.map +1 -1
- package/dist/coins.cjs +1 -1
- package/dist/coins.cjs.map +1 -1
- package/dist/coins.iife.js +1 -1
- package/dist/coins.iife.js.map +1 -1
- package/dist/coins.js +1 -1
- package/dist/coins.js.map +1 -1
- package/dist/currency.cjs.map +1 -1
- package/dist/currency.d.ts.map +1 -1
- package/dist/currency.js.map +1 -1
- package/dist/decimal.cjs.map +1 -1
- package/dist/decimal.d.ts.map +1 -1
- package/dist/decimal.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +1 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -4
- package/dist/errors.js.map +1 -1
- package/dist/exchange.cjs.map +1 -1
- package/dist/exchange.d.ts.map +1 -1
- package/dist/exchange.js.map +1 -1
- package/dist/format.cjs +1 -1
- package/dist/format.cjs.map +1 -1
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +26 -26
- package/dist/format.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -8
- package/dist/money.cjs +1 -1
- package/dist/money.cjs.map +1 -1
- package/dist/money.d.ts +4 -0
- package/dist/money.d.ts.map +1 -1
- package/dist/money.js +36 -31
- package/dist/money.js.map +1 -1
- package/dist/serialization.cjs +1 -1
- package/dist/serialization.cjs.map +1 -1
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +1 -1
- package/dist/serialization.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +21 -17
package/dist/errors.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export type CoinsErrorCode =\n | 'CURRENCY_MISMATCH'\n | 'DIVISION_BY_ZERO'\n | 'INVALID_ALLOCATION'\n | 'INVALID_CURRENCY'\n | 'INVALID_DECIMAL'\n | 'INVALID_MONEY'\n | 'INVALID_ROUNDING';\n\nexport class CoinsError extends Error {\n readonly code: CoinsErrorCode;\n\n
|
|
1
|
+
{"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export type CoinsErrorCode =\n | 'CURRENCY_MISMATCH'\n | 'DIVISION_BY_ZERO'\n | 'FORMAT_ERROR'\n | 'INVALID_ALLOCATION'\n | 'INVALID_CURRENCY'\n | 'INVALID_DECIMAL'\n | 'INVALID_MONEY'\n | 'INVALID_ROUNDING';\n\nexport class CoinsError extends Error {\n readonly code: CoinsErrorCode;\n\n constructor(code: CoinsErrorCode, message: string, options?: ErrorOptions) {\n super(message, options);\n this.code = code;\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class CurrencyMismatchError extends CoinsError {\n readonly expected: string;\n readonly received: string;\n\n constructor(expected: string, received: string) {\n super('CURRENCY_MISMATCH', `Currency mismatch: ${expected} and ${received}`);\n this.expected = expected;\n this.received = received;\n }\n}\n\nexport class InvalidCurrencyError extends CoinsError {\n readonly value: unknown;\n\n constructor(value: unknown) {\n super('INVALID_CURRENCY', `Unsupported currency: \"${String(value)}\"`);\n this.value = value;\n }\n}\n"],"mappings":"AAUA,IAAa,EAAb,cAAgC,KAAM,CACpC,KAEA,YAAY,EAAsB,EAAiB,EAAwB,CACzE,MAAM,EAAS,CAAO,EACtB,KAAK,KAAO,EACZ,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAEa,EAAb,cAA2C,CAAW,CACpD,SACA,SAEA,YAAY,EAAkB,EAAkB,CAC9C,MAAM,oBAAqB,sBAAsB,EAAS,OAAO,GAAU,EAC3E,KAAK,SAAW,EAChB,KAAK,SAAW,CAClB,CACF,EAEa,EAAb,cAA0C,CAAW,CACnD,MAEA,YAAY,EAAgB,CAC1B,MAAM,mBAAoB,0BAA0B,OAAO,CAAK,EAAE,EAAE,EACpE,KAAK,MAAQ,CACf,CACF"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
export type CoinsErrorCode = 'CURRENCY_MISMATCH' | 'DIVISION_BY_ZERO' | 'INVALID_ALLOCATION' | 'INVALID_CURRENCY' | 'INVALID_DECIMAL' | 'INVALID_MONEY' | 'INVALID_ROUNDING';
|
|
1
|
+
export type CoinsErrorCode = 'CURRENCY_MISMATCH' | 'DIVISION_BY_ZERO' | 'FORMAT_ERROR' | 'INVALID_ALLOCATION' | 'INVALID_CURRENCY' | 'INVALID_DECIMAL' | 'INVALID_MONEY' | 'INVALID_ROUNDING';
|
|
2
2
|
export declare class CoinsError extends Error {
|
|
3
3
|
readonly code: CoinsErrorCode;
|
|
4
|
-
static is(error: unknown): error is CoinsError;
|
|
5
4
|
constructor(code: CoinsErrorCode, message: string, options?: ErrorOptions);
|
|
6
5
|
}
|
|
7
6
|
export declare class CurrencyMismatchError extends CoinsError {
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GACtB,mBAAmB,GACnB,kBAAkB,GAClB,oBAAoB,GACpB,kBAAkB,GAClB,iBAAiB,GACjB,eAAe,GACf,kBAAkB,CAAC;AAEvB,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GACtB,mBAAmB,GACnB,kBAAkB,GAClB,cAAc,GACd,oBAAoB,GACpB,kBAAkB,GAClB,iBAAiB,GACjB,eAAe,GACf,kBAAkB,CAAC;AAEvB,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;gBAElB,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAM1E;AAED,qBAAa,qBAAsB,SAAQ,UAAU;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAK/C;AAED,qBAAa,oBAAqB,SAAQ,UAAU;IAClD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBAEZ,KAAK,EAAE,OAAO;CAI3B"}
|
package/dist/errors.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
//#region src/errors.ts
|
|
2
|
-
var e = class
|
|
2
|
+
var e = class extends Error {
|
|
3
3
|
code;
|
|
4
|
-
static is(t) {
|
|
5
|
-
return t instanceof e;
|
|
6
|
-
}
|
|
7
4
|
constructor(e, t, n) {
|
|
8
5
|
super(t, n), this.code = e, this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
|
|
9
6
|
}
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export type CoinsErrorCode =\n | 'CURRENCY_MISMATCH'\n | 'DIVISION_BY_ZERO'\n | 'INVALID_ALLOCATION'\n | 'INVALID_CURRENCY'\n | 'INVALID_DECIMAL'\n | 'INVALID_MONEY'\n | 'INVALID_ROUNDING';\n\nexport class CoinsError extends Error {\n readonly code: CoinsErrorCode;\n\n
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export type CoinsErrorCode =\n | 'CURRENCY_MISMATCH'\n | 'DIVISION_BY_ZERO'\n | 'FORMAT_ERROR'\n | 'INVALID_ALLOCATION'\n | 'INVALID_CURRENCY'\n | 'INVALID_DECIMAL'\n | 'INVALID_MONEY'\n | 'INVALID_ROUNDING';\n\nexport class CoinsError extends Error {\n readonly code: CoinsErrorCode;\n\n constructor(code: CoinsErrorCode, message: string, options?: ErrorOptions) {\n super(message, options);\n this.code = code;\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class CurrencyMismatchError extends CoinsError {\n readonly expected: string;\n readonly received: string;\n\n constructor(expected: string, received: string) {\n super('CURRENCY_MISMATCH', `Currency mismatch: ${expected} and ${received}`);\n this.expected = expected;\n this.received = received;\n }\n}\n\nexport class InvalidCurrencyError extends CoinsError {\n readonly value: unknown;\n\n constructor(value: unknown) {\n super('INVALID_CURRENCY', `Unsupported currency: \"${String(value)}\"`);\n this.value = value;\n }\n}\n"],"mappings":";AAUA,IAAa,IAAb,cAAgC,MAAM;CACpC;CAEA,YAAY,GAAsB,GAAiB,GAAwB;EAIzE,AAHA,MAAM,GAAS,CAAO,GACtB,KAAK,OAAO,GACZ,KAAK,OAAO,WAAW,MACvB,OAAO,eAAe,MAAM,WAAW,SAAS;CAClD;AACF,GAEa,IAAb,cAA2C,EAAW;CACpD;CACA;CAEA,YAAY,GAAkB,GAAkB;EAG9C,AAFA,MAAM,qBAAqB,sBAAsB,EAAS,OAAO,GAAU,GAC3E,KAAK,WAAW,GAChB,KAAK,WAAW;CAClB;AACF,GAEa,IAAb,cAA0C,EAAW;CACnD;CAEA,YAAY,GAAgB;EAE1B,AADA,MAAM,oBAAoB,0BAA0B,OAAO,CAAK,EAAE,EAAE,GACpE,KAAK,QAAQ;CACf;AACF"}
|
package/dist/exchange.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exchange.cjs","names":[],"sources":["../src/exchange.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"exchange.cjs","names":[],"sources":["../src/exchange.ts"],"sourcesContent":["import { isCurrency } from './currency';\nimport { decimal, roundDivision } from './decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { isMoney, withMinor } from './money';\nimport type { Currency, ExchangeRate, Money, RoundingMode } from './types';\n\nexport function exchangeRate<From extends Currency, To extends Currency>({\n from,\n to,\n value,\n}: {\n from: From;\n to: To;\n value: string;\n}): ExchangeRate<From, To> {\n if (!isCurrency(from) || !isCurrency(to))\n throw new CoinsError('INVALID_CURRENCY', 'Exchange rate requires registered currencies');\n\n const parsed = decimal(value);\n\n if (parsed.numerator < 0n) throw new CoinsError('INVALID_DECIMAL', 'Exchange rates cannot be negative');\n\n return Object.freeze({ from, to, value: parsed });\n}\n\nexport function exchange<From extends Currency, To extends Currency>(\n value: Money<From>,\n rate: ExchangeRate<From, To>,\n options: { rounding?: RoundingMode } = {},\n): Money<To> {\n if (!isMoney(value) || !isValidRate(rate))\n throw new CoinsError('INVALID_MONEY', 'Exchange requires canonical money and rate values');\n\n if (value.currency !== rate.from) throw new CurrencyMismatchError(value.currency.code, rate.from.code);\n\n const numerator = value.amount * rate.value.numerator * 10n ** BigInt(rate.to.minorUnit);\n const denominator = rate.value.denominator * 10n ** BigInt(rate.from.minorUnit);\n\n return withMinor(roundDivision(numerator, denominator, options.rounding ?? 'halfAwayFromZero'), rate.to);\n}\n\nfunction isValidRate(value: unknown): value is ExchangeRate {\n if (typeof value !== 'object' || value === null || !Object.isFrozen(value)) return false;\n\n const rate = value as Partial<ExchangeRate>;\n\n return (\n isCurrency(rate.from) &&\n isCurrency(rate.to) &&\n typeof rate.value === 'object' &&\n rate.value !== null &&\n Object.isFrozen(rate.value) &&\n typeof rate.value.numerator === 'bigint' &&\n rate.value.numerator >= 0n &&\n typeof rate.value.denominator === 'bigint' &&\n rate.value.denominator > 0n\n );\n}\n"],"mappings":"gHAMA,SAAgB,EAAyD,CACvE,OACA,KACA,SAKyB,CACzB,GAAI,CAAC,EAAA,WAAW,CAAI,GAAK,CAAC,EAAA,WAAW,CAAE,EACrC,MAAM,IAAI,EAAA,WAAW,mBAAoB,8CAA8C,EAEzF,IAAM,EAAS,EAAA,QAAQ,CAAK,EAE5B,GAAI,EAAO,UAAY,GAAI,MAAM,IAAI,EAAA,WAAW,kBAAmB,mCAAmC,EAEtG,OAAO,OAAO,OAAO,CAAE,OAAM,KAAI,MAAO,CAAO,CAAC,CAClD,CAEA,SAAgB,EACd,EACA,EACA,EAAuC,CAAC,EAC7B,CACX,GAAI,CAAC,EAAA,QAAQ,CAAK,GAAK,CAAC,EAAY,CAAI,EACtC,MAAM,IAAI,EAAA,WAAW,gBAAiB,mDAAmD,EAE3F,GAAI,EAAM,WAAa,EAAK,KAAM,MAAM,IAAI,EAAA,sBAAsB,EAAM,SAAS,KAAM,EAAK,KAAK,IAAI,EAErG,IAAM,EAAY,EAAM,OAAS,EAAK,MAAM,UAAY,KAAO,OAAO,EAAK,GAAG,SAAS,EACjF,EAAc,EAAK,MAAM,YAAc,KAAO,OAAO,EAAK,KAAK,SAAS,EAE9E,OAAO,EAAA,UAAU,EAAA,cAAc,EAAW,EAAa,EAAQ,UAAY,kBAAkB,EAAG,EAAK,EAAE,CACzG,CAEA,SAAS,EAAY,EAAuC,CAC1D,GAAI,OAAO,GAAU,WAAY,GAAkB,CAAC,OAAO,SAAS,CAAK,EAAG,MAAO,GAEnF,IAAM,EAAO,EAEb,OACE,EAAA,WAAW,EAAK,IAAI,GACpB,EAAA,WAAW,EAAK,EAAE,GAClB,OAAO,EAAK,OAAU,UACtB,EAAK,QAAU,MACf,OAAO,SAAS,EAAK,KAAK,GAC1B,OAAO,EAAK,MAAM,WAAc,UAChC,EAAK,MAAM,WAAa,IACxB,OAAO,EAAK,MAAM,aAAgB,UAClC,EAAK,MAAM,YAAc,EAE7B"}
|
package/dist/exchange.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exchange.d.ts","sourceRoot":"","sources":["../src/exchange.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"exchange.d.ts","sourceRoot":"","sources":["../src/exchange.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE3E,wBAAgB,YAAY,CAAC,IAAI,SAAS,QAAQ,EAAE,EAAE,SAAS,QAAQ,EAAE,EACvE,IAAI,EACJ,EAAE,EACF,KAAK,GACN,EAAE;IACD,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,EAAE,CAAC;IACP,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,CASzB;AAED,wBAAgB,QAAQ,CAAC,IAAI,SAAS,QAAQ,EAAE,EAAE,SAAS,QAAQ,EACjE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,EAC5B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,YAAY,CAAA;CAAO,GACxC,KAAK,CAAC,EAAE,CAAC,CAUX"}
|
package/dist/exchange.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exchange.js","names":[],"sources":["../src/exchange.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"exchange.js","names":[],"sources":["../src/exchange.ts"],"sourcesContent":["import { isCurrency } from './currency';\nimport { decimal, roundDivision } from './decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { isMoney, withMinor } from './money';\nimport type { Currency, ExchangeRate, Money, RoundingMode } from './types';\n\nexport function exchangeRate<From extends Currency, To extends Currency>({\n from,\n to,\n value,\n}: {\n from: From;\n to: To;\n value: string;\n}): ExchangeRate<From, To> {\n if (!isCurrency(from) || !isCurrency(to))\n throw new CoinsError('INVALID_CURRENCY', 'Exchange rate requires registered currencies');\n\n const parsed = decimal(value);\n\n if (parsed.numerator < 0n) throw new CoinsError('INVALID_DECIMAL', 'Exchange rates cannot be negative');\n\n return Object.freeze({ from, to, value: parsed });\n}\n\nexport function exchange<From extends Currency, To extends Currency>(\n value: Money<From>,\n rate: ExchangeRate<From, To>,\n options: { rounding?: RoundingMode } = {},\n): Money<To> {\n if (!isMoney(value) || !isValidRate(rate))\n throw new CoinsError('INVALID_MONEY', 'Exchange requires canonical money and rate values');\n\n if (value.currency !== rate.from) throw new CurrencyMismatchError(value.currency.code, rate.from.code);\n\n const numerator = value.amount * rate.value.numerator * 10n ** BigInt(rate.to.minorUnit);\n const denominator = rate.value.denominator * 10n ** BigInt(rate.from.minorUnit);\n\n return withMinor(roundDivision(numerator, denominator, options.rounding ?? 'halfAwayFromZero'), rate.to);\n}\n\nfunction isValidRate(value: unknown): value is ExchangeRate {\n if (typeof value !== 'object' || value === null || !Object.isFrozen(value)) return false;\n\n const rate = value as Partial<ExchangeRate>;\n\n return (\n isCurrency(rate.from) &&\n isCurrency(rate.to) &&\n typeof rate.value === 'object' &&\n rate.value !== null &&\n Object.isFrozen(rate.value) &&\n typeof rate.value.numerator === 'bigint' &&\n rate.value.numerator >= 0n &&\n typeof rate.value.denominator === 'bigint' &&\n rate.value.denominator > 0n\n );\n}\n"],"mappings":";;;;;AAMA,SAAgB,EAAyD,EACvE,SACA,OACA,YAKyB;CACzB,IAAI,CAAC,EAAW,CAAI,KAAK,CAAC,EAAW,CAAE,GACrC,MAAM,IAAI,EAAW,oBAAoB,8CAA8C;CAEzF,IAAM,IAAS,EAAQ,CAAK;CAE5B,IAAI,EAAO,YAAY,IAAI,MAAM,IAAI,EAAW,mBAAmB,mCAAmC;CAEtG,OAAO,OAAO,OAAO;EAAE;EAAM;EAAI,OAAO;CAAO,CAAC;AAClD;AAEA,SAAgB,EACd,GACA,GACA,IAAuC,CAAC,GAC7B;CACX,IAAI,CAAC,EAAQ,CAAK,KAAK,CAAC,EAAY,CAAI,GACtC,MAAM,IAAI,EAAW,iBAAiB,mDAAmD;CAE3F,IAAI,EAAM,aAAa,EAAK,MAAM,MAAM,IAAI,EAAsB,EAAM,SAAS,MAAM,EAAK,KAAK,IAAI;CAErG,IAAM,IAAY,EAAM,SAAS,EAAK,MAAM,YAAY,OAAO,OAAO,EAAK,GAAG,SAAS,GACjF,IAAc,EAAK,MAAM,cAAc,OAAO,OAAO,EAAK,KAAK,SAAS;CAE9E,OAAO,EAAU,EAAc,GAAW,GAAa,EAAQ,YAAY,kBAAkB,GAAG,EAAK,EAAE;AACzG;AAEA,SAAS,EAAY,GAAuC;CAC1D,IAAI,OAAO,KAAU,aAAY,KAAkB,CAAC,OAAO,SAAS,CAAK,GAAG,OAAO;CAEnF,IAAM,IAAO;CAEb,OACE,EAAW,EAAK,IAAI,KACpB,EAAW,EAAK,EAAE,KAClB,OAAO,EAAK,SAAU,YACtB,EAAK,UAAU,QACf,OAAO,SAAS,EAAK,KAAK,KAC1B,OAAO,EAAK,MAAM,aAAc,YAChC,EAAK,MAAM,aAAa,MACxB,OAAO,EAAK,MAAM,eAAgB,YAClC,EAAK,MAAM,cAAc;AAE7B"}
|
package/dist/format.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./errors.cjs"),t=require("./decimal.cjs"),n=require("./money.cjs");var r=20,i=new Map,
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./decimal.cjs"),n=require("./money.cjs");var r=20,i=`halfAwayFromZero`,a=new Map,o=new Map;function s(e,t={}){return c(e,t).map(e=>e.value).join(``)}function c(r,a={}){if(!n.isMoney(r))throw new e.CoinsError(`INVALID_MONEY`,`format() requires canonical money`);let{locale:o=`en-US`,maximumFractionDigits:s=r.currency.minorUnit,minimumFractionDigits:c=r.currency.minorUnit,rounding:f=i,style:p=`symbol`}=a;l(c,s);let m=10n**BigInt(s),h=s>=r.currency.minorUnit?r.amount*10n**BigInt(s-r.currency.minorUnit):t.roundDivision(r.amount,10n**BigInt(r.currency.minorUnit-s),f),g=h<0n,_=g?-h:h,v=_/m,y=(s===0?``:(_%m).toString().padStart(s,`0`)).replace(RegExp(`0{0,${Math.max(0,s-c)}}$`),``),b=u(o,r.currency.code,p,g),x=[],S=!1;for(let e of b)e.type!==`group`&&(e.type===`integer`?S||=(x.push({type:`integer`,value:d(o).format(v)}),!0):e.type===`decimal`?y&&x.push({type:`decimal`,value:e.value}):e.type===`fraction`?y&&x.push({type:`fraction`,value:y}):e.type===`currency`||e.type===`minusSign`||e.type===`plusSign`?x.push({type:e.type,value:e.value}):x.push({type:`literal`,value:e.value}));return x}function l(t,n){if(!Number.isInteger(n)||!Number.isInteger(t)||t<0||n<t||n>r)throw new e.CoinsError(`FORMAT_ERROR`,`Fraction digits must be integers satisfying 0 ≤ minimum ≤ maximum ≤ ${r}`)}function u(t,n,r,i){let a=`${t}\0${n}\0${r}\0${i}`,s=o.get(a);if(s)return s;try{let e=new Intl.NumberFormat(t,{currency:n,currencyDisplay:r,maximumFractionDigits:1,minimumFractionDigits:1,style:`currency`}).formatToParts(i?-1.1:1.1);return o.set(a,e),e}catch(r){throw new e.CoinsError(`FORMAT_ERROR`,`Cannot format currency "${n}" for locale "${t}"`,{cause:r})}}function d(t){let n=a.get(t);if(n)return n;try{let e=new Intl.NumberFormat(t,{maximumFractionDigits:0,useGrouping:!0});return a.set(t,e),e}catch(n){throw new e.CoinsError(`FORMAT_ERROR`,`Cannot create number formatter for locale "${t}"`,{cause:n})}}exports.format=s,exports.formatParts=c;
|
|
2
2
|
//# sourceMappingURL=format.cjs.map
|
package/dist/format.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.cjs","names":[],"sources":["../src/format.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"format.cjs","names":[],"sources":["../src/format.ts"],"sourcesContent":["import { roundDivision } from './decimal';\nimport { CoinsError } from './errors';\nimport { isMoney } from './money';\nimport type { FormatOptions, Money, MoneyFormatPart, RoundingMode } from './types';\n\nconst MAX_FRACTION_DIGITS = 20;\nconst defaultFormatRounding: RoundingMode = 'halfAwayFromZero';\nconst integerFormatters = new Map<string, Intl.NumberFormat>();\nconst templates = new Map<string, Intl.NumberFormatPart[]>();\n\nexport function format(value: Money, options: FormatOptions = {}): string {\n return formatParts(value, options)\n .map((part) => part.value)\n .join('');\n}\n\nexport function formatParts(value: Money, options: FormatOptions = {}): MoneyFormatPart[] {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'format() requires canonical money');\n\n const {\n locale = 'en-US',\n maximumFractionDigits = value.currency.minorUnit,\n minimumFractionDigits = value.currency.minorUnit,\n rounding = defaultFormatRounding,\n style = 'symbol',\n } = options;\n\n validateFractionDigits(minimumFractionDigits, maximumFractionDigits);\n\n const targetScale = 10n ** BigInt(maximumFractionDigits);\n const scaled =\n maximumFractionDigits >= value.currency.minorUnit\n ? value.amount * 10n ** BigInt(maximumFractionDigits - value.currency.minorUnit)\n : roundDivision(value.amount, 10n ** BigInt(value.currency.minorUnit - maximumFractionDigits), rounding);\n const negative = scaled < 0n;\n const absolute = negative ? -scaled : scaled;\n const integer = absolute / targetScale;\n const rawFraction =\n maximumFractionDigits === 0 ? '' : (absolute % targetScale).toString().padStart(maximumFractionDigits, '0');\n const fraction = rawFraction.replace(\n new RegExp(`0{0,${Math.max(0, maximumFractionDigits - minimumFractionDigits)}}$`),\n '',\n );\n const template = getTemplate(locale, value.currency.code, style, negative);\n const parts: MoneyFormatPart[] = [];\n let insertedInteger = false;\n\n for (const part of template) {\n if (part.type === 'group') continue;\n\n if (part.type === 'integer') {\n if (!insertedInteger) {\n parts.push({ type: 'integer', value: getIntegerFormatter(locale).format(integer) });\n insertedInteger = true;\n }\n } else if (part.type === 'decimal') {\n if (fraction) parts.push({ type: 'decimal', value: part.value });\n } else if (part.type === 'fraction') {\n if (fraction) parts.push({ type: 'fraction', value: fraction });\n } else if (part.type === 'currency' || part.type === 'minusSign' || part.type === 'plusSign') {\n parts.push({ type: part.type, value: part.value });\n } else {\n parts.push({ type: 'literal', value: part.value });\n }\n }\n\n return parts;\n}\n\nfunction validateFractionDigits(minimum: number, maximum: number): void {\n if (\n !Number.isInteger(maximum) ||\n !Number.isInteger(minimum) ||\n minimum < 0 ||\n maximum < minimum ||\n maximum > MAX_FRACTION_DIGITS\n ) {\n throw new CoinsError(\n 'FORMAT_ERROR',\n `Fraction digits must be integers satisfying 0 ≤ minimum ≤ maximum ≤ ${MAX_FRACTION_DIGITS}`,\n );\n }\n}\n\nfunction getTemplate(\n locale: string,\n currency: string,\n style: NonNullable<FormatOptions['style']>,\n negative: boolean,\n): Intl.NumberFormatPart[] {\n const key = `${locale}\\0${currency}\\0${style}\\0${negative}`;\n const cached = templates.get(key);\n\n if (cached) return cached;\n\n try {\n const template = new Intl.NumberFormat(locale, {\n currency,\n currencyDisplay: style,\n maximumFractionDigits: 1,\n minimumFractionDigits: 1,\n style: 'currency',\n }).formatToParts(negative ? -1.1 : 1.1);\n\n templates.set(key, template);\n\n return template;\n } catch (error) {\n throw new CoinsError('FORMAT_ERROR', `Cannot format currency \"${currency}\" for locale \"${locale}\"`, {\n cause: error,\n });\n }\n}\n\nfunction getIntegerFormatter(locale: string): Intl.NumberFormat {\n const cached = integerFormatters.get(locale);\n\n if (cached) return cached;\n\n try {\n const formatter = new Intl.NumberFormat(locale, { maximumFractionDigits: 0, useGrouping: true });\n\n integerFormatters.set(locale, formatter);\n\n return formatter;\n } catch (error) {\n throw new CoinsError('FORMAT_ERROR', `Cannot create number formatter for locale \"${locale}\"`, { cause: error });\n }\n}\n"],"mappings":"oFAKA,IAAM,EAAsB,GACtB,EAAsC,mBACtC,EAAoB,IAAI,IACxB,EAAY,IAAI,IAEtB,SAAgB,EAAO,EAAc,EAAyB,CAAC,EAAW,CACxE,OAAO,EAAY,EAAO,CAAO,CAAC,CAC/B,IAAK,GAAS,EAAK,KAAK,CAAC,CACzB,KAAK,EAAE,CACZ,CAEA,SAAgB,EAAY,EAAc,EAAyB,CAAC,EAAsB,CACxF,GAAI,CAAC,EAAA,QAAQ,CAAK,EAAG,MAAM,IAAI,EAAA,WAAW,gBAAiB,mCAAmC,EAE9F,GAAM,CACJ,SAAS,QACT,wBAAwB,EAAM,SAAS,UACvC,wBAAwB,EAAM,SAAS,UACvC,WAAW,EACX,QAAQ,UACN,EAEJ,EAAuB,EAAuB,CAAqB,EAEnE,IAAM,EAAc,KAAO,OAAO,CAAqB,EACjD,EACJ,GAAyB,EAAM,SAAS,UACpC,EAAM,OAAS,KAAO,OAAO,EAAwB,EAAM,SAAS,SAAS,EAC7E,EAAA,cAAc,EAAM,OAAQ,KAAO,OAAO,EAAM,SAAS,UAAY,CAAqB,EAAG,CAAQ,EACrG,EAAW,EAAS,GACpB,EAAW,EAAW,CAAC,EAAS,EAChC,EAAU,EAAW,EAGrB,GADJ,IAA0B,EAAI,IAAM,EAAW,EAAA,CAAa,SAAS,CAAC,CAAC,SAAS,EAAuB,GAAG,EAAA,CAC/E,QACvB,OAAO,OAAO,KAAK,IAAI,EAAG,EAAwB,CAAqB,EAAE,GAAG,EAChF,EACF,EACM,EAAW,EAAY,EAAQ,EAAM,SAAS,KAAM,EAAO,CAAQ,EACnE,EAA2B,CAAC,EAC9B,EAAkB,GAEtB,IAAK,IAAM,KAAQ,EACb,EAAK,OAAS,UAEd,EAAK,OAAS,UACZ,AAEF,KADA,EAAM,KAAK,CAAE,KAAM,UAAW,MAAO,EAAoB,CAAM,CAAC,CAAC,OAAO,CAAO,CAAE,CAAC,EAChE,IAEX,EAAK,OAAS,UACnB,GAAU,EAAM,KAAK,CAAE,KAAM,UAAW,MAAO,EAAK,KAAM,CAAC,EACtD,EAAK,OAAS,WACnB,GAAU,EAAM,KAAK,CAAE,KAAM,WAAY,MAAO,CAAS,CAAC,EACrD,EAAK,OAAS,YAAc,EAAK,OAAS,aAAe,EAAK,OAAS,WAChF,EAAM,KAAK,CAAE,KAAM,EAAK,KAAM,MAAO,EAAK,KAAM,CAAC,EAEjD,EAAM,KAAK,CAAE,KAAM,UAAW,MAAO,EAAK,KAAM,CAAC,GAIrD,OAAO,CACT,CAEA,SAAS,EAAuB,EAAiB,EAAuB,CACtE,GACE,CAAC,OAAO,UAAU,CAAO,GACzB,CAAC,OAAO,UAAU,CAAO,GACzB,EAAU,GACV,EAAU,GACV,EAAU,EAEV,MAAM,IAAI,EAAA,WACR,eACA,uEAAuE,GACzE,CAEJ,CAEA,SAAS,EACP,EACA,EACA,EACA,EACyB,CACzB,IAAM,EAAM,GAAG,EAAO,IAAI,EAAS,IAAI,EAAM,IAAI,IAC3C,EAAS,EAAU,IAAI,CAAG,EAEhC,GAAI,EAAQ,OAAO,EAEnB,GAAI,CACF,IAAM,EAAW,IAAI,KAAK,aAAa,EAAQ,CAC7C,WACA,gBAAiB,EACjB,sBAAuB,EACvB,sBAAuB,EACvB,MAAO,UACT,CAAC,CAAC,CAAC,cAAc,EAAW,KAAO,GAAG,EAItC,OAFA,EAAU,IAAI,EAAK,CAAQ,EAEpB,CACT,OAAS,EAAO,CACd,MAAM,IAAI,EAAA,WAAW,eAAgB,2BAA2B,EAAS,gBAAgB,EAAO,GAAI,CAClG,MAAO,CACT,CAAC,CACH,CACF,CAEA,SAAS,EAAoB,EAAmC,CAC9D,IAAM,EAAS,EAAkB,IAAI,CAAM,EAE3C,GAAI,EAAQ,OAAO,EAEnB,GAAI,CACF,IAAM,EAAY,IAAI,KAAK,aAAa,EAAQ,CAAE,sBAAuB,EAAG,YAAa,EAAK,CAAC,EAI/F,OAFA,EAAkB,IAAI,EAAQ,CAAS,EAEhC,CACT,OAAS,EAAO,CACd,MAAM,IAAI,EAAA,WAAW,eAAgB,8CAA8C,EAAO,GAAI,CAAE,MAAO,CAAM,CAAC,CAChH,CACF"}
|
package/dist/format.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,eAAe,EAAgB,MAAM,SAAS,CAAC;AAOnF,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAIxE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,GAAE,aAAkB,GAAG,eAAe,EAAE,CAmDxF"}
|
package/dist/format.js
CHANGED
|
@@ -2,38 +2,38 @@ import { CoinsError as e } from "./errors.js";
|
|
|
2
2
|
import { roundDivision as t } from "./decimal.js";
|
|
3
3
|
import { isMoney as n } from "./money.js";
|
|
4
4
|
//#region src/format.ts
|
|
5
|
-
var r = 20, i = /* @__PURE__ */ new Map(),
|
|
6
|
-
function
|
|
7
|
-
return
|
|
5
|
+
var r = 20, i = "halfAwayFromZero", a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
|
|
6
|
+
function s(e, t = {}) {
|
|
7
|
+
return c(e, t).map((e) => e.value).join("");
|
|
8
8
|
}
|
|
9
|
-
function
|
|
9
|
+
function c(r, a = {}) {
|
|
10
10
|
if (!n(r)) throw new e("INVALID_MONEY", "format() requires canonical money");
|
|
11
|
-
let { locale:
|
|
12
|
-
c
|
|
13
|
-
let
|
|
14
|
-
for (let e of
|
|
11
|
+
let { locale: o = "en-US", maximumFractionDigits: s = r.currency.minorUnit, minimumFractionDigits: c = r.currency.minorUnit, rounding: f = i, style: p = "symbol" } = a;
|
|
12
|
+
l(c, s);
|
|
13
|
+
let m = 10n ** BigInt(s), h = s >= r.currency.minorUnit ? r.amount * 10n ** BigInt(s - r.currency.minorUnit) : t(r.amount, 10n ** BigInt(r.currency.minorUnit - s), f), g = h < 0n, _ = g ? -h : h, v = _ / m, y = (s === 0 ? "" : (_ % m).toString().padStart(s, "0")).replace(RegExp(`0{0,${Math.max(0, s - c)}}$`), ""), b = u(o, r.currency.code, p, g), x = [], S = !1;
|
|
14
|
+
for (let e of b) e.type !== "group" && (e.type === "integer" ? S ||= (x.push({
|
|
15
15
|
type: "integer",
|
|
16
|
-
value:
|
|
17
|
-
}), !0) : e.type === "decimal" ?
|
|
16
|
+
value: d(o).format(v)
|
|
17
|
+
}), !0) : e.type === "decimal" ? y && x.push({
|
|
18
18
|
type: "decimal",
|
|
19
19
|
value: e.value
|
|
20
|
-
}) : e.type === "fraction" ?
|
|
20
|
+
}) : e.type === "fraction" ? y && x.push({
|
|
21
21
|
type: "fraction",
|
|
22
|
-
value:
|
|
23
|
-
}) : e.type === "currency" || e.type === "minusSign" || e.type === "plusSign" ?
|
|
22
|
+
value: y
|
|
23
|
+
}) : e.type === "currency" || e.type === "minusSign" || e.type === "plusSign" ? x.push({
|
|
24
24
|
type: e.type,
|
|
25
25
|
value: e.value
|
|
26
|
-
}) :
|
|
26
|
+
}) : x.push({
|
|
27
27
|
type: "literal",
|
|
28
28
|
value: e.value
|
|
29
29
|
}));
|
|
30
|
-
return
|
|
30
|
+
return x;
|
|
31
31
|
}
|
|
32
|
-
function
|
|
33
|
-
if (!Number.isInteger(n) || !Number.isInteger(t) || t < 0 || n < t || n > r) throw new e("
|
|
32
|
+
function l(t, n) {
|
|
33
|
+
if (!Number.isInteger(n) || !Number.isInteger(t) || t < 0 || n < t || n > r) throw new e("FORMAT_ERROR", `Fraction digits must be integers satisfying 0 ≤ minimum ≤ maximum ≤ ${r}`);
|
|
34
34
|
}
|
|
35
|
-
function
|
|
36
|
-
let
|
|
35
|
+
function u(t, n, r, i) {
|
|
36
|
+
let a = `${t}\0${n}\0${r}\0${i}`, s = o.get(a);
|
|
37
37
|
if (s) return s;
|
|
38
38
|
try {
|
|
39
39
|
let e = new Intl.NumberFormat(t, {
|
|
@@ -43,25 +43,25 @@ function l(t, n, r, i) {
|
|
|
43
43
|
minimumFractionDigits: 1,
|
|
44
44
|
style: "currency"
|
|
45
45
|
}).formatToParts(i ? -1.1 : 1.1);
|
|
46
|
-
return
|
|
46
|
+
return o.set(a, e), e;
|
|
47
47
|
} catch (r) {
|
|
48
|
-
throw new e("
|
|
48
|
+
throw new e("FORMAT_ERROR", `Cannot format currency "${n}" for locale "${t}"`, { cause: r });
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
function
|
|
52
|
-
let n =
|
|
51
|
+
function d(t) {
|
|
52
|
+
let n = a.get(t);
|
|
53
53
|
if (n) return n;
|
|
54
54
|
try {
|
|
55
55
|
let e = new Intl.NumberFormat(t, {
|
|
56
56
|
maximumFractionDigits: 0,
|
|
57
57
|
useGrouping: !0
|
|
58
58
|
});
|
|
59
|
-
return
|
|
59
|
+
return a.set(t, e), e;
|
|
60
60
|
} catch (n) {
|
|
61
|
-
throw new e("
|
|
61
|
+
throw new e("FORMAT_ERROR", `Cannot create number formatter for locale "${t}"`, { cause: n });
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
//#endregion
|
|
65
|
-
export {
|
|
65
|
+
export { s as format, c as formatParts };
|
|
66
66
|
|
|
67
67
|
//# sourceMappingURL=format.js.map
|
package/dist/format.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","names":[],"sources":["../src/format.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"format.js","names":[],"sources":["../src/format.ts"],"sourcesContent":["import { roundDivision } from './decimal';\nimport { CoinsError } from './errors';\nimport { isMoney } from './money';\nimport type { FormatOptions, Money, MoneyFormatPart, RoundingMode } from './types';\n\nconst MAX_FRACTION_DIGITS = 20;\nconst defaultFormatRounding: RoundingMode = 'halfAwayFromZero';\nconst integerFormatters = new Map<string, Intl.NumberFormat>();\nconst templates = new Map<string, Intl.NumberFormatPart[]>();\n\nexport function format(value: Money, options: FormatOptions = {}): string {\n return formatParts(value, options)\n .map((part) => part.value)\n .join('');\n}\n\nexport function formatParts(value: Money, options: FormatOptions = {}): MoneyFormatPart[] {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'format() requires canonical money');\n\n const {\n locale = 'en-US',\n maximumFractionDigits = value.currency.minorUnit,\n minimumFractionDigits = value.currency.minorUnit,\n rounding = defaultFormatRounding,\n style = 'symbol',\n } = options;\n\n validateFractionDigits(minimumFractionDigits, maximumFractionDigits);\n\n const targetScale = 10n ** BigInt(maximumFractionDigits);\n const scaled =\n maximumFractionDigits >= value.currency.minorUnit\n ? value.amount * 10n ** BigInt(maximumFractionDigits - value.currency.minorUnit)\n : roundDivision(value.amount, 10n ** BigInt(value.currency.minorUnit - maximumFractionDigits), rounding);\n const negative = scaled < 0n;\n const absolute = negative ? -scaled : scaled;\n const integer = absolute / targetScale;\n const rawFraction =\n maximumFractionDigits === 0 ? '' : (absolute % targetScale).toString().padStart(maximumFractionDigits, '0');\n const fraction = rawFraction.replace(\n new RegExp(`0{0,${Math.max(0, maximumFractionDigits - minimumFractionDigits)}}$`),\n '',\n );\n const template = getTemplate(locale, value.currency.code, style, negative);\n const parts: MoneyFormatPart[] = [];\n let insertedInteger = false;\n\n for (const part of template) {\n if (part.type === 'group') continue;\n\n if (part.type === 'integer') {\n if (!insertedInteger) {\n parts.push({ type: 'integer', value: getIntegerFormatter(locale).format(integer) });\n insertedInteger = true;\n }\n } else if (part.type === 'decimal') {\n if (fraction) parts.push({ type: 'decimal', value: part.value });\n } else if (part.type === 'fraction') {\n if (fraction) parts.push({ type: 'fraction', value: fraction });\n } else if (part.type === 'currency' || part.type === 'minusSign' || part.type === 'plusSign') {\n parts.push({ type: part.type, value: part.value });\n } else {\n parts.push({ type: 'literal', value: part.value });\n }\n }\n\n return parts;\n}\n\nfunction validateFractionDigits(minimum: number, maximum: number): void {\n if (\n !Number.isInteger(maximum) ||\n !Number.isInteger(minimum) ||\n minimum < 0 ||\n maximum < minimum ||\n maximum > MAX_FRACTION_DIGITS\n ) {\n throw new CoinsError(\n 'FORMAT_ERROR',\n `Fraction digits must be integers satisfying 0 ≤ minimum ≤ maximum ≤ ${MAX_FRACTION_DIGITS}`,\n );\n }\n}\n\nfunction getTemplate(\n locale: string,\n currency: string,\n style: NonNullable<FormatOptions['style']>,\n negative: boolean,\n): Intl.NumberFormatPart[] {\n const key = `${locale}\\0${currency}\\0${style}\\0${negative}`;\n const cached = templates.get(key);\n\n if (cached) return cached;\n\n try {\n const template = new Intl.NumberFormat(locale, {\n currency,\n currencyDisplay: style,\n maximumFractionDigits: 1,\n minimumFractionDigits: 1,\n style: 'currency',\n }).formatToParts(negative ? -1.1 : 1.1);\n\n templates.set(key, template);\n\n return template;\n } catch (error) {\n throw new CoinsError('FORMAT_ERROR', `Cannot format currency \"${currency}\" for locale \"${locale}\"`, {\n cause: error,\n });\n }\n}\n\nfunction getIntegerFormatter(locale: string): Intl.NumberFormat {\n const cached = integerFormatters.get(locale);\n\n if (cached) return cached;\n\n try {\n const formatter = new Intl.NumberFormat(locale, { maximumFractionDigits: 0, useGrouping: true });\n\n integerFormatters.set(locale, formatter);\n\n return formatter;\n } catch (error) {\n throw new CoinsError('FORMAT_ERROR', `Cannot create number formatter for locale \"${locale}\"`, { cause: error });\n }\n}\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./errors.cjs"),t=require("./
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./errors.cjs"),t=require("./currency.cjs"),n=require("./money.cjs"),r=require("./aggregate.cjs"),i=require("./exchange.cjs"),a=require("./format.cjs"),o=require("./serialization.cjs");exports.BHD=t.BHD,exports.CoinsError=e.CoinsError,exports.CurrencyMismatchError=e.CurrencyMismatchError,exports.EUR=t.EUR,exports.GBP=t.GBP,exports.InvalidCurrencyError=e.InvalidCurrencyError,exports.JPY=t.JPY,exports.KRW=t.KRW,exports.KWD=t.KWD,exports.USD=t.USD,exports.abs=n.abs,exports.add=n.add,exports.allocate=r.allocate,exports.clamp=n.clamp,exports.compare=n.compare,exports.currency=t.currency,exports.defineCurrency=t.defineCurrency,exports.divide=n.divide,exports.exchange=i.exchange,exports.exchangeRate=i.exchangeRate,exports.format=a.format,exports.formatParts=a.formatParts,exports.isCurrency=t.isCurrency,exports.isMoney=n.isMoney,exports.money=n.money,exports.multiply=n.multiply,exports.negate=n.negate,exports.parseMoney=n.parseMoney,exports.parseMoneyJSON=o.parseMoneyJSON,exports.round=n.round,exports.subtract=n.subtract,exports.sum=r.sum,exports.toDecimal=n.toDecimal,exports.toJSON=o.toJSON;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { allocate, sum } from './aggregate';
|
|
2
2
|
export { BHD, currency, defineCurrency, EUR, GBP, isCurrency, JPY, KRW, KWD, USD } from './currency';
|
|
3
|
-
export { decimal } from './decimal';
|
|
4
|
-
export { CoinsError, CurrencyMismatchError, InvalidCurrencyError } from './errors';
|
|
5
3
|
export type { CoinsErrorCode } from './errors';
|
|
4
|
+
export { CoinsError, CurrencyMismatchError, InvalidCurrencyError } from './errors';
|
|
6
5
|
export { exchange, exchangeRate } from './exchange';
|
|
7
6
|
export { format, formatParts } from './format';
|
|
8
|
-
export { abs, add, compare, divide, isMoney, money, multiply, negate, parseMoney, round, subtract, toDecimal, } from './money';
|
|
7
|
+
export { abs, add, clamp, compare, divide, isMoney, money, multiply, negate, parseMoney, round, subtract, toDecimal, } from './money';
|
|
9
8
|
export { parseMoneyJSON, toJSON } from './serialization';
|
|
10
9
|
export type { Currency, CurrencyCode, Decimal, ExchangeRate, FormatOptions, Money, MoneyFormatPart, MoneyJSON, RoundingMode, } from './types';
|
|
11
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACrG,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AACnF,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EACL,GAAG,EACH,GAAG,EACH,KAAK,EACL,OAAO,EACP,MAAM,EACN,OAAO,EACP,KAAK,EACL,QAAQ,EACR,MAAM,EACN,UAAU,EACV,KAAK,EACL,QAAQ,EACR,SAAS,GACV,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzD,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,YAAY,EACZ,aAAa,EACb,KAAK,EACL,eAAe,EACf,SAAS,EACT,YAAY,GACb,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { CoinsError as e, CurrencyMismatchError as t, InvalidCurrencyError as n } from "./errors.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
export { i as BHD, e as CoinsError, t as CurrencyMismatchError, a as EUR, o as GBP, n as InvalidCurrencyError, s as JPY, c as KRW, l as KWD, u as USD, m as abs, h as add, E as allocate, D as clamp, g as compare, d as currency, r as decimal, f as defineCurrency, _ as divide, k as exchange, A as exchangeRate, j as format, M as formatParts, p as isCurrency, v as isMoney, y as money, b as multiply, x as negate, S as parseMoney, N as parseMoneyJSON, C as round, w as subtract, O as sum, T as toDecimal, P as toJSON };
|
|
2
|
+
import { BHD as r, EUR as i, GBP as a, JPY as o, KRW as s, KWD as c, USD as l, currency as u, defineCurrency as d, isCurrency as f } from "./currency.js";
|
|
3
|
+
import { abs as p, add as m, clamp as h, compare as g, divide as _, isMoney as v, money as y, multiply as b, negate as x, parseMoney as S, round as C, subtract as w, toDecimal as T } from "./money.js";
|
|
4
|
+
import { allocate as E, sum as D } from "./aggregate.js";
|
|
5
|
+
import { exchange as O, exchangeRate as k } from "./exchange.js";
|
|
6
|
+
import { format as A, formatParts as j } from "./format.js";
|
|
7
|
+
import { parseMoneyJSON as M, toJSON as N } from "./serialization.js";
|
|
8
|
+
export { r as BHD, e as CoinsError, t as CurrencyMismatchError, i as EUR, a as GBP, n as InvalidCurrencyError, o as JPY, s as KRW, c as KWD, l as USD, p as abs, m as add, E as allocate, h as clamp, g as compare, u as currency, d as defineCurrency, _ as divide, O as exchange, k as exchangeRate, A as format, j as formatParts, f as isCurrency, v as isMoney, y as money, b as multiply, x as negate, S as parseMoney, M as parseMoneyJSON, C as round, w as subtract, D as sum, T as toDecimal, N as toJSON };
|
package/dist/money.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./errors.cjs"),t=require("./decimal.cjs"),n=require("./currency.cjs");var r=`halfAwayFromZero`;function i(n,i,a){if(
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./decimal.cjs"),n=require("./currency.cjs");var r=`halfAwayFromZero`;function i(n,i,a){if(x(i),typeof n==`bigint`){if(!a||!(`unit`in a)||a.unit!==`minor`)throw new e.CoinsError(`INVALID_MONEY`,`Bigint amounts require { unit: 'minor' }`);return v(n,i)}if(a&&`unit`in a)throw new e.CoinsError(`INVALID_MONEY`,`Decimal strings do not accept a unit option`);let o=t.decimal(n),s=o.numerator*10n**BigInt(i.minorUnit);if(s%o.denominator!==0n&&!a)throw new e.CoinsError(`INVALID_MONEY`,`Amount "${n}" exceeds ${i.code} precision; provide rounding`);return v(t.roundDivision(s,o.denominator,a?.rounding??r),i)}function a(t){if(!S(t))throw new e.CoinsError(`INVALID_MONEY`,`Money must be a plain data object`);let r=Object.getOwnPropertyDescriptors(t),i=r.amount,a=r.currency;if(!C(i)||!C(a))throw new e.CoinsError(`INVALID_MONEY`,`Money properties must be plain data values`);if(typeof i.value!=`bigint`||!n.isCurrency(a.value))throw new e.CoinsError(`INVALID_MONEY`,`Money must contain bigint amount and a registered currency`);return v(i.value,a.value)}function o(e){try{return a(e),!0}catch{return!1}}function s(e,t){return b(e,t),v(e.amount+t.amount,e.currency)}function c(e,t){return b(e,t),v(e.amount-t.amount,e.currency)}function l(e,n,i={}){y(e);let a=t.decimal(n);return v(t.roundDivision(e.amount*a.numerator,a.denominator,i.rounding??r),e.currency)}function u(n,i,a={}){y(n);let o=t.decimal(i);if(o.numerator===0n)throw new e.CoinsError(`DIVISION_BY_ZERO`,`Cannot divide money by zero`);let s=o.numerator<0n,c=s?-o.numerator:o.numerator,l=t.roundDivision(n.amount*o.denominator,c,a.rounding??r);return v(s?-l:l,n.currency)}function d(e,t){return b(e,t),e.amount===t.amount?0:e.amount<t.amount?-1:1}function f(t,n){if(d(n.min,n.max)===1)throw new e.CoinsError(`INVALID_MONEY`,`Clamp minimum cannot exceed maximum`);return d(t,n.min)===-1?n.min:d(t,n.max)===1?n.max:t}function p(e){return y(e),v(e.amount<0n?-e.amount:e.amount,e.currency)}function m(e){return y(e),v(-e.amount,e.currency)}function h(n,i){y(n);let{fractionDigits:a,rounding:o=r}=i;if(!Number.isInteger(a)||a<0||a>n.currency.minorUnit)throw new e.CoinsError(`INVALID_ROUNDING`,`fractionDigits must be an integer from 0 to ${n.currency.minorUnit}`);let s=10n**BigInt(n.currency.minorUnit-a);return v(t.roundDivision(n.amount,s,o)*s,n.currency)}function g(e){return y(e),t.toDecimalString(e.amount,e.currency.minorUnit)}function _(e,t){return x(t),v(e,t)}function v(e,t){return Object.freeze({amount:e,currency:t})}function y(t){if(!Object.isFrozen(t)||!n.isCurrency(t.currency))throw new e.CoinsError(`INVALID_MONEY`,`Money must be a canonical Coins value`)}function b(t,n){if(y(t),y(n),t.currency!==n.currency)throw new e.CurrencyMismatchError(t.currency.code,n.currency.code)}function x(t){if(!n.isCurrency(t))throw new e.CoinsError(`INVALID_CURRENCY`,`Money requires a registered currency`)}function S(e){if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function C(e){return e!==void 0&&`value`in e&&e.get===void 0&&e.set===void 0}exports.abs=p,exports.add=s,exports.clamp=f,exports.compare=d,exports.divide=u,exports.isMoney=o,exports.money=i,exports.multiply=l,exports.negate=m,exports.parseMoney=a,exports.round=h,exports.subtract=c,exports.toDecimal=g,exports.withMinor=_;
|
|
2
2
|
//# sourceMappingURL=money.cjs.map
|
package/dist/money.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"money.cjs","names":[],"sources":["../src/money.ts"],"sourcesContent":["import type { Currency, Money, RoundingMode } from './types';\n\nimport { isCurrency } from './currency';\nimport { decimal, roundDivision, toDecimalString } from './decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\n\nconst defaultRounding: RoundingMode = 'halfAwayFromZero';\n\nexport function money<C extends Currency>(amount: string, currency: C): Money<C>;\nexport function money<C extends Currency>(amount: string, currency: C, options: { rounding: RoundingMode }): Money<C>;\nexport function money<C extends Currency>(amount: bigint, currency: C, options: { unit: 'minor' }): Money<C>;\nexport function money<C extends Currency>(\n amount: bigint | string,\n currency: C,\n options?: { rounding: RoundingMode } | { unit: 'minor' },\n): Money<C> {\n assertCurrency(currency);\n\n if (typeof amount === 'bigint') {\n if (!options || !('unit' in options) || options.unit !== 'minor') {\n throw new CoinsError('INVALID_MONEY', \"Bigint amounts require { unit: 'minor' }\");\n }\n\n return createMoney(amount, currency);\n }\n\n if (options && 'unit' in options)\n throw new CoinsError('INVALID_MONEY', 'Decimal strings do not accept a unit option');\n\n const value = decimal(amount);\n const scaled = value.numerator * 10n ** BigInt(currency.minorUnit);\n const remainder = scaled % value.denominator;\n\n if (remainder !== 0n && !options) {\n throw new CoinsError('INVALID_MONEY', `Amount \"${amount}\" exceeds ${currency.code} precision; provide rounding`);\n }\n\n return createMoney(roundDivision(scaled, value.denominator, options?.rounding ?? defaultRounding), currency);\n}\n\nexport function parseMoney(value: unknown): Money {\n if (!isPlainDataObject(value)) throw new CoinsError('INVALID_MONEY', 'Money must be a plain data object');\n\n const descriptors = Object.getOwnPropertyDescriptors(value);\n const amountDescriptor = descriptors.amount;\n const currencyDescriptor = descriptors.currency;\n\n if (!isDataProperty(amountDescriptor) || !isDataProperty(currencyDescriptor)) {\n throw new CoinsError('INVALID_MONEY', 'Money properties must be plain data values');\n }\n\n if (typeof amountDescriptor.value !== 'bigint' || !isCurrency(currencyDescriptor.value)) {\n throw new CoinsError('INVALID_MONEY', 'Money must contain bigint amount and a registered currency');\n }\n\n return createMoney(amountDescriptor.value, currencyDescriptor.value);\n}\n\nexport function isMoney(value: unknown): value is Money {\n try {\n parseMoney(value);\n\n return true;\n } catch {\n return false;\n }\n}\n\nexport function add<C extends Currency>(left: Money<C>, right: Money<NoInfer<C>>): Money<C> {\n assertSameCurrency(left, right);\n\n return createMoney(left.amount + right.amount, left.currency);\n}\n\nexport function subtract<C extends Currency>(left: Money<C>, right: Money<NoInfer<C>>): Money<C> {\n assertSameCurrency(left, right);\n\n return createMoney(left.amount - right.amount, left.currency);\n}\n\nexport function multiply<C extends Currency>(\n value: Money<C>,\n factor: string,\n options: { rounding?: RoundingMode } = {},\n): Money<C> {\n assertMoney(value);\n\n const scalar = decimal(factor);\n\n return createMoney(\n roundDivision(value.amount * scalar.numerator, scalar.denominator, options.rounding ?? defaultRounding),\n value.currency,\n );\n}\n\nexport function divide<C extends Currency>(\n value: Money<C>,\n divisor: string,\n options: { rounding?: RoundingMode } = {},\n): Money<C> {\n assertMoney(value);\n\n const scalar = decimal(divisor);\n\n if (scalar.numerator === 0n) throw new CoinsError('DIVISION_BY_ZERO', 'Cannot divide money by zero');\n\n return createMoney(\n roundDivision(\n value.amount * scalar.denominator,\n scalar.numerator < 0n ? -scalar.numerator : scalar.numerator,\n options.rounding ?? defaultRounding,\n ) * (scalar.numerator < 0n ? -1n : 1n),\n value.currency,\n );\n}\n\nexport function compare<C extends Currency>(left: Money<C>, right: Money<NoInfer<C>>): -1 | 0 | 1 {\n assertSameCurrency(left, right);\n\n return left.amount === right.amount ? 0 : left.amount < right.amount ? -1 : 1;\n}\n\nexport function abs<C extends Currency>(value: Money<C>): Money<C> {\n assertMoney(value);\n\n return createMoney(value.amount < 0n ? -value.amount : value.amount, value.currency);\n}\n\nexport function negate<C extends Currency>(value: Money<C>): Money<C> {\n assertMoney(value);\n\n return createMoney(-value.amount, value.currency);\n}\n\nexport function round<C extends Currency>(\n value: Money<C>,\n options: { fractionDigits: number; rounding?: RoundingMode },\n): Money<C> {\n assertMoney(value);\n\n const { fractionDigits, rounding = defaultRounding } = options;\n\n if (!Number.isInteger(fractionDigits) || fractionDigits < 0 || fractionDigits > value.currency.minorUnit) {\n throw new CoinsError('INVALID_ROUNDING', `fractionDigits must be an integer from 0 to ${value.currency.minorUnit}`);\n }\n\n const factor = 10n ** BigInt(value.currency.minorUnit - fractionDigits);\n\n return createMoney(roundDivision(value.amount, factor, rounding) * factor, value.currency);\n}\n\nexport function toDecimal(value: Money): string {\n assertMoney(value);\n\n return toDecimalString(value.amount, value.currency.minorUnit);\n}\n\nexport function withMinor<C extends Currency>(amount: bigint, currency: C): Money<C> {\n assertCurrency(currency);\n\n return createMoney(amount, currency);\n}\n\nfunction createMoney<C extends Currency>(amount: bigint, currency: C): Money<C> {\n return Object.freeze({ amount, currency }) as Money<C>;\n}\n\nfunction assertMoney(value: Money): void {\n if (!Object.isFrozen(value) || !isCurrency(value.currency)) {\n throw new CoinsError('INVALID_MONEY', 'Money must be a canonical Coins value');\n }\n}\n\nfunction assertSameCurrency(left: Money, right: Money): void {\n assertMoney(left);\n assertMoney(right);\n\n if (left.currency !== right.currency) {\n throw new CurrencyMismatchError(left.currency.code, right.currency.code);\n }\n}\n\nfunction assertCurrency(value: Currency): void {\n if (!isCurrency(value)) throw new CoinsError('INVALID_CURRENCY', 'Money requires a registered currency');\n}\n\nfunction isPlainDataObject(value: unknown): value is Record<PropertyKey, unknown> {\n if (typeof value !== 'object' || value === null) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction isDataProperty(\n descriptor: PropertyDescriptor | undefined,\n): descriptor is PropertyDescriptor & { value: unknown } {\n return (\n descriptor !== undefined && 'value' in descriptor && descriptor.get === undefined && descriptor.set === undefined\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"money.cjs","names":[],"sources":["../src/money.ts"],"sourcesContent":["import { isCurrency } from './currency';\nimport { decimal, roundDivision, toDecimalString } from './decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport type { Currency, Money, RoundingMode } from './types';\n\nconst defaultRounding: RoundingMode = 'halfAwayFromZero';\n\nexport function money<C extends Currency>(amount: string, currency: C): Money<C>;\nexport function money<C extends Currency>(amount: string, currency: C, options: { rounding: RoundingMode }): Money<C>;\nexport function money<C extends Currency>(amount: bigint, currency: C, options: { unit: 'minor' }): Money<C>;\nexport function money<C extends Currency>(\n amount: bigint | string,\n currency: C,\n options?: { rounding: RoundingMode } | { unit: 'minor' },\n): Money<C> {\n assertCurrency(currency);\n\n if (typeof amount === 'bigint') {\n if (!options || !('unit' in options) || options.unit !== 'minor') {\n throw new CoinsError('INVALID_MONEY', \"Bigint amounts require { unit: 'minor' }\");\n }\n\n return createMoney(amount, currency);\n }\n\n if (options && 'unit' in options)\n throw new CoinsError('INVALID_MONEY', 'Decimal strings do not accept a unit option');\n\n const value = decimal(amount);\n const scaled = value.numerator * 10n ** BigInt(currency.minorUnit);\n const remainder = scaled % value.denominator;\n\n if (remainder !== 0n && !options) {\n throw new CoinsError('INVALID_MONEY', `Amount \"${amount}\" exceeds ${currency.code} precision; provide rounding`);\n }\n\n return createMoney(roundDivision(scaled, value.denominator, options?.rounding ?? defaultRounding), currency);\n}\n\nexport function parseMoney(value: unknown): Money {\n if (!isPlainDataObject(value)) throw new CoinsError('INVALID_MONEY', 'Money must be a plain data object');\n\n const descriptors = Object.getOwnPropertyDescriptors(value);\n const amountDescriptor = descriptors.amount;\n const currencyDescriptor = descriptors.currency;\n\n if (!isDataProperty(amountDescriptor) || !isDataProperty(currencyDescriptor)) {\n throw new CoinsError('INVALID_MONEY', 'Money properties must be plain data values');\n }\n\n if (typeof amountDescriptor.value !== 'bigint' || !isCurrency(currencyDescriptor.value)) {\n throw new CoinsError('INVALID_MONEY', 'Money must contain bigint amount and a registered currency');\n }\n\n return createMoney(amountDescriptor.value, currencyDescriptor.value);\n}\n\nexport function isMoney(value: unknown): value is Money {\n try {\n parseMoney(value);\n\n return true;\n } catch {\n return false;\n }\n}\n\nexport function add<C extends Currency>(left: Money<C>, right: Money<NoInfer<C>>): Money<C> {\n assertSameCurrency(left, right);\n\n return createMoney(left.amount + right.amount, left.currency);\n}\n\nexport function subtract<C extends Currency>(left: Money<C>, right: Money<NoInfer<C>>): Money<C> {\n assertSameCurrency(left, right);\n\n return createMoney(left.amount - right.amount, left.currency);\n}\n\nexport function multiply<C extends Currency>(\n value: Money<C>,\n factor: string,\n options: { rounding?: RoundingMode } = {},\n): Money<C> {\n assertMoney(value);\n\n const scalar = decimal(factor);\n\n return createMoney(\n roundDivision(value.amount * scalar.numerator, scalar.denominator, options.rounding ?? defaultRounding),\n value.currency,\n );\n}\n\nexport function divide<C extends Currency>(\n value: Money<C>,\n divisor: string,\n options: { rounding?: RoundingMode } = {},\n): Money<C> {\n assertMoney(value);\n\n const scalar = decimal(divisor);\n\n if (scalar.numerator === 0n) throw new CoinsError('DIVISION_BY_ZERO', 'Cannot divide money by zero');\n\n const negative = scalar.numerator < 0n;\n const absoluteDivisor = negative ? -scalar.numerator : scalar.numerator;\n const quotient = roundDivision(\n value.amount * scalar.denominator,\n absoluteDivisor,\n options.rounding ?? defaultRounding,\n );\n\n return createMoney(negative ? -quotient : quotient, value.currency);\n}\n\nexport function compare<C extends Currency>(left: Money<C>, right: Money<NoInfer<C>>): -1 | 0 | 1 {\n assertSameCurrency(left, right);\n\n return left.amount === right.amount ? 0 : left.amount < right.amount ? -1 : 1;\n}\n\nexport function clamp<C extends Currency>(\n value: Money<C>,\n options: { max: Money<NoInfer<C>>; min: Money<NoInfer<C>> },\n): Money<C> {\n if (compare(options.min, options.max) === 1) {\n throw new CoinsError('INVALID_MONEY', 'Clamp minimum cannot exceed maximum');\n }\n\n return compare(value, options.min) === -1 ? options.min : compare(value, options.max) === 1 ? options.max : value;\n}\n\nexport function abs<C extends Currency>(value: Money<C>): Money<C> {\n assertMoney(value);\n\n return createMoney(value.amount < 0n ? -value.amount : value.amount, value.currency);\n}\n\nexport function negate<C extends Currency>(value: Money<C>): Money<C> {\n assertMoney(value);\n\n return createMoney(-value.amount, value.currency);\n}\n\nexport function round<C extends Currency>(\n value: Money<C>,\n options: { fractionDigits: number; rounding?: RoundingMode },\n): Money<C> {\n assertMoney(value);\n\n const { fractionDigits, rounding = defaultRounding } = options;\n\n if (!Number.isInteger(fractionDigits) || fractionDigits < 0 || fractionDigits > value.currency.minorUnit) {\n throw new CoinsError('INVALID_ROUNDING', `fractionDigits must be an integer from 0 to ${value.currency.minorUnit}`);\n }\n\n const factor = 10n ** BigInt(value.currency.minorUnit - fractionDigits);\n\n return createMoney(roundDivision(value.amount, factor, rounding) * factor, value.currency);\n}\n\nexport function toDecimal(value: Money): string {\n assertMoney(value);\n\n return toDecimalString(value.amount, value.currency.minorUnit);\n}\n\nexport function withMinor<C extends Currency>(amount: bigint, currency: C): Money<C> {\n assertCurrency(currency);\n\n return createMoney(amount, currency);\n}\n\nfunction createMoney<C extends Currency>(amount: bigint, currency: C): Money<C> {\n return Object.freeze({ amount, currency }) as Money<C>;\n}\n\nfunction assertMoney(value: Money): void {\n if (!Object.isFrozen(value) || !isCurrency(value.currency)) {\n throw new CoinsError('INVALID_MONEY', 'Money must be a canonical Coins value');\n }\n}\n\nfunction assertSameCurrency(left: Money, right: Money): void {\n assertMoney(left);\n assertMoney(right);\n\n if (left.currency !== right.currency) {\n throw new CurrencyMismatchError(left.currency.code, right.currency.code);\n }\n}\n\nfunction assertCurrency(value: Currency): void {\n if (!isCurrency(value)) throw new CoinsError('INVALID_CURRENCY', 'Money requires a registered currency');\n}\n\nfunction isPlainDataObject(value: unknown): value is Record<PropertyKey, unknown> {\n if (typeof value !== 'object' || value === null) return false;\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction isDataProperty(\n descriptor: PropertyDescriptor | undefined,\n): descriptor is PropertyDescriptor & { value: unknown } {\n return (\n descriptor !== undefined && 'value' in descriptor && descriptor.get === undefined && descriptor.set === undefined\n );\n}\n"],"mappings":"uFAKA,IAAM,EAAgC,mBAKtC,SAAgB,EACd,EACA,EACA,EACU,CAGV,GAFA,EAAe,CAAQ,EAEnB,OAAO,GAAW,SAAU,CAC9B,GAAI,CAAC,GAAW,EAAE,SAAU,IAAY,EAAQ,OAAS,QACvD,MAAM,IAAI,EAAA,WAAW,gBAAiB,0CAA0C,EAGlF,OAAO,EAAY,EAAQ,CAAQ,CACrC,CAEA,GAAI,GAAW,SAAU,EACvB,MAAM,IAAI,EAAA,WAAW,gBAAiB,6CAA6C,EAErF,IAAM,EAAQ,EAAA,QAAQ,CAAM,EACtB,EAAS,EAAM,UAAY,KAAO,OAAO,EAAS,SAAS,EAGjE,GAFkB,EAAS,EAAM,cAEf,IAAM,CAAC,EACvB,MAAM,IAAI,EAAA,WAAW,gBAAiB,WAAW,EAAO,YAAY,EAAS,KAAK,6BAA6B,EAGjH,OAAO,EAAY,EAAA,cAAc,EAAQ,EAAM,YAAa,GAAS,UAAY,CAAe,EAAG,CAAQ,CAC7G,CAEA,SAAgB,EAAW,EAAuB,CAChD,GAAI,CAAC,EAAkB,CAAK,EAAG,MAAM,IAAI,EAAA,WAAW,gBAAiB,mCAAmC,EAExG,IAAM,EAAc,OAAO,0BAA0B,CAAK,EACpD,EAAmB,EAAY,OAC/B,EAAqB,EAAY,SAEvC,GAAI,CAAC,EAAe,CAAgB,GAAK,CAAC,EAAe,CAAkB,EACzE,MAAM,IAAI,EAAA,WAAW,gBAAiB,4CAA4C,EAGpF,GAAI,OAAO,EAAiB,OAAU,UAAY,CAAC,EAAA,WAAW,EAAmB,KAAK,EACpF,MAAM,IAAI,EAAA,WAAW,gBAAiB,4DAA4D,EAGpG,OAAO,EAAY,EAAiB,MAAO,EAAmB,KAAK,CACrE,CAEA,SAAgB,EAAQ,EAAgC,CACtD,GAAI,CAGF,OAFA,EAAW,CAAK,EAET,EACT,MAAQ,CACN,MAAO,EACT,CACF,CAEA,SAAgB,EAAwB,EAAgB,EAAoC,CAG1F,OAFA,EAAmB,EAAM,CAAK,EAEvB,EAAY,EAAK,OAAS,EAAM,OAAQ,EAAK,QAAQ,CAC9D,CAEA,SAAgB,EAA6B,EAAgB,EAAoC,CAG/F,OAFA,EAAmB,EAAM,CAAK,EAEvB,EAAY,EAAK,OAAS,EAAM,OAAQ,EAAK,QAAQ,CAC9D,CAEA,SAAgB,EACd,EACA,EACA,EAAuC,CAAC,EAC9B,CACV,EAAY,CAAK,EAEjB,IAAM,EAAS,EAAA,QAAQ,CAAM,EAE7B,OAAO,EACL,EAAA,cAAc,EAAM,OAAS,EAAO,UAAW,EAAO,YAAa,EAAQ,UAAY,CAAe,EACtG,EAAM,QACR,CACF,CAEA,SAAgB,EACd,EACA,EACA,EAAuC,CAAC,EAC9B,CACV,EAAY,CAAK,EAEjB,IAAM,EAAS,EAAA,QAAQ,CAAO,EAE9B,GAAI,EAAO,YAAc,GAAI,MAAM,IAAI,EAAA,WAAW,mBAAoB,6BAA6B,EAEnG,IAAM,EAAW,EAAO,UAAY,GAC9B,EAAkB,EAAW,CAAC,EAAO,UAAY,EAAO,UACxD,EAAW,EAAA,cACf,EAAM,OAAS,EAAO,YACtB,EACA,EAAQ,UAAY,CACtB,EAEA,OAAO,EAAY,EAAW,CAAC,EAAW,EAAU,EAAM,QAAQ,CACpE,CAEA,SAAgB,EAA4B,EAAgB,EAAsC,CAGhG,OAFA,EAAmB,EAAM,CAAK,EAEvB,EAAK,SAAW,EAAM,OAAS,EAAI,EAAK,OAAS,EAAM,OAAS,GAAK,CAC9E,CAEA,SAAgB,EACd,EACA,EACU,CACV,GAAI,EAAQ,EAAQ,IAAK,EAAQ,GAAG,IAAM,EACxC,MAAM,IAAI,EAAA,WAAW,gBAAiB,qCAAqC,EAG7E,OAAO,EAAQ,EAAO,EAAQ,GAAG,IAAM,GAAK,EAAQ,IAAM,EAAQ,EAAO,EAAQ,GAAG,IAAM,EAAI,EAAQ,IAAM,CAC9G,CAEA,SAAgB,EAAwB,EAA2B,CAGjE,OAFA,EAAY,CAAK,EAEV,EAAY,EAAM,OAAS,GAAK,CAAC,EAAM,OAAS,EAAM,OAAQ,EAAM,QAAQ,CACrF,CAEA,SAAgB,EAA2B,EAA2B,CAGpE,OAFA,EAAY,CAAK,EAEV,EAAY,CAAC,EAAM,OAAQ,EAAM,QAAQ,CAClD,CAEA,SAAgB,EACd,EACA,EACU,CACV,EAAY,CAAK,EAEjB,GAAM,CAAE,iBAAgB,WAAW,GAAoB,EAEvD,GAAI,CAAC,OAAO,UAAU,CAAc,GAAK,EAAiB,GAAK,EAAiB,EAAM,SAAS,UAC7F,MAAM,IAAI,EAAA,WAAW,mBAAoB,+CAA+C,EAAM,SAAS,WAAW,EAGpH,IAAM,EAAS,KAAO,OAAO,EAAM,SAAS,UAAY,CAAc,EAEtE,OAAO,EAAY,EAAA,cAAc,EAAM,OAAQ,EAAQ,CAAQ,EAAI,EAAQ,EAAM,QAAQ,CAC3F,CAEA,SAAgB,EAAU,EAAsB,CAG9C,OAFA,EAAY,CAAK,EAEV,EAAA,gBAAgB,EAAM,OAAQ,EAAM,SAAS,SAAS,CAC/D,CAEA,SAAgB,EAA8B,EAAgB,EAAuB,CAGnF,OAFA,EAAe,CAAQ,EAEhB,EAAY,EAAQ,CAAQ,CACrC,CAEA,SAAS,EAAgC,EAAgB,EAAuB,CAC9E,OAAO,OAAO,OAAO,CAAE,SAAQ,UAAS,CAAC,CAC3C,CAEA,SAAS,EAAY,EAAoB,CACvC,GAAI,CAAC,OAAO,SAAS,CAAK,GAAK,CAAC,EAAA,WAAW,EAAM,QAAQ,EACvD,MAAM,IAAI,EAAA,WAAW,gBAAiB,uCAAuC,CAEjF,CAEA,SAAS,EAAmB,EAAa,EAAoB,CAI3D,GAHA,EAAY,CAAI,EAChB,EAAY,CAAK,EAEb,EAAK,WAAa,EAAM,SAC1B,MAAM,IAAI,EAAA,sBAAsB,EAAK,SAAS,KAAM,EAAM,SAAS,IAAI,CAE3E,CAEA,SAAS,EAAe,EAAuB,CAC7C,GAAI,CAAC,EAAA,WAAW,CAAK,EAAG,MAAM,IAAI,EAAA,WAAW,mBAAoB,sCAAsC,CACzG,CAEA,SAAS,EAAkB,EAAuD,CAChF,GAAI,OAAO,GAAU,WAAY,EAAgB,MAAO,GAExD,IAAM,EAAY,OAAO,eAAe,CAAK,EAE7C,OAAO,IAAc,OAAO,WAAa,IAAc,IACzD,CAEA,SAAS,EACP,EACuD,CACvD,OACE,IAAe,IAAA,IAAa,UAAW,GAAc,EAAW,MAAQ,IAAA,IAAa,EAAW,MAAQ,IAAA,EAE5G"}
|
package/dist/money.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ export declare function divide<C extends Currency>(value: Money<C>, divisor: str
|
|
|
17
17
|
rounding?: RoundingMode;
|
|
18
18
|
}): Money<C>;
|
|
19
19
|
export declare function compare<C extends Currency>(left: Money<C>, right: Money<NoInfer<C>>): -1 | 0 | 1;
|
|
20
|
+
export declare function clamp<C extends Currency>(value: Money<C>, options: {
|
|
21
|
+
max: Money<NoInfer<C>>;
|
|
22
|
+
min: Money<NoInfer<C>>;
|
|
23
|
+
}): Money<C>;
|
|
20
24
|
export declare function abs<C extends Currency>(value: Money<C>): Money<C>;
|
|
21
25
|
export declare function negate<C extends Currency>(value: Money<C>): Money<C>;
|
|
22
26
|
export declare function round<C extends Currency>(value: Money<C>, options: {
|
package/dist/money.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"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"}
|
package/dist/money.js
CHANGED
|
@@ -4,21 +4,21 @@ import { isCurrency as a } from "./currency.js";
|
|
|
4
4
|
//#region src/money.ts
|
|
5
5
|
var o = "halfAwayFromZero";
|
|
6
6
|
function s(t, i, a) {
|
|
7
|
-
if (
|
|
7
|
+
if (w(i), typeof t == "bigint") {
|
|
8
8
|
if (!a || !("unit" in a) || a.unit !== "minor") throw new e("INVALID_MONEY", "Bigint amounts require { unit: 'minor' }");
|
|
9
|
-
return
|
|
9
|
+
return x(t, i);
|
|
10
10
|
}
|
|
11
11
|
if (a && "unit" in a) throw new e("INVALID_MONEY", "Decimal strings do not accept a unit option");
|
|
12
12
|
let s = n(t), c = s.numerator * 10n ** BigInt(i.minorUnit);
|
|
13
13
|
if (c % s.denominator !== 0n && !a) throw new e("INVALID_MONEY", `Amount "${t}" exceeds ${i.code} precision; provide rounding`);
|
|
14
|
-
return
|
|
14
|
+
return x(r(c, s.denominator, a?.rounding ?? o), i);
|
|
15
15
|
}
|
|
16
16
|
function c(t) {
|
|
17
|
-
if (!
|
|
17
|
+
if (!T(t)) throw new e("INVALID_MONEY", "Money must be a plain data object");
|
|
18
18
|
let n = Object.getOwnPropertyDescriptors(t), r = n.amount, i = n.currency;
|
|
19
|
-
if (!
|
|
19
|
+
if (!E(r) || !E(i)) throw new e("INVALID_MONEY", "Money properties must be plain data values");
|
|
20
20
|
if (typeof r.value != "bigint" || !a(i.value)) throw new e("INVALID_MONEY", "Money must contain bigint amount and a registered currency");
|
|
21
|
-
return
|
|
21
|
+
return x(r.value, i.value);
|
|
22
22
|
}
|
|
23
23
|
function l(e) {
|
|
24
24
|
try {
|
|
@@ -28,68 +28,73 @@ function l(e) {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
function u(e, t) {
|
|
31
|
-
return
|
|
31
|
+
return C(e, t), x(e.amount + t.amount, e.currency);
|
|
32
32
|
}
|
|
33
33
|
function d(e, t) {
|
|
34
|
-
return
|
|
34
|
+
return C(e, t), x(e.amount - t.amount, e.currency);
|
|
35
35
|
}
|
|
36
36
|
function f(e, t, i = {}) {
|
|
37
|
-
|
|
37
|
+
S(e);
|
|
38
38
|
let a = n(t);
|
|
39
|
-
return
|
|
39
|
+
return x(r(e.amount * a.numerator, a.denominator, i.rounding ?? o), e.currency);
|
|
40
40
|
}
|
|
41
41
|
function p(t, i, a = {}) {
|
|
42
|
-
|
|
42
|
+
S(t);
|
|
43
43
|
let s = n(i);
|
|
44
44
|
if (s.numerator === 0n) throw new e("DIVISION_BY_ZERO", "Cannot divide money by zero");
|
|
45
|
-
|
|
45
|
+
let c = s.numerator < 0n, l = c ? -s.numerator : s.numerator, u = r(t.amount * s.denominator, l, a.rounding ?? o);
|
|
46
|
+
return x(c ? -u : u, t.currency);
|
|
46
47
|
}
|
|
47
48
|
function m(e, t) {
|
|
48
|
-
return
|
|
49
|
+
return C(e, t), e.amount === t.amount ? 0 : e.amount < t.amount ? -1 : 1;
|
|
49
50
|
}
|
|
50
|
-
function h(
|
|
51
|
-
|
|
51
|
+
function h(t, n) {
|
|
52
|
+
if (m(n.min, n.max) === 1) throw new e("INVALID_MONEY", "Clamp minimum cannot exceed maximum");
|
|
53
|
+
return m(t, n.min) === -1 ? n.min : m(t, n.max) === 1 ? n.max : t;
|
|
52
54
|
}
|
|
53
55
|
function g(e) {
|
|
54
|
-
return
|
|
56
|
+
return S(e), x(e.amount < 0n ? -e.amount : e.amount, e.currency);
|
|
55
57
|
}
|
|
56
|
-
function _(
|
|
57
|
-
x(
|
|
58
|
+
function _(e) {
|
|
59
|
+
return S(e), x(-e.amount, e.currency);
|
|
60
|
+
}
|
|
61
|
+
function v(t, n) {
|
|
62
|
+
S(t);
|
|
58
63
|
let { fractionDigits: i, rounding: a = o } = n;
|
|
59
64
|
if (!Number.isInteger(i) || i < 0 || i > t.currency.minorUnit) throw new e("INVALID_ROUNDING", `fractionDigits must be an integer from 0 to ${t.currency.minorUnit}`);
|
|
60
65
|
let s = 10n ** BigInt(t.currency.minorUnit - i);
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
function v(e) {
|
|
64
|
-
return x(e), i(e.amount, e.currency.minorUnit);
|
|
66
|
+
return x(r(t.amount, s, a) * s, t.currency);
|
|
65
67
|
}
|
|
66
|
-
function y(e
|
|
67
|
-
return
|
|
68
|
+
function y(e) {
|
|
69
|
+
return S(e), i(e.amount, e.currency.minorUnit);
|
|
68
70
|
}
|
|
69
71
|
function b(e, t) {
|
|
72
|
+
return w(t), x(e, t);
|
|
73
|
+
}
|
|
74
|
+
function x(e, t) {
|
|
70
75
|
return Object.freeze({
|
|
71
76
|
amount: e,
|
|
72
77
|
currency: t
|
|
73
78
|
});
|
|
74
79
|
}
|
|
75
|
-
function
|
|
80
|
+
function S(t) {
|
|
76
81
|
if (!Object.isFrozen(t) || !a(t.currency)) throw new e("INVALID_MONEY", "Money must be a canonical Coins value");
|
|
77
82
|
}
|
|
78
|
-
function
|
|
79
|
-
if (
|
|
83
|
+
function C(e, n) {
|
|
84
|
+
if (S(e), S(n), e.currency !== n.currency) throw new t(e.currency.code, n.currency.code);
|
|
80
85
|
}
|
|
81
|
-
function
|
|
86
|
+
function w(t) {
|
|
82
87
|
if (!a(t)) throw new e("INVALID_CURRENCY", "Money requires a registered currency");
|
|
83
88
|
}
|
|
84
|
-
function
|
|
89
|
+
function T(e) {
|
|
85
90
|
if (typeof e != "object" || !e) return !1;
|
|
86
91
|
let t = Object.getPrototypeOf(e);
|
|
87
92
|
return t === Object.prototype || t === null;
|
|
88
93
|
}
|
|
89
|
-
function
|
|
94
|
+
function E(e) {
|
|
90
95
|
return e !== void 0 && "value" in e && e.get === void 0 && e.set === void 0;
|
|
91
96
|
}
|
|
92
97
|
//#endregion
|
|
93
|
-
export {
|
|
98
|
+
export { g as abs, u as add, h as clamp, m as compare, p as divide, l as isMoney, s as money, f as multiply, _ as negate, c as parseMoney, v as round, d as subtract, y as toDecimal, b as withMinor };
|
|
94
99
|
|
|
95
100
|
//# sourceMappingURL=money.js.map
|