@vielzeug/coins 2.1.0 → 2.2.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 (56) hide show
  1. package/README.md +2 -2
  2. package/dist/{decimal.cjs → _decimal.cjs} +2 -2
  3. package/dist/_decimal.cjs.map +1 -0
  4. package/dist/{decimal.d.ts → _decimal.d.ts} +1 -1
  5. package/dist/_decimal.d.ts.map +1 -0
  6. package/dist/{decimal.js → _decimal.js} +3 -2
  7. package/dist/_decimal.js.map +1 -0
  8. package/dist/aggregate.cjs +1 -1
  9. package/dist/aggregate.cjs.map +1 -1
  10. package/dist/aggregate.js +7 -9
  11. package/dist/aggregate.js.map +1 -1
  12. package/dist/coins.cjs +1 -1
  13. package/dist/coins.cjs.map +1 -1
  14. package/dist/coins.iife.js +1 -1
  15. package/dist/coins.iife.js.map +1 -1
  16. package/dist/coins.js +1 -1
  17. package/dist/coins.js.map +1 -1
  18. package/dist/currency.cjs +1 -1
  19. package/dist/currency.cjs.map +1 -1
  20. package/dist/currency.d.ts +3 -4
  21. package/dist/currency.d.ts.map +1 -1
  22. package/dist/currency.js +20 -40
  23. package/dist/currency.js.map +1 -1
  24. package/dist/errors.cjs.map +1 -1
  25. package/dist/errors.d.ts +1 -1
  26. package/dist/errors.d.ts.map +1 -1
  27. package/dist/errors.js.map +1 -1
  28. package/dist/exchange.cjs +1 -1
  29. package/dist/exchange.cjs.map +1 -1
  30. package/dist/exchange.d.ts +1 -0
  31. package/dist/exchange.d.ts.map +1 -1
  32. package/dist/exchange.js +12 -12
  33. package/dist/exchange.js.map +1 -1
  34. package/dist/format.cjs +1 -1
  35. package/dist/format.cjs.map +1 -1
  36. package/dist/format.js +15 -15
  37. package/dist/format.js.map +1 -1
  38. package/dist/index.cjs +1 -1
  39. package/dist/index.d.ts +2 -2
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +5 -5
  42. package/dist/money.cjs +1 -1
  43. package/dist/money.cjs.map +1 -1
  44. package/dist/money.d.ts +5 -4
  45. package/dist/money.d.ts.map +1 -1
  46. package/dist/money.js +33 -39
  47. package/dist/money.js.map +1 -1
  48. package/dist/serialization.cjs +1 -1
  49. package/dist/serialization.cjs.map +1 -1
  50. package/dist/serialization.d.ts.map +1 -1
  51. package/dist/serialization.js +15 -15
  52. package/dist/serialization.js.map +1 -1
  53. package/package.json +2 -1
  54. package/dist/decimal.cjs.map +0 -1
  55. package/dist/decimal.d.ts.map +0 -1
  56. package/dist/decimal.js.map +0 -1
package/README.md CHANGED
@@ -61,9 +61,9 @@ Built-in definitions: `USD`, `EUR`, `GBP`, `JPY`, `KRW`, `BHD`, `KWD`.
61
61
  Define a business currency explicitly when required:
62
62
 
63
63
  ```ts
64
- import { defineCurrency, money } from '@vielzeug/coins';
64
+ import { currency, money } from '@vielzeug/coins';
65
65
 
66
- const POINTS = defineCurrency({ code: 'PTS', minorUnit: 0 });
66
+ const POINTS = currency({ code: 'PTS', minorUnit: 0 });
67
67
  const balance = money('250', POINTS);
68
68
  ```
69
69
 
@@ -1,2 +1,2 @@
1
- const e=require("./errors.cjs");var t=/^(-?)(\d+)(?:\.(\d+))?$/,n=1e3,r=100;function i(i){if(i.length>n)throw new e.CoinsError(`INVALID_DECIMAL`,`Decimal input is too long`);let a=t.exec(i);if(!a)throw new e.CoinsError(`INVALID_DECIMAL`,`Invalid decimal: "${i}"`);let o=(a[3]??``).replace(/0+$/,``);if(o.length>r)throw new e.CoinsError(`INVALID_DECIMAL`,`Decimal precision cannot exceed ${r} places`);let c=10n**BigInt(o.length),l=BigInt(a[2])*c+BigInt(o||`0`),u=a[1]===`-`&&l!==0n?-l:l,d=s(u<0n?-u:u,c);return Object.freeze({denominator:c/d,numerator:u/d})}function a(t,n,r){if(n<=0n)throw new e.CoinsError(`INVALID_DECIMAL`,`Decimal denominator must be positive`);let i=t<0n,a=i?-t:t,o=a/n,s=a%n;if(s===0n)return i?-o:o;let c=(()=>{switch(r){case`awayFromZero`:return!0;case`ceil`:return!i;case`floor`:return i;case`halfAwayFromZero`:return s*2n>=n;case`halfEven`:{let e=s*2n;return e>n||e===n&&o%2n!=0n}case`towardZero`:return!1}})()?o+1n:o;return i?-c:c}function o(e,t){let n=e<0n,r=n?-e:e,i=10n**BigInt(t),a=r/i;if(t===0)return`${n?`-`:``}${a}`;let o=(r%i).toString().padStart(t,`0`);return`${n?`-`:``}${a}.${o}`}function s(e,t){let n=e,r=t;for(;r!==0n;)[n,r]=[r,n%r];return n===0n?1n:n}function c(e,t){return e/s(e,t)*t}exports.decimal=i,exports.gcd=s,exports.lcm=c,exports.roundDivision=a,exports.toDecimalString=o;
2
- //# sourceMappingURL=decimal.cjs.map
1
+ const e=require("./errors.cjs");var t=/^(-?)(\d+)(?:\.(\d+))?$/,n=1e3,r=100;function i(i){if(i.length>n)throw new e.CoinsError(`INVALID_DECIMAL`,`Decimal input is too long`);let a=t.exec(i);if(!a)throw new e.CoinsError(`INVALID_DECIMAL`,`Invalid decimal: "${i}"`);let o=(a[3]??``).replace(/0+$/,``);if(o.length>r)throw new e.CoinsError(`INVALID_DECIMAL`,`Decimal precision cannot exceed ${r} places`);let c=10n**BigInt(o.length),l=BigInt(a[2])*c+BigInt(o||`0`),u=a[1]===`-`&&l!==0n?-l:l,d=s(u<0n?-u:u,c);return Object.freeze({denominator:c/d,numerator:u/d})}function a(t,n,r){if(n<=0n)throw new e.CoinsError(`INVALID_DECIMAL`,`Decimal denominator must be positive`);let i=t<0n,a=i?-t:t,o=a/n,s=a%n;if(s===0n)return i?-o:o;let c=(()=>{switch(r){case`awayFromZero`:return!0;case`ceil`:return!i;case`floor`:return i;case`halfAwayFromZero`:return s*2n>=n;case`halfEven`:{let e=s*2n;return e>n||e===n&&o%2n!=0n}case`towardZero`:return!1;default:throw new e.CoinsError(`INVALID_ROUNDING`,`Unknown rounding mode: ${r}`)}})()?o+1n:o;return i?-c:c}function o(e,t){let n=e<0n,r=n?-e:e,i=10n**BigInt(t),a=r/i;if(t===0)return`${n?`-`:``}${a}`;let o=(r%i).toString().padStart(t,`0`);return`${n?`-`:``}${a}.${o}`}function s(e,t){let n=e,r=t;for(;r!==0n;)[n,r]=[r,n%r];return n===0n?1n:n}function c(e,t){return e/s(e,t)*t}exports.decimal=i,exports.gcd=s,exports.lcm=c,exports.roundDivision=a,exports.toDecimalString=o;
2
+ //# sourceMappingURL=_decimal.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_decimal.cjs","names":[],"sources":["../src/_decimal.ts"],"sourcesContent":["import { CoinsError } from './errors';\nimport type { Decimal, RoundingMode } from './types';\n\nconst DECIMAL = /^(-?)(\\d+)(?:\\.(\\d+))?$/;\nconst MAX_DECIMAL_DIGITS = 1000;\nconst MAX_DECIMAL_PLACES = 100;\n\nexport function decimal(value: string): Decimal {\n if (value.length > MAX_DECIMAL_DIGITS) throw new CoinsError('INVALID_DECIMAL', 'Decimal input is too long');\n\n const match = DECIMAL.exec(value);\n\n if (!match) throw new CoinsError('INVALID_DECIMAL', `Invalid decimal: \"${value}\"`);\n\n const fraction = (match[3] ?? '').replace(/0+$/, '');\n\n if (fraction.length > MAX_DECIMAL_PLACES) {\n throw new CoinsError('INVALID_DECIMAL', `Decimal precision cannot exceed ${MAX_DECIMAL_PLACES} places`);\n }\n\n const denominator = 10n ** BigInt(fraction.length);\n const unsigned = BigInt(match[2]!) * denominator + BigInt(fraction || '0');\n const numerator = match[1] === '-' && unsigned !== 0n ? -unsigned : unsigned;\n const divisor = gcd(numerator < 0n ? -numerator : numerator, denominator);\n\n return Object.freeze({ denominator: denominator / divisor, numerator: numerator / divisor }) as Decimal;\n}\n\nexport function roundDivision(numerator: bigint, denominator: bigint, mode: RoundingMode): bigint {\n if (denominator <= 0n) throw new CoinsError('INVALID_DECIMAL', 'Decimal denominator must be positive');\n\n const negative = numerator < 0n;\n const absolute = negative ? -numerator : numerator;\n const quotient = absolute / denominator;\n const remainder = absolute % denominator;\n\n if (remainder === 0n) return negative ? -quotient : quotient;\n\n const increment = (() => {\n switch (mode) {\n case 'awayFromZero':\n return true;\n case 'ceil':\n return !negative;\n case 'floor':\n return negative;\n case 'halfAwayFromZero':\n return remainder * 2n >= denominator;\n case 'halfEven': {\n const doubled = remainder * 2n;\n\n return doubled > denominator || (doubled === denominator && quotient % 2n !== 0n);\n }\n case 'towardZero':\n return false;\n default:\n throw new CoinsError('INVALID_ROUNDING', `Unknown rounding mode: ${mode satisfies never}`);\n }\n })();\n\n const result = increment ? quotient + 1n : quotient;\n\n return negative ? -result : result;\n}\n\nexport function toDecimalString(amount: bigint, minorUnit: number): string {\n const negative = amount < 0n;\n const absolute = negative ? -amount : amount;\n const scale = 10n ** BigInt(minorUnit);\n const whole = absolute / scale;\n\n if (minorUnit === 0) return `${negative ? '-' : ''}${whole}`;\n\n const fraction = (absolute % scale).toString().padStart(minorUnit, '0');\n\n return `${negative ? '-' : ''}${whole}.${fraction}`;\n}\n\nexport function gcd(left: bigint, right: bigint): bigint {\n let a = left;\n let b = right;\n\n while (b !== 0n) [a, b] = [b, a % b];\n\n return a === 0n ? 1n : a;\n}\n\nexport function lcm(left: bigint, right: bigint): bigint {\n return (left / gcd(left, right)) * right;\n}\n"],"mappings":"gCAGA,IAAM,EAAU,0BACV,EAAqB,IACrB,EAAqB,IAE3B,SAAgB,EAAQ,EAAwB,CAC9C,GAAI,EAAM,OAAS,EAAoB,MAAM,IAAI,EAAA,WAAW,kBAAmB,2BAA2B,EAE1G,IAAM,EAAQ,EAAQ,KAAK,CAAK,EAEhC,GAAI,CAAC,EAAO,MAAM,IAAI,EAAA,WAAW,kBAAmB,qBAAqB,EAAM,EAAE,EAEjF,IAAM,GAAY,EAAM,IAAM,GAAA,CAAI,QAAQ,MAAO,EAAE,EAEnD,GAAI,EAAS,OAAS,EACpB,MAAM,IAAI,EAAA,WAAW,kBAAmB,mCAAmC,EAAmB,QAAQ,EAGxG,IAAM,EAAc,KAAO,OAAO,EAAS,MAAM,EAC3C,EAAW,OAAO,EAAM,EAAG,EAAI,EAAc,OAAO,GAAY,GAAG,EACnE,EAAY,EAAM,KAAO,KAAO,IAAa,GAAK,CAAC,EAAW,EAC9D,EAAU,EAAI,EAAY,GAAK,CAAC,EAAY,EAAW,CAAW,EAExE,OAAO,OAAO,OAAO,CAAE,YAAa,EAAc,EAAS,UAAW,EAAY,CAAQ,CAAC,CAC7F,CAEA,SAAgB,EAAc,EAAmB,EAAqB,EAA4B,CAChG,GAAI,GAAe,GAAI,MAAM,IAAI,EAAA,WAAW,kBAAmB,sCAAsC,EAErG,IAAM,EAAW,EAAY,GACvB,EAAW,EAAW,CAAC,EAAY,EACnC,EAAW,EAAW,EACtB,EAAY,EAAW,EAE7B,GAAI,IAAc,GAAI,OAAO,EAAW,CAAC,EAAW,EAwBpD,IAAM,OAtBmB,CACvB,OAAQ,EAAR,CACE,IAAK,eACH,MAAO,GACT,IAAK,OACH,MAAO,CAAC,EACV,IAAK,QACH,OAAO,EACT,IAAK,mBACH,OAAO,EAAY,IAAM,EAC3B,IAAK,WAAY,CACf,IAAM,EAAU,EAAY,GAE5B,OAAO,EAAU,GAAgB,IAAY,GAAe,EAAW,IAAO,EAChF,CACA,IAAK,aACH,MAAO,GACT,QACE,MAAM,IAAI,EAAA,WAAW,mBAAoB,0BAA0B,GAAsB,CAC7F,CACF,EAAA,CAEe,EAAY,EAAW,GAAK,EAE3C,OAAO,EAAW,CAAC,EAAS,CAC9B,CAEA,SAAgB,EAAgB,EAAgB,EAA2B,CACzE,IAAM,EAAW,EAAS,GACpB,EAAW,EAAW,CAAC,EAAS,EAChC,EAAQ,KAAO,OAAO,CAAS,EAC/B,EAAQ,EAAW,EAEzB,GAAI,IAAc,EAAG,MAAO,GAAG,EAAW,IAAM,KAAK,IAErD,IAAM,GAAY,EAAW,EAAA,CAAO,SAAS,CAAC,CAAC,SAAS,EAAW,GAAG,EAEtE,MAAO,GAAG,EAAW,IAAM,KAAK,EAAM,GAAG,GAC3C,CAEA,SAAgB,EAAI,EAAc,EAAuB,CACvD,IAAI,EAAI,EACJ,EAAI,EAER,KAAO,IAAM,IAAI,CAAC,EAAG,GAAK,CAAC,EAAG,EAAI,CAAC,EAEnC,OAAO,IAAM,GAAK,GAAK,CACzB,CAEA,SAAgB,EAAI,EAAc,EAAuB,CACvD,OAAQ,EAAO,EAAI,EAAM,CAAK,EAAK,CACrC"}
@@ -4,4 +4,4 @@ export declare function roundDivision(numerator: bigint, denominator: bigint, mo
4
4
  export declare function toDecimalString(amount: bigint, minorUnit: number): string;
5
5
  export declare function gcd(left: bigint, right: bigint): bigint;
6
6
  export declare function lcm(left: bigint, right: bigint): bigint;
7
- //# sourceMappingURL=decimal.d.ts.map
7
+ //# sourceMappingURL=_decimal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_decimal.d.ts","sourceRoot":"","sources":["../src/_decimal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAMrD,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAmB9C;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAmChG;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAWzE;AAED,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOvD;AAED,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD"}
@@ -1,5 +1,5 @@
1
1
  import { CoinsError as e } from "./errors.js";
2
- //#region src/decimal.ts
2
+ //#region src/_decimal.ts
3
3
  var t = /^(-?)(\d+)(?:\.(\d+))?$/, n = 1e3, r = 100;
4
4
  function i(i) {
5
5
  if (i.length > n) throw new e("INVALID_DECIMAL", "Decimal input is too long");
@@ -28,6 +28,7 @@ function a(t, n, r) {
28
28
  return e > n || e === n && o % 2n != 0n;
29
29
  }
30
30
  case "towardZero": return !1;
31
+ default: throw new e("INVALID_ROUNDING", `Unknown rounding mode: ${r}`);
31
32
  }
32
33
  })() ? o + 1n : o;
33
34
  return i ? -c : c;
@@ -49,4 +50,4 @@ function c(e, t) {
49
50
  //#endregion
50
51
  export { i as decimal, s as gcd, c as lcm, a as roundDivision, o as toDecimalString };
51
52
 
52
- //# sourceMappingURL=decimal.js.map
53
+ //# sourceMappingURL=_decimal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_decimal.js","names":[],"sources":["../src/_decimal.ts"],"sourcesContent":["import { CoinsError } from './errors';\nimport type { Decimal, RoundingMode } from './types';\n\nconst DECIMAL = /^(-?)(\\d+)(?:\\.(\\d+))?$/;\nconst MAX_DECIMAL_DIGITS = 1000;\nconst MAX_DECIMAL_PLACES = 100;\n\nexport function decimal(value: string): Decimal {\n if (value.length > MAX_DECIMAL_DIGITS) throw new CoinsError('INVALID_DECIMAL', 'Decimal input is too long');\n\n const match = DECIMAL.exec(value);\n\n if (!match) throw new CoinsError('INVALID_DECIMAL', `Invalid decimal: \"${value}\"`);\n\n const fraction = (match[3] ?? '').replace(/0+$/, '');\n\n if (fraction.length > MAX_DECIMAL_PLACES) {\n throw new CoinsError('INVALID_DECIMAL', `Decimal precision cannot exceed ${MAX_DECIMAL_PLACES} places`);\n }\n\n const denominator = 10n ** BigInt(fraction.length);\n const unsigned = BigInt(match[2]!) * denominator + BigInt(fraction || '0');\n const numerator = match[1] === '-' && unsigned !== 0n ? -unsigned : unsigned;\n const divisor = gcd(numerator < 0n ? -numerator : numerator, denominator);\n\n return Object.freeze({ denominator: denominator / divisor, numerator: numerator / divisor }) as Decimal;\n}\n\nexport function roundDivision(numerator: bigint, denominator: bigint, mode: RoundingMode): bigint {\n if (denominator <= 0n) throw new CoinsError('INVALID_DECIMAL', 'Decimal denominator must be positive');\n\n const negative = numerator < 0n;\n const absolute = negative ? -numerator : numerator;\n const quotient = absolute / denominator;\n const remainder = absolute % denominator;\n\n if (remainder === 0n) return negative ? -quotient : quotient;\n\n const increment = (() => {\n switch (mode) {\n case 'awayFromZero':\n return true;\n case 'ceil':\n return !negative;\n case 'floor':\n return negative;\n case 'halfAwayFromZero':\n return remainder * 2n >= denominator;\n case 'halfEven': {\n const doubled = remainder * 2n;\n\n return doubled > denominator || (doubled === denominator && quotient % 2n !== 0n);\n }\n case 'towardZero':\n return false;\n default:\n throw new CoinsError('INVALID_ROUNDING', `Unknown rounding mode: ${mode satisfies never}`);\n }\n })();\n\n const result = increment ? quotient + 1n : quotient;\n\n return negative ? -result : result;\n}\n\nexport function toDecimalString(amount: bigint, minorUnit: number): string {\n const negative = amount < 0n;\n const absolute = negative ? -amount : amount;\n const scale = 10n ** BigInt(minorUnit);\n const whole = absolute / scale;\n\n if (minorUnit === 0) return `${negative ? '-' : ''}${whole}`;\n\n const fraction = (absolute % scale).toString().padStart(minorUnit, '0');\n\n return `${negative ? '-' : ''}${whole}.${fraction}`;\n}\n\nexport function gcd(left: bigint, right: bigint): bigint {\n let a = left;\n let b = right;\n\n while (b !== 0n) [a, b] = [b, a % b];\n\n return a === 0n ? 1n : a;\n}\n\nexport function lcm(left: bigint, right: bigint): bigint {\n return (left / gcd(left, right)) * right;\n}\n"],"mappings":";;AAGA,IAAM,IAAU,2BACV,IAAqB,KACrB,IAAqB;AAE3B,SAAgB,EAAQ,GAAwB;CAC9C,IAAI,EAAM,SAAS,GAAoB,MAAM,IAAI,EAAW,mBAAmB,2BAA2B;CAE1G,IAAM,IAAQ,EAAQ,KAAK,CAAK;CAEhC,IAAI,CAAC,GAAO,MAAM,IAAI,EAAW,mBAAmB,qBAAqB,EAAM,EAAE;CAEjF,IAAM,KAAY,EAAM,MAAM,GAAA,CAAI,QAAQ,OAAO,EAAE;CAEnD,IAAI,EAAS,SAAS,GACpB,MAAM,IAAI,EAAW,mBAAmB,mCAAmC,EAAmB,QAAQ;CAGxG,IAAM,IAAc,OAAO,OAAO,EAAS,MAAM,GAC3C,IAAW,OAAO,EAAM,EAAG,IAAI,IAAc,OAAO,KAAY,GAAG,GACnE,IAAY,EAAM,OAAO,OAAO,MAAa,KAAK,CAAC,IAAW,GAC9D,IAAU,EAAI,IAAY,KAAK,CAAC,IAAY,GAAW,CAAW;CAExE,OAAO,OAAO,OAAO;EAAE,aAAa,IAAc;EAAS,WAAW,IAAY;CAAQ,CAAC;AAC7F;AAEA,SAAgB,EAAc,GAAmB,GAAqB,GAA4B;CAChG,IAAI,KAAe,IAAI,MAAM,IAAI,EAAW,mBAAmB,sCAAsC;CAErG,IAAM,IAAW,IAAY,IACvB,IAAW,IAAW,CAAC,IAAY,GACnC,IAAW,IAAW,GACtB,IAAY,IAAW;CAE7B,IAAI,MAAc,IAAI,OAAO,IAAW,CAAC,IAAW;CAwBpD,IAAM,WAtBmB;EACvB,QAAQ,GAAR;GACE,KAAK,gBACH,OAAO;GACT,KAAK,QACH,OAAO,CAAC;GACV,KAAK,SACH,OAAO;GACT,KAAK,oBACH,OAAO,IAAY,MAAM;GAC3B,KAAK,YAAY;IACf,IAAM,IAAU,IAAY;IAE5B,OAAO,IAAU,KAAgB,MAAY,KAAe,IAAW,MAAO;GAChF;GACA,KAAK,cACH,OAAO;GACT,SACE,MAAM,IAAI,EAAW,oBAAoB,0BAA0B,GAAsB;EAC7F;CACF,EAAA,CAEe,IAAY,IAAW,KAAK;CAE3C,OAAO,IAAW,CAAC,IAAS;AAC9B;AAEA,SAAgB,EAAgB,GAAgB,GAA2B;CACzE,IAAM,IAAW,IAAS,IACpB,IAAW,IAAW,CAAC,IAAS,GAChC,IAAQ,OAAO,OAAO,CAAS,GAC/B,IAAQ,IAAW;CAEzB,IAAI,MAAc,GAAG,OAAO,GAAG,IAAW,MAAM,KAAK;CAErD,IAAM,KAAY,IAAW,EAAA,CAAO,SAAS,CAAC,CAAC,SAAS,GAAW,GAAG;CAEtE,OAAO,GAAG,IAAW,MAAM,KAAK,EAAM,GAAG;AAC3C;AAEA,SAAgB,EAAI,GAAc,GAAuB;CACvD,IAAI,IAAI,GACJ,IAAI;CAER,OAAO,MAAM,KAAI,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC;CAEnC,OAAO,MAAM,KAAK,KAAK;AACzB;AAEA,SAAgB,EAAI,GAAc,GAAuB;CACvD,OAAQ,IAAO,EAAI,GAAM,CAAK,IAAK;AACrC"}
@@ -1,2 +1,2 @@
1
- const e=require("./errors.cjs"),t=require("./decimal.cjs"),n=require("./money.cjs");function r(t,r){let i=0n,a=r?.currency;for(let r of t){if(!n.isMoney(r))throw new e.CoinsError(`INVALID_MONEY`,`sum() requires canonical money values`);if(a===void 0)a=r.currency;else if(r.currency!==a)throw new e.CurrencyMismatchError(a.code,r.currency.code);i+=r.amount}if(a===void 0)throw new e.CoinsError(`INVALID_MONEY`,`sum() of empty iterable requires { currency }`);return n.withMinor(i,a)}function i(r,i){if(!n.isMoney(r))throw new e.CoinsError(`INVALID_MONEY`,`allocate() requires canonical money`);if(typeof i==`number`)return a(r,i);if(i.length===0)throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation weights cannot be empty`);let o=i.map(t.decimal);if(o.some(e=>e.numerator<0n))throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation weights cannot be negative`);let s=o.reduce((e,n)=>t.lcm(e,n.denominator),1n),c=o.map(e=>e.numerator*(s/e.denominator)),l=c.reduce((e,t)=>e+t,0n);if(l===0n)throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation weights must include a positive value`);let u=r.amount<0n?-1n:1n,d=r.amount<0n?-r.amount:r.amount,f=c.map(e=>d*e/l),p=d-f.reduce((e,t)=>e+t,0n),m=c.map((e,t)=>({index:t,remainder:d*e%l})).sort((e,t)=>e.remainder===t.remainder?e.index-t.index:e.remainder>t.remainder?-1:1);for(let e of m){if(p===0n)break;f[e.index]+=1n,p-=1n}return f.map(e=>n.withMinor(e*u,r.currency))}function a(t,r){if(!Number.isInteger(r)||r<1)throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation count must be a positive integer`);let i=BigInt(r),a=t.amount<0n?-1n:1n,o=t.amount<0n?-t.amount:t.amount,s=o/i,c=o%i;return Array.from({length:r},(e,r)=>n.withMinor((s+(BigInt(r)<c?1n:0n))*a,t.currency))}exports.allocate=i,exports.sum=r;
1
+ const e=require("./errors.cjs"),t=require("./_decimal.cjs"),n=require("./money.cjs");function r(t,r){let i=0n,a=r?.currency;for(let r of t){if(n.assertMoney(r),a===void 0)a=r.currency;else if(r.currency!==a)throw new e.CurrencyMismatchError(a.code,r.currency.code);i+=r.amount}if(a===void 0)throw new e.CoinsError(`INVALID_MONEY`,`sum() of empty iterable requires { currency }`);return n.createMoney(i,a)}function i(r,i){if(n.assertMoney(r),typeof i==`number`)return a(r,i);if(i.length===0)throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation weights cannot be empty`);let o=i.map(t.decimal);if(o.some(e=>e.numerator<0n))throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation weights cannot be negative`);let s=o.reduce((e,n)=>t.lcm(e,n.denominator),1n),c=o.map(e=>e.numerator*(s/e.denominator)),l=c.reduce((e,t)=>e+t,0n);if(l===0n)throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation weights must include a positive value`);let u=r.amount<0n?-1n:1n,d=r.amount<0n?-r.amount:r.amount,f=c.map(e=>d*e/l),p=d-f.reduce((e,t)=>e+t,0n),m=c.map((e,t)=>({index:t,remainder:d*e%l})).sort((e,t)=>e.remainder===t.remainder?e.index-t.index:e.remainder>t.remainder?-1:1);for(let e of m){if(p===0n)break;f[e.index]+=1n,p-=1n}return f.map(e=>n.createMoney(e*u,r.currency))}function a(t,r){if(!Number.isInteger(r)||r<1)throw new e.CoinsError(`INVALID_ALLOCATION`,`Allocation count must be a positive integer`);let i=BigInt(r),a=t.amount<0n?-1n:1n,o=t.amount<0n?-t.amount:t.amount,s=o/i,c=o%i;return Array.from({length:r},(e,r)=>n.createMoney((s+(BigInt(r)<c?1n:0n))*a,t.currency))}exports.allocate=i,exports.sum=r;
2
2
  //# sourceMappingURL=aggregate.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate.cjs","names":[],"sources":["../src/aggregate.ts"],"sourcesContent":["import { decimal, lcm } from './decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { isMoney, withMinor } from './money';\nimport type { Currency, Money } from './types';\n\nexport function sum<C extends Currency>(values: readonly Money<C>[]): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options: { currency: C }): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options?: { currency: C }): Money<C> {\n let amount = 0n;\n let currency: C | undefined = options?.currency;\n\n for (const value of values) {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'sum() requires canonical money values');\n\n if (currency === undefined) {\n currency = value.currency;\n } else if (value.currency !== currency) {\n throw new CurrencyMismatchError(currency.code, value.currency.code);\n }\n\n amount += value.amount;\n }\n\n if (currency === undefined) throw new CoinsError('INVALID_MONEY', 'sum() of empty iterable requires { currency }');\n\n return withMinor(amount, currency);\n}\n\nexport function allocate<C extends Currency>(value: Money<C>, count: number): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weights: readonly string[]): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weightsOrCount: number | readonly string[]): Money<C>[] {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'allocate() requires canonical money');\n\n if (typeof weightsOrCount === 'number') return allocateEvenly(value, weightsOrCount);\n\n if (weightsOrCount.length === 0) throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be empty');\n\n const weights = weightsOrCount.map(decimal);\n\n if (weights.some((weight) => weight.numerator < 0n)) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be negative');\n }\n\n const commonDenominator = weights.reduce((result, weight) => lcm(result, weight.denominator), 1n);\n const scaledWeights = weights.map((weight) => weight.numerator * (commonDenominator / weight.denominator));\n const totalWeight = scaledWeights.reduce((result, weight) => result + weight, 0n);\n\n if (totalWeight === 0n)\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights must include a positive value');\n\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const shares = scaledWeights.map((weight) => (absolute * weight) / totalWeight);\n let remainder = absolute - shares.reduce((result, amount) => result + amount, 0n);\n const ranked = scaledWeights\n .map((weight, index) => ({ index, remainder: (absolute * weight) % totalWeight }))\n .sort((left, right) =>\n left.remainder === right.remainder ? left.index - right.index : left.remainder > right.remainder ? -1 : 1,\n );\n\n for (const entry of ranked) {\n if (remainder === 0n) break;\n\n shares[entry.index]! += 1n;\n remainder -= 1n;\n }\n\n return shares.map((amount) => withMinor(amount * sign, value.currency));\n}\n\nfunction allocateEvenly<C extends Currency>(value: Money<C>, countValue: number): Money<C>[] {\n if (!Number.isInteger(countValue) || countValue < 1) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation count must be a positive integer');\n }\n\n const count = BigInt(countValue);\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const base = absolute / count;\n const remainder = absolute % count;\n\n return Array.from({ length: countValue }, (_, index) =>\n withMinor((base + (BigInt(index) < remainder ? 1n : 0n)) * sign, value.currency),\n );\n}\n"],"mappings":"oFAOA,SAAgB,EAAwB,EAA4B,EAAqC,CACvG,IAAI,EAAS,GACT,EAA0B,GAAS,SAEvC,IAAK,IAAM,KAAS,EAAQ,CAC1B,GAAI,CAAC,EAAA,QAAQ,CAAK,EAAG,MAAM,IAAI,EAAA,WAAW,gBAAiB,uCAAuC,EAElG,GAAI,IAAa,IAAA,GACf,EAAW,EAAM,cACZ,GAAI,EAAM,WAAa,EAC5B,MAAM,IAAI,EAAA,sBAAsB,EAAS,KAAM,EAAM,SAAS,IAAI,EAGpE,GAAU,EAAM,MAClB,CAEA,GAAI,IAAa,IAAA,GAAW,MAAM,IAAI,EAAA,WAAW,gBAAiB,+CAA+C,EAEjH,OAAO,EAAA,UAAU,EAAQ,CAAQ,CACnC,CAIA,SAAgB,EAA6B,EAAiB,EAAwD,CACpH,GAAI,CAAC,EAAA,QAAQ,CAAK,EAAG,MAAM,IAAI,EAAA,WAAW,gBAAiB,qCAAqC,EAEhG,GAAI,OAAO,GAAmB,SAAU,OAAO,EAAe,EAAO,CAAc,EAEnF,GAAI,EAAe,SAAW,EAAG,MAAM,IAAI,EAAA,WAAW,qBAAsB,oCAAoC,EAEhH,IAAM,EAAU,EAAe,IAAI,EAAA,OAAO,EAE1C,GAAI,EAAQ,KAAM,GAAW,EAAO,UAAY,EAAE,EAChD,MAAM,IAAI,EAAA,WAAW,qBAAsB,uCAAuC,EAGpF,IAAM,EAAoB,EAAQ,QAAQ,EAAQ,IAAW,EAAA,IAAI,EAAQ,EAAO,WAAW,EAAG,EAAE,EAC1F,EAAgB,EAAQ,IAAK,GAAW,EAAO,WAAa,EAAoB,EAAO,YAAY,EACnG,EAAc,EAAc,QAAQ,EAAQ,IAAW,EAAS,EAAQ,EAAE,EAEhF,GAAI,IAAgB,GAClB,MAAM,IAAI,EAAA,WAAW,qBAAsB,kDAAkD,EAE/F,IAAM,EAAO,EAAM,OAAS,GAAK,CAAC,GAAK,GACjC,EAAW,EAAM,OAAS,GAAK,CAAC,EAAM,OAAS,EAAM,OACrD,EAAS,EAAc,IAAK,GAAY,EAAW,EAAU,CAAW,EAC1E,EAAY,EAAW,EAAO,QAAQ,EAAQ,IAAW,EAAS,EAAQ,EAAE,EAC1E,EAAS,EACZ,KAAK,EAAQ,KAAW,CAAE,QAAO,UAAY,EAAW,EAAU,CAAY,EAAE,CAAC,CACjF,MAAM,EAAM,IACX,EAAK,YAAc,EAAM,UAAY,EAAK,MAAQ,EAAM,MAAQ,EAAK,UAAY,EAAM,UAAY,GAAK,CAC1G,EAEF,IAAK,IAAM,KAAS,EAAQ,CAC1B,GAAI,IAAc,GAAI,MAEtB,EAAO,EAAM,QAAW,GACxB,GAAa,EACf,CAEA,OAAO,EAAO,IAAK,GAAW,EAAA,UAAU,EAAS,EAAM,EAAM,QAAQ,CAAC,CACxE,CAEA,SAAS,EAAmC,EAAiB,EAAgC,CAC3F,GAAI,CAAC,OAAO,UAAU,CAAU,GAAK,EAAa,EAChD,MAAM,IAAI,EAAA,WAAW,qBAAsB,6CAA6C,EAG1F,IAAM,EAAQ,OAAO,CAAU,EACzB,EAAO,EAAM,OAAS,GAAK,CAAC,GAAK,GACjC,EAAW,EAAM,OAAS,GAAK,CAAC,EAAM,OAAS,EAAM,OACrD,EAAO,EAAW,EAClB,EAAY,EAAW,EAE7B,OAAO,MAAM,KAAK,CAAE,OAAQ,CAAW,GAAI,EAAG,IAC5C,EAAA,WAAW,GAAQ,OAAO,CAAK,EAAI,EAAY,GAAK,KAAO,EAAM,EAAM,QAAQ,CACjF,CACF"}
1
+ {"version":3,"file":"aggregate.cjs","names":[],"sources":["../src/aggregate.ts"],"sourcesContent":["import { decimal, lcm } from './_decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { assertMoney, createMoney } from './money';\nimport type { Currency, Money } from './types';\n\nexport function sum<C extends Currency>(values: readonly Money<C>[]): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options: { currency: C }): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options?: { currency: C }): Money<C> {\n let amount = 0n;\n let currency: C | undefined = options?.currency;\n\n for (const value of values) {\n assertMoney(value);\n\n if (currency === undefined) {\n currency = value.currency;\n } else if (value.currency !== currency) {\n throw new CurrencyMismatchError(currency.code, value.currency.code);\n }\n\n amount += value.amount;\n }\n\n if (currency === undefined) throw new CoinsError('INVALID_MONEY', 'sum() of empty iterable requires { currency }');\n\n return createMoney(amount, currency);\n}\n\nexport function allocate<C extends Currency>(value: Money<C>, count: number): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weights: readonly string[]): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weightsOrCount: number | readonly string[]): Money<C>[] {\n assertMoney(value);\n\n if (typeof weightsOrCount === 'number') return allocateEvenly(value, weightsOrCount);\n\n if (weightsOrCount.length === 0) throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be empty');\n\n const weights = weightsOrCount.map(decimal);\n\n if (weights.some((weight) => weight.numerator < 0n)) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be negative');\n }\n\n const commonDenominator = weights.reduce((result, weight) => lcm(result, weight.denominator), 1n);\n const scaledWeights = weights.map((weight) => weight.numerator * (commonDenominator / weight.denominator));\n const totalWeight = scaledWeights.reduce((result, weight) => result + weight, 0n);\n\n if (totalWeight === 0n)\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights must include a positive value');\n\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const shares = scaledWeights.map((weight) => (absolute * weight) / totalWeight);\n let remainder = absolute - shares.reduce((result, amount) => result + amount, 0n);\n const ranked = scaledWeights\n .map((weight, index) => ({ index, remainder: (absolute * weight) % totalWeight }))\n .sort((left, right) =>\n left.remainder === right.remainder ? left.index - right.index : left.remainder > right.remainder ? -1 : 1,\n );\n\n for (const entry of ranked) {\n if (remainder === 0n) break;\n\n shares[entry.index]! += 1n;\n remainder -= 1n;\n }\n\n return shares.map((amount) => createMoney(amount * sign, value.currency));\n}\n\nfunction allocateEvenly<C extends Currency>(value: Money<C>, countValue: number): Money<C>[] {\n if (!Number.isInteger(countValue) || countValue < 1) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation count must be a positive integer');\n }\n\n const count = BigInt(countValue);\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const base = absolute / count;\n const remainder = absolute % count;\n\n return Array.from({ length: countValue }, (_, index) =>\n createMoney((base + (BigInt(index) < remainder ? 1n : 0n)) * sign, value.currency),\n );\n}\n"],"mappings":"qFAOA,SAAgB,EAAwB,EAA4B,EAAqC,CACvG,IAAI,EAAS,GACT,EAA0B,GAAS,SAEvC,IAAK,IAAM,KAAS,EAAQ,CAG1B,GAFA,EAAA,YAAY,CAAK,EAEb,IAAa,IAAA,GACf,EAAW,EAAM,cACZ,GAAI,EAAM,WAAa,EAC5B,MAAM,IAAI,EAAA,sBAAsB,EAAS,KAAM,EAAM,SAAS,IAAI,EAGpE,GAAU,EAAM,MAClB,CAEA,GAAI,IAAa,IAAA,GAAW,MAAM,IAAI,EAAA,WAAW,gBAAiB,+CAA+C,EAEjH,OAAO,EAAA,YAAY,EAAQ,CAAQ,CACrC,CAIA,SAAgB,EAA6B,EAAiB,EAAwD,CAGpH,GAFA,EAAA,YAAY,CAAK,EAEb,OAAO,GAAmB,SAAU,OAAO,EAAe,EAAO,CAAc,EAEnF,GAAI,EAAe,SAAW,EAAG,MAAM,IAAI,EAAA,WAAW,qBAAsB,oCAAoC,EAEhH,IAAM,EAAU,EAAe,IAAI,EAAA,OAAO,EAE1C,GAAI,EAAQ,KAAM,GAAW,EAAO,UAAY,EAAE,EAChD,MAAM,IAAI,EAAA,WAAW,qBAAsB,uCAAuC,EAGpF,IAAM,EAAoB,EAAQ,QAAQ,EAAQ,IAAW,EAAA,IAAI,EAAQ,EAAO,WAAW,EAAG,EAAE,EAC1F,EAAgB,EAAQ,IAAK,GAAW,EAAO,WAAa,EAAoB,EAAO,YAAY,EACnG,EAAc,EAAc,QAAQ,EAAQ,IAAW,EAAS,EAAQ,EAAE,EAEhF,GAAI,IAAgB,GAClB,MAAM,IAAI,EAAA,WAAW,qBAAsB,kDAAkD,EAE/F,IAAM,EAAO,EAAM,OAAS,GAAK,CAAC,GAAK,GACjC,EAAW,EAAM,OAAS,GAAK,CAAC,EAAM,OAAS,EAAM,OACrD,EAAS,EAAc,IAAK,GAAY,EAAW,EAAU,CAAW,EAC1E,EAAY,EAAW,EAAO,QAAQ,EAAQ,IAAW,EAAS,EAAQ,EAAE,EAC1E,EAAS,EACZ,KAAK,EAAQ,KAAW,CAAE,QAAO,UAAY,EAAW,EAAU,CAAY,EAAE,CAAC,CACjF,MAAM,EAAM,IACX,EAAK,YAAc,EAAM,UAAY,EAAK,MAAQ,EAAM,MAAQ,EAAK,UAAY,EAAM,UAAY,GAAK,CAC1G,EAEF,IAAK,IAAM,KAAS,EAAQ,CAC1B,GAAI,IAAc,GAAI,MAEtB,EAAO,EAAM,QAAW,GACxB,GAAa,EACf,CAEA,OAAO,EAAO,IAAK,GAAW,EAAA,YAAY,EAAS,EAAM,EAAM,QAAQ,CAAC,CAC1E,CAEA,SAAS,EAAmC,EAAiB,EAAgC,CAC3F,GAAI,CAAC,OAAO,UAAU,CAAU,GAAK,EAAa,EAChD,MAAM,IAAI,EAAA,WAAW,qBAAsB,6CAA6C,EAG1F,IAAM,EAAQ,OAAO,CAAU,EACzB,EAAO,EAAM,OAAS,GAAK,CAAC,GAAK,GACjC,EAAW,EAAM,OAAS,GAAK,CAAC,EAAM,OAAS,EAAM,OACrD,EAAO,EAAW,EAClB,EAAY,EAAW,EAE7B,OAAO,MAAM,KAAK,CAAE,OAAQ,CAAW,GAAI,EAAG,IAC5C,EAAA,aAAa,GAAQ,OAAO,CAAK,EAAI,EAAY,GAAK,KAAO,EAAM,EAAM,QAAQ,CACnF,CACF"}
package/dist/aggregate.js CHANGED
@@ -1,21 +1,19 @@
1
1
  import { CoinsError as e, CurrencyMismatchError as t } from "./errors.js";
2
- import { decimal as n, lcm as r } from "./decimal.js";
3
- import { isMoney as i, withMinor as a } from "./money.js";
2
+ import { decimal as n, lcm as r } from "./_decimal.js";
3
+ import { assertMoney as i, createMoney as a } from "./money.js";
4
4
  //#region src/aggregate.ts
5
5
  function o(n, r) {
6
6
  let o = 0n, s = r?.currency;
7
- for (let r of n) {
8
- if (!i(r)) throw new e("INVALID_MONEY", "sum() requires canonical money values");
9
- if (s === void 0) s = r.currency;
10
- else if (r.currency !== s) throw new t(s.code, r.currency.code);
11
- o += r.amount;
7
+ for (let e of n) {
8
+ if (i(e), s === void 0) s = e.currency;
9
+ else if (e.currency !== s) throw new t(s.code, e.currency.code);
10
+ o += e.amount;
12
11
  }
13
12
  if (s === void 0) throw new e("INVALID_MONEY", "sum() of empty iterable requires { currency }");
14
13
  return a(o, s);
15
14
  }
16
15
  function s(t, o) {
17
- if (!i(t)) throw new e("INVALID_MONEY", "allocate() requires canonical money");
18
- if (typeof o == "number") return c(t, o);
16
+ if (i(t), typeof o == "number") return c(t, o);
19
17
  if (o.length === 0) throw new e("INVALID_ALLOCATION", "Allocation weights cannot be empty");
20
18
  let s = o.map(n);
21
19
  if (s.some((e) => e.numerator < 0n)) throw new e("INVALID_ALLOCATION", "Allocation weights cannot be negative");
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate.js","names":[],"sources":["../src/aggregate.ts"],"sourcesContent":["import { decimal, lcm } from './decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { isMoney, withMinor } from './money';\nimport type { Currency, Money } from './types';\n\nexport function sum<C extends Currency>(values: readonly Money<C>[]): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options: { currency: C }): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options?: { currency: C }): Money<C> {\n let amount = 0n;\n let currency: C | undefined = options?.currency;\n\n for (const value of values) {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'sum() requires canonical money values');\n\n if (currency === undefined) {\n currency = value.currency;\n } else if (value.currency !== currency) {\n throw new CurrencyMismatchError(currency.code, value.currency.code);\n }\n\n amount += value.amount;\n }\n\n if (currency === undefined) throw new CoinsError('INVALID_MONEY', 'sum() of empty iterable requires { currency }');\n\n return withMinor(amount, currency);\n}\n\nexport function allocate<C extends Currency>(value: Money<C>, count: number): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weights: readonly string[]): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weightsOrCount: number | readonly string[]): Money<C>[] {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'allocate() requires canonical money');\n\n if (typeof weightsOrCount === 'number') return allocateEvenly(value, weightsOrCount);\n\n if (weightsOrCount.length === 0) throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be empty');\n\n const weights = weightsOrCount.map(decimal);\n\n if (weights.some((weight) => weight.numerator < 0n)) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be negative');\n }\n\n const commonDenominator = weights.reduce((result, weight) => lcm(result, weight.denominator), 1n);\n const scaledWeights = weights.map((weight) => weight.numerator * (commonDenominator / weight.denominator));\n const totalWeight = scaledWeights.reduce((result, weight) => result + weight, 0n);\n\n if (totalWeight === 0n)\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights must include a positive value');\n\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const shares = scaledWeights.map((weight) => (absolute * weight) / totalWeight);\n let remainder = absolute - shares.reduce((result, amount) => result + amount, 0n);\n const ranked = scaledWeights\n .map((weight, index) => ({ index, remainder: (absolute * weight) % totalWeight }))\n .sort((left, right) =>\n left.remainder === right.remainder ? left.index - right.index : left.remainder > right.remainder ? -1 : 1,\n );\n\n for (const entry of ranked) {\n if (remainder === 0n) break;\n\n shares[entry.index]! += 1n;\n remainder -= 1n;\n }\n\n return shares.map((amount) => withMinor(amount * sign, value.currency));\n}\n\nfunction allocateEvenly<C extends Currency>(value: Money<C>, countValue: number): Money<C>[] {\n if (!Number.isInteger(countValue) || countValue < 1) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation count must be a positive integer');\n }\n\n const count = BigInt(countValue);\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const base = absolute / count;\n const remainder = absolute % count;\n\n return Array.from({ length: countValue }, (_, index) =>\n withMinor((base + (BigInt(index) < remainder ? 1n : 0n)) * sign, value.currency),\n );\n}\n"],"mappings":";;;;AAOA,SAAgB,EAAwB,GAA4B,GAAqC;CACvG,IAAI,IAAS,IACT,IAA0B,GAAS;CAEvC,KAAK,IAAM,KAAS,GAAQ;EAC1B,IAAI,CAAC,EAAQ,CAAK,GAAG,MAAM,IAAI,EAAW,iBAAiB,uCAAuC;EAElG,IAAI,MAAa,KAAA,GACf,IAAW,EAAM;OACZ,IAAI,EAAM,aAAa,GAC5B,MAAM,IAAI,EAAsB,EAAS,MAAM,EAAM,SAAS,IAAI;EAGpE,KAAU,EAAM;CAClB;CAEA,IAAI,MAAa,KAAA,GAAW,MAAM,IAAI,EAAW,iBAAiB,+CAA+C;CAEjH,OAAO,EAAU,GAAQ,CAAQ;AACnC;AAIA,SAAgB,EAA6B,GAAiB,GAAwD;CACpH,IAAI,CAAC,EAAQ,CAAK,GAAG,MAAM,IAAI,EAAW,iBAAiB,qCAAqC;CAEhG,IAAI,OAAO,KAAmB,UAAU,OAAO,EAAe,GAAO,CAAc;CAEnF,IAAI,EAAe,WAAW,GAAG,MAAM,IAAI,EAAW,sBAAsB,oCAAoC;CAEhH,IAAM,IAAU,EAAe,IAAI,CAAO;CAE1C,IAAI,EAAQ,MAAM,MAAW,EAAO,YAAY,EAAE,GAChD,MAAM,IAAI,EAAW,sBAAsB,uCAAuC;CAGpF,IAAM,IAAoB,EAAQ,QAAQ,GAAQ,MAAW,EAAI,GAAQ,EAAO,WAAW,GAAG,EAAE,GAC1F,IAAgB,EAAQ,KAAK,MAAW,EAAO,aAAa,IAAoB,EAAO,YAAY,GACnG,IAAc,EAAc,QAAQ,GAAQ,MAAW,IAAS,GAAQ,EAAE;CAEhF,IAAI,MAAgB,IAClB,MAAM,IAAI,EAAW,sBAAsB,kDAAkD;CAE/F,IAAM,IAAO,EAAM,SAAS,KAAK,CAAC,KAAK,IACjC,IAAW,EAAM,SAAS,KAAK,CAAC,EAAM,SAAS,EAAM,QACrD,IAAS,EAAc,KAAK,MAAY,IAAW,IAAU,CAAW,GAC1E,IAAY,IAAW,EAAO,QAAQ,GAAQ,MAAW,IAAS,GAAQ,EAAE,GAC1E,IAAS,EACZ,KAAK,GAAQ,OAAW;EAAE;EAAO,WAAY,IAAW,IAAU;CAAY,EAAE,CAAC,CACjF,MAAM,GAAM,MACX,EAAK,cAAc,EAAM,YAAY,EAAK,QAAQ,EAAM,QAAQ,EAAK,YAAY,EAAM,YAAY,KAAK,CAC1G;CAEF,KAAK,IAAM,KAAS,GAAQ;EAC1B,IAAI,MAAc,IAAI;EAGtB,AADA,EAAO,EAAM,UAAW,IACxB,KAAa;CACf;CAEA,OAAO,EAAO,KAAK,MAAW,EAAU,IAAS,GAAM,EAAM,QAAQ,CAAC;AACxE;AAEA,SAAS,EAAmC,GAAiB,GAAgC;CAC3F,IAAI,CAAC,OAAO,UAAU,CAAU,KAAK,IAAa,GAChD,MAAM,IAAI,EAAW,sBAAsB,6CAA6C;CAG1F,IAAM,IAAQ,OAAO,CAAU,GACzB,IAAO,EAAM,SAAS,KAAK,CAAC,KAAK,IACjC,IAAW,EAAM,SAAS,KAAK,CAAC,EAAM,SAAS,EAAM,QACrD,IAAO,IAAW,GAClB,IAAY,IAAW;CAE7B,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAW,IAAI,GAAG,MAC5C,GAAW,KAAQ,OAAO,CAAK,IAAI,IAAY,KAAK,OAAO,GAAM,EAAM,QAAQ,CACjF;AACF"}
1
+ {"version":3,"file":"aggregate.js","names":[],"sources":["../src/aggregate.ts"],"sourcesContent":["import { decimal, lcm } from './_decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { assertMoney, createMoney } from './money';\nimport type { Currency, Money } from './types';\n\nexport function sum<C extends Currency>(values: readonly Money<C>[]): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options: { currency: C }): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options?: { currency: C }): Money<C> {\n let amount = 0n;\n let currency: C | undefined = options?.currency;\n\n for (const value of values) {\n assertMoney(value);\n\n if (currency === undefined) {\n currency = value.currency;\n } else if (value.currency !== currency) {\n throw new CurrencyMismatchError(currency.code, value.currency.code);\n }\n\n amount += value.amount;\n }\n\n if (currency === undefined) throw new CoinsError('INVALID_MONEY', 'sum() of empty iterable requires { currency }');\n\n return createMoney(amount, currency);\n}\n\nexport function allocate<C extends Currency>(value: Money<C>, count: number): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weights: readonly string[]): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weightsOrCount: number | readonly string[]): Money<C>[] {\n assertMoney(value);\n\n if (typeof weightsOrCount === 'number') return allocateEvenly(value, weightsOrCount);\n\n if (weightsOrCount.length === 0) throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be empty');\n\n const weights = weightsOrCount.map(decimal);\n\n if (weights.some((weight) => weight.numerator < 0n)) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be negative');\n }\n\n const commonDenominator = weights.reduce((result, weight) => lcm(result, weight.denominator), 1n);\n const scaledWeights = weights.map((weight) => weight.numerator * (commonDenominator / weight.denominator));\n const totalWeight = scaledWeights.reduce((result, weight) => result + weight, 0n);\n\n if (totalWeight === 0n)\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights must include a positive value');\n\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const shares = scaledWeights.map((weight) => (absolute * weight) / totalWeight);\n let remainder = absolute - shares.reduce((result, amount) => result + amount, 0n);\n const ranked = scaledWeights\n .map((weight, index) => ({ index, remainder: (absolute * weight) % totalWeight }))\n .sort((left, right) =>\n left.remainder === right.remainder ? left.index - right.index : left.remainder > right.remainder ? -1 : 1,\n );\n\n for (const entry of ranked) {\n if (remainder === 0n) break;\n\n shares[entry.index]! += 1n;\n remainder -= 1n;\n }\n\n return shares.map((amount) => createMoney(amount * sign, value.currency));\n}\n\nfunction allocateEvenly<C extends Currency>(value: Money<C>, countValue: number): Money<C>[] {\n if (!Number.isInteger(countValue) || countValue < 1) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation count must be a positive integer');\n }\n\n const count = BigInt(countValue);\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const base = absolute / count;\n const remainder = absolute % count;\n\n return Array.from({ length: countValue }, (_, index) =>\n createMoney((base + (BigInt(index) < remainder ? 1n : 0n)) * sign, value.currency),\n );\n}\n"],"mappings":";;;;AAOA,SAAgB,EAAwB,GAA4B,GAAqC;CACvG,IAAI,IAAS,IACT,IAA0B,GAAS;CAEvC,KAAK,IAAM,KAAS,GAAQ;EAG1B,IAFA,EAAY,CAAK,GAEb,MAAa,KAAA,GACf,IAAW,EAAM;OACZ,IAAI,EAAM,aAAa,GAC5B,MAAM,IAAI,EAAsB,EAAS,MAAM,EAAM,SAAS,IAAI;EAGpE,KAAU,EAAM;CAClB;CAEA,IAAI,MAAa,KAAA,GAAW,MAAM,IAAI,EAAW,iBAAiB,+CAA+C;CAEjH,OAAO,EAAY,GAAQ,CAAQ;AACrC;AAIA,SAAgB,EAA6B,GAAiB,GAAwD;CAGpH,IAFA,EAAY,CAAK,GAEb,OAAO,KAAmB,UAAU,OAAO,EAAe,GAAO,CAAc;CAEnF,IAAI,EAAe,WAAW,GAAG,MAAM,IAAI,EAAW,sBAAsB,oCAAoC;CAEhH,IAAM,IAAU,EAAe,IAAI,CAAO;CAE1C,IAAI,EAAQ,MAAM,MAAW,EAAO,YAAY,EAAE,GAChD,MAAM,IAAI,EAAW,sBAAsB,uCAAuC;CAGpF,IAAM,IAAoB,EAAQ,QAAQ,GAAQ,MAAW,EAAI,GAAQ,EAAO,WAAW,GAAG,EAAE,GAC1F,IAAgB,EAAQ,KAAK,MAAW,EAAO,aAAa,IAAoB,EAAO,YAAY,GACnG,IAAc,EAAc,QAAQ,GAAQ,MAAW,IAAS,GAAQ,EAAE;CAEhF,IAAI,MAAgB,IAClB,MAAM,IAAI,EAAW,sBAAsB,kDAAkD;CAE/F,IAAM,IAAO,EAAM,SAAS,KAAK,CAAC,KAAK,IACjC,IAAW,EAAM,SAAS,KAAK,CAAC,EAAM,SAAS,EAAM,QACrD,IAAS,EAAc,KAAK,MAAY,IAAW,IAAU,CAAW,GAC1E,IAAY,IAAW,EAAO,QAAQ,GAAQ,MAAW,IAAS,GAAQ,EAAE,GAC1E,IAAS,EACZ,KAAK,GAAQ,OAAW;EAAE;EAAO,WAAY,IAAW,IAAU;CAAY,EAAE,CAAC,CACjF,MAAM,GAAM,MACX,EAAK,cAAc,EAAM,YAAY,EAAK,QAAQ,EAAM,QAAQ,EAAK,YAAY,EAAM,YAAY,KAAK,CAC1G;CAEF,KAAK,IAAM,KAAS,GAAQ;EAC1B,IAAI,MAAc,IAAI;EAGtB,AADA,EAAO,EAAM,UAAW,IACxB,KAAa;CACf;CAEA,OAAO,EAAO,KAAK,MAAW,EAAY,IAAS,GAAM,EAAM,QAAQ,CAAC;AAC1E;AAEA,SAAS,EAAmC,GAAiB,GAAgC;CAC3F,IAAI,CAAC,OAAO,UAAU,CAAU,KAAK,IAAa,GAChD,MAAM,IAAI,EAAW,sBAAsB,6CAA6C;CAG1F,IAAM,IAAQ,OAAO,CAAU,GACzB,IAAO,EAAM,SAAS,KAAK,CAAC,KAAK,IACjC,IAAW,EAAM,SAAS,KAAK,CAAC,EAAM,SAAS,EAAM,QACrD,IAAO,IAAW,GAClB,IAAY,IAAW;CAE7B,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAW,IAAI,GAAG,MAC5C,GAAa,KAAQ,OAAO,CAAK,IAAI,IAAY,KAAK,OAAO,GAAM,EAAM,QAAQ,CACnF;AACF"}
package/dist/coins.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class extends Error{code;constructor(e,t,n){super(t,n),this.code=e,this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{expected;received;constructor(e,t){super(`CURRENCY_MISMATCH`,`Currency mismatch: ${e} and ${t}`),this.expected=e,this.received=t}},n=class extends e{value;constructor(e){super(`INVALID_CURRENCY`,`Unsupported currency: "${String(e)}"`),this.value=e}},r=/^(-?)(\d+)(?:\.(\d+))?$/,i=1e3,a=100;function o(t){if(t.length>i)throw new e(`INVALID_DECIMAL`,`Decimal input is too long`);let n=r.exec(t);if(!n)throw new e(`INVALID_DECIMAL`,`Invalid decimal: "${t}"`);let o=(n[3]??``).replace(/0+$/,``);if(o.length>a)throw new e(`INVALID_DECIMAL`,`Decimal precision cannot exceed ${a} places`);let s=10n**BigInt(o.length),c=BigInt(n[2])*s+BigInt(o||`0`),u=n[1]===`-`&&c!==0n?-c:c,d=l(u<0n?-u:u,s);return Object.freeze({denominator:s/d,numerator:u/d})}function s(t,n,r){if(n<=0n)throw new e(`INVALID_DECIMAL`,`Decimal denominator must be positive`);let i=t<0n,a=i?-t:t,o=a/n,s=a%n;if(s===0n)return i?-o:o;let c=(()=>{switch(r){case`awayFromZero`:return!0;case`ceil`:return!i;case`floor`:return i;case`halfAwayFromZero`:return s*2n>=n;case`halfEven`:{let e=s*2n;return e>n||e===n&&o%2n!=0n}case`towardZero`:return!1}})()?o+1n:o;return i?-c:c}function c(e,t){let n=e<0n,r=n?-e:e,i=10n**BigInt(t),a=r/i;if(t===0)return`${n?`-`:``}${a}`;let o=(r%i).toString().padStart(t,`0`);return`${n?`-`:``}${a}.${o}`}function l(e,t){let n=e,r=t;for(;r!==0n;)[n,r]=[r,n%r];return n===0n?1n:n}function u(e,t){return e/l(e,t)*t}var d=new Map,f=new Map;function p(e,t){let n=w(e,t);return d.set(e,n),n}var m=p(`USD`,2),h=p(`EUR`,2),g=p(`GBP`,2),_=p(`JPY`,0),v=p(`KRW`,0),y=p(`BHD`,3),ee=p(`KWD`,3);function b({code:e,minorUnit:t}){T(e,t);let n=d.get(e);if(n){if(n.minorUnit!==t)throw E(e,n.minorUnit);return n}let r=f.get(e);if(r){if(r.minorUnit!==t)throw E(e,r.minorUnit);return r}let i=w(e,t);return f.set(e,i),i}function x(e){let t=d.get(e)??f.get(e);if(!t)throw new n(e);return t}function S(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.code==`string`&&(d.get(t.code)===e||f.get(t.code)===e)}function C(e){let t=d.get(e);if(!t)throw new n(e);return t}function w(e,t){return T(e,t),Object.freeze({code:e,minorUnit:t})}function T(t,n){if(!/^[A-Z]{3}$/.test(t))throw new e(`INVALID_CURRENCY`,`Currency code must be three uppercase letters: "${t}"`);if(!Number.isInteger(n)||n<0||n>6)throw new e(`INVALID_CURRENCY`,`Currency "${t}" must have 0–6 minor-unit digits`)}function E(t,n){return new e(`INVALID_CURRENCY`,`Currency "${t}" already has ${n} minor-unit digits`)}var D=`halfAwayFromZero`;function O(t,n,r){if(B(n),typeof t==`bigint`){if(!r||!(`unit`in r)||r.unit!==`minor`)throw new e(`INVALID_MONEY`,`Bigint amounts require { unit: 'minor' }`);return L(t,n)}if(r&&`unit`in r)throw new e(`INVALID_MONEY`,`Decimal strings do not accept a unit option`);let i=o(t),a=i.numerator*10n**BigInt(n.minorUnit);if(a%i.denominator!==0n&&!r)throw new e(`INVALID_MONEY`,`Amount "${t}" exceeds ${n.code} precision; provide rounding`);return L(s(a,i.denominator,r?.rounding??D),n)}function k(t){if(!V(t))throw new e(`INVALID_MONEY`,`Money must be a plain data object`);let n=Object.getOwnPropertyDescriptors(t),r=n.amount,i=n.currency;if(!H(r)||!H(i))throw new e(`INVALID_MONEY`,`Money properties must be plain data values`);if(typeof r.value!=`bigint`||!S(i.value))throw new e(`INVALID_MONEY`,`Money must contain bigint amount and a registered currency`);return L(r.value,i.value)}function A(e){try{return k(e),!0}catch{return!1}}function j(e,t){return z(e,t),L(e.amount+t.amount,e.currency)}function te(e,t){return z(e,t),L(e.amount-t.amount,e.currency)}function ne(e,t,n={}){R(e);let r=o(t);return L(s(e.amount*r.numerator,r.denominator,n.rounding??D),e.currency)}function re(t,n,r={}){R(t);let i=o(n);if(i.numerator===0n)throw new e(`DIVISION_BY_ZERO`,`Cannot divide money by zero`);let a=i.numerator<0n,c=a?-i.numerator:i.numerator,l=s(t.amount*i.denominator,c,r.rounding??D);return L(a?-l:l,t.currency)}function M(e,t){return z(e,t),e.amount===t.amount?0:e.amount<t.amount?-1:1}function ie(t,n){if(M(n.min,n.max)===1)throw new e(`INVALID_MONEY`,`Clamp minimum cannot exceed maximum`);return M(t,n.min)===-1?n.min:M(t,n.max)===1?n.max:t}function ae(e){return R(e),L(e.amount<0n?-e.amount:e.amount,e.currency)}function N(e){return R(e),L(-e.amount,e.currency)}function P(t,n){R(t);let{fractionDigits:r,rounding:i=D}=n;if(!Number.isInteger(r)||r<0||r>t.currency.minorUnit)throw new e(`INVALID_ROUNDING`,`fractionDigits must be an integer from 0 to ${t.currency.minorUnit}`);let a=10n**BigInt(t.currency.minorUnit-r);return L(s(t.amount,a,i)*a,t.currency)}function F(e){return R(e),c(e.amount,e.currency.minorUnit)}function I(e,t){return B(t),L(e,t)}function L(e,t){return Object.freeze({amount:e,currency:t})}function R(t){if(!Object.isFrozen(t)||!S(t.currency))throw new e(`INVALID_MONEY`,`Money must be a canonical Coins value`)}function z(e,n){if(R(e),R(n),e.currency!==n.currency)throw new t(e.currency.code,n.currency.code)}function B(t){if(!S(t))throw new e(`INVALID_CURRENCY`,`Money requires a registered currency`)}function V(e){if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function H(e){return e!==void 0&&`value`in e&&e.get===void 0&&e.set===void 0}function U(n,r){let i=0n,a=r?.currency;for(let r of n){if(!A(r))throw new e(`INVALID_MONEY`,`sum() requires canonical money values`);if(a===void 0)a=r.currency;else if(r.currency!==a)throw new t(a.code,r.currency.code);i+=r.amount}if(a===void 0)throw new e(`INVALID_MONEY`,`sum() of empty iterable requires { currency }`);return I(i,a)}function W(t,n){if(!A(t))throw new e(`INVALID_MONEY`,`allocate() requires canonical money`);if(typeof n==`number`)return G(t,n);if(n.length===0)throw new e(`INVALID_ALLOCATION`,`Allocation weights cannot be empty`);let r=n.map(o);if(r.some(e=>e.numerator<0n))throw new e(`INVALID_ALLOCATION`,`Allocation weights cannot be negative`);let i=r.reduce((e,t)=>u(e,t.denominator),1n),a=r.map(e=>e.numerator*(i/e.denominator)),s=a.reduce((e,t)=>e+t,0n);if(s===0n)throw new e(`INVALID_ALLOCATION`,`Allocation weights must include a positive value`);let c=t.amount<0n?-1n:1n,l=t.amount<0n?-t.amount:t.amount,d=a.map(e=>l*e/s),f=l-d.reduce((e,t)=>e+t,0n),p=a.map((e,t)=>({index:t,remainder:l*e%s})).sort((e,t)=>e.remainder===t.remainder?e.index-t.index:e.remainder>t.remainder?-1:1);for(let e of p){if(f===0n)break;d[e.index]+=1n,f-=1n}return d.map(e=>I(e*c,t.currency))}function G(t,n){if(!Number.isInteger(n)||n<1)throw new e(`INVALID_ALLOCATION`,`Allocation count must be a positive integer`);let r=BigInt(n),i=t.amount<0n?-1n:1n,a=t.amount<0n?-t.amount:t.amount,o=a/r,s=a%r;return Array.from({length:n},(e,n)=>I((o+(BigInt(n)<s?1n:0n))*i,t.currency))}function K({from:t,to:n,value:r}){if(!S(t)||!S(n))throw new e(`INVALID_CURRENCY`,`Exchange rate requires registered currencies`);let i=o(r);if(i.numerator<0n)throw new e(`INVALID_DECIMAL`,`Exchange rates cannot be negative`);return Object.freeze({from:t,to:n,value:i})}function q(n,r,i={}){if(!A(n)||!oe(r))throw new e(`INVALID_MONEY`,`Exchange requires canonical money and rate values`);if(n.currency!==r.from)throw new t(n.currency.code,r.from.code);return I(s(n.amount*r.value.numerator*10n**BigInt(r.to.minorUnit),r.value.denominator*10n**BigInt(r.from.minorUnit),i.rounding??`halfAwayFromZero`),r.to)}function oe(e){if(typeof e!=`object`||!e||!Object.isFrozen(e))return!1;let t=e;return S(t.from)&&S(t.to)&&typeof t.value==`object`&&t.value!==null&&Object.isFrozen(t.value)&&typeof t.value.numerator==`bigint`&&t.value.numerator>=0n&&typeof t.value.denominator==`bigint`&&t.value.denominator>0n}var J=20,se=`halfAwayFromZero`,Y=new Map,X=new Map;function ce(e,t={}){return Z(e,t).map(e=>e.value).join(``)}function Z(t,n={}){if(!A(t))throw new e(`INVALID_MONEY`,`format() requires canonical money`);let{locale:r=`en-US`,maximumFractionDigits:i=t.currency.minorUnit,minimumFractionDigits:a=t.currency.minorUnit,rounding:o=se,style:c=`symbol`}=n;le(a,i);let l=10n**BigInt(i),u=i>=t.currency.minorUnit?t.amount*10n**BigInt(i-t.currency.minorUnit):s(t.amount,10n**BigInt(t.currency.minorUnit-i),o),d=u<0n,f=d?-u:u,p=f/l,m=(i===0?``:(f%l).toString().padStart(i,`0`)).replace(RegExp(`0{0,${Math.max(0,i-a)}}$`),``),h=ue(r,t.currency.code,c,d),g=[],_=!1;for(let e of h)e.type!==`group`&&(e.type===`integer`?_||=(g.push({type:`integer`,value:Q(r).format(p)}),!0):e.type===`decimal`?m&&g.push({type:`decimal`,value:e.value}):e.type===`fraction`?m&&g.push({type:`fraction`,value:m}):e.type===`currency`||e.type===`minusSign`||e.type===`plusSign`?g.push({type:e.type,value:e.value}):g.push({type:`literal`,value:e.value}));return g}function le(t,n){if(!Number.isInteger(n)||!Number.isInteger(t)||t<0||n<t||n>J)throw new e(`FORMAT_ERROR`,`Fraction digits must be integers satisfying 0 ≤ minimum ≤ maximum ≤ ${J}`)}function ue(t,n,r,i){let a=`${t}\0${n}\0${r}\0${i}`,o=X.get(a);if(o)return o;try{let e=new Intl.NumberFormat(t,{currency:n,currencyDisplay:r,maximumFractionDigits:1,minimumFractionDigits:1,style:`currency`}).formatToParts(i?-1.1:1.1);return X.set(a,e),e}catch(r){throw new e(`FORMAT_ERROR`,`Cannot format currency "${n}" for locale "${t}"`,{cause:r})}}function Q(t){let n=Y.get(t);if(n)return n;try{let e=new Intl.NumberFormat(t,{maximumFractionDigits:0,useGrouping:!0});return Y.set(t,e),e}catch(n){throw new e(`FORMAT_ERROR`,`Cannot create number formatter for locale "${t}"`,{cause:n})}}var de=/^(?:0|-[1-9]\d*|[1-9]\d*)$/,$=[`amount`,`currency`,`unit`];function fe(e){return{amount:e.amount.toString(),currency:e.currency.code,unit:`minor`}}function pe(t,n={}){try{let e=me(t),r=n.currency??C;return O(BigInt(e.amount),r(e.currency),{unit:`minor`})}catch(t){throw new e(`INVALID_MONEY`,`Invalid Money JSON`,{cause:t})}}function me(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!==$.length||!$.every(e=>n.includes(e)))throw TypeError(`Money JSON must contain only amount, currency, and unit`);for(let e of $){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 r=t.amount?.value,i=t.currency?.value,a=t.unit?.value;if(typeof r!=`string`||!de.test(r))throw TypeError(`Money JSON amount must be a canonical integer string`);if(typeof i!=`string`||a!==`minor`)throw TypeError(`Money JSON currency/unit are invalid`);return{amount:r,currency:i,unit:a}}exports.BHD=y,exports.CoinsError=e,exports.CurrencyMismatchError=t,exports.EUR=h,exports.GBP=g,exports.InvalidCurrencyError=n,exports.JPY=_,exports.KRW=v,exports.KWD=ee,exports.USD=m,exports.abs=ae,exports.add=j,exports.allocate=W,exports.clamp=ie,exports.compare=M,exports.currency=x,exports.defineCurrency=b,exports.divide=re,exports.exchange=q,exports.exchangeRate=K,exports.format=ce,exports.formatParts=Z,exports.isCurrency=S,exports.isMoney=A,exports.money=O,exports.multiply=ne,exports.negate=N,exports.parseMoney=k,exports.parseMoneyJSON=pe,exports.round=P,exports.subtract=te,exports.sum=U,exports.toDecimal=F,exports.toJSON=fe;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class extends Error{code;constructor(e,t,n){super(t,n),this.code=e,this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{expected;received;constructor(e,t){super(`CURRENCY_MISMATCH`,`Currency mismatch: ${e} and ${t}`),this.expected=e,this.received=t}},n=class extends e{value;constructor(e){super(`INVALID_CURRENCY`,`Unsupported currency: "${String(e)}"`),this.value=e}},r=/^(-?)(\d+)(?:\.(\d+))?$/,i=1e3,a=100;function o(t){if(t.length>i)throw new e(`INVALID_DECIMAL`,`Decimal input is too long`);let n=r.exec(t);if(!n)throw new e(`INVALID_DECIMAL`,`Invalid decimal: "${t}"`);let o=(n[3]??``).replace(/0+$/,``);if(o.length>a)throw new e(`INVALID_DECIMAL`,`Decimal precision cannot exceed ${a} places`);let s=10n**BigInt(o.length),c=BigInt(n[2])*s+BigInt(o||`0`),u=n[1]===`-`&&c!==0n?-c:c,d=l(u<0n?-u:u,s);return Object.freeze({denominator:s/d,numerator:u/d})}function s(t,n,r){if(n<=0n)throw new e(`INVALID_DECIMAL`,`Decimal denominator must be positive`);let i=t<0n,a=i?-t:t,o=a/n,s=a%n;if(s===0n)return i?-o:o;let c=(()=>{switch(r){case`awayFromZero`:return!0;case`ceil`:return!i;case`floor`:return i;case`halfAwayFromZero`:return s*2n>=n;case`halfEven`:{let e=s*2n;return e>n||e===n&&o%2n!=0n}case`towardZero`:return!1;default:throw new e(`INVALID_ROUNDING`,`Unknown rounding mode: ${r}`)}})()?o+1n:o;return i?-c:c}function c(e,t){let n=e<0n,r=n?-e:e,i=10n**BigInt(t),a=r/i;if(t===0)return`${n?`-`:``}${a}`;let o=(r%i).toString().padStart(t,`0`);return`${n?`-`:``}${a}.${o}`}function l(e,t){let n=e,r=t;for(;r!==0n;)[n,r]=[r,n%r];return n===0n?1n:n}function u(e,t){return e/l(e,t)*t}var d=new Map,f=new WeakSet;function p(e,t){C(e,t);let n=Object.freeze({code:e,minorUnit:t});return f.add(n),n}function m(e,t){let n=p(e,t);return d.set(e,n),n}var h=m(`USD`,2),g=m(`EUR`,2),_=m(`GBP`,2),ee=m(`JPY`,0),v=m(`KRW`,0),y=m(`BHD`,3),b=m(`KWD`,3);function x(e){if(typeof e==`string`){let t=d.get(e);if(!t)throw new n(e);return t}return p(e.code,e.minorUnit)}function S(e){return typeof e==`object`&&!!e&&f.has(e)}function C(t,n){if(!/^[A-Z]{3}$/.test(t))throw new e(`INVALID_CURRENCY`,`Currency code must be three uppercase letters: "${t}"`);if(!Number.isInteger(n)||n<0||n>6)throw new e(`INVALID_CURRENCY`,`Currency "${t}" must have 0–6 minor-unit digits`)}var w=new WeakSet,T=`halfAwayFromZero`;function E(t,n,r){if(z(n),typeof t==`bigint`){if(!r||!(`unit`in r)||r.unit!==`minor`)throw new e(`INVALID_MONEY`,`Bigint amounts require { unit: 'minor' }`);return I(t,n)}if(r&&`unit`in r)throw new e(`INVALID_MONEY`,`Decimal strings do not accept a unit option`);let i=o(t),a=i.numerator*10n**BigInt(n.minorUnit);if(a%i.denominator!==0n&&r?.rounding===void 0)throw new e(`INVALID_MONEY`,`Amount "${t}" exceeds ${n.code} precision; provide rounding`);return I(s(a,i.denominator,r?.rounding??T),n)}function D(t){if(!B(t))throw new e(`INVALID_MONEY`,`Money must be a plain data object`);let n=Object.getOwnPropertyDescriptors(t),r=n.amount,i=n.currency;if(!V(r)||!V(i))throw new e(`INVALID_MONEY`,`Money properties must be plain data values`);if(typeof r.value!=`bigint`||!S(i.value))throw new e(`INVALID_MONEY`,`Money must contain bigint amount and a registered currency`);return I(r.value,i.value)}function O(e){return typeof e==`object`&&!!e&&w.has(e)}function k(e,t){return R(e,t),I(e.amount+t.amount,e.currency)}function A(e,t){return R(e,t),I(e.amount-t.amount,e.currency)}function te(e,t,n={}){L(e);let r=o(t);return I(s(e.amount*r.numerator,r.denominator,n.rounding??T),e.currency)}function ne(t,n,r={}){L(t);let i=o(n);if(i.numerator===0n)throw new e(`DIVISION_BY_ZERO`,`Cannot divide money by zero`);let a=i.numerator<0n?-i.numerator:i.numerator,c=t.amount*i.denominator;return I(s(i.numerator<0n?-c:c,a,r.rounding??T),t.currency)}function j(e,t){return R(e,t),e.amount===t.amount?0:e.amount<t.amount?-1:1}function re(t,n){if(j(n.min,n.max)===1)throw new e(`INVALID_RANGE`,`Clamp minimum cannot exceed maximum`);return j(t,n.min)===-1?n.min:j(t,n.max)===1?n.max:t}function M(e){return L(e),I(e.amount<0n?-e.amount:e.amount,e.currency)}function N(e){return L(e),I(-e.amount,e.currency)}function P(t,n){L(t);let{fractionDigits:r,rounding:i=T}=n;if(!Number.isInteger(r)||r<0||r>t.currency.minorUnit)throw new e(`INVALID_ROUNDING`,`fractionDigits must be an integer from 0 to ${t.currency.minorUnit}`);let a=10n**BigInt(t.currency.minorUnit-r);return I(s(t.amount,a,i)*a,t.currency)}function F(e){return L(e),c(e.amount,e.currency.minorUnit)}function I(e,t){let n=Object.freeze({amount:e,currency:t});return w.add(n),n}function L(t){if(!O(t))throw new e(`INVALID_MONEY`,`Money must be a canonical @vielzeug/coins value`)}function R(e,n){if(L(e),L(n),e.currency!==n.currency)throw new t(e.currency.code,n.currency.code)}function z(t){if(!S(t))throw new e(`INVALID_CURRENCY`,`Money requires a registered currency`)}function B(e){if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function V(e){return e!==void 0&&`value`in e&&e.get===void 0&&e.set===void 0}function H(n,r){let i=0n,a=r?.currency;for(let e of n){if(L(e),a===void 0)a=e.currency;else if(e.currency!==a)throw new t(a.code,e.currency.code);i+=e.amount}if(a===void 0)throw new e(`INVALID_MONEY`,`sum() of empty iterable requires { currency }`);return I(i,a)}function U(t,n){if(L(t),typeof n==`number`)return W(t,n);if(n.length===0)throw new e(`INVALID_ALLOCATION`,`Allocation weights cannot be empty`);let r=n.map(o);if(r.some(e=>e.numerator<0n))throw new e(`INVALID_ALLOCATION`,`Allocation weights cannot be negative`);let i=r.reduce((e,t)=>u(e,t.denominator),1n),a=r.map(e=>e.numerator*(i/e.denominator)),s=a.reduce((e,t)=>e+t,0n);if(s===0n)throw new e(`INVALID_ALLOCATION`,`Allocation weights must include a positive value`);let c=t.amount<0n?-1n:1n,l=t.amount<0n?-t.amount:t.amount,d=a.map(e=>l*e/s),f=l-d.reduce((e,t)=>e+t,0n),p=a.map((e,t)=>({index:t,remainder:l*e%s})).sort((e,t)=>e.remainder===t.remainder?e.index-t.index:e.remainder>t.remainder?-1:1);for(let e of p){if(f===0n)break;d[e.index]+=1n,f-=1n}return d.map(e=>I(e*c,t.currency))}function W(t,n){if(!Number.isInteger(n)||n<1)throw new e(`INVALID_ALLOCATION`,`Allocation count must be a positive integer`);let r=BigInt(n),i=t.amount<0n?-1n:1n,a=t.amount<0n?-t.amount:t.amount,o=a/r,s=a%r;return Array.from({length:n},(e,n)=>I((o+(BigInt(n)<s?1n:0n))*i,t.currency))}var G=new WeakSet;function K({from:t,to:n,value:r}){if(!S(t)||!S(n))throw new e(`INVALID_CURRENCY`,`Exchange rate requires registered currencies`);let i=o(r);if(i.numerator<0n)throw new e(`INVALID_DECIMAL`,`Exchange rates cannot be negative`);let a=Object.freeze({from:t,to:n,value:i});return G.add(a),a}function q(e){return typeof e==`object`&&!!e&&G.has(e)}function J(n,r,i={}){if(L(n),!q(r))throw new e(`INVALID_EXCHANGE_RATE`,`Exchange requires a canonical exchange rate`);if(n.currency!==r.from)throw new t(n.currency.code,r.from.code);return I(s(n.amount*r.value.numerator*10n**BigInt(r.to.minorUnit),r.value.denominator*10n**BigInt(r.from.minorUnit),i.rounding??`halfAwayFromZero`),r.to)}var Y=20,ie=`halfAwayFromZero`,X=new Map,Z=new Map;function ae(e,t={}){return Q(e,t).map(e=>e.value).join(``)}function Q(e,t={}){L(e);let{locale:n=`en-US`,maximumFractionDigits:r=e.currency.minorUnit,minimumFractionDigits:i=e.currency.minorUnit,rounding:a=ie,style:o=`symbol`}=t;oe(i,r);let c=10n**BigInt(r),l=r>=e.currency.minorUnit?e.amount*10n**BigInt(r-e.currency.minorUnit):s(e.amount,10n**BigInt(e.currency.minorUnit-r),a),u=l<0n,d=u?-l:l,f=d/c,p=(r===0?``:(d%c).toString().padStart(r,`0`)).replace(RegExp(`0{0,${Math.max(0,r-i)}}$`),``),m=se(n,e.currency.code,o,u),h=[],g=!1;for(let e of m)e.type!==`group`&&(e.type===`integer`?g||=(h.push({type:`integer`,value:ce(n).format(f)}),!0):e.type===`decimal`?p&&h.push({type:`decimal`,value:e.value}):e.type===`fraction`?p&&h.push({type:`fraction`,value:p}):e.type===`currency`||e.type===`minusSign`||e.type===`plusSign`?h.push({type:e.type,value:e.value}):h.push({type:`literal`,value:e.value}));return h}function oe(t,n){if(!Number.isInteger(n)||!Number.isInteger(t)||t<0||n<t||n>Y)throw new e(`FORMAT_ERROR`,`Fraction digits must be integers satisfying 0 ≤ minimum ≤ maximum ≤ ${Y}`)}function se(t,n,r,i){let a=`${t}\0${n}\0${r}\0${i}`,o=Z.get(a);if(o)return o;try{let e=new Intl.NumberFormat(t,{currency:n,currencyDisplay:r,maximumFractionDigits:1,minimumFractionDigits:1,style:`currency`}).formatToParts(i?-1.1:1.1);return Z.set(a,e),e}catch(r){throw new e(`FORMAT_ERROR`,`Cannot format currency "${n}" for locale "${t}"`,{cause:r})}}function ce(t){let n=X.get(t);if(n)return n;try{let e=new Intl.NumberFormat(t,{maximumFractionDigits:0,useGrouping:!0});return X.set(t,e),e}catch(n){throw new e(`FORMAT_ERROR`,`Cannot create number formatter for locale "${t}"`,{cause:n})}}var le=/^(?:0|-[1-9]\d*|[1-9]\d*)$/,$=[`amount`,`currency`,`unit`];function ue(e){return L(e),{amount:e.amount.toString(),currency:e.currency.code,unit:`minor`}}function de(t,n={}){try{let e=fe(t),r=n.currency??x;return E(BigInt(e.amount),r(e.currency),{unit:`minor`})}catch(t){throw new e(`INVALID_MONEY`,`Invalid Money JSON`,{cause:t})}}function fe(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!==$.length||!$.every(e=>n.includes(e)))throw TypeError(`Money JSON must contain only amount, currency, and unit`);for(let e of $){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 r=t.amount?.value,i=t.currency?.value,a=t.unit?.value;if(typeof r!=`string`||!le.test(r))throw TypeError(`Money JSON amount must be a canonical integer string`);if(typeof i!=`string`||a!==`minor`)throw TypeError(`Money JSON currency/unit are invalid`);return{amount:r,currency:i,unit:a}}exports.BHD=y,exports.CoinsError=e,exports.CurrencyMismatchError=t,exports.EUR=g,exports.GBP=_,exports.InvalidCurrencyError=n,exports.JPY=ee,exports.KRW=v,exports.KWD=b,exports.USD=h,exports.abs=M,exports.add=k,exports.allocate=U,exports.clamp=re,exports.compare=j,exports.currency=x,exports.divide=ne,exports.exchange=J,exports.exchangeRate=K,exports.format=ae,exports.formatParts=Q,exports.isCurrency=S,exports.isExchangeRate=q,exports.isMoney=O,exports.money=E,exports.multiply=te,exports.negate=N,exports.parseMoney=D,exports.parseMoneyJSON=de,exports.round=P,exports.subtract=A,exports.sum=H,exports.toDecimal=F,exports.toJSON=ue;
2
2
  //# sourceMappingURL=coins.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"coins.cjs","names":[],"sources":["../src/errors.ts","../src/decimal.ts","../src/currency.ts","../src/money.ts","../src/aggregate.ts","../src/exchange.ts","../src/format.ts","../src/serialization.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","import { CoinsError } from './errors';\nimport type { Decimal, RoundingMode } from './types';\n\nconst DECIMAL = /^(-?)(\\d+)(?:\\.(\\d+))?$/;\nconst MAX_DECIMAL_DIGITS = 1000;\nconst MAX_DECIMAL_PLACES = 100;\n\nexport function decimal(value: string): Decimal {\n if (value.length > MAX_DECIMAL_DIGITS) throw new CoinsError('INVALID_DECIMAL', 'Decimal input is too long');\n\n const match = DECIMAL.exec(value);\n\n if (!match) throw new CoinsError('INVALID_DECIMAL', `Invalid decimal: \"${value}\"`);\n\n const fraction = (match[3] ?? '').replace(/0+$/, '');\n\n if (fraction.length > MAX_DECIMAL_PLACES) {\n throw new CoinsError('INVALID_DECIMAL', `Decimal precision cannot exceed ${MAX_DECIMAL_PLACES} places`);\n }\n\n const denominator = 10n ** BigInt(fraction.length);\n const unsigned = BigInt(match[2]!) * denominator + BigInt(fraction || '0');\n const numerator = match[1] === '-' && unsigned !== 0n ? -unsigned : unsigned;\n const divisor = gcd(numerator < 0n ? -numerator : numerator, denominator);\n\n return Object.freeze({ denominator: denominator / divisor, numerator: numerator / divisor }) as Decimal;\n}\n\nexport function roundDivision(numerator: bigint, denominator: bigint, mode: RoundingMode): bigint {\n if (denominator <= 0n) throw new CoinsError('INVALID_DECIMAL', 'Decimal denominator must be positive');\n\n const negative = numerator < 0n;\n const absolute = negative ? -numerator : numerator;\n const quotient = absolute / denominator;\n const remainder = absolute % denominator;\n\n if (remainder === 0n) return negative ? -quotient : quotient;\n\n const increment = (() => {\n switch (mode) {\n case 'awayFromZero':\n return true;\n case 'ceil':\n return !negative;\n case 'floor':\n return negative;\n case 'halfAwayFromZero':\n return remainder * 2n >= denominator;\n case 'halfEven': {\n const doubled = remainder * 2n;\n\n return doubled > denominator || (doubled === denominator && quotient % 2n !== 0n);\n }\n case 'towardZero':\n return false;\n }\n })();\n\n const result = increment ? quotient + 1n : quotient;\n\n return negative ? -result : result;\n}\n\nexport function toDecimalString(amount: bigint, minorUnit: number): string {\n const negative = amount < 0n;\n const absolute = negative ? -amount : amount;\n const scale = 10n ** BigInt(minorUnit);\n const whole = absolute / scale;\n\n if (minorUnit === 0) return `${negative ? '-' : ''}${whole}`;\n\n const fraction = (absolute % scale).toString().padStart(minorUnit, '0');\n\n return `${negative ? '-' : ''}${whole}.${fraction}`;\n}\n\nexport function gcd(left: bigint, right: bigint): bigint {\n let a = left;\n let b = right;\n\n while (b !== 0n) [a, b] = [b, a % b];\n\n return a === 0n ? 1n : a;\n}\n\nexport function lcm(left: bigint, right: bigint): bigint {\n return (left / gcd(left, right)) * right;\n}\n","import { CoinsError, InvalidCurrencyError } from './errors';\nimport type { Currency, CurrencyCode } from './types';\n\nconst builtins = new Map<string, Currency>();\nconst custom = new Map<string, Currency>();\n\nfunction builtin<C extends string>(code: C, minorUnit: number): Currency<C> {\n const definition = createDefinition(code, minorUnit);\n\n builtins.set(code, definition);\n\n return definition;\n}\n\nexport const USD = builtin('USD', 2);\nexport const EUR = builtin('EUR', 2);\nexport const GBP = builtin('GBP', 2);\nexport const JPY = builtin('JPY', 0);\nexport const KRW = builtin('KRW', 0);\nexport const BHD = builtin('BHD', 3);\nexport const KWD = builtin('KWD', 3);\n\n/** Custom definitions are explicit process configuration; built-ins remain immutable and separate. */\nexport function defineCurrency<C extends string>({ code, minorUnit }: { code: C; minorUnit: number }): Currency<C> {\n validateDefinition(code, minorUnit);\n\n const builtinDefinition = builtins.get(code);\n\n if (builtinDefinition) {\n if (builtinDefinition.minorUnit !== minorUnit) throw duplicateScaleError(code, builtinDefinition.minorUnit);\n\n return builtinDefinition as Currency<C>;\n }\n\n const existing = custom.get(code);\n\n if (existing) {\n if (existing.minorUnit !== minorUnit) throw duplicateScaleError(code, existing.minorUnit);\n\n return existing as Currency<C>;\n }\n\n const definition = createDefinition(code, minorUnit);\n\n custom.set(code, definition);\n\n return definition;\n}\n\nexport function currency(code: string): Currency {\n const definition = builtins.get(code) ?? custom.get(code);\n\n if (!definition) throw new InvalidCurrencyError(code);\n\n return definition;\n}\n\nexport function isCurrency(value: unknown): value is Currency {\n if (typeof value !== 'object' || value === null) return false;\n\n const candidate = value as Partial<Currency>;\n\n return (\n typeof candidate.code === 'string' &&\n (builtins.get(candidate.code) === value || custom.get(candidate.code) === value)\n );\n}\n\nexport function resolveBuiltinCurrency(code: string): Currency {\n const definition = builtins.get(code);\n\n if (!definition) throw new InvalidCurrencyError(code);\n\n return definition;\n}\n\nfunction createDefinition<C extends string>(code: C, minorUnit: number): Currency<C> {\n validateDefinition(code, minorUnit);\n\n return Object.freeze({ code: code as CurrencyCode<C>, minorUnit }) as Currency<C>;\n}\n\nfunction validateDefinition(code: string, minorUnit: number): void {\n if (!/^[A-Z]{3}$/.test(code)) {\n throw new CoinsError('INVALID_CURRENCY', `Currency code must be three uppercase letters: \"${code}\"`);\n }\n\n if (!Number.isInteger(minorUnit) || minorUnit < 0 || minorUnit > 6) {\n throw new CoinsError('INVALID_CURRENCY', `Currency \"${code}\" must have 0–6 minor-unit digits`);\n }\n}\n\nfunction duplicateScaleError(code: string, minorUnit: number): CoinsError {\n return new CoinsError('INVALID_CURRENCY', `Currency \"${code}\" already has ${minorUnit} minor-unit digits`);\n}\n","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","import { decimal, lcm } from './decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { isMoney, withMinor } from './money';\nimport type { Currency, Money } from './types';\n\nexport function sum<C extends Currency>(values: readonly Money<C>[]): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options: { currency: C }): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options?: { currency: C }): Money<C> {\n let amount = 0n;\n let currency: C | undefined = options?.currency;\n\n for (const value of values) {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'sum() requires canonical money values');\n\n if (currency === undefined) {\n currency = value.currency;\n } else if (value.currency !== currency) {\n throw new CurrencyMismatchError(currency.code, value.currency.code);\n }\n\n amount += value.amount;\n }\n\n if (currency === undefined) throw new CoinsError('INVALID_MONEY', 'sum() of empty iterable requires { currency }');\n\n return withMinor(amount, currency);\n}\n\nexport function allocate<C extends Currency>(value: Money<C>, count: number): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weights: readonly string[]): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weightsOrCount: number | readonly string[]): Money<C>[] {\n if (!isMoney(value)) throw new CoinsError('INVALID_MONEY', 'allocate() requires canonical money');\n\n if (typeof weightsOrCount === 'number') return allocateEvenly(value, weightsOrCount);\n\n if (weightsOrCount.length === 0) throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be empty');\n\n const weights = weightsOrCount.map(decimal);\n\n if (weights.some((weight) => weight.numerator < 0n)) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be negative');\n }\n\n const commonDenominator = weights.reduce((result, weight) => lcm(result, weight.denominator), 1n);\n const scaledWeights = weights.map((weight) => weight.numerator * (commonDenominator / weight.denominator));\n const totalWeight = scaledWeights.reduce((result, weight) => result + weight, 0n);\n\n if (totalWeight === 0n)\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights must include a positive value');\n\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const shares = scaledWeights.map((weight) => (absolute * weight) / totalWeight);\n let remainder = absolute - shares.reduce((result, amount) => result + amount, 0n);\n const ranked = scaledWeights\n .map((weight, index) => ({ index, remainder: (absolute * weight) % totalWeight }))\n .sort((left, right) =>\n left.remainder === right.remainder ? left.index - right.index : left.remainder > right.remainder ? -1 : 1,\n );\n\n for (const entry of ranked) {\n if (remainder === 0n) break;\n\n shares[entry.index]! += 1n;\n remainder -= 1n;\n }\n\n return shares.map((amount) => withMinor(amount * sign, value.currency));\n}\n\nfunction allocateEvenly<C extends Currency>(value: Money<C>, countValue: number): Money<C>[] {\n if (!Number.isInteger(countValue) || countValue < 1) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation count must be a positive integer');\n }\n\n const count = BigInt(countValue);\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const base = absolute / count;\n const remainder = absolute % count;\n\n return Array.from({ length: countValue }, (_, index) =>\n withMinor((base + (BigInt(index) < remainder ? 1n : 0n)) * sign, value.currency),\n );\n}\n","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","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","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":"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"}
1
+ {"version":3,"file":"coins.cjs","names":[],"sources":["../src/errors.ts","../src/_decimal.ts","../src/currency.ts","../src/money.ts","../src/aggregate.ts","../src/exchange.ts","../src/format.ts","../src/serialization.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_EXCHANGE_RATE'\n | 'INVALID_MONEY'\n | 'INVALID_RANGE'\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","import { CoinsError } from './errors';\nimport type { Decimal, RoundingMode } from './types';\n\nconst DECIMAL = /^(-?)(\\d+)(?:\\.(\\d+))?$/;\nconst MAX_DECIMAL_DIGITS = 1000;\nconst MAX_DECIMAL_PLACES = 100;\n\nexport function decimal(value: string): Decimal {\n if (value.length > MAX_DECIMAL_DIGITS) throw new CoinsError('INVALID_DECIMAL', 'Decimal input is too long');\n\n const match = DECIMAL.exec(value);\n\n if (!match) throw new CoinsError('INVALID_DECIMAL', `Invalid decimal: \"${value}\"`);\n\n const fraction = (match[3] ?? '').replace(/0+$/, '');\n\n if (fraction.length > MAX_DECIMAL_PLACES) {\n throw new CoinsError('INVALID_DECIMAL', `Decimal precision cannot exceed ${MAX_DECIMAL_PLACES} places`);\n }\n\n const denominator = 10n ** BigInt(fraction.length);\n const unsigned = BigInt(match[2]!) * denominator + BigInt(fraction || '0');\n const numerator = match[1] === '-' && unsigned !== 0n ? -unsigned : unsigned;\n const divisor = gcd(numerator < 0n ? -numerator : numerator, denominator);\n\n return Object.freeze({ denominator: denominator / divisor, numerator: numerator / divisor }) as Decimal;\n}\n\nexport function roundDivision(numerator: bigint, denominator: bigint, mode: RoundingMode): bigint {\n if (denominator <= 0n) throw new CoinsError('INVALID_DECIMAL', 'Decimal denominator must be positive');\n\n const negative = numerator < 0n;\n const absolute = negative ? -numerator : numerator;\n const quotient = absolute / denominator;\n const remainder = absolute % denominator;\n\n if (remainder === 0n) return negative ? -quotient : quotient;\n\n const increment = (() => {\n switch (mode) {\n case 'awayFromZero':\n return true;\n case 'ceil':\n return !negative;\n case 'floor':\n return negative;\n case 'halfAwayFromZero':\n return remainder * 2n >= denominator;\n case 'halfEven': {\n const doubled = remainder * 2n;\n\n return doubled > denominator || (doubled === denominator && quotient % 2n !== 0n);\n }\n case 'towardZero':\n return false;\n default:\n throw new CoinsError('INVALID_ROUNDING', `Unknown rounding mode: ${mode satisfies never}`);\n }\n })();\n\n const result = increment ? quotient + 1n : quotient;\n\n return negative ? -result : result;\n}\n\nexport function toDecimalString(amount: bigint, minorUnit: number): string {\n const negative = amount < 0n;\n const absolute = negative ? -amount : amount;\n const scale = 10n ** BigInt(minorUnit);\n const whole = absolute / scale;\n\n if (minorUnit === 0) return `${negative ? '-' : ''}${whole}`;\n\n const fraction = (absolute % scale).toString().padStart(minorUnit, '0');\n\n return `${negative ? '-' : ''}${whole}.${fraction}`;\n}\n\nexport function gcd(left: bigint, right: bigint): bigint {\n let a = left;\n let b = right;\n\n while (b !== 0n) [a, b] = [b, a % b];\n\n return a === 0n ? 1n : a;\n}\n\nexport function lcm(left: bigint, right: bigint): bigint {\n return (left / gcd(left, right)) * right;\n}\n","import { CoinsError, InvalidCurrencyError } from './errors';\nimport type { Currency, CurrencyCode } from './types';\n\nconst builtins = new Map<string, Currency>();\nconst canonicalCurrencies = new WeakSet<object>();\n\nfunction register<C extends string>(code: C, minorUnit: number): Currency<C> {\n validateDefinition(code, minorUnit);\n\n const definition = Object.freeze({ code: code as CurrencyCode<C>, minorUnit }) as Currency<C>;\n\n canonicalCurrencies.add(definition);\n\n return definition;\n}\n\nfunction builtin<C extends string>(code: C, minorUnit: number): Currency<C> {\n const definition = register(code, minorUnit);\n\n builtins.set(code, definition);\n\n return definition;\n}\n\nexport const USD = builtin('USD', 2);\nexport const EUR = builtin('EUR', 2);\nexport const GBP = builtin('GBP', 2);\nexport const JPY = builtin('JPY', 0);\nexport const KRW = builtin('KRW', 0);\nexport const BHD = builtin('BHD', 3);\nexport const KWD = builtin('KWD', 3);\n\n/** Resolve a built-in currency by code, or construct an immutable custom currency from a definition. */\nexport function currency<C extends string>(code: C): Currency<C>;\nexport function currency<C extends string>(definition: { code: C; minorUnit: number }): Currency<C>;\nexport function currency<C extends string>(input: C | { code: C; minorUnit: number }): Currency<C> {\n if (typeof input === 'string') {\n const definition = builtins.get(input);\n\n if (!definition) throw new InvalidCurrencyError(input);\n\n return definition as Currency<C>;\n }\n\n return register(input.code, input.minorUnit);\n}\n\nexport function isCurrency(value: unknown): value is Currency {\n return typeof value === 'object' && value !== null && canonicalCurrencies.has(value);\n}\n\nfunction validateDefinition(code: string, minorUnit: number): void {\n if (!/^[A-Z]{3}$/.test(code)) {\n throw new CoinsError('INVALID_CURRENCY', `Currency code must be three uppercase letters: \"${code}\"`);\n }\n\n if (!Number.isInteger(minorUnit) || minorUnit < 0 || minorUnit > 6) {\n throw new CoinsError('INVALID_CURRENCY', `Currency \"${code}\" must have 0–6 minor-unit digits`);\n }\n}\n","import { decimal, roundDivision, toDecimalString } from './_decimal';\nimport { isCurrency } from './currency';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport type { Currency, Money, RoundingMode } from './types';\n\nconst canonicalMoney = new WeakSet<object>();\n\nconst defaultRounding: RoundingMode = 'halfAwayFromZero';\n\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?.rounding === undefined) {\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\n/** Validates a plain data object and returns canonical money. Use for untrusted input; use `isMoney()` for trusted values. */\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 return typeof value === 'object' && value !== null && canonicalMoney.has(value);\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 divisorMagnitude = scalar.numerator < 0n ? -scalar.numerator : scalar.numerator;\n const dividend = value.amount * scalar.denominator;\n const quotient = roundDivision(\n scalar.numerator < 0n ? -dividend : dividend,\n divisorMagnitude,\n options.rounding ?? defaultRounding,\n );\n\n return createMoney(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_RANGE', '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 createMoney<C extends Currency>(amount: bigint, currency: C): Money<C> {\n const value = Object.freeze({ amount, currency }) as Money<C>;\n\n canonicalMoney.add(value);\n\n return value;\n}\n\nexport function assertMoney(value: unknown): asserts value is Money {\n if (!isMoney(value)) {\n throw new CoinsError('INVALID_MONEY', 'Money must be a canonical @vielzeug/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: unknown): asserts value is Currency {\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","import { decimal, lcm } from './_decimal';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { assertMoney, createMoney } from './money';\nimport type { Currency, Money } from './types';\n\nexport function sum<C extends Currency>(values: readonly Money<C>[]): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options: { currency: C }): Money<C>;\nexport function sum<C extends Currency>(values: Iterable<Money<C>>, options?: { currency: C }): Money<C> {\n let amount = 0n;\n let currency: C | undefined = options?.currency;\n\n for (const value of values) {\n assertMoney(value);\n\n if (currency === undefined) {\n currency = value.currency;\n } else if (value.currency !== currency) {\n throw new CurrencyMismatchError(currency.code, value.currency.code);\n }\n\n amount += value.amount;\n }\n\n if (currency === undefined) throw new CoinsError('INVALID_MONEY', 'sum() of empty iterable requires { currency }');\n\n return createMoney(amount, currency);\n}\n\nexport function allocate<C extends Currency>(value: Money<C>, count: number): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weights: readonly string[]): Money<C>[];\nexport function allocate<C extends Currency>(value: Money<C>, weightsOrCount: number | readonly string[]): Money<C>[] {\n assertMoney(value);\n\n if (typeof weightsOrCount === 'number') return allocateEvenly(value, weightsOrCount);\n\n if (weightsOrCount.length === 0) throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be empty');\n\n const weights = weightsOrCount.map(decimal);\n\n if (weights.some((weight) => weight.numerator < 0n)) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights cannot be negative');\n }\n\n const commonDenominator = weights.reduce((result, weight) => lcm(result, weight.denominator), 1n);\n const scaledWeights = weights.map((weight) => weight.numerator * (commonDenominator / weight.denominator));\n const totalWeight = scaledWeights.reduce((result, weight) => result + weight, 0n);\n\n if (totalWeight === 0n)\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation weights must include a positive value');\n\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const shares = scaledWeights.map((weight) => (absolute * weight) / totalWeight);\n let remainder = absolute - shares.reduce((result, amount) => result + amount, 0n);\n const ranked = scaledWeights\n .map((weight, index) => ({ index, remainder: (absolute * weight) % totalWeight }))\n .sort((left, right) =>\n left.remainder === right.remainder ? left.index - right.index : left.remainder > right.remainder ? -1 : 1,\n );\n\n for (const entry of ranked) {\n if (remainder === 0n) break;\n\n shares[entry.index]! += 1n;\n remainder -= 1n;\n }\n\n return shares.map((amount) => createMoney(amount * sign, value.currency));\n}\n\nfunction allocateEvenly<C extends Currency>(value: Money<C>, countValue: number): Money<C>[] {\n if (!Number.isInteger(countValue) || countValue < 1) {\n throw new CoinsError('INVALID_ALLOCATION', 'Allocation count must be a positive integer');\n }\n\n const count = BigInt(countValue);\n const sign = value.amount < 0n ? -1n : 1n;\n const absolute = value.amount < 0n ? -value.amount : value.amount;\n const base = absolute / count;\n const remainder = absolute % count;\n\n return Array.from({ length: countValue }, (_, index) =>\n createMoney((base + (BigInt(index) < remainder ? 1n : 0n)) * sign, value.currency),\n );\n}\n","import { decimal, roundDivision } from './_decimal';\nimport { isCurrency } from './currency';\nimport { CoinsError, CurrencyMismatchError } from './errors';\nimport { assertMoney, createMoney } from './money';\nimport type { Currency, ExchangeRate, Money, RoundingMode } from './types';\n\nconst canonicalRates = new WeakSet<object>();\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 const rate = Object.freeze({ from, to, value: parsed }) as ExchangeRate<From, To>;\n\n canonicalRates.add(rate);\n\n return rate;\n}\n\nexport function isExchangeRate(value: unknown): value is ExchangeRate {\n return typeof value === 'object' && value !== null && canonicalRates.has(value);\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 assertMoney(value);\n\n if (!isExchangeRate(rate)) {\n throw new CoinsError('INVALID_EXCHANGE_RATE', 'Exchange requires a canonical exchange rate');\n }\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 createMoney(roundDivision(numerator, denominator, options.rounding ?? 'halfAwayFromZero'), rate.to);\n}\n","import { roundDivision } from './_decimal';\nimport { CoinsError } from './errors';\nimport { assertMoney } 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 assertMoney(value);\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","import { currency } from './currency';\nimport { CoinsError } from './errors';\nimport { assertMoney, 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 assertMoney(value);\n\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 ?? currency;\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 currencyCode = 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 currencyCode !== 'string' || unit !== 'minor') throw new TypeError('Money JSON currency/unit are invalid');\n\n return { amount, currency: currencyCode, unit };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var Coins=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=class extends Error{code;constructor(e,t,n){super(t,n),this.code=e,this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{expected;received;constructor(e,t){super(`CURRENCY_MISMATCH`,`Currency mismatch: ${e} and ${t}`),this.expected=e,this.received=t}},r=class extends t{value;constructor(e){super(`INVALID_CURRENCY`,`Unsupported currency: "${String(e)}"`),this.value=e}},i=/^(-?)(\d+)(?:\.(\d+))?$/,a=1e3,o=100;function s(e){if(e.length>a)throw new t(`INVALID_DECIMAL`,`Decimal input is too long`);let n=i.exec(e);if(!n)throw new t(`INVALID_DECIMAL`,`Invalid decimal: "${e}"`);let r=(n[3]??``).replace(/0+$/,``);if(r.length>o)throw new t(`INVALID_DECIMAL`,`Decimal precision cannot exceed ${o} places`);let s=10n**BigInt(r.length),c=BigInt(n[2])*s+BigInt(r||`0`),l=n[1]===`-`&&c!==0n?-c:c,d=u(l<0n?-l:l,s);return Object.freeze({denominator:s/d,numerator:l/d})}function c(e,n,r){if(n<=0n)throw new t(`INVALID_DECIMAL`,`Decimal denominator must be positive`);let i=e<0n,a=i?-e:e,o=a/n,s=a%n;if(s===0n)return i?-o:o;let c=(()=>{switch(r){case`awayFromZero`:return!0;case`ceil`:return!i;case`floor`:return i;case`halfAwayFromZero`:return s*2n>=n;case`halfEven`:{let e=s*2n;return e>n||e===n&&o%2n!=0n}case`towardZero`:return!1}})()?o+1n:o;return i?-c:c}function l(e,t){let n=e<0n,r=n?-e:e,i=10n**BigInt(t),a=r/i;if(t===0)return`${n?`-`:``}${a}`;let o=(r%i).toString().padStart(t,`0`);return`${n?`-`:``}${a}.${o}`}function u(e,t){let n=e,r=t;for(;r!==0n;)[n,r]=[r,n%r];return n===0n?1n:n}function d(e,t){return e/u(e,t)*t}var f=new Map,p=new Map;function m(e,t){let n=T(e,t);return f.set(e,n),n}var h=m(`USD`,2),g=m(`EUR`,2),_=m(`GBP`,2),v=m(`JPY`,0),ee=m(`KRW`,0),y=m(`BHD`,3),b=m(`KWD`,3);function x({code:e,minorUnit:t}){E(e,t);let n=f.get(e);if(n){if(n.minorUnit!==t)throw D(e,n.minorUnit);return n}let r=p.get(e);if(r){if(r.minorUnit!==t)throw D(e,r.minorUnit);return r}let i=T(e,t);return p.set(e,i),i}function S(e){let t=f.get(e)??p.get(e);if(!t)throw new r(e);return t}function C(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.code==`string`&&(f.get(t.code)===e||p.get(t.code)===e)}function w(e){let t=f.get(e);if(!t)throw new r(e);return t}function T(e,t){return E(e,t),Object.freeze({code:e,minorUnit:t})}function E(e,n){if(!/^[A-Z]{3}$/.test(e))throw new t(`INVALID_CURRENCY`,`Currency code must be three uppercase letters: "${e}"`);if(!Number.isInteger(n)||n<0||n>6)throw new t(`INVALID_CURRENCY`,`Currency "${e}" must have 0–6 minor-unit digits`)}function D(e,n){return new t(`INVALID_CURRENCY`,`Currency "${e}" already has ${n} minor-unit digits`)}var O=`halfAwayFromZero`;function k(e,n,r){if(V(n),typeof e==`bigint`){if(!r||!(`unit`in r)||r.unit!==`minor`)throw new t(`INVALID_MONEY`,`Bigint amounts require { unit: 'minor' }`);return R(e,n)}if(r&&`unit`in r)throw new t(`INVALID_MONEY`,`Decimal strings do not accept a unit option`);let i=s(e),a=i.numerator*10n**BigInt(n.minorUnit);if(a%i.denominator!==0n&&!r)throw new t(`INVALID_MONEY`,`Amount "${e}" exceeds ${n.code} precision; provide rounding`);return R(c(a,i.denominator,r?.rounding??O),n)}function A(e){if(!H(e))throw new t(`INVALID_MONEY`,`Money must be a plain data object`);let n=Object.getOwnPropertyDescriptors(e),r=n.amount,i=n.currency;if(!U(r)||!U(i))throw new t(`INVALID_MONEY`,`Money properties must be plain data values`);if(typeof r.value!=`bigint`||!C(i.value))throw new t(`INVALID_MONEY`,`Money must contain bigint amount and a registered currency`);return R(r.value,i.value)}function j(e){try{return A(e),!0}catch{return!1}}function te(e,t){return B(e,t),R(e.amount+t.amount,e.currency)}function ne(e,t){return B(e,t),R(e.amount-t.amount,e.currency)}function re(e,t,n={}){z(e);let r=s(t);return R(c(e.amount*r.numerator,r.denominator,n.rounding??O),e.currency)}function ie(e,n,r={}){z(e);let i=s(n);if(i.numerator===0n)throw new t(`DIVISION_BY_ZERO`,`Cannot divide money by zero`);let a=i.numerator<0n,o=a?-i.numerator:i.numerator,l=c(e.amount*i.denominator,o,r.rounding??O);return R(a?-l:l,e.currency)}function M(e,t){return B(e,t),e.amount===t.amount?0:e.amount<t.amount?-1:1}function ae(e,n){if(M(n.min,n.max)===1)throw new t(`INVALID_MONEY`,`Clamp minimum cannot exceed maximum`);return M(e,n.min)===-1?n.min:M(e,n.max)===1?n.max:e}function N(e){return z(e),R(e.amount<0n?-e.amount:e.amount,e.currency)}function P(e){return z(e),R(-e.amount,e.currency)}function F(e,n){z(e);let{fractionDigits:r,rounding:i=O}=n;if(!Number.isInteger(r)||r<0||r>e.currency.minorUnit)throw new t(`INVALID_ROUNDING`,`fractionDigits must be an integer from 0 to ${e.currency.minorUnit}`);let a=10n**BigInt(e.currency.minorUnit-r);return R(c(e.amount,a,i)*a,e.currency)}function I(e){return z(e),l(e.amount,e.currency.minorUnit)}function L(e,t){return V(t),R(e,t)}function R(e,t){return Object.freeze({amount:e,currency:t})}function z(e){if(!Object.isFrozen(e)||!C(e.currency))throw new t(`INVALID_MONEY`,`Money must be a canonical Coins value`)}function B(e,t){if(z(e),z(t),e.currency!==t.currency)throw new n(e.currency.code,t.currency.code)}function V(e){if(!C(e))throw new t(`INVALID_CURRENCY`,`Money requires a registered currency`)}function H(e){if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function U(e){return e!==void 0&&`value`in e&&e.get===void 0&&e.set===void 0}function W(e,r){let i=0n,a=r?.currency;for(let r of e){if(!j(r))throw new t(`INVALID_MONEY`,`sum() requires canonical money values`);if(a===void 0)a=r.currency;else if(r.currency!==a)throw new n(a.code,r.currency.code);i+=r.amount}if(a===void 0)throw new t(`INVALID_MONEY`,`sum() of empty iterable requires { currency }`);return L(i,a)}function G(e,n){if(!j(e))throw new t(`INVALID_MONEY`,`allocate() requires canonical money`);if(typeof n==`number`)return K(e,n);if(n.length===0)throw new t(`INVALID_ALLOCATION`,`Allocation weights cannot be empty`);let r=n.map(s);if(r.some(e=>e.numerator<0n))throw new t(`INVALID_ALLOCATION`,`Allocation weights cannot be negative`);let i=r.reduce((e,t)=>d(e,t.denominator),1n),a=r.map(e=>e.numerator*(i/e.denominator)),o=a.reduce((e,t)=>e+t,0n);if(o===0n)throw new t(`INVALID_ALLOCATION`,`Allocation weights must include a positive value`);let c=e.amount<0n?-1n:1n,l=e.amount<0n?-e.amount:e.amount,u=a.map(e=>l*e/o),f=l-u.reduce((e,t)=>e+t,0n),p=a.map((e,t)=>({index:t,remainder:l*e%o})).sort((e,t)=>e.remainder===t.remainder?e.index-t.index:e.remainder>t.remainder?-1:1);for(let e of p){if(f===0n)break;u[e.index]+=1n,f-=1n}return u.map(t=>L(t*c,e.currency))}function K(e,n){if(!Number.isInteger(n)||n<1)throw new t(`INVALID_ALLOCATION`,`Allocation count must be a positive integer`);let r=BigInt(n),i=e.amount<0n?-1n:1n,a=e.amount<0n?-e.amount:e.amount,o=a/r,s=a%r;return Array.from({length:n},(t,n)=>L((o+(BigInt(n)<s?1n:0n))*i,e.currency))}function q({from:e,to:n,value:r}){if(!C(e)||!C(n))throw new t(`INVALID_CURRENCY`,`Exchange rate requires registered currencies`);let i=s(r);if(i.numerator<0n)throw new t(`INVALID_DECIMAL`,`Exchange rates cannot be negative`);return Object.freeze({from:e,to:n,value:i})}function oe(e,r,i={}){if(!j(e)||!se(r))throw new t(`INVALID_MONEY`,`Exchange requires canonical money and rate values`);if(e.currency!==r.from)throw new n(e.currency.code,r.from.code);return L(c(e.amount*r.value.numerator*10n**BigInt(r.to.minorUnit),r.value.denominator*10n**BigInt(r.from.minorUnit),i.rounding??`halfAwayFromZero`),r.to)}function se(e){if(typeof e!=`object`||!e||!Object.isFrozen(e))return!1;let t=e;return C(t.from)&&C(t.to)&&typeof t.value==`object`&&t.value!==null&&Object.isFrozen(t.value)&&typeof t.value.numerator==`bigint`&&t.value.numerator>=0n&&typeof t.value.denominator==`bigint`&&t.value.denominator>0n}var J=20,ce=`halfAwayFromZero`,Y=new Map,X=new Map;function le(e,t={}){return Z(e,t).map(e=>e.value).join(``)}function Z(e,n={}){if(!j(e))throw new t(`INVALID_MONEY`,`format() requires canonical money`);let{locale:r=`en-US`,maximumFractionDigits:i=e.currency.minorUnit,minimumFractionDigits:a=e.currency.minorUnit,rounding:o=ce,style:s=`symbol`}=n;ue(a,i);let l=10n**BigInt(i),u=i>=e.currency.minorUnit?e.amount*10n**BigInt(i-e.currency.minorUnit):c(e.amount,10n**BigInt(e.currency.minorUnit-i),o),d=u<0n,f=d?-u:u,p=f/l,m=(i===0?``:(f%l).toString().padStart(i,`0`)).replace(RegExp(`0{0,${Math.max(0,i-a)}}$`),``),h=Q(r,e.currency.code,s,d),g=[],_=!1;for(let e of h)e.type!==`group`&&(e.type===`integer`?_||=(g.push({type:`integer`,value:de(r).format(p)}),!0):e.type===`decimal`?m&&g.push({type:`decimal`,value:e.value}):e.type===`fraction`?m&&g.push({type:`fraction`,value:m}):e.type===`currency`||e.type===`minusSign`||e.type===`plusSign`?g.push({type:e.type,value:e.value}):g.push({type:`literal`,value:e.value}));return g}function ue(e,n){if(!Number.isInteger(n)||!Number.isInteger(e)||e<0||n<e||n>J)throw new t(`FORMAT_ERROR`,`Fraction digits must be integers satisfying 0 ≤ minimum ≤ maximum ≤ ${J}`)}function Q(e,n,r,i){let a=`${e}\0${n}\0${r}\0${i}`,o=X.get(a);if(o)return o;try{let t=new Intl.NumberFormat(e,{currency:n,currencyDisplay:r,maximumFractionDigits:1,minimumFractionDigits:1,style:`currency`}).formatToParts(i?-1.1:1.1);return X.set(a,t),t}catch(r){throw new t(`FORMAT_ERROR`,`Cannot format currency "${n}" for locale "${e}"`,{cause:r})}}function de(e){let n=Y.get(e);if(n)return n;try{let t=new Intl.NumberFormat(e,{maximumFractionDigits:0,useGrouping:!0});return Y.set(e,t),t}catch(n){throw new t(`FORMAT_ERROR`,`Cannot create number formatter for locale "${e}"`,{cause:n})}}var fe=/^(?:0|-[1-9]\d*|[1-9]\d*)$/,$=[`amount`,`currency`,`unit`];function pe(e){return{amount:e.amount.toString(),currency:e.currency.code,unit:`minor`}}function me(e,n={}){try{let t=he(e),r=n.currency??w;return k(BigInt(t.amount),r(t.currency),{unit:`minor`})}catch(e){throw new t(`INVALID_MONEY`,`Invalid Money JSON`,{cause:e})}}function he(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!==$.length||!$.every(e=>n.includes(e)))throw TypeError(`Money JSON must contain only amount, currency, and unit`);for(let e of $){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 r=t.amount?.value,i=t.currency?.value,a=t.unit?.value;if(typeof r!=`string`||!fe.test(r))throw TypeError(`Money JSON amount must be a canonical integer string`);if(typeof i!=`string`||a!==`minor`)throw TypeError(`Money JSON currency/unit are invalid`);return{amount:r,currency:i,unit:a}}return e.BHD=y,e.CoinsError=t,e.CurrencyMismatchError=n,e.EUR=g,e.GBP=_,e.InvalidCurrencyError=r,e.JPY=v,e.KRW=ee,e.KWD=b,e.USD=h,e.abs=N,e.add=te,e.allocate=G,e.clamp=ae,e.compare=M,e.currency=S,e.defineCurrency=x,e.divide=ie,e.exchange=oe,e.exchangeRate=q,e.format=le,e.formatParts=Z,e.isCurrency=C,e.isMoney=j,e.money=k,e.multiply=re,e.negate=P,e.parseMoney=A,e.parseMoneyJSON=me,e.round=F,e.subtract=ne,e.sum=W,e.toDecimal=I,e.toJSON=pe,e})({});
1
+ var Coins=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=class extends Error{code;constructor(e,t,n){super(t,n),this.code=e,this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},n=class extends t{expected;received;constructor(e,t){super(`CURRENCY_MISMATCH`,`Currency mismatch: ${e} and ${t}`),this.expected=e,this.received=t}},r=class extends t{value;constructor(e){super(`INVALID_CURRENCY`,`Unsupported currency: "${String(e)}"`),this.value=e}},i=/^(-?)(\d+)(?:\.(\d+))?$/,a=1e3,o=100;function s(e){if(e.length>a)throw new t(`INVALID_DECIMAL`,`Decimal input is too long`);let n=i.exec(e);if(!n)throw new t(`INVALID_DECIMAL`,`Invalid decimal: "${e}"`);let r=(n[3]??``).replace(/0+$/,``);if(r.length>o)throw new t(`INVALID_DECIMAL`,`Decimal precision cannot exceed ${o} places`);let s=10n**BigInt(r.length),c=BigInt(n[2])*s+BigInt(r||`0`),l=n[1]===`-`&&c!==0n?-c:c,d=u(l<0n?-l:l,s);return Object.freeze({denominator:s/d,numerator:l/d})}function c(e,n,r){if(n<=0n)throw new t(`INVALID_DECIMAL`,`Decimal denominator must be positive`);let i=e<0n,a=i?-e:e,o=a/n,s=a%n;if(s===0n)return i?-o:o;let c=(()=>{switch(r){case`awayFromZero`:return!0;case`ceil`:return!i;case`floor`:return i;case`halfAwayFromZero`:return s*2n>=n;case`halfEven`:{let e=s*2n;return e>n||e===n&&o%2n!=0n}case`towardZero`:return!1;default:throw new t(`INVALID_ROUNDING`,`Unknown rounding mode: ${r}`)}})()?o+1n:o;return i?-c:c}function l(e,t){let n=e<0n,r=n?-e:e,i=10n**BigInt(t),a=r/i;if(t===0)return`${n?`-`:``}${a}`;let o=(r%i).toString().padStart(t,`0`);return`${n?`-`:``}${a}.${o}`}function u(e,t){let n=e,r=t;for(;r!==0n;)[n,r]=[r,n%r];return n===0n?1n:n}function d(e,t){return e/u(e,t)*t}var f=new Map,p=new WeakSet;function m(e,t){C(e,t);let n=Object.freeze({code:e,minorUnit:t});return p.add(n),n}function h(e,t){let n=m(e,t);return f.set(e,n),n}var g=h(`USD`,2),ee=h(`EUR`,2),_=h(`GBP`,2),v=h(`JPY`,0),y=h(`KRW`,0),b=h(`BHD`,3),te=h(`KWD`,3);function x(e){if(typeof e==`string`){let t=f.get(e);if(!t)throw new r(e);return t}return m(e.code,e.minorUnit)}function S(e){return typeof e==`object`&&!!e&&p.has(e)}function C(e,n){if(!/^[A-Z]{3}$/.test(e))throw new t(`INVALID_CURRENCY`,`Currency code must be three uppercase letters: "${e}"`);if(!Number.isInteger(n)||n<0||n>6)throw new t(`INVALID_CURRENCY`,`Currency "${e}" must have 0–6 minor-unit digits`)}var w=new WeakSet,T=`halfAwayFromZero`;function E(e,n,r){if(R(n),typeof e==`bigint`){if(!r||!(`unit`in r)||r.unit!==`minor`)throw new t(`INVALID_MONEY`,`Bigint amounts require { unit: 'minor' }`);return F(e,n)}if(r&&`unit`in r)throw new t(`INVALID_MONEY`,`Decimal strings do not accept a unit option`);let i=s(e),a=i.numerator*10n**BigInt(n.minorUnit);if(a%i.denominator!==0n&&r?.rounding===void 0)throw new t(`INVALID_MONEY`,`Amount "${e}" exceeds ${n.code} precision; provide rounding`);return F(c(a,i.denominator,r?.rounding??T),n)}function D(e){if(!z(e))throw new t(`INVALID_MONEY`,`Money must be a plain data object`);let n=Object.getOwnPropertyDescriptors(e),r=n.amount,i=n.currency;if(!B(r)||!B(i))throw new t(`INVALID_MONEY`,`Money properties must be plain data values`);if(typeof r.value!=`bigint`||!S(i.value))throw new t(`INVALID_MONEY`,`Money must contain bigint amount and a registered currency`);return F(r.value,i.value)}function O(e){return typeof e==`object`&&!!e&&w.has(e)}function ne(e,t){return L(e,t),F(e.amount+t.amount,e.currency)}function re(e,t){return L(e,t),F(e.amount-t.amount,e.currency)}function ie(e,t,n={}){I(e);let r=s(t);return F(c(e.amount*r.numerator,r.denominator,n.rounding??T),e.currency)}function ae(e,n,r={}){I(e);let i=s(n);if(i.numerator===0n)throw new t(`DIVISION_BY_ZERO`,`Cannot divide money by zero`);let a=i.numerator<0n?-i.numerator:i.numerator,o=e.amount*i.denominator;return F(c(i.numerator<0n?-o:o,a,r.rounding??T),e.currency)}function k(e,t){return L(e,t),e.amount===t.amount?0:e.amount<t.amount?-1:1}function A(e,n){if(k(n.min,n.max)===1)throw new t(`INVALID_RANGE`,`Clamp minimum cannot exceed maximum`);return k(e,n.min)===-1?n.min:k(e,n.max)===1?n.max:e}function j(e){return I(e),F(e.amount<0n?-e.amount:e.amount,e.currency)}function M(e){return I(e),F(-e.amount,e.currency)}function N(e,n){I(e);let{fractionDigits:r,rounding:i=T}=n;if(!Number.isInteger(r)||r<0||r>e.currency.minorUnit)throw new t(`INVALID_ROUNDING`,`fractionDigits must be an integer from 0 to ${e.currency.minorUnit}`);let a=10n**BigInt(e.currency.minorUnit-r);return F(c(e.amount,a,i)*a,e.currency)}function P(e){return I(e),l(e.amount,e.currency.minorUnit)}function F(e,t){let n=Object.freeze({amount:e,currency:t});return w.add(n),n}function I(e){if(!O(e))throw new t(`INVALID_MONEY`,`Money must be a canonical @vielzeug/coins value`)}function L(e,t){if(I(e),I(t),e.currency!==t.currency)throw new n(e.currency.code,t.currency.code)}function R(e){if(!S(e))throw new t(`INVALID_CURRENCY`,`Money requires a registered currency`)}function z(e){if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function B(e){return e!==void 0&&`value`in e&&e.get===void 0&&e.set===void 0}function V(e,r){let i=0n,a=r?.currency;for(let t of e){if(I(t),a===void 0)a=t.currency;else if(t.currency!==a)throw new n(a.code,t.currency.code);i+=t.amount}if(a===void 0)throw new t(`INVALID_MONEY`,`sum() of empty iterable requires { currency }`);return F(i,a)}function H(e,n){if(I(e),typeof n==`number`)return U(e,n);if(n.length===0)throw new t(`INVALID_ALLOCATION`,`Allocation weights cannot be empty`);let r=n.map(s);if(r.some(e=>e.numerator<0n))throw new t(`INVALID_ALLOCATION`,`Allocation weights cannot be negative`);let i=r.reduce((e,t)=>d(e,t.denominator),1n),a=r.map(e=>e.numerator*(i/e.denominator)),o=a.reduce((e,t)=>e+t,0n);if(o===0n)throw new t(`INVALID_ALLOCATION`,`Allocation weights must include a positive value`);let c=e.amount<0n?-1n:1n,l=e.amount<0n?-e.amount:e.amount,u=a.map(e=>l*e/o),f=l-u.reduce((e,t)=>e+t,0n),p=a.map((e,t)=>({index:t,remainder:l*e%o})).sort((e,t)=>e.remainder===t.remainder?e.index-t.index:e.remainder>t.remainder?-1:1);for(let e of p){if(f===0n)break;u[e.index]+=1n,f-=1n}return u.map(t=>F(t*c,e.currency))}function U(e,n){if(!Number.isInteger(n)||n<1)throw new t(`INVALID_ALLOCATION`,`Allocation count must be a positive integer`);let r=BigInt(n),i=e.amount<0n?-1n:1n,a=e.amount<0n?-e.amount:e.amount,o=a/r,s=a%r;return Array.from({length:n},(t,n)=>F((o+(BigInt(n)<s?1n:0n))*i,e.currency))}var W=new WeakSet;function G({from:e,to:n,value:r}){if(!S(e)||!S(n))throw new t(`INVALID_CURRENCY`,`Exchange rate requires registered currencies`);let i=s(r);if(i.numerator<0n)throw new t(`INVALID_DECIMAL`,`Exchange rates cannot be negative`);let a=Object.freeze({from:e,to:n,value:i});return W.add(a),a}function K(e){return typeof e==`object`&&!!e&&W.has(e)}function q(e,r,i={}){if(I(e),!K(r))throw new t(`INVALID_EXCHANGE_RATE`,`Exchange requires a canonical exchange rate`);if(e.currency!==r.from)throw new n(e.currency.code,r.from.code);return F(c(e.amount*r.value.numerator*10n**BigInt(r.to.minorUnit),r.value.denominator*10n**BigInt(r.from.minorUnit),i.rounding??`halfAwayFromZero`),r.to)}var J=20,oe=`halfAwayFromZero`,Y=new Map,X=new Map;function se(e,t={}){return Z(e,t).map(e=>e.value).join(``)}function Z(e,t={}){I(e);let{locale:n=`en-US`,maximumFractionDigits:r=e.currency.minorUnit,minimumFractionDigits:i=e.currency.minorUnit,rounding:a=oe,style:o=`symbol`}=t;ce(i,r);let s=10n**BigInt(r),l=r>=e.currency.minorUnit?e.amount*10n**BigInt(r-e.currency.minorUnit):c(e.amount,10n**BigInt(e.currency.minorUnit-r),a),u=l<0n,d=u?-l:l,f=d/s,p=(r===0?``:(d%s).toString().padStart(r,`0`)).replace(RegExp(`0{0,${Math.max(0,r-i)}}$`),``),m=le(n,e.currency.code,o,u),h=[],g=!1;for(let e of m)e.type!==`group`&&(e.type===`integer`?g||=(h.push({type:`integer`,value:ue(n).format(f)}),!0):e.type===`decimal`?p&&h.push({type:`decimal`,value:e.value}):e.type===`fraction`?p&&h.push({type:`fraction`,value:p}):e.type===`currency`||e.type===`minusSign`||e.type===`plusSign`?h.push({type:e.type,value:e.value}):h.push({type:`literal`,value:e.value}));return h}function ce(e,n){if(!Number.isInteger(n)||!Number.isInteger(e)||e<0||n<e||n>J)throw new t(`FORMAT_ERROR`,`Fraction digits must be integers satisfying 0 ≤ minimum ≤ maximum ≤ ${J}`)}function le(e,n,r,i){let a=`${e}\0${n}\0${r}\0${i}`,o=X.get(a);if(o)return o;try{let t=new Intl.NumberFormat(e,{currency:n,currencyDisplay:r,maximumFractionDigits:1,minimumFractionDigits:1,style:`currency`}).formatToParts(i?-1.1:1.1);return X.set(a,t),t}catch(r){throw new t(`FORMAT_ERROR`,`Cannot format currency "${n}" for locale "${e}"`,{cause:r})}}function ue(e){let n=Y.get(e);if(n)return n;try{let t=new Intl.NumberFormat(e,{maximumFractionDigits:0,useGrouping:!0});return Y.set(e,t),t}catch(n){throw new t(`FORMAT_ERROR`,`Cannot create number formatter for locale "${e}"`,{cause:n})}}var Q=/^(?:0|-[1-9]\d*|[1-9]\d*)$/,$=[`amount`,`currency`,`unit`];function de(e){return I(e),{amount:e.amount.toString(),currency:e.currency.code,unit:`minor`}}function fe(e,n={}){try{let t=pe(e),r=n.currency??x;return E(BigInt(t.amount),r(t.currency),{unit:`minor`})}catch(e){throw new t(`INVALID_MONEY`,`Invalid Money JSON`,{cause:e})}}function pe(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!==$.length||!$.every(e=>n.includes(e)))throw TypeError(`Money JSON must contain only amount, currency, and unit`);for(let e of $){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 r=t.amount?.value,i=t.currency?.value,a=t.unit?.value;if(typeof r!=`string`||!Q.test(r))throw TypeError(`Money JSON amount must be a canonical integer string`);if(typeof i!=`string`||a!==`minor`)throw TypeError(`Money JSON currency/unit are invalid`);return{amount:r,currency:i,unit:a}}return e.BHD=b,e.CoinsError=t,e.CurrencyMismatchError=n,e.EUR=ee,e.GBP=_,e.InvalidCurrencyError=r,e.JPY=v,e.KRW=y,e.KWD=te,e.USD=g,e.abs=j,e.add=ne,e.allocate=H,e.clamp=A,e.compare=k,e.currency=x,e.divide=ae,e.exchange=q,e.exchangeRate=G,e.format=se,e.formatParts=Z,e.isCurrency=S,e.isExchangeRate=K,e.isMoney=O,e.money=E,e.multiply=ie,e.negate=M,e.parseMoney=D,e.parseMoneyJSON=fe,e.round=N,e.subtract=re,e.sum=V,e.toDecimal=P,e.toJSON=de,e})({});
2
2
  //# sourceMappingURL=coins.iife.js.map