@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.
Files changed (51) hide show
  1. package/README.md +3 -5
  2. package/dist/aggregate.cjs +1 -1
  3. package/dist/aggregate.cjs.map +1 -1
  4. package/dist/aggregate.d.ts +1 -4
  5. package/dist/aggregate.d.ts.map +1 -1
  6. package/dist/aggregate.js +22 -24
  7. package/dist/aggregate.js.map +1 -1
  8. package/dist/coins.cjs +1 -1
  9. package/dist/coins.cjs.map +1 -1
  10. package/dist/coins.iife.js +1 -1
  11. package/dist/coins.iife.js.map +1 -1
  12. package/dist/coins.js +1 -1
  13. package/dist/coins.js.map +1 -1
  14. package/dist/currency.cjs.map +1 -1
  15. package/dist/currency.d.ts.map +1 -1
  16. package/dist/currency.js.map +1 -1
  17. package/dist/decimal.cjs.map +1 -1
  18. package/dist/decimal.d.ts.map +1 -1
  19. package/dist/decimal.js.map +1 -1
  20. package/dist/errors.cjs +1 -1
  21. package/dist/errors.cjs.map +1 -1
  22. package/dist/errors.d.ts +1 -2
  23. package/dist/errors.d.ts.map +1 -1
  24. package/dist/errors.js +1 -4
  25. package/dist/errors.js.map +1 -1
  26. package/dist/exchange.cjs.map +1 -1
  27. package/dist/exchange.d.ts.map +1 -1
  28. package/dist/exchange.js.map +1 -1
  29. package/dist/format.cjs +1 -1
  30. package/dist/format.cjs.map +1 -1
  31. package/dist/format.d.ts.map +1 -1
  32. package/dist/format.js +26 -26
  33. package/dist/format.js.map +1 -1
  34. package/dist/index.cjs +1 -1
  35. package/dist/index.d.ts +3 -4
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +7 -8
  38. package/dist/money.cjs +1 -1
  39. package/dist/money.cjs.map +1 -1
  40. package/dist/money.d.ts +4 -0
  41. package/dist/money.d.ts.map +1 -1
  42. package/dist/money.js +36 -31
  43. package/dist/money.js.map +1 -1
  44. package/dist/serialization.cjs +1 -1
  45. package/dist/serialization.cjs.map +1 -1
  46. package/dist/serialization.d.ts.map +1 -1
  47. package/dist/serialization.js +1 -1
  48. package/dist/serialization.js.map +1 -1
  49. package/dist/types.d.ts +1 -0
  50. package/dist/types.d.ts.map +1 -1
  51. package/package.json +21 -17
package/dist/money.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"money.js","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.js","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":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("./errors.cjs"),t=require("./currency.cjs"),n=require("./money.cjs");var r=/^(?:0|-[1-9]\d*|[1-9]\d*)$/,i=[`amount`,`currency`,`unit`];function a(e){return{amount:e.amount.toString(),currency:e.currency.code,unit:`minor`}}function o(r,i={}){try{let e=s(r),a=i.currency??t.resolveBuiltinCurrency;return n.money(BigInt(e.amount),a(e.currency),{unit:`minor`})}catch(t){throw new e.CoinsError(`INVALID_MONEY`,`Invalid Money JSON`,{cause:t})}}function s(e){if(typeof e!=`object`||!e||Object.getPrototypeOf(e)!==Object.prototype)throw TypeError(`Money JSON must be a plain object`);let t=Object.getOwnPropertyDescriptors(e),n=Reflect.ownKeys(e);if(n.length!==i.length||!i.every(e=>n.includes(e)))throw TypeError(`Money JSON must contain only amount, currency, and unit`);for(let e of i){let n=t[e];if(!n||!(`value`in n)||n.get||n.set)throw TypeError(`Money JSON property "${e}" must be a data value`)}let a=t.amount.value,o=t.currency.value,s=t.unit.value;if(typeof a!=`string`||!r.test(a))throw TypeError(`Money JSON amount must be a canonical integer string`);if(typeof o!=`string`||s!==`minor`)throw TypeError(`Money JSON currency/unit are invalid`);return{amount:a,currency:o,unit:s}}exports.parseMoneyJSON=o,exports.toJSON=a;
1
+ const e=require("./errors.cjs"),t=require("./currency.cjs"),n=require("./money.cjs");var r=/^(?:0|-[1-9]\d*|[1-9]\d*)$/,i=[`amount`,`currency`,`unit`];function a(e){return{amount:e.amount.toString(),currency:e.currency.code,unit:`minor`}}function o(r,i={}){try{let e=s(r),a=i.currency??t.resolveBuiltinCurrency;return n.money(BigInt(e.amount),a(e.currency),{unit:`minor`})}catch(t){throw new e.CoinsError(`INVALID_MONEY`,`Invalid Money JSON`,{cause:t})}}function s(e){if(typeof e!=`object`||!e||Object.getPrototypeOf(e)!==Object.prototype)throw TypeError(`Money JSON must be a plain object`);let t=Object.getOwnPropertyDescriptors(e),n=Reflect.ownKeys(e);if(n.length!==i.length||!i.every(e=>n.includes(e)))throw TypeError(`Money JSON must contain only amount, currency, and unit`);for(let e of i){let n=t[e];if(!n||!(`value`in n)||n.get||n.set)throw TypeError(`Money JSON property "${e}" must be a data value`)}let a=t.amount?.value,o=t.currency?.value,s=t.unit?.value;if(typeof a!=`string`||!r.test(a))throw TypeError(`Money JSON amount must be a canonical integer string`);if(typeof o!=`string`||s!==`minor`)throw TypeError(`Money JSON currency/unit are invalid`);return{amount:a,currency:o,unit:s}}exports.parseMoneyJSON=o,exports.toJSON=a;
2
2
  //# sourceMappingURL=serialization.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"serialization.cjs","names":[],"sources":["../src/serialization.ts"],"sourcesContent":["import type { Currency, Money, MoneyJSON } from './types';\n\nimport { resolveBuiltinCurrency } from './currency';\nimport { CoinsError } from './errors';\nimport { money } from './money';\n\nconst INTEGER = /^(?:0|-[1-9]\\d*|[1-9]\\d*)$/;\nconst KEYS = ['amount', 'currency', 'unit'] as const;\n\nexport function toJSON(value: Money): MoneyJSON {\n return { amount: value.amount.toString(), currency: value.currency.code, unit: 'minor' };\n}\n\nexport function parseMoneyJSON(value: unknown, options: { currency?: (code: string) => Currency } = {}): Money {\n try {\n const payload = readPayload(value);\n const resolveCurrency = options.currency ?? resolveBuiltinCurrency;\n\n return money(BigInt(payload.amount), resolveCurrency(payload.currency), { unit: 'minor' });\n } catch (error) {\n throw new CoinsError('INVALID_MONEY', 'Invalid Money JSON', { cause: error });\n }\n}\n\nfunction readPayload(value: unknown): MoneyJSON {\n if (typeof value !== 'object' || value === null || Object.getPrototypeOf(value) !== Object.prototype) {\n throw new TypeError('Money JSON must be a plain object');\n }\n\n const descriptors = Object.getOwnPropertyDescriptors(value);\n const ownKeys = Reflect.ownKeys(value);\n\n if (ownKeys.length !== KEYS.length || !KEYS.every((key) => ownKeys.includes(key))) {\n throw new TypeError('Money JSON must contain only amount, currency, and unit');\n }\n\n for (const key of KEYS) {\n const descriptor = descriptors[key];\n\n if (!descriptor || !('value' in descriptor) || descriptor.get || descriptor.set) {\n throw new TypeError(`Money JSON property \"${key}\" must be a data value`);\n }\n }\n\n const amount = descriptors.amount!.value;\n const currency = descriptors.currency!.value;\n const unit = descriptors.unit!.value;\n\n if (typeof amount !== 'string' || !INTEGER.test(amount))\n throw new TypeError('Money JSON amount must be a canonical integer string');\n\n if (typeof currency !== 'string' || unit !== 'minor') throw new TypeError('Money JSON currency/unit are invalid');\n\n return { amount, currency, unit };\n}\n"],"mappings":"qFAMA,IAAM,EAAU,6BACV,EAAO,CAAC,SAAU,WAAY,MAAM,EAE1C,SAAgB,EAAO,EAAyB,CAC9C,MAAO,CAAE,OAAQ,EAAM,OAAO,SAAS,EAAG,SAAU,EAAM,SAAS,KAAM,KAAM,OAAQ,CACzF,CAEA,SAAgB,EAAe,EAAgB,EAAqD,CAAC,EAAU,CAC7G,GAAI,CACF,IAAM,EAAU,EAAY,CAAK,EAC3B,EAAkB,EAAQ,UAAY,EAAA,uBAE5C,OAAO,EAAA,MAAM,OAAO,EAAQ,MAAM,EAAG,EAAgB,EAAQ,QAAQ,EAAG,CAAE,KAAM,OAAQ,CAAC,CAC3F,OAAS,EAAO,CACd,MAAM,IAAI,EAAA,WAAW,gBAAiB,qBAAsB,CAAE,MAAO,CAAM,CAAC,CAC9E,CACF,CAEA,SAAS,EAAY,EAA2B,CAC9C,GAAI,OAAO,GAAU,WAAY,GAAkB,OAAO,eAAe,CAAK,IAAM,OAAO,UACzF,MAAU,UAAU,mCAAmC,EAGzD,IAAM,EAAc,OAAO,0BAA0B,CAAK,EACpD,EAAU,QAAQ,QAAQ,CAAK,EAErC,GAAI,EAAQ,SAAW,EAAK,QAAU,CAAC,EAAK,MAAO,GAAQ,EAAQ,SAAS,CAAG,CAAC,EAC9E,MAAU,UAAU,yDAAyD,EAG/E,IAAK,IAAM,KAAO,EAAM,CACtB,IAAM,EAAa,EAAY,GAE/B,GAAI,CAAC,GAAc,EAAE,UAAW,IAAe,EAAW,KAAO,EAAW,IAC1E,MAAU,UAAU,wBAAwB,EAAI,uBAAuB,CAE3E,CAEA,IAAM,EAAS,EAAY,OAAQ,MAC7B,EAAW,EAAY,SAAU,MACjC,EAAO,EAAY,KAAM,MAE/B,GAAI,OAAO,GAAW,UAAY,CAAC,EAAQ,KAAK,CAAM,EACpD,MAAU,UAAU,sDAAsD,EAE5E,GAAI,OAAO,GAAa,UAAY,IAAS,QAAS,MAAU,UAAU,sCAAsC,EAEhH,MAAO,CAAE,SAAQ,WAAU,MAAK,CAClC"}
1
+ {"version":3,"file":"serialization.cjs","names":[],"sources":["../src/serialization.ts"],"sourcesContent":["import { resolveBuiltinCurrency } from './currency';\nimport { CoinsError } from './errors';\nimport { money } from './money';\nimport type { Currency, Money, MoneyJSON } from './types';\n\nconst INTEGER = /^(?:0|-[1-9]\\d*|[1-9]\\d*)$/;\nconst KEYS = ['amount', 'currency', 'unit'] as const;\n\nexport function toJSON(value: Money): MoneyJSON {\n return { amount: value.amount.toString(), currency: value.currency.code, unit: 'minor' };\n}\n\nexport function parseMoneyJSON(value: unknown, options: { currency?: (code: string) => Currency } = {}): Money {\n try {\n const payload = readPayload(value);\n const resolveCurrency = options.currency ?? resolveBuiltinCurrency;\n\n return money(BigInt(payload.amount), resolveCurrency(payload.currency), { unit: 'minor' });\n } catch (error) {\n throw new CoinsError('INVALID_MONEY', 'Invalid Money JSON', { cause: error });\n }\n}\n\nfunction readPayload(value: unknown): MoneyJSON {\n if (typeof value !== 'object' || value === null || Object.getPrototypeOf(value) !== Object.prototype) {\n throw new TypeError('Money JSON must be a plain object');\n }\n\n const descriptors = Object.getOwnPropertyDescriptors(value);\n const ownKeys = Reflect.ownKeys(value);\n\n if (ownKeys.length !== KEYS.length || !KEYS.every((key) => ownKeys.includes(key))) {\n throw new TypeError('Money JSON must contain only amount, currency, and unit');\n }\n\n for (const key of KEYS) {\n const descriptor = descriptors[key];\n\n if (!descriptor || !('value' in descriptor) || descriptor.get || descriptor.set) {\n throw new TypeError(`Money JSON property \"${key}\" must be a data value`);\n }\n }\n\n const amount = descriptors.amount?.value;\n const currency = descriptors.currency?.value;\n const unit = descriptors.unit?.value;\n\n if (typeof amount !== 'string' || !INTEGER.test(amount))\n throw new TypeError('Money JSON amount must be a canonical integer string');\n\n if (typeof currency !== 'string' || unit !== 'minor') throw new TypeError('Money JSON currency/unit are invalid');\n\n return { amount, currency, unit };\n}\n"],"mappings":"qFAKA,IAAM,EAAU,6BACV,EAAO,CAAC,SAAU,WAAY,MAAM,EAE1C,SAAgB,EAAO,EAAyB,CAC9C,MAAO,CAAE,OAAQ,EAAM,OAAO,SAAS,EAAG,SAAU,EAAM,SAAS,KAAM,KAAM,OAAQ,CACzF,CAEA,SAAgB,EAAe,EAAgB,EAAqD,CAAC,EAAU,CAC7G,GAAI,CACF,IAAM,EAAU,EAAY,CAAK,EAC3B,EAAkB,EAAQ,UAAY,EAAA,uBAE5C,OAAO,EAAA,MAAM,OAAO,EAAQ,MAAM,EAAG,EAAgB,EAAQ,QAAQ,EAAG,CAAE,KAAM,OAAQ,CAAC,CAC3F,OAAS,EAAO,CACd,MAAM,IAAI,EAAA,WAAW,gBAAiB,qBAAsB,CAAE,MAAO,CAAM,CAAC,CAC9E,CACF,CAEA,SAAS,EAAY,EAA2B,CAC9C,GAAI,OAAO,GAAU,WAAY,GAAkB,OAAO,eAAe,CAAK,IAAM,OAAO,UACzF,MAAU,UAAU,mCAAmC,EAGzD,IAAM,EAAc,OAAO,0BAA0B,CAAK,EACpD,EAAU,QAAQ,QAAQ,CAAK,EAErC,GAAI,EAAQ,SAAW,EAAK,QAAU,CAAC,EAAK,MAAO,GAAQ,EAAQ,SAAS,CAAG,CAAC,EAC9E,MAAU,UAAU,yDAAyD,EAG/E,IAAK,IAAM,KAAO,EAAM,CACtB,IAAM,EAAa,EAAY,GAE/B,GAAI,CAAC,GAAc,EAAE,UAAW,IAAe,EAAW,KAAO,EAAW,IAC1E,MAAU,UAAU,wBAAwB,EAAI,uBAAuB,CAE3E,CAEA,IAAM,EAAS,EAAY,QAAQ,MAC7B,EAAW,EAAY,UAAU,MACjC,EAAO,EAAY,MAAM,MAE/B,GAAI,OAAO,GAAW,UAAY,CAAC,EAAQ,KAAK,CAAM,EACpD,MAAU,UAAU,sDAAsD,EAE5E,GAAI,OAAO,GAAa,UAAY,IAAS,QAAS,MAAU,UAAU,sCAAsC,EAEhH,MAAO,CAAE,SAAQ,WAAU,MAAK,CAClC"}
@@ -1 +1 @@
1
- {"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../src/serialization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAS1D,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAE9C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,CAAA;CAAO,GAAG,KAAK,CAS7G"}
1
+ {"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../src/serialization.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAK1D,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAE9C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,CAAA;CAAO,GAAG,KAAK,CAS7G"}
@@ -30,7 +30,7 @@ function s(e) {
30
30
  let n = t[e];
31
31
  if (!n || !("value" in n) || n.get || n.set) throw TypeError(`Money JSON property "${e}" must be a data value`);
32
32
  }
33
- let a = t.amount.value, o = t.currency.value, s = t.unit.value;
33
+ let a = t.amount?.value, o = t.currency?.value, s = t.unit?.value;
34
34
  if (typeof a != "string" || !r.test(a)) throw TypeError("Money JSON amount must be a canonical integer string");
35
35
  if (typeof o != "string" || s !== "minor") throw TypeError("Money JSON currency/unit are invalid");
36
36
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"serialization.js","names":[],"sources":["../src/serialization.ts"],"sourcesContent":["import type { Currency, Money, MoneyJSON } from './types';\n\nimport { resolveBuiltinCurrency } from './currency';\nimport { CoinsError } from './errors';\nimport { money } from './money';\n\nconst INTEGER = /^(?:0|-[1-9]\\d*|[1-9]\\d*)$/;\nconst KEYS = ['amount', 'currency', 'unit'] as const;\n\nexport function toJSON(value: Money): MoneyJSON {\n return { amount: value.amount.toString(), currency: value.currency.code, unit: 'minor' };\n}\n\nexport function parseMoneyJSON(value: unknown, options: { currency?: (code: string) => Currency } = {}): Money {\n try {\n const payload = readPayload(value);\n const resolveCurrency = options.currency ?? resolveBuiltinCurrency;\n\n return money(BigInt(payload.amount), resolveCurrency(payload.currency), { unit: 'minor' });\n } catch (error) {\n throw new CoinsError('INVALID_MONEY', 'Invalid Money JSON', { cause: error });\n }\n}\n\nfunction readPayload(value: unknown): MoneyJSON {\n if (typeof value !== 'object' || value === null || Object.getPrototypeOf(value) !== Object.prototype) {\n throw new TypeError('Money JSON must be a plain object');\n }\n\n const descriptors = Object.getOwnPropertyDescriptors(value);\n const ownKeys = Reflect.ownKeys(value);\n\n if (ownKeys.length !== KEYS.length || !KEYS.every((key) => ownKeys.includes(key))) {\n throw new TypeError('Money JSON must contain only amount, currency, and unit');\n }\n\n for (const key of KEYS) {\n const descriptor = descriptors[key];\n\n if (!descriptor || !('value' in descriptor) || descriptor.get || descriptor.set) {\n throw new TypeError(`Money JSON property \"${key}\" must be a data value`);\n }\n }\n\n const amount = descriptors.amount!.value;\n const currency = descriptors.currency!.value;\n const unit = descriptors.unit!.value;\n\n if (typeof amount !== 'string' || !INTEGER.test(amount))\n throw new TypeError('Money JSON amount must be a canonical integer string');\n\n if (typeof currency !== 'string' || unit !== 'minor') throw new TypeError('Money JSON currency/unit are invalid');\n\n return { amount, currency, unit };\n}\n"],"mappings":";;;;AAMA,IAAM,IAAU,8BACV,IAAO;CAAC;CAAU;CAAY;AAAM;AAE1C,SAAgB,EAAO,GAAyB;CAC9C,OAAO;EAAE,QAAQ,EAAM,OAAO,SAAS;EAAG,UAAU,EAAM,SAAS;EAAM,MAAM;CAAQ;AACzF;AAEA,SAAgB,EAAe,GAAgB,IAAqD,CAAC,GAAU;CAC7G,IAAI;EACF,IAAM,IAAU,EAAY,CAAK,GAC3B,IAAkB,EAAQ,YAAY;EAE5C,OAAO,EAAM,OAAO,EAAQ,MAAM,GAAG,EAAgB,EAAQ,QAAQ,GAAG,EAAE,MAAM,QAAQ,CAAC;CAC3F,SAAS,GAAO;EACd,MAAM,IAAI,EAAW,iBAAiB,sBAAsB,EAAE,OAAO,EAAM,CAAC;CAC9E;AACF;AAEA,SAAS,EAAY,GAA2B;CAC9C,IAAI,OAAO,KAAU,aAAY,KAAkB,OAAO,eAAe,CAAK,MAAM,OAAO,WACzF,MAAU,UAAU,mCAAmC;CAGzD,IAAM,IAAc,OAAO,0BAA0B,CAAK,GACpD,IAAU,QAAQ,QAAQ,CAAK;CAErC,IAAI,EAAQ,WAAW,EAAK,UAAU,CAAC,EAAK,OAAO,MAAQ,EAAQ,SAAS,CAAG,CAAC,GAC9E,MAAU,UAAU,yDAAyD;CAG/E,KAAK,IAAM,KAAO,GAAM;EACtB,IAAM,IAAa,EAAY;EAE/B,IAAI,CAAC,KAAc,EAAE,WAAW,MAAe,EAAW,OAAO,EAAW,KAC1E,MAAU,UAAU,wBAAwB,EAAI,uBAAuB;CAE3E;CAEA,IAAM,IAAS,EAAY,OAAQ,OAC7B,IAAW,EAAY,SAAU,OACjC,IAAO,EAAY,KAAM;CAE/B,IAAI,OAAO,KAAW,YAAY,CAAC,EAAQ,KAAK,CAAM,GACpD,MAAU,UAAU,sDAAsD;CAE5E,IAAI,OAAO,KAAa,YAAY,MAAS,SAAS,MAAU,UAAU,sCAAsC;CAEhH,OAAO;EAAE;EAAQ;EAAU;CAAK;AAClC"}
1
+ {"version":3,"file":"serialization.js","names":[],"sources":["../src/serialization.ts"],"sourcesContent":["import { resolveBuiltinCurrency } from './currency';\nimport { CoinsError } from './errors';\nimport { money } from './money';\nimport type { Currency, Money, MoneyJSON } from './types';\n\nconst INTEGER = /^(?:0|-[1-9]\\d*|[1-9]\\d*)$/;\nconst KEYS = ['amount', 'currency', 'unit'] as const;\n\nexport function toJSON(value: Money): MoneyJSON {\n return { amount: value.amount.toString(), currency: value.currency.code, unit: 'minor' };\n}\n\nexport function parseMoneyJSON(value: unknown, options: { currency?: (code: string) => Currency } = {}): Money {\n try {\n const payload = readPayload(value);\n const resolveCurrency = options.currency ?? resolveBuiltinCurrency;\n\n return money(BigInt(payload.amount), resolveCurrency(payload.currency), { unit: 'minor' });\n } catch (error) {\n throw new CoinsError('INVALID_MONEY', 'Invalid Money JSON', { cause: error });\n }\n}\n\nfunction readPayload(value: unknown): MoneyJSON {\n if (typeof value !== 'object' || value === null || Object.getPrototypeOf(value) !== Object.prototype) {\n throw new TypeError('Money JSON must be a plain object');\n }\n\n const descriptors = Object.getOwnPropertyDescriptors(value);\n const ownKeys = Reflect.ownKeys(value);\n\n if (ownKeys.length !== KEYS.length || !KEYS.every((key) => ownKeys.includes(key))) {\n throw new TypeError('Money JSON must contain only amount, currency, and unit');\n }\n\n for (const key of KEYS) {\n const descriptor = descriptors[key];\n\n if (!descriptor || !('value' in descriptor) || descriptor.get || descriptor.set) {\n throw new TypeError(`Money JSON property \"${key}\" must be a data value`);\n }\n }\n\n const amount = descriptors.amount?.value;\n const currency = descriptors.currency?.value;\n const unit = descriptors.unit?.value;\n\n if (typeof amount !== 'string' || !INTEGER.test(amount))\n throw new TypeError('Money JSON amount must be a canonical integer string');\n\n if (typeof currency !== 'string' || unit !== 'minor') throw new TypeError('Money JSON currency/unit are invalid');\n\n return { amount, currency, unit };\n}\n"],"mappings":";;;;AAKA,IAAM,IAAU,8BACV,IAAO;CAAC;CAAU;CAAY;AAAM;AAE1C,SAAgB,EAAO,GAAyB;CAC9C,OAAO;EAAE,QAAQ,EAAM,OAAO,SAAS;EAAG,UAAU,EAAM,SAAS;EAAM,MAAM;CAAQ;AACzF;AAEA,SAAgB,EAAe,GAAgB,IAAqD,CAAC,GAAU;CAC7G,IAAI;EACF,IAAM,IAAU,EAAY,CAAK,GAC3B,IAAkB,EAAQ,YAAY;EAE5C,OAAO,EAAM,OAAO,EAAQ,MAAM,GAAG,EAAgB,EAAQ,QAAQ,GAAG,EAAE,MAAM,QAAQ,CAAC;CAC3F,SAAS,GAAO;EACd,MAAM,IAAI,EAAW,iBAAiB,sBAAsB,EAAE,OAAO,EAAM,CAAC;CAC9E;AACF;AAEA,SAAS,EAAY,GAA2B;CAC9C,IAAI,OAAO,KAAU,aAAY,KAAkB,OAAO,eAAe,CAAK,MAAM,OAAO,WACzF,MAAU,UAAU,mCAAmC;CAGzD,IAAM,IAAc,OAAO,0BAA0B,CAAK,GACpD,IAAU,QAAQ,QAAQ,CAAK;CAErC,IAAI,EAAQ,WAAW,EAAK,UAAU,CAAC,EAAK,OAAO,MAAQ,EAAQ,SAAS,CAAG,CAAC,GAC9E,MAAU,UAAU,yDAAyD;CAG/E,KAAK,IAAM,KAAO,GAAM;EACtB,IAAM,IAAa,EAAY;EAE/B,IAAI,CAAC,KAAc,EAAE,WAAW,MAAe,EAAW,OAAO,EAAW,KAC1E,MAAU,UAAU,wBAAwB,EAAI,uBAAuB;CAE3E;CAEA,IAAM,IAAS,EAAY,QAAQ,OAC7B,IAAW,EAAY,UAAU,OACjC,IAAO,EAAY,MAAM;CAE/B,IAAI,OAAO,KAAW,YAAY,CAAC,EAAQ,KAAK,CAAM,GACpD,MAAU,UAAU,sDAAsD;CAE5E,IAAI,OAAO,KAAa,YAAY,MAAS,SAAS,MAAU,UAAU,sCAAsC;CAEhH,OAAO;EAAE;EAAQ;EAAU;CAAK;AAClC"}
package/dist/types.d.ts CHANGED
@@ -27,6 +27,7 @@ export type FormatOptions = Readonly<{
27
27
  locale?: string;
28
28
  maximumFractionDigits?: number;
29
29
  minimumFractionDigits?: number;
30
+ rounding?: RoundingMode;
30
31
  style?: 'code' | 'name' | 'narrowSymbol' | 'symbol';
31
32
  }>;
32
33
  export type MoneyFormatPart = Readonly<{
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,aAAa,EAAE,OAAO,MAAM,CAAC;AAC3C,OAAO,CAAC,MAAM,YAAY,EAAE,OAAO,MAAM,CAAC;AAC1C,OAAO,CAAC,MAAM,UAAU,EAAE,OAAO,MAAM,CAAC;AAExC,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG;IAAE,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;AAE1F,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IACzD,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC;IAC7B,QAAQ,CAAC,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,QAAQ,CAAC;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,CAAC,CAAC;IACZ,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;CAC1B,CAAC,CAAC;AAEH,MAAM,MAAM,YAAY,CAAC,IAAI,SAAS,QAAQ,GAAG,QAAQ,EAAE,EAAE,SAAS,QAAQ,GAAG,QAAQ,IAAI,QAAQ,CAAC;IACpG,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,EAAE,CAAC;IACP,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,cAAc,GAAG,QAAQ,CAAC;CACrD,CAAC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC7F,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,kBAAkB,GAAG,UAAU,GAAG,YAAY,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,aAAa,EAAE,OAAO,MAAM,CAAC;AAC3C,OAAO,CAAC,MAAM,YAAY,EAAE,OAAO,MAAM,CAAC;AAC1C,OAAO,CAAC,MAAM,UAAU,EAAE,OAAO,MAAM,CAAC;AAExC,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG;IAAE,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;AAE1F,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IACzD,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC;IAC7B,QAAQ,CAAC,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,QAAQ,CAAC;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,CAAC,CAAC;IACZ,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;CAC1B,CAAC,CAAC;AAEH,MAAM,MAAM,YAAY,CAAC,IAAI,SAAS,QAAQ,GAAG,QAAQ,EAAE,EAAE,SAAS,QAAQ,GAAG,QAAQ,IAAI,QAAQ,CAAC;IACpG,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,EAAE,CAAC;IACP,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,cAAc,GAAG,QAAQ,CAAC;CACrD,CAAC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC7F,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,kBAAkB,GAAG,UAAU,GAAG,YAAY,CAAC"}
package/package.json CHANGED
@@ -1,8 +1,16 @@
1
1
  {
2
2
  "name": "@vielzeug/coins",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Bigint-based monetary arithmetic with currency formatting, exchange rates, and rounding policies",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/helmuthdu/vielzeug",
8
+ "directory": "packages/coins"
9
+ },
5
10
  "type": "module",
11
+ "engines": {
12
+ "node": ">=22"
13
+ },
6
14
  "files": [
7
15
  "dist"
8
16
  ],
@@ -11,32 +19,28 @@
11
19
  "types": "dist/index.d.ts",
12
20
  "exports": {
13
21
  ".": {
14
- "source": "./src/index.ts",
15
- "types": "./dist/index.d.ts",
16
22
  "import": "./dist/index.js",
17
- "require": "./dist/index.cjs"
23
+ "require": "./dist/index.cjs",
24
+ "types": "./dist/index.d.ts"
18
25
  }
19
26
  },
20
- "scripts": {
21
- "build": "vite build && pnpm run build:bundle && pnpm run build:types",
22
- "build:types": "tsc -p tsconfig.declarations.json",
23
- "fix": "eslint --fix src",
24
- "lint": "eslint src",
25
- "prepublishOnly": "pnpm run build",
26
- "test": "vitest",
27
- "build:bundle": "vite build --config vite.bundle.config.ts"
28
- },
29
27
  "publishConfig": {
30
28
  "access": "public",
31
29
  "registry": "https://registry.npmjs.org/"
32
30
  },
33
- "engines": {
34
- "node": ">=22"
31
+ "scripts": {
32
+ "build": "vite build && pnpm run build:bundle && pnpm run build:types",
33
+ "build:bundle": "vite build --config vite.bundle.config.ts",
34
+ "build:types": "tsc -p tsconfig.declarations.json",
35
+ "fix": "biome check --write src",
36
+ "lint": "biome ci src",
37
+ "prepublishOnly": "pnpm run build",
38
+ "test": "vitest"
35
39
  },
36
40
  "devDependencies": {
37
- "@types/node": "^26.1.2",
41
+ "@types/node": "^26.2.0",
38
42
  "typescript": "^6.0.3",
39
- "vite": "^8.2.0",
43
+ "vite": "^8.2.1",
40
44
  "vitest": "^4.1.10"
41
45
  }
42
46
  }