From ed6d9e0f4781b92249374847eeb2e4167fae3ed1 Mon Sep 17 00:00:00 2001 From: Frode Aannevik Date: Mon, 16 Oct 2023 14:47:13 +0200 Subject: [PATCH] chore(dev-deps): Add groups to `dependabot.yml` and enable prettier (#104) Group related dependencies to reduce the number of PRs created by dependabot and run prettier on all files. Adjust the eslint configuration to extend from prettier instead of `dintero/typescript` --- .eslintrc.json | 22 +- .github/dependabot.yml | 18 + .github/workflows/build.yml | 31 +- .github/workflows/release.yml | 2 +- .prettierignore | 1 + .prettierrc.yml | 8 + .releaserc.json | 16 +- CHANGELOG.md | 4 +- README.md | 590 +++++++++++++------------- package.json | 101 ++--- src/__tests__/money.test.ts | 488 +++++++++++++--------- src/index.ts | 442 ++++++++++++-------- yarn.lock | 754 +--------------------------------- 13 files changed, 996 insertions(+), 1481 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc.yml diff --git a/.eslintrc.json b/.eslintrc.json index 98873e9..d4075da 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,16 +1,20 @@ { "root": true, "extends": [ - "dintero/typescript" - ], - "plugins": [ - "import" + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "prettier" ], + "plugins": ["@typescript-eslint"], "rules": { - "semi": ["error", "never"], - "@typescript-eslint/no-empty-function": "warn", // temporary lower from error to warn - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-unused-vars": "off", - "function-paren-newline": "off" + "@typescript-eslint/consistent-type-imports": ["error"], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } + ] } } diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c19c768..5bc4a02 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,3 +8,21 @@ updates: prefix: fix prefix-development: chore include: scope + groups: + semantic-release: + patterns: + - "@semantic-release/exec" + - "semantic-release" + jest: + patterns: + - "@types/jest" + - "jest" + - "jest-junit" + - "ts-jest" + eslint: + patterns: + - "eslint" + - "eslint-*" + - "@typescript-eslint/eslint-plugin" + - "@typescript-eslint/parser" + - "@trivago/prettier-plugin-sort-imports" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b97e2a3..391c00f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,27 +2,26 @@ name: CI on: pull_request: - branches: [ master ] + branches: [master] jobs: - build: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: 'lts/*' - cache: yarn + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "lts/*" + cache: yarn - - name: yarn install, build and test - run: | - yarn install - yarn run test - yarn run build + - name: yarn install, build and test + run: | + yarn install + yarn run test + yarn run build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1ed4ee2..90bb681 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v3 with: - node-version: 'lts/*' + node-version: "lts/*" cache: yarn - name: yarn install, build and test diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..581edad --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +**/dist diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 0000000..1d996e7 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,8 @@ +printWidth: 80 +tabWidth: 4 +overrides: + - files: + - "*.yml" + - "*.yaml" + options: + tabWidth: 2 diff --git a/.releaserc.json b/.releaserc.json index 1cb50dc..af4c860 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,11 +1,9 @@ { - "branches": [ - "master" - ], - "plugins": [ - "@semantic-release/commit-analyzer", - "@semantic-release/release-notes-generator", - "@semantic-release/github", - "@semantic-release/npm" - ] + "branches": ["master"], + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/github", + "@semantic-release/npm" + ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f19d78..5499a71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,3 @@ -# 1.0.0 - 14.09.2021 +# 1.0.0 - 14.09.2021 -- Initial version released +- Initial version released diff --git a/README.md b/README.md index 3654064..0804b96 100644 --- a/README.md +++ b/README.md @@ -2,62 +2,50 @@ Quick examples -````ts -Money.of(2090.5, 'EUR') - .toCurrency('NOK', 8.61) - .toString() // 17999.21 +```ts +Money.of(2090.5, "EUR").toCurrency("NOK", 8.61).toString(); // 17999.21 -Money.of(0.1, 'NOK') - .add(Money.of(0.2, 'NOK')) - .toString() // 0.30 +Money.of(0.1, "NOK").add(Money.of(0.2, "NOK")).toString(); // 0.30 -Money.fromPriceAndQuantity(0.0005, 30, 'NOK') - .toString() // 0.02 +Money.fromPriceAndQuantity(0.0005, 30, "NOK").toString(); // 0.02 -Money.fromPrice(0.001, 'NOK') - .multiply(60) - .resetDecimals() - .toString() // 0.06 +Money.fromPrice(0.001, "NOK").multiply(60).resetDecimals().toString(); // 0.06 -Money.of(10, 'NOK') - .distributeBy([1, 1, 1]) // list of moneys: [3.34, 3.33, 3.33] +Money.of(10, "NOK").distributeBy([1, 1, 1]); // list of moneys: [3.34, 3.33, 3.33] -Money.of(5.5, 'NOK') - .toLocaleString('no-NB') // 5,50 +Money.of(5.5, "NOK").toLocaleString("no-NB"); // 5,50 -Money.fromLocaleString('5,50', 'NOK', 'no-NB') - .toString() // 5.50 +Money.fromLocaleString("5,50", "NOK", "no-NB").toString(); // 5.50 -Money.of(12.5, 'NOK') - .getVat(25, true) // Amount includes VAT - .toString() // 2.50 +Money.of(12.5, "NOK") + .getVat(25, true) // Amount includes VAT + .toString(); // 2.50 -Money.of(10, 'NOK') - .getVat(25, false) // Amount does not include VAT - .toString() // 2.50 +Money.of(10, "NOK") + .getVat(25, false) // Amount does not include VAT + .toString(); // 2.50 -Money.of('1234567891234567.25', 'NOK') - .toNumber() // Throws because the number cannot be represented as a double -```` +Money.of("1234567891234567.25", "NOK").toNumber(); // Throws because the number cannot be represented as a double +``` See full api at the bottom of this page. ## Features -- Based on big.js, arbitrary base 10 decimal numbers. No weird results due to base 2 doubles. -- Basic math and comparisons -- Ensures correct precision for given currency -- Prevents mixed currencies in calculations -- Handle prices with arbitrary precision -- Print and parse from locale -- Print and parse from fractionless / minor unit / whole number of cents -- Rounding modes (from big.js). For example rounding half even (bankers rounding) -- Throws when encountering precision loss when converting to javascript numbers -- Money objects have tags and tag assertions. E.g. tag with includesVat=true to know that the amount has vat included. -- Everything is immutable -- Various utils - - Calculate VAT - - Distribute money by parts or weights (straight division doesn't work with money) +- Based on big.js, arbitrary base 10 decimal numbers. No weird results due to base 2 doubles. +- Basic math and comparisons +- Ensures correct precision for given currency +- Prevents mixed currencies in calculations +- Handle prices with arbitrary precision +- Print and parse from locale +- Print and parse from fractionless / minor unit / whole number of cents +- Rounding modes (from big.js). For example rounding half even (bankers rounding) +- Throws when encountering precision loss when converting to javascript numbers +- Money objects have tags and tag assertions. E.g. tag with includesVat=true to know that the amount has vat included. +- Everything is immutable +- Various utils + - Calculate VAT + - Distribute money by parts or weights (straight division doesn't work with money) ## About money in javascript / why this library exists @@ -67,49 +55,48 @@ Javascript uses double floating point numbers. There are several problems with these when it comes to handling money: -- Base 2 cannot accurately represent all base 10 numbers (e.g. 0.1 + 0.2). - This makes some calculations inaccurate, no matter the precision we choose. - It should be mentioned that this does not mean that we cannot convert between the bases in a precise way, - though it then should be mentioned that toFixed() is not a precise conversion -- double precision isn't infinite precision. - This matters when we need large numbers, or numbers with many fractional digits (like prices) -- Default rounding in javascript is wrong for negative money amounts +- Base 2 cannot accurately represent all base 10 numbers (e.g. 0.1 + 0.2). + This makes some calculations inaccurate, no matter the precision we choose. + It should be mentioned that this does not mean that we cannot convert between the bases in a precise way, + though it then should be mentioned that toFixed() is not a precise conversion +- double precision isn't infinite precision. + This matters when we need large numbers, or numbers with many fractional digits (like prices) +- Default rounding in javascript is wrong for negative money amounts It's easiest to show by example: -````ts +```ts // Without proper rounding, you'll accumulate small errors: -0.1 + 0.2 // => 0.30000000000000004 +0.1 + 0.2; // => 0.30000000000000004 // With proper rounding, you'll simply get wrong results: -2090.5 * 8.61 // => 17999.204999999998 -;(2090.5 * 8.61).toFixed(2) // => 17999.20 // should have been 17999.21 +2090.5 * 8.61; // => 17999.204999999998 +(2090.5 * 8.61).toFixed(2); // => 17999.20 // should have been 17999.21 // Even if the console.log manages to convert to base 10 for you, // the number might not be what you think it is inside the double, // and toFixed doesn't actually convert to base 10 properly. // (see also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) -8.165.toFixed(2) // => 8.16 // should have been 8.17 +(8.165).toFixed(2); // => 8.16 // should have been 8.17 // Math.round rounds towards 0, which doesn't make sense with money: -Math.round(-1.5) // => -1 // Should have been -2 for money - -// toFixed does it the correct way though: --1.5.toFixed(0) // => -2 // Say what now +Math.round(-1.5) - // => -1 // Should have been -2 for money + // toFixed does it the correct way though: + (1.5).toFixed(0); // => -2 // Say what now // 16 decimal digits are too much for javascript doubles // Note how it doesn't really matter whether we're using whole numbers or not -Number(9999999999999999).toString() // => 10000000000000000 // Too big for most money amounts, so probably fine -Number(999999999999999.9).toString() // => 999999999999999.9 -Number(99999999999999.99).toString() // => 99999999999999.98 -Number(9999999999999.999).toString() // => 9999999999999.998 -Number(999999999999.9999).toString() // => 999999999999.9999 -Number(99999999999.99999).toString() // => 99999999999.99998 -Number(9999999999.999999).toString() // => 9999999999.999998 -Number(999999999.9999999).toString() // => 999999999.9999999 -Number(99999999.99999999).toString() // => 99999999.99999999 -Number(9999999.999999999).toString() // => 9999999.999999998 // If this was a price we would be in trouble -```` +Number(9999999999999999).toString(); // => 10000000000000000 // Too big for most money amounts, so probably fine +Number(999999999999999.9).toString(); // => 999999999999999.9 +Number(99999999999999.99).toString(); // => 99999999999999.98 +Number(9999999999999.999).toString(); // => 9999999999999.998 +Number(999999999999.9999).toString(); // => 999999999999.9999 +Number(99999999999.99999).toString(); // => 99999999999.99998 +Number(9999999999.999999).toString(); // => 9999999999.999998 +Number(999999999.9999999).toString(); // => 999999999.9999999 +Number(99999999.99999999).toString(); // => 99999999.99999999 +Number(9999999.999999999).toString(); // => 9999999.999999998 // If this was a price we would be in trouble +``` This library uses the excellent big.js library which does arbitrary decimal (base 10) arithmetic. This automatically takes care of all the issues above. @@ -121,14 +108,14 @@ This is (probably, see below) completely fine for transport and storage, but it Here's why: -- You still have to divide, and division introduces decimals -- You still have to convert currencies, and the rates have decimals. -- You still have to deal with prices, and those can have an arbitrary number of decimals. - You would need bigints to deal with those since javascript only has 53 bits (15 decimal digits) available for integers. -- You probably still need to convert to and from decimal digits at some point, and .toFixed() is not accurate -- You MUST keep track of the currency and precision/scale. Any errors here and you'll be orders of magnitude off. - This can be larger headache than you might think if you need to cover prices with arbitrary precision. - The problem is also there for storage and transport in this case. +- You still have to divide, and division introduces decimals +- You still have to convert currencies, and the rates have decimals. +- You still have to deal with prices, and those can have an arbitrary number of decimals. + You would need bigints to deal with those since javascript only has 53 bits (15 decimal digits) available for integers. +- You probably still need to convert to and from decimal digits at some point, and .toFixed() is not accurate +- You MUST keep track of the currency and precision/scale. Any errors here and you'll be orders of magnitude off. + This can be larger headache than you might think if you need to cover prices with arbitrary precision. + The problem is also there for storage and transport in this case. In this library we've chosen to use big.js to avoid all potential pitfalls with whole number calculations. @@ -139,7 +126,7 @@ Consider that a double has 53 bits for the significand. This is the part that ha So we have 15 digits to work with. How much can we fit in those? -The worlds GDP is about 8*10^13 USD, which requires 14 digits. In cents it would be 16 digits. +The worlds GDP is about 8\*10^13 USD, which requires 14 digits. In cents it would be 16 digits. So in USD we're just about able to store the entire world's GDP in cents without loss of precision. Note that the exponent in the double doesn't change number of precise digits we get, @@ -148,19 +135,19 @@ so it doesn't matter if we store it as a whole number or a fractional number. In any case, it's quite likely that javascript numbers are good enough for transport and storage for most use cases, even as fractional numbers. However, there are some potential pitfalls: -- The JSON standard doesn't define a precision for numbers, and it's up to the parser to deal with. - It seems quite reasonable to assume at least a double precision though. -- Most currencies have between 0 and 4 decimals after the decimal point, but crypto currencies can have a lot more. - This might cause the precision requirement to go up. -- If you deal with prices, all bets are off. A price can have an arbitrary precision. +- The JSON standard doesn't define a precision for numbers, and it's up to the parser to deal with. + It seems quite reasonable to assume at least a double precision though. +- Most currencies have between 0 and 4 decimals after the decimal point, but crypto currencies can have a lot more. + This might cause the precision requirement to go up. +- If you deal with prices, all bets are off. A price can have an arbitrary precision. You'll have to know how large and precise your numbers will be before you choose how to store and transport them. This library gives you a couple of options: -- as fractionless / whole number -- as a normal number -- as a string +- as fractionless / whole number +- as a normal number +- as a string As we've seen, the first two have potential problems (however unlikely), but to mitigate the risk we make sure to throw an exception if you ever encounter these problems. @@ -171,10 +158,10 @@ If you want to be completely safe, use strings. Money is in a currency, and it usually has a major (e.g. Dollars) and minor unit (e.g. Cents). -- An amount of money cannot be smaller than the minor unit (e.g. half a cent). -- Prices can have arbitrary precision, but a price is not Money until it is rounded. -- A consequence of the precision rule is that money cannot be evenly divided into chunks (e.g. 10 USD into 3 chunks will be [3.34, 3.33, 3.33]) -- Money math and comparisons cannot be performed across currencies. A currency conversion to a common currency must take place first. +- An amount of money cannot be smaller than the minor unit (e.g. half a cent). +- Prices can have arbitrary precision, but a price is not Money until it is rounded. +- A consequence of the precision rule is that money cannot be evenly divided into chunks (e.g. 10 USD into 3 chunks will be [3.34, 3.33, 3.33]) +- Money math and comparisons cannot be performed across currencies. A currency conversion to a common currency must take place first. This library ensures that one operates on correct currencies and the correct precision for the given currency. For intermediary calculations and price it is possible to adjust the precision. @@ -185,210 +172,245 @@ big.js is quite fast and lightweight, but nowhere near the performance of native The following code takes around 0.06ms, and just the addition itself is around 0.02ms: -````ts -Money.of(Math.random(), 'NOK') - .add(Money.of(Math.random(), 'NOK')) - .toNumber() -```` +```ts +Money.of(Math.random(), "NOK").add(Money.of(Math.random(), "NOK")).toNumber(); +``` So you can do about 260 of those within a 60 fps frame, or around 800 pure additions. If we're talking larger jobs, you can do 300 million of the above in 5 minutes. ## API -````ts +```ts export type AdditionalOptions = { - decimals?: number // Override precision - roundingMode?: RoundingMode // See big.js rounding modes - tags?: Partial // Tag your money to keep track of what it represents -} + decimals?: number; // Override precision + roundingMode?: RoundingMode; // See big.js rounding modes + tags?: Partial; // Tag your money to keep track of what it represents +}; export declare class Money { - constructor(data: MoneyInputData); - - /** - * Create a money object. - * - * Amount can be any of number, string, or Big - * currency is the 3-character currency code (ISO 4217) - * currency can also be set to UNKNOWN, which gives a precision of 2 decimals. - * - * With options you can specify - * - decimals - * - roundingMode - * - tags - */ - static of(amount: NumberInput, currency: string, options?: AdditionalOptions): Money; - /** - * Instantiate from a string formatted in a certain locale. - * - * Examples: - * no-NB: 11 111,11 - * en-GB: 11,111.11 - * de-DE: 11.111,11 - * - * Before parsing, non-numeric characters are removed, and the decimal sign is normalized. - * - * Locales with unicode numbers are NOT SUPPORTED - * Example of formats NOT SUPPORTED: - * ar: ١١٬١١١٫١١ - */ - static fromLocaleString(str: string, currency: string, locale?: string, options?: AdditionalOptions): Money; - /** - * Instantiate from a whole number of minor units of the currency (e.g. whole number of cents) - * - * Example: - * Money.fromFractionlessAmount(1000, 'NOK') => 10.00 NOK - */ - static fromFractionlessAmount(amount: number, currency: string, options?: AdditionalOptions): Money; - /** - * A price has arbitrary precision. - * This method creates a Money instance with 6 decimals of precision by default. - * Remember to call .resetDecimals() when you want to go back to a proper Money value. - */ - static fromPrice(price: NumberInput, currency: string, options?: AdditionalOptions): Money; - /** - * Calculate total money according to a price and quantity. - * Default precision is 6 decimals. - */ - static fromPriceAndQuantity(price: NumberInput, quantity: Factor, currency: string, options?: AdditionalOptions): Money; - /** - * Sum an array of moneys. - * - * If the array is empty, a currency must be specified so that 0 can be returned in that currency. - * - * The precision, rounding mode, etc, is based on the first item in the array. - * If the array is empty, the options object will be used instead. - */ - static sum(moneys: Money[], currency?: string, options?: AdditionalOptions): Money; - static max(moneys: Money[]): Money; - static min(moneys: Money[]): Money; - /** - * Compare two money objects. - * - * 1 if money1 is greater than money2 - * 0 if equal - * -1 if money1 is less than money2 - * - * This can be plugged directly into array.sort(), - * and it will cause the array to be sorted in ascending order. - */ - static compare(money1: Money, money2: Money): number; - - merge: (data: Partial) => Money; - - // Tags - /** - * Tags allow you to communicate more about what the money represents. - * You can later assert on a tag to make sure you're using the right amount for the right purpose. - */ - getTags: () => Tags; - getTag: (tagName: Name, defaultValue?: Value | undefined) => Value | undefined; - setTag: (tagName: Name, value: any) => Money; - - // Assertions - assertTag: (tagName: Name, value: any, cmp?: (actual: any, value: any) => boolean) => Money; - assertSameCurrency: (money: Money) => Money; - - // Utils - amount: () => Big; - currency: () => string; - - // Converters - /** - * Converts the money amount into a whole number given in the minor unit of the currency - */ - toFractionlessAmount: () => number; - /** - * Converts to a regular javascript number. - * Throws an error if it's not possible to do keep full precision. - */ - toNumber: () => number; - toString: () => string; - toLocaleString: (locale?: string | undefined) => string; - toJSON: () => number; - - /** - * Gets the current precision in use. - */ - getDecimals: () => number; - /** - * Override the default precision of the currency. - * Useful if you're working with a price. - */ - setDecimals: (decimals: number) => Money; - /** - * Reset precision back to that of the currency. - * Useful for converting from a price to the final monetary amount. - */ - resetDecimals: () => Money; - /** - * Converts to a different currency using a currency rate. - * Sometimes (rarely) the rate is given multiplied by a certain unit amount which has to be divided away. - */ - toCurrency: (currency: string, currencyRate?: Factor, currencyUnit?: Factor) => Money; - - //Math - round: (decimals: number, roundingMode?: RoundingMode | undefined) => Money; - multiply: (factor: Factor) => Money; - /** - * Note that dividing a monetary amount cannot be exact in all cases. - * E.g. 10 NOK / 3 = 3.33 NOK - * Use `distribute` or `distributeBy` if you need an exact distribution. - * - * The division is performed with a precision of 20 decimals before - * rounding back to the monetary amount. (See https://mikemcl.github.io/big.js/#dp) - */ - divide: (divisor: Factor) => Money; - add: (money: Money) => Money; - subtract: (money: Money) => Money; - abs: () => Money; - - // Comparisons - equals: (money: Money) => boolean; - greaterThan: (money: Money) => boolean; - greaterThanOrEqual: (money: Money) => boolean; - lessThan: (money: Money) => boolean; - lessThanOrEqual: (money: Money) => boolean; - isZero: () => boolean; - /** - * Positive and not 0 - */ - isPositive: () => boolean; - /** - * Negative and not 0 - */ - isNegative: () => boolean; - - // Distribute - /** - * Divides money into n parts. - * - * Example: - * Money.of(10, 'NOK').distribute(3) => [3.34, 3.33, 3.33] - * - * Distributes any rest amount equally across the parts - */ - distribute: (nParts: number) => Money[]; - /** - * Divides money into parts, each defined by a weight. - * - * Each weight must be >= 0 - * Total of weights must be > 0 - * - * Example: - * Money.of(10, 'NOK').distributeBy([1, 1, 1]) => [3.34, 3.33, 3.33] - * - * Distributes any rest amount equally across the parts - */ - distributeBy: (inputWeights: Factor[]) => Money[]; - - // VAT - addVat: (vatPercentage: Factor) => Money; - removeVat: (vatPercentage: Factor) => Money; - getVat: (vatPercentage: Factor, includesVat?: boolean | undefined) => Money; + constructor(data: MoneyInputData); + + /** + * Create a money object. + * + * Amount can be any of number, string, or Big + * currency is the 3-character currency code (ISO 4217) + * currency can also be set to UNKNOWN, which gives a precision of 2 decimals. + * + * With options you can specify + * - decimals + * - roundingMode + * - tags + */ + static of( + amount: NumberInput, + currency: string, + options?: AdditionalOptions, + ): Money; + /** + * Instantiate from a string formatted in a certain locale. + * + * Examples: + * no-NB: 11 111,11 + * en-GB: 11,111.11 + * de-DE: 11.111,11 + * + * Before parsing, non-numeric characters are removed, and the decimal sign is normalized. + * + * Locales with unicode numbers are NOT SUPPORTED + * Example of formats NOT SUPPORTED: + * ar: ١١٬١١١٫١١ + */ + static fromLocaleString( + str: string, + currency: string, + locale?: string, + options?: AdditionalOptions, + ): Money; + /** + * Instantiate from a whole number of minor units of the currency (e.g. whole number of cents) + * + * Example: + * Money.fromFractionlessAmount(1000, 'NOK') => 10.00 NOK + */ + static fromFractionlessAmount( + amount: number, + currency: string, + options?: AdditionalOptions, + ): Money; + /** + * A price has arbitrary precision. + * This method creates a Money instance with 6 decimals of precision by default. + * Remember to call .resetDecimals() when you want to go back to a proper Money value. + */ + static fromPrice( + price: NumberInput, + currency: string, + options?: AdditionalOptions, + ): Money; + /** + * Calculate total money according to a price and quantity. + * Default precision is 6 decimals. + */ + static fromPriceAndQuantity( + price: NumberInput, + quantity: Factor, + currency: string, + options?: AdditionalOptions, + ): Money; + /** + * Sum an array of moneys. + * + * If the array is empty, a currency must be specified so that 0 can be returned in that currency. + * + * The precision, rounding mode, etc, is based on the first item in the array. + * If the array is empty, the options object will be used instead. + */ + static sum( + moneys: Money[], + currency?: string, + options?: AdditionalOptions, + ): Money; + static max(moneys: Money[]): Money; + static min(moneys: Money[]): Money; + /** + * Compare two money objects. + * + * 1 if money1 is greater than money2 + * 0 if equal + * -1 if money1 is less than money2 + * + * This can be plugged directly into array.sort(), + * and it will cause the array to be sorted in ascending order. + */ + static compare(money1: Money, money2: Money): number; + + merge: (data: Partial) => Money; + + // Tags + /** + * Tags allow you to communicate more about what the money represents. + * You can later assert on a tag to make sure you're using the right amount for the right purpose. + */ + getTags: () => Tags; + getTag: ( + tagName: Name, + defaultValue?: Value | undefined, + ) => Value | undefined; + setTag: (tagName: Name, value: any) => Money; + + // Assertions + assertTag: ( + tagName: Name, + value: any, + cmp?: (actual: any, value: any) => boolean, + ) => Money; + assertSameCurrency: (money: Money) => Money; + + // Utils + amount: () => Big; + currency: () => string; + + // Converters + /** + * Converts the money amount into a whole number given in the minor unit of the currency + */ + toFractionlessAmount: () => number; + /** + * Converts to a regular javascript number. + * Throws an error if it's not possible to do keep full precision. + */ + toNumber: () => number; + toString: () => string; + toLocaleString: (locale?: string | undefined) => string; + toJSON: () => number; + + /** + * Gets the current precision in use. + */ + getDecimals: () => number; + /** + * Override the default precision of the currency. + * Useful if you're working with a price. + */ + setDecimals: (decimals: number) => Money; + /** + * Reset precision back to that of the currency. + * Useful for converting from a price to the final monetary amount. + */ + resetDecimals: () => Money; + /** + * Converts to a different currency using a currency rate. + * Sometimes (rarely) the rate is given multiplied by a certain unit amount which has to be divided away. + */ + toCurrency: ( + currency: string, + currencyRate?: Factor, + currencyUnit?: Factor, + ) => Money; + + //Math + round: (decimals: number, roundingMode?: RoundingMode | undefined) => Money; + multiply: (factor: Factor) => Money; + /** + * Note that dividing a monetary amount cannot be exact in all cases. + * E.g. 10 NOK / 3 = 3.33 NOK + * Use `distribute` or `distributeBy` if you need an exact distribution. + * + * The division is performed with a precision of 20 decimals before + * rounding back to the monetary amount. (See https://mikemcl.github.io/big.js/#dp) + */ + divide: (divisor: Factor) => Money; + add: (money: Money) => Money; + subtract: (money: Money) => Money; + abs: () => Money; + + // Comparisons + equals: (money: Money) => boolean; + greaterThan: (money: Money) => boolean; + greaterThanOrEqual: (money: Money) => boolean; + lessThan: (money: Money) => boolean; + lessThanOrEqual: (money: Money) => boolean; + isZero: () => boolean; + /** + * Positive and not 0 + */ + isPositive: () => boolean; + /** + * Negative and not 0 + */ + isNegative: () => boolean; + + // Distribute + /** + * Divides money into n parts. + * + * Example: + * Money.of(10, 'NOK').distribute(3) => [3.34, 3.33, 3.33] + * + * Distributes any rest amount equally across the parts + */ + distribute: (nParts: number) => Money[]; + /** + * Divides money into parts, each defined by a weight. + * + * Each weight must be >= 0 + * Total of weights must be > 0 + * + * Example: + * Money.of(10, 'NOK').distributeBy([1, 1, 1]) => [3.34, 3.33, 3.33] + * + * Distributes any rest amount equally across the parts + */ + distributeBy: (inputWeights: Factor[]) => Money[]; + + // VAT + addVat: (vatPercentage: Factor) => Money; + removeVat: (vatPercentage: Factor) => Money; + getVat: (vatPercentage: Factor, includesVat?: boolean | undefined) => Money; } -```` +``` ### Creating a new release diff --git a/package.json b/package.json index 8271424..3325d50 100644 --- a/package.json +++ b/package.json @@ -1,52 +1,53 @@ { - "name": "@dintero/money", - "version": "0.0.0-development", - "description": "", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "test": "jest", - "clean": "rm -rf dist", - "check": "yarn run lint && yarn run test", - "build": "yarn run clean && yarn run check && tsc -p tsconfig.build.json", - "lint": "eslint ./src", - "semantic-release": "semantic-release", - "prepublishOnly": "yarn run build" - }, - "private": false, - "repository": { - "type": "git", - "url": "https://github.com/Dintero/money" - }, - "homepage": "https://github.com/Dintero/money", - "bugs": { - "url": "https://github.com/Dintero/money/issues" - }, - "author": "Magnus Tovslid", - "license": "MIT", - "jest": { - "preset": "ts-jest", - "testEnvironment": "node", - "testMatch": [ - "**/__tests__/**/*.test.ts" - ] - }, - "dependencies": { - "big.js": "^6.1.1", - "currency-codes": "^2.1.0" - }, - "devDependencies": { - "@semantic-release/git": "10.0.1", - "@types/big.js": "6.2.0", - "@types/jest": "29.5.5", - "@typescript-eslint/eslint-plugin": "6.7.4", - "@typescript-eslint/parser": "6.7.4", - "eslint": "8.51.0", - "eslint-config-dintero": "https://github.com/dintero/eslint-config-dintero", - "eslint-plugin-import": "2.28.1", - "jest": "29.7.0", - "semantic-release": "22.0.5", - "ts-jest": "29.1.1", - "typescript": "5.2.2" - } + "name": "@dintero/money", + "version": "0.0.0-development", + "description": "", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "test": "jest", + "clean": "rm -rf dist", + "check": "yarn run lint && yarn run test", + "build": "yarn run clean && yarn run check && tsc -p tsconfig.build.json", + "prettier": "prettier --config ./.prettierrc.yml --check --log-level warn --cache .", + "lint": "yarn prettier && eslint ./src", + "semantic-release": "semantic-release", + "prepublishOnly": "yarn run build" + }, + "private": false, + "repository": { + "type": "git", + "url": "https://github.com/Dintero/money" + }, + "homepage": "https://github.com/Dintero/money", + "bugs": { + "url": "https://github.com/Dintero/money/issues" + }, + "author": "Magnus Tovslid", + "license": "MIT", + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "testMatch": [ + "**/__tests__/**/*.test.ts" + ] + }, + "dependencies": { + "big.js": "^6.1.1", + "currency-codes": "^2.1.0" + }, + "devDependencies": { + "@semantic-release/git": "10.0.1", + "@types/big.js": "6.2.0", + "@types/jest": "29.5.5", + "@typescript-eslint/eslint-plugin": "6.7.4", + "@typescript-eslint/parser": "6.7.4", + "eslint": "8.51.0", + "eslint-config-prettier": "9.0.0", + "jest": "29.7.0", + "prettier": "3.0.3", + "semantic-release": "22.0.5", + "ts-jest": "29.1.1", + "typescript": "5.2.2" + } } diff --git a/src/__tests__/money.test.ts b/src/__tests__/money.test.ts index 80c1697..0dbc379 100644 --- a/src/__tests__/money.test.ts +++ b/src/__tests__/money.test.ts @@ -1,217 +1,329 @@ -import { Money } from '..' +import { Money } from ".."; -describe('money', () => { - it('should handle 0.1 + 0.2 = 0.3', () => { - const result = Money.of(0.1, 'NOK').add(Money.of(0.2, 'NOK')).toString() - expect(result).toBe('0.30') // Gives 0.30000000000000004 in double precision base 2 - }) +describe("money", () => { + it("should handle 0.1 + 0.2 = 0.3", () => { + const result = Money.of(0.1, "NOK") + .add(Money.of(0.2, "NOK")) + .toString(); + expect(result).toBe("0.30"); // Gives 0.30000000000000004 in double precision base 2 + }); - it('should handle multiplication where base 2 would round incorrectly', () => { - const result = Money - .of(2090.5, 'EUR') - .toCurrency('NOK', 8.61) - .toString() + it("should handle multiplication where base 2 would round incorrectly", () => { + const result = Money.of(2090.5, "EUR") + .toCurrency("NOK", 8.61) + .toString(); - expect(result).toBe('17999.21') // Gives 17999.20 in double precision base 2 - }) + expect(result).toBe("17999.21"); // Gives 17999.20 in double precision base 2 + }); - it('should convert float to correct decimal where base 2 rounds incorrectly', () => { - const result = Money.of(8.165, 'NOK').toString() + it("should convert float to correct decimal where base 2 rounds incorrectly", () => { + const result = Money.of(8.165, "NOK").toString(); - expect(result).toBe('8.17') // Gives 8.16 in double precision base 2 - }) + expect(result).toBe("8.17"); // Gives 8.16 in double precision base 2 + }); - it('should round away from zero for negative numbers', () => { - const result = Money.of(-1.5, 'UNKNOWN', { decimals: 0 }).toString() + it("should round away from zero for negative numbers", () => { + const result = Money.of(-1.5, "UNKNOWN", { decimals: 0 }).toString(); - expect(result).toBe('-2') // Math.round would give -1 here - }) + expect(result).toBe("-2"); // Math.round would give -1 here + }); - it('should round when converting to currency with less decimals', () => { - const result = Money - .of(1.56, 'NOK') - .toCurrency('JPY') - .toString() + it("should round when converting to currency with less decimals", () => { + const result = Money.of(1.56, "NOK").toCurrency("JPY").toString(); - expect(result).toBe('2') - }) + expect(result).toBe("2"); + }); - it('should keep precision when calculating total price', () => { - const result = Money.fromPriceAndQuantity(0.0005, 30, 'NOK').toString() - expect(result).toBe('0.02') - }) + it("should keep precision when calculating total price", () => { + const result = Money.fromPriceAndQuantity(0.0005, 30, "NOK").toString(); + expect(result).toBe("0.02"); + }); - it('should keep higher precision when explicitly set', () => { - const result = Money.fromPrice(0, 'NOK') - .add(Money.fromPrice(0.001, 'NOK')) + it("should keep higher precision when explicitly set", () => { + const result = Money.fromPrice(0, "NOK") + .add(Money.fromPrice(0.001, "NOK")) .multiply(60) - .toString() + .toString(); - expect(result).toBe('0.0600000000') - }) + expect(result).toBe("0.0600000000"); + }); - it('should be able to convert large numbers within double precision', () => { - Money.of('1234567891234.25', 'NOK') - .toNumber() - }) + it("should be able to convert large numbers within double precision", () => { + Money.of("1234567891234.25", "NOK").toNumber(); + }); - it('should throw when converting large numbers outside double precision', () => { + it("should throw when converting large numbers outside double precision", () => { expect(() => { - Money.of('1234567891234567.25', 'NOK') - .toNumber() - }).toThrow() - }) - - it('should distribute when parts does not add to initial amount', () => { - const parts = Money.of(1, 'NOK').distribute(3) - - expect(parts[0].toNumber()).toEqual(0.34) - expect(parts[1].toNumber()).toEqual(0.33) - expect(parts[2].toNumber()).toEqual(0.33) - }) - - it('should distribute when parts does not add to initial amount and theres more than one unit to distribute', () => { - const parts = Money.of(67, 'JPY').distribute(4) // parts are 16.75, but rounded to 17 due to JPY - - expect(parts[0].toNumber()).toEqual(16) - expect(parts[1].toNumber()).toEqual(17) - expect(parts[2].toNumber()).toEqual(17) - expect(parts[3].toNumber()).toEqual(17) - }) - - it('should distribute negative amounts', () => { - const parts = Money.of(-1, 'NOK').distribute(3) - - expect(parts[0].toNumber()).toEqual(-0.34) - expect(parts[1].toNumber()).toEqual(-0.33) - expect(parts[2].toNumber()).toEqual(-0.33) - }) - - it('should distribute when only one part can be above 0', () => { - const parts = Money.of(1, 'JPY').distribute(3) - - expect(parts[0].toNumber()).toEqual(1) - expect(parts[1].toNumber()).toEqual(0) - expect(parts[2].toNumber()).toEqual(0) - }) - - it('should distribute by weights', () => { - const parts = Money.of(1, 'NOK').distributeBy([1, 1, 1]) - - expect(parts[0].toNumber()).toEqual(0.34) - expect(parts[1].toNumber()).toEqual(0.33) - expect(parts[2].toNumber()).toEqual(0.33) - }) - - it('should distribute negative amount by weights', () => { - const parts = Money.of(-1, 'NOK').distributeBy([1, 1, 1]) - - expect(parts[0].toNumber()).toEqual(-0.34) - expect(parts[1].toNumber()).toEqual(-0.33) - expect(parts[2].toNumber()).toEqual(-0.33) - }) - - it('should distribute when one weight is 0', () => { - const parts = Money.of(-1, 'NOK').distributeBy([1, 1, 0]) - - expect(parts[0].toNumber()).toEqual(-0.5) - expect(parts[1].toNumber()).toEqual(-0.5) - expect(parts[2].toNumber()).toEqual(0) - }) - - it('should distribute by unequal weights', () => { - const parts = Money.of(11, 'NOK').distributeBy([5, 7]) - - expect(parts[0].toNumber()).toEqual(4.58) - expect(parts[1].toNumber()).toEqual(6.42) - }) - - it('should instantiate from fractionless amount', () => { - const result = Money.fromFractionlessAmount(1000, 'NOK').toString() - expect(result).toBe('10.00') - }) - - it('should print in locale', () => { - const result = Money.of(5.5, 'NOK').toLocaleString('no-NB') - expect(result).toBe('5,50') - }) - - describe('fromLocaleString', () => { + Money.of("1234567891234567.25", "NOK").toNumber(); + }).toThrow(); + }); + + it("should distribute when parts does not add to initial amount", () => { + const parts = Money.of(1, "NOK").distribute(3); + + expect(parts[0].toNumber()).toEqual(0.34); + expect(parts[1].toNumber()).toEqual(0.33); + expect(parts[2].toNumber()).toEqual(0.33); + }); + + it("should distribute when parts does not add to initial amount and theres more than one unit to distribute", () => { + const parts = Money.of(67, "JPY").distribute(4); // parts are 16.75, but rounded to 17 due to JPY + + expect(parts[0].toNumber()).toEqual(16); + expect(parts[1].toNumber()).toEqual(17); + expect(parts[2].toNumber()).toEqual(17); + expect(parts[3].toNumber()).toEqual(17); + }); + + it("should distribute negative amounts", () => { + const parts = Money.of(-1, "NOK").distribute(3); + + expect(parts[0].toNumber()).toEqual(-0.34); + expect(parts[1].toNumber()).toEqual(-0.33); + expect(parts[2].toNumber()).toEqual(-0.33); + }); + + it("should distribute when only one part can be above 0", () => { + const parts = Money.of(1, "JPY").distribute(3); + + expect(parts[0].toNumber()).toEqual(1); + expect(parts[1].toNumber()).toEqual(0); + expect(parts[2].toNumber()).toEqual(0); + }); + + it("should distribute by weights", () => { + const parts = Money.of(1, "NOK").distributeBy([1, 1, 1]); + + expect(parts[0].toNumber()).toEqual(0.34); + expect(parts[1].toNumber()).toEqual(0.33); + expect(parts[2].toNumber()).toEqual(0.33); + }); + + it("should distribute negative amount by weights", () => { + const parts = Money.of(-1, "NOK").distributeBy([1, 1, 1]); + + expect(parts[0].toNumber()).toEqual(-0.34); + expect(parts[1].toNumber()).toEqual(-0.33); + expect(parts[2].toNumber()).toEqual(-0.33); + }); + + it("should distribute when one weight is 0", () => { + const parts = Money.of(-1, "NOK").distributeBy([1, 1, 0]); + + expect(parts[0].toNumber()).toEqual(-0.5); + expect(parts[1].toNumber()).toEqual(-0.5); + expect(parts[2].toNumber()).toEqual(0); + }); + + it("should distribute by unequal weights", () => { + const parts = Money.of(11, "NOK").distributeBy([5, 7]); + + expect(parts[0].toNumber()).toEqual(4.58); + expect(parts[1].toNumber()).toEqual(6.42); + }); + + it("should instantiate from fractionless amount", () => { + const result = Money.fromFractionlessAmount(1000, "NOK").toString(); + expect(result).toBe("10.00"); + }); + + it("should print in locale", () => { + const result = Money.of(5.5, "NOK").toLocaleString("no-NB"); + expect(result).toBe("5,50"); + }); + + describe("fromLocaleString", () => { [ - { locale: 'no-NB', currency: 'NOK', fromStr: '11 111,11', toStr: '11111.11' }, - { locale: 'no-NB', currency: 'NOK', fromStr: '11 111,11kr', toStr: '11111.11' }, - { locale: 'no-NB', currency: 'NOK', fromStr: '11 111,11NOK', toStr: '11111.11' }, - { locale: 'no-NB', currency: 'NOK', fromStr: '11 111,11 NOK', toStr: '11111.11' }, - { locale: 'no-NB', currency: 'NOK', fromStr: 'NOK 11 111,11', toStr: '11111.11' }, - { locale: 'no-NB', currency: 'NOK', fromStr: '11 111', toStr: '11111.00' }, - { locale: 'no-NB', currency: 'NOK', fromStr: '-11 111,11', toStr: '-11111.11' }, - { locale: 'en-GB', currency: 'GBP', fromStr: '11,111.11', toStr: '11111.11' }, - { locale: 'en-GB', currency: 'GBP', fromStr: '-11,111.11', toStr: '-11111.11' }, - { locale: 'en-GB', currency: 'GBP', fromStr: '-£11,111.11', toStr: '-11111.11' }, - { locale: 'en-GB', currency: 'GBP', fromStr: '£-11,111.11', toStr: '-11111.11' }, - { locale: 'de-DE', currency: 'EUR', fromStr: '11.111,11', toStr: '11111.11' }, - { locale: 'de-DE', currency: 'EUR', fromStr: '-11.111,11', toStr: '-11111.11' }, - { locale: 'en-US', currency: 'USD', fromStr: '11,111.11', toStr: '11111.11' }, - { locale: 'en-US', currency: 'USD', fromStr: '-11,111.11', toStr: '-11111.11' }, - { locale: 'en-US', currency: 'USD', fromStr: '-$11,111.11', toStr: '-11111.11' }, - { locale: 'en-US', currency: 'USD', fromStr: '$-11,111.11', toStr: '-11111.11' }, - { locale: 'en-US', currency: 'USD', fromStr: '$11,111.11', toStr: '11111.11' }, - { locale: 'en-US', currency: 'USD', fromStr: '$11,111', toStr: '11111.00' }, - { locale: 'en-US', currency: 'USD', fromStr: '$-11,111', toStr: '-11111.00' }, - { locale: 'en-US', currency: 'USD', fromStr: '-$11,111', toStr: '-11111.00' }, - { locale: 'en-US', currency: 'USD', fromStr: '-$11,111 US dollars', toStr: '-11111.00' }, + { + locale: "no-NB", + currency: "NOK", + fromStr: "11 111,11", + toStr: "11111.11", + }, + { + locale: "no-NB", + currency: "NOK", + fromStr: "11 111,11kr", + toStr: "11111.11", + }, + { + locale: "no-NB", + currency: "NOK", + fromStr: "11 111,11NOK", + toStr: "11111.11", + }, + { + locale: "no-NB", + currency: "NOK", + fromStr: "11 111,11 NOK", + toStr: "11111.11", + }, + { + locale: "no-NB", + currency: "NOK", + fromStr: "NOK 11 111,11", + toStr: "11111.11", + }, + { + locale: "no-NB", + currency: "NOK", + fromStr: "11 111", + toStr: "11111.00", + }, + { + locale: "no-NB", + currency: "NOK", + fromStr: "-11 111,11", + toStr: "-11111.11", + }, + { + locale: "en-GB", + currency: "GBP", + fromStr: "11,111.11", + toStr: "11111.11", + }, + { + locale: "en-GB", + currency: "GBP", + fromStr: "-11,111.11", + toStr: "-11111.11", + }, + { + locale: "en-GB", + currency: "GBP", + fromStr: "-£11,111.11", + toStr: "-11111.11", + }, + { + locale: "en-GB", + currency: "GBP", + fromStr: "£-11,111.11", + toStr: "-11111.11", + }, + { + locale: "de-DE", + currency: "EUR", + fromStr: "11.111,11", + toStr: "11111.11", + }, + { + locale: "de-DE", + currency: "EUR", + fromStr: "-11.111,11", + toStr: "-11111.11", + }, + { + locale: "en-US", + currency: "USD", + fromStr: "11,111.11", + toStr: "11111.11", + }, + { + locale: "en-US", + currency: "USD", + fromStr: "-11,111.11", + toStr: "-11111.11", + }, + { + locale: "en-US", + currency: "USD", + fromStr: "-$11,111.11", + toStr: "-11111.11", + }, + { + locale: "en-US", + currency: "USD", + fromStr: "$-11,111.11", + toStr: "-11111.11", + }, + { + locale: "en-US", + currency: "USD", + fromStr: "$11,111.11", + toStr: "11111.11", + }, + { + locale: "en-US", + currency: "USD", + fromStr: "$11,111", + toStr: "11111.00", + }, + { + locale: "en-US", + currency: "USD", + fromStr: "$-11,111", + toStr: "-11111.00", + }, + { + locale: "en-US", + currency: "USD", + fromStr: "-$11,111", + toStr: "-11111.00", + }, + { + locale: "en-US", + currency: "USD", + fromStr: "-$11,111 US dollars", + toStr: "-11111.00", + }, ].forEach(({ locale, currency, fromStr, toStr }) => { it(`should parse (${locale} ${currency}) ${fromStr}`, () => { - const result = Money.fromLocaleString(fromStr, currency, locale).toString() - expect(result).toBe(toStr) - }) - }) - }) - - it('should add vat', () => { - const result = Money.of(10, 'NOK').addVat(25).toString() - expect(result).toBe('12.50') - }) - - it('should remove vat', () => { - const result = Money.of(12.5, 'NOK').removeVat(25).toString() - expect(result).toBe('10.00') - }) - - it('should calculate vat when amount includes vat', () => { - const result = Money.of(12.5, 'NOK').getVat(25, true).toString() - expect(result).toBe('2.50') - }) - - it('should calculate vat when amount does not include vat', () => { - const result = Money.of(10, 'NOK').getVat(25, false).toString() - expect(result).toBe('2.50') - }) - - it('should test complex performance', () => { - const N = 1000 - const start = new Date().getTime() + const result = Money.fromLocaleString( + fromStr, + currency, + locale, + ).toString(); + expect(result).toBe(toStr); + }); + }); + }); + + it("should add vat", () => { + const result = Money.of(10, "NOK").addVat(25).toString(); + expect(result).toBe("12.50"); + }); + + it("should remove vat", () => { + const result = Money.of(12.5, "NOK").removeVat(25).toString(); + expect(result).toBe("10.00"); + }); + + it("should calculate vat when amount includes vat", () => { + const result = Money.of(12.5, "NOK").getVat(25, true).toString(); + expect(result).toBe("2.50"); + }); + + it("should calculate vat when amount does not include vat", () => { + const result = Money.of(10, "NOK").getVat(25, false).toString(); + expect(result).toBe("2.50"); + }); + + it("should test complex performance", () => { + const N = 1000; + const start = new Date().getTime(); for (let i = 0; i < N; i++) { - Money.of(Math.random(), 'NOK').add(Money.of(Math.random(), 'NOK')).toNumber() + Money.of(Math.random(), "NOK") + .add(Money.of(Math.random(), "NOK")) + .toNumber(); } - const end = new Date().getTime() + const end = new Date().getTime(); - console.log('Complex performance', (end - start)/N, 'ms') - }) + console.log("Complex performance", (end - start) / N, "ms"); + }); - it('should test addition performance', () => { - const N = 1000 - const a = Money.of(Math.random(), 'NOK') - const b = Money.of(Math.random(), 'NOK') + it("should test addition performance", () => { + const N = 1000; + const a = Money.of(Math.random(), "NOK"); + const b = Money.of(Math.random(), "NOK"); - const start = new Date().getTime() + const start = new Date().getTime(); for (let i = 0; i < N; i++) { - a.add(b) + a.add(b); } - const end = new Date().getTime() + const end = new Date().getTime(); - console.log('Addition performance', (end - start)/N, 'ms') - }) -}) + console.log("Addition performance", (end - start) / N, "ms"); + }); +}); diff --git a/src/index.ts b/src/index.ts index 3006c94..a983806 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,66 +1,71 @@ -import Big, { RoundingMode } from 'big.js' -import cc from 'currency-codes' +import type { RoundingMode } from "big.js"; +import Big from "big.js"; +import cc from "currency-codes"; -type NumberInput = number | string | Big -type Factor = number | Big +type NumberInput = number | string | Big; +type Factor = number | Big; type Tags = { - includesVat: boolean - isVat: boolean - [key: string]: any -} + includesVat: boolean; + isVat: boolean; + [key: string]: any; +}; export type AdditionalOptions = { - decimals?: number - roundingMode?: RoundingMode - tags?: Partial -} + decimals?: number; + roundingMode?: RoundingMode; + tags?: Partial; +}; export type MoneyInputData = { - amount: NumberInput - currency: string - decimals?: number - roundingMode?: RoundingMode - tags?: Partial -} + amount: NumberInput; + currency: string; + decimals?: number; + roundingMode?: RoundingMode; + tags?: Partial; +}; type MoneyData = { - amount: Big - currency: string - decimals?: number - roundingMode?: RoundingMode - tags: Tags -} + amount: Big; + currency: string; + decimals?: number; + roundingMode?: RoundingMode; + tags: Tags; +}; -const DEFAULT_DECIMALS_PRICE = 10 +const DEFAULT_DECIMALS_PRICE = 10; const currencyToDecimals = (currency: string): number => { - const decimals = cc.code(currency)?.digits + const decimals = cc.code(currency)?.digits; if (decimals === undefined) { - if (currency === 'UNKNOWN') { - return 2 + if (currency === "UNKNOWN") { + return 2; } - throw new Error(`Currency ${currency} is not supported`) + throw new Error(`Currency ${currency} is not supported`); } - return decimals -} + return decimals; +}; -const percentToMultiplier = (percent: Factor): Big => Big(percent).add(100).div(100) -const percentToRate = (percent: Factor): Big => Big(percent).div(100) +const percentToMultiplier = (percent: Factor): Big => + Big(percent).add(100).div(100); +const percentToRate = (percent: Factor): Big => Big(percent).div(100); -const escapeRegex = (str: string) => str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') +const escapeRegex = (str: string) => + str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); export class Money { - private readonly _data: MoneyData + private readonly _data: MoneyData; constructor(data: MoneyInputData) { if (data.amount === undefined) { - throw new Error('Amount is undefined. Needs to be number, string, or Big') + throw new Error( + "Amount is undefined. Needs to be number, string, or Big", + ); } - const currency = data.currency - const decimals = data.decimals ?? currencyToDecimals(currency) - const amount = new Big(data.amount) + const currency = data.currency; + const decimals = data.decimals ?? currencyToDecimals(currency); + const amount = new Big(data.amount); this._data = { amount: amount.round(decimals, data.roundingMode), @@ -71,12 +76,12 @@ export class Money { includesVat: false, isPrice: false, isVat: false, - ...data.tags - } - } + ...data.tags, + }, + }; - Object.freeze(this) - Object.freeze(this._data) + Object.freeze(this); + Object.freeze(this._data); } /** @@ -91,8 +96,12 @@ export class Money { * - roundingMode * - tags */ - static of(amount: NumberInput, currency: string, options?: AdditionalOptions): Money { - return new Money({ amount, currency, ...options }) + static of( + amount: NumberInput, + currency: string, + options?: AdditionalOptions, + ): Money { + return new Money({ amount, currency, ...options }); } /** @@ -109,15 +118,21 @@ export class Money { * Example of formats NOT SUPPORTED: * ar: ١١٬١١١٫١١ */ - static fromLocaleString(str: string, currency: string, locale?: string, options?: AdditionalOptions): Money { - const parts = Intl.NumberFormat(locale).formatToParts(11111.11) - const decimalSign = parts.find(p => p.type === 'decimal')?.value ?? '.' + static fromLocaleString( + str: string, + currency: string, + locale?: string, + options?: AdditionalOptions, + ): Money { + const parts = Intl.NumberFormat(locale).formatToParts(11111.11); + const decimalSign = + parts.find((p) => p.type === "decimal")?.value ?? "."; str = str - .replace(new RegExp(`[^-\\d${escapeRegex(decimalSign)}]`, 'g'), '') - .replace(decimalSign, '.') + .replace(new RegExp(`[^-\\d${escapeRegex(decimalSign)}]`, "g"), "") + .replace(decimalSign, "."); - return Money.of(str, currency, options) + return Money.of(str, currency, options); } /** @@ -126,8 +141,14 @@ export class Money { * Example: * Money.fromFractionlessAmount(1000, 'NOK') => 10.00 NOK */ - static fromFractionlessAmount(amount: number, currency: string, options?: AdditionalOptions): Money { - return Money.of(amount, currency, options).divide(10**currencyToDecimals(currency)) + static fromFractionlessAmount( + amount: number, + currency: string, + options?: AdditionalOptions, + ): Money { + return Money.of(amount, currency, options).divide( + 10 ** currencyToDecimals(currency), + ); } /** @@ -135,18 +156,30 @@ export class Money { * This method creates a Money instance with 10 decimals of precision by default. * Remember to call .resetDecimals() when you want to go back to a proper Money value. */ - static fromPrice(price: NumberInput, currency: string, options?: AdditionalOptions): Money { - return Money.of(price, currency, { decimals: DEFAULT_DECIMALS_PRICE, ...options }) + static fromPrice( + price: NumberInput, + currency: string, + options?: AdditionalOptions, + ): Money { + return Money.of(price, currency, { + decimals: DEFAULT_DECIMALS_PRICE, + ...options, + }); } /** * Calculate total money according to a price and quantity. * Default precision is 10 decimals. */ - static fromPriceAndQuantity(price: NumberInput, quantity: Factor, currency: string, options?: AdditionalOptions): Money { + static fromPriceAndQuantity( + price: NumberInput, + quantity: Factor, + currency: string, + options?: AdditionalOptions, + ): Money { return Money.fromPrice(price, currency, options) .multiply(quantity) - .resetDecimals() + .resetDecimals(); } /** @@ -157,32 +190,46 @@ export class Money { * The precision, rounding mode, etc, is based on the first item in the array. * If the array is empty, the options object will be used instead. */ - static sum(moneys: Money[], currency?: string, options?: AdditionalOptions): Money { + static sum( + moneys: Money[], + currency?: string, + options?: AdditionalOptions, + ): Money { if (moneys.length === 0 && currency === undefined) { - throw new Error('Currency must be set when summing an empty list of money\'s') + throw new Error( + "Currency must be set when summing an empty list of money's", + ); } - currency = currency ?? moneys[0].currency() + currency = currency ?? moneys[0].currency(); if (moneys.length === 0) { - return Money.of(0, currency, options) + return Money.of(0, currency, options); } - return moneys.slice(1).reduce((sum, money) => sum.add(money), moneys[0]) + return moneys + .slice(1) + .reduce((sum, money) => sum.add(money), moneys[0]); } static max(moneys: Money[]): Money { if (moneys.length === 0) { - throw new Error('Need at least one money for comparison') + throw new Error("Need at least one money for comparison"); } - return moneys.reduce((max, money) => money.greaterThan(max) ? money : max, moneys[0]) + return moneys.reduce( + (max, money) => (money.greaterThan(max) ? money : max), + moneys[0], + ); } static min(moneys: Money[]): Money { if (moneys.length === 0) { - throw new Error('Need at least one money for comparison') + throw new Error("Need at least one money for comparison"); } - return moneys.reduce((min, money) => money.lessThan(min) ? money : min, moneys[0]) + return moneys.reduce( + (min, money) => (money.lessThan(min) ? money : min), + moneys[0], + ); } /** @@ -196,62 +243,73 @@ export class Money { * and it will cause the array to be sorted in ascending order. */ static compare(money1: Money, money2: Money): number { - money1.assertSameCurrency(money2) - return money1.amount().cmp(money2.amount()) + money1.assertSameCurrency(money2); + return money1.amount().cmp(money2.amount()); } merge = (data: Partial): Money => { - return new Money({ ...this._data, ...data }) - } + return new Money({ ...this._data, ...data }); + }; /** * Tags allow you to communicate more about what the money represents. * You can later assert on a tag to make sure you're using the right amount for the right purpose. */ getTags = () => { - return this._data.tags - } + return this._data.tags; + }; - getTag = (tagName: Name, defaultValue?: Value): Value | undefined => { - return this._data.tags?.[tagName] ?? defaultValue - } + getTag = ( + tagName: Name, + defaultValue?: Value, + ): Value | undefined => { + return this._data.tags?.[tagName] ?? defaultValue; + }; setTag = (tagName: Name, value: any): Money => { - return new Money({ ...this._data, tags: { ...this._data.tags, [tagName]: value } }) - } - - assertTag = (tagName: Name, value: any, cmp = (actual: any, value: any) => actual === value): Money => { - const actualValue = this.getTag(tagName, undefined) + return new Money({ + ...this._data, + tags: { ...this._data.tags, [tagName]: value }, + }); + }; + + assertTag = ( + tagName: Name, + value: any, + cmp = (actual: any, value: any) => actual === value, + ): Money => { + const actualValue = this.getTag(tagName, undefined); if (!cmp(actualValue, value)) { - throw new Error(`Tag assertion failed. ${tagName} should be ${value} but was ${actualValue}`) + throw new Error( + `Tag assertion failed. ${tagName} should be ${value} but was ${actualValue}`, + ); } - return this - } + return this; + }; assertSameCurrency = (money: Money): Money => { if (money.currency() !== this.currency()) { - throw new Error('Currencies must be the same') + throw new Error("Currencies must be the same"); } - return this - } + return this; + }; amount = (): Big => { - return this._data.amount - } + return this._data.amount; + }; currency = (): string => { - return this._data.currency - } + return this._data.currency; + }; /** * Converts the money amount into a whole number given in the minor unit of the currency */ toFractionlessAmount = (): number => { - return this - .multiply(10**currencyToDecimals(this.currency())) + return this.multiply(10 ** currencyToDecimals(this.currency())) .round(0) - .toNumber() - } + .toNumber(); + }; /** * Converts to a regular javascript number. @@ -259,74 +317,81 @@ export class Money { */ toNumber = (): number => { // Don't use big.js toNumber because it sometimes returns -0. - const str = this.toString() - const num = Number(str) + const str = this.toString(); + const num = Number(str); if (str !== this.merge({ amount: num }).toString()) { - throw new Error('Converting to number was imprecise') + throw new Error("Converting to number was imprecise"); } - return num - } + return num; + }; toString = (): string => { - return this._data.amount.toFixed(this.getDecimals()) - } + return this._data.amount.toFixed(this.getDecimals()); + }; toLocaleString = (locale?: string): string => { - const decimals = this.getDecimals() + const decimals = this.getDecimals(); return Intl.NumberFormat(locale, { minimumFractionDigits: decimals, - maximumFractionDigits: decimals - }).format(this.toNumber()) - } + maximumFractionDigits: decimals, + }).format(this.toNumber()); + }; toJSON = (): number => { - return this.toNumber() - } + return this.toNumber(); + }; /** * Gets the current precision in use. */ getDecimals = (): number => { - return this._data.decimals ?? currencyToDecimals(this.currency()) - } + return this._data.decimals ?? currencyToDecimals(this.currency()); + }; /** * Override the default precision of the currency. * Useful if you're working with a price. */ setDecimals = (decimals: number): Money => { - return this.merge({ decimals }) - } + return this.merge({ decimals }); + }; /** * Reset precision back to that of the currency. * Useful for converting from a price to the final monetary amount. */ resetDecimals = (): Money => { - return this.merge({ decimals: undefined }) - } + return this.merge({ decimals: undefined }); + }; /** * Converts to a different currency using a currency rate. * Sometimes (rarely) the rate is given multiplied by a certain unit amount which has to be divided away. */ - toCurrency = (currency: string, currencyRate: Factor = 1, currencyUnit: Factor = 1): Money => { + toCurrency = ( + currency: string, + currencyRate: Factor = 1, + currencyUnit: Factor = 1, + ): Money => { // Convert currency outside of Money to avoid wrong precision for the new currency. - const amount = this.amount().mul(currencyRate).div(currencyUnit) - return new Money({ ...this._data, amount, currency }) - } + const amount = this.amount().mul(currencyRate).div(currencyUnit); + return new Money({ ...this._data, amount, currency }); + }; round = (decimals: number, roundingMode?: RoundingMode): Money => { - const amount = this.amount().round(decimals, roundingMode ?? this._data.roundingMode) - return this.merge({ amount }) - } + const amount = this.amount().round( + decimals, + roundingMode ?? this._data.roundingMode, + ); + return this.merge({ amount }); + }; multiply = (factor: Factor): Money => { - const amount = this.amount().mul(factor) - return this.merge({ amount }) - } + const amount = this.amount().mul(factor); + return this.merge({ amount }); + }; /** * Note that dividing a monetary amount cannot be exact in all cases. @@ -337,64 +402,67 @@ export class Money { * rounding back to the monetary amount. (See https://mikemcl.github.io/big.js/#dp) */ divide = (divisor: Factor): Money => { - return this.merge({ amount: this.amount().div(divisor) }) - } + return this.merge({ amount: this.amount().div(divisor) }); + }; add = (money: Money): Money => { - this.assertSameCurrency(money) - return this.merge({ amount: this.amount().plus(money.amount()) }) - } + this.assertSameCurrency(money); + return this.merge({ amount: this.amount().plus(money.amount()) }); + }; subtract = (money: Money): Money => { - this.assertSameCurrency(money) - return this.merge({ amount: this.amount().minus(money.amount()) }) - } + this.assertSameCurrency(money); + return this.merge({ amount: this.amount().minus(money.amount()) }); + }; abs = (): Money => { - return this.merge({ amount: this.amount().abs() }) - } + return this.merge({ amount: this.amount().abs() }); + }; equals = (money: Money): boolean => { - return this._data.currency === money._data.currency && this.amount().eq(money.amount()) - } + return ( + this._data.currency === money._data.currency && + this.amount().eq(money.amount()) + ); + }; greaterThan = (money: Money): boolean => { - this.assertSameCurrency(money) - return this.amount().gt(money.amount()) - } + this.assertSameCurrency(money); + return this.amount().gt(money.amount()); + }; greaterThanOrEqual = (money: Money): boolean => { - this.assertSameCurrency(money) - return this.amount().gte(money.amount()) - } + this.assertSameCurrency(money); + return this.amount().gte(money.amount()); + }; lessThan = (money: Money): boolean => { - this.assertSameCurrency(money) - return this.amount().lt(money.amount()) - } + this.assertSameCurrency(money); + return this.amount().lt(money.amount()); + }; lessThanOrEqual = (money: Money): boolean => { - this.assertSameCurrency(money) - return this.amount().lte(money.amount()) - } + this.assertSameCurrency(money); + return this.amount().lte(money.amount()); + }; isZero = (): boolean => { - return this.amount().eq(0) - } + return this.amount().eq(0); + }; /** * Positive and not 0 */ isPositive = (): boolean => { - return this.amount().gt(0) - } + return this.amount().gt(0); + }; /** * Negative and not 0 */ isNegative = (): boolean => { - return this.amount().lt(0) - } + return this.amount().lt(0); + }; /** * Divides money into n parts. @@ -406,11 +474,11 @@ export class Money { */ distribute = (nParts: number): Money[] => { if (nParts !== Math.round(nParts)) { - throw new Error('Number of parts must be a whole number') + throw new Error("Number of parts must be a whole number"); } - return this.distributeBy(Array(nParts).fill(1)) - } + return this.distributeBy(Array(nParts).fill(1)); + }; /** * Divides money into parts, each defined by a weight. @@ -424,27 +492,30 @@ export class Money { * Distributes any rest amount equally across the parts */ distributeBy = (inputWeights: Factor[]): Money[] => { - const weights = inputWeights.map(w => Big(w)) - if (weights.some(w => w.lt(0))) { - throw new Error('Cannot distribute by negative weights') + const weights = inputWeights.map((w) => Big(w)); + if (weights.some((w) => w.lt(0))) { + throw new Error("Cannot distribute by negative weights"); } - const totalWeight = weights.reduce((a, b) => a.add(b), new Big(0)) + const totalWeight = weights.reduce((a, b) => a.add(b), new Big(0)); if (totalWeight.lte(0)) { - throw new Error('Total weight must be greater than 0') + throw new Error("Total weight must be greater than 0"); } - const parts = weights.map(weight => this.multiply(weight.div(totalWeight))) - let rest = this.subtract(Money.sum(parts, this.currency())) + const parts = weights.map((weight) => + this.multiply(weight.div(totalWeight)), + ); + let rest = this.subtract(Money.sum(parts, this.currency())); - const smallestUnit = this.merge({ amount: 1 }).divide(10**this.getDecimals()) - .multiply(rest.isPositive() ? 1 : -1) + const smallestUnit = this.merge({ amount: 1 }) + .divide(10 ** this.getDecimals()) + .multiply(rest.isPositive() ? 1 : -1); - let i = 0 + let i = 0; while (!rest.isZero()) { - parts[i] = parts[i].add(smallestUnit) - rest = rest.subtract(smallestUnit) - i++ + parts[i] = parts[i].add(smallestUnit); + rest = rest.subtract(smallestUnit); + i++; } /* @@ -476,21 +547,30 @@ export class Money { * So we see that it will be enough we just one iteration through parts. */ - return parts - } + return parts; + }; addVat = (vatPercentage: Factor): Money => { - return this.multiply(percentToMultiplier(vatPercentage)).setTag('includesVat', true) - } + return this.multiply(percentToMultiplier(vatPercentage)).setTag( + "includesVat", + true, + ); + }; removeVat = (vatPercentage: Factor): Money => { - return this.divide(percentToMultiplier(vatPercentage)).setTag('includesVat', false) - } + return this.divide(percentToMultiplier(vatPercentage)).setTag( + "includesVat", + false, + ); + }; getVat = (vatPercentage: Factor, includesVat?: boolean): Money => { - const withoutVat = (includesVat ?? this.getTag('includesVat', false)) - ? this.removeVat(vatPercentage) - : this - return withoutVat.multiply(percentToRate(vatPercentage)).setTag('isVat', true) - } + const withoutVat = + includesVat ?? this.getTag("includesVat", false) + ? this.removeVat(vatPercentage) + : this; + return withoutVat + .multiply(percentToRate(vatPercentage)) + .setTag("isVat", true); + }; } diff --git a/yarn.lock b/yarn.lock index 059e6c0..0d3f9cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1245,11 +1245,6 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - "@types/node@*": version "16.9.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.0.tgz#d9512fe037472dcb58931ce19f837348db828a62" @@ -1563,83 +1558,16 @@ argv-formatter@~1.0.0: resolved "https://registry.yarnpkg.com/argv-formatter/-/argv-formatter-1.0.0.tgz#a0ca0cbc29a5b73e836eebe1cbf6c5e0e4eb82f9" integrity sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw== -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== - dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" - array-ify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== -array-includes@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - is-string "^1.0.7" - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.findlastindex@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz#bc229aef98f6bd0533a2bc61ff95209875526c9b" - integrity sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - get-intrinsic "^1.1.3" - -array.prototype.flat@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" - integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" - integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - -arraybuffer.prototype.slice@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz#9b5ea3868a6eebc30273da577eb888381c0044bb" - integrity sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw== - dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.0" - get-intrinsic "^1.2.1" - is-array-buffer "^3.0.2" - is-shared-array-buffer "^1.0.2" - -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -1842,14 +1770,6 @@ cacache@^18.0.0: tar "^6.1.11" unique-filename "^3.0.0" -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -2170,13 +2090,6 @@ debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, d dependencies: ms "2.1.2" -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - dedent@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" @@ -2204,29 +2117,6 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-properties@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -define-properties@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" - integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -2264,13 +2154,6 @@ dir-glob@^3.0.0, dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -2354,115 +2237,6 @@ error-ex@^1.3.1, error-ex@^1.3.2: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" - integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - internal-slot "^1.0.4" - is-array-buffer "^3.0.1" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.10" - is-weakref "^1.0.2" - object-inspect "^1.12.2" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - safe-regex-test "^1.0.0" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.9" - -es-abstract@^1.21.2: - version "1.22.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" - integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw== - dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.1" - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.2.1" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.10" - is-weakref "^1.0.2" - object-inspect "^1.12.3" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.0" - safe-array-concat "^1.0.0" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.7" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.10" - -es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== - dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - has-tostringtag "^1.0.0" - -es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== - dependencies: - has "^1.0.3" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -2488,48 +2262,10 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -"eslint-config-dintero@https://github.com/dintero/eslint-config-dintero": - version "1.1.1" - resolved "https://github.com/dintero/eslint-config-dintero#cf259e28ac6ca2f4e2468d8be5b906d965435c10" - -eslint-import-resolver-node@^0.3.7: - version "0.3.7" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" - integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== - dependencies: - debug "^3.2.7" - is-core-module "^2.11.0" - resolve "^1.22.1" - -eslint-module-utils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== - dependencies: - debug "^3.2.7" - -eslint-plugin-import@2.28.1: - version "2.28.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4" - integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A== - dependencies: - array-includes "^3.1.6" - array.prototype.findlastindex "^1.2.2" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" - debug "^3.2.7" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" - eslint-module-utils "^2.8.0" - has "^1.0.3" - is-core-module "^2.13.0" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.fromentries "^2.0.6" - object.groupby "^1.0.0" - object.values "^1.1.6" - semver "^6.3.1" - tsconfig-paths "^3.14.2" +eslint-config-prettier@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz#eb25485946dd0c66cd216a46232dc05451518d1f" + integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw== eslint-scope@^7.2.2: version "7.2.2" @@ -2816,13 +2552,6 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - foreground-child@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" @@ -2884,21 +2613,6 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" - -functions-have-names@^1.2.2, functions-have-names@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - gauge@^4.0.3: version "4.0.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" @@ -2937,34 +2651,6 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-intrinsic@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" - integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" - -get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-proto "^1.0.1" - has-symbols "^1.0.3" - get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -2985,14 +2671,6 @@ get-stream@^8.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - git-log-parser@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/git-log-parser/-/git-log-parser-1.2.0.tgz#2e6a4c1b13fc00028207ba795a7ac31667b9fd4a" @@ -3065,13 +2743,6 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" -globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== - dependencies: - define-properties "^1.1.3" - globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -3095,13 +2766,6 @@ globby@^13.1.4: merge2 "^1.4.1" slash "^4.0.0" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - graceful-fs@4.2.10: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -3129,16 +2793,6 @@ handlebars@^4.7.7: optionalDependencies: uglify-js "^3.1.4" -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -3149,35 +2803,6 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== - -has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - -has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -3373,24 +2998,6 @@ init-package-json@^6.0.0: validate-npm-package-license "^3.0.4" validate-npm-package-name "^5.0.0" -internal-slot@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.4.tgz#8551e7baf74a7a6ba5f749cfb16aa60722f0d6f3" - integrity sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ== - dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - side-channel "^1.0.4" - -internal-slot@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== - dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" - side-channel "^1.0.4" - into-stream@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-7.0.0.tgz#d1a211e146be8acfdb84dabcbf00fe8205e72936" @@ -3409,54 +3016,11 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== -is-array-buffer@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.1.tgz#deb1db4fcae48308d54ef2442706c0393997052a" - integrity sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-typed-array "^1.1.10" - -is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" - is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-callable@^1.1.3, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-callable@^1.1.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - is-cidr@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-4.0.2.tgz#94c7585e4c6c77ceabf920f8cde51b8c0fda8814" @@ -3464,20 +3028,13 @@ is-cidr@^4.0.2: dependencies: cidr-regex "^3.1.1" -is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.8.1, is-core-module@^2.9.0: +is-core-module@^2.8.1, is-core-module@^2.9.0: version "2.13.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== dependencies: has "^1.0.3" -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -3505,18 +3062,6 @@ is-lambda@^1.0.1: resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-number-object@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== - dependencies: - has-tostringtag "^1.0.0" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -3537,21 +3082,6 @@ is-plain-object@^5.0.0: resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" @@ -3562,20 +3092,6 @@ is-stream@^3.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - is-text-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-2.0.0.tgz#b2484e2b720a633feb2e85b67dc193ff72c75636" @@ -3583,34 +3099,11 @@ is-text-path@^2.0.0: dependencies: text-extensions "^2.0.0" -is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.10" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-unicode-supported@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714" integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -4139,13 +3632,6 @@ json-stringify-safe@^5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" @@ -4555,7 +4041,7 @@ minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.6: +minimist@^1.2.0: version "1.2.7" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== @@ -4652,7 +4138,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1, ms@^2.1.2: +ms@^2.0.0, ms@^2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -4960,59 +4446,6 @@ nub@~0.0.0: resolved "https://registry.yarnpkg.com/nub/-/nub-0.0.0.tgz#b369bd32bdde66af59605c3b0520bc219dccc04f" integrity sha1-s2m9Mr3eZq9ZYFw7BSC8IZ3MwE8= -object-inspect@^1.12.2, object-inspect@^1.12.3: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - -object-inspect@^1.9.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" - integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.fromentries@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" - integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.groupby@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.0.tgz#cb29259cf90f37e7bac6437686c1ea8c916d12a9" - integrity sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.21.2" - get-intrinsic "^1.2.1" - -object.values@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" - integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - once@^1.3.0, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -5323,6 +4756,11 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +prettier@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" + integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== + pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" @@ -5514,24 +4952,6 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" -regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" - -regexp.prototype.flags@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" - integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - functions-have-names "^1.2.3" - registry-auth-token@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-5.0.2.tgz#8b026cc507c8552ebbe06724136267e63302f756" @@ -5566,7 +4986,7 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.20.0, resolve@^1.22.1: +resolve@^1.20.0: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -5599,16 +5019,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-array-concat@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.0.tgz#2064223cba3c08d2ee05148eedbc563cd6d84060" - integrity sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.0" - has-symbols "^1.0.3" - isarray "^2.0.5" - safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -5619,15 +5029,6 @@ safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-regex "^1.1.4" - "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -5708,15 +5109,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - signal-exit@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -5939,33 +5331,6 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.trim@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" - integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -6173,16 +5538,6 @@ ts-jest@29.1.1: semver "^7.5.3" yargs-parser "^21.0.1" -tsconfig-paths@^3.14.2: - version "3.14.2" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" - integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.2" - minimist "^1.2.6" - strip-bom "^3.0.0" - tuf-js@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tuf-js/-/tuf-js-2.1.0.tgz#87aa36d5a166e7522f1e2050eb502a3a9b0bde72" @@ -6229,45 +5584,6 @@ type-fest@^3.0.0, type-fest@^3.12.0, type-fest@^3.8.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.13.1.tgz#bb744c1f0678bea7543a2d1ec24e83e68e8c8706" integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g== -typed-array-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" - integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - is-typed-array "^1.1.10" - -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - is-typed-array "^1.1.9" - typescript@5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" @@ -6278,16 +5594,6 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - unicode-emoji-modifier-base@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz#dbbd5b54ba30f287e2a8d5a249da6c0cef369459" @@ -6392,40 +5698,6 @@ wcwidth@^1.0.0: dependencies: defaults "^1.0.3" -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-typed-array@^1.1.10: - version "1.1.11" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" - integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - -which-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" - which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"