diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index f82c093..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,34 +0,0 @@ -/** @type {import("eslint").Linter.Config} */ -module.exports = { - root: true, - extends: [ - "@thesis-co" - ], - ignorePatterns: [ - "node_modules", - "**/node_modules/**", - "**/**/node_modules/**", - "dist", - ".next", - "build", - "coverage", - ".eslintrc.js", - "**/.eslintrc.js", - "**/*.eslintrc.js", - "**/jest.config.js", - "**/babel.config.js" - ], - parser: "@typescript-eslint/parser", - parserOptions: { - project: "./tsconfig.eslint.json", - }, - rules: { - "import/prefer-default-export": "off", - "import/no-cycle": "off", - "@typescript-eslint/no-explicit-any": "warn", - "react/react-in-jsx-scope": "off", - "react/jsx-props-no-spreading": "off", - "react/button-has-type": "warn", - "no-console": "warn" - } -}; \ No newline at end of file diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..587ace7 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,4 @@ +# ignore formatting all library code with new biome config +1c5bbff84fd53e72c817189a3d839a2d522c904c +# ignore formatting all test code with new biome config +6dd383dd921fe4cb5b2fd02056dea1cfc4299b70 diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..18509f3 --- /dev/null +++ b/biome.json @@ -0,0 +1,4 @@ +{ + "extends": ["@thesis-co/biome-config/biome"], + "files": { "includes": ["test/**/*.ts"] } +} diff --git a/package.json b/package.json index 79ef2f7..80ad173 100644 --- a/package.json +++ b/package.json @@ -24,20 +24,16 @@ "access": "public" }, "scripts": { - "lint": "eslint \"src/**/*.ts*\" --max-warnings 0", - "lint:fix": "eslint \"src/**/*.ts\" --fix", + "lint": "pnpx @biomejs/biome check", + "lint:fix": "pnpx @biomejs/biome check --write", "build": "tsc", "test": "jest", "prepublishOnly": "pnpm run build && pnpm run test && pnpm run lint" }, "devDependencies": { - "@thesis-co/eslint-config": "^0.6.1", - "@thesis/prettier-config": "github:thesis/prettier-config", - "@typescript-eslint/eslint-plugin": "^7.1.0", - "@typescript-eslint/parser": "^7.1.0", + "@thesis-co/biome-config": "github:thesis/biome-config", "@types/jest": "^29.5.12", "@types/node": "^20.11.24", - "eslint": "^8.57.0", "jest": "^29.7.0", "ts-jest": "^29.1.2", "typescript": "5.5.4" @@ -56,6 +52,5 @@ "last 1 firefox version", "last 1 safari version" ] - }, - "prettier": "@thesis/prettier-config" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 060f8b4..405ca2e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,27 +12,15 @@ importers: specifier: ^3.25.67 version: 3.25.76 devDependencies: - '@thesis-co/eslint-config': - specifier: ^0.6.1 - version: 0.6.1(eslint@8.57.1)(prettier@3.6.2)(typescript@5.5.4) - '@thesis/prettier-config': - specifier: github:thesis/prettier-config - version: https://codeload.github.com/thesis/prettier-config/tar.gz/daeaac564056a7885e4366ce12bfde6fd823fc90(prettier@3.6.2) + '@thesis-co/biome-config': + specifier: github:thesis/biome-config + version: https://codeload.github.com/thesis/biome-config/tar.gz/6e8586bfa74c62c9ede2ca12abbcac1dc0ad4606 '@types/jest': specifier: ^29.5.12 version: 29.5.14 '@types/node': specifier: ^20.11.24 version: 20.19.9 - '@typescript-eslint/eslint-plugin': - specifier: ^7.1.0 - version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4) - '@typescript-eslint/parser': - specifier: ^7.1.0 - version: 7.18.0(eslint@8.57.1)(typescript@5.5.4) - eslint: - specifier: ^8.57.0 - version: 8.57.1 jest: specifier: ^29.7.0 version: 29.7.0(@types/node@20.19.9) @@ -214,36 +202,58 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - '@eslint-community/eslint-utils@4.7.0': - resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@biomejs/biome@2.1.1': + resolution: {integrity: sha512-HFGYkxG714KzG+8tvtXCJ1t1qXQMzgWzfvQaUjxN6UeKv+KvMEuliInnbZLJm6DXFXwqVi6446EGI0sGBLIYng==} + engines: {node: '>=14.21.3'} + hasBin: true - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@biomejs/cli-darwin-arm64@2.1.1': + resolution: {integrity: sha512-2Muinu5ok4tWxq4nu5l19el48cwCY/vzvI7Vjbkf3CYIQkjxZLyj0Ad37Jv2OtlXYaLvv+Sfu1hFeXt/JwRRXQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} + '@biomejs/cli-darwin-x64@2.1.1': + resolution: {integrity: sha512-cC8HM5lrgKQXLAK+6Iz2FrYW5A62pAAX6KAnRlEyLb+Q3+Kr6ur/sSuoIacqlp1yvmjHJqjYfZjPvHWnqxoEIA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead + '@biomejs/cli-linux-arm64-musl@2.1.1': + resolution: {integrity: sha512-/7FBLnTswu4jgV9ttI3AMIdDGqVEPIZd8I5u2D4tfCoj8rl9dnjrEQbAIDlWhUXdyWlFSz8JypH3swU9h9P+2A==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@2.1.1': + resolution: {integrity: sha512-tw4BEbhAUkWPe4WBr6IX04DJo+2jz5qpPzpW/SWvqMjb9QuHY8+J0M23V8EPY/zWU4IG8Ui0XESapR1CB49Q7g==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@2.1.1': + resolution: {integrity: sha512-kUu+loNI3OCD2c12cUt7M5yaaSjDnGIksZwKnueubX6c/HWUyi/0mPbTBHR49Me3F0KKjWiKM+ZOjsmC+lUt9g==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@2.1.1': + resolution: {integrity: sha512-3WJ1GKjU7NzZb6RTbwLB59v9cTIlzjbiFLDB0z4376TkDqoNYilJaC37IomCr/aXwuU8QKkrYoHrgpSq5ffJ4Q==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@2.1.1': + resolution: {integrity: sha512-vEHK0v0oW+E6RUWLoxb2isI3rZo57OX9ZNyyGH701fZPj6Il0Rn1f5DMNyCmyflMwTnIQstEbs7n2BxYSqQx4Q==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@2.1.1': + resolution: {integrity: sha512-i2PKdn70kY++KEF/zkQFvQfX1e8SkA8hq4BgC+yE9dZqyLzB/XStY2MvwI3qswlRgnGpgncgqe0QYKVS1blksg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} @@ -332,25 +342,6 @@ packages: '@jridgewell/trace-mapping@0.3.29': resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@pkgr/core@0.2.9': - resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -360,17 +351,10 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@thesis-co/eslint-config@0.6.1': - resolution: {integrity: sha512-0vJCCI4UwUdniDCQeTFlMBT+bSp5pGkrtHrZrG2vmyLZwSVdJNtInjkBc/Jd0sGfMtPo3pqQRwA40Zo80lPi+Q==} + '@thesis-co/biome-config@https://codeload.github.com/thesis/biome-config/tar.gz/6e8586bfa74c62c9ede2ca12abbcac1dc0ad4606': + resolution: {tarball: https://codeload.github.com/thesis/biome-config/tar.gz/6e8586bfa74c62c9ede2ca12abbcac1dc0ad4606} + version: 0.0.1 engines: {node: '>=14.0.0'} - peerDependencies: - eslint: '>=6.8.0' - - '@thesis/prettier-config@https://codeload.github.com/thesis/prettier-config/tar.gz/daeaac564056a7885e4366ce12bfde6fd823fc90': - resolution: {tarball: https://codeload.github.com/thesis/prettier-config/tar.gz/daeaac564056a7885e4366ce12bfde6fd823fc90} - version: 0.0.2 - peerDependencies: - prettier: '>=2.3.0 <4' '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -399,9 +383,6 @@ packages: '@types/jest@29.5.14': resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} - '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/node@20.19.9': resolution: {integrity: sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==} @@ -414,80 +395,6 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - '@typescript-eslint/eslint-plugin@7.18.0': - resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/parser@7.18.0': - resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/scope-manager@7.18.0': - resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/type-utils@7.18.0': - resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/types@7.18.0': - resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/typescript-estree@7.18.0': - resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/utils@7.18.0': - resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - - '@typescript-eslint/visitor-keys@7.18.0': - resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -511,71 +418,9 @@ packages: argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} - - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} - - array-includes@3.1.9: - resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} - engines: {node: '>= 0.4'} - - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - - array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} - - array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} - - array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} - - array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} - engines: {node: '>= 0.4'} - - array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} - - arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} - - ast-types-flow@0.0.8: - resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} - - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} - async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - axe-core@4.10.3: - resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} - engines: {node: '>=4'} - - axobject-query@4.1.0: - resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} - engines: {node: '>= 0.4'} - babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -629,18 +474,6 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -692,9 +525,6 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - confusing-browser-globals@1.0.11: - resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -707,29 +537,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - damerau-levenshtein@1.0.8: - resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - - data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} - - data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} - - data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.1: resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} @@ -747,21 +554,10 @@ packages: babel-plugin-macros: optional: true - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -770,22 +566,6 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - ejs@3.1.10: resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} @@ -801,44 +581,9 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - es-abstract@1.24.0: - resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} - engines: {node: '>= 0.4'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-iterator-helpers@1.2.1: - resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - es-shim-unscopables@1.1.0: - resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} - engines: {node: '>= 0.4'} - - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} - escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -847,150 +592,11 @@ packages: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-config-airbnb-base@15.0.0: - resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - eslint: ^7.32.0 || ^8.2.0 - eslint-plugin-import: ^2.25.2 - - eslint-config-airbnb-typescript@17.1.0: - resolution: {integrity: sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==} - peerDependencies: - '@typescript-eslint/eslint-plugin': ^5.13.0 || ^6.0.0 - '@typescript-eslint/parser': ^5.0.0 || ^6.0.0 - eslint: ^7.32.0 || ^8.2.0 - eslint-plugin-import: ^2.25.3 - - eslint-config-airbnb@19.0.4: - resolution: {integrity: sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==} - engines: {node: ^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^7.32.0 || ^8.2.0 - eslint-plugin-import: ^2.25.3 - eslint-plugin-jsx-a11y: ^6.5.1 - eslint-plugin-react: ^7.28.0 - eslint-plugin-react-hooks: ^4.3.0 - - eslint-config-prettier@9.1.2: - resolution: {integrity: sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - - eslint-module-utils@2.12.1: - resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - - eslint-plugin-import@2.32.0: - resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - - eslint-plugin-jsx-a11y@6.10.2: - resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} - engines: {node: '>=4.0'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - - eslint-plugin-no-only-tests@3.3.0: - resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==} - engines: {node: '>=5.0.0'} - - eslint-plugin-prettier@5.5.3: - resolution: {integrity: sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - '@types/eslint': '>=8.0.0' - eslint: '>=8.0.0' - eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' - prettier: '>=3.0.0' - peerDependenciesMeta: - '@types/eslint': - optional: true - eslint-config-prettier: - optional: true - - eslint-plugin-react-hooks@4.6.2: - resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - - eslint-plugin-react@7.37.5: - resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -1003,32 +609,12 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} - fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} @@ -1040,21 +626,6 @@ packages: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -1066,13 +637,6 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -1081,83 +645,25 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} - engines: {node: '>= 0.4'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -1169,14 +675,6 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - import-local@3.2.0: resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} engines: {node: '>=8'} @@ -1193,53 +691,13 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} - - is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} - is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} - - is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} - - is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} - is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} - - is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} - is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -1248,77 +706,14 @@ packages: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - - is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} - is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} - - is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - - is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} - - is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -1346,10 +741,6 @@ packages: resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} engines: {node: '>=8'} - iterator.prototype@1.1.5: - resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} - engines: {node: '>= 0.4'} - jake@10.9.2: resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} engines: {node: '>=10'} @@ -1491,62 +882,27 @@ packages: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} hasBin: true - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true - jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - language-subtag-registry@0.3.23: - resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} - - language-tags@1.0.9: - resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} - engines: {node: '>=0.10'} - leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -1554,20 +910,9 @@ packages: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -1581,17 +926,9 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -1607,13 +944,6 @@ packages: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1634,38 +964,6 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} - - object.entries@1.1.9: - resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} - engines: {node: '>= 0.4'} - - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} - - object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} - - object.values@1.2.1: - resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} - engines: {node: '>= 0.4'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -1673,14 +971,6 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} - engines: {node: '>= 0.4'} - p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -1693,18 +983,10 @@ packages: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -1724,10 +1006,6 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1743,23 +1021,6 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} - - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} - engines: {node: '>=14'} - hasBin: true - pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1768,33 +1029,12 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} - - regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -1803,10 +1043,6 @@ packages: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} @@ -1820,34 +1056,6 @@ packages: engines: {node: '>= 0.4'} hasBin: true - resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} - hasBin: true - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} - engines: {node: '>=0.4'} - - safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -1857,18 +1065,6 @@ packages: engines: {node: '>=10'} hasBin: true - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - - set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1877,22 +1073,6 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -1917,10 +1097,6 @@ packages: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} - stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} - string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -1929,37 +1105,10 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - string.prototype.includes@2.0.1: - resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} - engines: {node: '>= 0.4'} - - string.prototype.matchall@4.0.12: - resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} - engines: {node: '>= 0.4'} - - string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} - - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} @@ -1984,17 +1133,10 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - synckit@0.11.11: - resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} - engines: {node: ^14.18.0 || >=16.0.0} - test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -2002,12 +1144,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - ts-api-utils@1.4.3: - resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - ts-jest@29.4.0: resolution: {integrity: sha512-d423TJMnJGu80/eSgfQ5w/R+0zFJvdtTxwtF9KzFFunOpSeD+79lHJQIiAhluJoyGRbvj9NZJsl9WjCUo0ND7Q==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} @@ -2035,21 +1171,10 @@ packages: jest-util: optional: true - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} @@ -2058,31 +1183,11 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} - typescript@5.5.4: resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} engines: {node: '>=14.17'} hasBin: true - unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} - undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -2092,9 +1197,6 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - v8-to-istanbul@9.3.0: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} @@ -2102,31 +1204,11 @@ packages: walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} - - which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} - - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - - which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} - engines: {node: '>= 0.4'} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -2356,40 +1438,40 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@eslint-community/eslint-utils@4.7.0(eslint@8.57.1)': - dependencies: - eslint: 8.57.1 - eslint-visitor-keys: 3.4.3 + '@biomejs/biome@2.1.1': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.1.1 + '@biomejs/cli-darwin-x64': 2.1.1 + '@biomejs/cli-linux-arm64': 2.1.1 + '@biomejs/cli-linux-arm64-musl': 2.1.1 + '@biomejs/cli-linux-x64': 2.1.1 + '@biomejs/cli-linux-x64-musl': 2.1.1 + '@biomejs/cli-win32-arm64': 2.1.1 + '@biomejs/cli-win32-x64': 2.1.1 + + '@biomejs/cli-darwin-arm64@2.1.1': + optional: true - '@eslint-community/regexpp@4.12.1': {} + '@biomejs/cli-darwin-x64@2.1.1': + optional: true - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.12.6 - debug: 4.4.1 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color + '@biomejs/cli-linux-arm64-musl@2.1.1': + optional: true - '@eslint/js@8.57.1': {} + '@biomejs/cli-linux-arm64@2.1.1': + optional: true - '@humanwhocodes/config-array@0.13.0': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.1 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@biomejs/cli-linux-x64-musl@2.1.1': + optional: true + + '@biomejs/cli-linux-x64@2.1.1': + optional: true - '@humanwhocodes/module-importer@1.0.1': {} + '@biomejs/cli-win32-arm64@2.1.1': + optional: true - '@humanwhocodes/object-schema@2.0.3': {} + '@biomejs/cli-win32-x64@2.1.1': + optional: true '@istanbuljs/load-nyc-config@1.1.0': dependencies: @@ -2577,22 +1659,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.4 - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 - - '@pkgr/core@0.2.9': {} - - '@rtsao/scc@1.1.0': {} - '@sinclair/typebox@0.27.8': {} '@sinonjs/commons@3.0.1': @@ -2603,33 +1669,9 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@thesis-co/eslint-config@0.6.1(eslint@8.57.1)(prettier@3.6.2)(typescript@5.5.4)': - dependencies: - '@thesis-co/prettier-config': '@thesis/prettier-config@https://codeload.github.com/thesis/prettier-config/tar.gz/daeaac564056a7885e4366ce12bfde6fd823fc90(prettier@3.6.2)' - '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4) - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.5.4) - eslint: 8.57.1 - eslint-config-airbnb: 19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.5(eslint@8.57.1))(eslint@8.57.1) - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1))(eslint@8.57.1) - eslint-config-airbnb-typescript: 17.1.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4))(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1))(eslint@8.57.1) - eslint-config-prettier: 9.1.2(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1) - eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) - eslint-plugin-no-only-tests: 3.3.0 - eslint-plugin-prettier: 5.5.3(eslint-config-prettier@9.1.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2) - eslint-plugin-react: 7.37.5(eslint@8.57.1) - eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) - transitivePeerDependencies: - - '@types/eslint' - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - prettier - - supports-color - - typescript - - '@thesis/prettier-config@https://codeload.github.com/thesis/prettier-config/tar.gz/daeaac564056a7885e4366ce12bfde6fd823fc90(prettier@3.6.2)': + '@thesis-co/biome-config@https://codeload.github.com/thesis/biome-config/tar.gz/6e8586bfa74c62c9ede2ca12abbcac1dc0ad4606': dependencies: - prettier: 3.6.2 + '@biomejs/biome': 2.1.1 '@types/babel__core@7.20.5': dependencies: @@ -2671,8 +1713,6 @@ snapshots: expect: 29.7.0 pretty-format: 29.7.0 - '@types/json5@0.0.29': {} - '@types/node@20.19.9': dependencies: undici-types: 6.21.0 @@ -2685,102 +1725,6 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4)': - dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.5.4) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/type-utils': 7.18.0(eslint@8.57.1)(typescript@5.5.4) - '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.5.4) - '@typescript-eslint/visitor-keys': 7.18.0 - eslint: 8.57.1 - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare: 1.4.0 - ts-api-utils: 1.4.3(typescript@5.5.4) - optionalDependencies: - typescript: 5.5.4 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4)': - dependencies: - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.1 - eslint: 8.57.1 - optionalDependencies: - typescript: 5.5.4 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@7.18.0': - dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - - '@typescript-eslint/type-utils@7.18.0(eslint@8.57.1)(typescript@5.5.4)': - dependencies: - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) - '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.5.4) - debug: 4.4.1 - eslint: 8.57.1 - ts-api-utils: 1.4.3(typescript@5.5.4) - optionalDependencies: - typescript: 5.5.4 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@7.18.0': {} - - '@typescript-eslint/typescript-estree@7.18.0(typescript@5.5.4)': - dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.1 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.2 - ts-api-utils: 1.4.3(typescript@5.5.4) - optionalDependencies: - typescript: 5.5.4 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@7.18.0(eslint@8.57.1)(typescript@5.5.4)': - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/visitor-keys@7.18.0': - dependencies: - '@typescript-eslint/types': 7.18.0 - eslint-visitor-keys: 3.4.3 - - '@ungap/structured-clone@1.3.0': {} - - acorn-jsx@5.3.2(acorn@8.15.0): - dependencies: - acorn: 8.15.0 - - acorn@8.15.0: {} - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -2802,93 +1746,8 @@ snapshots: dependencies: sprintf-js: 1.0.3 - argparse@2.0.1: {} - - aria-query@5.3.2: {} - - array-buffer-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - is-array-buffer: 3.0.5 - - array-includes@3.1.9: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - is-string: 1.1.1 - math-intrinsics: 1.1.0 - - array-union@2.1.0: {} - - array.prototype.findlast@1.2.5: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-shim-unscopables: 1.1.0 - - array.prototype.findlastindex@1.2.6: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-shim-unscopables: 1.1.0 - - array.prototype.flat@1.3.3: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-shim-unscopables: 1.1.0 - - array.prototype.flatmap@1.3.3: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-shim-unscopables: 1.1.0 - - array.prototype.tosorted@1.1.4: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-shim-unscopables: 1.1.0 - - arraybuffer.prototype.slice@1.0.4: - dependencies: - array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - is-array-buffer: 3.0.5 - - ast-types-flow@0.0.8: {} - - async-function@1.0.0: {} - async@3.2.6: {} - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - axe-core@4.10.3: {} - - axobject-query@4.1.0: {} - babel-jest@29.7.0(@babel/core@7.28.0): dependencies: '@babel/core': 7.28.0 @@ -2976,23 +1835,6 @@ snapshots: buffer-from@1.1.2: {} - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - callsites@3.1.0: {} camelcase@5.3.1: {} @@ -3030,8 +1872,6 @@ snapshots: concat-map@0.0.1: {} - confusing-browser-globals@1.0.11: {} - convert-source-map@2.0.0: {} create-jest@29.7.0(@types/node@20.19.9): @@ -3055,401 +1895,37 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - damerau-levenshtein@1.0.8: {} - - data-view-buffer@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-offset@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - debug@3.2.7: - dependencies: - ms: 2.1.3 - debug@4.4.1: dependencies: ms: 2.1.3 dedent@1.6.0: {} - deep-is@0.1.4: {} - deepmerge@4.3.1: {} - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - detect-newline@3.1.0: {} - diff-sequences@29.6.3: {} - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - doctrine@2.1.0: - dependencies: - esutils: 2.0.3 - - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - ejs@3.1.10: - dependencies: - jake: 10.9.2 - - electron-to-chromium@1.5.190: {} - - emittery@0.13.1: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - error-ex@1.3.2: - dependencies: - is-arrayish: 0.2.1 - - es-abstract@1.24.0: - dependencies: - array-buffer-byte-length: 1.0.2 - arraybuffer.prototype.slice: 1.0.4 - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - data-view-buffer: 1.0.2 - data-view-byte-length: 1.0.2 - data-view-byte-offset: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - get-symbol-description: 1.1.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - internal-slot: 1.1.0 - is-array-buffer: 3.0.5 - is-callable: 1.2.7 - is-data-view: 1.0.2 - is-negative-zero: 2.0.3 - is-regex: 1.2.1 - is-set: 2.0.3 - is-shared-array-buffer: 1.0.4 - is-string: 1.1.1 - is-typed-array: 1.1.15 - is-weakref: 1.1.1 - math-intrinsics: 1.1.0 - object-inspect: 1.13.4 - object-keys: 1.1.1 - object.assign: 4.1.7 - own-keys: 1.0.1 - regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.3 - safe-push-apply: 1.0.0 - safe-regex-test: 1.1.0 - set-proto: 1.0.0 - stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.3 - typed-array-byte-length: 1.0.3 - typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 - unbox-primitive: 1.1.0 - which-typed-array: 1.1.19 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-iterator-helpers@1.2.1: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-set-tostringtag: 2.1.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - internal-slot: 1.1.0 - iterator.prototype: 1.1.5 - safe-array-concat: 1.1.3 - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - es-shim-unscopables@1.1.0: - dependencies: - hasown: 2.0.2 - - es-to-primitive@1.3.0: - dependencies: - is-callable: 1.2.7 - is-date-object: 1.1.0 - is-symbol: 1.1.1 - - escalade@3.2.0: {} - - escape-string-regexp@2.0.0: {} - - escape-string-regexp@4.0.0: {} - - eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1))(eslint@8.57.1): - dependencies: - confusing-browser-globals: 1.0.11 - eslint: 8.57.1 - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1) - object.assign: 4.1.7 - object.entries: 1.1.9 - semver: 6.3.1 - - eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4))(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1))(eslint@8.57.1): - dependencies: - '@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4) - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.5.4) - eslint: 8.57.1 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1) - - eslint-config-airbnb@19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.1))(eslint-plugin-react@7.37.5(eslint@8.57.1))(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1) - eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) - eslint-plugin-react: 7.37.5(eslint@8.57.1) - eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) - object.assign: 4.1.7 - object.entries: 1.1.9 - - eslint-config-prettier@9.1.2(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - - eslint-import-resolver-node@0.3.9: - dependencies: - debug: 3.2.7 - is-core-module: 2.16.1 - resolve: 1.22.10 - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.5.4) - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - - eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.9 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) - hasown: 2.0.2 - is-core-module: 2.16.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.1 - semver: 6.3.1 - string.prototype.trimend: 1.0.9 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.5.4) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - - eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1): - dependencies: - aria-query: 5.3.2 - array-includes: 3.1.9 - array.prototype.flatmap: 1.3.3 - ast-types-flow: 0.0.8 - axe-core: 4.10.3 - axobject-query: 4.1.0 - damerau-levenshtein: 1.0.8 - emoji-regex: 9.2.2 - eslint: 8.57.1 - hasown: 2.0.2 - jsx-ast-utils: 3.3.5 - language-tags: 1.0.9 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - safe-regex-test: 1.1.0 - string.prototype.includes: 2.0.1 - - eslint-plugin-no-only-tests@3.3.0: {} - - eslint-plugin-prettier@5.5.3(eslint-config-prettier@9.1.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2): - dependencies: - eslint: 8.57.1 - prettier: 3.6.2 - prettier-linter-helpers: 1.0.0 - synckit: 0.11.11 - optionalDependencies: - eslint-config-prettier: 9.1.2(eslint@8.57.1) - - eslint-plugin-react-hooks@4.6.2(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - - eslint-plugin-react@7.37.5(eslint@8.57.1): - dependencies: - array-includes: 3.1.9 - array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.3 - array.prototype.tosorted: 1.1.4 - doctrine: 2.1.0 - es-iterator-helpers: 1.2.1 - eslint: 8.57.1 - estraverse: 5.3.0 - hasown: 2.0.2 - jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.9 - object.fromentries: 2.0.8 - object.values: 1.2.1 - prop-types: 15.8.1 - resolve: 2.0.0-next.5 - semver: 6.3.1 - string.prototype.matchall: 4.0.12 - string.prototype.repeat: 1.0.0 - - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint@8.57.1: - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.1 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.3.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.1 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color + diff-sequences@29.6.3: {} - espree@9.6.1: + ejs@3.1.10: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 3.4.3 + jake: 10.9.2 - esprima@4.0.1: {} + electron-to-chromium@1.5.190: {} - esquery@1.6.0: - dependencies: - estraverse: 5.3.0 + emittery@0.13.1: {} + + emoji-regex@8.0.0: {} - esrecurse@4.3.0: + error-ex@1.3.2: dependencies: - estraverse: 5.3.0 + is-arrayish: 0.2.1 + + escalade@3.2.0: {} - estraverse@5.3.0: {} + escape-string-regexp@2.0.0: {} - esutils@2.0.3: {} + esprima@4.0.1: {} execa@5.1.1: dependencies: @@ -3473,34 +1949,12 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - fast-deep-equal@3.1.3: {} - - fast-diff@1.3.0: {} - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - fast-json-stable-stringify@2.1.0: {} - fast-levenshtein@2.0.6: {} - - fastq@1.19.1: - dependencies: - reusify: 1.1.0 - fb-watchman@2.0.2: dependencies: bser: 2.1.1 - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - filelist@1.0.4: dependencies: minimatch: 5.1.6 @@ -3514,23 +1968,6 @@ snapshots: locate-path: 5.0.0 path-exists: 4.0.0 - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@3.2.0: - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - rimraf: 3.0.2 - - flatted@3.3.3: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -3538,57 +1975,14 @@ snapshots: function-bind@1.1.2: {} - function.prototype.name@1.1.8: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - functions-have-names: 1.2.3 - hasown: 2.0.2 - is-callable: 1.2.7 - - functions-have-names@1.2.3: {} - gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - get-package-type@0.1.0: {} - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - get-stream@6.0.1: {} - get-symbol-description@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -3598,48 +1992,10 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - - gopd@1.2.0: {} - graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - - has-bigints@1.1.0: {} - has-flag@4.0.0: {} - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-proto@1.2.0: - dependencies: - dunder-proto: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -3648,13 +2004,6 @@ snapshots: human-signals@2.1.0: {} - ignore@5.3.2: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - import-local@3.2.0: dependencies: pkg-dir: 4.2.0 @@ -3669,131 +2018,20 @@ snapshots: inherits@2.0.4: {} - internal-slot@1.1.0: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.1.0 - - is-array-buffer@3.0.5: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - is-arrayish@0.2.1: {} - is-async-function@2.1.1: - dependencies: - async-function: 1.0.0 - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-bigint@1.1.0: - dependencies: - has-bigints: 1.1.0 - - is-boolean-object@1.2.2: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-callable@1.2.7: {} - is-core-module@2.16.1: dependencies: hasown: 2.0.2 - is-data-view@1.0.2: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - is-typed-array: 1.1.15 - - is-date-object@1.1.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-extglob@2.1.1: {} - - is-finalizationregistry@1.1.1: - dependencies: - call-bound: 1.0.4 - is-fullwidth-code-point@3.0.0: {} is-generator-fn@2.1.0: {} - is-generator-function@1.1.0: - dependencies: - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-map@2.0.3: {} - - is-negative-zero@2.0.3: {} - - is-number-object@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - is-number@7.0.0: {} - is-path-inside@3.0.3: {} - - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - is-set@2.0.3: {} - - is-shared-array-buffer@1.0.4: - dependencies: - call-bound: 1.0.4 - is-stream@2.0.1: {} - is-string@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-symbol@1.1.1: - dependencies: - call-bound: 1.0.4 - has-symbols: 1.1.0 - safe-regex-test: 1.1.0 - - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.19 - - is-weakmap@2.0.2: {} - - is-weakref@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-weakset@2.0.4: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - isarray@2.0.5: {} - isexe@2.0.0: {} istanbul-lib-coverage@3.2.2: {} @@ -3837,15 +2075,6 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - iterator.prototype@1.1.5: - dependencies: - define-data-property: 1.1.4 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - has-symbols: 1.1.0 - set-function-name: 2.0.2 - jake@10.9.2: dependencies: async: 3.2.6 @@ -4168,70 +2397,24 @@ snapshots: argparse: 1.0.10 esprima: 4.0.1 - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - jsesc@3.1.0: {} - json-buffer@3.0.1: {} - json-parse-even-better-errors@2.3.1: {} - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@1.0.2: - dependencies: - minimist: 1.2.8 - json5@2.2.3: {} - jsx-ast-utils@3.3.5: - dependencies: - array-includes: 3.1.9 - array.prototype.flat: 1.3.3 - object.assign: 4.1.7 - object.values: 1.2.1 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - kleur@3.0.3: {} - language-subtag-registry@0.3.23: {} - - language-tags@1.0.9: - dependencies: - language-subtag-registry: 0.3.23 - leven@3.1.0: {} - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - lines-and-columns@1.2.4: {} locate-path@5.0.0: dependencies: p-locate: 4.1.0 - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - lodash.memoize@4.1.2: {} - lodash.merge@4.6.2: {} - - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -4246,12 +2429,8 @@ snapshots: dependencies: tmpl: 1.0.5 - math-intrinsics@1.1.0: {} - merge-stream@2.0.0: {} - merge2@1.4.1: {} - micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -4267,12 +2446,6 @@ snapshots: dependencies: brace-expansion: 2.0.2 - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.2 - - minimist@1.2.8: {} - ms@2.1.3: {} natural-compare@1.4.0: {} @@ -4287,48 +2460,6 @@ snapshots: dependencies: path-key: 3.1.1 - object-assign@4.1.1: {} - - object-inspect@1.13.4: {} - - object-keys@1.1.1: {} - - object.assign@4.1.7: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 - - object.entries@1.1.9: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - object.fromentries@2.0.8: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - - object.groupby@1.0.3: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - - object.values@1.2.1: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -4337,21 +2468,6 @@ snapshots: dependencies: mimic-fn: 2.1.0 - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - own-keys@1.0.1: - dependencies: - get-intrinsic: 1.3.0 - object-keys: 1.1.1 - safe-push-apply: 1.0.0 - p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -4364,16 +2480,8 @@ snapshots: dependencies: p-limit: 2.3.0 - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - p-try@2.2.0: {} - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - parse-json@5.2.0: dependencies: '@babel/code-frame': 7.27.1 @@ -4389,8 +2497,6 @@ snapshots: path-parse@1.0.7: {} - path-type@4.0.0: {} - picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -4401,16 +2507,6 @@ snapshots: dependencies: find-up: 4.1.0 - possible-typed-array-names@1.1.0: {} - - prelude-ls@1.2.1: {} - - prettier-linter-helpers@1.0.0: - dependencies: - fast-diff: 1.3.0 - - prettier@3.6.2: {} - pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 @@ -4422,50 +2518,16 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 - prop-types@15.8.1: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - - punycode@2.3.1: {} - pure-rand@6.1.0: {} - queue-microtask@1.2.3: {} - - react-is@16.13.1: {} - react-is@18.3.1: {} - reflect.getprototypeof@1.0.10: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - which-builtin-type: 1.2.1 - - regexp.prototype.flags@1.5.4: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-errors: 1.3.0 - get-proto: 1.0.1 - gopd: 1.2.0 - set-function-name: 2.0.2 - require-directory@2.1.1: {} resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 - resolve-from@4.0.0: {} - resolve-from@5.0.0: {} resolve.exports@2.0.3: {} @@ -4476,101 +2538,16 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - resolve@2.0.0-next.5: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - reusify@1.1.0: {} - - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-array-concat@1.1.3: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - has-symbols: 1.1.0 - isarray: 2.0.5 - - safe-push-apply@1.0.0: - dependencies: - es-errors: 1.3.0 - isarray: 2.0.5 - - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - semver@6.3.1: {} semver@7.7.2: {} - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - set-function-name@2.0.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - - set-proto@1.0.0: - dependencies: - dunder-proto: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - signal-exit@3.0.7: {} sisteransi@1.0.5: {} @@ -4590,11 +2567,6 @@ snapshots: dependencies: escape-string-regexp: 2.0.0 - stop-iteration-iterator@1.1.0: - dependencies: - es-errors: 1.3.0 - internal-slot: 1.1.0 - string-length@4.0.2: dependencies: char-regex: 1.0.2 @@ -4606,62 +2578,10 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string.prototype.includes@2.0.1: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-abstract: 1.24.0 - - string.prototype.matchall@4.0.12: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-symbols: 1.1.0 - internal-slot: 1.1.0 - regexp.prototype.flags: 1.5.4 - set-function-name: 2.0.2 - side-channel: 1.1.0 - - string.prototype.repeat@1.0.0: - dependencies: - define-properties: 1.2.1 - es-abstract: 1.24.0 - - string.prototype.trim@1.2.10: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-data-property: 1.1.4 - define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 - has-property-descriptors: 1.0.2 - - string.prototype.trimend@1.0.9: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - string.prototype.trimstart@1.0.8: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - strip-bom@3.0.0: {} - strip-bom@4.0.0: {} strip-final-newline@2.0.0: {} @@ -4678,28 +2598,18 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - synckit@0.11.11: - dependencies: - '@pkgr/core': 0.2.9 - test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 minimatch: 3.1.2 - text-table@0.2.0: {} - tmpl@1.0.5: {} to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - ts-api-utils@1.4.3(typescript@5.5.4): - dependencies: - typescript: 5.5.4 - ts-jest@29.4.0(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.9))(typescript@5.5.4): dependencies: bs-logger: 0.2.6 @@ -4720,67 +2630,14 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.28.0) jest-util: 29.7.0 - tsconfig-paths@3.15.0: - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - type-detect@4.0.8: {} - type-fest@0.20.2: {} - type-fest@0.21.3: {} type-fest@4.41.0: {} - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - - typed-array-byte-length@1.0.3: - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - - typed-array-byte-offset@1.0.4: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.10 - - typed-array-length@1.0.7: - dependencies: - call-bind: 1.0.8 - for-each: 0.3.5 - gopd: 1.2.0 - is-typed-array: 1.1.15 - possible-typed-array-names: 1.1.0 - reflect.getprototypeof: 1.0.10 - typescript@5.5.4: {} - unbox-primitive@1.1.0: - dependencies: - call-bound: 1.0.4 - has-bigints: 1.1.0 - has-symbols: 1.1.0 - which-boxed-primitive: 1.1.1 - undici-types@6.21.0: {} update-browserslist-db@1.1.3(browserslist@4.25.1): @@ -4789,10 +2646,6 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - v8-to-istanbul@9.3.0: dependencies: '@jridgewell/trace-mapping': 0.3.29 @@ -4803,53 +2656,10 @@ snapshots: dependencies: makeerror: 1.0.12 - which-boxed-primitive@1.1.1: - dependencies: - is-bigint: 1.1.0 - is-boolean-object: 1.2.2 - is-number-object: 1.1.1 - is-string: 1.1.1 - is-symbol: 1.1.1 - - which-builtin-type@1.2.1: - dependencies: - call-bound: 1.0.4 - function.prototype.name: 1.1.8 - has-tostringtag: 1.0.2 - is-async-function: 2.1.1 - is-date-object: 1.1.0 - is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.0 - is-regex: 1.2.1 - is-weakref: 1.1.1 - isarray: 2.0.5 - which-boxed-primitive: 1.1.1 - which-collection: 1.0.2 - which-typed-array: 1.1.19 - - which-collection@1.0.2: - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.4 - - which-typed-array@1.1.19: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - which@2.0.2: dependencies: isexe: 2.0.0 - word-wrap@1.2.5: {} - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 diff --git a/src/assets.ts b/src/assets.ts index ac0c4da..a9ab71b 100644 --- a/src/assets.ts +++ b/src/assets.ts @@ -1,4 +1,4 @@ -import { AnyAsset, Asset, AssetAmount } from "./types" +import type { AnyAsset, Asset, AssetAmount } from "./types" /** * Check if two assets are equal diff --git a/src/currencies.ts b/src/currencies.ts index 5f9f0b1..e09ac3f 100644 --- a/src/currencies.ts +++ b/src/currencies.ts @@ -1,4 +1,4 @@ -import { Currency } from "./types" +import type { Currency } from "./types" // major world currencies with fractional units export const AFN: Currency = { diff --git a/src/decimal-strings.ts b/src/decimal-strings.ts index 7af90ac..2e4ab74 100644 --- a/src/decimal-strings.ts +++ b/src/decimal-strings.ts @@ -1,5 +1,5 @@ import { z } from "zod" -import { DecimalString } from "./types" +import type { DecimalString } from "./types" /** * Zod schema for validating decimal strings diff --git a/src/exchange-rate-sources.ts b/src/exchange-rate-sources.ts index 55a1b0d..86be0a2 100644 --- a/src/exchange-rate-sources.ts +++ b/src/exchange-rate-sources.ts @@ -1,5 +1,5 @@ -import { ExchangeRate } from "./exchange-rates" -import { Currency, UNIXTime } from "./types" +import type { ExchangeRate } from "./exchange-rates" +import type { Currency, UNIXTime } from "./types" /** * Metadata about an exchange rate source @@ -58,64 +58,64 @@ export interface RateStalenessConfig { } /** - * Utility functions for working with exchange rate sources + * Check if a rate is stale based on its timestamp + * @param timestamp - Rate timestamp + * @param config - Staleness configuration + * @returns Whether the rate is stale */ -export class ExchangeRateSourceUtils { - /** - * Check if a rate is stale based on its timestamp - * @param timestamp - Rate timestamp - * @param config - Staleness configuration - * @returns Whether the rate is stale - */ - static isRateStale( - timestamp: string | UNIXTime, - config: RateStalenessConfig, - ): boolean { - const now = Date.now() - const rateTime = - typeof timestamp === "string" - ? parseInt(timestamp, 10) - : parseInt(timestamp, 10) - const age = now - rateTime - - return age > config.maxAge - } +export function isRateStale( + timestamp: string | UNIXTime, + config: RateStalenessConfig, +): boolean { + const now = Date.now() + const rateTime = + typeof timestamp === "string" + ? parseInt(timestamp, 10) + : parseInt(timestamp, 10) + const age = now - rateTime - /** - * Compare two exchange rate sources by priority and reliability - * @param a - First source - * @param b - Second source - * @returns Comparison result (negative if a is better, positive if b is better) - */ - static compareSources(a: ExchangeRateSource, b: ExchangeRateSource): number { - // First compare by priority (lower is better) - if (a.priority !== b.priority) { - return a.priority - b.priority - } + return age > config.maxAge +} - // If priorities are equal, compare by reliability (higher is better) - return b.reliability - a.reliability +/** + * Compare two exchange rate sources by priority and reliability + * @param a - First source + * @param b - Second source + * @returns Comparison result (negative if a is better, positive if b is better) + */ +export function compareSources( + a: ExchangeRateSource, + b: ExchangeRateSource, +): number { + // First compare by priority (lower is better) + if (a.priority !== b.priority) { + return a.priority - b.priority } - /** - * Filter sources by minimum reliability threshold - * @param sources - Array of sources to filter - * @param minReliability - Minimum reliability threshold - * @returns Filtered sources - */ - static filterByReliability( - sources: ExchangeRateSource[], - minReliability: number, - ): ExchangeRateSource[] { - return sources.filter((source) => source.reliability >= minReliability) - } + // If priorities are equal, compare by reliability (higher is better) + return b.reliability - a.reliability +} - /** - * Sort sources by priority and reliability - * @param sources - Array of sources to sort - * @returns Sorted sources (best first) - */ - static sortSources(sources: ExchangeRateSource[]): ExchangeRateSource[] { - return [...sources].sort(this.compareSources) - } +/** + * Filter sources by minimum reliability threshold + * @param sources - Array of sources to filter + * @param minReliability - Minimum reliability threshold + * @returns Filtered sources + */ +export function filterByReliability( + sources: ExchangeRateSource[], + minReliability: number, +): ExchangeRateSource[] { + return sources.filter((source) => source.reliability >= minReliability) +} + +/** + * Sort sources by priority and reliability + * @param sources - Array of sources to sort + * @returns Sorted sources (best first) + */ +export function sortSources( + sources: ExchangeRateSource[], +): ExchangeRateSource[] { + return [...sources].sort(compareSources) } diff --git a/src/exchange-rates.ts b/src/exchange-rates.ts index e4160a5..d8eddca 100644 --- a/src/exchange-rates.ts +++ b/src/exchange-rates.ts @@ -1,13 +1,13 @@ import { z } from "zod" -import { Currency, UNIXTime } from "./types" -import { FixedPointNumber, FixedPoint } from "./fixed-point" -import { RationalNumber } from "./rationals" -import { ExchangeRateSource } from "./exchange-rate-sources" -import { nowUNIXTime, UNIXTimeSchema, toUNIXTime } from "./time" -import { NonNegativeBigIntStringSchema } from "./validation-schemas" -import { AnyAssetJSONSchema } from "./money" import { assetsEqual } from "./assets" +import type { ExchangeRateSource } from "./exchange-rate-sources" +import { FixedPoint, FixedPointNumber } from "./fixed-point" +import { AnyAssetJSONSchema } from "./money" import { isFixedPointNumber, toFixedPointNumber } from "./money/utils" +import { RationalNumber } from "./rationals" +import { nowUNIXTime, toUNIXTime, UNIXTimeSchema } from "./time" +import type { Currency, UNIXTime } from "./types" +import { NonNegativeBigIntStringSchema } from "./validation-schemas" /** * ExchangeRate data structure with clear base/quote semantics @@ -141,128 +141,7 @@ export class ExchangeRate implements ExchangeRateData { } /** - * Instance method to multiply this exchange rate - */ - multiply( - multiplier: FixedPointNumber | string | bigint | ExchangeRate, - ): ExchangeRate { - if (multiplier instanceof ExchangeRate) { - return new ExchangeRate( - ExchangeRate.multiply(this.toData(), multiplier.toData()), - ) - } - return new ExchangeRate(ExchangeRate.multiply(this.toData(), multiplier)) - } - - /** - * Instance method to convert money using this exchange rate - */ - convert( - money: import("./money").Money, - ): import("./money").Money { - return ExchangeRate.convert(money, this.toData()) - } - - /** - * Instance method to check if this rate is stale - */ - isStale(maxAge: number): boolean { - return ExchangeRate.isStale(this.toData(), maxAge) - } - - /** - * Instance method to get the age of this rate - */ - getAge(): number { - return ExchangeRate.getAge(this.toData()) - } - - /** - * Instance method to serialize this rate to JSON - */ - toJSON(): ExchangeRateJSON { - return ExchangeRate.toJSON(this.toData()) - } - - /** - * Instance method to format this rate as a string - */ - toString(options?: { - format?: "symbol" | "code" | "ratio" - precision?: number - locale?: string - }): string { - return ExchangeRate.toString(this.toData(), options) - } - - /** - * Apply a spread to create bid/ask rates around this rate - * @param spread - The spread as a FixedPointNumber, decimal string, or percent string - * @returns An object containing bid, ask, and mid rates - */ - spread(spread: FixedPointNumber | string): { - bid: ExchangeRate - ask: ExchangeRate - mid: ExchangeRate - } { - // Parse the spread parameter into a FixedPointNumber - let spreadFixed: FixedPointNumber - if (typeof spread === "string") { - spreadFixed = FixedPoint(spread) - } else { - spreadFixed = spread - } - - // Calculate half the spread for symmetric application - const halfSpread = spreadFixed.divide(new FixedPointNumber(2n, 0n)) - - // Create bid rate: rate - (rate * halfSpread) - const bidRate = this.rate.subtract(this.rate.multiply(halfSpread)) - - // Create ask rate: rate + (rate * halfSpread) - const askRate = this.rate.add(this.rate.multiply(halfSpread)) - - // Create the bid, ask, and mid exchange rates - const bidExchangeRate = new ExchangeRate({ - baseCurrency: this.baseCurrency, - quoteCurrency: this.quoteCurrency, - rate: bidRate, - timestamp: this.timestamp, - source: this.source, - }) - - const askExchangeRate = new ExchangeRate({ - baseCurrency: this.baseCurrency, - quoteCurrency: this.quoteCurrency, - rate: askRate, - timestamp: this.timestamp, - source: this.source, - }) - - const midExchangeRate = new ExchangeRate({ - baseCurrency: this.baseCurrency, - quoteCurrency: this.quoteCurrency, - rate: this.rate, - timestamp: this.timestamp, - source: this.source, - }) - - return { - bid: bidExchangeRate, - ask: askExchangeRate, - mid: midExchangeRate, - } - } - - /** - * Static method to create from JSON - */ - static fromJSON(json: unknown): ExchangeRate { - return new ExchangeRate(ExchangeRate.fromJSONData(json)) - } - - /** - * Invert an ExchangeRate by swapping base and quote currencies + * Static method to invert an ExchangeRate by swapping base and quote currencies */ static invert(rate: ExchangeRateData): ExchangeRateData { if (rate.rate.amount === 0n) { @@ -291,7 +170,21 @@ export class ExchangeRate implements ExchangeRateData { } /** - * Multiply an ExchangeRate by a scalar or another ExchangeRate + * Instance method to multiply this exchange rate + */ + multiply( + multiplier: FixedPointNumber | string | bigint | ExchangeRate, + ): ExchangeRate { + if (multiplier instanceof ExchangeRate) { + return new ExchangeRate( + ExchangeRate.multiply(this.toData(), multiplier.toData()), + ) + } + return new ExchangeRate(ExchangeRate.multiply(this.toData(), multiplier)) + } + + /** + * Static method to multiply an ExchangeRate by a scalar or another ExchangeRate */ static multiply( rate: ExchangeRateData, @@ -358,7 +251,14 @@ export class ExchangeRate implements ExchangeRateData { } /** - * Convert money from one currency to another using an exchange rate + * Instance method to convert money using this exchange rate + */ + convert(money: import("./money").Money): import("./money").Money { + return ExchangeRate.convert(money, this.toData()) + } + + /** + * Static method to convert money from one currency to another using an exchange rate */ static convert( money: import("./money").Money, @@ -366,10 +266,10 @@ export class ExchangeRate implements ExchangeRateData { ): import("./money").Money { const MoneyClass = require("./money").Money const fromCurrency = money.currency - + // Get the money amount as FixedPointNumber (convert from RationalNumber if needed) - const amount = isFixedPointNumber(money.amount) - ? money.amount + const amount = isFixedPointNumber(money.amount) + ? money.amount : toFixedPointNumber(money.amount) // Check if we can convert directly (from = base, to = quote) @@ -409,6 +309,186 @@ export class ExchangeRate implements ExchangeRateData { ) } + /** + * Instance method to check if this rate is stale + */ + isStale(maxAge: number): boolean { + return ExchangeRate.isStale(this.toData(), maxAge) + } + + /** + * Static method to check if a rate is stale based on its timestamp + */ + static isStale(rate: ExchangeRateData, maxAge: number): boolean { + if (!rate.timestamp) return false + + const now = Date.now() + const rateTime = parseInt(rate.timestamp, 10) + const age = now - rateTime + + return age > maxAge + } + + /** + * Instance method to get the age of this rate + */ + getAge(): number { + return ExchangeRate.getAge(this.toData()) + } + + /** + * Static method to get the age of a rate in milliseconds + */ + static getAge(rate: ExchangeRateData): number { + if (!rate.timestamp) return 0 + + const now = Date.now() + const rateTime = parseInt(rate.timestamp, 10) + return now - rateTime + } + + /** + * Instance method to serialize this rate to JSON + */ + toJSON(): ExchangeRateJSON { + return ExchangeRate.toJSON(this.toData()) + } + + /** + * Static method to serialize an ExchangeRate to JSON + */ + static toJSON(rate: ExchangeRateData): ExchangeRateJSON { + return { + baseCurrency: { + ...rate.baseCurrency, + decimals: rate.baseCurrency.decimals.toString(), + }, + quoteCurrency: { + ...rate.quoteCurrency, + decimals: rate.quoteCurrency.decimals.toString(), + }, + rate: { + amount: rate.rate.amount.toString(), + decimals: rate.rate.decimals.toString(), + }, + timestamp: rate.timestamp, + source: rate.source, + } + } + + /** + * Instance method to format this rate as a string + */ + toString(options?: { + format?: "symbol" | "code" | "ratio" + precision?: number + locale?: string + }): string { + return ExchangeRate.toString(this.toData(), options) + } + + /** + * Static method to format an ExchangeRate as a human-readable string + */ + static toString( + rate: ExchangeRateData, + options?: { + format?: "symbol" | "code" | "ratio" + precision?: number + locale?: string + }, + ): string { + const { format = "symbol", precision = 2, locale = "en-US" } = options || {} + + const rateString = rate.rate.toString() + const numberFormatter = new Intl.NumberFormat(locale, { + minimumFractionDigits: precision, + maximumFractionDigits: precision, + }) + + const formattedRate = numberFormatter.format(rateString) + + const baseSymbol = rate.baseCurrency.symbol || rate.baseCurrency.code + const quoteSymbol = rate.quoteCurrency.symbol || rate.quoteCurrency.code + + if (format === "ratio") { + return `1 ${rate.baseCurrency.code} = ${formattedRate} ${rate.quoteCurrency.code}` + } + + if (format === "code") { + return `${formattedRate} ${rate.quoteCurrency.code}/${rate.baseCurrency.code}` + } + + // Default symbol format + return `${formattedRate} ${quoteSymbol}/${baseSymbol}` + } + + /** + * Apply a spread to create bid/ask rates around this rate + * @param spread - The spread as a FixedPointNumber, decimal string, or percent string + * @returns An object containing bid, ask, and mid rates + */ + spread(spread: FixedPointNumber | string): { + bid: ExchangeRate + ask: ExchangeRate + mid: ExchangeRate + } { + // Parse the spread parameter into a FixedPointNumber + let spreadFixed: FixedPointNumber + if (typeof spread === "string") { + spreadFixed = FixedPoint(spread) + } else { + spreadFixed = spread + } + + // Calculate half the spread for symmetric application + const halfSpread = spreadFixed.divide(new FixedPointNumber(2n, 0n)) + + // Create bid rate: rate - (rate * halfSpread) + const bidRate = this.rate.subtract(this.rate.multiply(halfSpread)) + + // Create ask rate: rate + (rate * halfSpread) + const askRate = this.rate.add(this.rate.multiply(halfSpread)) + + // Create the bid, ask, and mid exchange rates + const bidExchangeRate = new ExchangeRate({ + baseCurrency: this.baseCurrency, + quoteCurrency: this.quoteCurrency, + rate: bidRate, + timestamp: this.timestamp, + source: this.source, + }) + + const askExchangeRate = new ExchangeRate({ + baseCurrency: this.baseCurrency, + quoteCurrency: this.quoteCurrency, + rate: askRate, + timestamp: this.timestamp, + source: this.source, + }) + + const midExchangeRate = new ExchangeRate({ + baseCurrency: this.baseCurrency, + quoteCurrency: this.quoteCurrency, + rate: this.rate, + timestamp: this.timestamp, + source: this.source, + }) + + return { + bid: bidExchangeRate, + ask: askExchangeRate, + mid: midExchangeRate, + } + } + + /** + * Static method to create from JSON + */ + static fromJSON(json: unknown): ExchangeRate { + return new ExchangeRate(ExchangeRate.fromJSONData(json)) + } + /** * Average multiple exchange rates */ @@ -516,104 +596,22 @@ export class ExchangeRate implements ExchangeRateData { } } - /** - * Format an ExchangeRate as a human-readable string - */ - static toString( - rate: ExchangeRateData, - options?: { - format?: "symbol" | "code" | "ratio" - precision?: number - locale?: string - }, - ): string { - const { format = "symbol", precision = 2, locale = "en-US" } = options || {} - - const rateString = rate.rate.toString() - const numberFormatter = new Intl.NumberFormat(locale, { - minimumFractionDigits: precision, - maximumFractionDigits: precision, - }) - - const formattedRate = numberFormatter.format(rateString) - - const baseSymbol = rate.baseCurrency.symbol || rate.baseCurrency.code - const quoteSymbol = rate.quoteCurrency.symbol || rate.quoteCurrency.code - - if (format === "ratio") { - return `1 ${rate.baseCurrency.code} = ${formattedRate} ${rate.quoteCurrency.code}` - } - - if (format === "code") { - return `${formattedRate} ${rate.quoteCurrency.code}/${rate.baseCurrency.code}` - } - - // Default symbol format - return `${formattedRate} ${quoteSymbol}/${baseSymbol}` - } - - /** - * Check if a rate is stale based on its timestamp - */ - static isStale(rate: ExchangeRateData, maxAge: number): boolean { - if (!rate.timestamp) return false - - const now = Date.now() - const rateTime = parseInt(rate.timestamp, 10) - const age = now - rateTime - - return age > maxAge - } - - /** - * Get the age of a rate in milliseconds - */ - static getAge(rate: ExchangeRateData): number { - if (!rate.timestamp) return 0 - - const now = Date.now() - const rateTime = parseInt(rate.timestamp, 10) - return now - rateTime - } - - /** - * Serialize an ExchangeRate to JSON - */ - static toJSON(rate: ExchangeRateData): ExchangeRateJSON { - return { - baseCurrency: { - ...rate.baseCurrency, - decimals: rate.baseCurrency.decimals.toString(), - }, - quoteCurrency: { - ...rate.quoteCurrency, - decimals: rate.quoteCurrency.decimals.toString(), - }, - rate: { - amount: rate.rate.amount.toString(), - decimals: rate.rate.decimals.toString(), - }, - timestamp: rate.timestamp, - source: rate.source, - } - } - /** * Create an ExchangeRate from a Price with configurable precision - * + * * @param price The Price instance to convert * @param options Configuration options for the conversion * @returns A new ExchangeRate instance */ static fromPrice( - price: import('./prices').Price, + price: import("./prices").Price, options: { - decimals: number | bigint, - baseCurrency?: Currency, - roundingMode?: import('./types').RoundingMode, - source?: ExchangeRateSource, + decimals: number | bigint + baseCurrency?: Currency + roundingMode?: import("./types").RoundingMode + source?: ExchangeRateSource timestamp?: UNIXTime | string - } + }, ): ExchangeRate { // Delegate to the Price instance method return price.toExchangeRate(options) diff --git a/src/fixed-point.ts b/src/fixed-point.ts index e3f5898..ef95bfb 100644 --- a/src/fixed-point.ts +++ b/src/fixed-point.ts @@ -1,12 +1,12 @@ import { z } from "zod" +import { getBitSize, isOnlyFactorsOf2And5 } from "./math-utils" import type { - FixedPoint as FixedPointType, - Ratio, DecimalString, + FixedPoint as FixedPointType, FormatOptions, + Ratio, } from "./types" import { RoundingMode } from "./types" -import { isOnlyFactorsOf2And5, getBitSize } from "./math-utils" export const FixedPointJSONSchema = z .string() @@ -711,8 +711,6 @@ export class FixedPointNumber implements FixedPointType, Ratio { return quotient + (isNegative ? -1n : 1n) } return quotient - - case "halfEven": default: // Round to nearest, ties toward even if (doubleRemainder > absDenominator) { diff --git a/src/index.ts b/src/index.ts index 8453e19..08304bf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,87 +1,90 @@ // Import type extensions first import "./types/intl-extensions" +// All currency constants +export * from "./currencies" +// String utilities +export { isDecimalString, toDecimalString } from "./decimal-strings" +export type { + ExchangeRateProvider, + ExchangeRateSource, + RateStalenessConfig, +} from "./exchange-rate-sources" +export { + compareSources, + filterByReliability, + isRateStale, + sortSources, +} from "./exchange-rate-sources" +export type { ExchangeRateData } from "./exchange-rates" +export { ExchangeRate } from "./exchange-rates" +export { + FixedPoint, + FixedPointJSONSchema, + FixedPointNumber, +} from "./fixed-point" // Core classes +// Factory functions export { - MoneyJSONSchema, - Money as MoneyClass, + AnyAssetJSONSchema, AssetJSONSchema, - FungibleAssetJSONSchema, CurrencyJSONSchema, - AnyAssetJSONSchema, + FungibleAssetJSONSchema, + Money as MoneyClass, + MoneyFactory as Money, + MoneyJSONSchema, } from "./money" -export { FixedPointNumber, FixedPointJSONSchema } from "./fixed-point" -export { RationalNumber, RationalNumberJSONSchema, Rational } from "./rationals" +// Money types +export type { MoneyAmount } from "./money/types" +// Money utilities +export { + getComparableValue, + isFixedPointNumber, + isNegative as isMoneyAmountNegative, + isPositive as isMoneyAmountPositive, + isRationalNumber, + isZero as isMoneyAmountZero, + toFixedPointNumber, +} from "./money/utils" +export { + PriceRange as PriceRangeClass, + PriceRangeFactory, + PriceRangeFactory as PriceRange, +} from "./price-range" export { Price } from "./prices" -export { ExchangeRate } from "./exchange-rates" -export { PriceRange as PriceRangeClass, PriceRangeFactory } from "./price-range" -export type { ExchangeRateData } from "./exchange-rates" -export { ExchangeRateSourceUtils } from "./exchange-rate-sources" -export type { - ExchangeRateSource, - ExchangeRateProvider, - RateStalenessConfig, -} from "./exchange-rate-sources" - -// Factory functions -export { MoneyFactory as Money } from "./money" -export { FixedPoint } from "./fixed-point" -export { PriceRangeFactory as PriceRange } from "./price-range" - -// All currency constants -export * from "./currencies" - +export { + getRationalStringType, + isFractionString, + isRationalString, + parseFraction, + toRationalString, +} from "./rational-strings" +export { Rational, RationalNumber, RationalNumberJSONSchema } from "./rationals" // Core types export type { - FixedPoint as FixedPointType, - Ratio, - Asset, - FungibleAsset, - Currency, AnyAsset, + Asset, AssetAmount, + Currency, DecimalString, + FixedPoint as FixedPointType, + FungibleAsset, + PricePoint, + Ratio, RationalString, UNIXTime, UTCTime, - PricePoint, } from "./types" - -// Money types -export type { MoneyAmount } from "./money/types" - -// Money utilities -export { - isFixedPointNumber, - isRationalNumber, - toFixedPointNumber, - getComparableValue, - isZero as isMoneyAmountZero, - isPositive as isMoneyAmountPositive, - isNegative as isMoneyAmountNegative, -} from "./money/utils" - // Rounding modes export { - RoundingMode, CEIL, - FLOOR, EXPAND, - TRUNC, + FLOOR, HALF_CEIL, - HALF_FLOOR, + HALF_EVEN, HALF_EXPAND, + HALF_FLOOR, HALF_TRUNC, - HALF_EVEN, + RoundingMode, + TRUNC, } from "./types" - -// String utilities -export { isDecimalString, toDecimalString } from "./decimal-strings" - -export { - isFractionString, - isRationalString, - toRationalString, - parseFraction, - getRationalStringType, -} from "./rational-strings" diff --git a/src/money/index.ts b/src/money/index.ts index 519805c..7bd8863 100644 --- a/src/money/index.ts +++ b/src/money/index.ts @@ -1,19 +1,19 @@ -import { z, ZodError } from "zod" -import { AssetAmount, FixedPoint, RoundingMode, Currency } from "../types" -import { MoneyAmount } from "./types" -import { FixedPointNumber, FixedPointJSONSchema } from "../fixed-point" -import { RationalNumber, RationalNumberJSONSchema } from "../rationals" +import { type ZodError, z } from "zod" import { assetsEqual, isAssetAmount } from "../assets" +import { FRACTIONAL_UNIT_SYMBOLS, getCurrencyFromCode } from "../currencies" +import { FixedPointJSONSchema, FixedPointNumber } from "../fixed-point" +import { RationalNumber, RationalNumberJSONSchema } from "../rationals" +import type { AssetAmount, Currency, FixedPoint, RoundingMode } from "../types" import { NonNegativeBigIntStringSchema } from "../validation-schemas" import { parseMoneyString } from "./parsing" -import { FRACTIONAL_UNIT_SYMBOLS, getCurrencyFromCode } from "../currencies" +import type { MoneyAmount } from "./types" import { isFixedPointNumber, + isNegative as isMoneyAmountNegative, + isPositive as isMoneyAmountPositive, + isZero as isMoneyAmountZero, isRationalNumber, toFixedPointNumber, - isZero as isMoneyAmountZero, - isPositive as isMoneyAmountPositive, - isNegative as isMoneyAmountNegative, } from "./utils" // Extend Intl.NumberFormatOptions to include roundingMode for older TypeScript versions diff --git a/src/money/parsing.ts b/src/money/parsing.ts index c5a65d8..0fbc809 100644 --- a/src/money/parsing.ts +++ b/src/money/parsing.ts @@ -1,12 +1,12 @@ -import { Currency } from "../types" import { currencies, - PRIMARY_SYMBOL_MAP, - getPrimaryCurrency, FRACTIONAL_UNIT_SYMBOLS, getFractionalUnitInfo, + getPrimaryCurrency, + PRIMARY_SYMBOL_MAP, } from "../currencies" import { FixedPointNumber } from "../fixed-point" +import type { Currency } from "../types" /** * Result of parsing a money string @@ -384,7 +384,10 @@ function tryParseFractionalUnitSymbol(input: string): MoneyParseResult | null { if (cleanInput.startsWith(symbol)) { const amountStr = cleanInput.slice(symbol.length).trim() if (amountStr) { - const fractionalInfo = getFractionalUnitInfo(symbol)! + const fractionalInfo = getFractionalUnitInfo(symbol) + if (!fractionalInfo) { + continue + } const { currency, decimals } = fractionalInfo // Parse the number (fractional units are typically integers) @@ -433,7 +436,10 @@ function tryParseSymbol(input: string): MoneyParseResult | null { if (cleanInput.startsWith(symbol)) { const amountStr = cleanInput.slice(symbol.length).trim() if (amountStr) { - const currency = getPrimaryCurrency(symbol)! + const currency = getPrimaryCurrency(symbol) + if (!currency) { + continue + } const format = detectNumberFormat(amountStr, currency) let parsed = parseNumber(amountStr, format) @@ -453,7 +459,10 @@ function tryParseSymbol(input: string): MoneyParseResult | null { if (cleanInput.endsWith(symbol)) { const amountStr = cleanInput.slice(0, -symbol.length).trim() if (amountStr) { - const currency = getPrimaryCurrency(symbol)! + const currency = getPrimaryCurrency(symbol) + if (!currency) { + continue + } const format = detectNumberFormat(amountStr, currency) let parsed = parseNumber(amountStr, format) diff --git a/src/money/types.ts b/src/money/types.ts index d7bb2fe..c13f50c 100644 --- a/src/money/types.ts +++ b/src/money/types.ts @@ -1,5 +1,5 @@ -import { FixedPointNumber } from "../fixed-point" -import { RationalNumber } from "../rationals" +import type { FixedPointNumber } from "../fixed-point" +import type { RationalNumber } from "../rationals" /** * Union type for Money amounts that can be either precise fixed-point or exact rational numbers diff --git a/src/price-range.ts b/src/price-range.ts index 01904ee..d7a419a 100644 --- a/src/price-range.ts +++ b/src/price-range.ts @@ -1,12 +1,12 @@ +import { assetsEqual } from "./assets" +import type { ExchangeRate } from "./exchange-rates" +import { FixedPoint } from "./fixed-point" import { - Money as MoneyClass, MoneyFactory as Money, - MoneyToStringOptions, + Money as MoneyClass, + type MoneyToStringOptions, } from "./money" -import { Currency } from "./types" -import { assetsEqual } from "./assets" -import { ExchangeRate } from "./exchange-rates" -import { FixedPoint } from "./fixed-point" +import type { Currency } from "./types" /** * Options for formatting PriceRange instances to strings @@ -308,8 +308,6 @@ export class PriceRange { case "between": return `Between ${minStr} and ${maxStr}` - - case "default": default: return `${minStr} - ${maxStr}` } @@ -455,20 +453,20 @@ function parsePriceRangeString(rangeStr: string): { try { min = Money(minStr.trim()) - } catch (error) { + } catch (_error) { throw new Error(`Invalid minimum price: "${minStr.trim()}"`) } // For compact format like "$50-100", the max part might not have currency symbol try { max = Money(maxStr.trim()) - } catch (error) { + } catch (_error) { // Try adding the same currency as min const minCurrency = min.currency if ("symbol" in minCurrency && minCurrency.symbol) { try { max = Money(`${minCurrency.symbol}${maxStr.trim()}`) - } catch (symbolError) { + } catch (_symbolError) { if ("code" in minCurrency && minCurrency.code) { max = Money(`${minCurrency.code} ${maxStr.trim()}`) } else { diff --git a/src/prices.ts b/src/prices.ts index 3bb15ac..abea9cc 100644 --- a/src/prices.ts +++ b/src/prices.ts @@ -1,10 +1,18 @@ -import { AssetAmount, FixedPoint, Ratio, UNIXTime, AnyAsset, Currency, RoundingMode } from "./types" -import { Money as MoneyClass } from "./money" import { assetsEqual } from "./assets" +import type { ExchangeRateSource } from "./exchange-rate-sources" +import { FixedPointNumber } from "./fixed-point" +import { Money as MoneyClass } from "./money" import { RationalNumber } from "./rationals" import { nowUNIXTime, toUNIXTime } from "./time" -import { FixedPointNumber } from "./fixed-point" -import type { ExchangeRateSource } from "./exchange-rate-sources" +import type { + AnyAsset, + AssetAmount, + Currency, + FixedPoint, + Ratio, + RoundingMode, + UNIXTime, +} from "./types" /** * Price class for representing price ratios between assets @@ -220,31 +228,35 @@ export class Price { /** * Convert this Price to an ExchangeRate with configurable precision - * + * * @param options Configuration options for the conversion * @returns A new ExchangeRate instance */ toExchangeRate(options?: { - decimals?: number | bigint, - baseCurrency?: Currency, - roundingMode?: RoundingMode, - source?: ExchangeRateSource, + decimals?: number | bigint + baseCurrency?: Currency + roundingMode?: RoundingMode + source?: ExchangeRateSource timestamp?: UNIXTime | string - }): import('./exchange-rates').ExchangeRate { - const ExchangeRateClass = require('./exchange-rates').ExchangeRate - + }): import("./exchange-rates").ExchangeRate { + const ExchangeRateClass = require("./exchange-rates").ExchangeRate + // Validate that both assets are currencies const currency1 = this.amounts[0].asset as Currency const currency2 = this.amounts[1].asset as Currency - - if (!('code' in currency1) || !('code' in currency2)) { - throw new Error('Cannot create ExchangeRate: both assets must be currencies with codes') + + if (!("code" in currency1) || !("code" in currency2)) { + throw new Error( + "Cannot create ExchangeRate: both assets must be currencies with codes", + ) } - + // Check for identical currencies if (assetsEqual(currency1, currency2)) { const code = currency1.code || currency1.name - throw new Error(`Cannot create ExchangeRate: both currencies are the same (${code})`) + throw new Error( + `Cannot create ExchangeRate: both currencies are the same (${code})`, + ) } // Determine base/quote currencies using "best" currency logic @@ -258,23 +270,33 @@ export class Price { baseCurrency = currency1 quoteCurrency = currency2 // Rate = amount2 / amount1 (how much of currency2 per 1 unit of currency1) - rate = this.calculateExchangeRate(this.amounts[1], this.amounts[0], options.decimals) + rate = this.calculateExchangeRate( + this.amounts[1], + this.amounts[0], + options.decimals, + ) } else if (assetsEqual(options.baseCurrency, currency2)) { baseCurrency = currency2 quoteCurrency = currency1 // Rate = amount1 / amount2 (how much of currency1 per 1 unit of currency2) - rate = this.calculateExchangeRate(this.amounts[0], this.amounts[1], options.decimals) + rate = this.calculateExchangeRate( + this.amounts[0], + this.amounts[1], + options.decimals, + ) } else { const baseName = options.baseCurrency.code || options.baseCurrency.name const curr1Name = currency1.code || currency1.name const curr2Name = currency2.code || currency2.name - throw new Error(`Specified baseCurrency (${baseName}) does not match either price currency (${curr1Name}, ${curr2Name})`) + throw new Error( + `Specified baseCurrency (${baseName}) does not match either price currency (${curr1Name}, ${curr2Name})`, + ) } } else { // Auto-select best currency as base (closest to 1) - const ratio1 = this.getAmountRatio(this.amounts[0]) // currency1 amount - const ratio2 = this.getAmountRatio(this.amounts[1]) // currency2 amount - + const ratio1 = this.getAmountRatio(this.amounts[0]) // currency1 amount + const ratio2 = this.getAmountRatio(this.amounts[1]) // currency2 amount + const distance1 = this.distanceFromOne(ratio1) const distance2 = this.distanceFromOne(ratio2) @@ -282,25 +304,37 @@ export class Price { // currency2 is closer to 1, make it base baseCurrency = currency2 quoteCurrency = currency1 - rate = this.calculateExchangeRate(this.amounts[0], this.amounts[1], options?.decimals) + rate = this.calculateExchangeRate( + this.amounts[0], + this.amounts[1], + options?.decimals, + ) } else if (distance1 < distance2) { // currency1 is closer to 1, make it base baseCurrency = currency1 quoteCurrency = currency2 - rate = this.calculateExchangeRate(this.amounts[1], this.amounts[0], options?.decimals) + rate = this.calculateExchangeRate( + this.amounts[1], + this.amounts[0], + options?.decimals, + ) } else { // Equal distances, use argument order (second becomes base) baseCurrency = currency2 quoteCurrency = currency1 - rate = this.calculateExchangeRate(this.amounts[0], this.amounts[1], options?.decimals) + rate = this.calculateExchangeRate( + this.amounts[0], + this.amounts[1], + options?.decimals, + ) } } // Set up default source metadata const defaultSource: ExchangeRateSource = { - name: 'Converted from Price', + name: "Converted from Price", priority: 3, - reliability: 0.8 + reliability: 0.8, } // Create the ExchangeRate @@ -309,7 +343,7 @@ export class Price { quoteCurrency, rate, timestamp: options?.timestamp || this.time, - source: options?.source || defaultSource + source: options?.source || defaultSource, }) } @@ -319,7 +353,7 @@ export class Price { private calculateExchangeRate( numeratorAmount: AssetAmount, denominatorAmount: AssetAmount, - decimals?: number | bigint + decimals?: number | bigint, ): FixedPointNumber { // Use RationalNumber for precise calculation const numeratorRational = new RationalNumber({ @@ -337,25 +371,33 @@ export class Price { // Determine target decimals let targetDecimals: bigint if (decimals !== undefined) { - targetDecimals = typeof decimals === 'bigint' ? decimals : BigInt(decimals) + targetDecimals = + typeof decimals === "bigint" ? decimals : BigInt(decimals) } else { // Default to max decimals of the two currencies - const curr1Decimals = 'decimals' in numeratorAmount.asset ? numeratorAmount.asset.decimals : 8n - const curr2Decimals = 'decimals' in denominatorAmount.asset ? denominatorAmount.asset.decimals : 8n - targetDecimals = curr1Decimals > curr2Decimals ? curr1Decimals : curr2Decimals + const curr1Decimals = + "decimals" in numeratorAmount.asset + ? numeratorAmount.asset.decimals + : 8n + const curr2Decimals = + "decimals" in denominatorAmount.asset + ? denominatorAmount.asset.decimals + : 8n + targetDecimals = + curr1Decimals > curr2Decimals ? curr1Decimals : curr2Decimals } // Convert to FixedPointNumber with target precision const fixedPoint = rateRational.toFixedPoint({ maxBits: 256 }) - + // Normalize to target decimals const result = new FixedPointNumber(fixedPoint.amount, fixedPoint.decimals) const target = new FixedPointNumber(0n, targetDecimals) const normalizedResult = result.normalize(target) - + // Check for significant precision loss and warn this.checkPrecisionLoss(rateRational, normalizedResult, targetDecimals) - + return normalizedResult } @@ -381,7 +423,7 @@ export class Price { private checkPrecisionLoss( originalRational: RationalNumber, convertedFixed: FixedPointNumber, - targetDecimals: bigint + targetDecimals: bigint, ): void { // Convert the fixed point result back to rational for comparison const convertedRational = new RationalNumber({ @@ -392,22 +434,26 @@ export class Price { // Calculate relative error const difference = originalRational.subtract(convertedRational) const relativeError = difference.divide(originalRational) - + // Convert to decimal for comparison (using high precision) - const errorDecimal = Math.abs(parseFloat(relativeError.toDecimalString(20n))) - + const errorDecimal = Math.abs( + parseFloat(relativeError.toDecimalString(20n)), + ) + // Warn if precision loss is significant (> 0.01% or 0.0001) const significantThreshold = 0.0001 if (errorDecimal > significantThreshold) { const currency1 = this.amounts[0].asset const currency2 = this.amounts[1].asset - const curr1Name = ('code' in currency1 ? currency1.code : currency1.name) || 'Unknown' - const curr2Name = ('code' in currency2 ? currency2.code : currency2.name) || 'Unknown' - + const curr1Name = + ("code" in currency1 ? currency1.code : currency1.name) || "Unknown" + const curr2Name = + ("code" in currency2 ? currency2.code : currency2.name) || "Unknown" + console.warn( `Warning: Significant precision loss detected when converting Price (${curr1Name}/${curr2Name}) to ExchangeRate with ${targetDecimals} decimals. ` + - `Relative error: ${(errorDecimal * 100).toFixed(4)}%. ` + - `Consider using higher decimal precision for more accuracy.` + `Relative error: ${(errorDecimal * 100).toFixed(4)}%. ` + + `Consider using higher decimal precision for more accuracy.`, ) } } diff --git a/src/rational-strings.ts b/src/rational-strings.ts index 8ea278e..11ec30a 100644 --- a/src/rational-strings.ts +++ b/src/rational-strings.ts @@ -1,5 +1,5 @@ import { z } from "zod" -import { RationalString, Ratio } from "./types" +import type { Ratio, RationalString } from "./types" /** * Zod schema for validating fraction strings diff --git a/src/rationals.ts b/src/rationals.ts index e1cc8cb..29b8cf6 100644 --- a/src/rationals.ts +++ b/src/rationals.ts @@ -1,16 +1,16 @@ import { z } from "zod" +import { FixedPointNumber } from "./fixed-point" +import { gcd, getBitSize } from "./math-utils" +import { getRationalStringType, parseFraction } from "./rational-strings" import { - Ratio, - FixedPoint, - DecimalString, - RationalString, - LossyConversionOptions, + type DecimalString, + type FixedPoint, + type LossyConversionOptions, + type Ratio, + type RationalString, RoundingMode, } from "./types" -import { gcd, getBitSize } from "./math-utils" import { BigIntStringSchema } from "./validation-schemas" -import { FixedPointNumber } from "./fixed-point" -import { parseFraction, getRationalStringType } from "./rational-strings" export const RationalNumberJSONSchema = z.object({ p: BigIntStringSchema, @@ -100,8 +100,6 @@ function applyRounding( return quotient + (isNegative ? -1n : 1n) } return quotient - - case RoundingMode.HALF_EVEN: default: // Round to nearest, ties toward even if (doubleRemainder > absDenominator) { diff --git a/src/time.ts b/src/time.ts index 38379d9..ec8fc85 100644 --- a/src/time.ts +++ b/src/time.ts @@ -1,5 +1,5 @@ import { z } from "zod" -import { UNIXTime, UTCTime } from "./types" +import type { UNIXTime, UTCTime } from "./types" /** * Zod schema for validating UNIX timestamps diff --git a/test/convert.test.ts b/test/convert.test.ts index 3e9dc99..f9ac430 100644 --- a/test/convert.test.ts +++ b/test/convert.test.ts @@ -1,5 +1,5 @@ import { Money, Price } from "../src" -import { USD, BTC } from "../src/currencies" +import { BTC, USD } from "../src/currencies" describe("Money.convert()", () => { it("should convert USD to BTC using a price (example from requirements)", () => { diff --git a/test/decimal-strings.test.ts b/test/decimal-strings.test.ts index 78d09f4..a4ff2c3 100644 --- a/test/decimal-strings.test.ts +++ b/test/decimal-strings.test.ts @@ -3,7 +3,7 @@ import { isDecimalString, toDecimalString, } from "../src/decimal-strings" -import { DecimalString } from "../src/types" +import type { DecimalString } from "../src/types" describe("DecimalString utilities", () => { describe("DecimalStringSchema", () => { diff --git a/test/exchange-rates.test.ts b/test/exchange-rates.test.ts index 52283a1..ac600fc 100644 --- a/test/exchange-rates.test.ts +++ b/test/exchange-rates.test.ts @@ -1,14 +1,15 @@ /* eslint-disable max-classes-per-file */ -import { Currency } from "../src/types" -import { FixedPointNumber } from "../src/fixed-point" -import { - ExchangeRateSource, + +import type { ExchangeRateProvider, + ExchangeRateSource, } from "../src/exchange-rate-sources" -import { nowUNIXTime } from "../src/time" -import { ExchangeRate, ExchangeRateData } from "../src/exchange-rates" +import { ExchangeRate, type ExchangeRateData } from "../src/exchange-rates" +import { FixedPointNumber } from "../src/fixed-point" import { Money } from "../src/money" import { Price } from "../src/prices" +import { nowUNIXTime } from "../src/time" +import type { Currency } from "../src/types" describe("ExchangeRate", () => { // Test currencies @@ -152,7 +153,7 @@ describe("ExchangeRate", () => { // Test individual arguments constructor with string timestamp const stringTimestamp = "1609459200000" // 2021-01-01 in milliseconds const rate1 = new ExchangeRate(USD, EUR, "1.08", stringTimestamp) - + expect(rate1.timestamp).toBe(stringTimestamp) expect(typeof rate1.timestamp).toBe("string") @@ -164,7 +165,7 @@ describe("ExchangeRate", () => { timestamp: stringTimestamp, } const rate2 = new ExchangeRate(data) - + expect(rate2.timestamp).toBe(stringTimestamp) expect(typeof rate2.timestamp).toBe("string") }) @@ -172,7 +173,7 @@ describe("ExchangeRate", () => { it("should throw error for invalid string timestamp", () => { // Test invalid string timestamp const invalidTimestamp = "invalid-timestamp" - + expect(() => { new ExchangeRate(USD, EUR, "1.08", invalidTimestamp) }).toThrow("Invalid UNIX timestamp") @@ -327,7 +328,9 @@ describe("ExchangeRate", () => { expect(averaged.baseCurrency).toBe(USD) expect(averaged.quoteCurrency).toBe(EUR) - expect(averaged.rate.toString()).toBe("1.1000000000000000000000000000000000000000000000000") // (1.00 + 1.20) / 2 + expect(averaged.rate.toString()).toBe( + "1.1000000000000000000000000000000000000000000000000", + ) // (1.00 + 1.20) / 2 }) it("should average three compatible rates", () => { @@ -355,7 +358,9 @@ describe("ExchangeRate", () => { expect(averaged.baseCurrency).toBe(USD) expect(averaged.quoteCurrency).toBe(EUR) - expect(averaged.rate.toString()).toBe("1.2333333333333333333333333333333333333333333333333") // (1.00 + 1.20 + 1.50) / 3 + expect(averaged.rate.toString()).toBe( + "1.2333333333333333333333333333333333333333333333333", + ) // (1.00 + 1.20 + 1.50) / 3 }) it("should average seven compatible rates", () => { @@ -370,19 +375,21 @@ describe("ExchangeRate", () => { ] const averaged = new ExchangeRate( - ExchangeRate.average(rates.map(r => r.toData())), + ExchangeRate.average(rates.map((r) => r.toData())), ) expect(averaged.baseCurrency).toBe(USD) expect(averaged.quoteCurrency).toBe(EUR) - expect(averaged.rate.toString()).toBe("1.3000000000000000000000000000000000000000000000000") // (1.00 + 1.10 + 1.20 + 1.30 + 1.40 + 1.50 + 1.60) / 7 + expect(averaged.rate.toString()).toBe( + "1.3000000000000000000000000000000000000000000000000", + ) // (1.00 + 1.10 + 1.20 + 1.30 + 1.40 + 1.50 + 1.60) / 7 }) it("should not error when averaging rates where length is not divisible by 2 or 5", () => { // This test specifically addresses the bug where averaging 3 or 7 rates would error // because the old implementation used FixedPointNumber.divide(BigInt) which only supports // divisors that are factors of 2 and 5. The fix uses RationalNumber for division. - + const rates = [ new ExchangeRate(USD, EUR, new FixedPointNumber(100n, 2n)), new ExchangeRate(USD, EUR, new FixedPointNumber(110n, 2n)), @@ -399,12 +406,12 @@ describe("ExchangeRate", () => { // Test various problematic lengths (not divisible by 2 or 5) const problematicLengths = [3, 7, 9, 11] - - problematicLengths.forEach(length => { + + problematicLengths.forEach((length) => { const subset = rates.slice(0, length) expect(() => { const averaged = new ExchangeRate( - ExchangeRate.average(subset.map(r => r.toData())), + ExchangeRate.average(subset.map((r) => r.toData())), ) expect(averaged.baseCurrency).toBe(USD) expect(averaged.quoteCurrency).toBe(EUR) @@ -883,12 +890,12 @@ describe("ExchangeRate", () => { // $50,000 per 1 BTC - BTC should become base const price = new Price( { asset: USD, amount: { amount: 5000000n, decimals: 2n } }, // $50,000 - { asset: BTC, amount: { amount: 100000000n, decimals: 8n } } // 1 BTC + { asset: BTC, amount: { amount: 100000000n, decimals: 8n } }, // 1 BTC ) const rate = ExchangeRate.fromPrice(price, { decimals: 2 }) - expect(rate.baseCurrency).toBe(BTC) // BTC is base + expect(rate.baseCurrency).toBe(BTC) // BTC is base expect(rate.quoteCurrency).toBe(USD) // USD is quote expect(rate.rate.toString()).toBe("50000.00") // 1 BTC = $50,000.00 }) @@ -896,20 +903,20 @@ describe("ExchangeRate", () => { it("should create exchange rate with custom options", () => { const price = new Price( { asset: USD, amount: { amount: 5000000n, decimals: 2n } }, - { asset: BTC, amount: { amount: 100000000n, decimals: 8n } } + { asset: BTC, amount: { amount: 100000000n, decimals: 8n } }, ) const customSource = { name: "Custom Static Source", priority: 1, - reliability: 0.99 + reliability: 0.99, } const rate = ExchangeRate.fromPrice(price, { decimals: 8, baseCurrency: USD, // Force USD as base source: customSource, - timestamp: "1640995200000" + timestamp: "1640995200000", }) expect(rate.baseCurrency).toBe(USD) diff --git a/test/factory-functions.test.ts b/test/factory-functions.test.ts index 7a8de88..618a7d0 100644 --- a/test/factory-functions.test.ts +++ b/test/factory-functions.test.ts @@ -1,7 +1,7 @@ import { FixedPoint, - Rational, FixedPointNumber, + Rational, RationalNumber, } from "../src/index" diff --git a/test/fixed-point.test.ts b/test/fixed-point.test.ts index 526f338..5f15ec1 100644 --- a/test/fixed-point.test.ts +++ b/test/fixed-point.test.ts @@ -1,9 +1,9 @@ import { - FixedPointNumber, - FixedPointJSONSchema, FixedPoint, + FixedPointJSONSchema, + FixedPointNumber, } from "../src/fixed-point" -import { RoundingMode } from "../src/types" +import { type DecimalString, RoundingMode } from "../src/types" describe("FixedPointNumber", () => { describe("constructor", () => { @@ -37,10 +37,10 @@ describe("FixedPointNumber", () => { it("should maintain immutability when copying from FixedPoint objects", () => { const fixedPoint = { amount: 789n, decimals: 4n } const fp = new FixedPointNumber(fixedPoint) - + // Modify the original object fixedPoint.amount = 999n - + // FixedPointNumber should be unaffected expect(fp.amount).toBe(789n) expect(fp.decimals).toBe(4n) @@ -592,43 +592,59 @@ describe("FixedPointNumber", () => { describe("combined formatting options", () => { it("should work with both asPercentage and trailingZeroes: false", () => { const fp = new FixedPointNumber(2500n, 4n) // 0.2500 - expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe("25%") + expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe( + "25%", + ) }) it("should handle percentage with some trailing zeros removed", () => { const fp = new FixedPointNumber(2540n, 4n) // 0.2540 - expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe("25.4%") + expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe( + "25.4%", + ) }) it("should handle percentage with no trailing zeros to remove", () => { const fp = new FixedPointNumber(2545n, 4n) // 0.2545 - expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe("25.45%") + expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe( + "25.45%", + ) }) it("should handle negative percentages with trailing zeros", () => { const fp = new FixedPointNumber(-2500n, 4n) // -0.2500 - expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe("-25%") + expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe( + "-25%", + ) }) it("should handle zero percentage with trailing zeros", () => { const fp = new FixedPointNumber(0n, 4n) // 0.0000 - expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe("0%") + expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe( + "0%", + ) }) it("should handle whole number percentages", () => { const fp = new FixedPointNumber(100n, 2n) // 1.00 - expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe("100%") + expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe( + "100%", + ) }) it("should handle high precision percentages with trailing zeros", () => { const fp = new FixedPointNumber(123450n, 8n) // 0.00123450 - expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe("0.12345%") + expect(fp.toString({ asPercentage: true, trailingZeroes: false })).toBe( + "0.12345%", + ) }) it("should preserve trailing zeros in percentage by default", () => { const fp = new FixedPointNumber(2500n, 4n) // 0.2500 expect(fp.toString({ asPercentage: true })).toBe("25.0000%") - expect(fp.toString({ asPercentage: true, trailingZeroes: true })).toBe("25.0000%") + expect(fp.toString({ asPercentage: true, trailingZeroes: true })).toBe( + "25.0000%", + ) }) }) }) @@ -1388,7 +1404,7 @@ describe("FixedPoint factory function", () => { }) it("should work with DecimalString type", () => { - const decimalStr = "1.5" as any // Simulating DecimalString + const decimalStr = "1.5" as DecimalString const fp = FixedPoint(decimalStr) expect(fp.amount).toBe(15n) expect(fp.decimals).toBe(1n) @@ -1491,7 +1507,7 @@ describe("FixedPoint factory function", () => { const original = FixedPoint("25.5%") const asPercentage = original.toString({ asPercentage: true }) expect(asPercentage).toBe("25.500%") - + const roundTrip = FixedPoint(asPercentage) expect(roundTrip.equals(original)).toBe(true) }) @@ -1528,7 +1544,7 @@ describe("FixedPoint factory function", () => { }) it("should throw when decimals parameter is missing", () => { - expect(() => FixedPoint(123n as any)).toThrow( + expect(() => FixedPoint(123n as unknown as string)).toThrow( "decimals parameter is required", ) }) @@ -1577,8 +1593,8 @@ describe("FixedPoint factory function", () => { describe("equivalence with constructor", () => { it("should produce same results as constructor for bigint mode", () => { const factory = FixedPoint(12345n, 3n) - const constructor = new FixedPointNumber(12345n, 3n) - expect(factory.equals(constructor)).toBe(true) + const fromConstructor = new FixedPointNumber(12345n, 3n) + expect(factory.equals(fromConstructor)).toBe(true) }) it("should produce same results as fromDecimalString for string mode", () => { @@ -1901,8 +1917,9 @@ describe("FixedPoint factory function", () => { const largeAmount = BigInt("12345678901234567890") const largeDecimals = BigInt("18") const fp = new FixedPointNumber(largeAmount, largeDecimals) - - const expectedBits = largeAmount.toString(2).length + largeDecimals.toString(2).length + + const expectedBits = + largeAmount.toString(2).length + largeDecimals.toString(2).length expect(fp.getBitSize()).toBe(expectedBits) }) @@ -1917,10 +1934,13 @@ describe("FixedPoint factory function", () => { testCases.forEach(({ amount, decimals }) => { const fp = new FixedPointNumber(amount, decimals) - const amountBits = amount === 0n ? 0 : (amount < 0n ? -amount : amount).toString(2).length + const amountBits = + amount === 0n + ? 0 + : (amount < 0n ? -amount : amount).toString(2).length const decimalsBits = decimals === 0n ? 0 : decimals.toString(2).length const expectedBits = amountBits + decimalsBits - + expect(fp.getBitSize()).toBe(expectedBits) }) }) @@ -1930,19 +1950,20 @@ describe("FixedPoint factory function", () => { const amount = BigInt(Number.MAX_SAFE_INTEGER) * 2n const decimals = 15n const fp = new FixedPointNumber(amount, decimals) - - const expectedBits = amount.toString(2).length + decimals.toString(2).length + + const expectedBits = + amount.toString(2).length + decimals.toString(2).length expect(fp.getBitSize()).toBe(expectedBits) }) it("should reflect changes after normalization", () => { const fp1 = new FixedPointNumber(1230n, 3n) // 1.230 - const fp2 = new FixedPointNumber(123n, 2n) // 1.23 - + const fp2 = new FixedPointNumber(123n, 2n) // 1.23 + const originalBitSize = fp2.getBitSize() const normalized = fp2.normalize(fp1) // normalize fp2 to 3 decimals -> 1230, 3 const normalizedBitSize = normalized.getBitSize() - + // Normalized version should have potentially different bit size expect(normalizedBitSize).toBeGreaterThanOrEqual(originalBitSize) expect(normalized.amount).toBe(1230n) @@ -1957,7 +1978,7 @@ describe("FixedPoint factory function", () => { // toPrecision(5) should give 1.2345 = 12345n with 5 decimals const fp = new FixedPointNumber(1234567890n, 10n) const result = fp.toPrecision(5n) - + expect(result.amount).toBe(12345n) expect(result.decimals).toBe(5n) }) @@ -1967,7 +1988,7 @@ describe("FixedPoint factory function", () => { // should equal { amount: 12345n, decimals: 5n } const fp = new FixedPointNumber(1234567890n, 10n) const result = fp.toPrecision(5n, { roundingMode: RoundingMode.TRUNC }) - + expect(result.amount).toBe(12345n) expect(result.decimals).toBe(5n) expect(result.equals({ amount: 12345n, decimals: 5n })).toBe(true) @@ -1977,7 +1998,7 @@ describe("FixedPoint factory function", () => { // 0.000123 with precision 2 should give 0.00012 const fp = new FixedPointNumber(123n, 6n) // 0.000123 const result = fp.toPrecision(2n) - + expect(result.amount).toBe(12n) expect(result.decimals).toBe(5n) // 0.00012 = 12n with 5 decimals }) @@ -1986,7 +2007,7 @@ describe("FixedPoint factory function", () => { // 12345.67 with precision 3 should give 123 (with appropriate decimals) const fp = new FixedPointNumber(1234567n, 2n) // 12345.67 const result = fp.toPrecision(3n) - + expect(result.amount).toBe(123n) expect(result.decimals).toBe(-2n) // 123 * 10^2 = 12300 }) @@ -1995,7 +2016,7 @@ describe("FixedPoint factory function", () => { // 1.23 with precision 3 should remain 1.23 const fp = new FixedPointNumber(123n, 2n) // 1.23 const result = fp.toPrecision(3n) - + expect(result.amount).toBe(123n) expect(result.decimals).toBe(2n) }) @@ -2004,7 +2025,7 @@ describe("FixedPoint factory function", () => { // 1.5 with precision 5 should give 1.5000 const fp = new FixedPointNumber(15n, 1n) // 1.5 const result = fp.toPrecision(5n) - + expect(result.amount).toBe(15000n) expect(result.decimals).toBe(4n) }) @@ -2015,7 +2036,7 @@ describe("FixedPoint factory function", () => { // 1.999 with precision 2 should give 1.9 with TRUNC const fp = new FixedPointNumber(1999n, 3n) // 1.999 const result = fp.toPrecision(2n) - + expect(result.amount).toBe(19n) expect(result.decimals).toBe(1n) // 1.9 }) @@ -2024,7 +2045,7 @@ describe("FixedPoint factory function", () => { // 1.231 with precision 2 should give 1.3 with CEIL const fp = new FixedPointNumber(1231n, 3n) // 1.231 const result = fp.toPrecision(2n, { roundingMode: RoundingMode.CEIL }) - + expect(result.amount).toBe(13n) expect(result.decimals).toBe(1n) // 1.3 }) @@ -2033,7 +2054,7 @@ describe("FixedPoint factory function", () => { // 1.999 with precision 2 should give 1.9 with FLOOR const fp = new FixedPointNumber(1999n, 3n) // 1.999 const result = fp.toPrecision(2n, { roundingMode: RoundingMode.FLOOR }) - + expect(result.amount).toBe(19n) expect(result.decimals).toBe(1n) // 1.9 }) @@ -2041,8 +2062,10 @@ describe("FixedPoint factory function", () => { it("should support HALF_EVEN rounding mode", () => { // 1.225 with precision 3 should give 1.22 with HALF_EVEN (banker's rounding) const fp = new FixedPointNumber(1225n, 3n) // 1.225 - const result = fp.toPrecision(3n, { roundingMode: RoundingMode.HALF_EVEN }) - + const result = fp.toPrecision(3n, { + roundingMode: RoundingMode.HALF_EVEN, + }) + expect(result.amount).toBe(122n) expect(result.decimals).toBe(2n) // 1.22 }) @@ -2051,7 +2074,7 @@ describe("FixedPoint factory function", () => { // 1.231 with precision 2 should give 1.3 with EXPAND (away from zero) const fp = new FixedPointNumber(1231n, 3n) // 1.231 const result = fp.toPrecision(2n, { roundingMode: RoundingMode.EXPAND }) - + expect(result.amount).toBe(13n) expect(result.decimals).toBe(1n) // 1.3 }) @@ -2062,7 +2085,7 @@ describe("FixedPoint factory function", () => { // -1.999 with precision 2 should give -1.9 with TRUNC const fp = new FixedPointNumber(-1999n, 3n) // -1.999 const result = fp.toPrecision(2n, { roundingMode: RoundingMode.TRUNC }) - + expect(result.amount).toBe(-19n) expect(result.decimals).toBe(1n) // -1.9 }) @@ -2071,7 +2094,7 @@ describe("FixedPoint factory function", () => { // -1.231 with precision 2 should give -1.2 with CEIL (toward positive infinity) const fp = new FixedPointNumber(-1231n, 3n) // -1.231 const result = fp.toPrecision(2n, { roundingMode: RoundingMode.CEIL }) - + expect(result.amount).toBe(-12n) expect(result.decimals).toBe(1n) // -1.2 }) @@ -2080,7 +2103,7 @@ describe("FixedPoint factory function", () => { // -1.231 with precision 2 should give -1.3 with FLOOR (toward negative infinity) const fp = new FixedPointNumber(-1231n, 3n) // -1.231 const result = fp.toPrecision(2n, { roundingMode: RoundingMode.FLOOR }) - + expect(result.amount).toBe(-13n) expect(result.decimals).toBe(1n) // -1.3 }) @@ -2090,7 +2113,7 @@ describe("FixedPoint factory function", () => { it("should handle zero", () => { const fp = new FixedPointNumber(0n, 5n) // 0.00000 const result = fp.toPrecision(3n) - + expect(result.amount).toBe(0n) expect(result.decimals).toBe(0n) // Just 0 }) @@ -2099,7 +2122,7 @@ describe("FixedPoint factory function", () => { // 0.0000001 with precision 1 should give 0.0000001 (1 significant digit) const fp = new FixedPointNumber(1n, 7n) // 0.0000001 const result = fp.toPrecision(1n) - + expect(result.amount).toBe(1n) expect(result.decimals).toBe(7n) // 0.0000001 }) @@ -2108,7 +2131,7 @@ describe("FixedPoint factory function", () => { // 12000 with precision 2 should give 12000 (represented as 12 * 10^3) const fp = new FixedPointNumber(12000n, 0n) // 12000 const result = fp.toPrecision(2n) - + expect(result.amount).toBe(12n) expect(result.decimals).toBe(-3n) // 12 * 10^3 = 12000 }) @@ -2117,7 +2140,7 @@ describe("FixedPoint factory function", () => { // 12.345 with precision 1 should give 1 * 10^1 = 10 const fp = new FixedPointNumber(12345n, 3n) // 12.345 const result = fp.toPrecision(1n) - + expect(result.amount).toBe(1n) expect(result.decimals).toBe(-1n) // 1 * 10^1 = 10 }) @@ -2126,7 +2149,7 @@ describe("FixedPoint factory function", () => { // Test with precision larger than current digits const fp = new FixedPointNumber(123n, 2n) // 1.23 const result = fp.toPrecision(10n) - + expect(result.amount).toBe(1230000000n) expect(result.decimals).toBe(9n) // 1.230000000 }) @@ -2135,20 +2158,22 @@ describe("FixedPoint factory function", () => { describe("error handling", () => { it("should throw error for zero precision", () => { const fp = new FixedPointNumber(123n, 2n) - + expect(() => fp.toPrecision(0n)).toThrow("precision must be positive") }) it("should throw error for negative precision", () => { const fp = new FixedPointNumber(123n, 2n) - + expect(() => fp.toPrecision(-1n)).toThrow("precision must be positive") }) it("should throw error for precision exceeding maximum", () => { const fp = new FixedPointNumber(123n, 2n) - - expect(() => fp.toPrecision(51n)).toThrow("precision must be between 1 and 50") + + expect(() => fp.toPrecision(51n)).toThrow( + "precision must be between 1 and 50", + ) }) }) @@ -2157,7 +2182,7 @@ describe("FixedPoint factory function", () => { const fp = new FixedPointNumber(314159n, 5n) // 3.14159 const result2 = fp.toPrecision(2n) // Should be 3.1 const result3 = fp.toPrecision(3n) // Should be 3.14 - + expect(result2.amount).toBe(31n) expect(result2.decimals).toBe(1n) expect(result3.amount).toBe(314n) @@ -2167,9 +2192,13 @@ describe("FixedPoint factory function", () => { it("should handle rounding boundaries correctly", () => { // Test values exactly at rounding boundaries const fp = new FixedPointNumber(125n, 2n) // 1.25 - const resultTrunc = fp.toPrecision(2n, { roundingMode: RoundingMode.TRUNC }) - const resultHalfEven = fp.toPrecision(2n, { roundingMode: RoundingMode.HALF_EVEN }) - + const resultTrunc = fp.toPrecision(2n, { + roundingMode: RoundingMode.TRUNC, + }) + const resultHalfEven = fp.toPrecision(2n, { + roundingMode: RoundingMode.HALF_EVEN, + }) + expect(resultTrunc.amount).toBe(12n) expect(resultTrunc.decimals).toBe(1n) // 1.2 expect(resultHalfEven.amount).toBe(12n) // Should round to even (1.2) @@ -2180,7 +2209,7 @@ describe("FixedPoint factory function", () => { const fp = new FixedPointNumber(123n, 2n) // 1.23 const result = fp.toPrecision(3n) // 3 significant digits, should add a zero const secondResult = result.toPrecision(3n) // Should be unchanged - + expect(result.equals(secondResult)).toBe(true) }) }) diff --git a/test/fractional-unit-symbols.test.ts b/test/fractional-unit-symbols.test.ts index 5d8278c..5b71521 100644 --- a/test/fractional-unit-symbols.test.ts +++ b/test/fractional-unit-symbols.test.ts @@ -1,5 +1,5 @@ -import { MoneyFactory, Money } from "../src/money" -import { BTC, USD, GBP } from "../src/currencies" +import { BTC, GBP, USD } from "../src/currencies" +import { Money, MoneyFactory } from "../src/money" describe("Fractional Unit Symbols", () => { describe("Parsing", () => { @@ -42,75 +42,92 @@ describe("Fractional Unit Symbols", () => { it("should format BTC with sats symbol", () => { const money = new Money({ asset: BTC, - amount: { amount: 10000n, decimals: 8n } + amount: { amount: 10000n, decimals: 8n }, }) - + expect(money.toString({ preferredUnit: "sat" })).toBe("10,000 sats") - expect(money.toString({ preferredUnit: "sat", preferFractionalSymbol: true })).toBe("§10,000") + expect( + money.toString({ preferredUnit: "sat", preferFractionalSymbol: true }), + ).toBe("§10,000") }) it("should format BTC with satoshi symbol", () => { const money = new Money({ asset: BTC, - amount: { amount: 10000n, decimals: 8n } + amount: { amount: 10000n, decimals: 8n }, }) - - expect(money.toString({ preferredUnit: "satoshi" })).toBe("10,000 satoshis") - expect(money.toString({ preferredUnit: "satoshi", preferFractionalSymbol: true })).toBe("§10,000") + + expect(money.toString({ preferredUnit: "satoshi" })).toBe( + "10,000 satoshis", + ) + expect( + money.toString({ + preferredUnit: "satoshi", + preferFractionalSymbol: true, + }), + ).toBe("§10,000") }) it("should format BTC with compact notation and symbol", () => { const money = new Money({ asset: BTC, - amount: { amount: 100000000n, decimals: 8n } // 1 BTC + amount: { amount: 100000000n, decimals: 8n }, // 1 BTC }) - - expect(money.toString({ preferredUnit: "sat", compact: true })).toBe("100M sats") - expect(money.toString({ - preferredUnit: "sat", - preferFractionalSymbol: true, - compact: true - })).toBe("§100M") + + expect(money.toString({ preferredUnit: "sat", compact: true })).toBe( + "100M sats", + ) + expect( + money.toString({ + preferredUnit: "sat", + preferFractionalSymbol: true, + compact: true, + }), + ).toBe("§100M") }) it("should handle negative amounts in formatting", () => { const money = new Money({ asset: BTC, - amount: { amount: -10000n, decimals: 8n } + amount: { amount: -10000n, decimals: 8n }, }) - - expect(money.toString({ - preferredUnit: "sat", - preferFractionalSymbol: true - })).toBe("§-10,000") + + expect( + money.toString({ + preferredUnit: "sat", + preferFractionalSymbol: true, + }), + ).toBe("§-10,000") }) it("should fallback to word format when symbol not available", () => { const money = new Money({ asset: BTC, - amount: { amount: 10000n, decimals: 8n } + amount: { amount: 10000n, decimals: 8n }, }) - + // When preferFractionalSymbol is true but no matching symbol exists - expect(money.toString({ - preferredUnit: "bit", - preferFractionalSymbol: true - })).toBe("1,000 bits") + expect( + money.toString({ + preferredUnit: "bit", + preferFractionalSymbol: true, + }), + ).toBe("1,000 bits") }) }) describe("Error Handling", () => { it("should throw error when both currency and fractional symbols are present", () => { expect(() => MoneyFactory("$¢50")).toThrow( - "Cannot parse money string with both currency and fractional unit symbols" + "Cannot parse money string with both currency and fractional unit symbols", ) - + expect(() => MoneyFactory("§₿100")).toThrow( - "Cannot parse money string with both currency and fractional unit symbols" + "Cannot parse money string with both currency and fractional unit symbols", ) - + expect(() => MoneyFactory("¢$25")).toThrow( - "Cannot parse money string with both currency and fractional unit symbols" + "Cannot parse money string with both currency and fractional unit symbols", ) }) }) @@ -119,12 +136,12 @@ describe("Fractional Unit Symbols", () => { it("should maintain consistency for BTC sats", () => { const original = "§10000" const money = MoneyFactory(original) - const formatted = money.toString({ - preferredUnit: "sat", - preferFractionalSymbol: true + const formatted = money.toString({ + preferredUnit: "sat", + preferFractionalSymbol: true, }) expect(formatted).toBe("§10,000") - + // Parse the formatted string back const reparsed = MoneyFactory("§10,000") expect(reparsed.equals(money)).toBe(true) @@ -132,10 +149,10 @@ describe("Fractional Unit Symbols", () => { it("should work with compact notation", () => { const money = MoneyFactory("§100000") - const compact = money.toString({ - preferredUnit: "sat", - preferFractionalSymbol: true, - compact: true + const compact = money.toString({ + preferredUnit: "sat", + preferFractionalSymbol: true, + compact: true, }) expect(compact).toBe("§100K") }) @@ -145,23 +162,27 @@ describe("Fractional Unit Symbols", () => { it("should work with Money operations", () => { const money1 = MoneyFactory("§10000") const money2 = MoneyFactory("§5000") - + const sum = money1.add(money2) - expect(sum.toString({ - preferredUnit: "sat", - preferFractionalSymbol: true - })).toBe("§15,000") + expect( + sum.toString({ + preferredUnit: "sat", + preferFractionalSymbol: true, + }), + ).toBe("§15,000") }) it("should work with different unit preferences", () => { const money = MoneyFactory("§100000000") // 1 BTC worth of sats - + expect(money.toString()).toBe("1 BTC") expect(money.toString({ preferredUnit: "sat" })).toBe("100,000,000 sats") - expect(money.toString({ - preferredUnit: "sat", - preferFractionalSymbol: true - })).toBe("§100,000,000") + expect( + money.toString({ + preferredUnit: "sat", + preferFractionalSymbol: true, + }), + ).toBe("§100,000,000") }) }) -}) \ No newline at end of file +}) diff --git a/test/intl-extensions.test.ts b/test/intl-extensions.test.ts index 40210dc..8f6f656 100644 --- a/test/intl-extensions.test.ts +++ b/test/intl-extensions.test.ts @@ -33,4 +33,4 @@ describe("Intl.NumberFormat string extension", () => { expect(formatter.format(123456.78)).toBe("123,456.78") expect(formatter.format(123456n)).toBe("123,456.00") }) -}) \ No newline at end of file +}) diff --git a/test/math-utils.test.ts b/test/math-utils.test.ts index e1ffac1..306fb05 100644 --- a/test/math-utils.test.ts +++ b/test/math-utils.test.ts @@ -1,4 +1,4 @@ -import { gcd, isOnlyFactorsOf2And5, getBitSize } from "../src/math-utils" +import { gcd, getBitSize, isOnlyFactorsOf2And5 } from "../src/math-utils" describe("Math Utils", () => { describe("gcd", () => { diff --git a/test/money-factory.test.ts b/test/money-factory.test.ts index a78e95b..e3dd1db 100644 --- a/test/money-factory.test.ts +++ b/test/money-factory.test.ts @@ -1,6 +1,6 @@ +import { BTC, ETH, EUR, GBP, JPY, USD, USDC, USDT } from "../src/currencies" import { Money } from "../src/index" import { Money as MoneyClass } from "../src/money" -import { USD, EUR, GBP, JPY, BTC, ETH, CNY as __CNY, USDT, USDC } from "../src/currencies" describe("Money Factory Function", () => { describe("US Number Format (1,234.56)", () => { @@ -1020,7 +1020,7 @@ describe("Money Factory Function", () => { it("should work with different currencies", () => { const currencies = [USD, EUR, BTC, ETH] - + for (const currency of currencies) { const originalMoney = new MoneyClass({ asset: currency, @@ -1052,14 +1052,14 @@ describe("Money Factory Function", () => { // Create a Money instance and get its JSON representation const originalMoney = new MoneyClass({ asset: USD, - amount: { amount: 12345n, decimals: 2n } + amount: { amount: 12345n, decimals: 2n }, }) const jsonObject = originalMoney.toJSON() // AssetAmount object (has 'asset' field) const assetAmountObject = { asset: USD, - amount: { amount: 12345n, decimals: 2n } + amount: { amount: 12345n, decimals: 2n }, } const fromJson = Money(jsonObject) diff --git a/test/money.test.ts b/test/money.test.ts index 0c39688..49cf7b6 100644 --- a/test/money.test.ts +++ b/test/money.test.ts @@ -1,24 +1,20 @@ import { - Money, - MoneyJSONSchema, - formatMoney, - shouldUseIsoFormatting, - formatWithIntlCurrency, - formatWithCustomFormatting, - convertToPreferredUnit, findFractionalUnitInfo, getCurrencyDisplayPart, + Money, + MoneyJSONSchema, normalizeLocale, pluralizeFractionalUnit, + shouldUseIsoFormatting, } from "../src/money" import { - Currency, - AssetAmount, - RoundingMode, - HALF_EXPAND, - HALF_EVEN, + type AssetAmount, CEIL, + type Currency, FLOOR, + HALF_EVEN, + HALF_EXPAND, + RoundingMode, } from "../src/types" describe("Money", () => { @@ -1839,21 +1835,30 @@ describe("Money", () => { const eurMoney = new Money(eurAmount) expect(() => usdMoney.compare(eurMoney)).toThrow( - "Cannot compare Money with different asset types" + "Cannot compare Money with different asset types", ) }) it("should work for sorting arrays", () => { const amounts = [ - new Money({ asset: usdCurrency, amount: { amount: 10000n, decimals: 2n } }), // $100.00 - new Money({ asset: usdCurrency, amount: { amount: 5000n, decimals: 2n } }), // $50.00 - new Money({ asset: usdCurrency, amount: { amount: 7500n, decimals: 2n } }), // $75.00 + new Money({ + asset: usdCurrency, + amount: { amount: 10000n, decimals: 2n }, + }), // $100.00 + new Money({ + asset: usdCurrency, + amount: { amount: 5000n, decimals: 2n }, + }), // $50.00 + new Money({ + asset: usdCurrency, + amount: { amount: 7500n, decimals: 2n }, + }), // $75.00 ] const sorted = amounts.sort((a, b) => a.compare(b)) - expect(sorted[0].balance.amount.amount).toBe(5000n) // $50.00 - expect(sorted[1].balance.amount.amount).toBe(7500n) // $75.00 + expect(sorted[0].balance.amount.amount).toBe(5000n) // $50.00 + expect(sorted[1].balance.amount.amount).toBe(7500n) // $75.00 expect(sorted[2].balance.amount.amount).toBe(10000n) // $100.00 }) }) @@ -1948,7 +1953,7 @@ describe("Money", () => { asset: usdCurrency, amount: { amount: 10050n, decimals: 2n }, // $100.50 }) - + // Convert to RationalNumber by dividing by 3 const rationalMoney = money.add(money).add(money).distribute(3)[0] const json = rationalMoney.toJSON({ compact: true }) @@ -1998,7 +2003,9 @@ describe("Money", () => { amount: "100.50", } - expect(() => Money.fromJSON(json)).toThrow("Unsupported currency code: UNKNOWN") + expect(() => Money.fromJSON(json)).toThrow( + "Unsupported currency code: UNKNOWN", + ) }) it("should handle RationalNumber amounts in compact format", () => { @@ -2513,9 +2520,15 @@ describe("Money", () => { }) // minDecimals forces trailing zeros, maxDecimals limits precision - expect(money.toString({ minDecimals: 2, maxDecimals: 4 })).toBe("1.2346 BTC") - expect(money.toString({ minDecimals: 6, maxDecimals: 4 })).toBe("1.2346 BTC") // maxDecimals takes precedence - expect(money.toString({ minDecimals: 2, maxDecimals: 8 })).toBe("1.23456789 BTC") + expect(money.toString({ minDecimals: 2, maxDecimals: 4 })).toBe( + "1.2346 BTC", + ) + expect(money.toString({ minDecimals: 6, maxDecimals: 4 })).toBe( + "1.2346 BTC", + ) // maxDecimals takes precedence + expect(money.toString({ minDecimals: 2, maxDecimals: 8 })).toBe( + "1.23456789 BTC", + ) }) it("should handle zero amounts with minDecimals", () => { @@ -2548,8 +2561,12 @@ describe("Money", () => { amount: { amount: 100000000n, decimals: 8n }, // 1.00000000 BTC }) - expect(money.toString({ minDecimals: 0, preferredUnit: "satoshi" })).toBe("100,000,000 satoshis") - expect(money.toString({ minDecimals: 2, preferredUnit: "satoshi" })).toBe("100,000,000.00 satoshis") + expect( + money.toString({ minDecimals: 0, preferredUnit: "satoshi" }), + ).toBe("100,000,000 satoshis") + expect( + money.toString({ minDecimals: 2, preferredUnit: "satoshi" }), + ).toBe("100,000,000.00 satoshis") }) }) describe("excludeCurrency option", () => { @@ -2576,8 +2593,12 @@ describe("Money", () => { asset: btc, amount: { amount: 200000000n, decimals: 8n }, // 2.0 BTC }) - expect(money.toString({ preferSymbol: true, excludeCurrency: true })).toBe("2") - expect(money.toString({ preferSymbol: true, excludeCurrency: false })).toBe("₿2") + expect( + money.toString({ preferSymbol: true, excludeCurrency: true }), + ).toBe("2") + expect( + money.toString({ preferSymbol: true, excludeCurrency: false }), + ).toBe("₿2") expect(money.toString({ preferSymbol: true })).toBe("₿2") // default behavior }) it("should exclude fractional unit when using preferredUnit and excludeCurrency is true", () => { @@ -2585,18 +2606,30 @@ describe("Money", () => { asset: btc, amount: { amount: 100000000n, decimals: 8n }, // 1.0 BTC }) - expect(money.toString({ preferredUnit: "sat", excludeCurrency: true })).toBe("100,000,000") - expect(money.toString({ preferredUnit: "sat", excludeCurrency: false })).toBe("100,000,000 sats") - expect(money.toString({ preferredUnit: "sat" })).toBe("100,000,000 sats") // default behavior + expect( + money.toString({ preferredUnit: "sat", excludeCurrency: true }), + ).toBe("100,000,000") + expect( + money.toString({ preferredUnit: "sat", excludeCurrency: false }), + ).toBe("100,000,000 sats") + expect(money.toString({ preferredUnit: "sat" })).toBe( + "100,000,000 sats", + ) // default behavior }) it("should work with other formatting options", () => { const money = new Money({ asset: usd, amount: { amount: 123456n, decimals: 2n }, // $1234.56 }) - expect(money.toString({ excludeCurrency: true, locale: "de-DE" })).toBe("1.234,56") - expect(money.toString({ excludeCurrency: true, maxDecimals: 1 })).toBe("1,234.6") - expect(money.toString({ excludeCurrency: true, minDecimals: 3 })).toBe("1,234.560") + expect(money.toString({ excludeCurrency: true, locale: "de-DE" })).toBe( + "1.234,56", + ) + expect(money.toString({ excludeCurrency: true, maxDecimals: 1 })).toBe( + "1,234.6", + ) + expect(money.toString({ excludeCurrency: true, minDecimals: 3 })).toBe( + "1,234.560", + ) }) }) }) diff --git a/test/precision-safety.test.ts b/test/precision-safety.test.ts index b41a6df..10eca53 100644 --- a/test/precision-safety.test.ts +++ b/test/precision-safety.test.ts @@ -1,4 +1,4 @@ -import { Money, FixedPointNumber } from "../src" +import { FixedPointNumber, Money } from "../src" import { BTC, ETH, USD } from "../src/currencies" describe("Precision Safety", () => { diff --git a/test/price-range.test.ts b/test/price-range.test.ts index 3eab7c5..e49959d 100644 --- a/test/price-range.test.ts +++ b/test/price-range.test.ts @@ -1,8 +1,8 @@ import { describe, expect, it } from "@jest/globals" +import { BTC, EUR, USD } from "../src/currencies" +import { ExchangeRate } from "../src/exchange-rates" import { Money } from "../src/index" import { PriceRange, PriceRangeFactory } from "../src/price-range" -import { USD, EUR, BTC } from "../src/currencies" -import { ExchangeRate } from "../src/exchange-rates" describe("PriceRange", () => { describe("Factory Function", () => { @@ -49,7 +49,9 @@ describe("PriceRange", () => { it("throws error for invalid range (max < min)", () => { expect(() => { PriceRangeFactory(Money("$100"), Money("$50")) - }).toThrow("Invalid range: maximum must be greater than or equal to minimum") + }).toThrow( + "Invalid range: maximum must be greater than or equal to minimum", + ) }) it("allows equal min and max values", () => { @@ -167,8 +169,8 @@ describe("PriceRange", () => { it("calculates intersection of overlapping ranges", () => { const intersection = range1.intersect(range2) expect(intersection).not.toBeNull() - expect(intersection!.min.equals(Money("$80"))).toBe(true) - expect(intersection!.max.equals(Money("$100"))).toBe(true) + expect(intersection?.min.equals(Money("$80"))).toBe(true) + expect(intersection?.max.equals(Money("$100"))).toBe(true) }) it("returns null for non-overlapping intersections", () => { @@ -281,7 +283,9 @@ describe("PriceRange", () => { }) it("formats with between style", () => { - expect(range.toString({ format: "between" })).toBe("Between $50.00 and $100.00") + expect(range.toString({ format: "between" })).toBe( + "Between $50.00 and $100.00", + ) }) it("formats large ranges with compact notation", () => { @@ -402,19 +406,19 @@ describe("PriceRange", () => { { name: "Item B", price: Money("$75") }, { name: "Item C", price: Money("$110") }, { name: "Item D", price: Money("$50") }, - { name: "Item E", price: Money("$100") } + { name: "Item E", price: Money("$100") }, ] it("filters products within range", () => { - const inRange = products.filter(p => range.contains(p.price)) + const inRange = products.filter((p) => range.contains(p.price)) expect(inRange.length).toBe(3) - expect(inRange.map(p => p.name)).toEqual(["Item B", "Item D", "Item E"]) + expect(inRange.map((p) => p.name)).toEqual(["Item B", "Item D", "Item E"]) }) it("works with Money array methods", () => { - const prices = products.map(p => p.price) - const inRangePrices = prices.filter(price => range.contains(price)) + const prices = products.map((p) => p.price) + const inRangePrices = prices.filter((price) => range.contains(price)) expect(inRangePrices.length).toBe(3) }) }) -}) \ No newline at end of file +}) diff --git a/test/prices.test.ts b/test/prices.test.ts index 0d56ea6..0fa030b 100644 --- a/test/prices.test.ts +++ b/test/prices.test.ts @@ -1,8 +1,7 @@ +import { FixedPointNumber } from "../src/fixed-point" import { Price } from "../src/prices" -import { ExchangeRate } from "../src/exchange-rates" -import { Currency, AssetAmount } from "../src/types" import { RationalNumber } from "../src/rationals" -import { FixedPointNumber } from "../src/fixed-point" +import type { AssetAmount, Currency } from "../src/types" describe("Price", () => { const usdCurrency: Currency = { @@ -330,12 +329,12 @@ describe("Price", () => { // $50,000 per 1 BTC - BTC should become base since amount is 1 const price = new Price( { asset: usdCurrency, amount: { amount: 5000000n, decimals: 2n } }, // $50,000 - { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } } // 1 BTC + { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } }, // 1 BTC ) const rate = price.toExchangeRate({ decimals: 2 }) - expect(rate.baseCurrency).toBe(btcCurrency) // BTC is base + expect(rate.baseCurrency).toBe(btcCurrency) // BTC is base expect(rate.quoteCurrency).toBe(usdCurrency) // USD is quote expect(rate.rate.toString()).toBe("50000.00") // 1 BTC = $50,000.00 }) @@ -343,14 +342,14 @@ describe("Price", () => { it("should convert price with fractional base currency", () => { // $100 per 0.002 BTC - BTC should become base since 0.002 is closer to 1 than 100 const price = new Price( - { asset: usdCurrency, amount: { amount: 10000n, decimals: 2n } }, // $100 - { asset: btcCurrency, amount: { amount: 200000n, decimals: 8n } } // 0.002 BTC + { asset: usdCurrency, amount: { amount: 10000n, decimals: 2n } }, // $100 + { asset: btcCurrency, amount: { amount: 200000n, decimals: 8n } }, // 0.002 BTC ) const rate = price.toExchangeRate({ decimals: 2 }) - expect(rate.baseCurrency).toBe(btcCurrency) // BTC is base (closer to 1) - expect(rate.quoteCurrency).toBe(usdCurrency) // USD is quote + expect(rate.baseCurrency).toBe(btcCurrency) // BTC is base (closer to 1) + expect(rate.quoteCurrency).toBe(usdCurrency) // USD is quote expect(rate.rate.toString()).toBe("50000.00") // 1 BTC = 50,000 USD (100/0.002 = 50,000) }) @@ -358,23 +357,23 @@ describe("Price", () => { // $50,000 per 1 BTC, but force USD as base const price = new Price( { asset: usdCurrency, amount: { amount: 5000000n, decimals: 2n } }, // $50,000 - { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } } // 1 BTC + { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } }, // 1 BTC ) - const rate = price.toExchangeRate({ + const rate = price.toExchangeRate({ decimals: 8, - baseCurrency: usdCurrency + baseCurrency: usdCurrency, }) - expect(rate.baseCurrency).toBe(usdCurrency) // USD forced as base - expect(rate.quoteCurrency).toBe(btcCurrency) // BTC is quote + expect(rate.baseCurrency).toBe(usdCurrency) // USD forced as base + expect(rate.quoteCurrency).toBe(btcCurrency) // BTC is quote expect(rate.rate.toString()).toBe("0.00002000") // 1 USD = 0.00002 BTC }) it("should include default source metadata", () => { const price = new Price( { asset: usdCurrency, amount: { amount: 5000000n, decimals: 2n } }, - { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } } + { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } }, ) const rate = price.toExchangeRate({ decimals: 2 }) @@ -388,18 +387,18 @@ describe("Price", () => { it("should allow custom source metadata override", () => { const price = new Price( { asset: usdCurrency, amount: { amount: 5000000n, decimals: 2n } }, - { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } } + { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } }, ) const customSource = { name: "Custom Market Data", priority: 1, - reliability: 0.95 + reliability: 0.95, } - const rate = price.toExchangeRate({ + const rate = price.toExchangeRate({ decimals: 2, - source: customSource + source: customSource, }) expect(rate.source).toBe(customSource) @@ -408,13 +407,13 @@ describe("Price", () => { it("should include timestamp", () => { const price = new Price( { asset: usdCurrency, amount: { amount: 5000000n, decimals: 2n } }, - { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } } + { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } }, ) const customTimestamp = "1640995200000" - const rate = price.toExchangeRate({ + const rate = price.toExchangeRate({ decimals: 2, - timestamp: customTimestamp + timestamp: customTimestamp, }) expect(rate.timestamp).toBe(customTimestamp) @@ -423,7 +422,7 @@ describe("Price", () => { it("should auto-generate timestamp if not provided", () => { const price = new Price( { asset: usdCurrency, amount: { amount: 5000000n, decimals: 2n } }, - { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } } + { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } }, ) const rate = price.toExchangeRate({ decimals: 2 }) @@ -435,26 +434,26 @@ describe("Price", () => { it("should handle equal ratios by using argument order", () => { // $100 per 100 EUR - both amounts are equal, should use argument order const price = new Price( - { asset: usdCurrency, amount: { amount: 10000n, decimals: 2n } }, // $100 - { asset: eurCurrency, amount: { amount: 10000n, decimals: 2n } } // €100 + { asset: usdCurrency, amount: { amount: 10000n, decimals: 2n } }, // $100 + { asset: eurCurrency, amount: { amount: 10000n, decimals: 2n } }, // €100 ) const rate = price.toExchangeRate({ decimals: 4 }) // First argument (USD) becomes quote, second (EUR) becomes base - expect(rate.baseCurrency).toBe(eurCurrency) // EUR is base (second arg) + expect(rate.baseCurrency).toBe(eurCurrency) // EUR is base (second arg) expect(rate.quoteCurrency).toBe(usdCurrency) // USD is quote (first arg) - expect(rate.rate.toString()).toBe("1.0000") // 1 EUR = $1.00 + expect(rate.rate.toString()).toBe("1.0000") // 1 EUR = $1.00 }) it("should throw error for identical currencies", () => { const price = new Price( - { asset: usdCurrency, amount: { amount: 10000n, decimals: 2n } }, // $100 - { asset: usdCurrency, amount: { amount: 5000n, decimals: 2n } } // $50 + { asset: usdCurrency, amount: { amount: 10000n, decimals: 2n } }, // $100 + { asset: usdCurrency, amount: { amount: 5000n, decimals: 2n } }, // $50 ) expect(() => price.toExchangeRate({ decimals: 2 })).toThrow( - "Cannot create ExchangeRate: both currencies are the same (USD)" + "Cannot create ExchangeRate: both currencies are the same (USD)", ) }) @@ -462,20 +461,23 @@ describe("Price", () => { // 1 ETH per 0.05 BTC const ethCurrency: Currency = { name: "Ethereum", - code: "ETH", + code: "ETH", decimals: 18n, - symbol: "Ξ" + symbol: "Ξ", } const price = new Price( - { asset: ethCurrency, amount: { amount: 1000000000000000000n, decimals: 18n } }, // 1 ETH - { asset: btcCurrency, amount: { amount: 5000000n, decimals: 8n } } // 0.05 BTC + { + asset: ethCurrency, + amount: { amount: 1000000000000000000n, decimals: 18n }, + }, // 1 ETH + { asset: btcCurrency, amount: { amount: 5000000n, decimals: 8n } }, // 0.05 BTC ) const rate = price.toExchangeRate({ decimals: 8 }) - expect(rate.baseCurrency).toBe(ethCurrency) // ETH is base (closer to 1) - expect(rate.quoteCurrency).toBe(btcCurrency) // BTC is quote + expect(rate.baseCurrency).toBe(ethCurrency) // ETH is base (closer to 1) + expect(rate.quoteCurrency).toBe(btcCurrency) // BTC is quote expect(rate.rate.toString()).toBe("0.05000000") // 1 ETH = 0.05 BTC }) @@ -483,7 +485,7 @@ describe("Price", () => { // Test default decimals behavior const price = new Price( { asset: usdCurrency, amount: { amount: 5000000n, decimals: 2n } }, - { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } } + { asset: btcCurrency, amount: { amount: 100000000n, decimals: 8n } }, ) const rate = price.toExchangeRate() diff --git a/test/rational-strings.test.ts b/test/rational-strings.test.ts index efc2565..6bbe326 100644 --- a/test/rational-strings.test.ts +++ b/test/rational-strings.test.ts @@ -1,11 +1,11 @@ import { FractionStringSchema, - RationalStringSchema, + getRationalStringType, isFractionString, isRationalString, - toRationalString, parseFraction, - getRationalStringType, + RationalStringSchema, + toRationalString, } from "../src/rational-strings" describe("FractionStringSchema", () => { diff --git a/test/rationals.test.ts b/test/rationals.test.ts index df13238..9d45a1f 100644 --- a/test/rationals.test.ts +++ b/test/rationals.test.ts @@ -1,6 +1,6 @@ -import { RationalNumber, Rational } from "../src/rationals" -import { Ratio, RoundingMode } from "../src/types" import { getBitSize } from "../src/math-utils" +import { Rational, RationalNumber } from "../src/rationals" +import { type DecimalString, type Ratio, RoundingMode } from "../src/types" describe("RationalNumber", () => { const oneHalf: Ratio = { p: 1n, q: 2n } // 1/2 @@ -427,7 +427,7 @@ describe("Rational factory function", () => { }) it("should work with DecimalString type", () => { - const decimalStr = "0.75" as any // Simulating DecimalString + const decimalStr = "0.75" as DecimalString const r = Rational(decimalStr) expect(r.p).toBe(75n) expect(r.q).toBe(100n) @@ -462,16 +462,16 @@ describe("Rational factory function", () => { it("should produce same results as constructor for Ratio mode", () => { const ratio: Ratio = { p: 22n, q: 7n } const factory = Rational(ratio) - const constructor = new RationalNumber(ratio) - expect(factory.p).toBe(constructor.p) - expect(factory.q).toBe(constructor.q) + const fromConstructor = new RationalNumber(ratio) + expect(factory.p).toBe(fromConstructor.p) + expect(factory.q).toBe(fromConstructor.q) }) it("should produce equivalent results for fraction strings", () => { const factory = Rational("22/7") - const constructor = new RationalNumber({ p: 22n, q: 7n }) - expect(factory.p).toBe(constructor.p) - expect(factory.q).toBe(constructor.q) + const fromConstructor = new RationalNumber({ p: 22n, q: 7n }) + expect(factory.p).toBe(fromConstructor.p) + expect(factory.q).toBe(fromConstructor.q) }) it("should round-trip with toString for fractions", () => { @@ -840,7 +840,7 @@ describe("Rational factory function", () => { const largeP = BigInt("12345678901234567890") const largeQ = BigInt("98765432109876543210") const rational = new RationalNumber({ p: largeP, q: largeQ }) - + const expectedSize = largeP.toString(2).length + largeQ.toString(2).length expect(rational.getBitSize()).toBe(expectedSize) }) @@ -848,11 +848,11 @@ describe("Rational factory function", () => { it("should work with simplified rationals", () => { const unsimplified = new RationalNumber({ p: 6n, q: 9n }) // 6/9 = 2/3 const simplified = unsimplified.simplify() - + // Original: getBitSize(6n) = 3, getBitSize(9n) = 4, total = 7 expect(unsimplified.getBitSize()).toBe(7) - - // Simplified: getBitSize(2n) = 2, getBitSize(3n) = 2, total = 4 + + // Simplified: getBitSize(2n) = 2, getBitSize(3n) = 2, total = 4 expect(simplified.getBitSize()).toBe(4) }) @@ -870,7 +870,7 @@ describe("Rational factory function", () => { const pBits = p === 0n ? 0 : (p < 0n ? -p : p).toString(2).length const qBits = q === 0n ? 0 : (q < 0n ? -q : q).toString(2).length const expectedBits = pBits + qBits - + expect(rational.getBitSize()).toBe(expectedBits) }) }) @@ -881,7 +881,7 @@ describe("Rational factory function", () => { it("should convert 22/7 to 2 significant digits", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) // ≈ 3.142857... const result = rational.toFixedPoint({ maxPrecision: 2 }) - + // 22/7 ≈ 3.142857, truncated to 2 significant digits = 3.1 = 31/10 expect(result.amount).toBe(31n) expect(result.decimals).toBe(1n) @@ -890,7 +890,7 @@ describe("Rational factory function", () => { it("should convert 22/7 to 4 significant digits", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) // ≈ 3.142857... const result = rational.toFixedPoint({ maxPrecision: 4 }) - + // 22/7 ≈ 3.142857, truncated to 4 significant digits = 3.142 = 3142/1000 expect(result.amount).toBe(3142n) expect(result.decimals).toBe(3n) @@ -899,7 +899,7 @@ describe("Rational factory function", () => { it("should handle large numbers with precision reduction", () => { const rational = new RationalNumber({ p: 300000n, q: 1n }) // 300000 const result = rational.toFixedPoint({ maxPrecision: 1 }) - + // 300000 truncated to 1 significant digit = 3 × 10^5 = 3/10^(-5) expect(result.amount).toBe(3n) expect(result.decimals).toBe(-5n) @@ -908,7 +908,7 @@ describe("Rational factory function", () => { it("should handle negative rationals", () => { const rational = new RationalNumber({ p: -22n, q: 7n }) // ≈ -3.142857... const result = rational.toFixedPoint({ maxPrecision: 2 }) - + // -3.142857... truncated to 2 significant digits = -3.1 = -31/10 expect(result.amount).toBe(-31n) expect(result.decimals).toBe(1n) @@ -917,7 +917,7 @@ describe("Rational factory function", () => { it("should handle fractions less than 1", () => { const rational = new RationalNumber({ p: 1n, q: 3n }) // ≈ 0.333333... const result = rational.toFixedPoint({ maxPrecision: 2 }) - + // 1/3 ≈ 0.333333, truncated to 2 significant digits = 0.33 = 33/100 expect(result.amount).toBe(33n) expect(result.decimals).toBe(2n) @@ -926,7 +926,7 @@ describe("Rational factory function", () => { it("should handle single significant digit", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) // ≈ 3.142857... const result = rational.toFixedPoint({ maxPrecision: 1 }) - + // 3.142857... truncated to 1 significant digit = 3 = 3/1 expect(result.amount).toBe(3n) expect(result.decimals).toBe(0n) @@ -934,16 +934,25 @@ describe("Rational factory function", () => { it("should handle different rounding modes", () => { const rational = new RationalNumber({ p: 5n, q: 2n }) // 2.5 - - const ceiling = rational.toFixedPoint({ maxPrecision: 1, roundingMode: RoundingMode.CEIL }) + + const ceiling = rational.toFixedPoint({ + maxPrecision: 1, + roundingMode: RoundingMode.CEIL, + }) expect(ceiling.amount).toBe(3n) expect(ceiling.decimals).toBe(0n) - - const floor = rational.toFixedPoint({ maxPrecision: 1, roundingMode: RoundingMode.FLOOR }) + + const floor = rational.toFixedPoint({ + maxPrecision: 1, + roundingMode: RoundingMode.FLOOR, + }) expect(floor.amount).toBe(2n) expect(floor.decimals).toBe(0n) - - const halfEven = rational.toFixedPoint({ maxPrecision: 1, roundingMode: RoundingMode.HALF_EVEN }) + + const halfEven = rational.toFixedPoint({ + maxPrecision: 1, + roundingMode: RoundingMode.HALF_EVEN, + }) expect(halfEven.amount).toBe(2n) // 2.5 rounds to 2 (nearest even) expect(halfEven.decimals).toBe(0n) }) @@ -951,7 +960,7 @@ describe("Rational factory function", () => { it("should handle very small numbers", () => { const rational = new RationalNumber({ p: 1n, q: 1000000n }) // 0.000001 const result = rational.toFixedPoint({ maxPrecision: 1 }) - + // 0.000001 to 1 significant digit = 0.000001 = 1/1000000 (magnitude is -5, so 1 sig digit means 6 decimals) expect(result.amount).toBe(1n) expect(result.decimals).toBe(6n) @@ -960,7 +969,7 @@ describe("Rational factory function", () => { it("should handle exact decimal representations", () => { const rational = new RationalNumber({ p: 1n, q: 4n }) // 0.25 (exact) const result = rational.toFixedPoint({ maxPrecision: 2 }) - + // 0.25 to 2 significant digits = 0.25 = 25/100 expect(result.amount).toBe(25n) expect(result.decimals).toBe(2n) @@ -969,7 +978,7 @@ describe("Rational factory function", () => { it("should work with default rounding mode", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) const result = rational.toFixedPoint({ maxPrecision: 2 }) - + // Should default to TRUNC and produce a valid result expect(typeof result.amount).toBe("bigint") expect(typeof result.decimals).toBe("bigint") @@ -981,10 +990,11 @@ describe("Rational factory function", () => { it("should convert using bit-based precision", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) const result = rational.toFixedPoint({ maxBits: 16 }) - + // maxBits = 16 means we can use at most 16 bits total // This should determine the appropriate decimal precision automatically - const totalBits = getBitSize(result.amount) + getBitSize(result.decimals) + const totalBits = + getBitSize(result.amount) + getBitSize(result.decimals) expect(totalBits).toBeLessThanOrEqual(16) expect(typeof result.amount).toBe("bigint") expect(typeof result.decimals).toBe("bigint") @@ -992,14 +1002,15 @@ describe("Rational factory function", () => { it("should produce smaller numbers with smaller bit budgets", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) - + const result8 = rational.toFixedPoint({ maxBits: 8 }) const result16 = rational.toFixedPoint({ maxBits: 16 }) - + // 16-bit budget should allow for more precision than 8-bit const bits8 = getBitSize(result8.amount) + getBitSize(result8.decimals) - const bits16 = getBitSize(result16.amount) + getBitSize(result16.decimals) - + const bits16 = + getBitSize(result16.amount) + getBitSize(result16.decimals) + expect(bits8).toBeLessThanOrEqual(8) expect(bits16).toBeLessThanOrEqual(16) expect(bits16).toBeGreaterThanOrEqual(bits8) @@ -1008,9 +1019,10 @@ describe("Rational factory function", () => { it("should handle very small bit budgets", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) const result = rational.toFixedPoint({ maxBits: 4 }) - + // With only 4 bits, should still produce a valid result - const totalBits = getBitSize(result.amount) + getBitSize(result.decimals) + const totalBits = + getBitSize(result.amount) + getBitSize(result.decimals) expect(totalBits).toBeLessThanOrEqual(4) expect(typeof result.amount).toBe("bigint") expect(typeof result.decimals).toBe("bigint") @@ -1019,7 +1031,7 @@ describe("Rational factory function", () => { it("should handle large bit budgets", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) const result = rational.toFixedPoint({ maxBits: 64 }) - + // Large bit budget should allow high precision expect(typeof result.amount).toBe("bigint") expect(typeof result.decimals).toBe("bigint") @@ -1031,7 +1043,7 @@ describe("Rational factory function", () => { it("should handle zero rational", () => { const rational = new RationalNumber({ p: 0n, q: 1n }) const result = rational.toFixedPoint({ maxPrecision: 2 }) - + expect(result.amount).toBe(0n) expect(result.decimals).toBe(2n) }) @@ -1039,7 +1051,7 @@ describe("Rational factory function", () => { it("should handle very large rationals", () => { const rational = new RationalNumber({ p: 999999999999n, q: 1n }) const result = rational.toFixedPoint({ maxPrecision: 1 }) - + // Should successfully convert even very large numbers expect(typeof result.amount).toBe("bigint") expect(result.decimals).toBe(-11n) // 12-digit number truncated to 1 digit needs -11 decimal places @@ -1047,15 +1059,15 @@ describe("Rational factory function", () => { it("should throw error for invalid maxPrecision", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) - + expect(() => { rational.toFixedPoint({ maxPrecision: 0 }) }).toThrow() - + expect(() => { rational.toFixedPoint({ maxPrecision: -1 }) }).toThrow() - + expect(() => { rational.toFixedPoint({ maxPrecision: 51 }) }).toThrow() @@ -1063,11 +1075,11 @@ describe("Rational factory function", () => { it("should throw error for invalid maxBits", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) - + expect(() => { rational.toFixedPoint({ maxBits: 0 }) }).toThrow() - + expect(() => { rational.toFixedPoint({ maxBits: -1 }) }).toThrow() @@ -1075,18 +1087,18 @@ describe("Rational factory function", () => { it("should throw error when both maxPrecision and maxBits are specified", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) - + expect(() => { - rational.toFixedPoint({ - maxPrecision: 2, - maxBits: 16 + rational.toFixedPoint({ + maxPrecision: 2, + maxBits: 16, }) }).toThrow() }) it("should throw error when neither maxPrecision nor maxBits are specified", () => { const rational = new RationalNumber({ p: 22n, q: 7n }) - + expect(() => { rational.toFixedPoint({}) }).toThrow() @@ -1097,11 +1109,11 @@ describe("Rational factory function", () => { it("should be consistent with known mathematical results", () => { // Test π approximation (22/7) to various precisions const pi = new RationalNumber({ p: 22n, q: 7n }) - + const result1 = pi.toFixedPoint({ maxPrecision: 1 }) expect(result1.amount).toBe(3n) // 1 significant digit = 3 expect(result1.decimals).toBe(0n) - + const result2 = pi.toFixedPoint({ maxPrecision: 2 }) expect(result2.amount).toBe(31n) // 2 significant digits = 3.1 (truncated) expect(result2.decimals).toBe(1n) @@ -1110,20 +1122,29 @@ describe("Rational factory function", () => { it("should handle different rounding modes consistently", () => { // Test 2.5 (exact tie case) with different rounding modes const tie = new RationalNumber({ p: 5n, q: 2n }) - - const trunc = tie.toFixedPoint({ maxPrecision: 1, roundingMode: RoundingMode.TRUNC }) + + const trunc = tie.toFixedPoint({ + maxPrecision: 1, + roundingMode: RoundingMode.TRUNC, + }) expect(trunc.amount).toBe(2n) // Truncate toward zero - - const halfEven = tie.toFixedPoint({ maxPrecision: 1, roundingMode: RoundingMode.HALF_EVEN }) + + const halfEven = tie.toFixedPoint({ + maxPrecision: 1, + roundingMode: RoundingMode.HALF_EVEN, + }) expect(halfEven.amount).toBe(2n) // Round to even - - const halfExpand = tie.toFixedPoint({ maxPrecision: 1, roundingMode: RoundingMode.HALF_EXPAND }) + + const halfExpand = tie.toFixedPoint({ + maxPrecision: 1, + roundingMode: RoundingMode.HALF_EXPAND, + }) expect(halfExpand.amount).toBe(3n) // Round away from zero }) it("should preserve sign through truncation", () => { const negative = new RationalNumber({ p: -5n, q: 2n }) // -2.5 - + const result = negative.toFixedPoint({ maxPrecision: 1 }) expect(result.amount).toBe(-2n) // Truncate toward zero expect(result.decimals).toBe(0n) diff --git a/test/setup.ts b/test/setup.ts index 7d7c570..4d5eaba 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -1,68 +1,81 @@ // Set consistent locale for number formatting across environments -process.env.LC_ALL = 'en_US.UTF-8' -process.env.LANG = 'en_US.UTF-8' +process.env.LC_ALL = "en_US.UTF-8" +process.env.LANG = "en_US.UTF-8" // Store original NumberFormat before any modules are loaded const originalNumberFormat = Intl.NumberFormat -// Apply the mock immediately (not in beforeAll) to ensure it's active before module loading -Object.defineProperty(Intl, 'NumberFormat', { - value: function(locale?: string | string[], options?: Intl.NumberFormatOptions) { - // Use provided locale, fallback to en-US - const normalizedLocale = locale || 'en-US' - - // Create formatter with normalized options - const normalizedOptions = { ...options } - - // Always implement manual rounding for consistency across environments - if (normalizedOptions.roundingMode && normalizedOptions.maximumFractionDigits !== undefined) { - const { roundingMode, ...restOptions } = normalizedOptions - const formatter = new originalNumberFormat(normalizedLocale, restOptions) - - // Return a wrapper that handles rounding manually for consistency - return { - format: (value: number | bigint | string) => { - const numValue = typeof value === 'string' ? parseFloat(value) : Number(value) - - // Apply manual rounding based on roundingMode and maximumFractionDigits - const multiplier = Math.pow(10, restOptions.maximumFractionDigits) - let roundedValue = numValue - - switch (roundingMode) { - case 'floor': - roundedValue = Math.floor(numValue * multiplier) / multiplier - break - case 'ceil': - roundedValue = Math.ceil(numValue * multiplier) / multiplier - break - case 'halfExpand': - roundedValue = Math.round(numValue * multiplier) / multiplier - break - case 'halfEven': - // Banker's rounding - const scaled = numValue * multiplier - const truncated = Math.trunc(scaled) - const fraction = scaled - truncated - if (Math.abs(fraction) === 0.5) { - roundedValue = (truncated % 2 === 0 ? truncated : truncated + Math.sign(fraction)) / multiplier - } else { - roundedValue = Math.round(scaled) / multiplier - } - break - default: - roundedValue = Math.round(numValue * multiplier) / multiplier +// Create a proper constructor function +function CustomNumberFormat( + locale?: string | string[], + options?: Intl.NumberFormatOptions, +): Intl.NumberFormat { + // Use provided locale, fallback to en-US + const normalizedLocale = locale || "en-US" + + // Create formatter with normalized options + const normalizedOptions = { ...options } + + // Always implement manual rounding for consistency across environments + if ( + normalizedOptions.roundingMode && + normalizedOptions.maximumFractionDigits !== undefined + ) { + const { roundingMode, ...restOptions } = normalizedOptions + const formatter = new originalNumberFormat(normalizedLocale, restOptions) + + // Return a wrapper that handles rounding manually for consistency + return { + format: (value: number | bigint | string) => { + const numValue = + typeof value === "string" ? parseFloat(value) : Number(value) + + // Apply manual rounding based on roundingMode and maximumFractionDigits + const multiplier = 10 ** (restOptions.maximumFractionDigits ?? 2) + let roundedValue = numValue + + switch (roundingMode) { + case "floor": + roundedValue = Math.floor(numValue * multiplier) / multiplier + break + case "ceil": + roundedValue = Math.ceil(numValue * multiplier) / multiplier + break + case "halfExpand": + roundedValue = Math.round(numValue * multiplier) / multiplier + break + case "halfEven": { + // Banker's rounding + const scaled = numValue * multiplier + const truncated = Math.trunc(scaled) + const fraction = scaled - truncated + if (Math.abs(fraction) === 0.5) { + roundedValue = + (truncated % 2 === 0 + ? truncated + : truncated + Math.sign(fraction)) / multiplier + } else { + roundedValue = Math.round(scaled) / multiplier + } + break } - - return formatter.format(roundedValue) - }, - formatToParts: formatter.formatToParts?.bind(formatter), - resolvedOptions: formatter.resolvedOptions?.bind(formatter) - } - } - - return new originalNumberFormat(normalizedLocale, normalizedOptions) - }, + default: + roundedValue = Math.round(numValue * multiplier) / multiplier + } + + return formatter.format(roundedValue) + }, + formatToParts: formatter.formatToParts?.bind(formatter), + resolvedOptions: formatter.resolvedOptions?.bind(formatter), + } as Intl.NumberFormat + } + + return new originalNumberFormat(normalizedLocale, normalizedOptions) +} + +// Apply the mock immediately (not in beforeAll) to ensure it's active before module loading +Object.defineProperty(Intl, "NumberFormat", { + value: CustomNumberFormat, writable: true, - configurable: true + configurable: true, }) - diff --git a/test/time.test.ts b/test/time.test.ts index a49dd5a..ce03aa9 100644 --- a/test/time.test.ts +++ b/test/time.test.ts @@ -1,18 +1,18 @@ import { - UNIXTimeSchema, - isUNIXTime, - toUNIXTime, - nowUNIXTime, dateToUNIXTime, - unixTimeToDate, - UTCTimeSchema, + dateToUTCTime, + isUNIXTime, isUTCTime, - toUTCTime, + nowUNIXTime, nowUTCTime, - dateToUTCTime, + toUNIXTime, + toUTCTime, + UNIXTimeSchema, + UTCTimeSchema, + unixTimeToDate, utcTimeToDate, } from "../src/time" -import { UNIXTime, UTCTime } from "../src/types" +import type { UNIXTime, UTCTime } from "../src/types" describe("UNIXTime utilities", () => { describe("UNIXTimeSchema", () => { diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json deleted file mode 100644 index b342bf1..0000000 --- a/tsconfig.eslint.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": [".eslintrc.js", "./*.js", "src", "test"] -}